Repository navigation
Registry fold, phase 1+2a (PR #442): the registry slice is conferred, not configured — and the portable trust root is broadcast #537
Description
Activity
- addedarea:trust-rootGenesis, accord, canonical blessing, haltGenesis, accord, canonical blessing, halt
on Sep 4, 2026 Ruling to carry through the fold (Eric, 2026-09-22): infrastructure does not vote. Voting for infrastructure is done only by the accord; the canonical node's owner handles its configuration. Recording it here with the texts and the artifacts that currently say otherwise.
The CC already says this. CC 3.4.7.1:
node(infrastructure) = "steward +infra:*reach only, never agency." CC 3 (cc3 §"infrastructure must not have agency"): "Infrastructure is the right enforcer precisely because it has no agency of its own to exercise," and "Authority stays quorum-bound. A co-locatedstewardrole does NOT let a single node issue a federation-scope attestation." CC 3.2'sciris-canonicalworked example lists founders asregistry_steward_us/eu/apac— steward keys, human-rooted — not node keys. The infrastructure community is a roster/audience object for the service installs; its admission quorum is the accord's, not the nodes'. Config: CC 3.4.5config:{scope}is self-or-owner — the node reports it, its owner sets it.The code already behaves this way.
accord.rs::canonical_op_quorum_mresolves Structural ops throughkill_switch_quorum_m→family_quorum_m, which readshumanity-accord's entrenchedquorum:M/N. Operational is the1knob (#441).quorum.rs::canonical_community/verify_canonical_quorum— the node-founder quorum — have zero callers insrc/. On the live canonical (read-only):federation_families=humanity-accord(A1/B1/C1,quorum:2/3);federation_communities= 0 rows.What contradicts the ruling and needs re-cutting:
FSD/REGISTRY_FOLD_DERISK.md§1 — "entrenched 2-of-3 founder-quorum over the threeciris-canonicalper-node keys. A node gains a vote, never a verdict." Nodes gain no vote. The trust-root swap is steward-key → accord quorum, with theciris-canonicalcommunity as the conferred roster the accord admits into.src/quorum.rs— its stated purpose (a per-node founder quorum) andverify_canonical_quorum; either delete or re-document as verifying an accord signature set over the community record.- add-canonical is 1-of-3 while the baked founding record is 2-of-3 — decide the Operational quorum before canonical-2/-3 are admitted #441 — the Operational/Structural quorum question is over the accord holders; a "canonical roster" that votes is not a thing.
- CC-native build manifests: drain the manifest Contribution, walk infra:attest delegation to the human, drop the steward key #25 §3 — the build-authority trust config hangs off the
ciris-canonicalcommunity's stewards, not off node founders.
What is still true and still missing: the
ciris-canonicalinfrastructure community row itself (CC 3.2, Commons-tier per CC 4.4.3.2.1) — created by accord co-scrub, founders = the accord-conferred steward keys, members = the canonical installs with rolemember. It is the audience for manifests-as-blobs (CC 3.1.9.1agent_files+holds_bytes) and the re-root target for consumers. Creating it does not give any node a vote.- addedstate:needs-decisionBlocked on a maintainer/product/policy call — the question is in a comment.Blocked on a maintainer/product/policy call — the question is in a comment.size:LMore than three days, or a new subsystem.More than three days, or a new subsystem.enhancementNew feature or requestNew feature or request
on Sep 25, 2026 Status check against origin/main (046e1b3), 2026-09-25. Labelled
state:needs-decision.PR #442 is still open (last updated 2026-09-04, based on the edge 18.2 main; main is now edge v31). None of it is on main:
compose_registryis stilltodo!()(src/compose.rs:5161), and there is noregistry_slice_conferredand noGET /v1/trust-root/bundle. Thetodo!()is still reachable ifcfg.slices.registryis set true. That is the trap phase 1 was written to remove.The 2026-09-22 ruling also means
src/quorum.rsandFSD/REGISTRY_FOLD_DERISK.md§1 need re-cutting.Question for the maintainer: should PR #442 be rebased onto v31 and landed with the ruling applied? Or should it be closed and phase 1 (the role gate and the non-panicking body) and phase 2a be re-cut fresh?
Tracking issue for PR #442 — the first two increments of folding
ciris-registry-coreinto this repo (CIRISRegistry#62). The PR is green on all eight checks and rebased onto the edge-18.2 main; this records why it is shaped the way it is, so the decisions survive the PR body.The ordering constraint the whole fold hangs on
Convert registry-us / registry-eu into
ciris-canonical-2/-3first, and you turn two working registries into two blessed nodes that cannot do registry work. So "can serve registry capabilities" has to be something the node evaluates, not something an operator asserts. That is what phase 1 makes true.Phase 1 — the role gate (
ffa3b5f)Before: the slice was selected by
cfg.slices.registry, a boolean defaulting tofalse. An operator setting a boolean is exactly the self-assertion the accord-scrub model exists to remove. A node is canonical because the trust root signed off; the authority slice it runs must be conferred the same way.After:
registry_slice_conferred()walkscapability_roots_to_trusted_root(dir, me, me, INFRA_ATTEST_SCOPE). Both key ids are ours deliberately — the question is "do I hold this capability, from a root I myself accept?" — and the second half is the operator's un-trust lever: delete thetrust:acceptsrow and the walk returnsNone, the slice goes dark on its own, nothing special-cased it. The check lives insidecompose_registry, because an authority check belongs with the thing it authorises.cfg.slices.registrysurvives as an opt-out only: it can keep a blessed node from serving; it can never make an unblessed node serve.No charter amendment was needed — the verbs already exist. This was the open question and the answer is favourable: the baked
genesis-charterdeclares[infra:attest, infra:serve, infra:store, infra:transport], andgenesis-grant:ciris-canonical-1-d7bdeu223kcarries all four. Registry's work is attestation-shaped, so it ridesinfra:attest+infra:serve, which a canonical node holds the moment it is blessed. That matters because the scopes live in the signed bytes — amending the charter is an m-of-n re-scrub by the holder roster, not an edit.The gate could not join
Capabilities.Capabilities::detectruns before the Engine opens — it is a pre-corpus structural gate, which is whyDEFAULT_LENS_STORE_MIN_GIBis a baked constant rather than aconfig:*object. A delegation-graph walk needs the corpus, so this gate is necessarily post-corpus, at slice-composition time.The trap the PR is shaped around.
compose_registrywas atodo!(), unreachable only because the bool defaulted to false. Swapping the boolean for the grant check without first giving the function a non-panicking body would panic at boot on exactly the nodes that are blessed — canonical-1 holds all four verbs. A production outage dressed as a one-line change. So the body is honest instead: blessed nodes log that the surfaces are not composed yet; unblessed nodes log the withholding as the steady state it is;Ok(None)is not an error. Three tests pin it, includingmatches!(.., Ok(None))on that regression directly.Phase 2a — the portable trust root is broadcast (
b5beb15)GET /v1/trust-root/bundleserves theGenesisBundlepersist bakes — charter, roster, scopes, serve-node grants. Public, mounted without a loopback layer (unliketrust_root_api's import/list/delete verbs, which are the operator's own act): a peer bootstrapping into the mesh has to be able to fetch the root and check it against its own roster. The bundle was scanned before exposure — public keys, signatures, an already-announced transport hint, YubiKey PIV certs; nothing withheld-worthy.Why this retires
/v1/steward-keyrather than repairing it (CIRISRegistry#133). Registry published its own key as its own trust root, and the live state was worse than the issue said: three mutually incompatible schemas exist and no two agree — verify's actual HTTP client expects single-steward{classical{}, pqc{}, …}whose non-Optionfields are absent from what registry served, so it failed to deserialize outright; the spec-conformant parser next to it was never reached by the HTTP path. The live response also declaredsignature_mode: "HYBRID_REQUIRED"while carrying no signature at all, and assertedhardware_class: HSM_PRODunderself_attested: true. There was no working contract to preserve.The invariant: authority lives inside
bundleand nowhere else. The bundle is self-authenticating —verify_bundle_quorumre-derives authority from the reader's records, so a forged bundle carrying attacker "holders" proves nothing (CIRISPersist#377). Everything outsidebundleis unsigned convenience metadata. There is deliberately noresponse_signature: signing the wrapper would prove only that the relaying node said it — precisely what/v1/steward-keyproved, and precisely what was worthless — and it would invite consumers to check the envelope instead of the artifact. A test pins thatresponse_signature/signature_mode/hardware_classnever appear on the outer envelope. Registry v3.0.0 (CIRISRegistry#136) serves the identical schema at both paths, so the fold changes nothing a consumer sees.What #442 does not do, and what comes next
compose_registrystill composes nothing. Phases 2b–4 are the persist-native rewrite of the residual with live consumers — builds, verify manifests, revocation, integrity, transparency — dropping sqlx and tonic rather than porting them (12,153 + 14,400 LOC of registry-core's 21,689 touch one or the other), and Portal's UI arriving as client cards so its RPC surface stops existing rather than being re-hosted. Scoped in the PR'sFSD/REGISTRY_SLICE_ROLE_GATE.md§6.provenance:build_manifest:*at confidence 1.0 and reads the directory instead, but nothing emits the Contributions yet — the producer and the CI-key bless ceremony (Serve /v1/accord/ci-key/{propose,cosign} — the CI-bless (approve CI runner) serve leg; verify 10.3.0 consumer half already bundled (CIRISVerify#185) #290) both shipped; the drain has not (CIRISRegistry#138 has the order).add-canonicalfrom the Trust Root card. Which still wants the quorum decision in add-canonical is 1-of-3 while the baked founding record is 2-of-3 — decide the Operational quorum before canonical-2/-3 are admitted #441: the op is 1-of-3 today while the baked founding record is 2-of-3, and these two admissions double the canonical set.Refs: #442, #25, #290, #441, CIRISRegistry#62, CIRISRegistry#133, CIRISRegistry#136, CIRISRegistry#138, CIRISPersist#377.
Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com
🤖 Generated with Claude Code
https://claude.ai/code/session_014iEaqmXHrbpy7P1rvXR6BS