Context
A correction to a ticket belongs in its body. Appending it as a comment leaves the stale claim authoritative, because a reader hits the body first and stops there.
The rule already exists. ticket-create-workflow.md §11 says "Ticket body: Update your own in place." On 2026-08-06 I read that payload while filing #16599 and #16600, then appended three correction comments to #16582 — whose body still argued from a justification I had falsified and still prescribed a fix I had come to doubt in my own comment.
So this is not a missing rule. It is a rule in the wrong place, worded as permission.
The Problem
Two independent causes, and only one is about wording.
1. §11 reads as permission, not obligation. The section is titled Authorship Respect; its bold lead is "You never override another author's"; its *Why:* is "Rewriting someone else's prose causes attribution collapse." Every framing cue points at not touching peers' artifacts. The self-clause — "Update your own in place" — reads as you are allowed to, not the body must state current facts. The section's actual subject is absorbed; the clause slides past.
2. The rule lives in a create-time payload, and correction happens later. ticket-create fires before create_issue. It is not in context when an agent returns to a 14-hour-old ticket to record a finding — and it should not be: re-reading a creation skill to write a comment would be pure token waste. So a better-worded §11 still would not have been present at the moment of the defect.
Operator framing of exactly this split:
"2 cases: directly after creating a ticket, it should be hot context. in our case => hey there is this 14h old ticket => no trigger to re-read the skill (and there should not be one)."
Why it costs more than tidiness:
- A reviewer checks the body for ACs. On a PR the body is the contract, so verifying AC-by-AC against superseded ACs produces a confident verdict on a dead contract — rigorous work aimed at the wrong target. Our own PR-body lint already encodes body-as-authority by requiring
## Post-Merge Validation / ## Deltas / Evidence: there.
- Comment sediment must be read in full to be safe, because only the whole set reveals which correction supersedes which. Meanwhile the economical read — body, then stop — returns the stale version. The tax punishes the careful reader and misleads the frugal one.
- It scales with how wrong the body is, which is backwards: the more a ticket has been corrected, the more expensive and less reliable it becomes to read.
- It lands hardest on the peers with least room. GPT seats cap at 258k with ~124k usable. My three #16582 comments are ~3–4k tokens — roughly 3% of a GPT peer's usable budget spent reconstructing what the body should have said in place.
The Architectural Reality
ai/mcp/ToolService.mjs already implements the two-surface split this fix needs — one compact, one full:
ToolService.mjs:40 "Enables compact `tools/list` descriptions while preserving full …"
ToolService.mjs:330 compact label = x-neo-tool-summary || summary || fullDescription
ToolService.mjs:187 fullDescription = operation.description || operation.summary || toolName
So for manage_issue_comment (ai/mcp/server/github-workflow/openapi.yaml:489):
summary is the compact label an agent receives when the tool schema loads. Currently Manage Comments (Create or Update) — 34 chars, and it says nothing about where a correction goes. Verified empirically: a ToolSearch fetch of this tool returns exactly that string; the description: block is not in the fetched schema.
description is the handbook body, surfaced via get_mcp_tool_handbook (toolService.mjs:428) and mandatory to read on first use.
That is the placement answer. The compact label is the only surface guaranteed present at the moment of the act, because it re-arrives on every schema load; the handbook is read once and goes stale in context exactly like the skill does.
Operator constraint that shapes the split:
"we have too many mcp tools => shorter initial details save focus and tokens."
So the label carries the imperative only, and the reason goes in the handbook where full detail belongs.
The Fix
1. manage_issue_comment summary — the imperative, minimal.
summary: Manage Comments (Create or Update) # unchanged — this is the TITLE source
+ x-neo-tool-summary: Manage Comments (Create or Update) — dialogue only; corrections go in the BODY, not a comment
93 chars, +59 on the projected record. Present at the act, for every agent, on every schema load.
Corrected 2026-08-07 on @neo-gpt's review — the annotation, not summary. This body first prescribed putting the imperative in summary, and reported the cost as +59 from the label length. That was wrong, and the reason is the thing to carry forward:
title : operation.summary || toolName,
description : listDescription,
With no x-neo-tool-summary, both fields resolve to summary, so the addition is emitted twice — the projected tools/list record grows +118, not +59. I had measured the yaml scalar while the runtime duplicated it. x-neo-tool-summary carries it once and leaves title stable at the 34-char name, which is what makes the originally-claimed +59 actually true.
The cap is not cosmetic, and the ordering inside the label is load-bearing. buildToolListDescription (ToolService.mjs:329-339) truncates past toolListDescriptionMaxLength — 120 for this server (ai/mcp/server/github-workflow/toolService.mjs:470) — rather than failing. The operative clause sits at the very end, so an over-long label would keep corrections go in the BODY, and silently drop not a comment: a surface that reads like guidance while instructing nothing. Demonstrated by mutation, evidence in the PR body. The guard therefore pins the tail and the absence of an ellipsis, not just the topic phrase.
2. manage_issue_comment description — the reason, in the handbook half. Two clauses: a reviewer checks the body for ACs, so a comment leaves them reviewing a dead contract; and sediment must be read in full while the cheap read returns the stale version. Plus the distinction that keeps this from over-correcting into never comment: BODY = state (problem, evidence, prescription, ACs), COMMENT = dialogue (review response, answer to a peer, a measurement handed to a named person).
2b. The same description currently routes corrections INTO a comment — found while implementing. Under Action: 'update' it reads "When to use: To correct mistakes or update status in a previously posted comment." With no scope on whose mistake or which claim, the handbook endorses the exact anti-pattern the compact label now warns against. Scoped, not banned: correcting your own dialogue stays legitimate, and collapsing a superseded comment of yours to a one-line pointer is how consolidation removes the sediment tax — while correcting what the ticket claims routes to the body.
3. ticket-create-workflow.md §11 — reframe permission into obligation, NET-REDUCING bytes.
- - **Ticket body:** Update your own in place. If it's someone else's ticket, respond via a NEW comment.
- - **Ticket AC list:** Extend your own list. If it's someone else's ticket, do NOT mutate their AC list; propose additions via comment.
+ - **Your own:** correct the BODY, incl. ACs. A comment cannot supersede it — reviewers read the body for ACs.
+ - **Someone else's:** propose via comment; never mutate their body or ACs.
237 → 186 bytes: −51. Measured at implementation; this body's earlier estimate of 238 → 185 (−53) was hand-counted and off by two in each direction. Whole-file: 22,084 → 22,033, confirming the two bullets are the only change. The *Why:* line about attribution collapse stays; it is correct for the peers' half.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
openapi.yaml x-neo-tool-summary for manage_issue_comment |
ToolService.mjs:330 compact-label precedence (x-neo-tool-summary → summary → description) |
carry the imperative; 93 chars, +59 on the record |
none needed — advisory text |
is the doc |
summary also feeds title at :194, so putting it there emits it twice (+118) |
openapi.yaml summary for manage_issue_comment |
ToolService.mjs:194 title source |
unchanged at the 34-char name |
— |
is the doc |
a stable title is what keeps the record cost at +59 |
same operation's description |
ToolService.mjs:187 + toolService.mjs:428 handbook route |
add the two reasons + BODY/COMMENT distinction |
handbook is already mandatory-on-first-use |
is the doc |
handbook resolves operation.description |
ticket-create-workflow.md §11 |
this ticket; the #16582 specimen |
permission → obligation |
— |
is the doc |
−51 bytes measured (237 → 186) |
same operation's description, 'update' when-to-use |
discovered at implementation |
scope it to your own dialogue; route claim-corrections to the body |
— |
is the doc |
the line read "To correct mistakes" with no scope on whose |
Decision Record impact
none. No ADR governs tool-label wording or skill-section phrasing. Placement was validated against turn-memory-pre-flight's decision tree: Step 2 (a specific, identifiable lifecycle event) resolves to skill-level, and the rule already has a skill home, so no new skill and no AGENTS.md addition. The openapi metadata is MCP tool documentation rather than turn-loaded memory substrate, so it sits outside that tree. No harness-loading file is touched, so the mechanical pre-flight commands do not apply.
Acceptance Criteria
Out of Scope
- A mechanical guard. "Correction comment while the body is unchanged" is a heuristic that would false-positive on exactly the dialogue the skill should keep protecting — review responses, peer answers. This lands advisory text at the right trigger; it does not claim to close the class.
- The write-side asymmetry. Ticket body edits go through
gh issue edit in bash, not an MCP tool, so no equivalent label exists to carry a reminder there. Real, and not fixable by this change.
- Other tools' labels. Only
manage_issue_comment is in scope; a sweep of every compact label for missing guidance is separate work and would fight the terseness constraint.
- Rewriting #16582's body. That is the specimen, and its consolidation waits on
@neo-gpt's in-flight framing challenge.
AGENTS.md. Rejected by the decision tree — this is not a universal per-turn rule, and turn-loaded real estate is the most expensive surface we have.
Avoided Traps
Adding a new section, or a new skill. The rule already exists and did not fire. My own substrate warns that a guard which keeps not firing is scoped wrong, not under-emphasised, and that adding emphasis to a non-firing guard is the additive-drift anti-pattern. So this reframes and relocates; the skill half comes out smaller.
Putting the note in the tool's description because that is where prose belongs. It would have been invisible: the fetched schema is built from summary. A beautifully-worded handbook note would never have reached the agent about to comment. Checked before proposing, because this is exactly the class of assumption that has cost real time.
Padding the compact label with the reasoning. Directly against "shorter initial details save focus and tokens" across a large tool surface. The label gets the imperative; the handbook gets the why.
Claiming this would have prevented the #16582 comments. It would not have prevented all three — the skill half only fires when an agent is already in ticket-create. The tool half is the part that reaches the 14-hour-old-ticket case, and it is advisory. Stated because an overclaimed fix is how a defect gets closed while remaining live.
Related
- #16582 — the specimen: three correction comments on a body that still contradicts them.
- #16588 — tools/list compaction reaching the description but not the schema beside it. Same tool-metadata surface, different concern (payload size vs guidance placement); worth reading together before touching compaction.
- #16594 — loaded review substrate prescribing a check a tool now falsifies. The same substrate-vs-reality drift, one layer over.
ai/mcp/ToolService.mjs — the compact/full split this fix relies on.
Origin Session ID: 555fc3d6-7078-4aca-b8da-5bb349e68711
Live latest-open sweep: checked the latest 20 open issues at 2026-08-06T22:4xZ; no equivalent found (#16588 is the nearest neighbour and is about compaction payload, not guidance placement). A2A in-flight claim sweep: no [lane-claim]/[lane-intent] on tool labels or ticket-create in the herd window.
Retrieval Hint: query_raw_memories("correction belongs in the ticket body not a comment tool summary trigger") · ai/mcp/ToolService.mjs:330 · ticket-create-workflow.md §11
Authored by @neo-opus-vega (Claude Opus 5).
Context
A correction to a ticket belongs in its body. Appending it as a comment leaves the stale claim authoritative, because a reader hits the body first and stops there.
The rule already exists.
ticket-create-workflow.md§11 says "Ticket body: Update your own in place." On 2026-08-06 I read that payload while filing #16599 and #16600, then appended three correction comments to #16582 — whose body still argued from a justification I had falsified and still prescribed a fix I had come to doubt in my own comment.So this is not a missing rule. It is a rule in the wrong place, worded as permission.
The Problem
Two independent causes, and only one is about wording.
1. §11 reads as permission, not obligation. The section is titled Authorship Respect; its bold lead is "You never override another author's"; its
*Why:*is "Rewriting someone else's prose causes attribution collapse." Every framing cue points at not touching peers' artifacts. The self-clause — "Update your own in place" — reads as you are allowed to, not the body must state current facts. The section's actual subject is absorbed; the clause slides past.2. The rule lives in a create-time payload, and correction happens later.
ticket-createfires beforecreate_issue. It is not in context when an agent returns to a 14-hour-old ticket to record a finding — and it should not be: re-reading a creation skill to write a comment would be pure token waste. So a better-worded §11 still would not have been present at the moment of the defect.Operator framing of exactly this split:
Why it costs more than tidiness:
## Post-Merge Validation/## Deltas/Evidence:there.The Architectural Reality
ai/mcp/ToolService.mjsalready implements the two-surface split this fix needs — one compact, one full:So for
manage_issue_comment(ai/mcp/server/github-workflow/openapi.yaml:489):summaryis the compact label an agent receives when the tool schema loads. CurrentlyManage Comments (Create or Update)— 34 chars, and it says nothing about where a correction goes. Verified empirically: aToolSearchfetch of this tool returns exactly that string; thedescription:block is not in the fetched schema.descriptionis the handbook body, surfaced viaget_mcp_tool_handbook(toolService.mjs:428) and mandatory to read on first use.That is the placement answer. The compact label is the only surface guaranteed present at the moment of the act, because it re-arrives on every schema load; the handbook is read once and goes stale in context exactly like the skill does.
Operator constraint that shapes the split:
So the label carries the imperative only, and the reason goes in the handbook where full detail belongs.
The Fix
1.
manage_issue_commentsummary — the imperative, minimal.93 chars, +59 on the projected record. Present at the act, for every agent, on every schema load.
Corrected 2026-08-07 on
@neo-gpt's review — the annotation, notsummary. This body first prescribed putting the imperative insummary, and reported the cost as +59 from the label length. That was wrong, and the reason is the thing to carry forward:title : operation.summary || toolName, // ToolService.mjs:194 description : listDescription, // → x-neo-tool-summary || summary || descriptionWith no
x-neo-tool-summary, both fields resolve tosummary, so the addition is emitted twice — the projectedtools/listrecord grows +118, not +59. I had measured the yaml scalar while the runtime duplicated it.x-neo-tool-summarycarries it once and leavestitlestable at the 34-char name, which is what makes the originally-claimed +59 actually true.The cap is not cosmetic, and the ordering inside the label is load-bearing.
buildToolListDescription(ToolService.mjs:329-339) truncates pasttoolListDescriptionMaxLength— 120 for this server (ai/mcp/server/github-workflow/toolService.mjs:470) — rather than failing. The operative clause sits at the very end, so an over-long label would keepcorrections go in the BODY,and silently dropnot a comment: a surface that reads like guidance while instructing nothing. Demonstrated by mutation, evidence in the PR body. The guard therefore pins the tail and the absence of an ellipsis, not just the topic phrase.2.
manage_issue_commentdescription — the reason, in the handbook half. Two clauses: a reviewer checks the body for ACs, so a comment leaves them reviewing a dead contract; and sediment must be read in full while the cheap read returns the stale version. Plus the distinction that keeps this from over-correcting into never comment: BODY = state (problem, evidence, prescription, ACs), COMMENT = dialogue (review response, answer to a peer, a measurement handed to a named person).2b. The same
descriptioncurrently routes corrections INTO a comment — found while implementing. UnderAction: 'update'it reads "When to use: To correct mistakes or update status in a previously posted comment." With no scope on whose mistake or which claim, the handbook endorses the exact anti-pattern the compact label now warns against. Scoped, not banned: correcting your own dialogue stays legitimate, and collapsing a superseded comment of yours to a one-line pointer is how consolidation removes the sediment tax — while correcting what the ticket claims routes to the body.3.
ticket-create-workflow.md§11 — reframe permission into obligation, NET-REDUCING bytes.237 → 186 bytes: −51. Measured at implementation; this body's earlier estimate of 238 → 185 (−53) was hand-counted and off by two in each direction. Whole-file: 22,084 → 22,033, confirming the two bullets are the only change. The
*Why:*line about attribution collapse stays; it is correct for the peers' half.Contract Ledger Matrix
openapi.yamlx-neo-tool-summaryformanage_issue_commentToolService.mjs:330compact-label precedence (x-neo-tool-summary→summary→ description)summaryalso feedstitleat:194, so putting it there emits it twice (+118)openapi.yamlsummaryformanage_issue_commentToolService.mjs:194titlesourcedescriptionToolService.mjs:187+toolService.mjs:428handbook routeoperation.descriptionticket-create-workflow.md§11description,'update'when-to-useDecision Record impact
none. No ADR governs tool-label wording or skill-section phrasing. Placement was validated againstturn-memory-pre-flight's decision tree: Step 2 (a specific, identifiable lifecycle event) resolves to skill-level, and the rule already has a skill home, so no new skill and noAGENTS.mdaddition. The openapi metadata is MCP tool documentation rather than turn-loaded memory substrate, so it sits outside that tree. No harness-loading file is touched, so the mechanical pre-flight commands do not apply.Acceptance Criteria
manage_issue_comment's compact label carries the imperative and stays ≤120 chars.title+descriptionpair — measured on the projected record, not on the yaml scalar.summaryfeeds bothtitleand the compact-description fallback, so the naive placement doubles the payload.ToolSearch/tools/listfetch of the tool shows that text — verified by fetching it, not by reading the yaml, since the two surfaces differ.ticket-create-workflow.md§11 states the body obligation for one's own tickets and the comment-proposal rule for others', and the peers'-half*Why:*survives..agents/skills/**byte delta for this change is ≤ 0.Out of Scope
gh issue editin bash, not an MCP tool, so no equivalent label exists to carry a reminder there. Real, and not fixable by this change.manage_issue_commentis in scope; a sweep of every compact label for missing guidance is separate work and would fight the terseness constraint.@neo-gpt's in-flight framing challenge.AGENTS.md. Rejected by the decision tree — this is not a universal per-turn rule, and turn-loaded real estate is the most expensive surface we have.Avoided Traps
Adding a new section, or a new skill. The rule already exists and did not fire. My own substrate warns that a guard which keeps not firing is scoped wrong, not under-emphasised, and that adding emphasis to a non-firing guard is the additive-drift anti-pattern. So this reframes and relocates; the skill half comes out smaller.
Putting the note in the tool's
descriptionbecause that is where prose belongs. It would have been invisible: the fetched schema is built fromsummary. A beautifully-worded handbook note would never have reached the agent about to comment. Checked before proposing, because this is exactly the class of assumption that has cost real time.Padding the compact label with the reasoning. Directly against "shorter initial details save focus and tokens" across a large tool surface. The label gets the imperative; the handbook gets the why.
Claiming this would have prevented the #16582 comments. It would not have prevented all three — the skill half only fires when an agent is already in
ticket-create. The tool half is the part that reaches the 14-hour-old-ticket case, and it is advisory. Stated because an overclaimed fix is how a defect gets closed while remaining live.Related
ai/mcp/ToolService.mjs— the compact/full split this fix relies on.Origin Session ID: 555fc3d6-7078-4aca-b8da-5bb349e68711
Live latest-open sweep: checked the latest 20 open issues at 2026-08-06T22:4xZ; no equivalent found (#16588 is the nearest neighbour and is about compaction payload, not guidance placement). A2A in-flight claim sweep: no
[lane-claim]/[lane-intent]on tool labels orticket-createin the herd window.Retrieval Hint:
query_raw_memories("correction belongs in the ticket body not a comment tool summary trigger")·ai/mcp/ToolService.mjs:330·ticket-create-workflow.md §11Authored by @neo-opus-vega (Claude Opus 5).