Skip to content

transport stage B: carriers over the host's I/O (tcp, stdio), the connector drives every connection through a carrier - #502

Merged
MattJackson merged 55 commits into
predevfrom
p2-transport-carrier
Oct 12, 2026
Merged

MattJackson merged 55 commits into
predevfrom
p2-transport-carrier

Conversation

@MattJackson

@MattJackson MattJackson commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Stage B of the transport stack: every connection rides a carrier over the host's I/O.

What changes

  • Host I/O table (io.*) — new memory-ABI table in busbar-contract/src/abi/host/io.rs: open, listen, accept, read, write, ready, shut, close, spawn and ends. The host owns every OS handle, and a plugin holds only an opaque handle that it owns. The layout golden and the C header are regenerated, and the trait-to-slot coverage test is extended to carriers and framers.
  • Carriers — tcp and stdio are carriers over io.*, both in their own repos and in-tree. Framers stay sans-IO. The connector builds a stack from a carrier, the optional TLS in connsec, and an optional framer, and drives the carrier through its slots the same way whether the carrier is linked or dropped in. TLS stays in the connector, and upgrades still move the byte stream.
  • Destination guard — the connector admits exactly the pinned address, bind or program for each ticket. Anything else is refused by the host before any system call.
  • Address carrier — the first carrier, in declared order, whose claim serves a port. Declared order is the build's linked rows, then the dropped-in doors in plugins-directory sorted order. There is no process-wide slot: each wire holds a resolver that the root hands it. The choice is pinned by a registry test, and the dropped-in tcp leg asserts that every data worker accepts through the dropped-in carrier, also with the neutral framer declared first.
  • Root listeners — the data and admin listeners accept through the address carrier and hand the socket up to the kernel.
  • Conformance — the suite's carrier script runs on tcp and stdio both ways: linked against dlopen, compared byte for byte, exact crossing counts, red arm kept. The interim "suite refuses a CARRIER role" guard is removed, and the loader's own transport both-ways test now drives the shipped carrier through the same script.
  • Source-scan test — busbar-core-connector/tests/no_io_outside_hostio.rs: no connector file outside the host's I/O opens, binds, accepts, spawns or shuts an OS handle. The red arm is kept. tls/engine.rs and udp/dtls are named exceptions, and both live in the connector.
  • neutral_frame_door — the fixture now declares itself a framer, so it can never be picked as an address carrier.

Proof

Debug builds on Latchkey.

  • This head:
    • clippy (--workspace --all-targets -D warnings) and fmt --check are green; the C header is unchanged after regeneration.
    • Tests of contract, connector, loader, stdio, busbar, kernel and the ws subject are green, except ledger_identity, which needs the oracle engine cloned from GitHub (runner limitation).
    • The dropped-in tcp and dropped-in stdio legs are green.
    • Single plane llm fails two tests: declared_codes_do_not_collide_with_the_registry and export_request_log_file_1_5_5. Neither file is touched by this PR; whether predev fails the same way on this leg is not yet confirmed.
  • Before the last predev merge (6b0c0a3):
    • Workspace tests: 13033 passed. The 11 failures are xtask tests that need .git (runner limitation) and the loader-naming test, fixed since in 4ff76aa.
    • The timing, duplex-ws, loader pack, contract test-seal, voice runtime, admin, oauth2 and webhook legs are green.
  • Gate rows (gate --all): the FAIL rows on the merged head are the same set as predev c162c71's.
  • Oracle: the route., wire. and stdio cells, recorded and replayed against golden/1.5.5, give rows identical to predev, and all 9 wire cells PASS.

Kind-isolation: before and after, per rule (Latchkey, each tree measured against predev as base)

This PR's census change (W4B-Q1, 8bf1d22) counts the pinned plugin checkouts, because they ship. The 27 extra findings are edges and batteries that already existed and were not counted before. This is a fix to the measurement, not a code regression. They are routed to GATE-BURN as gate-battery work (exit row 3). No ledger rows are added for them.

gate rule predev 2bbe362 #502 1ace7f3
kind-isolation deps 3 3
kind-isolation test-deps 5 6
kind-isolation-ship control-path 73 73
kind-isolation-ship deps 15 17
kind-isolation-ship faces 4 4
kind-isolation-ship legacy-drain 5 5
kind-isolation-ship test-deps 13 23
kind-isolation-ship testkit 2 16

secret-hygiene: green on both. The head also merges predev 2bbe362; busbar_plugin.h is regenerated from the merged ABI source.

…) and its SDK; HostTables.io; carrier frame bits on write/read; the loader's io slots, inline tickets and Plugin::call_inline
… (listen/accept, dial, exchange, a pending read the host's wake resumes, the host's guard as the RED arm); the interim carrier guard is gone; the SDK's host-buffer io calls
…les; every connection rides a carrier's slots (carrier.rs: two inline sides, the destination guard admitting exactly what it pinned); compose, listen, program and the legacy wire seam carry through it; stdio is a carrier over io.* (WIP: tests)
…rry), install the host's I/O, the root's own binds listen through the address carrier; loader states a carrier's ported claim (WIP)
… framer-knobbed test entries are framers over it; host I/O and carrier witnesses; a handed-up stream half-closes through the host
…-tcp p2-transport-carrier: tcp is a carrier over io.*); stdio's lock drops tokio and futures
… kept); the trait-to-kind-op coverage of the memory ABI (RED arm kept); the layout golden and the header generator learn the host I/O table
…table, HostTables.io and the carrier's frame bits (cargo xtask abi-header --write)
…h the published suite's carrier script (linked vs dropped in, exact counts, RED arms kept); contract docs cite the design in words; universal_needs serves the test carrier as the address carrier
… rows then the dropped-in doors (plugins dir sorted order), the first carrier serving a port is the address carrier (pinned by a registry test); the neutral frame door states FRAMER; the dropped-in tcp leg asserts every data worker accepts through the dropped-in carrier, also with the neutral framer declared first
…the connector's doc names the loader's listing in words (the loader is named only by root/loader.rs)
…e holds the resolver the root hands it: the connector's address carrier, asked at each dial); stdio's stale feature rows struck; the suite's role test moves to its own file; the stdio crate comment names its files without the deferral label
… host double; the served wires take their address-carrier resolver as an argument (the root hands the connector's, a mount with no root none); the header's pinned count; rustfmt
@MattJackson
MattJackson enabled auto-merge October 6, 2026 21:49
@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

promote into predev: all green @ede9be409

Already red on predev, not this PR's: 11
gate row detail
build:deny ::deny unmaintained: unsafe-libyaml is unmaintained
construction one-pick-site 3 production call site(s) of 'pick_among(' (ceiling 2): crates/busbar-kernel-egress/src/walk.rs:298; crates/busbar-llm/src/engine/exhaustion/fallback.rs:120; crates/busbar-llm/src/engine/pipeline.rs:8
kind-isolation kind-isolation:deps 3 finding(s), 93 shipped edge instance(s) over 30 class(es), 93 declaration(s); 56 '[[dep]]' row(s), 0 question(s): unlisted-dep-edge legacy -> plane busbar-llm -> busbar-plane-llm is a shipped edge w
kind-isolation kind-isolation:law0 5 hit(s) off the [[law0]] ceilings, 3 finding(s) over 14 neutral crate(s): law0-rise busbar × instance:secret 37 hit(s) against a ceiling of 35: this landing grew a neutral crate's instance vocabulary
kind-isolation-ship kind-isolation:deps 10 finding(s) over 93 shipped edge(s): ship-edge kernel -> hooks busbar-kernel -> busbar-hook-ranking is 'not-allowed': the architecture grants no kernel -> hooks edge, and the ship criterion is the a
kind-isolation-ship kind-isolation:test-deps 8 finding(s) over 32 test edge(s): ship-edge cleanliness -> export busbar-core-admin -> busbar-export-prometheus is 'not-allowed': the architecture grants no cleanliness -> export edge, and the ship c
kind-isolation-ship kind-isolation:law0 5 hit(s) off the [[law0]] ceilings, 3 finding(s) over 14 neutral crate(s): law0-rise busbar × instance:secret 37 hit(s) against a ceiling of 35: this landing grew a neutral crate's instance vocabulary
kind-isolation-ship kind-isolation:faces 2 finding(s) over 40 crate(s): foreign-entry crates/busbar busbar is kind 'root' and implements 'Transport' 1 time(s) in shipped source — the entry face of kind 'transport'. A trait implementation is
kind-isolation-ship kind-isolation:legacy-drain 3 finding(s): transitional-live qa/kind-isolation.toml 'busbar-a2a -> busbar-core-admin' (legacy drain: the retiring A2A engine's tests drive the admin surface that drained into the cleanliness tier)
ship-ready ship-ready:ship-twin 'kind-isolation-ship' is not green: kind-isolation:deps (a dependency the architecture does not grant is still in the graph); kind-isolation:test-deps (a dependency the architecture does not grant is
structure-lint structure-lint:plane-dup:unledgered 22 finding(s): PLANE-DUPLICATE (module): 'config.rs' — a2a:crates/busbar-a2a/src/a2a/config.rs decisions:crates/busbar-plane-decisions/src/config.rs voice:crates/busbar-voice/src/config.rs (the ledger

tests passed: 24581, failed: 0. Run: https://github.com/GetBusbar/busbar/actions/runs/38246977973 . Artifact verdict-ede9be4096779f4f1a84eebdbc15f0a25509356a (failures.json, junit.xml, raw.log; 90 days).

…rmance_suite!) as a live battery entry, so a plugin that runs busbar's suite is not 'battery-ignored' (stdio, decisions); linked-dropped-features' unified-deps plant gives the plugin a registry dep of its own first (the stdio carrier has none to share)
@MattJackson
MattJackson added this pull request to the merge queue Oct 6, 2026
…-end case: a whole construction run and a whole kind-isolation-ship run, on one thread; 9 294 units on 5172cd4, predev 8 415-8 493), allowed at the declared slack
@MattJackson
MattJackson removed this pull request from the merge queue due to a manual request Oct 6, 2026
@MattJackson
MattJackson added this pull request to the merge queue Oct 6, 2026
# Conflicts:
#	crates/busbar-contract/include/busbar_plugin.h
#	crates/busbar/src/root/tests/serve.rs
#	crates/busbar/src/root/tests/serve_door.rs
@MattJackson
MattJackson removed this pull request from the merge queue due to a manual request Oct 7, 2026
… (file, webhook) carry [[dep]] rows like otlp's and prometheus's (measured once the census reads pinned checkouts); test-deps back to predev's 5
@MattJackson
MattJackson enabled auto-merge October 7, 2026 02:06
@MattJackson
MattJackson added this pull request to the merge queue Oct 7, 2026
@MattJackson MattJackson added fixing and removed fixing labels Oct 10, 2026
@MattJackson MattJackson added fixing and removed fixing labels Oct 10, 2026
… re-pin the floors at #502's count

law0-base: busbar-contract x instance:secret read 133 -> 134 over the
merge-base d7929b6. The scan counts every "C" literal in a neutral crate
as busbar-secret-c's id (plugins.yaml alias), and io_tests.rs's c_abi!
macro still spelled extern "C" once. exchange_tests.rs spelled it twice
(its slot! macro and the hand-written facts slot); facts now goes through
slot!, so the module spells it once and the cell is 133 again, the
merge-base's own number. Ruling: BUSBAR-1.6.0.md:1997-2002 (a neutral
crate's instance vocabulary is ceiling 0, ARMED; no ratchet row raises
it), so the branch may not grow the cell, and nothing licenses a raise of
its [[law0]] row. The gate and the ledger are unchanged.

xtask selftest blocking-ffi / response-header / settings-leak / tracing:
each floor is a ratchet pinned AT the measured count, and each selftest
removes one file and expects the floor row red. This branch adds nine
non-test files (the host I/O table and the carriers) and removes three
(connector stream.rs, stdio carrier.rs and conn.rs), so both walks read
6 more than predev and the one-file-short plant cleared the old floor.
population::FLOOR 941 -> 947 and tracing SCAN_FLOOR 971 -> 977 (counted
from the tree: base 971 / head 977 outside /tests/; +9 -3 for the
population). Ruling: BUSBAR-1.6.0.md:2089-2092 (Law 9: a census floor
pins its ceiling at TODAY'S MEASURED VALUE); population.rs: "raised as
the tree grows, never lowered".

Reasoned from source: the Latchkey run budget is spent (RUN_CAP), so the
PR's own CI is the proof.
…77 under predev's floor_plant

The one conflict, xtask/src/gates/tracing.rs: predev 13a9ecb replaced the
one-file floor plant with floor_plant (the walk cut to SCAN_FLOOR - 1 however
far the tree has grown), and #502 had re-pinned SCAN_FLOOR at its own count.
Both kept: the crates walk on this merge reads 977 files outside /tests/, so
SCAN_FLOOR stays 977, and the doc comment takes predev's floor_plant wording.

Ruling: BUSBAR-1.6.0.md:2091-2092, a census floor "pins its ceiling at
TODAY'S MEASURED VALUE", and :2063, an instrument declares "a floor beneath
which its own result is a refusal". Keeping 971 would leave the floor six
under the count.
… floor at 947 under predev's FLOOR - 1 plant

The one conflict, xtask/src/gates/population.rs: predev 9ae787f made the
one-file-short plant cut the live population to FLOOR - 1 whatever its size
(Overlay::below_floor) and kept FLOOR at predev's measured 941; #502 had
re-pinned FLOOR at its own count, 947 (+9 -3 non-test files). Both kept: the
doc takes predev's plant wording, FLOOR stays 947. Predev added and removed
only test files under crates/ since the merge-base 356afd1, so the merged
population is #502's 947.

Why it kept re-conflicting: predev keeps rewriting the same floor lines that
#502 re-pins (tracing.rs SCAN_FLOOR last time, population.rs FLOOR now), so
each predev floor change re-opens the conflict; this is a fresh conflict, not
the old one left unresolved.

Ruling: BUSBAR-1.6.0.md:2091-2092, a census floor "pins its ceiling at
TODAY'S MEASURED VALUE"; keeping 941 would leave the floor six under the
count.

Not proven on Latchkey: the run budget is spent (RUN_CAP), so the PR's own
CI is the proof.
… gated as the suite is

`lib.rs` compiles `mod conformance` under `any(test, feature = "conformance")` so this crate's own
tests drive the shipped transport row through it, but `dispatch/load.rs`'s
`door_addresses_of_library` and `dispatch/worker.rs`'s `answers` / `answered_after` / `drain`
stayed behind `feature = "conformance"` alone. A test build without the feature (test:loader-pack,
dropped-in-tcp) compiled the suite without them: E0425 at `conformance/mod.rs:565`, E0599 at
`conformance/plane.rs:972-1048`. The four helpers now carry the suite's own gate, so every build
that compiles the suite compiles what it calls, and none other does.
…door, chosen by rank

busbar-transport-webrtc's conformance (2 tests) failed at `stated()`: "the cdylib exports
busbar_plugin_door". `choose_cdylib` took `target/debug/libbusbar_transport_webrtc.*`, uplifted by
an earlier plain build without the `dropped-in` feature, so that image has no door. The test
build's own image, `deps/libbusbar_transport_webrtc.*`, does export it but was never a candidate:
cargo names a workspace cdylib with no metadata hash, and a `cargo test` never uplifts a lib's
cdylib (the lib is not a root unit), so the uplifted file is only ever another build's.

The choice now ranks: the image CDYLIB_ENV names; the lib unit's own unhashed `deps/<lib>`; the
uplifted image; the one hashed image. At every rank an image that does not load or exports no
`busbar_plugin_door` is passed over, and only doorless images built is a failure naming them.

Why this over a dedicated target dir: the suite is published to every plugin repo and runs inside
their test binaries; building the image into a dir of its own would mean a nested cargo build from
a test (a second cold build of the closure, a lock on the target dir), and `plugin-ci.yml` already
names its image in CDYLIB_ENV. Probing the symbol decides by what an image IS, the door the
dropped-in leg needs, never by which build ran last; the existing refusal of two different images
at one rank stays.

Tests: a doorless uplifted image is passed over for the deps image with the door, before and after
a later plain build; doorless images only are refused naming them; the real probe tells the example
cdylib from a file with no door. Fixed forward with the root cause (BUSBAR-1.6.0 §11.4, Part 2 #2:
one table, compiled in or dropped in; Part 6: nothing waived).

(cherry picked from commit a31461a)
Conflict: xtask/src/gates/population.rs. Predev raised FLOOR 941 -> 942 for conformance/red.rs; #502 raised it 941 -> 947 (+9 -3 non-test files). The merged tree counts 948, so FLOOR is pinned at 948 with both notes kept.
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