Skip to content

The frame bound follows the slice bound, not the context window - #191

Merged
OpenCnid merged 1 commit into
masterfrom
d/frame-and-slice-caps-relayered-4c71a8
Jul 24, 2026
Merged

The frame bound follows the slice bound, not the context window#191
OpenCnid merged 1 commit into
masterfrom
d/frame-and-slice-caps-relayered-4c71a8

Conversation

@OpenCnid

Copy link
Copy Markdown
Owner

Owner ruling, 2026-07-24: 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 again.

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; 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. 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. Both numbers were individually plausible; only their relationship was wrong, and nothing in the tree compared them.

The layering installed

what is bounded question constant
REPL namespace how large a corpus? Tier0Limits.address_space_bytes (1 GiB)
one slice host store to guest namespace BrokerCaps.max_result_bytes (2 MiB)
model attention what reaches the transcript MarshalCaps (20 KiB stdout, 64 KiB answer)
one wire message how large is a frame 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_bytes is the single lever for bulk transfer; the frame follows it.

The DoS property is independent 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.

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

  • pytest 1,036 to 1,042; vitest 1,416 / 119.
  • The new invariants were 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.
  • check:repo-surface PASS (0 issues); wiki:check --check-html PASS.

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.
@OpenCnid
OpenCnid merged commit 614f83c into master Jul 24, 2026
3 checks passed
@OpenCnid
OpenCnid deleted the d/frame-and-slice-caps-relayered-4c71a8 branch July 24, 2026 20:55
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