ciris-server 0.5.77__tar.gz → 0.5.78__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ciris_server-0.5.77 → ciris_server-0.5.78}/Cargo.lock +5 -5
- {ciris_server-0.5.77 → ciris_server-0.5.78}/Cargo.toml +5 -5
- {ciris_server-0.5.77 → ciris_server-0.5.78}/PKG-INFO +1 -1
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/Cargo.toml +2 -2
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_provision.rs +42 -4
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/compose.rs +27 -3
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/holonomic.rs +4 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/replication_reconcile.rs +20 -6
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/accord_admit_node.rs +106 -0
- ciris_server-0.5.78/tests/mesh_seed_keyplane_e2e.rs +225 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/support.rs +2 -2
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/replication_reconcile.rs +23 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.cargo/config.toml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.claude/workflows/localize-ui.js +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/bench.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/build-wheels.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/ci.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/client-artifacts.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/conformance.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/localization.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/publish-pypi.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/release.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/.gitignore +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/CHANGELOG.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/LICENSE +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/MISSION.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/README.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/WIRE_VOCABULARY_KINDS.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/bench-site/bench_results.json +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/bench-site/index.html +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/bench_results.json +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/alm_chain.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/erasure_survival.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/n_eff_scoring.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/pqc_av_streaming.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/replication_ingest.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/sig_overhead.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/stream_fanout.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/.github/workflows/bench.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/.github/workflows/ci.yml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/.gitignore +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/.pre-commit-config.yaml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/FSD/CIRIS_LENS_CORE.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/FSD/LENS_CORE_V0_5.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/FSD/OPEN_QUESTIONS.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/LICENSE +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/MISSION.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/README.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/benches/aggregate.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/benches/canonicalize.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/benches/project.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/deny.toml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/BENCHMARKS.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/COHABITATION.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/PRE_COMMIT.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/PUBLIC_SCHEMA_CONTRACT.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/PYPI_PUBLISH.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/RELEASE_NOTES.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/STANDARDS_COMPARISON.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/THREAT_MODEL.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/extraction/json_path.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/extraction/metadata.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/extraction/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/distilbert_loader.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/fields.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/ner.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/ort_loader.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/proptests.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/regex.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/walker.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/xlm_r_loader.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/pyproject.toml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/python/ciris_lens_core/__init__.py +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/audit/api.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/audit/delegate.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/audit/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/audit/pyo3.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/canonical/ceg_egress.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/canonical/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capacity/attestation.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capacity/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capacity/score.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/batch.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/client.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/consent.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/correlation.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/event.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/partial.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/py_engine.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/seal.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/cohort/declared.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/cohort/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/cohort/resourcing.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/egress.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/node.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/retention.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/upstream.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/axis_metrics.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/coherence_ratchet.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/correlated_action.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/distributive_access.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/manifold.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/extract/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/extract/projection.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/ffi/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/ffi/pyo3.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/lib.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/observability/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/pipeline/lifecycle.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/pipeline/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/retention/eviction.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/retention/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/retention/summary.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/handler.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/node.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/relay.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/ret_relay.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scores/aggregate.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scores/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scores/oracle.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/assembly.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/axis_calibration.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/calibration.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/capacity.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/n_eff.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/result.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/signing/event.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/signing/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/wire/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/wire/signer.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/tests/parity/README.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/tests/parity/canonical_fixtures.json +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/tests/parity/generate_canonical_fixtures.py +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/tests/sovereign_rlib.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/data/live_mesh_2026-06-22.json +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/docs/SCOPE_PRIVACY.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/mesh_propagation/main.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/accord.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/common.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/family.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/main.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/verify.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/README.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/bundle-jre.ps1 +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/ciris-server-entry.py +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/ciris-server-installer.iss +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/ciris-server.spec +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/pyproject.toml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/python/ciris_server/__init__.py +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/python/ciris_server/__main__.py +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/python/ciris_server/cli.py +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/python/ciris_server/desktop_launcher.py +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/rust-toolchain.toml +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/scripts/bench_report.py +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_custody.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_halt.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_pki/yubico_attestation_root_1.der +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_pki/yubico_attestation_root_1.pem +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_reactivate.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/adapter.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/ABSORPTION.md +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/api_keys.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/attestation.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/bootstrap.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/consent.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/device_auth.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/device_grant.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/erasure.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/gate.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/loopback.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/oauth.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/occurrence.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/ownership.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/portable_occurrence.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/roles.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/self_login.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/session.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/store.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/verify.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/benchmarks/bench_results.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/benchmarks/mesh.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/benchmarks/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/benchmarks/scoreboard.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/claim_remote.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/config.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/config_api.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/config_reconcile.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/delegation_transparency.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/family.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/federation_admin.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/federation_nodecode.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/federation_peers.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/graph_config.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/health.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/http_log.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/identity.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/ids.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/import.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/ingest_http.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/lib.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/main.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/memory_api.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/mesh_relay.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/nodecode.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/peer.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/proxy.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/py_adapter.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/quorum.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/radio.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/age.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/mod.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/moderation.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/named.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/watchlist.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/scorer/n_eff.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/scorer.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/system_data.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/telemetry_logs.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/src/yubico_attestation_ca.pem +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/accord.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/alm_chain.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/audit_chain.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/capacity_scorer.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/chaos_mesh.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/claim_remote.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/config_reconcile.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/device_grant.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/federation_admin.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/federation_session_kex.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/graph_config.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/ingest_http.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/mesh_seed_e2e.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/nat_traversal.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/nodecode.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/noise_floor.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/occurrence.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/ownership.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/peer_replication.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/portable_occurrence.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage1.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage2.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage3.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage4.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage5.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage6.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage7.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage8.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/replication.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/root_bootstrap.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/safety.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/stream_sth_consistency.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/wire_vocabulary_gate.rs +0 -0
- {ciris_server-0.5.77 → ciris_server-0.5.78}/tools/audit_cohort_scope_callers.py +0 -0
|
@@ -821,8 +821,8 @@ dependencies = [
|
|
|
821
821
|
|
|
822
822
|
[[package]]
|
|
823
823
|
name = "ciris-edge"
|
|
824
|
-
version = "8.
|
|
825
|
-
source = "git+https://github.com/CIRISAI/CIRISEdge?tag=v8.
|
|
824
|
+
version = "8.6.1"
|
|
825
|
+
source = "git+https://github.com/CIRISAI/CIRISEdge?tag=v8.6.1#acf26ce7cfe01aee5400c7e01dbd9d5b2e797d9b"
|
|
826
826
|
dependencies = [
|
|
827
827
|
"async-trait",
|
|
828
828
|
"axum",
|
|
@@ -943,8 +943,8 @@ dependencies = [
|
|
|
943
943
|
|
|
944
944
|
[[package]]
|
|
945
945
|
name = "ciris-persist"
|
|
946
|
-
version = "12.0
|
|
947
|
-
source = "git+https://github.com/CIRISAI/CIRISPersist?tag=v12.0
|
|
946
|
+
version = "12.2.0"
|
|
947
|
+
source = "git+https://github.com/CIRISAI/CIRISPersist?tag=v12.2.0#766212c92b52f27f7bf35779bf99f692d6b6a8d0"
|
|
948
948
|
dependencies = [
|
|
949
949
|
"async-trait",
|
|
950
950
|
"base64 0.22.1",
|
|
@@ -983,7 +983,7 @@ dependencies = [
|
|
|
983
983
|
|
|
984
984
|
[[package]]
|
|
985
985
|
name = "ciris-server"
|
|
986
|
-
version = "0.5.
|
|
986
|
+
version = "0.5.78"
|
|
987
987
|
dependencies = [
|
|
988
988
|
"anyhow",
|
|
989
989
|
"async-trait",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "ciris-server"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.78" # 0.5.78 = edge v8.6.1 / persist v12.2.0 adoption — the COMPLETE admit-node → mesh-seed loop. (1) #144 KEY-PLANE replication (KERI publish-own): the ReplicationRuntime converges an EnvelopeKind::Key coordinator per consent peer + a key_selector publishing the node's OWN key_id. (2) #150 PRODUCER: admit-node now calls persist v12.2.0 Engine::adopt_scrub_upgrade (CIRISPersist#351) to upgrade the node's own self-signed row to the accord-holder-scrubbed record — so the Key plane publishes an ANCHORED, rootable record → peers root it. Producer (server upgrades the row) + publish-own (edge advertises it) = the seed closes in place, no wipe. (3) #147 §Q B5: persist FountainHeldMeta.{content_bytes,cohort_scope} adopted (server has no fountain-content admit path; import.rs already sets cohort_scope). Verify unchanged v8.5.0. 0.5.77 = persist v12.0.2 anchor seed + accord-card UX.
|
|
4
4
|
edition = "2021"
|
|
5
5
|
# MSRV floor is set by the substrate: ciris-verify v5.2.0 requires 1.86
|
|
6
6
|
# (persist v6.0.1 is 1.83). Build with the higher of the two.
|
|
@@ -123,8 +123,8 @@ ciris-lens-core = { path = "crates/ciris-lens-core" } # ABSORBED in-tree (wo
|
|
|
123
123
|
# `cirislens_wa_cert` + `cirislens_service_token_revocation` expose the auth
|
|
124
124
|
# substrate the fabric absorbs (CIRISServer#9, src/auth): the agent's `wa_cert`
|
|
125
125
|
# table (users/WA/OAuth/api-keys) + the `revoked_service_tokens` table.
|
|
126
|
-
ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v12.0
|
|
127
|
-
ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v8.
|
|
126
|
+
ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v12.2.0", features = ["sqlite", "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"] }
|
|
127
|
+
ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v8.6.1", features = ["transport-reticulum", "transport-http", "transport-packet-radio"] }
|
|
128
128
|
# Founder-quorum verification + key-id fingerprint at the composition root
|
|
129
129
|
# (threshold:: module path — NOT re-exported at the crate root).
|
|
130
130
|
# LOCKSTEP: persist v9.4.0 transitively pins verify-core v6.6.x — the whole
|
|
@@ -206,7 +206,7 @@ tracing-appender = "0.2"
|
|
|
206
206
|
# - keyring `tpm` (tss-esapi / TPM 2.0) — the real hardware backend; needs
|
|
207
207
|
# libtss2 (Linux build dep). Other targets keep the software keystore.
|
|
208
208
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
209
|
-
ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v12.0
|
|
209
|
+
ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v12.2.0", features = ["postgres", "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"] }
|
|
210
210
|
# keyring `tpm` (TPM-at-rest, Linux-only via tss-esapi). `pkcs11` is no longer
|
|
211
211
|
# per-target — it rides the global `pkcs11` feature now that cryptoki builds on all
|
|
212
212
|
# targets (CIRISVerify v6.12.0).
|
|
@@ -259,7 +259,7 @@ ciris-crypto = { git = "https://github.com/CIRISAI/CIRISVerify", tag = "v8.5.0"
|
|
|
259
259
|
# and never encodes/decodes). This lets tests/chaos_mesh.rs exercise the SUBSTRATE
|
|
260
260
|
# codec (`fountain_encode`/`fountain_decode`) directly — a real MEASURED proof,
|
|
261
261
|
# not a reference stand-in.
|
|
262
|
-
ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v8.
|
|
262
|
+
ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v8.6.1", features = ["codec-fountain"] }
|
|
263
263
|
|
|
264
264
|
# PQC realtime-A/V streaming E2E benchmark (CIRISEdge#62 realtime_av profile).
|
|
265
265
|
[[bench]]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ciris-server
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.78
|
|
4
4
|
License-File: LICENSE
|
|
5
5
|
Summary: The fabric node — the federation's headless cohabitation runtime (registry + lens [+ node] over one shared substrate), as the abi3 wheel CIRISAgent consumes. agent = fabric node + brain.
|
|
6
6
|
Author-email: Eric Moore <eric@ciris.ai>
|
|
@@ -26,8 +26,8 @@ crate-type = ["cdylib", "rlib"]
|
|
|
26
26
|
#
|
|
27
27
|
# OQ-01 closure 2026-05-03: rlib primary, PyO3 cdylib via `python`
|
|
28
28
|
# feature for the deployed-lens cutover.
|
|
29
|
-
ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v12.0
|
|
30
|
-
ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v8.
|
|
29
|
+
ciris-persist = { git = "https://github.com/CIRISAI/CIRISPersist", tag = "v12.2.0", version = "12", features = ["extract", "sqlite"] }
|
|
30
|
+
ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v8.6.1", version = "8", features = ["transport-http", "transport-reticulum"] }
|
|
31
31
|
|
|
32
32
|
# Keyring — relay mode (CIRISLensCore#10) loads its Edge transport-
|
|
33
33
|
# signing identity via `ciris_keyring::load_local_seed`. Edge's
|
|
@@ -1048,7 +1048,7 @@ fn default_admit_identity_type() -> String {
|
|
|
1048
1048
|
/// (the predictable, persist-ingestable path the operator hands to CIRISPersist
|
|
1049
1049
|
/// v12.0.2 to bake) and returned. **1-of-N bootstrap:** a single holder suffices —
|
|
1050
1050
|
/// this is a trust EXTENSION, not the 2/3 kill-switch. Loopback + `pkcs11`-gated.
|
|
1051
|
-
async fn admit_node(State(
|
|
1051
|
+
async fn admit_node(State(st): State<ProvisionState>, body: axum::body::Bytes) -> Response {
|
|
1052
1052
|
let req: AdmitNodeRequest = match serde_json::from_slice(&body) {
|
|
1053
1053
|
Ok(r) => r,
|
|
1054
1054
|
Err(e) => return err(StatusCode::BAD_REQUEST, &format!("bad request: {e}")),
|
|
@@ -1082,11 +1082,11 @@ async fn admit_node(State(_st): State<ProvisionState>, body: axum::body::Bytes)
|
|
|
1082
1082
|
"target key_id contains path separators — refusing to write it",
|
|
1083
1083
|
);
|
|
1084
1084
|
}
|
|
1085
|
-
admit_node_impl(req).await
|
|
1085
|
+
admit_node_impl(st.engine, req).await
|
|
1086
1086
|
}
|
|
1087
1087
|
|
|
1088
1088
|
#[cfg(not(feature = "pkcs11"))]
|
|
1089
|
-
async fn admit_node_impl(_req: AdmitNodeRequest) -> Response {
|
|
1089
|
+
async fn admit_node_impl(_engine: Arc<Engine>, _req: AdmitNodeRequest) -> Response {
|
|
1090
1090
|
err(
|
|
1091
1091
|
StatusCode::NOT_IMPLEMENTED,
|
|
1092
1092
|
"admit-node needs the `pkcs11` feature (the holder's YubiKey + USB-wrapped ML-DSA signer)",
|
|
@@ -1094,7 +1094,7 @@ async fn admit_node_impl(_req: AdmitNodeRequest) -> Response {
|
|
|
1094
1094
|
}
|
|
1095
1095
|
|
|
1096
1096
|
#[cfg(feature = "pkcs11")]
|
|
1097
|
-
async fn admit_node_impl(req: AdmitNodeRequest) -> Response {
|
|
1097
|
+
async fn admit_node_impl(engine: Arc<Engine>, req: AdmitNodeRequest) -> Response {
|
|
1098
1098
|
use std::path::PathBuf;
|
|
1099
1099
|
use std::sync::Arc;
|
|
1100
1100
|
|
|
@@ -1253,10 +1253,48 @@ async fn admit_node_impl(req: AdmitNodeRequest) -> Response {
|
|
|
1253
1253
|
);
|
|
1254
1254
|
}
|
|
1255
1255
|
|
|
1256
|
+
// #150 — PRODUCER: adopt the scrubbed record onto this node's OWN directory row
|
|
1257
|
+
// (persist v12.2.0 `Engine::adopt_scrub_upgrade`, CIRISPersist#351). When the
|
|
1258
|
+
// target IS this node, its boot-time self-signed own-key row is upgraded to the
|
|
1259
|
+
// accord-holder-scrubbed record, so the Key plane (edge publish-own) advertises
|
|
1260
|
+
// an ANCHORED, rootable record and consent peers root it. The primitive is
|
|
1261
|
+
// self-gating (verifies the scrub sig + only upgrades a self-signed → scrubbed
|
|
1262
|
+
// row for the SAME key_id/pubkey), so we call it unconditionally: a target whose
|
|
1263
|
+
// row isn't a valid local upgrade returns Err and we report it without failing
|
|
1264
|
+
// the outbox write (the JSON is still the transport for a remote target / bake).
|
|
1265
|
+
let applied: serde_json::Value = match serde_json::to_value(&scrubbed)
|
|
1266
|
+
.and_then(serde_json::from_value::<ciris_persist::federation::SignedKeyRecord>)
|
|
1267
|
+
{
|
|
1268
|
+
Ok(persist_rec) => match engine.adopt_scrub_upgrade(persist_rec).await {
|
|
1269
|
+
Ok(outcome) => {
|
|
1270
|
+
tracing::info!(
|
|
1271
|
+
target_key_id = %req.target.key_id.trim(),
|
|
1272
|
+
?outcome,
|
|
1273
|
+
"admit-node: adopted the scrubbed record onto the local directory row"
|
|
1274
|
+
);
|
|
1275
|
+
serde_json::json!({ "adopted": true, "outcome": format!("{outcome:?}") })
|
|
1276
|
+
}
|
|
1277
|
+
Err(e) => {
|
|
1278
|
+
tracing::warn!(
|
|
1279
|
+
target_key_id = %req.target.key_id.trim(),
|
|
1280
|
+
error = %e,
|
|
1281
|
+
"admit-node: scrubbed record NOT adopted locally (not this node's own \
|
|
1282
|
+
self-signed row?) — seed JSON saved for transport/bake"
|
|
1283
|
+
);
|
|
1284
|
+
serde_json::json!({ "adopted": false, "reason": e.to_string() })
|
|
1285
|
+
}
|
|
1286
|
+
},
|
|
1287
|
+
Err(e) => {
|
|
1288
|
+
tracing::warn!(error = %e, "admit-node: scrubbed record convert for local adoption");
|
|
1289
|
+
serde_json::json!({ "adopted": false, "reason": format!("record convert: {e}") })
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
|
|
1256
1293
|
(
|
|
1257
1294
|
StatusCode::OK,
|
|
1258
1295
|
Json(serde_json::json!({
|
|
1259
1296
|
"saved_to": out_path.display().to_string(),
|
|
1297
|
+
"applied": applied,
|
|
1260
1298
|
"seed": seed,
|
|
1261
1299
|
})),
|
|
1262
1300
|
)
|
|
@@ -1352,18 +1352,42 @@ async fn setup_peer_replication(
|
|
|
1352
1352
|
// health:liveness in. v5.1.0 `start` installs the scheduler control channel
|
|
1353
1353
|
// unconditionally, so the runtime accepts `set_peers` mutation with no
|
|
1354
1354
|
// extra opt-in (CIRISEdge#173 resolved).
|
|
1355
|
+
// Two coordinators per consent peer: Attestation (capacity:* / health:liveness)
|
|
1356
|
+
// AND Key (#144, CIRISEdge#257 — the KERI publish-own key plane). The reconciler
|
|
1357
|
+
// (replication_reconcile.rs) converges the same pair set at runtime.
|
|
1355
1358
|
let peers: Vec<ReplicationPeer> = desired
|
|
1356
1359
|
.iter()
|
|
1357
|
-
.
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
+
.flat_map(|p| {
|
|
1361
|
+
[
|
|
1362
|
+
ReplicationPeer {
|
|
1363
|
+
peer_key_id: p.clone(),
|
|
1364
|
+
kind: EnvelopeKind::Attestation,
|
|
1365
|
+
},
|
|
1366
|
+
ReplicationPeer {
|
|
1367
|
+
peer_key_id: p.clone(),
|
|
1368
|
+
kind: EnvelopeKind::Key,
|
|
1369
|
+
},
|
|
1370
|
+
]
|
|
1360
1371
|
})
|
|
1361
1372
|
.collect();
|
|
1373
|
+
|
|
1374
|
+
// Key-plane publish selector (CIRISEdge#257 / edge v8.6.0): the Key plane's
|
|
1375
|
+
// `list_keys` advertises the key_ids THIS selector yields — the node's OWN
|
|
1376
|
+
// record — instead of the cohort's-own-keys projection. `list_keys` re-reads
|
|
1377
|
+
// the record live each tick, so once admit-node scrub-signs this node's own
|
|
1378
|
+
// record (scrub_key_id = an accord holder), the NEXT anti-entropy round
|
|
1379
|
+
// publishes the scrubbed, ANCHORED record to consent peers → they root it.
|
|
1380
|
+
// (KERI publish-own: the controller publishes its own establishment record.)
|
|
1381
|
+
let own_key_id = cfg.key_id.clone();
|
|
1382
|
+
let key_selector: ciris_edge::replication::CohortProvider =
|
|
1383
|
+
Arc::new(move || vec![own_key_id.clone()]);
|
|
1384
|
+
|
|
1362
1385
|
let runtime = ReplicationRuntime::start(
|
|
1363
1386
|
directory,
|
|
1364
1387
|
transport as Arc<dyn ciris_edge::transport::Transport>,
|
|
1365
1388
|
peers,
|
|
1366
1389
|
ReplicationRuntimeConfig::default(),
|
|
1390
|
+
Some(key_selector),
|
|
1367
1391
|
)
|
|
1368
1392
|
.await;
|
|
1369
1393
|
|
|
@@ -185,6 +185,8 @@ mod tests {
|
|
|
185
185
|
min_viable_symbols: 6,
|
|
186
186
|
symbol_size: 256,
|
|
187
187
|
held_symbols: 5,
|
|
188
|
+
content_bytes: 1280,
|
|
189
|
+
cohort_scope: Some("federation".to_string()),
|
|
188
190
|
recoverable: false,
|
|
189
191
|
admitted_at: "2026-06-21T00:00:00Z".to_string(),
|
|
190
192
|
};
|
|
@@ -207,6 +209,8 @@ mod tests {
|
|
|
207
209
|
min_viable_symbols: 1,
|
|
208
210
|
symbol_size: 1,
|
|
209
211
|
held_symbols: 0,
|
|
212
|
+
content_bytes: 0,
|
|
213
|
+
cohort_scope: None,
|
|
210
214
|
recoverable: false,
|
|
211
215
|
admitted_at: "2026-06-21T00:00:00Z".to_string(),
|
|
212
216
|
};
|
|
@@ -68,13 +68,25 @@ pub async fn reconcile_once(
|
|
|
68
68
|
// EnvelopeKind::Attestation carries BOTH directions (capacity:* out,
|
|
69
69
|
// health:liveness in).
|
|
70
70
|
let directory = engine.federation_directory();
|
|
71
|
-
let mut desired: Vec<ReplicationPeer> = Vec::with_capacity(consented.len());
|
|
71
|
+
let mut desired: Vec<ReplicationPeer> = Vec::with_capacity(consented.len() * 2);
|
|
72
72
|
for peer in consented {
|
|
73
73
|
match directory.lookup_public_key(&peer).await {
|
|
74
|
-
Ok(Some(_)) =>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
Ok(Some(_)) => {
|
|
75
|
+
// BOTH planes per admitted peer:
|
|
76
|
+
// - Attestation: capacity:* out, health:liveness in (as before).
|
|
77
|
+
// - Key (#144, CIRISEdge#257): the KEY-PLANE anti-entropy. Paired
|
|
78
|
+
// with the runtime's `key_selector` (publishes the node's OWN
|
|
79
|
+
// record — KERI publish-own), this converges a node's scrub-signed
|
|
80
|
+
// accord-anchored record to its consent peers so they can ROOT it.
|
|
81
|
+
desired.push(ReplicationPeer {
|
|
82
|
+
peer_key_id: peer.clone(),
|
|
83
|
+
kind: EnvelopeKind::Attestation,
|
|
84
|
+
});
|
|
85
|
+
desired.push(ReplicationPeer {
|
|
86
|
+
peer_key_id: peer,
|
|
87
|
+
kind: EnvelopeKind::Key,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
78
90
|
Ok(None) => tracing::warn!(
|
|
79
91
|
peer_key_id = %peer,
|
|
80
92
|
"consent:replication observed for an UNADMITTED peer key — skipping reconcile for \
|
|
@@ -91,7 +103,9 @@ pub async fn reconcile_once(
|
|
|
91
103
|
// Diff-converge the live Initiator set to the desired consent peers. Adds
|
|
92
104
|
// become active Initiators (scheduler-driven pull) at runtime; removals stop
|
|
93
105
|
// their rounds + drop inbound routing — all without a restart.
|
|
94
|
-
|
|
106
|
+
// `desired` holds TWO coordinators per peer (Attestation + Key); the reported
|
|
107
|
+
// count is distinct consent peers.
|
|
108
|
+
let count = desired.len() / 2;
|
|
95
109
|
if let Err(e) = runtime.set_peers(desired).await {
|
|
96
110
|
// The runtime's scheduler has stopped (shutdown) — surface so the caller
|
|
97
111
|
// logs + skips; the controller never panics.
|
|
@@ -159,3 +159,109 @@ async fn admit_node_scrubbed_record_roots_at_accord_anchor() {
|
|
|
159
159
|
"must NOT root when A1 is not a pinned anchor, got {verdict_wrong:?}"
|
|
160
160
|
);
|
|
161
161
|
}
|
|
162
|
+
|
|
163
|
+
/// The PRODUCER path (CIRISServer#150 / CIRISPersist#351): a node that already
|
|
164
|
+
/// holds its boot-time **self-signed** own-key row upgrades that row IN PLACE to
|
|
165
|
+
/// the accord-holder-scrubbed record via `Engine::adopt_scrub_upgrade` (the old
|
|
166
|
+
/// `register_federation_key` is `ON CONFLICT DO NOTHING` and would have left the
|
|
167
|
+
/// self-signed row). After the upgrade the row ROOTS at the anchor, and a second
|
|
168
|
+
/// apply is idempotent — exactly what admit-node relies on to publish an anchored
|
|
169
|
+
/// record over the Key plane.
|
|
170
|
+
#[tokio::test]
|
|
171
|
+
async fn adopt_scrub_upgrade_promotes_self_signed_own_row_and_roots() {
|
|
172
|
+
use ciris_persist::federation::register::AdoptScrubOutcome;
|
|
173
|
+
|
|
174
|
+
let engine = node().await;
|
|
175
|
+
let now = chrono::Utc::now().to_rfc3339();
|
|
176
|
+
|
|
177
|
+
let a1 = HybridSigningIdentity::generate("humanity-accord-a1-test").expect("gen A1");
|
|
178
|
+
let anchor = produce_self_key_record(&a1, "steward,accord_holder", &now)
|
|
179
|
+
.await
|
|
180
|
+
.expect("A1 anchor");
|
|
181
|
+
let a1_ed_b64 = anchor.record.pubkey_ed25519_base64.clone();
|
|
182
|
+
engine
|
|
183
|
+
.register_federation_key(to_persist(&anchor))
|
|
184
|
+
.await
|
|
185
|
+
.expect("register A1 anchor");
|
|
186
|
+
|
|
187
|
+
// The node's boot-time state: its OWN row, SELF-signed.
|
|
188
|
+
let target = HybridSigningIdentity::generate("canonical-server-1-test").expect("gen target");
|
|
189
|
+
let target_self = produce_self_key_record(&target, "node", &now)
|
|
190
|
+
.await
|
|
191
|
+
.expect("target self record");
|
|
192
|
+
let target_ed_b64 = target_self.record.pubkey_ed25519_base64.clone();
|
|
193
|
+
let target_mldsa_b64 = target_self
|
|
194
|
+
.record
|
|
195
|
+
.pubkey_ml_dsa_65_base64
|
|
196
|
+
.clone()
|
|
197
|
+
.expect("target ml_dsa");
|
|
198
|
+
engine
|
|
199
|
+
.register_federation_key(to_persist(&target_self))
|
|
200
|
+
.await
|
|
201
|
+
.expect("register target SELF-signed own row");
|
|
202
|
+
|
|
203
|
+
// Precondition: a self-signed row does NOT root.
|
|
204
|
+
let backend = engine.sqlite_backend().expect("sqlite backend");
|
|
205
|
+
let anchor_set = [ed32(&a1_ed_b64)];
|
|
206
|
+
assert!(
|
|
207
|
+
!matches!(
|
|
208
|
+
root_binding_anchored(
|
|
209
|
+
backend.as_ref(),
|
|
210
|
+
"canonical-server-1-test",
|
|
211
|
+
&target_ed_b64,
|
|
212
|
+
&anchor_set
|
|
213
|
+
)
|
|
214
|
+
.await,
|
|
215
|
+
RootingVerdict::Confirmed { .. }
|
|
216
|
+
),
|
|
217
|
+
"precondition: the self-signed own row must NOT root yet"
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// A1 scrub-signs the target, and the node ADOPTS the upgrade onto its own row.
|
|
221
|
+
let scrubbed = produce_scrubbed_key_record(
|
|
222
|
+
&a1,
|
|
223
|
+
ScrubTarget {
|
|
224
|
+
key_id: "canonical-server-1-test".to_string(),
|
|
225
|
+
pubkey_ed25519_base64: target_ed_b64.clone(),
|
|
226
|
+
pubkey_ml_dsa_65_base64: target_mldsa_b64,
|
|
227
|
+
identity_type: "node".to_string(),
|
|
228
|
+
},
|
|
229
|
+
&now,
|
|
230
|
+
)
|
|
231
|
+
.await
|
|
232
|
+
.expect("A1 scrub-signs target");
|
|
233
|
+
|
|
234
|
+
let outcome = engine
|
|
235
|
+
.adopt_scrub_upgrade(to_persist(&scrubbed))
|
|
236
|
+
.await
|
|
237
|
+
.expect("adopt_scrub_upgrade must succeed on a self-signed own row");
|
|
238
|
+
assert!(
|
|
239
|
+
matches!(outcome, AdoptScrubOutcome::Upgraded),
|
|
240
|
+
"first adopt upgrades the self-signed row, got {outcome:?}"
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// Now the SAME key_id ROOTS — the Key plane would publish an anchored record.
|
|
244
|
+
assert!(
|
|
245
|
+
matches!(
|
|
246
|
+
root_binding_anchored(
|
|
247
|
+
backend.as_ref(),
|
|
248
|
+
"canonical-server-1-test",
|
|
249
|
+
&target_ed_b64,
|
|
250
|
+
&anchor_set
|
|
251
|
+
)
|
|
252
|
+
.await,
|
|
253
|
+
RootingVerdict::Confirmed { .. }
|
|
254
|
+
),
|
|
255
|
+
"after adopt the own row must ROOT at the accord anchor"
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
// Idempotent: re-applying the same outbox record is a no-op (second boot).
|
|
259
|
+
let again = engine
|
|
260
|
+
.adopt_scrub_upgrade(to_persist(&scrubbed))
|
|
261
|
+
.await
|
|
262
|
+
.expect("re-adopt must not error");
|
|
263
|
+
assert!(
|
|
264
|
+
matches!(again, AdoptScrubOutcome::AlreadyAdopted),
|
|
265
|
+
"second adopt is idempotent, got {again:?}"
|
|
266
|
+
);
|
|
267
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
//! TRUE end-to-end QA gate for the genesis-mesh SEED via the KEY PLANE
|
|
2
|
+
//! (deploy-with-confidence). Complements `mesh_seed_e2e.rs` (which covers the
|
|
3
|
+
//! relay/trace Attestation path); this proves the admit-node → rooting loop for
|
|
4
|
+
//! **key records** across TWO independent engines, driving the REAL edge
|
|
5
|
+
//! replication bridge (no mocks of our own logic):
|
|
6
|
+
//!
|
|
7
|
+
//! 1. **Seed** — the baked HUMANITY_ACCORD anchor (A1) is present on BOTH nodes
|
|
8
|
+
//! (persist v12.0.2 first-boot seed, simulated here by registering A1).
|
|
9
|
+
//! 2. **Producer** (CIRISServer#150 / CIRISPersist#351) — node A holds its
|
|
10
|
+
//! boot-time SELF-signed own row, then `Engine::adopt_scrub_upgrade` upgrades
|
|
11
|
+
//! it IN PLACE to the A1-scrubbed (anchored) record.
|
|
12
|
+
//! 3. **Publish-own** (CIRISEdge#257 / edge v8.6.x) — A's replication bridge with
|
|
13
|
+
//! the Key-plane `key_selector` = A's own key_id advertises A's OWN anchored
|
|
14
|
+
//! record over `EnvelopeKind::Key` (`list_envelope_refs` + `fetch_envelope_bytes`).
|
|
15
|
+
//! 4. **Receive** — node B applies those exact wire bytes via the bridge
|
|
16
|
+
//! (`apply_envelope_bytes`) — the receive side of anti-entropy.
|
|
17
|
+
//! 5. **Root** — B now ROOTS A at the accord anchor (`root_binding_anchored`),
|
|
18
|
+
//! which it could NOT do before receiving A's record.
|
|
19
|
+
//!
|
|
20
|
+
//! The Reticulum transport hop + the scheduler cadence are edge's own tested
|
|
21
|
+
//! concerns; this gate proves OUR composition (producer + publish-set selection +
|
|
22
|
+
//! apply + root) end-to-end and deterministically, with software keys.
|
|
23
|
+
|
|
24
|
+
use std::sync::Arc;
|
|
25
|
+
|
|
26
|
+
use base64::Engine as _;
|
|
27
|
+
|
|
28
|
+
use ciris_edge::replication::{
|
|
29
|
+
BridgeConfig, CohortProvider, EnvelopeKind, FederationDirectoryReplicationBridge,
|
|
30
|
+
ReplicationDirectory,
|
|
31
|
+
};
|
|
32
|
+
use ciris_persist::federation::rooting::{root_binding_anchored, RootingVerdict};
|
|
33
|
+
use ciris_persist::federation::FederationDirectory;
|
|
34
|
+
use ciris_persist::federation::SignedKeyRecord as PersistSignedKeyRecord;
|
|
35
|
+
use ciris_persist::prelude::{Engine, LocalSigner};
|
|
36
|
+
use ciris_persist::store::sqlite::SqliteBackend;
|
|
37
|
+
|
|
38
|
+
use ciris_verify_core::federation_self_record::{
|
|
39
|
+
produce_scrubbed_key_record, produce_self_key_record, ScrubTarget, SignedKeyRecord,
|
|
40
|
+
};
|
|
41
|
+
use ciris_verify_core::self_at_login::HybridSigningIdentity;
|
|
42
|
+
|
|
43
|
+
use ciris_keyring::MlDsa65SoftwareSigner;
|
|
44
|
+
use ed25519_dalek::SigningKey;
|
|
45
|
+
|
|
46
|
+
/// A fresh in-memory sqlite Engine with a distinct signer seed.
|
|
47
|
+
async fn engine(seed: u8, alias: &str) -> Arc<Engine> {
|
|
48
|
+
let signing_key = SigningKey::from_bytes(&[seed; 32]);
|
|
49
|
+
let pqc = Arc::new(
|
|
50
|
+
MlDsa65SoftwareSigner::from_seed_bytes(&[seed ^ 0xFF; 32], format!("{alias}-pqc"))
|
|
51
|
+
.expect("ML-DSA-65 seed"),
|
|
52
|
+
);
|
|
53
|
+
let signer = Arc::new(LocalSigner::from_parts(
|
|
54
|
+
signing_key,
|
|
55
|
+
alias.to_string(),
|
|
56
|
+
Some(pqc),
|
|
57
|
+
Some(format!("{alias}-pqc")),
|
|
58
|
+
));
|
|
59
|
+
Arc::new(
|
|
60
|
+
Engine::with_signer(signer, "sqlite::memory:")
|
|
61
|
+
.await
|
|
62
|
+
.expect("Engine::with_signer (sqlite::memory:)"),
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fn to_persist(v: &SignedKeyRecord) -> PersistSignedKeyRecord {
|
|
67
|
+
serde_json::from_value(serde_json::to_value(v).expect("serialize verify record"))
|
|
68
|
+
.expect("deserialize into persist record")
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn ed32(b64: &str) -> [u8; 32] {
|
|
72
|
+
base64::engine::general_purpose::STANDARD
|
|
73
|
+
.decode(b64)
|
|
74
|
+
.expect("b64 ed25519")
|
|
75
|
+
.try_into()
|
|
76
|
+
.expect("32-byte ed25519")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async fn roots(backend: &SqliteBackend, key_id: &str, ed_b64: &str, anchor: &[[u8; 32]]) -> bool {
|
|
80
|
+
matches!(
|
|
81
|
+
root_binding_anchored(backend, key_id, ed_b64, anchor).await,
|
|
82
|
+
RootingVerdict::Confirmed { .. }
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#[tokio::test]
|
|
87
|
+
async fn admit_node_seed_replicates_and_peer_roots_end_to_end() {
|
|
88
|
+
let node_a_key = "canonical-node-a-test";
|
|
89
|
+
let node_b_key = "canonical-node-b-test";
|
|
90
|
+
|
|
91
|
+
let engine_a = engine(0xA0, node_a_key).await;
|
|
92
|
+
let engine_b = engine(0xB0, node_b_key).await;
|
|
93
|
+
let now = chrono::Utc::now().to_rfc3339();
|
|
94
|
+
|
|
95
|
+
// (1) SEED — A1, the baked HUMANITY_ACCORD anchor, present on BOTH nodes.
|
|
96
|
+
let a1 = HybridSigningIdentity::generate("humanity-accord-a1-test").expect("gen A1");
|
|
97
|
+
let a1_anchor = produce_self_key_record(&a1, "steward,accord_holder", &now)
|
|
98
|
+
.await
|
|
99
|
+
.expect("A1 anchor");
|
|
100
|
+
let a1_ed = ed32(&a1_anchor.record.pubkey_ed25519_base64);
|
|
101
|
+
for e in [&engine_a, &engine_b] {
|
|
102
|
+
e.register_federation_key(to_persist(&a1_anchor))
|
|
103
|
+
.await
|
|
104
|
+
.expect("seed A1 anchor");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Node A's identity + its BOOT-time SELF-signed own row (what register_self_key
|
|
108
|
+
// writes) in A's directory.
|
|
109
|
+
let node_a = HybridSigningIdentity::generate(node_a_key).expect("gen node A");
|
|
110
|
+
let a_self = produce_self_key_record(&node_a, "node", &now)
|
|
111
|
+
.await
|
|
112
|
+
.expect("A self record");
|
|
113
|
+
let a_ed_b64 = a_self.record.pubkey_ed25519_base64.clone();
|
|
114
|
+
let a_mldsa_b64 = a_self
|
|
115
|
+
.record
|
|
116
|
+
.pubkey_ml_dsa_65_base64
|
|
117
|
+
.clone()
|
|
118
|
+
.expect("A ml_dsa");
|
|
119
|
+
engine_a
|
|
120
|
+
.register_federation_key(to_persist(&a_self))
|
|
121
|
+
.await
|
|
122
|
+
.expect("A self-signed own row");
|
|
123
|
+
|
|
124
|
+
let anchor_set = [a1_ed];
|
|
125
|
+
|
|
126
|
+
// Precondition: B cannot root A (it has never seen A's record).
|
|
127
|
+
assert!(
|
|
128
|
+
!roots(
|
|
129
|
+
engine_b.sqlite_backend().unwrap().as_ref(),
|
|
130
|
+
node_a_key,
|
|
131
|
+
&a_ed_b64,
|
|
132
|
+
&anchor_set
|
|
133
|
+
)
|
|
134
|
+
.await,
|
|
135
|
+
"precondition: B must NOT root A before receiving A's record"
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// (2) PRODUCER — A1 scrub-signs A; A adopts the upgrade onto its OWN row.
|
|
139
|
+
let a_scrubbed = produce_scrubbed_key_record(
|
|
140
|
+
&a1,
|
|
141
|
+
ScrubTarget {
|
|
142
|
+
key_id: node_a_key.to_string(),
|
|
143
|
+
pubkey_ed25519_base64: a_ed_b64.clone(),
|
|
144
|
+
pubkey_ml_dsa_65_base64: a_mldsa_b64,
|
|
145
|
+
identity_type: "node".to_string(),
|
|
146
|
+
},
|
|
147
|
+
&now,
|
|
148
|
+
)
|
|
149
|
+
.await
|
|
150
|
+
.expect("A1 scrub-signs A");
|
|
151
|
+
engine_a
|
|
152
|
+
.adopt_scrub_upgrade(to_persist(&a_scrubbed))
|
|
153
|
+
.await
|
|
154
|
+
.expect("A adopts the scrub upgrade onto its own row");
|
|
155
|
+
|
|
156
|
+
// A's own row roots LOCALLY now — the producer worked.
|
|
157
|
+
assert!(
|
|
158
|
+
roots(
|
|
159
|
+
engine_a.sqlite_backend().unwrap().as_ref(),
|
|
160
|
+
node_a_key,
|
|
161
|
+
&a_ed_b64,
|
|
162
|
+
&anchor_set
|
|
163
|
+
)
|
|
164
|
+
.await,
|
|
165
|
+
"A's own row must root locally after adopt"
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// (3) PUBLISH-OWN — A's bridge with the Key-plane selector = A's own key_id.
|
|
169
|
+
let a_dir: Arc<dyn FederationDirectory> = engine_a.federation_directory();
|
|
170
|
+
let cohort_a: CohortProvider = Arc::new(move || vec![node_b_key.to_string()]);
|
|
171
|
+
let key_sel: CohortProvider = Arc::new(move || vec![node_a_key.to_string()]);
|
|
172
|
+
let a_bridge =
|
|
173
|
+
FederationDirectoryReplicationBridge::with_config(a_dir, cohort_a, BridgeConfig::default())
|
|
174
|
+
.with_key_selector(Some(key_sel));
|
|
175
|
+
|
|
176
|
+
let refs = a_bridge.list_envelope_refs(EnvelopeKind::Key).await;
|
|
177
|
+
assert_eq!(
|
|
178
|
+
refs.len(),
|
|
179
|
+
1,
|
|
180
|
+
"A publishes exactly its OWN record on the Key plane (selector-scoped), got {refs:?}"
|
|
181
|
+
);
|
|
182
|
+
let bytes = a_bridge
|
|
183
|
+
.fetch_envelope_bytes(EnvelopeKind::Key, &refs[0].envelope_hash)
|
|
184
|
+
.await
|
|
185
|
+
.expect("A serves its own record bytes");
|
|
186
|
+
|
|
187
|
+
// (4) RECEIVE — B applies the exact wire bytes via its bridge (anti-entropy RX).
|
|
188
|
+
let b_dir: Arc<dyn FederationDirectory> = engine_b.federation_directory();
|
|
189
|
+
let b_bridge = FederationDirectoryReplicationBridge::with_config(
|
|
190
|
+
b_dir,
|
|
191
|
+
Arc::new(move || vec![node_a_key.to_string()]),
|
|
192
|
+
BridgeConfig::default(),
|
|
193
|
+
);
|
|
194
|
+
let admitted = b_bridge
|
|
195
|
+
.apply_envelope_bytes(EnvelopeKind::Key, &bytes)
|
|
196
|
+
.await;
|
|
197
|
+
assert!(
|
|
198
|
+
admitted,
|
|
199
|
+
"B must admit A's anchored record (validates against seeded A1)"
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// (5) ROOT — B now roots A at the accord anchor. THE SEED CLOSED.
|
|
203
|
+
assert!(
|
|
204
|
+
roots(
|
|
205
|
+
engine_b.sqlite_backend().unwrap().as_ref(),
|
|
206
|
+
node_a_key,
|
|
207
|
+
&a_ed_b64,
|
|
208
|
+
&anchor_set
|
|
209
|
+
)
|
|
210
|
+
.await,
|
|
211
|
+
"after receiving A's anchored record, B MUST root A — the mesh seed is complete"
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
// Negative: B still won't root A under a WRONG anchor set (the gate bites).
|
|
215
|
+
assert!(
|
|
216
|
+
!roots(
|
|
217
|
+
engine_b.sqlite_backend().unwrap().as_ref(),
|
|
218
|
+
node_a_key,
|
|
219
|
+
&a_ed_b64,
|
|
220
|
+
&[[0x11u8; 32]]
|
|
221
|
+
)
|
|
222
|
+
.await,
|
|
223
|
+
"B must NOT root A when A1 is not the pinned anchor"
|
|
224
|
+
);
|
|
225
|
+
}
|
|
@@ -32,8 +32,8 @@ use std::path::PathBuf;
|
|
|
32
32
|
// verify v8.3.0→v8.5.0 (CIRISVerify#162 produce_scrubbed_key_record, the accord
|
|
33
33
|
// admit-node op), edge v8.3.0→v8.4.1 (anchor gate for free + verify/persist lockstep).
|
|
34
34
|
pub const TARGET_VERIFY: &str = "v8.5.0";
|
|
35
|
-
pub const TARGET_PERSIST: &str = "v12.0
|
|
36
|
-
pub const TARGET_EDGE: &str = "v8.
|
|
35
|
+
pub const TARGET_PERSIST: &str = "v12.2.0";
|
|
36
|
+
pub const TARGET_EDGE: &str = "v8.6.1";
|
|
37
37
|
/// Stage 6/7: the persist MAJOR family that bakes the canonical genesis seed.
|
|
38
38
|
/// (Name is historical — the seed-bake family moved v10 → **v12** with the v12.0
|
|
39
39
|
/// genesis-mesh rooting anchor: persist v12.0.1 enforces it, v12.0.2 bakes the
|