Skip to content

feat(economic): the beta root register is pinned to the register histories the real fleet holds - #771

Merged
cryptskii merged 1 commit into
mainfrom
feat/pin-root-register-set-id
Sep 5, 2026
Merged

feat(economic): the beta root register is pinned to the register histories the real fleet holds#771
cryptskii merged 1 commit into
mainfrom
feat/pin-root-register-set-id

Conversation

@cryptskii

Copy link
Copy Markdown
Collaborator

Item B.1 of the locked order: pin the root-register authority set, so D runs against a tree with no open authority assumption.

What #770 left open, and what this closes

#770 gave a vault's birth commitment (member_id, register_incarnation_id) pairs, but the network-wide root register still derived its set id from whatever candidate the catalog offered, constrained only to the right member ids. The adversarial gate would rightly ask who chose the incarnation values? — and the answer was "the resolved catalog candidate."

Now RootRegisterProfile carries storage_set_id as a pinned commitment, and verify_candidate replaces derive_set_id at every call site — two conjuncts, neither sufficient alone:

  1. the candidate's member ids are exactly the network's members;
  2. the id re-derived from the candidate's pairs equals the pin.

A member that rebuilt its register passes 1 and fails 2 → new refusal SetIdIsNotThePinnedOne, never a silent resolution to a different register. Endpoints stay transport metadata.

The pin is the three real (member, incarnation) pairs, not an opaque digest. One source: the member list and the id both derive from them, so they cannot drift; an auditor reads which register histories are trusted. pinned_root_register_members() is public — a commitment, not a secret — and every fixture builds from it, so nothing duplicates values that must match.

Unprovisioned fails closed by construction. The placeholder was all-zero, which #770 already refuses as the "not yet established" sentinel; confirmed ProfileNotDerivable(ZeroRegisterIncarnation) before the values landed.

Provisioning — the values came off the real nodes, in the order you set

