diff --git a/Cargo.toml b/Cargo.toml index 996a4c84..be56af00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,18 +77,6 @@ tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev [patch."ssh://git@github.com/openai-oss-forks/tungstenite-rs.git"] tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" } -[[bin]] -name = "epiphany-atlas-publisher" -path = "epiphany-core/src/bin/epiphany-atlas-publisher.rs" - -[[bin]] -name = "epiphany-model-entanglement-projector" -path = "epiphany-core/src/bin/epiphany-model-entanglement-projector.rs" - -[[bin]] -name = "epiphany-atlas-impact-ingress" -path = "epiphany-core/src/bin/epiphany-atlas-impact-ingress.rs" - [[bin]] name = "epiphany-release" path = "epiphany-core/src/bin/epiphany-release.rs" diff --git a/epiphany-core/src/bin/epiphany-atlas-impact-ingress.rs b/epiphany-core/src/bin/epiphany-atlas-impact-ingress.rs deleted file mode 100644 index 07c0472b..00000000 --- a/epiphany-core/src/bin/epiphany-atlas-impact-ingress.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; -use std::path::PathBuf; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -use anyhow::{Result, bail}; -use epiphany_core::{ - AtlasImpactIngressRunConfig, AtlasImpactIngressRunOutcome, AtlasRepositoryIdentity, - run_atlas_impact_ingress_once, -}; - -fn main() -> Result<()> { - let (args, switches) = arguments()?; - let once = switches.contains("--once"); - let running = Arc::new(AtomicBool::new(true)); - let stop = running.clone(); - ctrlc::set_handler(move || stop.store(false, Ordering::SeqCst))?; - while running.load(Ordering::SeqCst) { - let config = AtlasImpactIngressRunConfig { - local_repository: AtlasRepositoryIdentity::new( - required(&args, "--swarm-id")?, - required(&args, "--workspace-id")?, - )?, - projector_repository: AtlasRepositoryIdentity::new( - required(&args, "--projector-swarm-id")?, - required(&args, "--projector-workspace-id")?, - )?, - runtime_id: required(&args, "--runtime-id")?.into(), - runtime_mind_store: path(&args, "--mind-store")?, - local_verse_store: path(&args, "--verse-store")?, - projector_store: path(&args, "--projector-store")?, - impact_store: path(&args, "--impact-store")?, - resident_self_store: path(&args, "--resident-self-store")?, - cooldown_after_completion_ms: args - .get("--cooldown-ms") - .map(|value| value.parse()) - .transpose()? - .unwrap_or(30_000), - now_unix_ms: now_unix_ms()?, - }; - match run_atlas_impact_ingress_once(&config)? { - AtlasImpactIngressRunOutcome::HeldByBrake { - brake_id, - last_projection, - } => println!( - "atlas impact ingress held by brake {brake_id}; last projection remains read-only: {}", - last_projection.is_some() - ), - AtlasImpactIngressRunOutcome::Evaluated { - admitted_impacts, - scheduled_pressures, - held_impacts, - } => println!( - "atlas impact ingress admitted {admitted_impacts}, scheduled {scheduled_pressures}, held {held_impacts}" - ), - } - if once { - break; - } - std::thread::sleep(Duration::from_secs(5)); - } - Ok(()) -} - -fn arguments() -> Result<(BTreeMap, BTreeSet)> { - let mut values = BTreeMap::new(); - let mut switches = BTreeSet::new(); - let mut args = std::env::args().skip(1); - while let Some(name) = args.next() { - if name == "--once" { - switches.insert(name); - continue; - } - if !name.starts_with("--") { - bail!("unexpected Atlas impact argument {name}") - } - values.insert( - name.clone(), - args.next() - .ok_or_else(|| anyhow::anyhow!("{name} requires a value"))?, - ); - } - Ok((values, switches)) -} - -fn required<'a>(args: &'a BTreeMap, name: &str) -> Result<&'a str> { - args.get(name) - .map(String::as_str) - .ok_or_else(|| anyhow::anyhow!("missing required {name}")) -} -fn path(args: &BTreeMap, name: &str) -> Result { - Ok(PathBuf::from(required(args, name)?)) -} -fn now_unix_ms() -> Result { - Ok(SystemTime::now() - .duration_since(UNIX_EPOCH)? - .as_millis() - .try_into()?) -} diff --git a/epiphany-core/src/bin/epiphany-atlas-publisher.rs b/epiphany-core/src/bin/epiphany-atlas-publisher.rs deleted file mode 100644 index 8fff7a26..00000000 --- a/epiphany-core/src/bin/epiphany-atlas-publisher.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; -use std::path::PathBuf; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -use anyhow::{Result, bail}; -use epiphany_core::{ - ATLAS_PUBLISHER_HEARTBEAT_INTERVAL_MS, AtlasPublisherRunConfig, AtlasPublisherRunOutcome, - AtlasRepositoryIdentity, run_atlas_publisher_once, -}; - -fn main() -> Result<()> { - let (args, switches) = arguments()?; - let once = switches.contains("--once"); - let running = Arc::new(AtomicBool::new(true)); - let stop = running.clone(); - ctrlc::set_handler(move || stop.store(false, Ordering::SeqCst))?; - while running.load(Ordering::SeqCst) { - let config = AtlasPublisherRunConfig { - repository: AtlasRepositoryIdentity::new( - required(&args, "--swarm-id")?, - required(&args, "--workspace-id")?, - )?, - runtime_id: required(&args, "--runtime-id")?.into(), - runtime_incarnation_id: required(&args, "--runtime-incarnation-id")?.into(), - runtime_mind_store: path(&args, "--mind-store")?, - local_verse_store: path(&args, "--verse-store")?, - 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()?, - }; - match run_atlas_publisher_once(&config)? { - AtlasPublisherRunOutcome::HeldByBrake { brake_id } => { - println!("atlas publisher held by brake {brake_id}") - } - AtlasPublisherRunOutcome::Published { - new_publications, - transported_publications, - } => println!( - "atlas publisher committed {new_publications} new records and transported {transported_publications} immutable records" - ), - } - if once { - break; - } - std::thread::sleep(Duration::from_millis(ATLAS_PUBLISHER_HEARTBEAT_INTERVAL_MS)); - } - Ok(()) -} - -fn arguments() -> Result<(BTreeMap, BTreeSet)> { - let mut values = BTreeMap::new(); - let mut switches = BTreeSet::new(); - let mut args = std::env::args().skip(1); - while let Some(name) = args.next() { - if name == "--once" { - switches.insert(name); - continue; - } - if !name.starts_with("--") { - bail!("unexpected Atlas publisher argument {name}") - } - values.insert( - name.clone(), - args.next() - .ok_or_else(|| anyhow::anyhow!("{name} requires a value"))?, - ); - } - Ok((values, switches)) -} - -fn required<'a>(args: &'a BTreeMap, name: &str) -> Result<&'a str> { - args.get(name) - .map(String::as_str) - .ok_or_else(|| anyhow::anyhow!("missing required {name}")) -} - -fn path(args: &BTreeMap, name: &str) -> Result { - Ok(PathBuf::from(required(args, name)?)) -} - -fn now_unix_ms() -> Result { - Ok(SystemTime::now() - .duration_since(UNIX_EPOCH)? - .as_millis() - .try_into()?) -} diff --git a/epiphany-core/src/bin/epiphany-model-entanglement-projector.rs b/epiphany-core/src/bin/epiphany-model-entanglement-projector.rs deleted file mode 100644 index de1d617c..00000000 --- a/epiphany-core/src/bin/epiphany-model-entanglement-projector.rs +++ /dev/null @@ -1,121 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; -use std::path::PathBuf; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -use anyhow::{Result, bail}; -use epiphany_core::{ - AtlasProjectorRunConfig, AtlasProjectorRunOutcome, AtlasRepositoryIdentity, - AtlasStoreWriteOutcome, pin_atlas_publisher_trust_anchor, run_atlas_projector_once, -}; - -fn main() -> Result<()> { - let (args, switches, command) = arguments()?; - let projector = AtlasRepositoryIdentity::new( - required(&args, "--swarm-id")?, - required(&args, "--workspace-id")?, - )?; - if command == "pin-trust" { - let publisher = AtlasRepositoryIdentity::new( - required(&args, "--publisher-swarm-id")?, - required(&args, "--publisher-workspace-id")?, - )?; - let expected_revision = args - .get("--expected-revision") - .map(|value| value.parse()) - .transpose()?; - let outcome = pin_atlas_publisher_trust_anchor( - &path(&args, "--projector-store")?, - projector, - publisher, - &path(&args, "--trust-anchor")?, - expected_revision, - now_unix_ms()?, - )?; - if outcome == AtlasStoreWriteOutcome::Conflict { - bail!("Atlas trust pin CAS conflicted") - } - println!("Atlas publisher trust pin admitted: {outcome:?}"); - return Ok(()); - } - if command != "run" { - bail!("Atlas projector command must be `run` or `pin-trust`") - } - let once = switches.contains("--once"); - let running = Arc::new(AtomicBool::new(true)); - let stop = running.clone(); - ctrlc::set_handler(move || stop.store(false, Ordering::SeqCst))?; - while running.load(Ordering::SeqCst) { - let config = AtlasProjectorRunConfig { - projector_repository: projector.clone(), - runtime_id: required(&args, "--runtime-id")?.into(), - local_verse_store: path(&args, "--verse-store")?, - projector_store: path(&args, "--projector-store")?, - projector_cultmesh_store: path(&args, "--cultmesh-store")?, - odin_endpoint: required(&args, "--odin-endpoint")?.parse()?, - now_unix_ms: now_unix_ms()?, - }; - match run_atlas_projector_once(&config)? { - AtlasProjectorRunOutcome::HeldByBrake { - brake_id, - last_projection, - } => println!( - "atlas projector held by brake {brake_id}; last projection remains read-only: {}", - last_projection.is_some() - ), - AtlasProjectorRunOutcome::Projected { - projection, - accepted_publications, - rejected_publications, - } => println!( - "atlas projector {} accepted {accepted_publications}, rejected {rejected_publications}, derived {} edges and {} cycles", - projection.projection_sha256, - projection.entanglements.len(), - projection.cycles.len() - ), - } - if once { - break; - } - std::thread::sleep(Duration::from_secs(5)); - } - Ok(()) -} - -fn arguments() -> Result<(BTreeMap, BTreeSet, String)> { - let mut raw = std::env::args().skip(1); - let command = raw.next().unwrap_or_else(|| "run".into()); - let mut values = BTreeMap::new(); - let mut switches = BTreeSet::new(); - while let Some(name) = raw.next() { - if name == "--once" { - switches.insert(name); - continue; - } - if !name.starts_with("--") { - bail!("unexpected Atlas projector argument {name}") - } - values.insert( - name.clone(), - raw.next() - .ok_or_else(|| anyhow::anyhow!("{name} requires a value"))?, - ); - } - Ok((values, switches, command)) -} - -fn required<'a>(args: &'a BTreeMap, name: &str) -> Result<&'a str> { - args.get(name) - .map(String::as_str) - .ok_or_else(|| anyhow::anyhow!("missing required {name}")) -} -fn path(args: &BTreeMap, name: &str) -> Result { - Ok(PathBuf::from(required(args, name)?)) -} -fn now_unix_ms() -> Result { - Ok(SystemTime::now() - .duration_since(UNIX_EPOCH)? - .as_millis() - .try_into()?) -} diff --git a/epiphany-release-construction/src/lib.rs b/epiphany-release-construction/src/lib.rs index 357a2c4b..f92afbd9 100644 --- a/epiphany-release-construction/src/lib.rs +++ b/epiphany-release-construction/src/lib.rs @@ -84,15 +84,6 @@ pub fn required_packaged_release_binaries(target_triple: &str) -> Vec<(&'static vec![ ("release-publisher", file_name("epiphany-release")), ("state-steward", file_name("epiphany-state")), - ("atlas-publisher", file_name("epiphany-atlas-publisher")), - ( - "model-entanglement-projector", - file_name("epiphany-model-entanglement-projector"), - ), - ( - "atlas-impact-ingress", - file_name("epiphany-atlas-impact-ingress"), - ), ("repository-body", file_name("epiphany-repository-body")), ("host-identity", file_name("epiphany-host-identity")), ("swarm", file_name("epiphany-swarm")), diff --git a/notes/model-atlas-vertical-slice.md b/notes/model-atlas-vertical-slice.md index c0599011..43b56553 100644 --- a/notes/model-atlas-vertical-slice.md +++ b/notes/model-atlas-vertical-slice.md @@ -111,21 +111,25 @@ not merely that the projector drew one. - `atlas.publish`, `atlas.project`, and `atlas.impact_ingress` brakes stop writes and scheduling while retaining the last projection read-only. -## Live organs +## Library organs; deployment not admitted -- `epiphany-atlas-publisher` reads a local Mind store, publishes immutable - events to its publisher CultCache/CultMesh store, and transports them to - Odin. Its signing identity lives in a separate private `.cc` store. -- `epiphany-model-entanglement-projector` pins repository trust anchors, queries - Odin, verifies publications, derives a deterministic projection, and - publishes the canonical Eve provider and surface documents. -- `epiphany-atlas-impact-ingress` compares a projection with locally owned - claims, admits exact impact documents, and asks local Resident Self to - schedule permitted pressure. +- The publisher library reads a local Mind store, publishes immutable events to + its publisher CultCache/CultMesh store, and transports them to Odin. Its + signing identity lives in a separate private `.cc` store. +- The projector library pins repository trust anchors, queries Odin, verifies + publications, derives a deterministic projection, and publishes canonical + Eve provider and surface documents. +- The impact-ingress library compares a projection with locally owned claims, + admits exact impact documents, and asks local Resident Self to schedule + permitted pressure. -Each organ has its own store. The local Mind, private identity, publisher -events, CultMesh publication, Odin catalog, projection, and impact scheduler -state are never collapsed into a writable mega-graph. +These are typed library owners, not three production daemons. The former +command wrappers had no unit, live consumer, deployment phase, or independent +failure-isolation contract and are not shipped. If the operational gate is +adopted, its process topology must be designed from the admitted lifecycle +rather than resurrected from those wrappers. The local Mind, private identity, +publisher events, CultMesh publication, Odin catalog, projection, and impact +scheduler state must not collapse into a writable mega-graph. ## Starfire pilot topology @@ -148,7 +152,7 @@ pinned by exact repository coordinates; key rotation is operator-gated. ## Rollout gates 1. Keep impact ingress absent. Let ordinary Modeling admit the three local seed - facts into isolated Mind stores, then run the publishers and projector until + facts into isolated Mind stores, then exercise the publisher and projector owners until signed publications, exact watermarks, and the retained Eve tree exist. Engage `atlas.publish`, `atlas.project`, and `atlas.impact_ingress`, run one more publisher/projector cycle plus the first ingress cycle, and prove every @@ -158,9 +162,10 @@ pinned by exact repository coordinates; key rotation is operator-gated. 2. Release Atlas scopes for Modeling and Soul while leaving existing Hands authorization unchanged. A temporary Eve contract change must wake Odin Modeling and then Epiphany Modeling without an operator prompt. -3. Place the organs under the existing daemon supervisor. Sustain the pilot - while observing publisher/projector lag, per-publisher watermarks, - rejection count, cycles, and pending impacts through CultMesh/Eve. +3. Admit only the minimum Idunn-managed process topology justified by the + proven lifecycle and failure-isolation requirements. Sustain the pilot while + observing publisher/projector lag, per-publisher watermarks, rejection + count, cycles, and pending impacts through CultMesh/Eve. 4. Only after sustained local proof, register topology and recovery runbooks in `gamecult-ops`. Yggdrasil and the public Verse remain outside V1.