Skip to content

Fold prep: substrate co-bump, CI, and the constitution corpus re-home - #136

Merged
emooreatx merged 10 commits into
mainfrom
fold-prep/substrate-catchup
Sep 4, 2026
Merged

emooreatx merged 10 commits into
mainfrom
fold-prep/substrate-catchup

Conversation

@emooreatx

Copy link
Copy Markdown
Contributor

Prepares CIRISRegistry for the fold into CIRISServer. Four commits, each independently reviewable.

What lands

commit
fa6dc30 Remove the constitution corpus — CC + CEG are homed at CIRISAI/CIRISConstitution (#131)
c77efd6 Add a CI test pipeline
aacab5d Co-bump the substrate triple to CIRISServer's pins (#76)
72bc0a7 Reconcile FSD-002 with the ratified constitution (#132)

The co-bump was far cheaper than the version numbers suggest

persist v5.5.5 → v32.3.0, edge v2.2.2 → v17.4.1, verify v5.1.3 → v13.3.1.

That reads as 31 major versions of persist drift. The library compiled against it without a single edit. All six changes were in test code:

  • KeyRecord.roles → capability_roles, plus new consent_role / additional_scrubs — 2 sites
  • Attestation.additional_scrubs — 2 sites
  • Ed25519Signer::random() is now fallible — 2 sites

The surface held because only 12 of this crate's files touch the substrate at all, the From<federation::Error> match ends in a catch-all arm, and this crate declares its own 8-method FederationDirectory trait and delegates into persist's rather than implementing it — so persist growing that trait is invisible here.

That last change is a safety improvement rather than churn: random() returns Result so it fails secure when ciris-crypto's RNG health check has marked the source degraded, instead of silently minting a key from it.

Pinned to CIRISServer's tags, deliberately not to latest

persist v36.1.0 / edge v17.8.0 / verify v13.4.0 exist. We are not taking them. CIRISServer#340 measured why: persist and edge both pin verify by git tag, and a cargo git tag is part of the source ID rather than a semver range — so moving the verify pin alone forks verify instead of upgrading it, yielding two incompatible ciris_keyring + ciris_verify_core crates. The verify pin moves only as part of an upstream persist+edge co-bump.

Two checks that would have bitten in production, not CI

  • No wire break. No persist federation type is serialized into an HTTP response — they are confined to federation/ and edge_transport/ — so the roles rename is invisible to the three live nodes.
  • No libsqlite3.so.0 crash-loop. The graph still resolves a single libsqlite3-sys 0.28, so the bundled feature union still propagates to every consumer.

Also removed the pkcs8 = "=0.11.0-rc.11" resolver pin: it existed to stop cargo preferring API-incompatible stable pkcs8 over the pre-release ml-dsa rc.8 wanted, and v13.3.1 ships stable ml-dsa 0.1.1, so the pin now conflicted with the dependency it was added to satisfy and blocked resolution outright. MSRV 1.84 → 1.86 (verify's floor; Dockerfile is on 1.93 and unaffected).

CI

There was none — docker.yml built an image and nothing ran cargo test; last main run was 2026-06-13. Two jobs now: build + 148 tests with no database (this crate uses runtime sqlx::query(...), never the compile-time query! macros), and db_integration against a postgres:16 service.

Gated on build and tests only. cargo fmt --check carries ~200 standing diffs and clippy 200+ warnings against 0 errors — gating either would make the workflow red on arrival, and reformatting inside a substrate bump would bury the six-line diff. Both are noted in the workflow header as follow-ups.

Doc corpus

The constitution moved to its own repo and evolved past the copies here (1.0-RC3 vs the 0.7 carried here). manifests/WIRE_VOCABULARY.md had diverged too — sha256 c6bd6aa4… here against 80dfa166… upstream, so #131's "sha256 unchanged" note was itself out of date and this repo held the stale copy.

FSD/CEG/ is replaced by a redirect stub rather than deleted: ~28 files across seven sibling repos link into FSD/CEG/*.md, and the stub carries the 20-section → 8-Part map since the §N numbering did not survive the re-home. Cross-repo repointing is follow-up, not a prerequisite. CEG_VERSION corrected from 0.10 to 1.0-RC3 — note the 1.0-RC29 line this directory declared is discontinued lineage, not a later revision than RC3.

FSD-002 (#132)

Two defects. The ladder-named dimensions (attestation:l1:self_verify) contradicted the ratified mechanism-named set — CIRISVerify's shipped crate already carried an authority note flagging this exact drift and citing #132. One occurrence was not a rename: an enforcement rule keyed on the prefix attestation:l1:*, which under the ratified set has no subtree, so it now binds a single leaf dimension.

The second is a signing-preimage injection surface. §3.2.1.x pinned a line-oriented preimage — newline-delimited key=value — and source = direct:{url} carries attacker-influenceable text, so a crafted URL with a newline plus a key= sequence can present a different field set that hashes identically. CC supersedes it with a v2 JCS form that closes the class by construction; CIRISVerify adopts it as a deliberate wire break (CIRISVerify#231). Retired blocks are preserved and marked MUST-NOT rather than deleted, for the ~34 inbound citations.

Not in this PR

All 32 open issues are triaged and labelled (fold:move-to-constitution 16 / fold:closes-via-fold 8 / fold:real 8), each with a comment stating its disposition. None were closed — that is a maintainer call.

Closes #76
Closes #131
Closes #132

…CIRISConstitution (#131)

The CIRIS Constitution moved to its own repo and has evolved past the copies
here: CIRISConstitution is at 1.0-RC3 while FSD/CIRIS_Constitution carried 0.7.
manifests/WIRE_VOCABULARY.md had likewise diverged — its sha256 is c6bd6aa4…
here against 80dfa166… upstream, so #131's "sha256 unchanged" note is itself
out of date and the stale copy was the one in this repo.

Removed:
  - FSD/CIRIS_Constitution/ (54 tracked files + the .aux/.log/.out build litter)
  - manifests/WIRE_VOCABULARY.md

FSD/CEG/ is replaced by a redirect stub rather than deleted outright. Roughly
28 files across seven sibling repos (Server, Persist, Edge, Verify, Agent,
Conformance, NodeCore) link into FSD/CEG/*.md paths; the stub gives those links
a signpost and carries the section→part mapping, since the 20 CEG sections were
reorganised into the constitution's 8 Parts and the §N numbering did not survive
the move. Cross-repo repointing is follow-up work, not a prerequisite.

Also corrects CEG_VERSION from "0.10" to "1.0-RC3". The registry has been
emitting 0.10 on every response's CEG-Version header. Note the 1.0-RC29 line
this directory used to declare is DISCONTINUED lineage from before the re-home —
it is not a later revision than RC3, and the stub says so explicitly so nobody
"restores" the higher number. No test or consumer pinned the old value.

Intra-repo links in MISSION.md, docs/ and FSD-003 are repointed at the stub.

Refs #131
…han prod

The registry has had no `cargo test` in CI. `docker.yml` builds an image and
gates :latest behind a smoke test, which catches a broken binary but not a
broken behaviour. The last main-branch run was 2026-06-13.

That is a tolerable gap for a repo nobody is changing. It is not tolerable for
one about to take the persist/edge/verify co-bump (#76): the substrate delta is
small (five struct fields) but the verification story is currently "deploy to
three live nodes and watch", which is the wrong place to discover a mistake.

Two jobs, split so a database outage cannot mask a compile or logic regression:

  test — build + 148 tests, no database. Registry uses runtime `sqlx::query(...)`
         and never the compile-time `query!` macros, so there is no live schema
         to verify against at build time and no .sqlx cache to keep in sync.
  db   — `tests/db_integration.rs` against a postgres:16 service, since
         `sqlx::test` creates and migrates a database per test.

Deliberately not gated, both for the same reason — they are red on arrival and
fixing them inside a substrate bump would bury the diff that matters:

  - `cargo fmt --check`: ~200 standing rustfmt diffs. Land the reformat on its
    own commit, then add the gate.
  - clippy `-D warnings`: 200+ standing warnings, 0 errors. Clippy runs so
    regressions stay visible in the log, with continue-on-error.

Verified locally against the exact commands the workflow runs: 103 lib +
19 crypto_properties + 26 capability_properties, all green, `--locked` clean.
    persist  v5.5.5  → v32.3.0
    edge     v2.2.2  → v17.4.1
    verify   v5.1.3  → v13.3.1   (ciris-crypto + ciris-keyring)

Pinned to the tags CIRISServer 0.5.177 pins, NOT to the newest tags (persist
v36.1.0 / edge v17.8.0 / verify v13.4.0 exist). Matching exactly is the point:
registry-core is being absorbed into that workspace, and CIRISServer#340
measured what divergence costs — persist and edge both pin verify by git `tag`,
and a cargo git tag is part of the source ID rather than a semver range, so
moving the verify pin alone forks verify instead of upgrading it. This old
floor is precisely why CIRISServer held registry-core out of its dependency
graph; it can come back in now.

The gap reads as 31 major versions of persist. The real cost was six changes,
all in test code — the library itself compiled against the new substrate
without a single edit:

  KeyRecord.roles → capability_roles, plus the new consent_role and
  additional_scrubs      — 2 sites (edge_transport/content_miss, federation/mod)
  Attestation.additional_scrubs (new)
                         — 2 sites (edge_transport/agent_files, content_miss)
  Ed25519Signer::random() is now fallible
                         — 2 sites (api/http, build_manifest)

That last one is a safety improvement rather than churn: `random()` returns
Result so it can fail secure when ciris-crypto's RNG health check has marked
the source failed, instead of silently minting a key from a degraded RNG.

Revocation.revoked_after was also added upstream but this crate never
constructs a Revocation literal, so it needed no change.

The surface held because only 12 of this crate's files touch the substrate at
all, the `From<federation::Error>` match ends in a catch-all arm (new upstream
variants cannot break it), and this crate declares its OWN 8-method
FederationDirectory trait and delegates into persist's rather than implementing
it (so persist growing that trait is invisible here).

Also removed: the `pkcs8 = "=0.11.0-rc.11"` resolver pin. It existed because
ciris-crypto pulled `ml-dsa = "=0.1.0-rc.8"` and cargo's caret resolution for
pre-releases would otherwise select API-incompatible pkcs8 0.11.0 stable.
v13.3.1 pulls stable `ml-dsa = "=0.1.1"` which wants plain `pkcs8 ^0.11`, so
the pin now conflicts with the dependency it was added to satisfy and blocked
resolution outright. Registry never used pkcs8 directly.

MSRV 1.84 → 1.86, the highest of the three floors (verify 1.86; persist 1.83,
edge 1.75).

All feature names survived the gap unchanged — persist `postgres`/`sqlite`,
edge `transport-reticulum-tcp-{server,client}`, crypto `pqc-ml-dsa`, keyring
`software`/`pqc-ml-dsa`.

Green: 103 lib + 19 crypto_properties + 26 capability_properties, `--locked`
clean. db_integration still needs a live postgres (now wired in CI).

Closes #76
FSD-002 is cited 34 times across CIRISVerify as the normative attestation-
surface spec, so its drift propagates. Two defects, and the second is the
serious one.

1. Ladder-named dimensions contradicted the ratified set.

   §3.2 carried `attestation:l1:self_verify` … `attestation:l5:agent_integrity`.
   CC part_3 §3.1.2 and CIRISVerify's shipped constants
   (ciris-verify-core/src/federation_provenance.rs::dim) both use mechanism
   names with no ladder number. CC gives the reasoning: L-numbers name a
   verdict-shape, not a mechanism, and the L1-L5 ladder lives as consumer-side
   composition per CC 4.4.3.6 Policy I. Verify dropped the ladder from the wire
   in v3.7.0 and CC subsequently ratified it — FSD-002 was the sole outlier.

   Note the L2 row changed TWO tokens: the ladder number went, and the mechanism
   token is `hardware_rooted`, not `hardware`. The rename carries through §4.3,
   §4.8, §5.3 and §5.5.

   One of those is not a rename. §948's enforcement rule was keyed on the PREFIX
   `attestation:l1:*` — a pattern matching a prefix nothing emits. Under the
   ratified set there is no `l1` subtree, so the rule now binds a single leaf
   dimension, `attestation:self_verify`, and not a wildcard.

2. §3.2.1.x pinned a line-oriented signing preimage — an injection surface.

   The v1 canonical bytes were a domain prefix followed by newline-delimited
   `key=value` fields. A delimiter-based preimage is ambiguous whenever a field
   carries attacker-influenceable free text, and `source = direct:{url}` is
   exactly such a field: a crafted URL carrying a newline plus a `key=` sequence
   can present a different field set that hashes identically.

   CC supersedes it with a v2 JCS form — `sha256(JCS({…}))` over pinned `.v2`
   domain literals — which closes the class by construction. Producers MUST emit
   v2; CIRISVerify adopts it as a deliberate wire break (CIRISVerify#231). Only
   the Merkle LEAF preimage changed; parent-node hashing, locale ordering,
   padding and inclusion-proof shape are untouched.

The retired v1 blocks are preserved and marked MUST-NOT at §3.2.1.1-R and
§3.2.1.2-R rather than deleted, and the retired ladder names are kept in
correction notes, so a reader arriving from one of the ~34 inbound citations
finds what replaced them instead of a silent gap.

No FSD-002 version bump: the version line of record is CC's, not this
document's. This repo no longer carries the spec — normative pointers now go to
CIRISAI/CIRISConstitution.

Closes #132
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@socket-security

socket-security Bot commented Aug 18, 2026 •

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
High CVE: cargo hickory-proto: NSEC3 closest-encloser proof validation enters unbounded loop on cross-zone responses

CVE: GHSA-3v94-mw7p-v465 hickory-proto: NSEC3 closest-encloser proof validation enters unbounded loop on cross-zone responses (HIGH)

Affected versions: >= 0.25.0-alpha.3 <= 0.25.2

Patched version: No patched versions

From: ? → cargo/hickory-proto@0.25.2

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/hickory-proto@0.25.2. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: libcrux: Potential Panic on Overlong Ciphertext Buffer in cargo libcrux-chacha20poly1305

CVE: GHSA-hc3c-63hc-2r9f libcrux: Potential Panic on Overlong Ciphertext Buffer (HIGH)

Affected versions: < 0.0.8

Patched version: 0.0.8

From: ? → cargo/libcrux-chacha20poly1305@0.0.6

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/libcrux-chacha20poly1305@0.0.6. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: libcrux: Potential Panic on Overlong Ciphertext Buffer in cargo libcrux-chacha20poly1305

CVE: GHSA-hc3c-63hc-2r9f libcrux: Potential Panic on Overlong Ciphertext Buffer (HIGH)

Affected versions: < 0.0.8

Patched version: 0.0.8

From: ? → cargo/libcrux-chacha20poly1305@0.0.7

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/libcrux-chacha20poly1305@0.0.7. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: libcrux has All-Zero Key Generation Upon Catastrophic RNG Failure in cargo libcrux-ed25519

CVE: GHSA-434v-x5qv-pmh6 libcrux has All-Zero Key Generation Upon Catastrophic RNG Failure (HIGH)

Affected versions: < 0.0.7

Patched version: 0.0.7

From: ? → cargo/libcrux-ed25519@0.0.6

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/libcrux-ed25519@0.0.6. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: libcrux Panics During Standalone MAC Operations in cargo libcrux-poly1305

CVE: GHSA-pv9v-5j35-xwcr libcrux Panics During Standalone MAC Operations (HIGH)

Affected versions: < 0.0.5

Patched version: 0.0.5

From: ? → cargo/libcrux-poly1305@0.0.4

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/libcrux-poly1305@0.0.4. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

emooreatx and others added 3 commits August 19, 2026 18:23
    persist  v32.3.0 → v37.1.0
    edge     v17.4.1 → v18.2.0
    verify   v13.3.1 → v13.6.1

Supersedes the previous commit's target. That one matched CIRISServer 0.5.177's
then-current pins; edge 18.2 is the declared **Server 0.6 (registry fold)**
release, so the fold's floor moves with it. Server co-bumps to the same set.

## Why this set is takeable

The rule from the previous commit stands — never move the verify pin alone,
because persist and edge both pin verify by git `tag` and a tag is part of the
source ID, so an independent bump forks verify rather than upgrading it
(CIRISServer#340). What makes this bump safe is that the set is **internally
coherent**:

    edge v18.2.0   pins persist v37.1.0  and  verify v13.6.1
    persist v37.1.0                      pins verify v13.6.1

One verify in the graph, not two. Confirmed in the lockfile: ciris-crypto and
ciris-keyring both resolve to exactly 13.6.1.

## Cost

Nothing. Zero source changes — not even in tests this time.

KeyRecord, Attestation and Revocation are **field-identical** between v32.3.0
and v37.1.0, so the construction sites the previous commit fixed needed no
further work. All 20 substrate symbols this crate imports survive at the new
tags. MSRV stays 1.86 (verify's floor; persist 1.83, edge 1.75).

Leviculum rode along 0.16.0 → 0.20.0 as edge's transitive Reticulum stack.

Re-verified the two pins that would bite in production rather than CI:
libsqlite3-sys still resolves to a single 0.28, so the `bundled` union holds and
the libsqlite3.so.0 crash-loop stays closed; and no persist federation type is
serialized into an HTTP response, so nothing here is wire-visible to consumers.

Green: 103 lib + 19 crypto_properties + 26 capability_properties.

Refs #76, #62
    persist  v37.1.0 → v40.0.0
    edge     v18.2.0 → v20.1.1
    verify   v13.6.1 → v14.1.0

## verify 14.2.0 exists and is deliberately NOT taken

Both edge v20.1.1 and persist v40.0.0 pin the verify family at v14.1.0. Taking
14.2.0 would not upgrade verify — it would FORK it, because a cargo git `tag` is
part of the source id, not a semver range (CIRISServer#340). One verify in the
graph is the whole constraint. 14.2.0 becomes available when persist and edge
repin, not before.

## One real change this time

`FederationDirectory::put_attestation` now returns `AttestationOutcome`
(Inserted | AlreadyHeld) where it returned `()`. We discard it, and the comment
at the call site says why that is safe rather than leaving a reader to guess:

persist documents BOTH variants as idempotent success — "I already hold this" is
the anti-entropy protocol working, deliberately not an error variant. A genuine
disagreement (same attestation_id, different bytes) never reaches the Ok path;
it is a typed `Error::Conflict` and still propagates.

What is lost is the Inserted-vs-AlreadyHeld progress signal. Registry's own
FederationDirectory trait returns `Result<()>`, nothing acts on the distinction
today, and widening a trait on a crate being dissolved into CIRISServer to carry
a signal no caller reads would be speculative. Widen it when something needs it.

KeyRecord / Attestation / Revocation remain field-identical across the gap, so
no construction site moved. MSRV stays 1.86. Leviculum rode 0.20 → 0.24.

Re-verified: single libsqlite3-sys 0.28 (the `bundled` union holds, so the
libsqlite3.so.0 crash-loop stays closed), and no persist federation type is
serialized into an HTTP response, so nothing here is wire-visible.

Green: 103 lib + 19 crypto_properties + 26 capability_properties.

Refs #76, #62

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iEaqmXHrbpy7P1rvXR6BS
…ds the directory (#133, #137, #138)

Two changes that let the registry navigate the CEG-native transition honestly,
on the nodes that are live today.

## /v1/steward-key now serves the baked GenesisBundle

The old body published registry's own key as a trust root — unsigned on the
wire while declaring `signature_mode: "HYBRID_REQUIRED"`, asserting
`hardware_class: HSM_PROD` under `self_attested: true`, and in a shape none of
verify's three client schemas could parse. There was no working contract to
preserve, so it is replaced rather than repaired (#133).

What is served is the GenesisBundle persist bakes: the humanity-accord charter,
the A1/B1/C1 roster, the infra:* scopes the charter confers, and the serve-node
grants. It is self-authenticating — its `authorizations` are hybrid signatures
from accord holders over the charter, re-derived by the consumer from its OWN
records. Everything outside `bundle` is unsigned convenience metadata, and there
is deliberately no `response_signature`: signing the wrapper would prove only
that the relay said so, which is exactly what the old endpoint proved. The
schema is field-for-field CIRISServer's `/v1/trust-root/bundle`, which is now
also served here under that path, so the fold changes nothing a consumer sees.

## /v1/builds provenance stops asserting what it never verified

`compose_federation_provenance` synthesized `provenance:build_manifest:{target}`
at `score: 1.0, confidence: 1.0` from the Postgres row itself, attributed to
whoever inserted it — an unsigned self-assertion in the position of an
attestation, and one that OVER-reports: a consumer was told a manifest was
attested when a row had merely been inserted (#138). Its own comment conceded
the intent: "#17 will read from federation_attestations once attestations land
there."

It now reads the directory. The manifest entry is emitted only when a
pipeline-signed Contribution binding this exact (target, binary_version,
manifest_hash) exists, signed by a `node` key carrying the accord-conferred
infra:attest role, whose bound-hybrid signature re-verifies here against the
pipeline's directory-pinned pubkeys — the same threshold-1 check
ciris_verify_core::manifest_contribution performs. Absent that, the dimension is
ABSENT and `note` says so. Walk order is forced by what the directory indexes:
no dimension index exists, so it starts from WHO may attest and lists what each
blessed pipeline signed. The bless predicate requires the role AND an accord
scrub (primary or additional); a role a key declares about itself confers
nothing.

Nothing emits these Contributions into the directory yet — CIRISServer#25 is
the consumer half and the producers are not wired (#138 has the order). So
today this returns no manifest entry everywhere. That is the correct answer
today, and the code lights up unchanged when the pipelines start signing.
Manifest BYTES continue to be served from the registry's build table through
the transition; only the provenance claim changed.

## -stable is folded on read, and nothing else

Publishers strip the channel suffix before registering, so registry holds
`2.9.48` while the agent reports `2.9.48-stable` and nothing on the consumer
side re-strips it — a guaranteed 404 on data that exists (#137). `-stable` is
the publisher's own documented equivalence and is folded on version lookup.
`-rc*`/`-beta*` are NOT: an rc and a stable of the same number are different
artifacts, and folding them would serve the stable manifest for an rc query — a
false pass. A test pins the asymmetry.

## Plumbing

- ciris-verify-core added as a direct dep (default-features = false, "pqc").
  The note refusing it over a libsqlite3-sys conflict was stale: persist has
  pulled it transitively at every tag since #76, and the lock resolves one
  libsqlite3-sys 0.28. Declaring it adds nothing to the graph.
- registry's FederationDirectory trait gains list_keys_by_identity_type
  (NoOp + persist delegation) — the entry point of the walk.
- VerificationPolicy is retained: it belongs to /v1/accord-holders, not
  steward-key.

Five tests pin the invariants that would regress into over-reporting: the
outer envelope claims no authority; the baked bundle names its charter and
roster; the version fold strips -stable only; a pipeline is blessed only by an
accord scrub carrying the role; an empty directory yields no manifest
provenance and a note that says ABSENT.

Green: 108 lib + 19 crypto_properties + 26 capability_properties.

Refs #133, #137, #138, #62, CIRISServer#25

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iEaqmXHrbpy7P1rvXR6BS
…substrate floor)

MAJOR per RELEASE.md: adopting a new spec series bumps MAJOR. 2.x was CEG 0.2;
this branch moves CEG_VERSION to the constitution's current cut and reconciles
FSD-002 to it. #41 also pre-declared the cutover as v3.0.0.

CC 1.0-rc4 shipped while this was in flight (2026-09-04). Nothing rc4 changed
touches what FSD-002 was reconciled against — part_3 §3.1.2's attestation
table and §3.1.2.1's canonical bytes are untouched — and rc4's 3.4.7.3 ruling
(`node` exclusive of `agent`/`user`; infrastructure holding no agency is what
can be trusted to refuse it) strengthens the model the manifest consumer is
built on: a CI pipeline blessed with infra:attest stays pure `node`. The
CEG-Version header now matches the constitution's VERSION file byte-for-byte
(`1.0-rc4`), since that file is the artifact the header claims conformance to.

Cut directly rather than through an rc: RELEASE.md prefers vX.Y.Z-rc.N first
for breaking changes, but rc tags do not promote :latest (docker.yml promotes
only on refs/heads/main), so an rc would not reach the three nodes. The wire
changes are the point of this release.

Deviates from RELEASE.md step 3 in one respect: `cargo update -p` on the two
member crates rather than `cargo update --workspace`. The workspace form would
also bump every transitive crates.io dependency in a release commit, which is
not what a version bump is for; the lock changes here are exactly the two
package versions.

Rollback: no migrations. Config unchanged. The old /v1/steward-key shape and
the synthesized provenance entry are gone — both by design, see CHANGELOG.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iEaqmXHrbpy7P1rvXR6BS
@emooreatx
emooreatx force-pushed the fold-prep/substrate-catchup branch from 8da9ae8 to 48fb171 Compare September 4, 2026 18:26
emooreatx and others added 2 commits September 4, 2026 13:28
CC 1.0-rc4 landed while the 3.0.0 cut was in flight. One of its rulings
touches FSD-002 directly: CC 2.1 no longer names an
`accountability:mode_shift:{from}:{to}` dimension. Per rc4, a mode shift is a
stewardship act on the delegation plane — a superseding `delegates_to` carrying
the new scope set — and there is no `accountability:*` family at all:
accountability is structural (the audit chain), never a named axis, which is
why the earlier draft's dimension could never have admitted under CC 3.1.7 R2.

FSD-002 v1.4.1 announced that dimension in two places (the §2.1 changelog
bullet and the `oversight_mode` envelope-field row) as "attestable
Contributions". Both now state the withdrawal and quote the rc4 ruling
verbatim, extracted programmatically from CC part_2's own `oversight_mode`
row rather than paraphrased, so the two documents cannot drift in wording.

The `oversight_mode` FIELD itself is unchanged and remains in the envelope —
rc4 withdrew the attestable-dimension claim, not the human-control gradient.

Confirmed before removing it: no shipped code emits or parses
`accountability:mode_shift` — zero occurrences across CIRISVerify, CIRISAgent,
CIRISPersist, CIRISServer and CIRISNodeCore outside tests. Removing it from
the spec opens no doc/code split; it closes one the spec had with the
constitution.

Same class as #132 (FSD-002 is cited ~34x by CIRISVerify as normative);
found by the rc4 adoption pass rather than filed separately.

Refs #132

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iEaqmXHrbpy7P1rvXR6BS
The FSD-002 correction in 3e3c3b6 ships in this release; the notes should say
so rather than leave "reconciled with CC" to imply it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iEaqmXHrbpy7P1rvXR6BS
@emooreatx
emooreatx merged commit 2dd4518 into main Sep 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment