Skip to content

transport: the framer's head piece states its declared body length (declared_len), for 1.5.5's pre-body download cap - #1032

Merged
MattJackson merged 2 commits into
predevfrom
lane-conn-declared-len
Oct 15, 2026
Merged

MattJackson merged 2 commits into
predevfrom
lane-conn-declared-len

Conversation

@MattJackson

@MattJackson MattJackson commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Why (ARCHITECT ruling, 1.5.5 parity)

1.5.5's plugins.fetch downloader refused an honest over-cap declared length before reading any body byte: "GET {url}: declared Content-Length {len} exceeds the {cap}-byte plugins.fetch download cap" (v1.5.5 source; the same text sits in predev's crates/busbar-kernel/src/preflight.rs today). In 1.6.0 the download moves onto the host connector (#805, crates/busbar-core-connector/src/fetch.rs), and the connector cannot see the declared length:

  • the head field block never carries it: crates/busbar-contract/src/abi/transport/fields.rs:14-16 says the framer drops it because the pieces carry the body the framer already unframed;
  • busbar_contract::conn::Piece had no length field.

fields.rs:14-16 stays true. The declared length is not a field and never enters the block. It travels as its own typed value on the head piece, the way code and retry_after_secs already do.

The change

A neutral declared_len: "the body length the message's head declared on the wire, if it stated one". It is a statement, not a count of delivered bytes.

  • Transport ABI abi::transport::FramePiece appends declared_len: u64 at offset 40 (size 40 -> 48). It is present under the new flag PIECE_HAS_DECLARED_LEN = 128, the HAS-flag encoding code/retry_after_secs use (absent = flag clear, value 0). This is a pre-release layout change and the transport ABI version is unchanged (ARCHITECT). tests/golden/abi-layout.golden, tests/layout_golden.rs and include/busbar_plugin.h are updated together (#define, struct field, size and offset asserts, in the generator's format). check_framer admits the bit only on a field block; anywhere else it is framer.piece.declared_len_not_fields.
  • SDK sdk_hyper::Piece gains declared_len: Option<u64>, and fill sets the flag and value, so a Rust framer states it.
  • Connection table conn::Piece gains declared_len: Option<u64>. Its mechanical lowering abi::host::conn::WirePiece appends declared_len at offset 72 (72 -> 80) under WirePiece flag PIECE_HAS_DECLARED_LEN = 4, so a plugin reading the table sees it too.
  • Connector carries it from the framer's piece (Got) into the table's piece untouched, with no interpretation. Every other piece literal in the workspace names it absent.

RED

  • busbar-core-connector connector_tests::a_framers_declared_body_length_reaches_the_tables_head_piece: a TestDoor framer (new fields / declared_len knobs), driven over a real loopback far end through the connector's table, states 2^40 on its head field block. The table's Fields piece carries declared_len == Some(2^40). A framer stating none yields None.
  • conn_lowering_tests::every_operation_crosses_the_lowering: it crosses the WirePiece lowering both ways (Some/None).
  • sdk_hyper fill_states_a_heads_declared_length_where_it_declared_one.
  • transport_check_tests::a_declared_length_rides_a_field_block_only.
  • The layout golden and the header stay in sync (layout_golden, abi-header).

No skip, no #[ignore].

Next

#805's fetch.rs consumes Piece::declared_len to refuse an over-cap download before the first body byte. No oracle cell covers the over-cap refusal; the url cell is egress.fetch|plugins|url.

Why every transport plugin repins past this (row 81)

FramePiece grows 40 -> 48 bytes and WirePiece 72 -> 80. Both are array-element / out structs, so the stride changes. No check crosses the host/plugin boundary for them: FramePiece has no size field and each side only asserts its own build (const _: () = assert!(size_of::<FramePiece>() == ..)); WirePiece.size is written by the host and validated by no plugin; the loader (plugin-loader dispatch/load.rs table::<K>) checks only the ops table's slots/size. A transport framer built at an older pin and dropped in would therefore mis-stride the piece arrays while passing the unchanged ABI version check. Pre-tag, appends are guarded by the layout golden without a version bump (BUSBAR-1.6.0.md l.1211; R9), so the guard is row 81: every roster transport plugin (tcp, stdio, webrtc; http/ws/grpc with their door changes) is repinned past this commit.

…eclared_len)

ARCHITECT ruling (1.5.5 parity, plugins.fetch's pre-body download cap): 1.5.5 refused an honest
over-cap declared body length before reading a body byte. In 1.6.0 the download runs on the host
connector, which sees only the table's pieces: the head field block never carries the declared
length (abi::transport::fields, its own rule, unchanged), and conn::Piece had no field for it.

The framer's HEAD piece gains a neutral declared_len, "the body length the message's head declared
on the wire, if it stated one":

* abi::transport::FramePiece appends `declared_len: u64` @40 (size 40 -> 48), present under the new
  flag PIECE_HAS_DECLARED_LEN = 128, the encoding `code` and `retry_after_secs` already use.
  Pre-tag v1 layout edit, transport ABI version unchanged; abi-layout.golden, layout_golden.rs and
  include/busbar_plugin.h updated together. check_framer admits the bit, on a field block only
  (framer.piece.declared_len_not_fields otherwise).
* sdk_hyper::Piece gains `declared_len: Option<u64>`; fill sets the flag and value.
* conn::Piece gains `declared_len: Option<u64>`, lowered as WirePiece.declared_len @72 (72 -> 80)
  under WirePiece PIECE_HAS_DECLARED_LEN = 4, so a plugin reading the table sees it too.
* busbar-core-connector carries it from the framer's piece (Got) into the table's piece untouched;
  every other piece literal names it absent.

RED: connector_tests::a_framers_declared_body_length_reaches_the_tables_head_piece (a TestDoor
framer over a real far end states 2^40 on its head field block; the table's Fields piece carries
Some(2^40); a framer stating none yields None). Also conn_lowering_tests (it crosses the WirePiece
lowering), sdk_hyper fill_states_a_heads_declared_length_where_it_declared_one, and
transport_check_tests a_declared_length_rides_a_field_block_only.
MattJackson added a commit that referenced this pull request Oct 14, 2026
… base, so it compiles against #787's FramePiece (fault in the old _reserved byte)

#787's FramePiece states the framer's fault reading in the byte that was `_reserved` (the breaker
plane-fault work); the datagram rig landed on predev against the old layout and named
`_reserved: 0`, which #787's tree does not have (E0560). FramePiece has no constructor or Default,
so the literal names the four fields the rig sets and takes the rest from an all-zero piece (code,
status class, FAULT_NONE, no retry), as the contract and loader tests' `z()` pieces do. An appended
field (#1032's declared_len) no longer breaks it. Every other FramePiece and WirePiece literal in
the tree was checked: the rest are built from `z()` or already name the current fields.
… appended declared_len at zero

compile/clippy/test were red on busbar-transport-ws (pinned f8ba71d), whose door builds a FramePiece
literal field by field and so missed the appended declared_len. The pin moves to 140691cf2e, f8ba71d
plus one change: the literal ends in `..std::mem::zeroed()` (FramePiece is plain repr(C) integers;
zero is every field's absent value), so this and any later append compile. The framer states no
declared length. ws's own dev carries the off-line door changes (#1012/#1019) and repins with them.
MattJackson added a commit that referenced this pull request Oct 15, 2026
…formance host and a connector test sink were written against the piece before #1032 named its padding fault and appended declared_len (E0560)
@MattJackson
MattJackson merged commit 19e2045 into predev Oct 15, 2026
1 check was pending
@MattJackson
MattJackson deleted the lane-conn-declared-len branch October 15, 2026 05:33
MattJackson added a commit that referenced this pull request Oct 15, 2026
- busbar-plane-llm tests: WholeCtx and ReplyCtx initializers state translate_cap (the default
  cap, as the in-crate tests already do), the reply rig's Piece copy carries tap_fault, and the
  dialect's auth-failure status is already a u16 (no as_u16) (#1030/#1031 against the rehomed
  exchange tests).
- busbar build.rs: a test-linked door row's module is the one its plane-door row names in
  linked-entry (busbar_plane_a2a::agent_door, busbar_plane_mcp::plane_door), not an assumed
  <crate>::plane_door (E0433 in out/test_linked.rs after FLIP-A2A).
- root serve_door_far: the far end's conn::Piece states declared_len (#1032).
- root serve_tests session_door: DoorReach takes its secret seam as a shared Arc (#787's
  per-hop credential re-resolution).
MattJackson added a commit that referenced this pull request Oct 15, 2026
… the framer repin past #1032; token-sealed's new red

From ModernCI's nextest log at predev f4eb715 (8c1c308c) and its gates log (f50fb550):

Two lanes meeting:
- busbar config_validate_cross_plane: a present card is held to every registration the section
  bills, keyed <first scope kind>:<name> (DoorSection ledger lanes, d1be722); the cell's row was
  keyed `lane:`. Its row is now the registration's lane (BUSBAR-1.6.0.md l.2226, #42; #77(5)).
- busbar Book is boot-only: the credential refresher's own `book()` (door_steps) read as a call of
  root::boot::book; renamed kept_book. The one boot call stays main.rs's.
- busbar gauntlet_kernel: served_rider_chains_what_it_audits / _charges_the_presenting_key were
  cited only by the a2a and streaming root cells, which FLIP-A2A/FLIP-STREAMING re-pointed to their
  door legs; cited by nobody, they are dropped as U14 (686b91e) dropped mcp's two.
- busbar plane_host_universal_purity: with a2a and streaming served through their doors (a plugin
  reaches busbar only over the ABI, BUSBAR-1.6.0.md l.2179, Part 2 #2) one in-root plane is left,
  so clock_now_secs has one caller: allowlisted with its reason, and the detector's multi-plane
  class is proved over the same counter on two planted plane sources.
- busbar-contract feature_invariance: #65 made acquire_for_kernel dev-only; it is spelled
  #[cfg(feature = "test-seal")] and named in TEST_SEAL_ITEMS (no contract cfg(test) code calls it).
- busbar-contract / busbar-plane-a2a: the design cited in words, not section signs.
- xtask ledger_merge: [[shape-word]] (#787's reservation table) has its identity
  (word, file, holder), as duplicate-shape-word keys it.
- xtask reachability selftest: #935's plane-crates row reads the root manifest's pins; the green
  fixture tree gains its root Cargo.toml (no pins: all five plane crates are laid).
- busbar-core-connector fetch: the pre-body cap reads the head piece's declared_len (#1032); the
  field block never carries content-length, so the old lookup could not fire.
- busbar root model_egress: pools_of registers the neutral test plane before parsing models/pools,
  as bf08115 did for the timeout cells (nextest: one process per test).

A test wrong on its own head:
- busbar-core-connector listen: the framer entry's listener rides the address carrier, so the
  view lays one beside it (TestDoor::identity("carrier")), as the connector's other cells do.
- busbar-plane-llm conformance: an openai caller's head carries no anthropic-version, whose
  header claim outranks the chat-completions path claim (1.5.5's detection order).
- busbar-plane-llm exchange_reply: never the far body; the far sentence is checked except where it
  is the caller dialect's own refusal sentence, which the envelope equality pins.
- busbar-plane-streaming broker: the pre-X-2204 assertion that an expiry-less ek_ answer reads as
  0 is struck; X-2204 refuses it (a_minted_answer_with_no_stated_expiry_is_refused).

Gates: token-sealed's red was seal_release_path.rs minting a Pass outside crates/busbar-kernel/src;
the release-path witness holds the seal and mints nothing.

Not fixed here: universal_needs x8 are the pinned http framer built against a pre-#1032 contract
(40-byte FramePiece against the host's 48); they go green with lane-transport-repin-1032.
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