Skip to content

store-memory: busbar predev's in-tree crate, history imported, at busbar e1694a8ca1 (P5 extraction) - #12

Merged
MattJackson merged 34 commits into
devfrom
p5-extract
Oct 12, 2026
Merged

MattJackson merged 34 commits into
devfrom
p5-extract

Conversation

@MattJackson

@MattJackson MattJackson commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Merge with a merge commit: busbar pins this PR's head sha.

busbar predev's in-tree crates/store-memory, extracted (P5), at busbar e1694a8ca156c118ce5697fd8f0c50b78681db76 (1.6.0). The repo pins busbar 4e9b306af100d3f7e59f4320252068ea8067ac70: that's predev e1694a8ca1 plus one plugin-ci.yml fix on busbar's lane-p5-extract-nonplane (see below).

History

git filter-repo --path crates/store-memory/ --path-rename crates/store-memory/:store-memory/ over busbar predev at e1694a8ca1, merged into dev (2776d0d). The merge takes busbar's side for every file, so store-memory/ at the merge is busbar's crate byte for byte.

Crates

  • store-memory/ (busbar-store-memory, rlib): src/, src/tests/ and tests/ are byte for byte busbar e1694a8ca1's crates/store-memory (diff -r is clean). Only the manifest is adapted: busbar-contract, serde and serde_json from the workspace table; rlib only (the cdylib is the plugin crate's); the dropped-in feature keeps its in-tree meaning.
  • store-memory-plugin/ (busbar-store-memory-plugin, cdylib + rlib): re-exports the logic crate and forwards dropped-in to it, so the one export_door! stays in the logic crate and no build defines the door symbol twice. tests/conformance.rs is busbar's published conformance_suite! over busbar_store_memory::door and this cdylib; tests/conformance.json is busbar's own store fixture inputs at the pin.

Templated files

busbar-release plugin render busbar-store-memory --tree . --pin e1694a8ca1 1.6.0: .busbar-ref, the workspace table, deny.toml, toolchain, the CI and release workflows (plugin-ci.yml at the pin), CODEOWNERS, the community files, the README header and store-memory/declares.json (store contract ABI 3). Cargo.lock is busbar's lock at the pin, resolved by cargo metadata to this workspace.

The pin: busbar 4e9b306af1

The first run at e1694a8ca1 failed only in the release conformance step: the plugin's cdylib (libbusbar_store_memory_plugin.so) is not built under target/release. Since busbar 1882521983 (audit loader-conformance #13) the suite takes only the uplifted image or one hashed image. cargo test doesn't uplift a dependency's cdylib, and a path crate's cdylib under deps/ has no hash, so with no cache there's no image. busbar 4e9b306af1 makes plugin-ci's conformance step build the release image first, the same way the build step builds the debug one. Nothing else moves: the render at 4e9b306af1 is the render at e1694a8ca1 with the sha changed.

Checked before push (debug and release)

cargo fmt --check, cargo clippy --workspace --all-targets --locked -D warnings, cargo test --workspace --locked and the release conformance run: all 10 suite tests green, and the RED run (BUSBAR_CONFORMANCE_RED=count) fails on the comparator.

