Skip to content

Export sinks on their doors; the cold export lane deleted - #488

Open
MattJackson wants to merge 26 commits into
predevfrom
p2-export-cold
Open

MattJackson wants to merge 26 commits into
predevfrom
p2-export-cold

Conversation

@MattJackson

Copy link
Copy Markdown
Collaborator

Q2 step 2 (ARCHITECT ruling: port the EXP2/disk.append fixes, re-pin, delete the cold export lane). Stacks on #482 (disk.append).

Re-pin: busbar-export-file at its merged dev PR head (GetBusbar/busbar-export-file#13: appends through disk.append, runs busbar's published conformance suite) and busbar-export-webhook at GetBusbar/busbar-export-webhook#12 (door behind dropped-in, the Need's keep mode and deny list, target from settings.url, published suite). Both on the export-doors axis; both cdylibs built with dropped-in.

Ported from lane-w3a/w3b (no salvage verdict overlaps p6-salvage #471): export-file door-only; EXP2 fixes (MAX-INFLIGHT: an instance's in-flight bound from its settings, DEFAULT_INFLIGHT 64; ENVELOPE: an opened instance's #85 envelope reaches the host's observability; EGRESS-GRANT: a third-party plugin declaring a first-party egress class is skipped at scan, named in the grant's words); the #11 export_conformance_tests restored on the door registries, its disk host on the kernel lane's rules.

Deleted (old-lane line count: abi/cold 2164 -> 1138): DynExport and ColdExport (plugin-loader export.rs, scrape.rs), the host's cold acts and egress carrier (host.rs trimmed to the rotate-by-rename the plugin log files use), the root's cold exports axis, LinkedExport, HostEgressCarrier and its collector policy (root otlp.rs; the door sinks' egress is judged by the connector's class), the contract's cold export wire (abi/cold/export.rs) and SDK glue (export_export_plugin!, ExportHandler, HostStep). MetricFamily/MetricSample move to abi::export (the prometheus door renders them). The JSON-lane loader tests run on the auth fixture. Ledgers: one-memory-abi and door-only rows struck; abi-freeze cold lowered.

Proof (Latchkey, debug): fmt clean; workspace clippy -D warnings; contract, loader (585), kernel lib (2641) green; busbar export tests (dropped-in serves, 1.5.5 file line byte for byte, traces both doors, scrape first-party, scrape boot window) green; --no-default-features tests green and every single-plane set builds; xtask gate --all at row level identical to f27bd58 (no new reds). ledger_identity needs the oracle checkout (network) on the runner, as before.

… (THE DESIGN §11.11 R4, §11.12; ARCHITECT ruling Q-C1-FILE 2026-10-03)

The request-log file sink is door-only, and it asked the host for a disk lane that did not exist, so
every line was dropped with BUSBAR-7074, a break from 1.5.5. The host now serves the lane.

- contract: abi::host::service gains op DISK_APPEND = 22 (SERVICES 22 -> 23, may pend), with DiskAppendIn
  {head, dest_key, bytes, result} -> DiskWritten {size, rotated, faults, written}. A FAILED answer names
  its step in value (DISK_OPEN_FAILED / DISK_APPEND_FAILED) and still reports the rotation.
  check_disk_append_in (host side) and check_disk_append (caller side), one RED per arm.
  HostSlots.disk_append is appended (184 -> 192); the abi-layout golden gains the appended rows and the
  new table size. SDK: Connector::disk_append, on the op's handle count. services: HostServices::disk_append,
  DiskDest, DiskReport, DISK_KEEP (9), DISK_ROTATE_KEY ("rotate_mb", the host's rotation key).
- loader: an opener grants an instance the destinations its manifest declares (ExportRows::open,
  Plugin::grant_destinations); open and refresh bind each one to the path the settings give it. The
  disk_append slot maps the key through that binding (NO_DESTINATION otherwise) and writes the lane's report.
- kernel: host_disk::DiskLane: one thread, appends in submission order, bounded (LANE_BOUND). It writes
  as 1.5.5 did (open for append, create if absent, write the bytes whole), after a rename rotation when one is due.
- root: LateServices and CredentialServices forward the call.
A delivery's host-service results and connections are stored under (ticket, n), with n counting from 0.
The flusher used ONE ticket for every batch, so the second batch picked up the first batch's stored
results: otlp got the first batch's establish ("the far end took no bytes": one export, then nothing),
and the file sink got the first batch's disk.append (only the first batch was written). Minting a
ticket per batch and recycling it afterwards forgets those results (worker recycle_now: completions,
services, conns).
…of 265), the design cited in words in the contract, every HostServices double answers disk_append
…'s export-doors axis (busbar_export_file::door) and its dropped-in cdylib is built with its dropped-in feature; plugin-loader's cold both-ways row for it goes, with the tests whose subject was its cold entry (the #11 file-sink suite, load_and_exercise_export_plugin) and export_tests drive an in-test cold boundary (owner NO-TEST-PLUGINS Q7, the CONF-SUITE-DEL treatment of ec6feb9); the webhook sink's cold suite stays
…lt distribution links the http framer; request-log-webhook moves to its door

- Cargo.toml: export-file a0dfd7d (busbar-export-file#12: deliver appends through disk.append),
  export-otlp fc87b52 (#12), export-prometheus 4689954 (#12), export-webhook 631a1dc (#11). Each is a
  repin to 4abda5b using scripts/fleet/repin.sh, the same way busbar-auth-oidc#23 did it. otlp and
  webhook Needs now state keep_mode and the deny list. The coordinator replaced the fleet-pins merge with this.
- busbar Cargo.toml: `transport-http-door` is linked on the connector-door axis, under scheme `http`
  (busbar_transport_http::door). This is ARCHITECT ruling Q-C1-OTLP: packaging only, so kernel, contract
  and loader source name no instance. `module: otlp` boots, and its spans reach the collector over the
  Connector's http framer. The `http` wire row is unchanged.
- request-log-webhook: the dev head is door-only (export_door!, no cold entry), so it moves to the
  export-doors axis (entry busbar_export_webhook). Its need is framed by the `http` claim.
- plugin-loader: the cold webhook both-ways row and its suite (export_conformance_tests) are removed,
  the CONF-SUITE-DEL treatment already applied to the file sink. Real plugins are the proofs, so the
  webhook joins export_axis_tests on both doors (probe, the 1.5.5 settings refusal, open).
- busbar tests: export_request_log_file_1_5_5 (new). Two requests through the linked file sink each
  append the line the 1.5.5 golden cell export|request-log-file|jsonl recorded, byte for byte under
  the cell's masks. export_plugin_dropped_in_serves now states the door's Statement in the dropped-in
  manifest (common::plugins::state).
…ce); the linked-entry scan names an external entry by its crate (c1's 42bb141, the export-doors rows list no bare door); the catalogue reads both export axes and the page test runs on either (linked_axis_export_doors declared); the dropped-in export proof renders through the door; a stray doc block's empty line (clippy)
…nto the export kind's door registries (ARCHITECT ruling EXP2-PROOF 2026-10-03: the spec's working proof of the plugin model; deleting it was a gate weakening)

Every test the file held at predev-all/b9 is ported to the real sinks on the memory ABI, each
LINKED by its logic crate's door and DROPPED IN as its -plugin crate's cdylib (signed first-party,
Statement rendering in its manifest), no test plugin (owner NO-TEST-PLUGINS):
- envelope observations identical (#85), the observations the sink produced, one row + same
  fold, first-party series granted through either door and to nobody else, settings validation,
  host-written destination: the request-log FILE sink through disk.append (the host's acts served
  by crate::host's destination writes, rotating by rename);
- declared diagnostics, host-carried outbound request, the need's egress class: the request-log
  WEBHOOK sink over the host's connection table (a recording table that honours the DeclaredConns
  contract);
- the RED arm the_pre_envelope_path_loses_a_dropped_in_plugins_counters: the real file-sink cdylib
  staged by the loader, every op forwarded with its reply's envelope kept plugin-local; the host
  ingests nothing while the compiled-in build reports both rotations;
- the pre-op RED arms (validate, check): a door whose table predates the op is refused at the load.
The three cold-lane claims with no door form (the cold start op, 600 in flight past the blocking
pool, the manifest egress-policy grant) are stated in the module doc with the reason.

ExportRows::with_envelope: an opened instance's #85 envelope goes where the opener says (NoSink
when unset, as before). plugin-loader dev-deps: busbar-export-file and busbar-export-file-plugin
(dropped-in) at the workspace pin.
….5 behaviour frozen)

WEBHOOK-TARGET: busbar-export-webhook repinned to f85762d (PR GetBusbar/busbar-export-webhook#11):
its need's target comes from `settings.url`, so the host's connector no longer refuses it and every
delivery is POSTed again.

MAX-INFLIGHT: an export instance runs up to its in-flight bound of deliveries at once, each on a
ticket of its own and awaited (no thread held while it pends), every batch started on one worker in
queue order; while fewer lines are queued than may start, each travels alone. The bound is the
instance's `max_inflight_deliveries` (contract export_calls::INFLIGHT_KEY; DEFAULT_INFLIGHT 64 when
unset, 1.5.5's) within the plugin's declared max_inflight; the webhook declares no ceiling of its own.

ENVELOPE (#85, owner-locked): the opener's default envelope sink is the host's observability
(observe::EnvelopeObserver: a door's metrics named by their Statement family, its declared
diagnostics by their id, into the installed PluginObserver); the plugin log sink also forwards a
declared diagnostic downstream. Never NoSink for an opened export instance.

EGRESS-GRANT (§5): the scan refuses a plugin that is not first-party whose stated Statement declares
a need in a first-party egress class (provider, operator-infrastructure, loopback-allowed): skipped
as RejectKind::EgressGrant, named in the grant's words; the export opener names a scan refusal.

Tests: export_conformance_tests gains the 600-past-512 bound (door form), the third-party egress
refusal (the OTLP collector), the envelope-to-observability arm and the span through both doors;
traces_stream_both_doors: a third-party dropped collector is refused at load (--validate names it,
a config naming it does not boot), the linked collector still receives the spans.
…erver through a bounded, non-blocking intake (ARCHITECT ruling ENVELOPE-ALL 2026-10-03; #85 owner-locked)

- dispatch::Plugin::bind stands observe::EnvelopeObserver before whatever sink the binder gave, for
  every kind (plane, auth, store, hook, secret, transport, export): a metric of a family the
  Statement declares (named by family, kind and label keys) and a declared diagnostic reach the
  installed PluginObserver under the plugin's Statement name and kind word; log records stay with
  the plugin log; the binder's sink still receives every entry. ExportRows no longer builds its
  own observer (the bind does); the plugin log sink no longer forwards declared diagnostics.
- observe: the intake is a bounded queue (INTAKE_BOUND 4096) drained by one observer thread; a
  plugin call hands its back-channel over with try_send and never waits. A full intake drops and
  counts; the count reaches PluginObserver::dropped, which the root wires to the kernel's new
  busbar_plugin_observations_dropped_total (in the root's HOST_SERIES; docs/observability.md).
  Cold envelopes (observe::fold) take the same intake.
- Tests (observe_tests): one per kind through the real door where the crate's graph has one
  (auth admin-tokens, store-memory, secret-env, transport-tcp, export-file; plane and hook through
  their kinds' existing fixtures), a metric named by its family for every kind, and the full
  intake dropping, counting and never stalling the caller. RED-checked: without the bind's
  observer every per-kind arm fails.
…d SDK glue, the host's cold acts and egress carrier, the root's cold exports axis); the export axis opens door rows only
…heus door renders them); the cold-linked check stays for the auth residue
…nt (kind::EXPORT => &[...]) reads as one keyed by its word
…ow is gone); the transport-error class is the auth residue's
…RABLE-BYPASS row's ledgered rename exemption, and its error-text intern a reviewed hold-escapes site (bounded by MAX_WORDS)
…i, door-only CARRIER), abi-freeze cold 2164 -> 1138; the dropped-in staging file is one per call; the 1.5.5 file-sink line test names its store
@MattJackson
MattJackson enabled auto-merge October 5, 2026 16:17
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

promote into predev: BOARD @1ed5bd61c: 3 failing test row(s), 14 DENY row(s)

Failing tests (3)

crate test step first panic
`` nextest xtask::cli::selftest_runs_every_registered_gates_red_proof test:workspace
transport_dropped_in_serves a_dropped_in_transport_registers_through_the_one_fold_and_serves test:dropped-in-tcp-transport crates/busbar/tests/transport_dropped_in_serves.rs:168:13: busbar exited (ExitStatus(unix_wait_status(512))) before serving; log:
-p busbar --test transport_dropped_in_serves test target failed test:dropped-in-tcp-transport

DENY rows (14)

gate row detail
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
reachability reachability:unit-path:decision NO LIVE UNIT PATH: roster plane 'decision' has no kernel-loop runner registered for its capability key, no 'Units' impl its linked entry exports and no served door, so nothing 'fn main()' reaches driv
reachability reachability:root-reach:decision NO UNIT PATH REACHED: no module a chain from crates/busbar/src/main.rs arrives at routes plane 'decision''s capability key onto a kernel-loop runner, its linked entry exports no 'Units' impl, and no s
kind-isolation kind-isolation:deps 4 finding(s), 78 shipped edge instance(s) over 28 class(es), 78 declaration(s); 62 '[[dep]]' row(s), 0 question(s): unlisted-dep-edge cleanliness -> plugin-tooling busbar-core-admin -> busbar-plugin-l
kind-isolation kind-isolation:test-deps 7 finding(s), 37 test edge instance(s) over 20 class(es), 37 declaration(s); 22 '[[dep]]' row(s), 0 question(s): unlisted-dep-edge cleanliness -> legacy busbar-core-admin -> busbar-a2a is a test edge
kind-isolation-ship kind-isolation:deps 16 finding(s) over 78 shipped edge(s): ship-edge cleanliness -> plugin-tooling busbar-core-admin -> busbar-plugin-loader is 'not-allowed': the architecture grants no cleanliness -> plugin-tooling edge
kind-isolation-ship kind-isolation:test-deps 15 finding(s) over 37 test edge(s): ship-edge cleanliness -> legacy busbar-core-admin -> busbar-a2a is 'not-allowed': the architecture grants no cleanliness -> legacy edge, and the ship criterion is t
kind-isolation-ship kind-isolation:faces 4 finding(s) over 31 crate(s): foreign-entry crates/busbar busbar is kind 'root' and implements 'Store' 2 time(s) in shipped source — the entry face of kind 'store'. A trait implementation is a claim
kind-isolation-ship kind-isolation:testkit 2 finding(s) over 12 crate(s): battery-ignored crates/busbar-plane-decisions busbar-plane-decisions carries a tests/conformance.rs whose every entry is '#[ignore]'d (or which has none). 'cargo test'
kind-isolation-ship kind-isolation:legacy-drain 5 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)
kind-isolation-ship kind-isolation:control-path 77 finding(s) over 3 control surface(s): upstream crates/busbar-core-admin/src/admin_codec/meta.rs:84 busbar-core-admin names 'egress' — a control surface has no upstream to reach, so the vocabulary o
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
instance-noun-neutrality instance-noun-neutrality:voice tracked known-debt census — 8: crates/busbar-plane-llm/src/codec/gemini/handler.rs×7 [cross-plugin] | crates/busbar-plane-llm/src/codec/gemini/tests/handler_tests.rs×2 [cross-plugin] | crates/busbar
structure-lint structure-lint:plane-dup:unledgered 24 finding(s): PLANE-DUPLICATE (module): 'config.rs' — a2a:crates/busbar-a2a/src/a2a/config.rs decisions:crates/busbar-plane-decisions/src/config.rs mcp:crates/busbar-mcp/src/mcp/config.rs voice:crate

Judged against base fb60d3435: 0 new red, 0 worse, 9 standing (excused).

tests passed: 24228, failed: 1. Run: https://github.com/GetBusbar/busbar/actions/runs/37339690309 . Artifact verdict-1ed5bd61c890d568b75562dc1ea481682dad9524 (failures.json, junit.xml, raw.log; 90 days).

@MattJackson
MattJackson added this pull request to the merge queue Oct 5, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 5, 2026

This branch has not been deployed

No deployments
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