Summary
When a model emits an approval-gated call together with other calls, Atomic correctly isolates the first gated call, but it discards every sibling payload and asks the model to regenerate them on the next step. This preserves the approval boundary but costs an avoidable inference and loses the exact original arguments.
This is the residual form of finding §5 from Yabloko Labs' evaluation. Current v0.1.73 improved the old repair path by mechanically trimming the batch, but the dropped-call behavior remains explicit.
Current behavior
tryTrimApprovalGated keeps only the first approval-gated call and records every other call as dropped:
The next-step notice tells the model to emit those calls again:
Observed pattern:
[approval-gated write, read-back verification]
→ execute write alone
→ drop read payload
→ spend another model step reconstructing the read
Proposed behavior
Treat approval-gated calls as ordered barriers rather than selecting one call and dropping the rest.
The retained-barrier path is eligible only when the original batch size is at most maxParallelToolCalls and every call can be preflighted. Every oversized batch containing an approval-gated or other non-pure_read call must go through fail-closed repair. Deterministic cap splitting is reserved for the all-pure_read case tracked in #111.
For an eligible batch:
- Preflight every call against the registry, resource class, and argument schema before executing any retained work.
- Walk prefixes and approval barriers in array order.
- Execute each valid batchable prefix using the existing resource-class planner and wait for the prefix to settle.
- Execute the following approval-gated call alone.
- Continue with later calls only if that barrier was approved and completed successfully.
- On denial, failure, or cancellation, invalidate all unexecuted later calls.
reply and finish should not be automatically replayed through this mechanism. A batch containing terminal calls, invalid arguments, unknown tools, an oversized original payload, or another non-preflightable shape should remain on the existing fail-closed repair path.
Acceptance criteria
- Ordered-barrier retention is ineligible when the original batch exceeds
maxParallelToolCalls.
- Every retained call passes registry, resource-class, and argument-schema validation before partial execution begins.
- Prefixes and approval barriers are processed in array order, and every prefix fully settles before its following barrier; calls within a prefix retain existing class-aware concurrency, global batch indexes, and ordered result correlation.
- Calls after a barrier retain their original payloads and run only after approval and successful completion.
- Denial, gated-tool failure, turn cancellation, or session cancellation invalidates all unexecuted later calls.
- Subsequent approval-gated calls remain separate barriers and surface their own approval requests.
reply and finish are excluded from automatic retained-call replay.
- An oversized
[approval_gated, pure_read, ...] batch triggers parse_retry; no original call is dispatched before a valid repaired response.
- The runtime does not need another LLM completion solely to reconstruct eligible, already parsed, and validated calls.
- Events/metrics report completed waves, approval barriers, retained count, and invalidated count.
- Regression tests cover a gated call in first and non-first position, invalid sibling arguments, terminal siblings, multiple gates, an oversized approval batch, denial, tool failure, and cancellation.
Summary
When a model emits an approval-gated call together with other calls, Atomic correctly isolates the first gated call, but it discards every sibling payload and asks the model to regenerate them on the next step. This preserves the approval boundary but costs an avoidable inference and loses the exact original arguments.
This is the residual form of finding §5 from Yabloko Labs' evaluation. Current v0.1.73 improved the old repair path by mechanically trimming the batch, but the dropped-call behavior remains explicit.
Current behavior
tryTrimApprovalGatedkeeps only the first approval-gated call and records every other call as dropped:step-executor.tsThe next-step notice tells the model to emit those calls again:
step-executor.tsObserved pattern:
Proposed behavior
Treat approval-gated calls as ordered barriers rather than selecting one call and dropping the rest.
The retained-barrier path is eligible only when the original batch size is at most
maxParallelToolCallsand every call can be preflighted. Every oversized batch containing an approval-gated or other non-pure_readcall must go through fail-closed repair. Deterministic cap splitting is reserved for the all-pure_readcase tracked in #111.For an eligible batch:
replyandfinishshould not be automatically replayed through this mechanism. A batch containing terminal calls, invalid arguments, unknown tools, an oversized original payload, or another non-preflightable shape should remain on the existing fail-closed repair path.Acceptance criteria
maxParallelToolCalls.replyandfinishare excluded from automatic retained-call replay.[approval_gated, pure_read, ...]batch triggersparse_retry; no original call is dispatched before a valid repaired response.