Repository navigation
K1-10 / Q-STEP9-a: pools is reserved; the strip runs at exact depths; an entry named after a reserved key is refused - #599
MattJackson wants to merge 9 commits into
Conversation
…xact depths; an entry named after a reserved key is refused at load ARCHITECT ruling 2026-10-07 (spec BUSBAR-1.6.0.md :561-570, decision #47): - `pools` (busbar_contract::section::RESERVED_POOLS_KEY) joins the deal's reserved sub-keys. - deal::strip takes reserved keys at exactly four depths, no recursion: the section, each registration, each pool (pools.<p>) and each member (pools.<p>.members[i]); every key is recorded at its path. Under a declared verb the whole `pools` subtree leaves and its pools' and members' keys are recorded too. - The root `pools:` section keeps 1.5.5's two reserved words (hooks, upstream_credentials); a pool named tier/work/breaker/rate_card/... is a pool and crosses. - spec :567 generic refusal: a declared-verb section's depth-1 entry named after a reserved key whose value is plainly not that knob is refused at load (--validate and boot), at the entry's own path and position, in reserved_name_refusal's sentence (1.5.5's bytes for the two section words).
…TION_KEYS (root_key_spelling)
promote into
|
…ted with an example of what slips through
…y pool), as the shape judge and pool reader read it
…finity beside its settings, never in them
ARCHITECT ruling P1b (b), 2026-10-07 (spec BUSBAR-1.6.0.md :552-554, :561-570): `affinity` is an
owner-locked reserved core-owned sub-key, read by the kernel and stripped before the ABI. The llm
plane read `pools.<p>.affinity.header_name` out of its own settings to derive the session key
(shaping.rs), so the strip would have taken 1.5.5's session affinity with it. The kernel now hands
the plane, beside its settings, the resolved directive of each pool:
- busbar-contract abi/plane: PlaneOpenIn.pool_affinity (a tail addition) and PlaneRefreshIn
{refresh: RefreshIn, pool_affinity}, the plane lifecycle's `refresh` `in`; one JSON object
`{"<pool>": {"header_name": "<header>"}}` (POOL_AFFINITY_HEADER_NAME), absent when no pool names a
header. Layout golden re-seeded (pre-tag v1 layout, no ABI_VERSION moves) and the C header
regenerated.
- busbar-kernel deal: `crossing(verb, section)` runs the one strip and returns, beside the stripped
section, `pool_affinity(verb, reserved)`: every pool's `affinity` read off what the strip took
(config::pools::AffinityCfg), the root `pools:` section's and a declared verb's alike, no plane
named.
- plugin-loader: open_door / refresh_door carry the projection; the facing probe is handed none
(it routes no session).
- busbar serve: a door plane's open and both refresh paths are handed its projection.
- llm plane: Shaping reads the session header off the projection (Shaping::with_affinity), never
off its settings; decisions and the test plane door read PlaneRefreshIn.
…est plane records the bytes it is handed)
…oss through the deal's one strip
Spec BUSBAR-1.6.0.md :561-570 ("A plane's settings reach it as ONE validated JSON object
{section: value} per open/refresh, reserved keys and secrets stripped; upstream_credentials is
kernel-owned"). Measured on predev 5e672d1 (Latchkey cli-d43752e9): serve.rs `open` removed only
the top-level `work`, `refresh` handed the section as written, and the owned sections and the
kernel's facing probe were handed as written, so breaker, on_exhausted, gates, hooks,
upstream_credentials, affinity, tier, repeatable, rate_card, fees, work and pools all crossed, at
the section, each registration and each pool.
- serve.rs `crossed`: the settings a door plane is handed at open and at both refresh paths
(DoorApply::refreshed, DoorAppliers::refresh_models) go through
busbar_kernel::config_validate::deal::strip (P1's one strip, its exact depths: section,
registration, pools.<p>, pools.<p>.members[i]); the root llm `pools:` keeps only its two section
words reserved, as P1 rules; the consumed sections the llm plane reads beside it (providers,
models, limits) cross through the same strip; the pool affinity projection (P1b-a) is read off
the same strip. The owned sections cross through it too.
- busbar-kernel door.rs: the facing probe's section and DoorOwned::bytes cross through it.
Secrets are not touched here (ARCHITECT, via SECURITY: P1b strips reserved keys only; the secret
references are sec-plane-secret-refs, which stacks on this).
SECURITY: P1b: a door plane's open, refresh, owned sections and facing probe cross through the deal's one strip
|
Superseded by #728: K1-10 / Q-STEP9-a carried onto predev, with predev's entry |
K1-10 / Q-STEP9-a. ARCHITECT ruling 2026-10-07, approved. Spec
BUSBAR-1.6.0.md(origin/predev) :561-570 (POOLS-VERBS; ":567 a plane entry named after any reserved key is refused at validation with a clear message (a generic check)"; ":568 one validated JSON object, reserved keys and secrets stripped"), decision #47, :4692. Stacked on #577 (p6-d2-money-labels, 6c963d2).What changes
poolsis a reserved sub-key.deal::RESERVED_SUB_KEYSgainsbusbar_contract::section::RESERVED_POOLS_KEY.busbar_kernel::config_validate::deal::stripstrips at four depths: the section, each registration,pools.<p>, andpools.<p>.members[i](when the member is a map). Each key it takes is recorded inSection::reservedat its exact path. Under a declared verb, the wholepoolssubtree leaves the blob and is recorded at[verb, "pools"]. The reserved keys of each pool and each member are also recorded at their own paths. A reserved word deeper than those four depths crosses unchanged.pools:section stays as it was in 1.5.5. This is the seat whose verb isRESERVED_POOLS_KEY. Only 1.5.5's two frozen words (hooks,upstream_credentials) are taken at section level. Every other depth-1 key is a pool. A pool namedtier,work,breaker,rate_cardand so on is a pool and crosses (v1.5.5config/mod.rs:1503-1531).config::prepass::plane_remainderreads each declared-verb section through the newdeal::read_section. That is the load both--validateand boot run. The deal (validate_dealt) runs at boot only, so it was not used.deal::names_an_entry). It is refused at the entry's own path and position, before the plane is given anything. The rendering is the same asDocument::refusal:config.yaml: invalid YAML: <section>.<key>: <sentence> at line L column C.pools:is a core-owned concrete section and is not lifted, so 1.5.5's ownPoolsCfgrefusal still applies there, unchanged.busbar_contract::section::reserved_name_refusalis nowpub. For the two section words it writes 1.5.5's sentence byte for byte. For the other reserved keys it uses the same form with a different parenthesis (below).docs/design/1.6.0-QUESTIONS.md: theQ-STEP9-arow now carries the ruling line.Refusal sentences
a {noun} may not be named `{name}`: that key is RESERVED at the `{section}:` section level (the all-{section} `hooks:` attach list and `upstream_credentials:` default). Rename the {noun}.a {noun} may not be named `{name}`: that key is RESERVED at the `{section}:` section level (the core-owned `{name}:` setting). Rename the {noun}.{noun}is the section's planesubject_noun, orentrywhen no plane declares the section.How the refusal decides that a value is not its knob
The shapes come from the kernel types that read each knob:
hooks,gates,repeatable: a list.upstream_credentials,tier: a scalar.breaker=BreakerCfg {base_cooldown_secs, max_cooldown_secs, trip};on_exhausted=OnExhaustedCfg(a word, or{fallback_pool}/{queue});affinity=AffinityCfg {mode, header_name};work=WorkBounds::of_section {max_live, retain_s};fees=PlaneFeesCfg {per_request, per_session}.poolsandrate_card: a map whose values are maps.A test pins the field lists against the types' own
expected one oflists. The check is generic and names no plane.Limit, as the ruling asks me to state:
poolsandrate_cardare maps of maps. A registration-shaped mapping whose values are all maps cannot be told apart from those knobs, so it is not refused. For example,tools.pools: {x: {...}}is read as pools. Only a clear mismatch is refused: a non-map value inside the map, a key the knob does not read, or a map where the knob is a list or a scalar. A knob of the right kind that is malformed is left to the knob's own reader.Tests and REDs
The REDs come from one Latchkey job that ran these tests over the base code (6c963d2).
config_validate::deal::tests::red_each_exact_depth_is_stripped_and_recorded_at_its_path: RED. On base,tools.poolscrossed whole, with its pool's breaker and its member's tier.config_validate::deal::tests::a_reserved_word_below_the_exact_depths_is_not_stripped: RED on base only throughpoolscrossing. The no-recursion half is a guard, because base did not recurse either.config_validate::deal::tests::red_root_pools_named_after_a_knob_are_pools_and_cross: RED. On base, root pools named tier/work/breaker/rate_card were stripped and the blob was{"pools":{}}.config::tests::a_plane_entry_named_after_a_reserved_key_is_refused_at_its_position: RED. On base, an entry named after each of the 12 reserved keys loaded. The test also checks that every well-shaped knob loads.config::tests::root_pools_named_after_a_reserved_sub_key_load_as_in_1_5_5: guard. It passes on base, andhooks/upstream_credentialsas pool names keep 1.5.5's sentence.config_validate::deal::tests::red_a_value_plainly_not_its_knob_names_an_entry,the_knob_field_lists_are_the_kernel_types_own,the_reserved_name_sentence_is_1_5_5s: these use the new API (names_an_entryand thepubsentence), so they do not compile on base.root::boot::tests::red_3g_deals_a_root_pool_named_after_a_knob_as_a_pool(busbar): RED. On base it got{"pools":{}}.cli_validate::validate_accepts_root_pools_named_after_a_reserved_sub_key_as_1_5_5_did: guard. A 1.5.5-shaped config with poolstierandworkprintsok: config valid — 1 provider(s), 1 model(s), 2 pool(s).Proof (Latchkey, head 1ed7629)
cargo fmt --all --check: rc 0.cargo clippy --locked --workspace --all-targets --all-features --exclude busbar-auth-oauth -- -D warnings: rc 0.cargo test --locked -p busbar-kernel: 2983 passed, 1 failed, 1 ignored. The one failure is the known pre-existingroot_key_spellingfailure, and it names onlyauth/inbound.rs.cargo test --locked -p busbar-contract: 1234 passed, 0 failed, 5 ignored.cargo test --locked -p busbar --bin busbar: 641 passed, 0 failed, 1 ignored.--test validate_matches_the_1_5_5_golden --test migration_corpus --test cli_validate --test docs_examples --test law7_served_surface: 49 passed, 0 failed.Oracle: base 6c963d2 vs head 1ed7629
4a7a7bba2cef, with--id-filter. The work was split into two jobs per side.^(config\.migrate\||boot\.refusal\||boot\.warning\||config\|): base and head each recorded 365 cells (rc 0), replay rc 1, 385 judged rows (229 ACCEPTED, 66 FAIL, 90 PASS). Rows sha256afe497ff76f8243a488caf26a2dc6f2055a8a9f7e577bcc53fd7fa20fca49718on both sides; byte-identical, empty diff.^(admin\.ops\|): base and head each recorded 280 cells (rc 0), replay rc 3, 240 judged rows (5 ACCEPTED, 31 FAIL, 204 PASS). Rows sha256efa0dcddf76c41de58ea36ef86a8a91cf3a97219fd6b12f5bd566392084f524eon both sides; byte-identical.Follow-up (not fixed here)
The door planes' open/refresh blob is built in
crates/busbar/src/root/serve.rs(open,settings_of, about l.1434-1500). It strips onlyworkand none of the other reserved keys. So the spec's ":568 reserved keys stripped" is not yet met at open/refresh.deal::stripis the single function that path should call. P1b will do that.Accepted limit: maps of maps (stated in QUESTIONS Q-STEP9-a too)
poolsandrate_cardare maps whose values are maps. A registration namedpoolsorrate_cardwhose own value is also a map of maps cannot be told from the knob, so it is NOT refused. It is read as the knob and leaves the crossing blob.tools: {pools: {fs: {url: "https://x"}}}, where the operator meant a tool namedpools. It is read as a pool namedfswith no members. The shape judge checks only that each value of a map-of-maps knob is a map, and the door pool reader reads onlymembers. So the operator's tool silently becomes an empty pool.tools: {pools: {fs: 3}}), a field the knob does not read, or a map where the knob is a list or a scalar.root_key_spelling, pair run (same job, base #577 6c963d2 vs head 1ed7629)
Both sides fail identically:
It is pre-existing, inherited from DEL's older base, and green on DEL 913fb20+. #599 adds no spelling: its own first-run hit in deal.rs is fixed in 1ed7629.
Head is now ed7e8de. The two commits after 1ed7629 are QUESTIONS doc edits only.