Give Atlas publisher a durable identity lifecycle

This commit is contained in:
Meta Vens 2026-08-16 20:22:34 +02:00
commit 7b385b0445
4 changed files with 57 additions and 3 deletions

View file

@ -7,7 +7,10 @@ use cultcache_rs::{
CacheBackingStore, CultCache, CultCacheEnvelope, DatabaseEntry,
SingleFileMessagePackBackingStore,
};
use cultnet_rs::{ServiceIdentityProfile, ServiceIdentityTrustAnchor, enroll_service_identity_at};
use cultnet_rs::{
ServiceIdentityProfile, ServiceIdentitySigner, ServiceIdentityTrustAnchor,
enroll_service_identity_at, export_service_identity_trust_anchor, open_service_identity_at,
};
use super::*;
@ -39,6 +42,7 @@ pub struct AtlasPublisherRunConfig {
pub publisher_store: PathBuf,
pub publisher_cultmesh_store: PathBuf,
pub identity_store: PathBuf,
pub trust_anchor_store: PathBuf,
pub odin_endpoint: SocketAddr,
pub now_unix_ms: u64,
}
@ -248,6 +252,7 @@ pub fn run_atlas_publisher_once(
&config.publisher_store,
&config.publisher_cultmesh_store,
&config.identity_store,
&config.trust_anchor_store,
])?;
if let Some(brake_id) = atlas_brake_id(
&config.local_verse_store,
@ -263,8 +268,8 @@ pub fn run_atlas_publisher_once(
{
bail!("Atlas publisher repository/runtime differs from its current Body basis")
}
let signer =
enroll_service_identity_at::<AtlasRepositorySigningIdentity>(&config.identity_store)?;
let signer = open_or_enroll_atlas_repository_identity(&config.identity_store)?;
export_service_identity_trust_anchor(&signer, &config.trust_anchor_store)?;
let store = AtlasCultCacheStore::new(&config.publisher_store, config.repository.clone())?;
ensure_local_publisher_trust(&store, &signer, config.now_unix_ms)?;
let heartbeat_sequence = next_heartbeat_sequence(&store)?;
@ -319,6 +324,16 @@ pub fn run_atlas_publisher_once(
})
}
fn open_or_enroll_atlas_repository_identity(
identity_store: &Path,
) -> Result<ServiceIdentitySigner<AtlasRepositorySigningIdentity>> {
if identity_store.exists() {
open_service_identity_at::<AtlasRepositorySigningIdentity>(identity_store)
} else {
enroll_service_identity_at::<AtlasRepositorySigningIdentity>(identity_store)
}
}
pub fn run_atlas_projector_once(
config: &AtlasProjectorRunConfig,
) -> Result<AtlasProjectorRunOutcome> {
@ -1406,4 +1421,24 @@ mod tests {
assert!(stale_source.load_local_atlas_mind_snapshot().is_err());
Ok(())
}
#[test]
fn publisher_identity_reopens_and_exports_one_stable_public_anchor() -> Result<()> {
let temp = tempfile::tempdir()?;
let identity_store = temp.path().join("publisher-identity.cc");
let trust_anchor_store = temp.path().join("publisher-trust-anchor.cc");
let enrolled = open_or_enroll_atlas_repository_identity(&identity_store)?;
let first_anchor = export_service_identity_trust_anchor(&enrolled, &trust_anchor_store)?;
let reopened = open_or_enroll_atlas_repository_identity(&identity_store)?;
let replayed_anchor = export_service_identity_trust_anchor(&reopened, &trust_anchor_store)?;
assert_eq!(enrolled.entry(), reopened.entry());
assert_eq!(first_anchor, replayed_anchor);
assert_eq!(
read_atlas_repository_trust_anchor(&trust_anchor_store)?,
first_anchor
);
Ok(())
}
}

View file

@ -29,6 +29,7 @@ fn main() -> Result<()> {
publisher_store: path(&args, "--publisher-store")?,
publisher_cultmesh_store: path(&args, "--cultmesh-store")?,
identity_store: path(&args, "--identity-store")?,
trust_anchor_store: path(&args, "--trust-anchor-store")?,
odin_endpoint: required(&args, "--odin-endpoint")?.parse()?,
now_unix_ms: now_unix_ms()?,
};

View file

@ -4753,3 +4753,12 @@ presentation-only; domain mutation routes back to the owning repository's
Modeling interface. Brake scopes `atlas.publish`, `atlas.project`, and
`atlas.impact_ingress` freeze writes and scheduling while preserving the last
projection as visibly stale read-only state.
The repository publisher also owns the lifecycle of its signing identity.
Its private identity store is enrolled only when absent and reopened exactly on
later cycles; retries cannot rotate or replace it. Every unbraked cycle exports
the same public trust anchor idempotently to a physically separate store for
operator-gated projector pinning. The projector never reads the private store,
and an existing divergent public anchor refuses instead of being repaired.
This cut is required for both the second publisher heartbeat and real trust
enrollment; one-shot identity creation is not a viable daemon lifecycle.

View file

@ -47,6 +47,15 @@ publishers/projector establish signed sight; then engage all three Atlas brakes
and prove later organ cycles are held while the last Eve projection remains
visibly stale/read-only and no lane wakes.
Gate 1 preflight exposed and cut one publisher lifecycle defect before live
evidence was admitted. The publisher now enrolls its private signing identity
only when absent, reopens that exact identity on later heartbeats, and exports
one idempotent public trust anchor to a separate operator-readable store. This
keeps identity rotation impossible by retry and gives the projector a real
public anchor to pin without reading private state. The focused identity
reopen/export test passes; the operational gate remains in progress and is not
yet accepted.
Public positioning was synchronized on 2026-08-16 without changing that next
rite. `docs/positioning.md` is the current claim owner: Epiphany is the
organizational layer above frontier AI workers; the primary failure is global