The frame bound follows the slice bound, not the context window - #191
Merged
Conversation
Owner ruling, July 24 2026: max_result_bytes 2 MiB, max_frame_len 4 MiB, and the frame is derived from the slice. tests/test_config.py asserts max_frame_len >= 2 * max_result_bytes so the pair cannot diverge silently. This corrects a layer, not a number. A previous edition derived MAX_FRAME_LEN from the worker's context window -- half of gpt-5.4's 1,050,000 tokens at ~4 bytes each -- so that no single frame could context-saturate its worker. The rule is sound and the layer was wrong, with two consequences. It protected nothing. A slice does not reach the model's attention by landing in the guest namespace; MarshalCaps holds that independently and an order of magnitude lower. Measured: a 12 MiB value in the namespace produces a ~4 KB exec reply, because the marshaller describes the value (4 KiB repr plus a spill handle) rather than carrying it. And it broke a live path. It left the frame cap at 2 MiB while BrokerCaps.max_result_bytes was 8 MiB, so a result the broker considered legal could not cross the wire at all. Both numbers were individually plausible; only their relationship was wrong, and nothing in the tree compared them. The layering the ruling installs, four bounds answering four questions: REPL namespace how large a corpus? Tier0Limits.address_space_bytes one slice host store -> guest? BrokerCaps.max_result_bytes model attention what reaches the transcript? MarshalCaps one wire message how large is a frame? DEFAULT_MAX_FRAME_LEN The REPL is meant to be large -- potentially gigabytes -- and read in slices. No bound above constrains that; the corpus ceiling is address space. The token derivation survives as the way the SLICE is chosen, "about what one model pass could consider", and is recorded as a sizing convention rather than an enforcing bound, because treating it as enforcing is the error being corrected. Cost stated where the constant lives: a 2 MiB slice means ~500 round trips per GB. max_result_bytes is the single lever for bulk transfer and the frame follows it. The DoS property is independent of all of this and always held: read_frame compares the declared length before reading a body, so a frame declaring 4 GiB is refused for four bytes and a hostile peer must actually send what it claims. Frame size was never protecting memory. CONFORMANCE section 2.3 closes with the ruling and preserves the evidence that produced it, annotated: its method was right and only its inputs moved. INTERFACES section 9 item 3 closes. Density-trellis C12 updated alongside. Verified: pytest 1036 -> 1042; the new invariants watched failing against the exact historical configuration (slice 8 MiB, frame 2 MiB), which reddens four of the six including the fit check written for it; vitest 1416/119; check:repo-surface PASS (0 issues); wiki:check --check-html PASS.
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.
Owner ruling, 2026-07-24:
max_result_bytes2 MiB,max_frame_len4 MiB, and the frame is derived from the slice.tests/test_config.pyassertsmax_frame_len >= 2 * max_result_bytesso the pair cannot diverge silently again.This corrects a layer, not a number
A previous edition derived
MAX_FRAME_LENfrom the worker's context window — half ofgpt-5.4's 1,050,000 tokens at ~4 bytes each — so that no single frame could context-saturate its worker. The rule is sound; the layer was wrong, and it had two consequences.It protected nothing. A slice does not reach the model's attention by landing in the guest namespace.
MarshalCapsholds that independently and an order of magnitude lower. Measured: a 12 MiB value in the namespace produces a ~4 KBexecreply, because the marshaller describes the value (4 KiB repr plus a spill handle) rather than carrying it.And it broke a live path. It left the frame cap at 2 MiB while
BrokerCaps.max_result_byteswas 8 MiB, so a result the broker considered legal could not cross the wire. Both numbers were individually plausible; only their relationship was wrong, and nothing in the tree compared them.The layering installed
Tier0Limits.address_space_bytes(1 GiB)BrokerCaps.max_result_bytes(2 MiB)MarshalCaps(20 KiB stdout, 64 KiB answer)DEFAULT_MAX_FRAME_LEN(4 MiB)The REPL is meant to be large — potentially gigabytes — and read in slices. No bound above constrains that; the corpus ceiling is address space. The token derivation survives as the way the slice is chosen — "about what one model pass could consider" — recorded as a sizing convention, never an enforcing bound, because treating it as enforcing is the error being corrected.
Cost stated where the constant lives: a 2 MiB slice means ~500 round trips per GB.
max_result_bytesis the single lever for bulk transfer; the frame follows it.The DoS property is independent and always held:
read_framecompares the declared length before reading a body, so a frame declaring 4 GiB is refused for four bytes and a hostile peer must actually send what it claims. Frame size was never protecting memory.Records
CONFORMANCE§2.3 closes with the ruling and preserves the evidence that produced it, annotated — its method was right and only its inputs moved, so 16 MiB became 4 MiB when the slice went 8 MiB to 2 MiB.INTERFACES§9 item 3 closes. Density-trellis C12 updated alongside.Verification
pytest1,036 to 1,042;vitest1,416 / 119.check:repo-surfacePASS (0 issues);wiki:check --check-htmlPASS.