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.
Files changed (262) hide show
  1. {ciris_server-0.5.77 → ciris_server-0.5.78}/Cargo.lock +5 -5
  2. {ciris_server-0.5.77 → ciris_server-0.5.78}/Cargo.toml +5 -5
  3. {ciris_server-0.5.77 → ciris_server-0.5.78}/PKG-INFO +1 -1
  4. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/Cargo.toml +2 -2
  5. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_provision.rs +42 -4
  6. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/compose.rs +27 -3
  7. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/holonomic.rs +4 -0
  8. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/replication_reconcile.rs +20 -6
  9. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/accord_admit_node.rs +106 -0
  10. ciris_server-0.5.78/tests/mesh_seed_keyplane_e2e.rs +225 -0
  11. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/support.rs +2 -2
  12. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/replication_reconcile.rs +23 -0
  13. {ciris_server-0.5.77 → ciris_server-0.5.78}/.cargo/config.toml +0 -0
  14. {ciris_server-0.5.77 → ciris_server-0.5.78}/.claude/workflows/localize-ui.js +0 -0
  15. {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/bench.yml +0 -0
  16. {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/build-wheels.yml +0 -0
  17. {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/ci.yml +0 -0
  18. {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/client-artifacts.yml +0 -0
  19. {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/conformance.yml +0 -0
  20. {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/localization.yml +0 -0
  21. {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/publish-pypi.yml +0 -0
  22. {ciris_server-0.5.77 → ciris_server-0.5.78}/.github/workflows/release.yml +0 -0
  23. {ciris_server-0.5.77 → ciris_server-0.5.78}/.gitignore +0 -0
  24. {ciris_server-0.5.77 → ciris_server-0.5.78}/CHANGELOG.md +0 -0
  25. {ciris_server-0.5.77 → ciris_server-0.5.78}/LICENSE +0 -0
  26. {ciris_server-0.5.77 → ciris_server-0.5.78}/MISSION.md +0 -0
  27. {ciris_server-0.5.77 → ciris_server-0.5.78}/README.md +0 -0
  28. {ciris_server-0.5.77 → ciris_server-0.5.78}/WIRE_VOCABULARY_KINDS.md +0 -0
  29. {ciris_server-0.5.77 → ciris_server-0.5.78}/bench-site/bench_results.json +0 -0
  30. {ciris_server-0.5.77 → ciris_server-0.5.78}/bench-site/index.html +0 -0
  31. {ciris_server-0.5.77 → ciris_server-0.5.78}/bench_results.json +0 -0
  32. {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/alm_chain.rs +0 -0
  33. {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/erasure_survival.rs +0 -0
  34. {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/n_eff_scoring.rs +0 -0
  35. {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/pqc_av_streaming.rs +0 -0
  36. {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/replication_ingest.rs +0 -0
  37. {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/sig_overhead.rs +0 -0
  38. {ciris_server-0.5.77 → ciris_server-0.5.78}/benches/stream_fanout.rs +0 -0
  39. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/.github/workflows/bench.yml +0 -0
  40. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/.github/workflows/ci.yml +0 -0
  41. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/.gitignore +0 -0
  42. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/.pre-commit-config.yaml +0 -0
  43. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/FSD/CIRIS_LENS_CORE.md +0 -0
  44. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/FSD/LENS_CORE_V0_5.md +0 -0
  45. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/FSD/OPEN_QUESTIONS.md +0 -0
  46. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/LICENSE +0 -0
  47. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/MISSION.md +0 -0
  48. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/README.md +0 -0
  49. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/benches/aggregate.rs +0 -0
  50. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/benches/canonicalize.rs +0 -0
  51. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/benches/project.rs +0 -0
  52. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/deny.toml +0 -0
  53. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/BENCHMARKS.md +0 -0
  54. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/COHABITATION.md +0 -0
  55. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/PRE_COMMIT.md +0 -0
  56. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/PUBLIC_SCHEMA_CONTRACT.md +0 -0
  57. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/PYPI_PUBLISH.md +0 -0
  58. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/RELEASE_NOTES.md +0 -0
  59. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/STANDARDS_COMPARISON.md +0 -0
  60. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/docs/THREAT_MODEL.md +0 -0
  61. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/extraction/json_path.rs +0 -0
  62. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/extraction/metadata.rs +0 -0
  63. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/extraction/mod.rs +0 -0
  64. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/distilbert_loader.rs +0 -0
  65. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/fields.rs +0 -0
  66. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/mod.rs +0 -0
  67. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/ner.rs +0 -0
  68. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/ort_loader.rs +0 -0
  69. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/proptests.rs +0 -0
  70. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/regex.rs +0 -0
  71. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/patterns_from_cirislens_core/scrubber/walker.rs +0 -0
  72. {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
  73. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/pyproject.toml +0 -0
  74. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/python/ciris_lens_core/__init__.py +0 -0
  75. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/audit/api.rs +0 -0
  76. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/audit/delegate.rs +0 -0
  77. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/audit/mod.rs +0 -0
  78. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/audit/pyo3.rs +0 -0
  79. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/canonical/ceg_egress.rs +0 -0
  80. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/canonical/mod.rs +0 -0
  81. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capacity/attestation.rs +0 -0
  82. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capacity/mod.rs +0 -0
  83. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capacity/score.rs +0 -0
  84. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/batch.rs +0 -0
  85. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/client.rs +0 -0
  86. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/consent.rs +0 -0
  87. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/correlation.rs +0 -0
  88. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/event.rs +0 -0
  89. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/mod.rs +0 -0
  90. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/partial.rs +0 -0
  91. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/py_engine.rs +0 -0
  92. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/capture/seal.rs +0 -0
  93. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/cohort/declared.rs +0 -0
  94. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/cohort/mod.rs +0 -0
  95. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/cohort/resourcing.rs +0 -0
  96. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/egress.rs +0 -0
  97. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/mod.rs +0 -0
  98. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/node.rs +0 -0
  99. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/retention.rs +0 -0
  100. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/config/upstream.rs +0 -0
  101. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/axis_metrics.rs +0 -0
  102. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/coherence_ratchet.rs +0 -0
  103. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/correlated_action.rs +0 -0
  104. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/distributive_access.rs +0 -0
  105. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/manifold.rs +0 -0
  106. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/detector/mod.rs +0 -0
  107. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/extract/mod.rs +0 -0
  108. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/extract/projection.rs +0 -0
  109. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/ffi/mod.rs +0 -0
  110. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/ffi/pyo3.rs +0 -0
  111. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/lib.rs +0 -0
  112. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/observability/mod.rs +0 -0
  113. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/pipeline/lifecycle.rs +0 -0
  114. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/pipeline/mod.rs +0 -0
  115. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/retention/eviction.rs +0 -0
  116. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/retention/mod.rs +0 -0
  117. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/retention/summary.rs +0 -0
  118. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/handler.rs +0 -0
  119. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/mod.rs +0 -0
  120. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/node.rs +0 -0
  121. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/relay.rs +0 -0
  122. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/role/ret_relay.rs +0 -0
  123. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scores/aggregate.rs +0 -0
  124. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scores/mod.rs +0 -0
  125. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scores/oracle.rs +0 -0
  126. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/assembly.rs +0 -0
  127. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/axis_calibration.rs +0 -0
  128. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/calibration.rs +0 -0
  129. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/capacity.rs +0 -0
  130. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/mod.rs +0 -0
  131. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/n_eff.rs +0 -0
  132. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/scoring/result.rs +0 -0
  133. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/signing/event.rs +0 -0
  134. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/signing/mod.rs +0 -0
  135. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/wire/mod.rs +0 -0
  136. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/src/wire/signer.rs +0 -0
  137. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/tests/parity/README.md +0 -0
  138. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/tests/parity/canonical_fixtures.json +0 -0
  139. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/tests/parity/generate_canonical_fixtures.py +0 -0
  140. {ciris_server-0.5.77 → ciris_server-0.5.78}/crates/ciris-lens-core/tests/sovereign_rlib.rs +0 -0
  141. {ciris_server-0.5.77 → ciris_server-0.5.78}/data/live_mesh_2026-06-22.json +0 -0
  142. {ciris_server-0.5.77 → ciris_server-0.5.78}/docs/SCOPE_PRIVACY.md +0 -0
  143. {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/mesh_propagation/main.rs +0 -0
  144. {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/accord.rs +0 -0
  145. {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/common.rs +0 -0
  146. {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/family.rs +0 -0
  147. {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/main.rs +0 -0
  148. {ciris_server-0.5.77 → ciris_server-0.5.78}/examples/qa_runner/verify.rs +0 -0
  149. {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/README.md +0 -0
  150. {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/bundle-jre.ps1 +0 -0
  151. {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/ciris-server-entry.py +0 -0
  152. {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/ciris-server-installer.iss +0 -0
  153. {ciris_server-0.5.77 → ciris_server-0.5.78}/installers/windows/ciris-server.spec +0 -0
  154. {ciris_server-0.5.77 → ciris_server-0.5.78}/pyproject.toml +0 -0
  155. {ciris_server-0.5.77 → ciris_server-0.5.78}/python/ciris_server/__init__.py +0 -0
  156. {ciris_server-0.5.77 → ciris_server-0.5.78}/python/ciris_server/__main__.py +0 -0
  157. {ciris_server-0.5.77 → ciris_server-0.5.78}/python/ciris_server/cli.py +0 -0
  158. {ciris_server-0.5.77 → ciris_server-0.5.78}/python/ciris_server/desktop_launcher.py +0 -0
  159. {ciris_server-0.5.77 → ciris_server-0.5.78}/rust-toolchain.toml +0 -0
  160. {ciris_server-0.5.77 → ciris_server-0.5.78}/scripts/bench_report.py +0 -0
  161. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord.rs +0 -0
  162. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_custody.rs +0 -0
  163. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_halt.rs +0 -0
  164. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_pki/yubico_attestation_root_1.der +0 -0
  165. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_pki/yubico_attestation_root_1.pem +0 -0
  166. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/accord_reactivate.rs +0 -0
  167. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/adapter.rs +0 -0
  168. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/ABSORPTION.md +0 -0
  169. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/api_keys.rs +0 -0
  170. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/attestation.rs +0 -0
  171. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/bootstrap.rs +0 -0
  172. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/consent.rs +0 -0
  173. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/device_auth.rs +0 -0
  174. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/device_grant.rs +0 -0
  175. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/erasure.rs +0 -0
  176. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/gate.rs +0 -0
  177. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/loopback.rs +0 -0
  178. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/mod.rs +0 -0
  179. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/oauth.rs +0 -0
  180. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/occurrence.rs +0 -0
  181. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/ownership.rs +0 -0
  182. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/portable_occurrence.rs +0 -0
  183. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/roles.rs +0 -0
  184. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/self_login.rs +0 -0
  185. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/session.rs +0 -0
  186. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/store.rs +0 -0
  187. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/auth/verify.rs +0 -0
  188. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/benchmarks/bench_results.rs +0 -0
  189. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/benchmarks/mesh.rs +0 -0
  190. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/benchmarks/mod.rs +0 -0
  191. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/benchmarks/scoreboard.rs +0 -0
  192. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/claim_remote.rs +0 -0
  193. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/config.rs +0 -0
  194. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/config_api.rs +0 -0
  195. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/config_reconcile.rs +0 -0
  196. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/delegation_transparency.rs +0 -0
  197. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/family.rs +0 -0
  198. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/federation_admin.rs +0 -0
  199. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/federation_nodecode.rs +0 -0
  200. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/federation_peers.rs +0 -0
  201. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/graph_config.rs +0 -0
  202. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/health.rs +0 -0
  203. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/http_log.rs +0 -0
  204. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/identity.rs +0 -0
  205. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/ids.rs +0 -0
  206. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/import.rs +0 -0
  207. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/ingest_http.rs +0 -0
  208. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/lib.rs +0 -0
  209. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/main.rs +0 -0
  210. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/memory_api.rs +0 -0
  211. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/mesh_relay.rs +0 -0
  212. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/nodecode.rs +0 -0
  213. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/peer.rs +0 -0
  214. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/proxy.rs +0 -0
  215. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/py_adapter.rs +0 -0
  216. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/quorum.rs +0 -0
  217. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/radio.rs +0 -0
  218. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/age.rs +0 -0
  219. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/mod.rs +0 -0
  220. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/moderation.rs +0 -0
  221. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/named.rs +0 -0
  222. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/safety/watchlist.rs +0 -0
  223. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/scorer/n_eff.rs +0 -0
  224. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/scorer.rs +0 -0
  225. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/system_data.rs +0 -0
  226. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/telemetry_logs.rs +0 -0
  227. {ciris_server-0.5.77 → ciris_server-0.5.78}/src/yubico_attestation_ca.pem +0 -0
  228. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/accord.rs +0 -0
  229. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/alm_chain.rs +0 -0
  230. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/audit_chain.rs +0 -0
  231. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/capacity_scorer.rs +0 -0
  232. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/chaos_mesh.rs +0 -0
  233. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/claim_remote.rs +0 -0
  234. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/config_reconcile.rs +0 -0
  235. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/device_grant.rs +0 -0
  236. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/federation_admin.rs +0 -0
  237. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/federation_session_kex.rs +0 -0
  238. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/graph_config.rs +0 -0
  239. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/ingest_http.rs +0 -0
  240. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/mesh_seed_e2e.rs +0 -0
  241. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/nat_traversal.rs +0 -0
  242. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/nodecode.rs +0 -0
  243. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/noise_floor.rs +0 -0
  244. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/occurrence.rs +0 -0
  245. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/ownership.rs +0 -0
  246. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/peer_replication.rs +0 -0
  247. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/portable_occurrence.rs +0 -0
  248. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage1.rs +0 -0
  249. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage2.rs +0 -0
  250. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage3.rs +0 -0
  251. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage4.rs +0 -0
  252. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage5.rs +0 -0
  253. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage6.rs +0 -0
  254. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage7.rs +0 -0
  255. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates/stage8.rs +0 -0
  256. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/release_gates.rs +0 -0
  257. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/replication.rs +0 -0
  258. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/root_bootstrap.rs +0 -0
  259. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/safety.rs +0 -0
  260. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/stream_sth_consistency.rs +0 -0
  261. {ciris_server-0.5.77 → ciris_server-0.5.78}/tests/wire_vocabulary_gate.rs +0 -0
  262. {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.4.2"
825
- source = "git+https://github.com/CIRISAI/CIRISEdge?tag=v8.4.2#fa66d9319f9293b718d07ae22fde7342e93a0b7e"
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.2"
947
- source = "git+https://github.com/CIRISAI/CIRISPersist?tag=v12.0.2#883349f4e68b58de0a1905c37ad98ab55a80e918"
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.77"
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.77" # 0.5.77 = persist v12.0.2 (the accord-holder anchor SEED CIRISPersist#347, seeds A1/B1/C1 at first boot) + edge v8.4.2 adoption, + accord-card UX polish: (1) lists the holder roster, (2) SELECT the holder from the roster (dropdown) instead of typing, (3) SELECT the target from owned-nodes auto-fills both hybrid pubkeys from the local directory (added pubkey_ml_dsa_65 to LocalPeerState / GET /v1/federation/peers), (4) BROWSE for the USB PQC folder (DirectoryPicker). Verify unchanged v8.5.0. 0.5.76 = the admit-node card + v12.0 adoption.
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.2", 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.4.2", features = ["transport-reticulum", "transport-http", "transport-packet-radio"] }
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.2", 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"] }
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.4.2", features = ["codec-fountain"] }
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.77
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.2", version = "12", features = ["extract", "sqlite"] }
30
- ciris-edge = { git = "https://github.com/CIRISAI/CIRISEdge", tag = "v8.4.2", version = "8", features = ["transport-http", "transport-reticulum"] }
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(_st): State<ProvisionState>, body: axum::body::Bytes) -> Response {
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
- .map(|p| ReplicationPeer {
1358
- peer_key_id: p.clone(),
1359
- kind: EnvelopeKind::Attestation,
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(_)) => desired.push(ReplicationPeer {
75
- peer_key_id: peer,
76
- kind: EnvelopeKind::Attestation,
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
- let count = desired.len();
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.2";
36
- pub const TARGET_EDGE: &str = "v8.4.2";
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