MCP can write a ticket's reasoning but cannot read it back
create_instance_ticket takes a reasoning argument and describes it as the audit record
(workers/mcp/src/storage-tools.ts:223):
reasoning: z.string().optional().describe("Why — the decision/audit, shown on the card")
instance_board does not return it. groupBoard builds each card from a fixed field list
(workers/mcp/src/instance-tools/shared.ts:123-132) and maps detail: it.description —
reasoning is absent, and grep -rn 'reasoning' workers/mcp/src/ finds it only in the writer,
in ask_ticket's prose, and in comments. So an agent can file the "why" and no MCP reader can
retrieve it.
Why it matters more after #568
#568 (0172534) fixed the truncation at the writer, so description is no longer silently cut
at 300 chars. That closes the API-side gap — confirmed live. It does not help an MCP caller,
because the fuller text lives in reasoning, which instance_board never returns.
Measured on the delegation card for session csess_e80b6a21 (instance
bd43f4de-ef35-4051-bdec-43f8571414a1): description 375 chars, reasoning 691 chars naming
four trunk pushes plus "and 11 more" — 15 in total. agent_trace(level:"warn") independently
shows 15 act.consequential events between 01:42 and 03:22 on 2026-08-11. A model reading
instance_board sees the short field; the record of what the agent actually did is in the field
it cannot see.
ask_ticket reaches reasoning (instance-tools/board.ts:186), but that is a model call over
one ticket, not a read. There is no way to simply fetch the field.
The decision this needs
Returning reasoning on every card enlarges every instance_board response, and this repo has
been bitten by payload size in both directions — #503 budgeted a payload down rather than
raising a cap, and #569 is open on list_instance_tools returning ~117 KB by default. So do not
just add the field:
- Return it only on request (an argument), or
- return it only for cards whose
description was derived from it, or
- return it always and justify the size against a measurement.
State which, and why, with a measured before/after on a real board.
Acceptance criteria
- An MCP caller can retrieve a ticket's
reasoning without a model call.
- The size decision above is made explicitly and backed by a measured payload delta.
- A guard asserts that a field the MCP writer accepts is reachable by some MCP reader — stated
with its denominator per ADR 0002, over the whole write-tool argument set, not a hand-picked
list. The general asymmetry is the bug; reasoning is one instance of it.
- The guard fails if
reasoning is removed from the read path again.
Verified vs inferred
- Verified: both
file:line citations, the grep result, the 375/691 character counts, the
15 act.consequential events, and that ask_ticket is the only current consumer.
- Inferred: nothing load-bearing. AC3's wider asymmetry is asserted from this one confirmed
case — whether other written-but-unreadable fields exist is exactly what the guard would
measure, and is deliberately not claimed here.
MCP can write a ticket's
reasoningbut cannot read it backcreate_instance_tickettakes areasoningargument and describes it as the audit record(
workers/mcp/src/storage-tools.ts:223):instance_boarddoes not return it.groupBoardbuilds each card from a fixed field list(
workers/mcp/src/instance-tools/shared.ts:123-132) and mapsdetail: it.description—reasoningis absent, andgrep -rn 'reasoning' workers/mcp/src/finds it only in the writer,in
ask_ticket's prose, and in comments. So an agent can file the "why" and no MCP reader canretrieve it.
Why it matters more after #568
#568 (
0172534) fixed the truncation at the writer, sodescriptionis no longer silently cutat 300 chars. That closes the API-side gap — confirmed live. It does not help an MCP caller,
because the fuller text lives in
reasoning, whichinstance_boardnever returns.Measured on the delegation card for session
csess_e80b6a21(instancebd43f4de-ef35-4051-bdec-43f8571414a1):description375 chars,reasoning691 chars namingfour trunk pushes plus "and 11 more" — 15 in total.
agent_trace(level:"warn")independentlyshows 15
act.consequentialevents between 01:42 and 03:22 on 2026-08-11. A model readinginstance_boardsees the short field; the record of what the agent actually did is in the fieldit cannot see.
ask_ticketreachesreasoning(instance-tools/board.ts:186), but that is a model call overone ticket, not a read. There is no way to simply fetch the field.
The decision this needs
Returning
reasoningon every card enlarges everyinstance_boardresponse, and this repo hasbeen bitten by payload size in both directions — #503 budgeted a payload down rather than
raising a cap, and #569 is open on
list_instance_toolsreturning ~117 KB by default. So do notjust add the field:
descriptionwas derived from it, orState which, and why, with a measured before/after on a real board.
Acceptance criteria
reasoningwithout a model call.with its denominator per ADR 0002, over the whole write-tool argument set, not a hand-picked
list. The general asymmetry is the bug;
reasoningis one instance of it.reasoningis removed from the read path again.Verified vs inferred
file:linecitations, the grep result, the 375/691 character counts, the15
act.consequentialevents, and thatask_ticketis the only current consumer.case — whether other written-but-unreadable fields exist is exactly what the guard would
measure, and is deliberately not claimed here.