Skip to content

fix: tier-2 parity — error_max_turns, control acks, invalid-model shape, thinking signature#15

Merged
dn00 merged 2 commits into
mainfrom
fix/parity-tier2
Jun 10, 2026
Merged

fix: tier-2 parity — error_max_turns, control acks, invalid-model shape, thinking signature#15
dn00 merged 2 commits into
mainfrom
fix/parity-tier2

Conversation

@dn00

@dn00 dn00 commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Closes the tier-2 (consumed-field) parity gaps confirmed by replay — PARITY-GAPS #2/#3/#14/#15/#16 — and writes the parity policy (contract / consumed fields / on-demand / won't-fix-by-design) into PARITY-GAPS.md. Independent of #12/#13/#14 (branched off main).

Fixes, each verified live against the sonnet goldens

  • --max-turns semantics — native's unit is assistant API rounds inside the agentic loop (golden: 1 user prompt, num_turns: 2), not user prompts. clarp now counts SSE message_start events; on exceeding it interrupts, then reports result.error_max_turns (is_error, no result field, num_turns = rounds) and exits 1 even in stream-json mode — whether or not the interrupt beats the turn's natural completion. Prompt-count check kept as a fallback for backends without SSE.
  • Control acksinitialize (truthful payload: commands from transcript init, output_style, pid — not native's full account/models capabilities; documented as tier-4) and set_permission_mode (echoes {mode}) are acked in native's nested shape {type, response: {subtype, request_id, response}}. The interrupt ack migrated from clarp's old flat shape to the nested one.
  • Invalid-model result shape — turn-level backend API errors report subtype: "success" with is_error: true (the golden's actual shape — the gap list had this wrong), not subtype: "error". emitResult decouples is_error from subtype and can omit result.
  • Thinking signature — the assembler accumulates signature_delta; thinking blocks are {type, thinking, signature} like native (consumers replaying content to the API need it).
  • Exit codes — after an is_error result the session exits 1 on stdin-drain (native does; clarp exited 0).

Live verification (replay vs goldens, free)

case result exit (clarp/native)
max-turns-exhaustion error_max_turns, num_turns: 2, no result field 1 / 1
invalid-model-error success + is_error: true 1 / 1
control-protocol-misc both acks emitted, result_delta: 0 0 / 0

Suite: 417 tests green (8 new; 6 pre-existing tests updated where they codified the old, non-native shapes).

dn00 added a commit that referenced this pull request Jun 10, 2026
…pe, thinking signature

Closes the consumed-field parity gaps confirmed by replay against the
2026-06-09 goldens (PARITY-GAPS #2/#3/#14/#15/#16), and adds the parity-policy
tiers to PARITY-GAPS.md (contract / consumed fields / on-demand / won't-fix).

- --max-turns now counts assistant API rounds (SSE message_start) like native,
  not user prompts — a single prompt chaining tools can exhaust it. On
  exceeding: interrupt, then report result.error_max_turns (is_error, NO
  result field, num_turns = rounds) and exit 1, even in stream-json mode,
  whether or not the interrupt beat the turn's natural completion. The old
  prompt-count check remains as a fallback for backends without SSE.
- Ack initialize (truthful payload: commands from transcript init,
  output_style, pid) and set_permission_mode (echo mode) using native's
  nested control_response shape {type, response: {subtype, request_id,
  response}}; migrated the interrupt ack from clarp's old flat shape.
- Turn-level backend API errors report subtype "success" with is_error: true
  (invalid-model golden), not subtype "error"; emitResult decouples is_error
  from subtype and can omit the result field (error_max_turns has none).
- Assembler accumulates signature_delta; thinking blocks are {type, thinking,
  signature} like native.
- Exit code now reflects the last result's is_error on stdin-drain shutdown
  (native exits 1 after an invalid-model turn even though the stream ends
  normally).
@dn00 dn00 force-pushed the fix/parity-tier2 branch from 28ad7f3 to fd9335f Compare June 10, 2026 21:47
@dn00 dn00 force-pushed the fix/parity-tier2 branch from fd9335f to 43025d7 Compare June 10, 2026 21:50
dn00 added a commit that referenced this pull request Jun 10, 2026
…pe, thinking signature

Closes the consumed-field parity gaps confirmed by replay against the
2026-06-09 goldens (PARITY-GAPS #2/#3/#14/#15/#16), and adds the parity-policy
tiers to PARITY-GAPS.md (contract / consumed fields / on-demand / won't-fix).

- --max-turns now counts assistant API rounds (SSE message_start) like native,
  not user prompts — a single prompt chaining tools can exhaust it. On
  exceeding: interrupt, then report result.error_max_turns (is_error, NO
  result field, num_turns = rounds) and exit 1, even in stream-json mode,
  whether or not the interrupt beat the turn's natural completion. The old
  prompt-count check remains as a fallback for backends without SSE.
- Ack initialize (truthful payload: commands from transcript init,
  output_style, pid) and set_permission_mode (echo mode) using native's
  nested control_response shape {type, response: {subtype, request_id,
  response}}; migrated the interrupt ack from clarp's old flat shape.
- Turn-level backend API errors report subtype "success" with is_error: true
  (invalid-model golden), not subtype "error"; emitResult decouples is_error
  from subtype and can omit the result field (error_max_turns has none).
- Assembler accumulates signature_delta; thinking blocks are {type, thinking,
  signature} like native.
- Exit code now reflects the last result's is_error on stdin-drain shutdown
  (native exits 1 after an invalid-model turn even though the stream ends
  normally).
dn00 added a commit that referenced this pull request Jun 10, 2026
…pe, thinking signature

Closes the consumed-field parity gaps confirmed by replay against the
2026-06-09 goldens (PARITY-GAPS #2/#3/#14/#15/#16), and adds the parity-policy
tiers to PARITY-GAPS.md (contract / consumed fields / on-demand / won't-fix).

- --max-turns now counts assistant API rounds (SSE message_start) like native,
  not user prompts — a single prompt chaining tools can exhaust it. On
  exceeding: interrupt, then report result.error_max_turns (is_error, NO
  result field, num_turns = rounds) and exit 1, even in stream-json mode,
  whether or not the interrupt beat the turn's natural completion. The old
  prompt-count check remains as a fallback for backends without SSE.
- Ack initialize (truthful payload: commands from transcript init,
  output_style, pid) and set_permission_mode (echo mode) using native's
  nested control_response shape {type, response: {subtype, request_id,
  response}}; migrated the interrupt ack from clarp's old flat shape.
- Turn-level backend API errors report subtype "success" with is_error: true
  (invalid-model golden), not subtype "error"; emitResult decouples is_error
  from subtype and can omit the result field (error_max_turns has none).
- Assembler accumulates signature_delta; thinking blocks are {type, thinking,
  signature} like native.
- Exit code now reflects the last result's is_error on stdin-drain shutdown
  (native exits 1 after an invalid-model turn even though the stream ends
  normally).
@dn00 dn00 force-pushed the fix/parity-tier2 branch from 43025d7 to 6ff23fe Compare June 10, 2026 23:00
dn00 added 2 commits June 10, 2026 16:02
…pe, thinking signature

Closes the consumed-field parity gaps confirmed by replay against the
2026-06-09 goldens (PARITY-GAPS #2/#3/#14/#15/#16), and adds the parity-policy
tiers to PARITY-GAPS.md (contract / consumed fields / on-demand / won't-fix).

- --max-turns now counts assistant API rounds (SSE message_start) like native,
  not user prompts — a single prompt chaining tools can exhaust it. On
  exceeding: interrupt, then report result.error_max_turns (is_error, NO
  result field, num_turns = rounds) and exit 1, even in stream-json mode,
  whether or not the interrupt beat the turn's natural completion. The old
  prompt-count check remains as a fallback for backends without SSE.
- Ack initialize (truthful payload: commands from transcript init,
  output_style, pid) and set_permission_mode (echo mode) using native's
  nested control_response shape {type, response: {subtype, request_id,
  response}}; migrated the interrupt ack from clarp's old flat shape.
- Turn-level backend API errors report subtype "success" with is_error: true
  (invalid-model golden), not subtype "error"; emitResult decouples is_error
  from subtype and can omit the result field (error_max_turns has none).
- Assembler accumulates signature_delta; thinking blocks are {type, thinking,
  signature} like native.
- Exit code now reflects the last result's is_error on stdin-drain shutdown
  (native exits 1 after an invalid-model turn even though the stream ends
  normally).
@dn00 dn00 force-pushed the fix/parity-tier2 branch from 6ff23fe to 6a20c08 Compare June 10, 2026 23:02
@dn00 dn00 merged commit 144ad84 into main Jun 10, 2026
9 checks passed
dn00 added a commit that referenced this pull request Jun 10, 2026
…pe, thinking signature

Closes the consumed-field parity gaps confirmed by replay against the
2026-06-09 goldens (PARITY-GAPS #2/#3/#14/#15/#16), and adds the parity-policy
tiers to PARITY-GAPS.md (contract / consumed fields / on-demand / won't-fix).

- --max-turns now counts assistant API rounds (SSE message_start) like native,
  not user prompts — a single prompt chaining tools can exhaust it. On
  exceeding: interrupt, then report result.error_max_turns (is_error, NO
  result field, num_turns = rounds) and exit 1, even in stream-json mode,
  whether or not the interrupt beat the turn's natural completion. The old
  prompt-count check remains as a fallback for backends without SSE.
- Ack initialize (truthful payload: commands from transcript init,
  output_style, pid) and set_permission_mode (echo mode) using native's
  nested control_response shape {type, response: {subtype, request_id,
  response}}; migrated the interrupt ack from clarp's old flat shape.
- Turn-level backend API errors report subtype "success" with is_error: true
  (invalid-model golden), not subtype "error"; emitResult decouples is_error
  from subtype and can omit the result field (error_max_turns has none).
- Assembler accumulates signature_delta; thinking blocks are {type, thinking,
  signature} like native.
- Exit code now reflects the last result's is_error on stdin-drain shutdown
  (native exits 1 after an invalid-model turn even though the stream ends
  normally).
@dn00 dn00 deleted the fix/parity-tier2 branch June 10, 2026 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant