Skip to content

row 74 F25: the door path's jwt-bearer mint keeps 1.5.5's raw aud, the stripped dial and the Basic - #922

Open
MattJackson wants to merge 44 commits into
lane-row74-userinfo-basicfrom
lane-row74-userinfo-door-aud
Open

MattJackson wants to merge 44 commits into
lane-row74-userinfo-basicfrom
lane-row74-userinfo-door-aud

Conversation

@MattJackson

Copy link
Copy Markdown
Collaborator

Stacked on #913 (base lane-row74-userinfo-basic), which is stacked on #876.

What

ARCHITECT ruling: the door path is what ships, so the jwt-bearer userinfo proof lives on it. This PR is test only, because the door path already behaves as 1.5.5 did. The in-process service-account stripping that moved aud off 1.5.5 was dropped before it was pushed.

A door-served jwt-bearer member whose service account's token_uri contains user:pass@ (crates/busbar/src/root/tests/door_steps.rs, a_service_account_token_uri_userinfo_rides_the_mint_as_1_5_5_sent_it):

  1. No userinfo on the plane's side. The member's sealed route (its base URL and every spelled base URL) and the need the minting plugin declared over its settings contain no userinfo.
  2. Raw aud. The signed assertion's aud is the raw token_uri, exactly as 1.5.5 signed it: v1.5.5 crates/busbar/src/egress_auth/jwt_bearer.rs:152-159 (jwt_claims_json(.., &self.token_uri, ..)).
  3. Stripped dial, Basic first. The mint POSTs to the stripped endpoint, with authorization: Basic base64(user:pass) as the first field and no field carrying the userinfo in the clear. This matches 1.5.5's reqwest POST to token_uri as written (jwt_bearer.rs:175-181, reqwest 0.12.28 request.rs:169-182, util.rs:4-25).

…o-socket pin armed (E7)

