Summary
Since the #192 fix (d1ac134, "stream-json answer keeps every text block of the turn") the turn's answer is the concatenation of every assistant text block, in order. That is right for the ledger, but the turn-end notification excerpt (notify: brief, 500 chars) and the inline result_text are taken from the head of that answer, so an orchestrator sees the worker's narration ("Reading the tests… Starting the gates…") and never the completion receipt the worker wrote last. Please keep every block in the transcript (do not reopen #192) and let the excerpt select an explicit completion receipt.
What happened
Two managed claude sessions (adapter claude-stream-json, project excore), each ending its turn with a deliberately short receipt:
| session |
turn |
answer chars |
receipt starts at |
blocks before it |
500-char brief excerpt shows |
| s871 (2026-09-05) |
1 |
~3,900 |
1,020 |
7 |
narration only |
| s871 |
2 |
~1,700 |
516 |
3 |
narration, receipt cut |
| s908 (2026-09-06) |
1 |
1,067 |
647 |
5 |
narration only, ends mid-sentence ("All checks green (selftes") |
s908's receipt (420 chars: verdict, card@commit, checks incl. NOT RUN, risks, evidence path) is exactly what the orchestrator needs; the brief notification carried none of it. notify: final (2000) shows it only because the turn happened to be short. The orchestrator then spends an agent_read round trip to learn the verdict (the frugality concern of #194/#195).
Code: crates/ccteam-harness/src/execution/claude_stream_json/translate.rs:222-233 builds final_text from acc_text (all blocks joined); crates/ccteam-im/src/delegation.rs:293 BRIEF_NOTIFICATION_ANSWER_MAX_CHARS = 500 and notification_answer_max_chars(NotifyMode) size the excerpt from that text's head.
Expected
Keep the transcript as is (every block, ordered). For the notification excerpt and result_text, pick a receipt instead of the head, in this order:
- If the answer contains an explicit receipt marker (e.g. a
<report>…</report> block, or a configurable marker), use that block.
- Otherwise use the last assistant text block of the turn (the block after the final tool call) — that is where a disciplined worker puts its conclusion.
- Otherwise fall back to today's head excerpt.
The excerpt could say which rule fired (receipt: marker|last-block|head) so the reader knows whether they saw a conclusion or a preview. agent_read and FleetView should keep showing the whole answer.
Impact
Workaround in use
Worker protocol: the final text block is a receipt ≤400 chars (verdict · id@commit · checks incl. NOT RUN · risks · evidence path); the orchestrator reads it with agent_read{sid, n:1, max_chars:600} after every completion notification instead of trusting the excerpt.
Environment
Summary
Since the #192 fix (d1ac134, "stream-json answer keeps every text block of the turn") the turn's answer is the concatenation of every assistant text block, in order. That is right for the ledger, but the turn-end notification excerpt (
notify: brief, 500 chars) and the inlineresult_textare taken from the head of that answer, so an orchestrator sees the worker's narration ("Reading the tests… Starting the gates…") and never the completion receipt the worker wrote last. Please keep every block in the transcript (do not reopen #192) and let the excerpt select an explicit completion receipt.What happened
Two managed claude sessions (adapter
claude-stream-json, projectexcore), each ending its turn with a deliberately short receipt:s908's receipt (420 chars: verdict, card@commit, checks incl. NOT RUN, risks, evidence path) is exactly what the orchestrator needs; the brief notification carried none of it.
notify: final(2000) shows it only because the turn happened to be short. The orchestrator then spends anagent_readround trip to learn the verdict (the frugality concern of #194/#195).Code:
crates/ccteam-harness/src/execution/claude_stream_json/translate.rs:222-233buildsfinal_textfromacc_text(all blocks joined);crates/ccteam-im/src/delegation.rs:293BRIEF_NOTIFICATION_ANSWER_MAX_CHARS = 500andnotification_answer_max_chars(NotifyMode)size the excerpt from that text's head.Expected
Keep the transcript as is (every block, ordered). For the notification excerpt and
result_text, pick a receipt instead of the head, in this order:<report>…</report>block, or a configurable marker), use that block.The excerpt could say which rule fired (
receipt: marker|last-block|head) so the reader knows whether they saw a conclusion or a preview.agent_readand FleetView should keep showing the whole answer.Impact
notify: briefcannot act on completion notifications; they must poll or read transcripts (token cost, latency).Workaround in use
Worker protocol: the final text block is a receipt ≤400 chars (verdict · id@commit · checks incl. NOT RUN · risks · evidence path); the orchestrator reads it with
agent_read{sid, n:1, max_chars:600}after every completion notification instead of trusting the excerpt.Environment
claude-stream-json, Claude Code 2.1.260, projectexcore, sessions s871 / s908.