…ores (type_complexity, introduced with the #79 priced_from_ms key) and make the store conformance module's outer doc a plain comment (mixed_attributes_style); no behaviour change, store tests green
…plane's session count, a plane's declared classes, a pools open class — off the metering row the same accrual now writes (#71 #47 #42, OWNER RULING Q9/Q32, P2-usagegaps, MONEY, commits alone)

Fault named: BROKEN DERIVATION. /admin/usage prices metering rows, and a
metering row carried only the four token tiers and a request count. The budget
book's accrual (GovState::record_usage, the kernel side of meter_ledger)
holds more: one PER_SESSION per opened session on the plane's fee lane, a
plane's declared classes (tools `tool_calls`, agents `bytes`, the streams
plane's audio/text/tool classes), a pools open class (a rerank's
`search_units`). None of those reached a metering row, so the view lacked
inputs the ledger has. Ledger and rate card are correct.

Why the row and not a direct read of the budget book: the budget book is keyed
per budget bucket and budget window (a key's own bucket is ALL-TIME), not per
UTC day, so it cannot answer /admin/usage's day bucket. One derivation instead:
the SAME accrual call writes both — record_usage mirrors every class it
receives onto the key's metering row — and /admin/usage prices that row's
counts through the same one function (Tally / price_in_view) the budget book
uses. No second place computes the counts.

Seam:
- busbar-contract MeteringDelta/MeteringRow gain `usage_units` (class ->
  count, serde default, skipped when empty: every pools-only and 1.5.5 row is
  byte-identical on the store wire).
- governance: MeterCounts carries the map; record_usage -> meter_classes lands
  a plane-qualified lane "<plane>\x1f<subject>" on (subject, plane) — the row a
  plane's metered request already writes — a fee lane on ("", plane), a pools
  lane on (lane, ""). A pools lane's four token tiers are left off (the same
  response's record_metering carries them in the token columns): nothing is
  counted twice. The flush writes the map.
- store-memory / store-example-plugin sum the map. plugin-loader: a published
  1.5.x store (abi < 4) has no column for it — stripped, said once (the usage
  ledger's existing warn), and a classes-only delta is not sent at all.
- core-admin v1: derive_spend_micros_row_classes(_at_card) price the row's map
  on its lane beside its tokens (on the fee lane for a plane's fee row); the
  existing two derivations keep their signatures and route through the same
  projection (row_lanes / row_entries). get_usage passes r.usage_units.

Before -> after, GET /admin/usage total (flat fee 5; budget book in brackets,
unchanged):
- 2 sessions, streams-style plane fees.per_session 40: 0 -> 80 [80].
- 3 tool calls, tools card tool_calls 7, fees.per_request 3: 9 -> 30 [30].
- 2 reranks of 1,000,000 search units at 3 micro-units: 10 -> 610 [610].
- mixed (1 token call, 1 rerank, 1 session, 2 tool calls): 216 -> 570 [570].
- pools-only tokens (2 x 1M in / 0.5M out at 1/2): 410 -> 410 (unchanged).
Customer-visible (queue): /admin/usage total, by_key and by_model spend now
include session fees, plane class charges and pools open classes; by_model can
gain a ("", <plane>) fee row and a (<model>, "") open-class row; a PRESENT
plane card silent about a class it now sees refuses the read (409
unpriced_class, #42), as the budget book already does. On a published 1.5.x
store plugin the class counts do not persist (same as the budget ledger's
non-reserved units).

Exit tests:
- busbar-core-admin v1::service::tests::plane_fees_on_admin_usage::{
  two_sessions_price_their_session_fee_on_admin_usage,
  a_planes_ledgered_class_prices_on_admin_usage,
  a_pools_open_class_prices_on_admin_usage,
  mixed_traffic_agrees_with_the_budget_book,
  pools_only_token_traffic_is_unchanged,
  the_dated_read_prices_a_rows_classes_as_the_fallback_does}
- busbar-kernel governance::tests::the_metering_row_carries_every_class_the_budget_book_holds
- busbar-plugin-loader legacy_metering_tests::an_abi_2_store_is_never_sent_a_class_it_has_no_column_for
RED at 836abc72c (tests only): cargo test -p busbar-core-admin --lib --
plane_fees_on_admin_usage -> exit 101 (0 != 800000; 90000 != 300000;
100000 != 6100000; 2160000 != 5700000).
Green (HEAD + this change, clean worktree): busbar-core-admin lib 420,
busbar-kernel lib 1918, busbar bin 482, money_one_function_equivalence 14/14,
busbar-mcp (test-support) 576, busbar-a2a 617, busbar-llm 603, store-memory,
store-example-plugin, plugin-loader; clippy -D warnings. money-invariants
green at 836abc72c + this change (at HEAD its two scan rows are red on
root/durability.rs moved by 847c22f98 and busbar-kernel-audit/src/record.rs,
neither touched here).

Money commit, alone.
…tial kind

Both files used the sigv4/bearer scheme vocabulary purely as an opaque credential-kind
tag/token-value fixture in this store-kind's own conformance and unit tests; neither is
matched against real scheme semantics, so both are renamed to a neutral placeholder.
Assertions unchanged.
…ecords, the busbar-api edge dropped (batch 68/69 DW-store-memory, TODO item 68; #40 dependency wall, P68-0 table)

RecordStore (imported as Store), RecordStoreError/RecordStoreResult, PlaneDisposition, PlaneRecord,
PlaneSelector, VirtualKey, ModelTokens, ModelTokensDelta, SecretForm and UNIT_* are named at
busbar_contract::records, the same types busbar-api re-exports. No behaviour change: 58 crate tests
green before and after (29 unit + 3 mutation_hardening + 11 record_conformance + 15 store_conformance).
The one-line Cargo.lock hunk (busbar-store-memory drops busbar-api) is not in this commit: the lock
carries foreign uncommitted hunks.
… #40, #83): the default store and the ranking hooks are rows of the root's linked tables — the kernel names neither crate

The kernel carried two built-in plugin instances: governance/mod.rs re-exported the RAM store crate
(a kernel -> store-instance edge) and preflight.rs linked the ranking hook crate by name. Both now
come from the composition root's generated linked tables, registered through the one cold-kind axis:

- store-memory and hooks-ranking each gain a `linked` entry: STORE = (name, ephemeral, open) and
  HOOK = (name, aliases, open). The crates own their row name and the frozen strategy spellings
  (aliases of the one hook row, K5b 3c), which were the kernel's config constants before; same bytes.
- The root manifest links both ([package.metadata.busbar.linked] store-memory (required dependency,
  every build) / hooks-ranking (its feature), linked-axes `stores` / `hooks`); linked_gen.rs emits
  the two tables; main.rs hands them to busbar_kernel::preflight::install_linked_rows before anything
  resolves a row.
- The kernel keeps ONE registration function: linked_rows() builds the rows from whatever tables it
  was handed — stores, then its own secret modules, then hooks (the registration order of before) —
  and registers them through PluginRegistry::link, the admission a dropped-in row takes. A test build
  (no root) stands in the same `linked` entries through test-only edges (`test-support` feature +
  dev-dependencies, renamed fixture-store / fixture-hook in the manifest, so no kernel source names
  the plugin). The kernel's normal dependency on the RAM store crate is gone; the hook crate edge is
  test-only; the kernel's `hooks-ranking` feature now only says whether the stand-in carries that row.
- governance::MemoryStore (the universal test double) is test-only, from the store fixture.

Kernel code 50692 -> 50690 (cargo xtask loc). instance-noun-neutrality: memory@busbar-kernel 1 -> 0,
ranking@busbar-kernel 1 -> 0.

Behaviour: default build unchanged — oracle record+diff (base vs this change, families admin.ops,
auth.lifecycle, billing, boot, config, hooks, ledger, plugins, route.failover, teller, cli,
documented, ops.scrape): 814 PASS, 0 differences, 29 UNBASELINED on both sides. No money figure
moves (the store the ledger writes is the same type, opened the same way): money_never_ends_an_admitted_unit
5/5, money_one_function_equivalence 14/14, kernel spentledger/dated_budget/settlement green.
Both-ways conformance: plugin-loader 306 passed (store/hook conformance), store-memory store/record
conformance 15/11, hooks-ranking 18+2, kernel --lib 1900 passed, kernel integration tests green,
core-admin --lib 424, busbar bin 374 + integration tests green.

Exit test: root::linked::tests::the_default_store_and_ranking_hooks_are_rows_of_the_linked_tables.
RED: deleting the store-memory / hooks-ranking rows of [package.metadata.busbar.linked] fails it
(left [] vs right [("memory", true)]), exit 101.
…s its dropped-in door — a cdylib behind a `dropped-in` feature, its ONE constructor `open` exported through the contract's `export_store_plugin!`; the crate is `#![deny(unsafe_code)]` with the single macro-generated `exports` module allowed, and `linked::STORE` now names the same `open`

Exit test: crates/store-memory/tests/dropped_in_door.rs (the door's BUSBAR_COLD_ENTRY opens the
crate's own store and answers a store operation as the store answers it directly; RED at the base:
the package has no `dropped-in` feature, exit 101). qa/construction.toml: store-memory struck from
forbid-unsafe known_missing_deny (the attribute is now present; strike only).
…ault governance store is the linked store row that DECLARES itself the default (ARCHITECT ruling 2026-09-27, WARDEN store-noun (ii)); the root resolves it from the linked rows' claims and two claims refuse boot

- busbar-store-memory's linked declaration `linked::STORE` gains a default bit, `(name, ephemeral, default, open)`, and this store sets it. `preflight::LinkedStore` carries the bit.
- The root resolves the default in `root::linked::default_store`:
  - one row claims it: that row;
  - no row claims it: `None`;
  - two rows claim it: a refusal naming both ("linked stores 'a' and 'b' both declare themselves the default governance store; a build links at most one default store").
  `root::linked::register_stores` installs the rows and the resolved name through `preflight::install_linked_rows((stores, hooks, default))`. On the refusal it exits 2, before anything resolves a store, as every duplicate claim refuses boot.
- `busbar_kernel::config::GOVERNANCE_STORE_MEMORY` is deleted, along with its uses in config/mod.rs, preflight.rs, the kernel tests, root/cli.rs and root/tests/linked.rs. `default_governance_store()` reads the root-resolved name (`preflight::root_rows().2`). An omitted `store:` block, a `store:` block with no module, `StoreCfg::default()` and `store: {module: memory}` therefore resolve to one name and read back as one document. The customer-visible bytes are unchanged.
- Kernel code nets -1 line (cargo xtask loc: 51171 -> 51170; the construction kernel figure is 51090 -> 51089).
- The 7 instance-noun-neutrality [[leak]] rows that named this drain (token `store_memory`, 60b0ca984) are struck, and the `store` row measures PASS.
- qa/kind-isolation.standing.txt is lowered to the measurement for the three cells this drain moves: busbar × store 12 -> 9, busbar-kernel × store 42 -> 36, kernel -> store 42 -> 36. Posture shows no rise.

Exit tests:
- root::linked::tests::the_default_store_is_the_row_that_declares_it. RED when the resolver reads position instead of the claim.
- root::linked::tests::two_rows_declaring_the_default_refuse_boot. RED arm: first claim wins -> Ok(Some("acme-a")).
- config::tests::an_omitted_store_module_reads_back_as_the_declaring_row. RED when the default reads "" instead of the declaring row.

Oracle ^(config|boot|governance|plugins|cli): base vs mine shows 0 diverging. Against golden/1.5.5, base and mine have the same divergence set. (STORE-DEFAULT)
…ory store on the v3 table, the loader's LoadedStore

WIRE-STORE C1 (THE DESIGN, the plugin ABI; ARCHITECT rulings: WIRE-STORE approved, store v3
money slots, S1-S5, window caps v2, Q7 (b) StoreBridge).

- busbar-contract abi/sdk/store: StoreSlots, the typed trait a store implements, and store_door!,
  every store v3 slot a Safe slot over it; the Statement carries the store tail (ephemeral,
  durable_plane, fork_refusal) and declares STORE_OPID_CONFLICT / STORE_CAP_CONFLICT.
  abi/sdk/lent: the store In/Out lists and host buffers.
- busbar-contract store_calls: StoreCalls, the store kind's typed call surface (every op a
  future), and StoreFailure.
- abi/store/check: a REFUSED window_caps push may name the op_id conflict (DEDUPE applies to
  every slot); it faulted before. RED: window_caps_refusal_may_name_an_op_id_conflict, and the
  conformance script's "caps op reused" line.
- store-memory: the v3 slots (op_id dedupe log, caps, drawn totals, slices, ledger streams,
  sessions) and `door` via store_door!; the dropped-in cdylib exports it through export_door!.
  M6: the legacy cold export moves under feature cold-dropped-in (the legacy adapter's tests only).
- plugin-loader: Kind::context reads the store tail at bind (StoreFacts); store_v3::LoadedStore
  answers StoreCalls (ticketed, awaited, one short re-call) and, as the Q7 bridge, RecordStore
  (ticket-less on the caller's thread; a store that pends there is FAULT, logged at error, and a
  debug build panics).
- Tests: store_v3 unit + conformance (compiled-in == dropped-in transcript over all 47 kind
  slots) + H5 deadline classes (a hung WriteBehind op does not hold the reload drain, a hung Call
  op does, a pend on the bridge panics in debug); store_money_acceptance's MoneySlots stand-in
  rewritten to the v3 shapes at v3::bind.
… tests name no instance

WIRE-STORE C1 follow-up (gates on a Linux link and kind-isolation --posture vs f20ab051a).
- The loader's test build links its own `busbar_plugin_door` fixtures; linking
  busbar-store-memory's rlib with `dropped-in` defined the symbol twice (rust-lld: duplicate
  symbol; ld64 tolerated it). The v3 door dropped in is now the `store_memory_door` example cdylib
  (the export_door_plugin pattern); the dev-dependency keeps only `cold-dropped-in` (M6).
  both_ways::example_cdylib finds it and refuses to skip under CI. CI's dropped-in memory store row
  type-checks both doors.
- kind-isolation: the store_v3 tests and the memory store's v3 state named instance words
  (`keys`, `none`, `memory`, `streams`); renamed. kind-isolation --posture: no RISE, no NEW.
…ernal ruling or document id

public-hygiene-lint: C1 added 28 hits (bare S1-S5 / H5 / (M6) ids, 'audit 1' labels, abi-brief
references) that the gate-diff filter missed; all rewritten to plain prose. public-hygiene: 0 hits,
as the base fcf95b471.
…othing in the SDK (abi-audit F3)

BUSBAR-1.6.0.md §11.2 (docs/design/BUSBAR-1.6.0.md:1260-1261: "memory a plugin returns is
plugin-owned and valid until that plugin's next refresh generation; no allocation and no blocking
on the hot path") and §11.11 M8 (:1494, store request-path money operations) put `reserve` and
`slice_release` on the request path with no allocation. The store SDK allocated on both: the door
collected the decoded cells into a Vec and the items into a Vec<(u64,u64)>, and the StoreSlots
trait returned Vec<Grant> / Vec<u64>.

The trait now takes the input as an iterator over the host's `in` array and the answer through a
caller-provided sink:

  fn reserve<'c>(&self, op, epoch, cells: impl Iterator<Item = Cell<'c>> + Clone,
                 grants: &mut impl Extend<Grant>) -> Result<(), ReserveRefused>;
  fn slice_release(&self, op, epoch, items: impl Iterator<Item = (u64, u64)> + Clone,
                   released: &mut impl Extend<u64>) -> OpResult<()>;

The door hands the store the host's own grants/released arrays wrapped in the SDK's HostBuf
(GrantsInto, ReleasedInto; ReleasedInto still clamps each amount to its item's `unspent`), and
iterates LentList in place (LentList::iter is now also Clone). The order of checks is unchanged:
the M-SB capacity check first, then every cell decodes (a malformed cell is REFUSED with the same
text before the store is called), then the store; READY only when exactly one grant/amount per
cell/item was written, any other count FAULT; refusals/conflicts answer as before. No repr(C)
type changes.

Implementors updated: busbar-store-memory (collects into its own Vec for its dedupe log; the
dedupe body text is unchanged), the plugin-loader Miscounts double, store-memory tests.

Red-before-green: crates/busbar-contract/tests/store_money_slots_allocate_nothing.rs, a counting
global allocator over the real store door; reserve and slice_release through the SDK allocate
exactly what a bare trampoline crossing does (0 extra). It does not build against the old trait.

Money proof (one Latchkey job, LK_FULL=1): build --workspace --all-targets 0; tests
busbar-contract 1067/0, busbar-store-memory 85/0, busbar-plugin-loader 583/0;
money_one_function_equivalence EQUIV 16/16; money-invariants --selftest 0, --posture green;
no-float-money --selftest 0, gate green; fmt --check 0; clippy -D warnings 0; full-gate
--selftest 0; public-hygiene 0; oracle record + replay --strict 'billing|ledger|teller|concurrency'
vs testing/shadow-oracle/golden/1.5.5: 32 PASS, 0 FAIL. Posture (construction/kind-isolation/
qa-names) vs base 113f3858e: no new finding; busbar-contract LOC 25601 -> 25628 (ceiling 25636,
no re-arm).

(cherry picked from commit 05fe68feb6be75369bc187114089dbd10c696c37)
…ed and called nowhere

ARCHITECT R7 2026-10-01 (STORE-NOALLOC 2): after ABI-TRIM the 22-method journal trait
busbar_contract::kinds::Store had no implementor and no caller beyond the crate-root re-export
(lib.rs `pub use kinds::{.., SliceGrant, Store, ..}`). Every `impl Store for` in the tree names
another trait: store-memory's is `records::RecordStore as Store`, core-admin's is
`verb_store::Store`. kinds::SliceGrant was used only by that trait's reserve/release (the live
SliceGrant is busbar_contract::slice::SliceGrant). Both are deleted, with the re-export and the
trait-only imports (PrincipalId, RecordSchemaId, SessionId, Plugin). kinds::StoreError stays: the
memory store's record half answers it.

The construction rule no-default-bodies names its traits and refuses one it cannot find, so
`Store` is struck from qa/construction.toml in this commit (as EgressAuthScheme was), and the
construction selftest's planted default body moves from `Store` to `Plane` (plane.rs), a trait
the rule still scans, so the plant still proves the rule red.

Docs that named the deleted path now name abi::sdk::store::StoreSlots, which declares the same
record_put/record_get/record_scan (records.rs, store-memory, root keyset).
…mory straight through

ARCHITECT R7 2026-10-01 (STORE-NOALLOC 4, ruled): the copies left on the non-money store request
path were a seam defect. The store traits now take borrowed views and a store that keeps a
record copies it itself.

- busbar_contract::records: PlaneRecordRef<'a> (kind/id/parent as &str, body as &[u8], the
  typed sidecar by value), with PlaneRecord::view() and PlaneRecordRef::to_record().
  PlaneSelector<'a>::Parent is a Cow<'a, str>: borrowed where the caller holds the parent (the
  door passes the host's ABI string), owned where it came off the legacy JSON wire (StoreRequest
  carries PlaneSelector<'static>; same JSON bytes). to_static() for the legacy wire's request.
- RecordStore::upsert_plane_record / append_plane_record take PlaneRecordRef<'_>;
  list_plane_records takes &PlaneSelector<'_>. StoreSlots::append_plane_record_op takes
  PlaneRecordRef<'_>; StoreSlots::record_put takes value: &[u8] (the door refuses one over
  MAX_RECORD_BYTES first, same refusal text). The kernel's PlaneStore mirror and the loader's
  StoreCalls take the same views.
- abi::sdk::store::door: plane_record() views the host's PlaneRecordRow (no copy); record_put
  passes the host's bytes; list_plane_records SELECT_PARENT borrows the parent.
- Implementors updated: store-memory (copies inside the plugin: to_record(), RecordBytes::new;
  its op_id dedupe body keeps the PlaneRecord Debug text), the loader's LoadedStore and legacy
  DynStore (which builds its owned JSON request), the kernel's PlaneStoreView and DurableStore,
  and every in-tree test double (they rebind `let record = &record.to_record();`). Callers pass
  `rec.view()`; selector parents are borrowed instead of re-allocated.
- Witness tests/store_door_allocations.rs extended: upsert_plane_record, append_plane_record,
  list_plane_records SELECT_PARENT and record_put READY now count 0 allocations too.

Money slots (reserve, slice_release, add_usage_batch) untouched. Out-of-tree store plugins
implementing RecordStore/StoreSlots change signature when they bump their busbar pin.
The rustfmt patch the STORE-NOALLOC proof printed, applied verbatim: the rewritten
`.view()` call sites and the zero-allocation witness. No code change.

Recorded here as ruled (ARCHITECT 2026-10-01): PlaneSelector::Parent is a Cow<'a, str>, not a
&str, and that deviation is ACCEPTED. The request path stays borrowed and allocation-free (the
door hands the store the host's ABI string as Cow::Borrowed); only the legacy serde path owns
(StoreRequest deserializes PlaneSelector<'static>, where a plain &str would refuse an escaped
string).
…se-only validate, and Pending/resume for every store op

Re-lands the WIRE-STORE rescue branch (rescue-wire-store, e88152025) on predev as one commit.

- busbar_kernel::door::op_id(): the node's ONE op_id allocator (spec WIRE-STORE Q10). The node half
  is drawn once per process from the OS CSPRNG (never 0); the counter is process-global from 1.
  LoadedStore::open takes an OpIdMint, and no store handle keeps a counter of its own (a second
  handle, a reload or a restart can no longer re-mint an id that a durable store dedupes away).
- abi::store::SLICE_TTL_MS documents the store kind's epoch and slice life. A fleet store
  persists and fences the epoch and bounds valid_until_ms. A node-local store holds one epoch, and
  that rule holds for a single node only. A release always applies, capped at what the slice has
  left, and returns 0 once the slice is closed. busbar_contract::testkit::store_v3 holds the shared
  cases (fleet_store, single_node_store); store-memory runs single_node_store.
- StoreSlots::validate only parses (it never opens, connects or migrates). LoadedStore::validate
  reports the store's text verbatim. A failed open keeps predev's
  `plugin '<name>' open failed: <reason>`, which rides the host-lent reason buffer.
- abi::sdk::store: Step / Op. Every store op takes `cx: &mut Op<'_>` and may answer Pending and
  resume on its ticket with ONE connection per op (Op::checkout, established with no extra pin).
  The door FAULTs a RESUME with nothing parked and a PENDING on 0 with no connector service in
  flight, and it closes the checkout on any non-PENDING answer. StoreSlots carries the 1.5.5 op set
  itself (no RecordStore supertrait). It keeps predev's borrowed record views and its no-allocation
  money slots (reserve and slice_release read the host's array in place and write into it).
- The tests reach the build's store by KIND (fixture_<kind>.rs from build.rs), and the
  instance-noun-neutrality test-anchor rows expire. The store test doubles that predev added since
  the rescue base (the money and door allocation witnesses, the broken-store and open-reason
  fixtures) are ported to the new trait.

REDs, each failing with its fix reverted: kernel door_op_id_tests (two boots never mint an equal id);
plugin-loader store_v3 opid_tests (two handles on one durable store both land their writes);
validate_tests (validate parses and never opens the store); pend_tests (a resume with nothing parked
is FAULT); store-memory the_single_node_rule_and_the_release_rule_hold.

Proof: CI (promote preflight + hop, including the oracle replay). The local Latchkey proof log is
busbar-run/wire-store-p3.log (script wsp1.sh: build, clippy -D, tests of the touched crates, the RED
arms, EQUIV/MI/NFM, postures compared with predev, oracle strict on
billing|ledger|teller|concurrency|store-persist).
… dropped in (the store axis)

WIRE-STORE scope 2 (card handoffs/cards/WIRE-STORE.md; spec WIRE-STORE Q8/Q9; ARCHITECT 2026-10-02:
boot store door). appbuild opened the configured store with PluginRegistry::open_store: a linked
row's in-process open, or for a dropped-in plugin the cold lane (load_store_image -> wire_up_raw ->
DynStore -> StoreAdapter). A door-only store (every ported fleet store: sqlite, mysql, postgres,
valkey) could not boot ("returned a null kind string").

- busbar_contract::store_calls: StoreDoor (a linked DoorFn, or a dropped-in plugin's verified bytes
  plus its stated Statement), OpenedStore { records, calls } (Q9) and the StoreAxis trait (Q8: the
  kernel receives the axis from the root and never names the dispatcher).
- plugin-loader: PluginRegistry::store_door hands boot a store's DOOR. A store that states none (a
  1.5.5 JSON-contract plugin, or a linked row with no door) is refused naming the rebuild.
  LinkedEntry::Store carries the row's door (LinkedPlugin::with_store_door).
  store_v3::DoorStoreAxis loads the door through the ONE dispatcher (load_linked /
  load_dropped_bytes), logs under plugins.logs, declares needs on the one connection table, and
  opens a LoadedStore that the kernel's op_id allocator mints for.
- kernel: RootInstall.store_axis. The LinkedStore row carries its door; appbuild opens
  store_door(module) on the installed axis, with the same "store '<m>' plugin load failed: ..."
  error. The test build stands in the loader's axis over a test dispatcher.
- root: register_stores installs the axis over root::dispatch's dispatcher (built at boot before
  the configuration is applied), plugins.logs, connector::the() and busbar_kernel::door::op_id.
- store-memory: linked::STORE is (name, ephemeral, default, open, door).

Tests: plugin-loader store_v3::axis_tests:
boot_opens_the_build_store_through_its_door_linked_and_dropped_in_alike (both ways: the linked door
and the store_v3_door cdylib answer one 1.5.5 + v3 script, equal);
boot_is_handed_a_stores_door_never_its_in_process_open (RED before: no store_door, and boot called
the row's in-process open).

This unblocks DEL-COLD-LOADER: once it lands, nothing at boot reaches load_store_image, DynStore or
StoreAdapter::over_loaded_store. The cold path stays only for the loader's own legacy tests until that lane
deletes it.

Proof: CI (promote preflight + hop). Local Latchkey log: busbar-run/wire-store-boot-p1.log.
…s the store fixture by kind

plugin-loader's store money acceptance suite and its store v3 door fixture named the build's store
crate (`busbar_store_memory`, `MemoryStore`), the four T13b test-anchor rows. ARCHITECT Q-GG4(c)
(route accepted, move withdrawn): keep the suite in plugin-loader and reach the fixture BY KIND, as
the both-ways conformance tests do.
- build.rs: from the `[package.metadata.busbar.both-ways] store` row it also writes
  `$OUT_DIR/store_fixture.rs` (the crate alias + its cdylib stem) and `$OUT_DIR/store_door.rs` (the
  example's one `export_door!` line).
- tests/fixtures/store_v3_door.rs includes store_door.rs.
- store_money_acceptance.rs includes store_fixture.rs. Its "rust type" subject is the fixture's one
  constructor (`open`) behind the record-store face, and its cold cdylib name comes from the table.
  Two assertion messages name "the fixture store". Every money assertion and expected value is
  byte-equal. RED arms unchanged.
- a_record_blob_comes_back_byte_exact exercises the store's own inherent record API
  (record_put/get/scan), which no kind face carries. It moves into crates/store-memory/src/tests/lib_tests.rs
  (the store tests itself), assertions byte-equal.
The four drained rows and their T13b header are struck from qa/instance-noun-neutrality.toml (downward
only). No KI or [[dep]] row added; plugin-loader's dev-dependency on the fixture crate is unchanged.
# Conflicts:
#	crates/plugin-loader/tests/fixtures/store_v3_door.rs
#	crates/plugin-loader/tests/store_money_acceptance.rs
#	qa/instance-noun-neutrality.toml
# Conflicts:
#	crates/busbar-kernel/src/preflight.rs
#	crates/busbar/src/root/linked.rs
#	crates/plugin-loader/src/registry.rs
predev landing: one integration branch (train/1..14 + open predev PRs)
…ck is refused; --migrate-config inserts store: {module: memory}; the default-store claim is deleted

- config_validate refuses an absent store: with config::store_required() (1.5.5 refusal style:
  v1.5.5 config_validate/mod.rs:1655 words, v1.5.5 migrate.rs:44 command).
- migrate_store_required (last pass) inserts store: {module: memory}, or names the module of a
  store: block without one; MIGRATED_STORE_MODULE cites v1.5.5 GOVERNANCE_STORE_MEMORY.
- Deleted: LinkedStore's default flag, RootInstall.default_store_module, default_governance_store,
  StoreCfg's Default, root default_store and its tests; preflight resolves only a configured store.
- Fixtures name their store; no-store fixture + REDs: store_required_tests.rs, tests/store_required.rs.
- QUESTIONS Q133: the owner sign-off row (oracle baseline + 78 config.migrate cells, drafted entry).
…hrough the memory-ABI door

The JSON lane's store, secret and auth-verify paths are deleted: DynStore, DynSecret,
load_store*/load_secret*, the legacy 1.5.5 store wire (legacy_usage), the in-process store open
(LinkedEntry::Store keeps only the store v3 door), the cold secret fallback (a no-door secret
module is refused naming the rebuild, PluginRegistry::secret_refusal), ColdAuth and open_auth (a
no-door auth row is refused on the auth axis, auth_axis::JSON_AUTH_REFUSED). The kernel's
in-process auth test stand-ins move to auth::stand_in (test-support only).

Contract: abi/cold keeps only the two paths not yet moved — the hosted login's auth wire
(p4-oidc-repin moves it to the auth door) and the request-log file/webhook export wire (their door
re-pins need the host disk lane and the EXP2 export fixes, not on predev). The kind words move to
abi::mechanism::kind, the #85 envelope to abi::mechanism::observe, the served-route pair to
abi::mechanism::endpoint, and the HOT lane's two-symbol handshake to abi::handshake. The SDK's
store/secret JSON exports (export_store_plugin!, export_secret_plugin!, dispatch, dispatch_secret)
are gone.

The 1.5.5 refusal-at-boot proof gains its secret arm (abi_version 1, admitted until now).
…elease plugin probe expects the 1.5.x refusal
# Conflicts:
#	crates/busbar-kernel/src/preflight.rs
#	crates/busbar/src/root/tests/linked.rs
#	crates/plugin-loader/src/tests/store_conformance_tests.rs
#	crates/store-memory/src/lib.rs
…on root names it (store-memory's STORE, [package.metadata.busbar.linked-canonical] for auths), the kernel registers it with the key as alias and prints the key on every surface; the operator credential is judged by the plugin its module resolves to (config::names_operator); the admin install holds an upload to the one-version rule; --validate counts a linked copy as validated; a drift guard holds every linked row to plugins.yaml's manifest_name
…r e1694a8ca1 (P5 extraction)

git filter-repo --path crates/store-memory/ --path-rename crates/store-memory/:store-memory/ over
busbar predev at e1694a8ca156c118ce5697fd8f0c50b78681db76. store-memory/ is byte for byte busbar's
crates/store-memory at that commit; the next commit adapts its manifest to this workspace.
…uns busbar's published conformance suite

store-memory/Cargo.toml takes busbar-contract, serde and serde_json from the workspace table and is
an rlib: the linked door. Its dropped-in feature keeps its in-tree meaning (the one export_door!,
in the logic crate's door_export module).

store-memory-plugin is the cdylib a signed tarball carries: it re-exports the logic crate and
forwards dropped-in to it, so no build defines the door symbol twice. tests/conformance.rs is
busbar's conformance_suite! over busbar_store_memory::door and this cdylib; conformance.json is
busbar's own store fixture inputs at the pin (crates/plugin-loader/tests/fixtures/store_conformance.json).
…-resolved from busbar's lock at the pin

busbar-release plugin render busbar-store-memory --tree . --pin e1694a8ca156c118ce5697fd8f0c50b78681db76 1.6.0
(template/ at busbar-release 8f85d9a738, plugins.yaml at busbar e1694a8ca1): .busbar-ref, the
workspace table, deny.toml, toolchain, CI and release workflows at the pin, CODEOWNERS, the community
files, the README header and store-memory/declares.json (store contract ABI 3). Cargo.lock is
busbar's lock at the pin, resolved by cargo metadata to this workspace.
…shed suite loads

busbar lane-p5-extract-nonplane 4e9b306af1 (on predev e1694a8ca1): the conformance step builds
cargo build --release -p busbar-store-memory-plugin --lib --features dropped-in before it runs the
suite. Without it the release suite finds no image on a runner with no cache (run 38209702979:
the debug suite green, the release suite 'the plugin's cdylib ... is not built'). The pin is the only
change: the render at 4e9b306af1 is the render at e1694a8ca1 with the sha moved, and busbar-contract
is the same source.
@MattJackson
MattJackson merged commit e752176 into dev Oct 12, 2026
6 checks passed
@MattJackson
MattJackson deleted the p5-extract branch October 12, 2026 06:31
MattJackson added a commit to GetBusbar/busbar that referenced this pull request Oct 12, 2026
…-memory, pulled at a pinned rev (P5 item store-memory)

BUSBAR-1.6.0.md §9 ("Every plugin lives in its own repo"); 1.6.0-TODO.md P5 (order: ... http;
store-memory; hook-ranking; ...).

- crates/store-memory deleted (snapshot: ~/Downloads/p5-extract-store-memory-e1694a8ca1.tgz). Its
  history, imported with filter-repo, is the logic crate of GetBusbar/busbar-store-memory#12 (head
  848851e63a, merged to dev as e752176673, plugin-ci green): src/ and tests/ are byte for byte
  predev e1694a8's crates/store-memory, and the -plugin cdylib runs busbar's published
  conformance suite (store script). The repo pins busbar 4e9b306, this lane's plugin-ci fix.
- One pin: busbar-store-memory = git at 848851e63a (the root's linked store-memory row on the store
  axis and the plugin loader's store both-ways fixture, unchanged package name), and the same package
  at the same rev as fixture-store, the kernel's test-support stand-in (a rev bump moves both lines).
  The [patch] row for busbar-contract was already there. deny.toml allow-git gains the repo.
  Cargo.lock: the package takes the git source and drops serde/serde_json (dev-only).
- Ledger rows deleted with the crate (its gates run in the plugin repo's CI): qa/construction.toml
  census store 1 -> 0 (the crate keeps its package name, so the pin alone excuses the drop);
  design-bindings PB-38 and PB-99 strike the eight store-memory test citations that moved with the
  crate (each row keeps its kernel tests), ledger regenerated with `cargo xtask gate design-bindings
  --write`. qa/audit-ledger.json keeps the crate's scopes (coordinator ruling: extraction moves a
  plugin's scopes, it never strikes them). kind-isolation's rows are unchanged: the census reads
  the pinned checkout at crates/busbar-store-memory.
- Scan floors re-pinned at the measured counts, the two non-test files (src/lib.rs, src/v3.rs)
  having left with the crate: population FLOOR 941 -> 939 (settings-leak, response-header,
  blocking-ffi), tracing SCAN_FLOOR 971 -> 969.
- xtask: the kind-isolation plants on the store move to the pinned mount crates/busbar-store-memory
  (the unit tests read through pinned::with_pinned, and kind_isolation_verdict reads the store's
  lib.rs from its pinned checkout); the registry's missed-member plant names crates/plugin-loader;
  structure-lint's plugin-dir fallback is crates/busbar-plane-decisions.
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