Per node (dsm-node-1/2/3): pg_dump snapshot (forensic only, pre-b1-wipe-*.sql.gz) → DROP SCHEMA public CASCADE → boot merged f00d1e0c with [storage_set] absent → node mints and logs its incarnation → collect all three → write [[storage_set.members]] into every node and the client config → restart. Every node then logged the same set id, E05YS8101EJH33KY2CG625JJE8A0Z4GJNSEM335TX1XVTWM9RR8G, and no node refused (the #770 refusal for a config/DB incarnation mismatch was live throughout).

member incarnation (Base32-Crockford, as logged)
dsm-node-1 DXWR7W9J2E5ASQ5BJBYF13ZZEK1VFTZFYNWAYPF1KNT8C33YPVM0
dsm-node-2 H4ZSDG34M1BSQQH8T9WWWZ65Y90YW9QY2CYRR2EG3H621VDGJ3W0
dsm-node-3 VW3REAWA7PR608Y4AY3VX18M8BE4828PFPNVTG380XV18HKF8SSG

Two tests pin this end to end: beta_root_register_pins_render_to_the_logged_values (the pinned bytes render to exactly those strings — also cross-checked against the raw register_incarnation rows) and the_pinned_beta_set_id_is_the_one_every_provisioned_member_logged (core's derivation equals the id every node logged).

Mutation control

verify_candidate stops comparing against the pin → one_member_rebuilding_its_register_changes_the_set_id red (got Ok(()) — the rebuilt member was accepted). Restored on an identical tree stamp.

Verification (Rust 1.98.0)

  • root make lint — exit 0
  • workspace board — 3984 passed, 0 failed
  • node board (SQLite) — 288 passed, 0 failed
  • node board (Postgres 14) — 258 passed, 0 failed
  • production_safety_checks.sh (incl. TLA+), ci_scan.sh, no_clock_and_no_json.sh, check_forbidden_symbols.sh — all exit 0

What went wrong on the way, stated

  • I built the wrong Dockerfile first. Local Docker Desktop was wedged, so I built on node 3 — from ci/docker/StorageNode.Dockerfile (distroless, no CMD) instead of Dockerfile.cloud. The binary defaulted to --config config.toml, found nothing, and main.rs silently fell back to localhost:5432 → crash loop. Recovered by wrapping the already-compiled binary in Dockerfile.cloud's runtime stage (trixie-slim to match the builder's glibc — the one deviation). Nothing was minted by the failed boot (schema still empty), so the wipe-then-mint ordering held.
  • That silent fallback is a real defect (required(false) config + defaulted database.url): a node that can't read its config should refuse, not quietly connect to localhost. Filed as a follow-up, out of this PR's scope.
  • Pre-existing gap surfaced: no node sets node.network_id, so all three log faucet-ticket register is INACTIVE. Economic admission cannot complete on this fleet until network_id = "dsm-testnet" is configured. Your call; I did not change it.
  • Phones must re-register — device rows went with the schema, as you chose.

…ories the real fleet holds

#770 gave a vault's birth commitment `(member_id, register_incarnation_id)`
pairs, but the network-wide root register still derived its set id from
whatever candidate the catalog offered, constrained only to the right member
ids. "Who chose the incarnation values?" answered "the resolved catalog
candidate" — and `derive_set_id(&candidate) -> Result<[u8; 32]>` returned the
id derived from its own input, which both call sites then used as the
expected id. A checker that returns what it derived hands the authority to
its input.

`RootRegisterProfile` now carries `storage_set_id` as a pinned commitment, and
`verify_candidate` replaces `derive_set_id` at every call site: the candidate's
membership must be the network's AND the id re-derived from its pairs must
equal the pin. A member that rebuilt its register passes the first and fails
the second, and is refused (`SetIdIsNotThePinnedOne`) rather than silently
resolved to a different register. Endpoints remain transport metadata.

The pin is the three real `(member, incarnation)` pairs, not an opaque digest:
member list and set id both derive from the one source, so they cannot drift,
and an auditor can read which register histories are trusted.
`pinned_root_register_members()` is public — a commitment, not a secret — and
every fixture builds from it, so nothing holds parallel values that must
match. Before the values existed the placeholder was all-zero, which the
encoder already refuses; an unprovisioned network fails closed by
construction (`ProfileNotDerivable(ZeroRegisterIncarnation)`), not by anyone
remembering to check.

The values came off the provisioned nodes in the owner's order. Each member:
forensic `pg_dump`, `DROP SCHEMA public CASCADE`, boot on merged `f00d1e0c`
with `[storage_set]` absent, mint and log the incarnation. Then the collected
pairs were written as `[[storage_set.members]]` to every node and to the client
config, and every node restarted into the set logging the identical id
`E05YS8101EJH33KY2CG625JJE8A0Z4GJNSEM335TX1XVTWM9RR8G` with no refusal. Two
tests pin this end to end: the pinned bytes render to exactly the strings each
node logged (cross-checked against the raw `register_incarnation` rows), and
core's derivation equals the id every node logged.

Mutation control: disabling the pin comparison turned
`one_member_rebuilding_its_register_changes_the_set_id` red (`got Ok(())` —
the rebuilt member was accepted); restored on an identical tree stamp.

Not changed, surfaced: no node sets `node.network_id`, so the faucet-ticket
register is inactive fleet-wide until it is configured. A fail-open in
`main.rs` (optional config + a defaulted `database.url` that quietly points
at localhost) is filed separately; it turned a wrong-image build into a
crash loop during provisioning rather than a refusal.

Verification (Rust 1.98.0, the version rust-toolchain.toml declares):
- root `make lint` exit 0
- workspace board 3984 passed, 0 failed
- node board (local-dev,strict / SQLite) 288 passed, 0 failed
- node board (default features / Postgres 14) 258 passed, 0 failed
- production_safety_checks (incl. TLA+), ci_scan, no_clock_and_no_json,
  check_forbidden_symbols all exit 0
@cryptskii
cryptskii merged commit b0dc977 into main Sep 5, 2026
19 checks passed
@cryptskii
cryptskii deleted the feat/pin-root-register-set-id branch September 5, 2026 21:27
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