Skip to content

A ticket's reasoning can be written over MCP and never read back #574

Description

@serge-ivo

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:

  1. Return it only on request (an argument), or
  2. return it only for cards whose description was derived from it, or
  3. 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

  1. An MCP caller can retrieve a ticket's reasoning without a model call.
  2. The size decision above is made explicitly and backed by a measured payload delta.
  3. 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.
  4. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions