Skip to content

Deliver Card activation in budgeted pieces and earn the delivery claim - #131

Merged
KimGLee merged 3 commits into
mainfrom
feat/activation-transport-budget
Aug 22, 2026
Merged

Deliver Card activation in budgeted pieces and earn the delivery claim#131
KimGLee merged 3 commits into
mainfrom
feat/activation-transport-budget

Conversation

@KimGLee

@KimGLee KimGLee commented Aug 22, 2026

Copy link
Copy Markdown
Owner

The gap this closes

K13/19 requires an activation payload to have entered a worker's execution context before a runtime may call it running. Its Execution-context Delivery section claimed an admission proved exactly that:

This proves that the exact tool-result payload entered the named host session.

It did not. The claim was minted before the result left the server, so a host that externalizes an oversized tool result left the payload outside the model context while the receipt still asserted machine delivery — and no gate could observe the divergence.

A 2026-08-22 measurement against a live host made it concrete. Server delivery was complete and all 23 content hashes matched, but the single 231,164-byte result was spilled to a file and only a 2KB preview reached the model. The divergence was noticed by accident, because a test session happened to report the host's spill marker. No production path would have caught it.

What changes

card-first-readback-v3. Admission stops embedding bytes and freezes a piece manifest instead — one record per deliverable file with its hash and size. The bytes travel afterwards through --deliver-activation-piece, one file per tool result, inside MAX_ACTIVATION_PIECE_ENVELOPE_BYTES (49152). The measured object is the serialized delivery, not the source file: 50,495 bytes of Card source arrived as a 231,164-byte result, so envelope overhead exceeded the payload itself. Admission fails closed when any frozen piece would exceed the budget, which turns an oversized leaf into a governance problem at its own boundary rather than a transport accident mid-batch.

A piece is always a whole file. Splitting one across results would break the only check the receiving end can make: the frozen hash binds the complete file, a model cannot rehash fragments, and no party could prove a reassembly was faithful.

Admission no longer claims delivery. It records host-bound or prepared. Completion is earned per piece: each delivery carries a single-use nonce after the content, returned by --ack-activation-piece from the same context. The nonce is one part of three and never the whole — a host can show a head-and-tail summary, keep structural fields while externalizing content, or leave an agent reading a spilled file's tail. Only the server hash, a conformant adapter, and the ack together are delivery evidence. The protocol says so in those words, so a later reader cannot mistake a returned nonce for a proof of presence.

queued -> open stops binding the host session. That v1-era rule protected a claim v3 no longer makes there, and keeping it would re-couple the Queue lifecycle to the context lifecycle K13/19 separates. open still proves the frozen Bundle equals current bytes; the context binding moves to the new delivery gate. Sealed v1/v2 receipts replay under their own shape.

New leaf K13/20 Assignment State and Delivery Gate. pending → delivering → delivered → running, where delivered requires the ack set to equal the frozen manifest exactly, every ack to bind the same assignment/context/bundle/attempt, and the adapter to resolve to a current conformance registration. Delivery evidence never transfers between contexts. The admission criteria for a new leaf were answered before writing it, and are in the commit message.

Conformance is measured, not assumed. Tools/tests/inline_probe_server.py returns a payload of an exact size with a nonce at its very end; host_conformance_probe.py emits the two-control procedure and judges the result. Both controls are mandatory — a positive result alone certifies nothing, because a probe that cannot fail cannot certify.

Measured against Claude Code 2.1.223:

payload tail nonce externalized control
49152 B (= budget) present no positive passes
57344 B absent yes negative passes
65536 B absent yes negative passes

That result carries a warning, recorded in the registry: the inline ceiling sits between 49152 and 57344 bytes, so the budget has no headroom. Raising MAX_ACTIVATION_PIECE_ENVELOPE_BYTES without re-measuring would not make this adapter refuse a larger piece — it would silently externalize it, restoring the exact failure mode v3 removes.

Scope, stated plainly

This is Core-ready, not a closure. K13/20 is normative text; the Assignment state machine has no executable implementation because no reference runtime exists to host it. The primitives it consumes — piece delivery receipts, acks, and the frozen piece set — are implemented and tested, so landing a runtime is wiring rather than design. The host-side remainder of D-008 stays open until a runtime enforces delivered → running.

Why one PR and not three

The design split this into three PRs, one per layer. The implementation collapsed layers 1 and 2 into one governance decision, and the reason is measurable rather than a matter of taste: v3's own text says completion is earned at the K13/20 gate, so layer 1 carries three wiki links to a page layer 2 introduces. Checked out alone, layer 1 fails wiki-link-integrity with missing=3. An intermediate state that fails a registered gate must not reach main, so the two land together. Layer 3 is separable but small, and splitting it would leave the receipt template referencing a registry that does not exist yet.

Connected closure

Every capability implementation's SHA is pinned in Tools/compiled/metadata-execution-contract.json, so changing these tools without regenerating the compiled artifacts fails profile-load and cascades — one run showed 1061 of 2029 tests failing from that single root cause. Regenerated here: metadata-execution-contract, cli-contract, mcp-tools, and the five host-config products. check_queue's producer version moves to 1.25.0 in K00/12 for its changed accept set.

Adding the Budgeted Piece Delivery section pushed K13/19 past its registered 7.5KB cap and stamp_cards --check refused it. That is the mechanism working, so the cap was raised to 11KB through K00/16 with its reason and re-split condition recorded, rather than worked around. The section was deliberately not split further: a reader who had the byte budget without the conformance requirement would conclude that a small result is a proven one, which is the error this protocol exists to remove. K13/20 enters the R01 and R07 loading boundaries, both Cards give it an explicit source_files disposition, and R01/R07/R09 were regenerated and re-stamped.

Verification

make check                        pass
Tools/tests/test_card_activation  21/21
Tools/tests/test_host_conformance 9/9
Tools/tests/test_check_queue      166
Tools/tests/test_update_queue     181
Tools/tests/test_mcp_server       71
full suite                        2106 tests

The full suite reports 3 failures, all from an unrelated uncommitted README/ROADMAP rewrite in the working tree that pins text in README.zh-CN.md. These commits touch only Tools/ and kernel/; git diff --name-only confirms no README, ROADMAP, or profiles/ path is included. CI on a clean checkout should be green.

Closes #132

KimGLee and others added 3 commits August 22, 2026 13:33
K13/19 required an activation payload to have entered a worker's execution
context before a runtime may call it running, and the Execution-context
Delivery section claimed an admission proved exactly that. It did not. The
claim was minted before the result left the server, so a host that
externalizes an oversized tool result left the payload outside the model
context while the receipt still asserted machine delivery, and no gate could
observe the divergence.

A 2026-08-22 measurement against a live host made the gap concrete: server
delivery was complete and every hash matched, but the 231,164-byte single
result was spilled to a file and only a 2KB preview reached the model. The
divergence was noticed by accident.

v3 stops embedding bytes in the admission result. Admission freezes a piece
manifest -- one record per deliverable file with its hash and size -- and the
bytes travel afterwards through --deliver-activation-piece, one file per tool
result, inside MAX_ACTIVATION_PIECE_ENVELOPE_BYTES. The measured object is the
serialized delivery, not the source file: 50,495 bytes of Card source arrived
as a 231,164-byte result, so envelope overhead exceeded the payload. Admission
fails closed when any frozen piece would exceed the budget, which turns an
oversized leaf into a governance problem at its own boundary instead of a
transport accident mid-batch.

A piece is always a whole file. Splitting one across results would break the
only check the receiving end can make: the frozen hash binds the complete
file, a model cannot rehash fragments, and no party could prove a reassembly
was faithful.

Admission now records host-bound or prepared. Neither claims delivery.
Completion is earned per piece: each delivery carries a single-use nonce after
the content, returned by --ack-activation-piece from the same context. The
nonce is one part of three and never the whole -- a host can show a head-and-
tail summary, keep structure while externalizing content, or leave an agent
reading a spilled file's tail. Only the server hash, a conformant adapter, and
the ack together are delivery evidence.

The v1/v2 same-session consumption rule at queued -> open is retired. It
protected a claim v3 no longer makes there, and keeping it would re-couple the
Queue lifecycle to the context lifecycle K13/19 separates. open still proves
the frozen Bundle equals current bytes; the context binding moves to the
Assignment delivery gate. Sealed v1/v2 receipts replay under their own shape.

mcp_server now exports the host's declared clientInfo alongside the execution
context id, so delivery evidence can bind the adapter build it ran against
rather than inheriting a registration a later update invalidated.

Also connected: every capability implementation's SHA is pinned in
Tools/compiled/metadata-execution-contract.json, so changing these tools
without regenerating the compiled artifacts fails profile-load and cascades
through the suite. metadata-execution-contract, cli-contract, mcp-tools and
the host-config products are regenerated here; check_queue's producer version
moves to 1.25.0 in K00/12 for the changed accept set.

Tests: test_card_activation 21/21, full suite 2106 tests with 3 pre-existing
failures that belong to an unrelated uncommitted README rewrite. make check
passes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
open means a batch is admitted and its partition reserved. It does not mean
any worker holds the Cards. Before this leaf the distance between those two
facts was unmeasured: a runtime could call a worker running on the strength of
an admission receipt, and the 2026-08-22 host measurement showed that failure
reaching production with nothing able to detect it.

This module owns the mapping between one admitted batch and one temporary
execution context, and the gate that decides when that context may be called
running. K13/19 owns what is delivered and how one piece is proven; this owns
whether enough of it arrived. It is not a second Queue -- no work list, no
batch lifecycle, no completion semantics -- and it is discarded when its
context ends while the batch survives. That separation is why the two
lifecycles can fail independently: losing the context loses the delivery
evidence and nothing else.

delivering -> delivered requires the ack set to equal the frozen piece
manifest exactly, every ack to bind the same assignment, context, bundle hash
and attempt, and the host's declared adapter identity to resolve to a current
inline-delivery conformance registration. Only delivered admits running. A
runtime that cannot reach it records degraded and may not claim machine-
enforced Card delivery; Queue open is unaffected, since a human integrator
admits batches with no Assignment at all.

Delivery evidence does not transfer. A new context, a reassignment, a reopened
batch, a new bundle hash or a revised Profile contract each start a new
attempt and void every earlier ack. Re-delivery is idempotent reading; a
transferable ack would let a context claim delivery it never received.

The gate proves the frozen bytes were delivered within budget to a conformant
adapter and acknowledged from the same context. It does not prove the worker
read, understood, or will obey them, and no field here asserts that.

The admission criteria were answered before writing it: no existing module
owns this (K13/19 explicitly creates no ledger, K13/10 is Queue-side, K13/01
has no per-context object); its rules change without touching Queue lifecycle
or Bundle compilation; both one-sided loads are real (a resuming worker needs
delivery rules without Queue-write rules, a CLI integrator needs the reverse);
and the measurable change is that running moves from zero enforceable gates to
a set-equality predicate.

Connected closure: the leaf enters the R01 and R07 loading boundaries, both
Cards give it an explicit source_files disposition and were regenerated and
re-stamped, and K13/19's size cap rises from 7.5KB to 11KB in K00/16 with its
reason recorded. That section was not split further on purpose -- a reader who
had the byte budget without the conformance requirement would conclude a small
result is a proven one, which is the error v3 exists to remove.

Scope, stated plainly: this is normative text. The Assignment state machine
has no executable implementation because no reference runtime exists to host
it. The primitives it consumes -- piece delivery receipts, acks, and the
frozen piece set -- are implemented and tested, so landing a runtime is wiring
rather than design.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A server can prove what it sent and an ack can prove which context answered.
Neither can see what the host did in between, and that gap is the failure
card-first-readback-v3 exists to catch. It is now measured against a live
adapter rather than assumed.

inline_probe_server returns a payload of an exactly requested size with a
nonce at its very end. It touches no corpus: the subject under test is the
adapter, not Cambium state. host_conformance_probe emits the exact two-control
procedure and judges the observations.

Both controls are mandatory. The positive one requires a payload of exactly
minimum_bytes to arrive whole, proven by the model reporting the trailing
nonce. The negative one requires a larger payload to be OBSERVED as
externalized. A positive result alone certifies nothing -- a probe that cannot
fail cannot certify -- and the probe reports that case as its own failure.

Measured against Claude Code 2.1.223 on 2026-08-22: 49152 bytes arrived inline
with the tail nonce intact, while 57344 and 65536 bytes were both spilled to a
persisted-output file with the nonce absent. So the adapter meets the budget,
and the probe demonstrably detects the failure it rules out.

That result carries a warning, recorded in the registry: the inline ceiling
sits between 49152 and 57344 bytes, so the budget has no headroom above it.
MAX_ACTIVATION_PIECE_ENVELOPE_BYTES must not be raised without re-measuring --
this adapter would not refuse a larger piece, it would silently externalize
it, restoring the exact failure mode v3 removes.

Registration binds the declared clientInfo name and a version range because
hosts update themselves underneath a passing test; an unlisted build degrades
rather than inheriting a stale pass. Absence from the registry is a statement
about measurement, not about quality.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@KimGLee KimGLee added bug Something isn't working enhancement New feature or request documentation Improvements or additions to documentation agent-interface Host-neutral agent interface: contract, projection, MCP server, per-host configs labels Aug 22, 2026
@KimGLee
KimGLee merged commit 5a3d920 into main Aug 22, 2026
12 checks passed
@KimGLee
KimGLee deleted the feat/activation-transport-budget branch August 22, 2026 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-interface Host-neutral agent interface: contract, projection, MCP server, per-host configs bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prevent oversized Card activation results from falsely claiming machine delivery

1 participant