Send once: a delivery stops repeating what it has already handed over, and says where the context stands - #441
Merged
m2ux merged 7 commits intoAug 7, 2026
Conversation
A response repeats the contract and rules blocks its techniques share. Those blocks now collapse to a marker from their second copy on, and the first copy ships in full, so the bytes a marker stands for are always above it in the same payload — readable by a freshly spawned worker holding no prior delivery. dedupTechniqueBlocks takes readLedger: it consults this scope's earlier deliveries only where the caller asked for reference delivery, and always consults what this response has already staged. Measured over the batch benchmark's three-activity run: a fresh worker per activity receives 213,476 characters where it received 225,617, about 4,000 characters an activity.
A ledger entry says a scope received a payload in full, so a second ask for the same bytes is answered with a marker whatever delivery mode the call declares — the content is in the asking context already. Two conditions keep it sound. The caller must name its context: with agent_id omitted the scope falls back to the session's own identity, which sibling workers share, so a marker could reach a context that never received the bytes. And full: true still serves the whole body, for a context that summarized the content away. One measured run re-sent 67,772 characters over 18 repeat fetches, one of them the same 15,126-character dispatch guidance twice inside 46 seconds.
A worker decides whether to ask for another activity from may_continue, so the answer rides in the response text as a leading batch: block as well as in _meta.batch — the same reason artifact_prefix is in the header. batchState takes a pending delivery, so the standing a response carries counts the activity and characters that response is delivering without composing the payload twice. That keeps the block and _meta reporting one figure. The payload still repeats byte for byte across two identical calls; the standing is live state and moves, which the reference-delivery test now measures over the payload rather than the whole response.
This was referenced Aug 6, 2026
…a marker What to do with may_continue is owned by the worker role technique every activity bundle carries, so the block carries the reading and not a third copy of the instruction. That takes it from 262 characters to 112 on every delivery, which matters on an activity light enough to have no repeated blocks to collapse. The resolution model described one ground for a marker, reference delivery, and asserted twice that a fresh or default session always receives full bodies. There are three grounds now, two of them needing no opt-in because the bytes demonstrably reached the asking context, and the doc sets out which call each one governs.
Naming a context is evidence of one context only where the name belongs to one. dispatch_child defaults agent_id to "worker", which is the session's own identity, so two sibling workers can each pass it without either having received what the other did. That scope keeps its earlier behaviour: it collapses on a declared reference opt-in, which is a claim about one context, and not on the name alone. A solo walk legitimately owns the identity and declares context_mode: "persistent", so it collapses on that ground.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three defects with one theme: content the server has already handed over once. A single response
carried the same rule and contract blocks several times. Two calls asking for the same technique were
each answered in full. And the answer telling a worker whether it may take another activity was
emitted somewhere a worker does not reliably read.
Work items W7, W9 and the server half of W8 of the delivery-cost epic #404. Stacked on #440, which
this branch includes.
A shared block is sent once per response — W7
Every composed technique in a delivery carries the contract blocks and rules it inherits from its
container, so a response bundling five step techniques carried five copies of the same text — 16,453
characters byte-identical in the worst case the review measured. The pass that removes them ran only
where the caller had asked for reference delivery, which is exactly not the case a freshly spawned
worker is in, and that worker is the one whose budget is tightest.
The pass now runs on every delivery, with
readLedgerselecting what a marker may point at:collapses. The bytes are always above the marker in the payload the marker arrives in, so a context
holding nothing can still resolve it.
The response says so. Where a full delivery collapses anything, it carries a note pointing the reader
at the earliest
step_techniquesentry showing that block, rather than the reference-mode note aboutcontent already in the reader's context.
Measured over
npm run bench:batch's three-activity run of the main workflow: a fresh worker peractivity receives 213,476 characters where it received 225,617 — about 4,000 characters an
activity, roughly a thousand tokens a dispatch. The batched pass drops too (161,847 → 152,553),
because a batch's first activity is a full delivery as well.
A repeat fetch arrives as a marker — W9
A ledger entry means one thing: this scope received these bytes in full. So a second ask for the same
content is answered with a marker whatever delivery mode the call declares. One measured run re-sent
67,772 characters over 18 repeat fetches — 12 to 17 per cent of everything it fetched on demand — one
of them the same 15,126-character dispatch guidance twice inside 46 seconds, in one uninterrupted
worker run.
Two conditions keep this sound, and both are tested:
agent_idomitted the scope falls back to the session'sown identity, which sibling workers share — a marker would then reach a context that never received
the bytes. Nothing collapses for an unnamed caller.
full: truestill serves the whole body, which is the escape hatch for a context thatsummarized the content away.
The batch standing arrives where a worker reads it — W8
The field a worker reads to know it may take another activity was emitted in
_meta.batchonly. Onthe 5 August run no context anywhere took a second activity and no refusal was recorded either —
nothing was refused because no continuation was ever attempted. A limit no worker can read is a limit
that cannot bind.
The standing now leads the response text as a
batch:block —activities,max_activities,delivered_chars,budget_chars,may_continue, and a sentence saying what to do with the answer —as well as staying in
_meta.batch. This is the same reasonartifact_prefixis in the responseheader: the text is the surface a worker is certain to read.
batchStatenow takes the pending delivery, so the standing a response carries counts the activityand the characters that response is delivering, without composing the payload twice to find out. The
block and
_metareport one figure, which a test asserts.What this does not establish. That a run then actually forms needs a real session against a
server build carrying this change. The read to make afterwards:
activity_dispatchedevents groupedby
agentId— a scope holding two or more activities is a run that formed — and anybatch_refusedevent, which now means a worker read the standing and asked anyway. The 5 August baseline is four
setup activities under four identities and twelve client activities under thirteen, with no refusal
anywhere.
Scope of change
src/utils/delivery.ts—readLedger,countCollapsedBlocks, and the module contract for whatmakes a marker readable.
src/tools/workflow-tools.ts— the dedup pass on every delivery, the full-mode note, thebatch:block.
src/tools/resource-tools.ts— the repeat-fetch collapse and the two tool descriptions.src/utils/batch.ts—batchStatetakes a pending delivery.docs/dispatch_model.md— where the standing is reported.tests/send-once.test.ts(new, 9 tests),tests/reference-delivery.test.ts(two tests restated).No schema change.
Two restated tests, and why
Two assertions in
tests/reference-delivery.test.tsencoded the behaviour this branch changes, sothey now assert the new contract rather than being suppressed:
references content from an earlier call, and every composed technique still arrives whole. What it
no longer does is repeat a shared block within one response. The byte-identity assertion now
compares the payload rather than the whole response, because the batch standing that leads it is
live state and moves by design.
assertions that carry W9's contract: a named context asking twice gets a marker, an unnamed caller
never does.
Verification
npx tsc --noEmitclean.npm run bench:batchreports the figures quoted above.Non-goals
it lands on top of this.
spent sending resource bodies the first delivery could not afford — that is the budget working.
Investigation detail
engineering/artifacts/planning/2026-08-06-startup-cost-on-real-runs
— the repeat-fetch tables and the batching-formed-no-run finding.
engineering/artifacts/planning/2026-08-04-solid-affinity
— the duplicate-block measurement and why no relevance threshold was added.