chore(triage): compose/defer over inventing precedence rules; converge to one comment#5242
Conversation
…nverge to one comment Two response-discipline fixes prompted by the triage routine's behavior on PR #5219 (it invented a "brand wins on conflict" SHOULD for what was really a compose/defer call, then posted an answer followed by a self-retraction addendum): - Step 5: add "Design-question discipline" — for "how do these inputs interact / should the spec define X" questions, default to compose / agent-territory / file-an-issue. Don't synthesize a normative precedence/conflict/MUST/SHOULD rule absent a concrete *interop* failure (incompatible wire output) — aesthetic divergence and unpredictable creative output are not interop failures. - Step 6: "Finalize before you comment — one comment per run." Never post an answer then a correction/addendum; a public answer-then-retraction trail is worse than a slightly-later single answer. - Comment engagement rule 6: if a re-run changes a posted conclusion, EDIT the original comment (gh api PATCH), don't stack a new one. - Two reinforcing entries in the quick-reference "Never" list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
LGTM. Clean, targeted prompt fix that names the two failure modes from #5219 and burns rules in at the exact steps where they fired.
Things I checked
- Step 5 addition at L517–L535: compose/defer default is gated on a concrete interop (incompatible wire output) failure, not aesthetic divergence — the right bar. The list (a/b/c) maps to the actual taxonomy the routine already uses (wire vs. agent-internals vs. out-of-scope).
- Step 6 addition at L599–L610: "finalize before you comment" lands ahead of the comment-format block, so a reader following Step 6 top-to-bottom hits the rule before drafting. Correct ordering.
- Engagement rule 6 at L1227–L1235: the
gh api -X PATCH repos/<owner>/<repo>/issues/comments/<id> -f body=…syntax is right (issue comments, not review comments — correct surface forissue_comment-routed triage). - Two new "Never" entries at L1268–L1271: cross-reference to "Design-question discipline in Step 5" resolves to the new header text. Parity with existing terse-bullet style.
- Cross-refs: Step 5's "(see Step 6)" → Step 6's new "finalize before you comment" paragraph. Step 6's "see 'Comment engagement (existing threads)'" → the engagement-rules block at L1194+. Both targets exist.
- Scope claim in PR body holds: prompt-only, no schema, no code, independent of #5219.
Follow-ups (non-blocking)
- The edit-don't-stack path assumes the routine kept (or can re-derive) the comment id from its own prior run. The new rule 6 covers re-derivation via the comments-list call, but a future tightening could have the routine record the posted comment id in the run summary so the PATCH is one call instead of list-then-patch. Not worth doing now.
Approving. The "two conformant agents producing incompatible wire output" framing for what counts as an interop failure is the load-bearing line in this change — it's the test the routine will actually apply next time someone asks "should the spec define X."
…", workflow routes them in Tracing why the routine answered WG questions on PR #5219 (the invented precedence rule + answer-then-addendum) surfaced a prompt/workflow contradiction: - claude-issue-triage.yml fires on issue_comment for issues AND PRs and injects a `MODE: PR-feedback` block telling the routine to answer PR questions — but triage-prompt.md claimed "PR conversations are out of scope; the workflow filters them; that's auto-fix's job." The workflow does the opposite, so the routine ran PR-comment answers ungoverned by the prompt's discipline. Fixes (same surface as the prior commit on this branch): - triage-prompt.md: replace the stale "PR conversations are out of scope" paragraph with an accurate `MODE: PR-feedback` section that routes PR questions through Step 5 (Design-question discipline) + Step 6 (finalize / one comment) + rule 6 (edit, don't addend). - claude-issue-triage.yml: tighten the payload's `MODE: PR-feedback` line to defer to those prompt rules (compose/defer; one coherent reply; edit don't addend) instead of a bare "answer it as a reply comment". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Run type section) The Run-type `comment.created` entry still said the workflow filters out PR comments, contradicting the corrected MODE: PR-feedback section. Align it: PR comments ARE routed here (is_pr + MODE: PR-feedback), handled per the PR-feedback rules, not as issue triage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Clean fix for a real misfire. Right shape: reconciles the prompt/workflow contradiction at the source instead of patching the bad comment on #5219.
Things I checked
- Step 5 "Design-question discipline" (
.agents/routines/triage-prompt.md~L520-538) — the interop-failure gate ("two conformant agents producing incompatible wire output") is the right operational line. Aesthetic divergence / unpredictability / "buyer might not like it" explicitly out. That's the load-bearing distinction. - Step 6 "Finalize before you comment — one comment per run" (~L599-611) — directly targets the answer-then-addend trail that produced the Option-A/B walkback on #5219.
- Comment-engagement rule 6 edit-don't-stack (~L1230-1239) —
gh api -X PATCH repos/<owner>/<repo>/issues/comments/<id>is the correct endpoint for issue and PR conversation comments. PR review-line comments are a different endpoint, but those aren't what the routine posts. - Workflow ↔ prompt coherence: the YAML
MODE: PR-feedbackpayload now defers to the prompt rules (.github/workflows/claude-issue-triage.yml:191). The stale "PR conversations are out of scope" paragraph is gone; the newMODE: PR-feedbacksection routes PR questions through the same Step 5 / Step 6 / rule 6 discipline. - Triage scope: prompt routine + one-line YAML string. No schema, no auth, no migration, no wire change. No changeset needed.
Follow-ups (non-blocking — file as issues)
- Asymmetric framing in Step 5. Explicit (a)/(b)/(c) examples for compose/defer, abstract definition for interop. Worth one concrete interop example ("two agents return incompatible field names for the same input") symmetric to the aesthetic-divergence counter-example, otherwise the routine may under-engage on questions that actually are interop.
- Third category not addressed. Wire-valid interpretation divergence — two agents both emit valid JSON but mean different things by the same field. Fold into the interop gate or explicitly defer.
- Footer self-check not wired into the PATCH path. Rule 6 names the
Triaged by Claude Codefooter as the self-check but doesn't say "match on the footer to find the comment id before PATCHing." One sentence closes it. - Workflow still inlines fix/question/conversational branches alongside the prompt that now covers them. Either prune the YAML inlines and let the prompt own it, or add a one-line YAML comment marking the duplication as intentional belt-and-suspenders. A future edit to one and not the other reopens the same drift this PR is closing.
Minor nits (non-blocking)
- Bullet the 13-line Step 5 paragraph. ~L520-538 packs the landing-pad, the NOT-synthesize rule, the not-interop list, the over-constrains rationale, and the escape hatch into a single block. Five beats want five bullets.
- Unicode ellipsis in the example. ~L1233 shows
-f body=…with a literal….-f body=<new-body>copy-pastes more reliably.
Approving on the strength of the workflow/prompt reconciliation plus the explicit interop-failure gate. Fix lands at the root cause — the prompt-workflow contradiction — not the symptom on #5219.
There was a problem hiding this comment.
Approving. Fixes a real misfire on #5219 and resolves the prompt/workflow contradiction at the same time — the routine was reading "PR conversations are out of scope" out of the prompt while the workflow was injecting MODE: PR-feedback. Reconciling those is the right shape.
Things I checked
- Cross-references resolve. Step 5's new "Design-question discipline" cites Step 6; Step 6 cites "Comment engagement (existing threads)"; rule 6 sits inside that section; the new
MODE: PR-feedbackblock names all three; the "Never" list (triage-prompt.md:1283-1287) backs them up. Internally coherent. - Workflow ↔ prompt seam.
.github/workflows/claude-issue-triage.yml:191now defers to the prompt ("Follow the MODE: PR-feedback rules in .agents/routines/triage-prompt.md") and the prompt's PR-feedback section (triage-prompt.md:1241-1260) is the actual source of truth. One restatement remains in the payload — load-bearing as a hint, accepted drift risk. - The
gh api -X PATCH repos/<owner>/<repo>/issues/comments/<id>edit path is the correct endpoint for PR conversation comments delivered byissue_commentevents — which is what this workflow fires on. - Bright line is checkable. "Concrete interop / wire-incompatibility failure" as the gate for inventing a precedence rule is sharper than "your judgment" — gives the routine something to fail against.
- No over-correction. Compose/defer is scoped to "how do two inputs interact / should the spec define X" questions, not all PR questions; fix-requests and concrete clarifications still flow.
Follow-ups (non-blocking — file as issues)
-
Edit semantics aren't pinned. Rule 6 (
triage-prompt.md:1227-1238) tells the routine to PATCH the original comment when a re-run changes the conclusion, but doesn't say what the edited body must contain. Without a rule the routine will likely keep the prior answer with strikethrough or "previously I said" framing — which reproduces the answer-then-walkback trail inside one comment. Add: "the edited body stands as the sole answer; no strikethrough, no 'previously I said' annotation; the edit replaces, it does not narrate." Also: if humans have already replied to the original answer, an edit silently rewrites context under their reply — that case probably wants a fresh comment with explicit re-statement, not a PATCH. Worth deciding before the next time this trips. -
The interop bright line wants a pinned negative example. Step 5's discipline paragraph (
triage-prompt.md:517-535) will hold better if it carries the #5219 case verbatim as its anti-example: "two agents generating different creative output from the samebrand+transformer_idis not wire incompatibility; the wire carries the creative artifact, and the buyer evaluates it." Expert framings around "operator reality / migration cost" read as wire-divergent to a sloppy synthesizer — a worked negative is the cheapest guardrail. -
Scope of
MODE: PR-feedback. Worth stating explicitly that this covers PR conversation comments only — inline review-comment threads firepull_request_review_comment, a different event the workflow doesn't subscribe to. Today the operational risk is zero (the routine literally won't see those events), but a one-liner in the PR-feedback section prevents a future maintainer from wiring it up without the matching PATCH path. Cheap.
Minor nits (non-blocking)
- Workflow restatement will drift.
.github/workflows/claude-issue-triage.yml:191restates "lean compose/defer over inventing precedence/MUST/SHOULD rules" in the payload after pointing at the prompt. If the prompt evolves, this string won't. The deference clause is doing the real work — consider trimming the restatement to a shorter pointer on a follow-up sweep.
LGTM. Follow-ups noted below.
What
Tightens the issue-triage routine's response discipline, after tracing why it mishandled @pkras's WG questions on #5219. Turned out to be two problems — a behavior gap and a prompt/workflow contradiction.
Behavior (what went wrong on #5219)
brandandtransformer_idare both present, brand wins on conflict" SHOULD — for a question that's really compose/defer (the buyer chose both inputs; generative output is never pixel-predictable; they evaluate and refine/discard).Surface (why it even engaged a PR)
The routine shouldn't have been ungoverned on a PR — except
triage-prompt.mdclaimed "PR conversations are out of scope; the workflow filters them; that's auto-fix's job," whileclaude-issue-triage.ymldoes the opposite: it fires onissue_commentfor issues and PRs and injects aMODE: PR-feedbackblock telling the routine to answer PR questions. So the routine followed the payload, with no discipline. (Auto-fix is unrelated — it pushes code fixes, doesn't post WG answers.)Changes
.agents/routines/triage-prompt.mdMODE: PR-feedbacksection that routes PR questions through the Step 5 / Step 6 / rule 6 discipline..github/workflows/claude-issue-triage.ymlMODE: PR-feedbackline to defer to those prompt rules (compose/defer; one coherent reply; edit don't addend) instead of a bare "answer it as a reply comment."Scope
Prompt + the one workflow string. No protocol/schema/code. Independent of #5219.
🤖 Generated with Claude Code