The inbound listener's accept/serve loop (hyper-util's auto builder, graceful shutdown, the body
read bounds, the accept backoff and the connection-placement balancer) moves verbatim from
busbar-kernel/src/tls.rs into the composition root, crates/busbar/src/root/listener.rs. The
connector binds every listener (Listening::bind_stream) and hands each admitted stream up; the
accept-source trait (Admits, Admitted) moves to busbar-core-connector's listen.rs beside the
listener that implements it. tls.rs keeps read_pem for its outbound callers. The kernel drops
tokio-util. BUSBAR-1.6.0.md l.475-483 (INBOUND-LISTEN: the root's stream hand-up) and the ARCHITECT
ruling on #710 (2026-10-10). This is #741's change on current predev; it supersedes #741.

Tests move with the code: the kernel's tls_tests.rs and busbar/tests/tls_listener_h2.rs become
root/tests/listener_tests.rs and listener_h2_tests.rs; the connector's TLS-listener rows join them
(their scratch PEM name keeps predev's unique-per-call suffix).

Ledgers: law0 busbar-kernel x transport 285 -> 268 and busbar x transport 208 -> 225 (the move, total
flat, per the #710 ruling); population floor 947 -> 948 (root/listener.rs is a new file; tls.rs stays).

E7: crates/busbar-kernel/tests/no_socket.rs holds busbar-kernel to a drain-only pin of every
(file, needle) naming a socket, resolver or HTTP client/server stack, and every manifest ask for
one; tls.rs is not in it. A new offender is RED, a drained pin left standing is RED, and the RED
arm plants a dial, a resolver and a server stack and sees each.
…me itself

busbar-kernel/src/net_guard.rs was a glob re-export of the egress unit's guard
(busbar_kernel_egress::trust::net) plus SystemResolver, a getaddrinfo on a thread of its own: the
one piece of the guard that touched the network. Deleted.

- The kernel's call sites name the guard in its homes: the pure host atoms from busbar_contract::net
  (observability, config_validate, plane_host/guard), the pre-dial guard from
  busbar_kernel_egress::trust::net (plane_host/egress, egress/duplex_ws, config_validate's
  ssrf_blocked_host re-export). Same items, same answers.
- The name lookup is the connector's. busbar_core_connector::process::SystemNames is the deleted
  SystemResolver, verbatim, implementing the unit's Resolver seam. The root installs it behind the
  egress-trust capability (GuardedEgressTrust's third field) with the guard and the TLS wrap, at the
  same boot step. The kernel's two resolve-then-pin dials (the plane-host egress open and the
  duplex_ws dial) ask plane_host::egress_trust::InstalledResolver, which reads the capability. With
  no guarded capability, a production kernel refuses the name (fail closed); a test build resolves
  through egress::fixtures::system_names, the same body, in test scaffolding. No new static.
- The connector reads split_url from the unit instead of through the shim, and depends on
  busbar-kernel-egress (kind-isolation [[dep]] row, cleanliness -> kernel, allowed). core-oauth2
  reads parse_url from busbar_contract::net. busbar-a2a and busbar-voice (legacy, deleted by #787 and
  #503) reach the unit through the kernel's existing busbar_kernel::proxy::egress_unit re-export, so
  no new legacy edge.
- Tests: the shim suites' four rows the unit's suite did not already hold move to
  busbar-kernel-egress trust/tests/net_tests.rs; the other 32 were duplicates of it.
  egress_trust_tests gains the_guarded_seam_resolves_by_the_resolver_behind_it. The root's
  net_guard_one_judge compares config_validate's re-exports with the unit. no_socket strikes
  ("src/net_guard.rs", "lookup_host").
- Population floor 948 -> 947 (one non-test file deleted, reviewed).
- design bindings PB-68: the shared-predicate row names its surviving copy in the egress unit's
  suite (crates/busbar-kernel-egress/src/trust/tests/net_tests.rs, same test), not the deleted
  kernel suite; qa-names and design-bindings:regen-clean follow.
- law0 busbar-kernel x plane 1172 -> 1166: the shim and its suites carried six plane words.
- The moved NAT64 row's doc names no plane (busbar-kernel-egress x plane stays at 5).
…ener

# Conflicts:
#	xtask/src/gates/population.rs
# Conflicts:
#	xtask/src/gates/population.rs
…guard

# Conflicts:
#	qa/kind-isolation.toml
#	xtask/src/gates/population.rs
…guard

# Conflicts:
#	xtask/src/gates/population.rs
no_io_outside_hostio holds that no connector file but the host's I/O touches the OS, and
SystemNames (the system name lookup the kernel's remaining resolve-then-pin dials ask through the
egress-trust capability) called tokio::net::lookup_host from process.rs. It moves, unchanged, into
hostio.rs, the host's I/O; the root installs busbar_core_connector::hostio::SystemNames. The test's
allowlist is unchanged.
#798 (row 157) deleted plane_host/guard.rs and the guard_url slot, and moved the egress-trust
capability to egress::trust: the kernel's resolve-then-pin dials ask egress::trust::InstalledResolver.
Ledger by the merge rule (theirs + ours - base): busbar-kernel x plane 1168/1162/1141 -> 1135,
busbar-kernel x transport 285/268/284 -> 267.
…y/scrape-shape tests wait for admin bound and dump the node log on panic

161: drain_frames_checked_scales_linearly_in_frame_count read a wall-clock ratio (8.3x under prover load). It now reads the thread's CPU time (/proc/thread-self/schedstat, Law 8, as the xtask selftest budget of #790); the 8x bound, the 1ms floor and min-of-3 are unchanged, and quadratic still reads ~16x.
162: no_data_dir_neutrality and scrape_shape_1_5_5 fired the admin call on the first 'busbar listening' line (data worker 0), before admin is bound. They wait for both lines via the shared common::boot helper, and hold common::boot::DumpOnPanic so a panic prints the node's out.log.
… judges every move (row 163)

OWNER 2026-10-12 "ModernCI only"; 2026-10-13 "delete anything you don't need anymore, yes" and
"we keep the busbar-release repo, slimmed down. ModernCI replaces its CI half; the busbar-specific
tools stay." Spec Part 6 gains the ruling (keep/delete lists, the ladder on .ci/*.yaml, the oracle
home) and the passages it supersedes are struck, Part 5's DEV-GREEN item 6 included.

- .github/workflows/promote.yml deleted: the busbar-release hop ran on every PR into dev/qa/main
  and ended INFRA every run (R2 keys unset).
- workflow-rules: R16 (engine pin), R18 (promote.yml release artifact), R19 (hop R2 keys) go with
  the file they held; the R1/R11/R14-flow mutations move to plugin-ci.yml and planted files;
  MIN_WORKFLOWS 5 -> 4 (the four plugin-*.yml workflows).
- no-self-filed-issues: discovery floor 5 -> 4, the same workflow count.
- infra: the "every gate the pipeline calls is registered" test reads .ci/*.yaml, the pipeline.
- .ci/predev.yaml: no longer a shadow; gates requires git-history as in .ci/default.yaml.
- RELEASE.md, required-status-checks, CONTRIBUTING, README badge, actions-pins: the ladder is
  ModernCI's.
… in 1.5.5

The OpenAI (gpt-image-1) and Gemini image readers parsed the answer's token usage into
Billing::Tokens, and both image ops now tap the same-dialect body, so a key was charged the
model entry's token rates, and its tokens: caps counted, where 1.5.5 billed no image token
(v1.5.5 crates/busbar/src/handlers/openai.rs:731-758 and handlers/gemini.rs:446-472 set neither
usage nor cost_basis; no image op tapped usage). An unreadable count also refused an answer 1.5.5
served. ImageResp::billing now records the reported tokens as residual units (the settle's
usage.residual audit row) on a zero token line, and the readers read them leniently. The per-image
`images` class (LEDGER-100, CHANGELOG Upgrade) is unchanged.
…k lane, config time only (OWNER 2026-10-13, row 166)

The owner amended R4: the host-owned bounded disk lane serves the SQLite store, the file export sink,
and the secret kind's file source, the last only at config time (boot, config apply, refresh) and
never from a request path, which a gate holds. Audit pinned secret-file #1 (blocking reads inside
resolve) is fixed against this text.
…so no gate loses the code after a /* in a string (audit xtask A2 HIGH 1, H1 HIGH 2)

The hole: scan::split_comment_line reset its in-string flag on every line and
carried only a block-comment bool. On the continuation line of a multi-line
string (crates/busbar-kernel/src/plugin_routes.rs:273, `{or_metrics}{root}/*"`)
the `/*` opened a block comment that never closed, so lines 274-564 of that
file read as comment to kernel-token-wire-purity, no-deferral,
plane-transport-neutrality, kind-isolation and every production_lines reader;
xtask/src/cli.rs, audit_cmd.rs, gates/no_float_money.rs and
xtask/tests/construction_verdict.rs ended the same way.

The fix: split_comment_line now reads THE ONE LEXER (lex_line, the
classification blank_code already used) and carries a LexState, so an open
literal (normal, raw r#"..."#, byte, escaped) or a nested block comment
survives the line end, char literals ('"') and lifetimes are told apart, and
the code/comment split agrees with blank_code by construction. The carrier is
a CommentCarry trait: LexState carries everything; a bool still compiles and
carries only the block flag. production_lines, kernel-token-wire-purity,
no-deferral, seal-witness and instance-noun-neutrality now carry LexState.
blank_code's output is unchanged (checked line for line over every tracked
.rs on predev 5c99bef).

RED plants:
- kernel-token-wire-purity selftest "a raw wire field after a `/*` inside a
  continued string is still read": a kernel file whose continued string ends
  `{root}/*")`, then `v["input_tokens"]` on line 6. The old scanner opened a
  block comment at the `/*` and read lines 4-7 as empty, so the gate stayed
  green and the case expecting planted_wire_read.rs:6 went red.
- no-deferral selftest "a deferral after a `/*` inside a continued string is
  still a marker": the same string shape, then `todo!()` on line 5; the old
  scanner read it as comment, so no marker.
- xtask/tests/infra.rs: a_comment_opener_inside_a_continued_string_is_string
  (strip_comment_line and production_lines both return the line after the
  string) and the_comment_splitter_reads_raw_strings_chars_lifetimes_and_nesting.

Predev: no gate figure moves. Every line whose reading changes (327 under
crates/, the rest under xtask/src) was checked against each consumer's
needles. None trips a gate, and no ledger or ceiling row changes.
#741 landed the same E1 listener move on predev (7fe0203, 5f189a7), so every E1 conflict takes
predev's side: crates/busbar/src/root/listener.rs and crates/busbar-kernel/src/tls.rs (predev's comments
name a plane's outbound identity, not busbar-a2a), xtask/src/gates/population.rs (predev replaced the
hand-pinned FLOOR with the tracked-set reconciliation). qa/kind-isolation.toml: busbar x transport and
busbar-kernel x transport each carry the same +17/-17 move on both sides, so theirs (224, 266) is
taken, count and cite: adding both deltas would count the move twice.

What this branch still adds over predev is crates/busbar-kernel/tests/no_socket.rs (the kernel's
no-socket pin, E7); its PINNED list matches predev's kernel exactly (no new pair, none drained).
… into lane-egress-e2-net-guard

qa/kind-isolation.toml: predev's rows, plus this branch's own E2 drain. busbar x transport and
busbar-kernel x transport: this branch carries the same E1 +17/-17 move #741 landed on predev, so theirs
(224, 266) is taken, count and cite. busbar-kernel x plane: predev 1128 (row 156 and #674 drains since
this branch's last predev, 1141) minus E2's own six (net_guard.rs and its two suites deleted:
1141 -> 1135 here) = 1122, predev's cite kept with E2's clause renumbered 1128 -> 1122. Every other row
is predev's.
…ini codecs (row-159 L3#10)

Three accepted-differences entries (FID-CHAT, FID-RESPONSES, FID-GEMINI), each citing the LLM
dialect fidelity rule (docs/design/BUSBAR-1.6.0.md:4769, :4771, :4774) and, per move, the 1.5.5
and served path:line, with their CHANGELOG lines. Two moves the rule does not cover are restored
to 1.5.5 instead: a refusal reaches a Gemini client as OTHER (v1.5.5 proto/gemini/mod.rs:771), and
an Imagen :predict answer carries no usageMetadata (v1.5.5 handlers/gemini.rs:474-492).
…and the transcription boundary

- synth_rng kept a 4 KiB thread_local! entropy pool shared by every instance on a thread. Each
  draw now goes straight to the host's source (busbar_contract::codec::fill_entropy); the module
  holds nothing.
- The OpenAI transcription boundary and its Content-Type were per-process OnceLock draws (with a
  wall-clock fallback). The boundary is 1.5.5's literal again (v1.5.5
  crates/busbar/src/handlers/openai.rs:238, :281), a constant; part_carries_delimiter still fails a
  body carrying it closed, which is the guarantee against smuggled parts.
BUSBAR-1.6.0.md THE DESIGN §2: a plugin holds no process-global state; the one approved per-thread
slot is the door's log-capture slot. Row-159 plane-llm L1#4 / L2#6 (entropy pool) and L3#1.
…s, not timed

drain_frames_checked_scales_linearly_in_frame_count compared wall-clock times of 1M- and 4M-frame
drains and flaked under shared CI load (ModernCI quarantined it). The drain now counts its own
buffer work (DrainWork: bytes walked as frames, buffer edits, bytes those edits moved), and every
edit of the drained buffer goes through the counting consume_front/clear_all. The test asserts one
edit per pass, nothing moved for whole frames, every byte walked once, and total work under 8x
from 1k to 4k frames (Law 8: count work, not time). The RED arm runs the old per-frame drain
through the same counter: 1k/4k edits and quadratic bytes moved, rejected by the same check.
…t, as in 1.5.5

The Gemini upstream_path fallback made every verb without an action stream-aware, so a streamed
moderation or rerank request targeted :streamGenerateContent. 1.5.5 made only Chat, Transcription
and Speech stream-aware and sent Moderation and Rerank to :generateContent (v1.5.5
crates/busbar/src/handlers/gemini.rs:52-63). F25 map row 558 (the attempt-path parity REHOME).
…ning (row 114)

restart_phase (durability_amend.rs), node_boot_hooks_arm (serve_money.rs) and
panic_child (plugin-loader dispatch_tests.rs) each returned early when their
parent's variable was unset, so the default run counted three passes that
proved nothing. Each is now #[ignore = child process of <parent>], fails by
name when run without its parent, and its parent runs it with --ignored (the
pattern loader_seam_tests' foreign_panic_child already uses). The parents
already assert the child ran ("1 passed" / a non-success abort), so a child
that stops running fails its parent.

capture_latency_metrics (busbar-llm) was an env-gated no-op passing in 0s: it
is #[ignore = a measurement] and runs whenever asked with --ignored.

The two bare #[ignore] benches (busbar-plane-llm same_proto_fidelity_tests,
busbar-kernel store tests) state their reason.
row 130 E2: net_guard leaves busbar-kernel; the kernel resolves no name itself (stacked on #796)
row 163: retire busbar-release from busbar — delete promote.yml, ModernCI alone judges every move
row 166: spec §11.11 R4 admits the secret kind's file source to the disk lane, config time only (OWNER 2026-10-13)
tests: child halves and an opt-in measurement no longer pass by returning (row 114, 2/2)
llm codec: Gemini moderation and rerank always target :generateContent, as in 1.5.5 (F25 row 558)
flakes (rows 161, 162): CPU-time drain scaling; admin-bound wait + log dump in two boot tests
…-linearity test stays counted (Option A)

#815 (9ed8689) rewrote the timed drain_frames_checked_scales_linearly_in_frame_count to read CPU
time. This branch replaces that test with the counted one (DrainWork), so the conflict in
eventstream_tests.rs resolves to the counted version. #815's other changes (common::boot,
no_data_dir_neutrality, scrape_shape_1_5_5) come in unchanged.
register: fidelity-rule byte moves of the Chat, Responses and Gemini codecs (row-159 L3#10)
…e stripped dial and the Basic

ARCHITECT ruling: the door path is what ships, so the proof lives there. A door-served jwt-bearer
member whose service account's token_uri spells `user:pass@`:
(1) the plane's side of the seal carries no userinfo: the member's route (its base and every
    spelled base) and the need the minting plugin declared over its settings;
(2) the assertion's aud is the raw token_uri, as 1.5.5 signed it (v1.5.5
    crates/busbar/src/egress_auth/jwt_bearer.rs:152-159, jwt_claims_json over &self.token_uri);
(3) the mint POSTs to the stripped endpoint, led by `authorization: Basic base64(user:pass)`, as
    1.5.5's reqwest POST to token_uri as written sent it (jwt_bearer.rs:175-181).
Test only; the door path already behaves so. The in-process service-account stripping
(6796dc557b) is dropped, unpushed: it moved aud off 1.5.5.
row 159: the shared comment scanner keeps string state across lines, so no gate loses the code after a /* in a string (audit xtask A2 HIGH 1, H1 HIGH 2)
…corded zero

The image readers (gemini/handler.rs and openai_chat/handler.rs, read_image_response) read the
recorded image token counts with a silent zero default (`.and_then(read_count_u64).unwrap_or(0)`).
That turned gates no-float-money:count-read-shape (#81) red: a defaulted zero records no work for
work that happened (OWNER rule 21: money is ledger x ratecard, exact).

Both now read through the crate's one count seam, usage_count::billed_count, as every other
billed and recorded read in the codec does: absent or null is zero, a readable count (float
spelling included) is recorded, and a present unreadable count is a CodecError refusal naming the
field. The counts stay recorded (residual units) and never billed, as in 1.5.5.

Two REDs, one per site, in float_usage_tests.rs:
an_unreadable_image_count_refuses_instead_of_recording_zero. Each fails on the defaulted read and
passes on the refusal.
…s served and the count is never 0

Coordinator correction to c83d790. The image token counts are recorded, never billed, and 1.5.5
served the answer whatever its usage said (v1.5.5 handlers/openai.rs:731-758 and
handlers/gemini.rs:446-472 read no usage). So refusing the answer over an unreadable, unbilled
count is a customer-visible change that the money rule does not require. A fabricated 0 is still
banned (#81, OWNER rule 21).

- ir/image.rs: ImageResp.usage is Option<ImageTokens { input: Option<u64>, output: Option<u64> }>.
  `None` is UNKNOWN. billing() leaves an unknown count out of residual_units, as it does a zero.
- usage_count::recorded_count reads through billed_count, the one seam. Absent or null is Some(0);
  readable is Some(n); present and unreadable is None, with the field named on the answer's
  warnings and in a warn log line. It is never 0 and never a refusal.
- Both read_image_response readers (gemini, openai_chat) use recorded_count and carry the warnings.
- Both write_image_response writers leave an unknown count out, along with the total it would sum
  into, rather than writing 0. A fully readable usage writes the same bytes as before.

REDs, one per site, in float_usage_tests.rs:
an_unreadable_image_count_is_recorded_as_unknown_and_the_answer_served. Each asserts the answer is
served, the count is unknown (None, absent from the record and from the re-emitted body, never 0),
and the field is named in the warnings. Each fails on the defaulted read and on the refusal.
…iter is 1.5.5's {predictions} alone (#867), so the unreadable-count RED asserts no usageMetadata is re-emitted
@MattJackson

Copy link
Copy Markdown
Collaborator Author

row 155 B2 (#974) edits crates/busbar-kernel/src/bound_credential.rs at DeclaredBuilder::headers_for; disjoint from this PR's hunks.

llm codec: event-stream drain linearity counted in work units, not timed (quarantined flake)
$ llm codec: image answers record their token counts and bill none, as in 1.5.5
llm codec: no per-thread or process-global state in the entropy seam and the transcription boundary (row-159 L1#4, L2#6, L3#1)
…tions and the client-credentials style name no auth instance

law0 busbar x auth 53/49 and busbar-kernel x auth 50/48 were this stack's own growth: the cited 1.5.5
path `egress_auth/oauth_client_credentials.rs` reads as the `auth-oauth` plugin's id (four doc and
comment citations), and `ProviderAuth::OAuthClientCredentials` written out in two new tests does too.
The citations now name the file and its egress-auth tree apart, and the two tests name the style
through a local `ProviderAuth as Style` alias: busbar x auth back to 49, busbar-kernel x auth to 48,
no ceiling touched.
…ress::trust::net, where #800 left them

#800 (E2) deleted the kernel's net_guard re-export, so the merge of predev left this stack's
crate::net_guard / busbar_kernel::net_guard paths naming a module that no longer exists. They now name
busbar_kernel_egress::trust::net directly, as predev's own callers do (plane_host/egress.rs,
core-connector guard.rs/process.rs). No behaviour change.
…he config parser, not an alias

A `ProviderAuth as Style` alias hid a real auth-instance reference from the law0 scanner. The root
door_steps test and the kernel config_validate test now take the style the way an operator's config
gives it, `serde_yaml::from_str("oauth-client-credentials")`, so the Rust source names no instance
and nothing is hidden. busbar x auth stays 49, busbar-kernel x auth 48.
@MattJackson

Copy link
Copy Markdown
Collaborator Author

Rule 20 note from #1031 (row 155, draft): disjoint hunks in root/door_steps.rs (kernel_sections limits), root/tests/door_steps.rs (one test appended), and gemini mod.rs/tests.rs (GeminiWriter.translate_cap; the cap tests read the default const). A test merge is clean.

…and_then

compile/clippy/test were red on root door_steps.rs: UrlUserinfo::leading answers Option<Vec<..>>, so
mapping it left an Option<Option<..>> and `.first()` met an Option. and_then flattens it; no behaviour
change (no userinfo, or a binding naming authorization, keys on the empty value as before).
…a fixture data file (KN-3a)

The root door_steps test and the kernel config_validate test read
`fixtures/client_credentials_style.yaml` through the config's own parser, so the Rust source names
no auth style at all; nothing is aliased or hidden.

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