Retire unadmitted Model Atlas daemons

This commit is contained in:
Meta Vens 2026-08-23 19:01:52 +02:00
commit 56267201b7
6 changed files with 24 additions and 352 deletions

View file

@ -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"

View file

@ -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<String, String>, BTreeSet<String>)> {
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<String, String>, name: &str) -> Result<&'a str> {
args.get(name)
.map(String::as_str)
.ok_or_else(|| anyhow::anyhow!("missing required {name}"))
}
fn path(args: &BTreeMap<String, String>, name: &str) -> Result<PathBuf> {
Ok(PathBuf::from(required(args, name)?))
}
fn now_unix_ms() -> Result<u64> {
Ok(SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_millis()
.try_into()?)
}

View file

@ -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<String, String>, BTreeSet<String>)> {
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<String, String>, name: &str) -> Result<&'a str> {
args.get(name)
.map(String::as_str)
.ok_or_else(|| anyhow::anyhow!("missing required {name}"))
}
fn path(args: &BTreeMap<String, String>, name: &str) -> Result<PathBuf> {
Ok(PathBuf::from(required(args, name)?))
}
fn now_unix_ms() -> Result<u64> {
Ok(SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_millis()
.try_into()?)
}

View file

@ -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<String, String>, BTreeSet<String>, 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<String, String>, name: &str) -> Result<&'a str> {
args.get(name)
.map(String::as_str)
.ok_or_else(|| anyhow::anyhow!("missing required {name}"))
}
fn path(args: &BTreeMap<String, String>, name: &str) -> Result<PathBuf> {
Ok(PathBuf::from(required(args, name)?))
}
fn now_unix_ms() -> Result<u64> {
Ok(SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_millis()
.try_into()?)
}

View file

@ -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")),

View file

@ -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.