From 7cdf49ecb66d3fa9428eb9e7d43cea68ee9e4df0 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 8 Sep 2026 16:12:19 -0500 Subject: [PATCH 1/2] =?UTF-8?q?0.5.204:=20the=20minor=20triple=20=E2=80=94?= =?UTF-8?q?=20edge=20v21.1.0=20/=20persist=20v42.1.0=20/=20verify=20v15.0.?= =?UTF-8?q?0;=20dimension=20reads=20are=20index-served=20(#557=20closed=20?= =?UTF-8?q?at=20the=20substrate)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopts CIRISServer#571. Pins ×4 persist, ×2 edge, the lens-core member, TARGET_* in the substrate gate, README, evidence rows; one copy each. persist v42.1.0: #817 both dimension axes of list_attestations are index-served (V137 on the generated `dimension` column; the prefix filter is a range on it) — the substrate fix for our #557; graph_config's config: prefix scan is no longer O(rows this node authored), and its comment says so. #818 a prefix filter compares bytes on every backend. edge v21.1.0: #579 the cohab lane injects verify beside persist (our lane injects no pins). Ships what main carries since 0.5.203: #569 the legible, bounded stop; #570 the per-engine config snapshot cache; #566 the gating Windows installer; #565 the process-global test log capture. Closes #571. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0132ELwj5JU6t4jEKpwH9bJ7 --- Cargo.lock | 10 +++++----- Cargo.toml | 14 +++++++------- README.md | 2 +- crates/ciris-lens-core/Cargo.toml | 4 ++-- evidence/CIRISServer.cc_impl.tsv | 16 ++++++++-------- src/graph_config.rs | 18 +++++++++--------- tests/release_gates/substrate.rs | 4 ++-- 7 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84ab8420..a9ee318e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -964,8 +964,8 @@ dependencies = [ [[package]] name = "ciris-edge" -version = "21.0.0" -source = "git+https://github.com/CIRISAI/CIRISEdge?tag=v21.0.0#6174b20533a19558d274df446494fea744d32f2c" +version = "21.1.0" +source = "git+https://github.com/CIRISAI/CIRISEdge?tag=v21.1.0#4dca38d77fdbb3ff15fb08735ab0457a3cba4cdc" dependencies = [ "async-trait", "axum", @@ -1086,8 +1086,8 @@ dependencies = [ [[package]] name = "ciris-persist" -version = "42.0.0" -source = "git+https://github.com/CIRISAI/CIRISPersist?tag=v42.0.0#13aa6347f15085cd8253a6265a3e873202650126" +version = "42.1.0" +source = "git+https://github.com/CIRISAI/CIRISPersist?tag=v42.1.0#00bc08e52a114c1099cb083af9d043ebfa73800f" dependencies = [ "anyhow", "async-trait", @@ -1132,7 +1132,7 @@ dependencies = [ [[package]] name = "ciris-server" -version = "0.5.203" +version = "0.5.204" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index c7cd9503..b2908282 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ciris-server" -version = "0.5.203" # 0.5.203 = A SPLIT NODE SIGNS ITS CONSENT AS ITSELF (CIRISServer#563, from the Android run-without-AI leg, CIRISAgent#1149). On an agent-hosted node the engine signs as the ACTOR and boot mints/adopts a separate NODE key (CC 3.4.7.3 Clause A); the consent guard compared that node signer's keystore ALIAS to the node's DERIVED id, so the boot re-author that moves the actor's grants onto the node (the #312 cure) refused every grant — a node whose actor peered at setup died on its next boot, and the one test covering it registered its node under a bare label. Now: `peer::signer_holds` recognises both signer conventions (registered id verbatim, or alias whose derived id is the registered id); the split records the node's signer for the process (`node_key::set_node_signer` / `held_node_signer`) and a consent emit naming the node with no explicit signer authors through it, so `POST /v1/federation/peers`, the edge's consent callback and the coverage top-up author as the node on a split node without learning about the split; the key-split fixture registers its node under the derived id like production, and a new end-to-end test drives the real sealed node keystore through resolve → re-author → runtime emit. Substrate unchanged: edge v21.0.0 / persist v42.0.0 / verify v15.0.0. 0.5.202 (the tag that SHIPPED the triple; 0.5.201 never published — Windows wheel) content follows: Substrate: edge v21.0.0 / persist v42.0.0 / verify v15.0.0 (CIRISServer#559, from edge; a MAJOR on both substrates — the floor moves for the major, all four persist ABI constants unchanged). persist v42: #811 an agent member whose only incoming edge is an UNMARKED conferral is no longer steward-bound (this repo's three `is_steward_bound` sites are on node keys, which the rule exempts, and its conferrals carry `delegation_purpose: owner_binding`); #814 part 3 (CC 3.4.5.1) the `config:` live set is ONE row per (subject, scope, leaf) and a renewal MUST be a `supersedes` naming the row it replaces — this reddened four suites here, because the plane kept every key on one leaf `config:v1`, so the second key's write was refused; the plane now puts each key on its OWN leaf `config:{key}:v1`, the first write of a key is a `scores` row and every later write a `supersedes` of the leaf head (revoked or not — persist does not fold a recant out of its live set), the read is one prefix scan of the `config:` family on the `dimension` column reading both row types, rows written before 0.5.201 on the legacy leaf still read and are shadowed by version when the key is next written, and a key that cannot name a `vocab` segment is refused at the door with the reason; the `config:admission` / `config:transport` sensitive-leaf floor (`self` only) is met by every write here; #815 dimensions are case-sensitive per segment (every dimension here is lowercase). verify v15: `FedCode` and `OwnedNode` are `#[non_exhaustive]` — the mint builds its code through `FedCode::new(...).with_alias_hint(...).with_ml_dsa_65_pubkey_sha256(...)`; and `AdmittedHybridKey::admit(&code, pulled)` is the ONLY constructor of a hybrid registration input, fail-closed without a commitment — the fedcode v3 pull path (`POST /v1/contacts` with a code, 202 → pull → re-paste) binds the pulled ML-DSA-65 half through it. ALSO ON MAIN SINCE 0.5.200 and shipped here: the SIGTERM broker (#555/#556 — `docker stop` ends the node cleanly; a process-lifetime broker owns the signal, installed before the first boot phase, propagating termination after teardown unless a host owns SIGTERM) and the config snapshot (#557/#558 — `graph_config` reads are one scan per process with write invalidation, `ConfigSnapshot`; the status node's 20 s-of-a-core config resolve becomes one scan). Client floor 0.5.203. +version = "0.5.204" # 0.5.204 = THE MINOR TRIPLE, AND THE STOP IS LEGIBLE. Substrate: edge v21.1.0 / persist v42.1.0 / verify v15.0.0 (CIRISServer#571, a minor on #559; leviculum unchanged). persist v42.1.0: #817 dimension reads are INDEX-SERVED (V137 indexes the generated `dimension` column and the prefix filter compiles to a range on it) — this closes CIRISServer#557 at the substrate, so `graph_config`'s `config:` prefix scan is no longer a per-row json_extract over everything the node authored; #818 a dimension-prefix filter compares BYTES on every backend (sqlite's LIKE was case-insensitive). edge v21.1.0: #579 the cohab lane injects verify beside persist (an explicit pin beats a transitive range). ON MAIN SINCE 0.5.203 and shipped here: #569 the stop is legible from the node's own log — a serve marker names a stop that skipped the door (`/serving.json`, WARN on the next boot with the dead pid), the read API's drain reports in_flight/drained per listener, every stop request names its origin, every teardown step is timed/named/bounded (10 s) and the edge run loop that never returned after its shutdown (CIRISEdge#578) no longer holds the process: SIGTERM → exit in ~10 s with status 143 instead of never; #570 the config snapshot cache is one slot per engine with per-engine invalidation (the one-scan flake on mac/win); #566 the Windows installer builds from the client package and its job is gating; #565 the test log capture is a process-global routing layer (#542). Client floor 0.5.203. edition = "2021" # MSRV floor is set by the substrate: ciris-verify v5.2.0 requires 1.86 # (persist v6.0.1 is 1.83). Build with the higher of the two. @@ -135,8 +135,8 @@ ciris-lens-core = { path = "crates/ciris-lens-core" } # ABSORBED in-tree (wo # `cirislens_wa_cert` + `cirislens_service_token_revocation` expose the auth # substrate the fabric absorbs (CIRISServer#9, src/auth): the agent's `wa_cert` # table (users/WA/OAuth/api-keys) + the `revoked_service_tokens` table. -ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.0.0", features = ["sqlite", "scrub", "cirisgraph", "cirislens_wa_cert", "cirislens_service_token_revocation", "cirisaudit", "cirislens_tasks", "cirislens_thoughts", "cirislens_tickets", "cirislens_correlations", "cirislens_deferral_reports", "cirislens_maintenance_locks", "cirislens_creation_ceremonies", "cirislens_legacy_migration", "cirisincident", "telemetry", "secrets"] } -ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v21.0.0", features = ["transport-reticulum", "transport-http", "transport-packet-radio", "ffi-uniffi"] } +ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.1.0", features = ["sqlite", "scrub", "cirisgraph", "cirislens_wa_cert", "cirislens_service_token_revocation", "cirisaudit", "cirislens_tasks", "cirislens_thoughts", "cirislens_tickets", "cirislens_correlations", "cirislens_deferral_reports", "cirislens_maintenance_locks", "cirislens_creation_ceremonies", "cirislens_legacy_migration", "cirisincident", "telemetry", "secrets"] } +ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v21.1.0", features = ["transport-reticulum", "transport-http", "transport-packet-radio", "ffi-uniffi"] } # Founder-quorum verification + key-id fingerprint at the composition root # (threshold:: module path — NOT re-exported at the crate root). # LOCKSTEP: persist v9.4.0 transitively pins verify-core v6.6.x — the whole @@ -276,7 +276,7 @@ tracing-appender = "0.2" # - keyring `tpm` (tss-esapi / TPM 2.0) — the real hardware backend; needs # libtss2 (Linux build dep). Other targets keep the software keystore. [target.'cfg(target_os = "linux")'.dependencies] -ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.0.0", features = ["postgres", "scrub", "cirisgraph", "cirislens_wa_cert", "cirislens_service_token_revocation", "cirisaudit", "cirislens_tasks", "cirislens_thoughts", "cirislens_tickets", "cirislens_correlations", "cirislens_deferral_reports", "cirislens_maintenance_locks", "cirislens_creation_ceremonies", "cirislens_legacy_migration", "cirisincident", "telemetry", "secrets"] } +ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.1.0", features = ["postgres", "scrub", "cirisgraph", "cirislens_wa_cert", "cirislens_service_token_revocation", "cirisaudit", "cirislens_tasks", "cirislens_thoughts", "cirislens_tickets", "cirislens_correlations", "cirislens_deferral_reports", "cirislens_maintenance_locks", "cirislens_creation_ceremonies", "cirislens_legacy_migration", "cirisincident", "telemetry", "secrets"] } # keyring `tpm` (TPM-at-rest, Linux-only via tss-esapi). `pkcs11` is no longer # per-target — it rides the global `pkcs11` feature now that cryptoki builds on all # targets (CIRISVerify v6.12.0). @@ -305,7 +305,7 @@ ciris-keyring = { git = "https://github.com/CIRISAI/CIRISVerify", tag = "v15.0.0 # `full_traces` at Detailed and RELABELS the trace `detailed`, loudly. A mobile # node therefore never ships content claiming a scrub it did not receive; it # simply cannot offer the NER tier. -ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.0.0", features = ["scrub-ner"] } +ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.1.0", features = ["scrub-ner"] } serialport = "4" # libsqlite3-sys (pulled by persist's `sqlite` feature) links the SYSTEM libsqlite3 @@ -363,7 +363,7 @@ ciris-crypto = { git = "https://github.com/CIRISAI/CIRISVerify", tag = "v15.0.0 # and never encodes/decodes). This lets tests/chaos_mesh.rs exercise the SUBSTRATE # codec (`fountain_encode`/`fountain_decode`) directly — a real MEASURED proof, # not a reference stand-in. -ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v21.0.0", features = ["codec-fountain"] } +ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v21.1.0", features = ["codec-fountain"] } # Enable persist's TEST-ONLY genesis-seam (`test-genesis-seam`, CIRISPersist#387) for the # accord ceremony tests (tests/accord.rs): `Engine::with_signer_pre_genesis` yields a clean # engine with the HUMANITY_ACCORD genesis seed SKIPPED, so those tests can stand up their OWN @@ -375,7 +375,7 @@ ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v21.0.0", # without one. Pre-genesis is now a supported boot mode, not a test seam, and an Engine built # that way reports `GenesisPosture::PreGenesis` while every ROOT_REQUIRING_GATES gate refuses # with `NoConstitutionalRootYet`. A node that trusts nothing is not a node that checks nothing. -ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.0.0" } +ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.1.0" } # The QA runner exercises the family/accord ceremony surfaces against a # CONTROLLABLE roster — holders it can sign as. persist v31.0.0 made roster growth diff --git a/README.md b/README.md index 42e4439f..a225b9a0 100644 --- a/README.md +++ b/README.md @@ -339,7 +339,7 @@ itself, while a quorum roots to `humanity-accord`. The charter is 2-of-2 over a — a replicated row proves its own m-of-n rather than deferring to the bundle it arrived in. Two humans to halt, two to legitimize. -Substrate pins: **persist v42.0.0 / edge v21.0.0 / verify v15.0.0** — hybrid PQ +Substrate pins: **persist v42.1.0 / edge v21.1.0 / verify v15.0.0** — hybrid PQ throughout, Registry-of-Record admission, drift-witnessed policy hashes. Edge v15.7.x adds the realtime A/V spine (MLS X-Wing epoch keys, signed Welcome, fragment ARQ); the server exercises publisher → relay → subscriber diff --git a/crates/ciris-lens-core/Cargo.toml b/crates/ciris-lens-core/Cargo.toml index 1f68a298..36df7acf 100644 --- a/crates/ciris-lens-core/Cargo.toml +++ b/crates/ciris-lens-core/Cargo.toml @@ -25,8 +25,8 @@ crate-type = ["cdylib", "rlib"] # # OQ-01 closure 2026-05-03: rlib primary, PyO3 cdylib via `python` # feature for the deployed-lens cutover. -ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.0.0", version = "42", features = ["extract", "sqlite"] } -ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v21.0.0", version = "21", features = ["transport-http", "transport-reticulum"] } +ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v42.1.0", version = "42", features = ["extract", "sqlite"] } +ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v21.1.0", version = "21", features = ["transport-http", "transport-reticulum"] } # Keyring — relay mode (CIRISLensCore#10) loads its Edge transport- # signing identity via `ciris_keyring::load_local_seed`. Edge's diff --git a/evidence/CIRISServer.cc_impl.tsv b/evidence/CIRISServer.cc_impl.tsv index 34b658d7..5171edc8 100644 --- a/evidence/CIRISServer.cc_impl.tsv +++ b/evidence/CIRISServer.cc_impl.tsv @@ -10,14 +10,14 @@ # # ─── RESOLVED ────────────────────────────────────────────────────────────────── decimal_id claim_id repo path#symbol crate@version -3.1 CLM-nsproc-dimension CIRISServer src/compose_policy.rs#polarity_for ciris-server@v0.5.203 -4.4.2 CLM-nsproc-aggregation-policy CIRISServer src/compose_policy.rs#polarity_for ciris-server@v0.5.203 -4.4.3.4.3 CLM-nsproc-cohort-scope CIRISServer src/graph_config.rs#set_config ciris-server@v0.5.203 -4.2.2.1 CLM-nsproc-attestation-evidence CIRISServer src/hardware_attestation.rs#admit_hardware_class_against_root ciris-server@v0.5.203 -2.6.6.1 CLM-location CIRISServer src/location.rs#mint_location_proof ciris-server@v0.5.203 -2.6.6 CLM-canonicalization-cell CIRISServer src/location.rs#mint_location_proof ciris-server@v0.5.203 -3.4.5 CLM-capacity-score CIRISServer src/scorer.rs#score_and_emit ciris-server@v0.5.203 -3.3.7 CLM-consent-directed CIRISServer src/peer.rs#emit_replication_consent ciris-server@v0.5.203 +3.1 CLM-nsproc-dimension CIRISServer src/compose_policy.rs#polarity_for ciris-server@v0.5.204 +4.4.2 CLM-nsproc-aggregation-policy CIRISServer src/compose_policy.rs#polarity_for ciris-server@v0.5.204 +4.4.3.4.3 CLM-nsproc-cohort-scope CIRISServer src/graph_config.rs#set_config ciris-server@v0.5.204 +4.2.2.1 CLM-nsproc-attestation-evidence CIRISServer src/hardware_attestation.rs#admit_hardware_class_against_root ciris-server@v0.5.204 +2.6.6.1 CLM-location CIRISServer src/location.rs#mint_location_proof ciris-server@v0.5.204 +2.6.6 CLM-canonicalization-cell CIRISServer src/location.rs#mint_location_proof ciris-server@v0.5.204 +3.4.5 CLM-capacity-score CIRISServer src/scorer.rs#score_and_emit ciris-server@v0.5.204 +3.3.7 CLM-consent-directed CIRISServer src/peer.rs#emit_replication_consent ciris-server@v0.5.204 # # ─── DECLARED GAPS ───────────────────────────────────────────────────────────── # Controls the Constitution attributes to this repo that are NOT enforced here. diff --git a/src/graph_config.rs b/src/graph_config.rs index f46f6719..3bd5b37e 100644 --- a/src/graph_config.rs +++ b/src/graph_config.rs @@ -617,15 +617,15 @@ async fn live_config_rows(engine: &Arc) -> Result { // The FAMILY prefix, not one exact leaf: since persist v42 every key is // its own leaf (`config:{key}:v1`), and the legacy single leaf `config:v1` // matches the same prefix, which is how a corpus written before 0.5.201 - // keeps reading. On this handle persist compiles `dimension_prefixes` to - // `json_extract(attestation_envelope, '$.dimension') LIKE 'config:%'` — - // still a per-row JSON parse of everything this node authored, exactly as - // `dimension_exact` was (CIRISServer#557); the `attesting_key_id` predicate - // is what bounds it. That is why the result is cached as a snapshot, and - // why the indexed family seek is asked of persist (CIRISPersist#817) - // rather than papered over here. No type filter: the first write of a key - // is a `scores` row and every renewal is a `supersedes` (CC 3.4.5.1); both - // carry the entry and both are folded below. + // keeps reading. Since persist v42.1.0 (CIRISPersist#817, filed from + // CIRISServer#557) this handle compiles `dimension_prefixes` to a RANGE on + // the indexed generated `dimension` column (V137) — the read is + // index-served, no longer a per-row `json_extract` over everything this + // node authored — and (#818) compares bytes, not case-folded LIKE. The + // snapshot cache stays: the point was fifty getters costing one read, and + // that is true whatever the read costs. No type filter: the first write of + // a key is a `scores` row and every renewal is a `supersedes` (CC 3.4.5.1); + // both carry the entry and both are folded below. filter.dimension_prefixes = vec![CONFIG_DIMENSION_PREFIX.to_owned()]; // ── The scope gate is REAL and this read must pass it honestly ────────── diff --git a/tests/release_gates/substrate.rs b/tests/release_gates/substrate.rs index c7c83e74..54def99c 100644 --- a/tests/release_gates/substrate.rs +++ b/tests/release_gates/substrate.rs @@ -13,8 +13,8 @@ use crate::ladder::{ /// The substrate floor this cut ships on. Moving a release means moving these /// three deliberately, in one commit. pub const TARGET_VERIFY: &str = "v15.0.0"; -pub const TARGET_PERSIST: &str = "v42.0.0"; -pub const TARGET_EDGE: &str = "v21.0.0"; +pub const TARGET_PERSIST: &str = "v42.1.0"; +pub const TARGET_EDGE: &str = "v21.1.0"; /// Every substrate repo we pin by git tag, and the crate names that come out of /// it. All crates from one repo MUST carry ONE tag. From 75507ecdb8eb8f06b5fe0d1a3bdc5547bd26bca3 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 8 Sep 2026 16:24:43 -0500 Subject: [PATCH 2/2] ci: retrigger with the ci:full label present (a substrate repin runs the full OS matrix) Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0132ELwj5JU6t4jEKpwH9bJ7