Collapse native coordinator store boundary

This commit is contained in:
Meta Vens 2026-07-12 07:58:19 +01:00
commit c0b542f7ba
9 changed files with 83 additions and 93 deletions

View file

@ -751,9 +751,7 @@ fn collect_coordinator_status(runtime_store: &Path, thread_id: &str) -> Result<V
"--json",
"--thread-id",
thread_id,
"--thread-state-store",
&store,
"--runtime-store",
"--store",
&store,
],
)
@ -762,7 +760,7 @@ fn collect_coordinator_status(runtime_store: &Path, thread_id: &str) -> Result<V
fn apply_bootstrap_patch(runtime_store: &Path, thread_id: &str, patch: Value) -> Result<Value> {
let patch: epiphany_core::EpiphanyRoleStatePatchDocument =
serde_json::from_value(patch).context("failed to decode typed bootstrap state patch")?;
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store, runtime_store);
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store);
let applied = service.apply_state_update(
thread_id,
epiphany_core::state_update_from_role_patch(Some(0), patch),
@ -771,7 +769,7 @@ fn apply_bootstrap_patch(runtime_store: &Path, thread_id: &str, patch: Value) ->
Ok(json!({
"revision": applied.revision,
"changedFields": applied.changed_fields.iter().map(|field| format!("{field:?}")).collect::<Vec<_>>(),
"epiphanyState": applied.state,
"state": applied.state,
}))
}
fn resolve_model_runtime_bin(root: &Path, configured: &Path) -> Result<PathBuf> {
@ -971,7 +969,7 @@ fn launch_role(
expected_revision: Option<i64>,
max_runtime_seconds: u64,
) -> Result<Value> {
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store, runtime_store);
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store);
let state = service
.state()?
.ok_or_else(|| anyhow!("cannot launch role without native coordinator state"))?;
@ -1020,7 +1018,7 @@ fn launch_role(
"launcherJobId": launched.launcher_job_id,
"backendJobId": launched.backend_job_id,
"revision": launched.epiphany_state.revision,
"epiphanyState": launched.epiphany_state,
"state": launched.epiphany_state,
}))
}
@ -1030,7 +1028,7 @@ fn accept_role(
role_id: &str,
expected_revision: Option<u64>,
) -> Result<Value> {
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store, runtime_store);
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store);
let state = service
.state()?
.ok_or_else(|| anyhow!("cannot accept role without native coordinator state"))?;
@ -1048,7 +1046,7 @@ fn accept_role(
Ok(json!({
"roleId": role,
"revision": accepted.state.revision,
"epiphanyState": accepted.state,
"state": accepted.state,
"acceptedReceiptId": accepted.update.accepted_receipt_id,
"acceptedObservationId": accepted.update.accepted_observation_id,
"acceptedEvidenceId": accepted.update.accepted_evidence_id,
@ -1156,7 +1154,7 @@ fn supersede_role_result(
accepted_evidence_id: None,
summary: Some(summary),
};
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store, runtime_store);
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store);
let applied = service.apply_state_update(
thread_id,
epiphany_core::EpiphanyStateUpdate {
@ -1169,7 +1167,7 @@ fn supersede_role_result(
Ok(json!({
"revision": applied.revision,
"changedFields": applied.changed_fields.iter().map(|field| format!("{field:?}")).collect::<Vec<_>>(),
"epiphanyState": applied.state,
"state": applied.state,
"receipt": receipt,
}))
}
@ -1190,7 +1188,7 @@ fn launch_reorient(
expected_revision: Option<i64>,
max_runtime_seconds: u64,
) -> Result<Value> {
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store, runtime_store);
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store);
let state = service
.state()?
.ok_or_else(|| anyhow!("cannot launch reorientation without native coordinator state"))?;
@ -1231,7 +1229,7 @@ fn launch_reorient(
"launcherJobId": launched.launcher_job_id,
"backendJobId": launched.backend_job_id,
"revision": launched.epiphany_state.revision,
"epiphanyState": launched.epiphany_state,
"state": launched.epiphany_state,
"decision": decision,
}))
}
@ -1784,6 +1782,9 @@ mod tests {
"native coordinator regrew host dependency {forbidden:?}"
);
}
let compatibility_field = ["epiphany", "State"].concat();
assert!(!production.contains(&compatibility_field));
assert!(!production.contains("--thread-state-store"));
}
#[test]

View file

@ -51,8 +51,7 @@ use std::path::{Path, PathBuf};
use std::process::Command;
const DEFAULT_CARGO_TARGET_DIR: &str = r"C:\Users\Meta\.cargo-target-codex";
const DEFAULT_THREAD_STATE_STORE: &str = "state/thread-state.msgpack";
const DEFAULT_RUNTIME_STORE: &str = "state/runtime-spine.msgpack";
const DEFAULT_COORDINATOR_STORE: &str = "state/runtime-spine.msgpack";
const REORIENT_BINDING_ID: &str = "reorient-worker";
const IMAGINATION_BINDING_ID: &str = "imagination-synthesis-worker";
const RESEARCH_BINDING_ID: &str = "research-source-gather-worker";
@ -94,8 +93,7 @@ fn main() -> Result<()> {
struct Args {
thread_id: Option<String>,
cwd: PathBuf,
thread_state_store: PathBuf,
runtime_store: PathBuf,
store: PathBuf,
ephemeral: bool,
json: bool,
result: Option<PathBuf>,
@ -112,8 +110,7 @@ impl Args {
let mut parsed = Args {
thread_id: None,
cwd: root.clone(),
thread_state_store: PathBuf::from(DEFAULT_THREAD_STATE_STORE),
runtime_store: PathBuf::from(DEFAULT_RUNTIME_STORE),
store: PathBuf::from(DEFAULT_COORDINATOR_STORE),
ephemeral: true,
json: false,
result: None,
@ -130,12 +127,7 @@ impl Args {
match arg.as_str() {
"--thread-id" => parsed.thread_id = Some(take_string(&mut args, "--thread-id")?),
"--cwd" => parsed.cwd = take_path(&mut args, "--cwd")?,
"--thread-state-store" => {
parsed.thread_state_store = take_path(&mut args, "--thread-state-store")?
}
"--runtime-store" => {
parsed.runtime_store = take_path(&mut args, "--runtime-store")?
}
"--store" => parsed.store = take_path(&mut args, "--store")?,
"--ephemeral" => parsed.ephemeral = true,
"--no-ephemeral" => parsed.ephemeral = false,
"--json" => parsed.json = true,
@ -171,14 +163,8 @@ fn run_native_interrupt(args: &Args) -> Result<Value> {
.interrupt_binding
.as_ref()
.ok_or_else(|| anyhow!("--interrupt-binding requires a binding id"))?;
let store = absolute_path(&args.thread_state_store)?;
let runtime_store = absolute_path(&args.runtime_store)?;
if store != runtime_store {
return Err(anyhow!(
"native interruption requires one unified thread/runtime store"
));
}
let service = epiphany_core::EpiphanyCoordinatorService::new(&store, &runtime_store);
let store = absolute_path(&args.store)?;
let service = epiphany_core::EpiphanyCoordinatorService::new(&store);
let state = service
.state()?
.ok_or_else(|| anyhow!("cannot interrupt without native coordinator state"))?;
@ -198,14 +184,14 @@ fn run_native_interrupt(args: &Args) -> Result<Value> {
"revision": result.epiphany_state.revision,
"cancelRequested": result.cancel_requested,
"interruptedThreadIds": result.interrupted_thread_ids,
"epiphanyState": result.epiphany_state,
"state": result.epiphany_state,
}))
}
fn run_native_status(args: &Args) -> Result<Value> {
let cwd = absolute_path(&args.cwd)?;
let store_path = absolute_path(&args.thread_state_store)?;
let runtime_store_path = absolute_path(&args.runtime_store)?;
let store_path = absolute_path(&args.store)?;
let runtime_store_path = store_path.clone();
let state = if store_path.exists() {
read_accepted_coordinator_state(&store_path)
.with_context(|| format!("failed to load {}", store_path.display()))?
@ -1415,11 +1401,22 @@ mod native_interrupt_tests {
use super::*;
use epiphany_state_model::{EpiphanyJobBinding, EpiphanyJobKind};
#[test]
fn native_operator_contract_has_one_store_and_no_codex_state_field() {
let source = include_str!("epiphany-mvp-status.rs");
let production = source.split("#[cfg(test)]").next().unwrap_or(source);
let compatibility_field = ["epiphany", "State"].concat();
assert!(!production.contains(&compatibility_field));
assert!(!production.contains("--thread-state-store"));
assert!(!production.contains("--runtime-store"));
assert!(production.contains("--store"));
}
#[test]
fn default_status_interrupt_uses_native_coordinator_state() -> Result<()> {
let temp = tempfile::tempdir()?;
let store = temp.path().join("status-interrupt.cc");
let service = epiphany_core::EpiphanyCoordinatorService::new(&store, &store);
let service = epiphany_core::EpiphanyCoordinatorService::new(&store);
service.apply_state_update(
"thread-1",
epiphany_core::EpiphanyStateUpdate {
@ -1441,8 +1438,7 @@ mod native_interrupt_tests {
let args = Args {
thread_id: Some("thread-1".to_string()),
cwd: temp.path().to_path_buf(),
thread_state_store: store.clone(),
runtime_store: store,
store,
ephemeral: true,
json: true,
result: None,
@ -1455,7 +1451,7 @@ mod native_interrupt_tests {
assert_eq!(result["source"], "native");
assert_eq!(result["cancelRequested"], false);
assert_eq!(
result["epiphanyState"]["job_bindings"][0]["blocking_reason"],
result["state"]["job_bindings"][0]["blocking_reason"],
"native status proof"
);
Ok(())

View file

@ -25,29 +25,21 @@ use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct EpiphanyCoordinatorService {
thread_state_store: PathBuf,
runtime_spine_store: PathBuf,
store: PathBuf,
}
impl EpiphanyCoordinatorService {
pub fn new(
thread_state_store: impl Into<PathBuf>,
runtime_spine_store: impl Into<PathBuf>,
) -> Self {
pub fn new(store: impl Into<PathBuf>) -> Self {
Self {
thread_state_store: thread_state_store.into(),
runtime_spine_store: runtime_spine_store.into(),
store: store.into(),
}
}
pub fn thread_state_store(&self) -> &Path {
&self.thread_state_store
}
pub fn runtime_spine_store(&self) -> &Path {
&self.runtime_spine_store
pub fn store(&self) -> &Path {
&self.store
}
pub fn state(&self) -> Result<Option<EpiphanyThreadState>> {
read_coordinator_state(&self.thread_state_store)
read_coordinator_state(&self.store)
}
pub fn role_result(
@ -58,7 +50,7 @@ impl EpiphanyCoordinatorService {
let state = self.state()?;
Ok(read_role_result_snapshot(
state.as_ref(),
Some(&self.runtime_spine_store),
Some(&self.store),
role_id,
binding_id,
))
@ -71,7 +63,7 @@ impl EpiphanyCoordinatorService {
let state = self.state()?;
Ok(read_reorient_result_snapshot(
state.as_ref(),
Some(&self.runtime_spine_store),
Some(&self.store),
binding_id,
))
}
@ -82,12 +74,7 @@ impl EpiphanyCoordinatorService {
update: EpiphanyStateUpdate,
reference_turn_id: Option<String>,
) -> Result<EpiphanyCoordinatorStateApplied> {
apply_coordinator_state_update(
&self.thread_state_store,
thread_id,
update,
reference_turn_id,
)
apply_coordinator_state_update(&self.store, thread_id, update, reference_turn_id)
}
pub fn apply_state_update_from(
@ -98,7 +85,7 @@ impl EpiphanyCoordinatorService {
reference_turn_id: Option<String>,
) -> Result<EpiphanyCoordinatorStateApplied> {
apply_coordinator_state_update_from_state(
&self.thread_state_store,
&self.store,
thread_id,
current_state,
update,
@ -118,18 +105,11 @@ impl EpiphanyCoordinatorService {
let plan = plan_coordinator_job_launch(
state,
request,
&self.runtime_spine_store,
&self.store,
launcher_job_id,
backend_job_id,
)?;
commit_coordinator_job_launch(
&self.runtime_spine_store,
thread_id,
state,
request,
&plan,
created_at,
)
commit_coordinator_job_launch(&self.store, thread_id, state, request, &plan, created_at)
}
pub fn accept_role(
@ -144,7 +124,7 @@ impl EpiphanyCoordinatorService {
nonce: &str,
) -> Result<EpiphanyNativeRoleAcceptance> {
accept_coordinator_role_finding(
&self.runtime_spine_store,
&self.store,
thread_id,
state,
role_id,
@ -169,7 +149,7 @@ impl EpiphanyCoordinatorService {
update_investigation_checkpoint: bool,
) -> Result<EpiphanyNativeReorientAcceptance> {
accept_coordinator_reorient_finding(
&self.runtime_spine_store,
&self.store,
thread_id,
state,
binding_id,
@ -188,7 +168,7 @@ impl EpiphanyCoordinatorService {
state: &EpiphanyThreadState,
request: EpiphanyJobInterruptRequest,
) -> Result<EpiphanyJobInterruptResult> {
interrupt_coordinator_job(&self.thread_state_store, thread_id, state, request)
interrupt_coordinator_job(&self.store, thread_id, state, request)
}
}
@ -209,6 +189,8 @@ mod tests {
"build_role_acceptance_bundle",
"serde_json",
"thread/epiphany/",
"thread_state_store",
"runtime_spine_store",
] {
assert!(
!production.contains(forbidden),

View file

@ -85,12 +85,11 @@ flowchart LR
`runtime_spine.rs` registers and persists worker launch requests, worker
results, Mind reviews, Mind commit receipts, Eyes packets, Substrate Gate
grants, Hands consequence receipts, Soul verdicts, Continuity receipts, and
coordinator run receipts. Conceptually, the runtime store is lifecycle/evidence
truth and the thread-state store is admitted Mind truth. Current launch and
acceptance code, however, receive `runtime_spine_store` and write
`THREAD_STATE_KEY` into that cache. Production often aliases the paths, but the
API names conceal that requirement. The boundary must be repaired before the
two-store invariant can be claimed.
coordinator run receipts. `EpiphanyCoordinatorService` now accepts one `store`
path for canonical state and its atomic runtime/witness companions. The native
status mouth exposes the same boundary as one `--store` argument. Document
families remain typed and separately owned inside the cache; filesystem path
plurality no longer pretends to be an authority boundary.
## Hands → Soul → Modeling Loop
@ -110,7 +109,7 @@ consequence valid.
## Read And Recommendation Flow
`epiphany-mvp-status` reads the native thread-state and runtime-spine stores.
`epiphany-mvp-status` reads the unified native coordinator store.
It derives:
- scene via `surfaces/scene.rs`;
@ -178,10 +177,9 @@ The following are structurally absent:
- Codex-backed MVP status/interruption;
- `epiphany-codex-bridge`.
Native operator projections may still emit a compatibility-shaped
`epiphanyState` field. That field belongs to Epiphany's native projection and is
an active cleanup target; it is not the deleted Codex `Thread.epiphanyState`
contract returning through a side door.
Native coordinator/status projections emit `state`, not the deleted Codex
`Thread.epiphanyState` spelling. Source guards reject that compatibility field
and reject the old two-store status flags.
Codex app-server protocol has no dependency on `epiphany-state-model`.
App-server has no Epiphany state-model/core/bridge dependency. Negative source

View file

@ -94,6 +94,11 @@ Exit evidence:
### 2. Normalize Native Operator Contracts
Status: complete for the canonical coordinator/status boundary. The two-path
service constructor and status flags are deleted, native JSON emits `state`,
and the wrapper supplies the live unified store. Source guards reject the old
field and flags.
- Audit native JSON artifacts for compatibility-shaped field names and nested
Codex response assumptions.
- Rename only when no external contract depends on the old shape; otherwise
@ -188,7 +193,7 @@ Delete or demote:
## Immediate Next Action
Normalize native operator contracts. Begin with an inventory of
compatibility-shaped `epiphanyState` JSON and misleading `runtime_spine_store`
path names, identify each living consumer, and either rename the native
contract or record a bounded migration with an expiry.
Audit the live Hands -> Soul -> Modeling -> Mind -> Self loop against the fresh
repository exit evidence. Identify which required receipt, admission, and
negative-bypass proofs are current and which are only historical claims; close
the first missing proof rather than adding another route or summary.

View file

@ -1992,6 +1992,14 @@ impersonation. The full core library passes 248 tests. That sweep also repaired
mixed-case `Persona`/`Modeling` dependency ids that made the renamed organs
depend on themselves. Next inventory native compatibility-shaped operator JSON
and the misleading `runtime_spine_store` name before renaming either.
That operator-boundary cut is complete. `EpiphanyCoordinatorService` now takes
one `store`; status takes one `--store`; the local wrapper passes its live
coordinator store; and native coordinator/status JSON emits `state` rather than
the extinct Codex-shaped `epiphanyState`. Guards reject the old field and split
flags. The actual status executable ran successfully against
`state/runtime-spine.msgpack`. Next audit current proof of the full Hands ->
Soul -> Modeling -> Mind -> Self loop instead of trusting historical victory
prose.
## Immediate Re-entry Instruction

Binary file not shown.

View file

@ -356,7 +356,7 @@ rejected_paths:
reason: making Epiphany cleaner inside Codex still preserves the wrong organ; Codex must be starved down to OpenAI subscription auth/model transport, while Epiphany data and subsystem communication move to typed CultCache/CultNet.
current_status:
summary: Epiphany state, prompts, coordinator policy, runtime spine, receipts, and operator surfaces are native typed Rust/CultCache/CultMesh/CultNet organs. Vendored Codex retains Codex-native app-server plus OpenAI-compatible auth/model transport only. The ThreadEpiphany JSON-RPC surface, DTOs, Codex thread-state projection, legacy rollout migration, compatibility smokes, watcher adapter, and epiphany-codex-bridge crate are deleted. Native MVP status and interruption read the unified native state/runtime store. The next mapping debt is the stale algorithmic-map document, not surviving runtime authority.
summary: Epiphany state, prompts, coordinator policy, runtime spine, receipts, and operator surfaces are native typed Rust/CultCache/CultMesh/CultNet organs. Vendored Codex retains Codex-native app-server plus OpenAI-compatible auth/model transport only. Canonical state has one transaction owner and one coordinator store boundary; native status/coordinator JSON emits `state`, and the extinct Codex Epiphany routes, DTOs, bridge, migration, and compatibility field cannot decide or describe native truth.
latest_cut: >
The bridge host seam has been cut down: target-specific Hands prompt scar
tissue was purged, bridge manifests carry the retained Codex websocket fork
@ -659,4 +659,4 @@ current_status:
- Service lifecycle receipt history is now event-only: `load_epiphany_cultmesh_daemon_service_lifecycle_receipts` filters out the `epiphany-local/daemon-service-lifecycle-receipt/latest` mirror, while `load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt` remains the latest-state reader. Focused unit test `service_lifecycle_receipt_history_excludes_latest_mirror` proves two per-receipt writes return exactly two history records and latest points at the second. Fresh smoke `verse-query-lifecycle-history-filter-smoke` and live overview/triage `local-20260618-145632-497-efac6f0d` / `local-20260618-145632-321-867947af` prove compact swarm sights still expose service lifecycle attention plus the present elevated runbook artifact without daemon pokes or service mutation. Do not use a broad unscoped cargo test filter for this check on Windows; it fans out across bin harnesses and hit a broken pipe during this pass.
- `epiphany-verse-query seed-compact` is the compact seed receipt for wrappers and read-only rites. The older `seed` command still prints the full local Verse context for explicit debugging, but compact wrapper modes now avoid full `seed`/final `query` readback after the combined overview proof exposed Windows debug stack overflow from full-context serialization pressure.
last_completed_repo_swarm_cut: Huginn live-fire has crossed the first real repo Body from Persona pressure to branch-local Hands commit and Soul/Mind closure, and now has repeatable closure and redacted-public-proof mouths. On `E:\Projects\Huginn` branch `epiphany/huginn/first-awakening`, `tools/epiphany_local_run.ps1 -Mode repo-persona-intake` accepted item `huginn-inspection-readback-livefire`, Weksa/Persona intake remained sealed, and `epiphany-work derive-plan` lowered it to model-authored safe family `repo.status_section` for `README.md` only. `tools/epiphany_local_run.ps1 -Mode repo-swarm-run` advanced four bounded pulses: run-from-plan, adopt-from-plan, execute-from-plan, and close-from-execute. Huginn commit `e9b07c38fceabbdc89ea35c2156326c80c0393a2` updated only `README.md`; closure receipt `.epiphany\work\work-close-huginn-inspection-readback-livefire.json` records status `closed`, Soul verdict `passed`, Mind state commit `repo-work-close-huginn-inspection-readback-livefire-mind-commit`, safe family `repo.status_section`, path scope `README.md`, Bifrost publication gate, and `privateStateExposed=false`. Verification also ran Huginn's TypeScript compiler through concrete Node path: `C:\Program Files\nodejs\node.exe E:\Projects\Huginn\node_modules\typescript\bin\tsc -p tsconfig.json` passed. Native verifier `epiphany-repo-livefire-closure-smoke --workspace E:\Projects\Huginn --item huginn-inspection-readback-livefire --expected-path README.md --expected-family repo.status_section --expected-gate awaiting-publication --expected-blocker bifrost-publication-missing` checks closure receipt, Mind map entry, overview gate/blocker, authority seals, and `git show` changed paths, returning `status=ok`, `soulVerdict=passed`, `publicationGate=Bifrost`, and `privateStateExposed=false`. Wrapper `tools/epiphany_local_run.ps1 -Mode repo-livefire-closure -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exposes the same read-only proof through the local operator mouth; artifact `local-20260621-190156-803-2f85ba15` printed commit, path, gate, blocker, Soul verdict, Mind commit receipt, and `privateStateExposed=False` without push, merge, publication, or target mutation. New wrapper `tools/epiphany_local_run.ps1 -Mode repo-work-public-proof -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exports the redacted proof bundle and repo-local Verse index without publishing; artifact `local-20260621-190645-345-4555b1dc` wrote `.epiphany\public\proof-bundles\repo-work-public-proof-huginn-inspection-readback-livefire.json`, proof id `repo-work-public-proof-huginn-inspection-readback-livefire`, SHA-256 `857545b199f3e37eb06c2e757e5cfc201958e46667bb1f8403fd333a22620f63`, nine artifact rows, zero publication rows, and `privateStateExposed=False`. Gjallar readback `local-20260621-190701-140-b9519ec6` sees the `REPO-WORK-PUBLIC-PROOF` row and action row from Huginn's repo-local Verse with the same SHA-256 while Bifrost publication remains missing. Launcher compact modes are now named compact operator-context modes instead of read-only modes, and `bifrost-public-proof` summaries print item, target public Verse, room, proof SHA-256, review receipts, and credit receipts so publication receipts are auditable without claiming upstream sync.
next_action: Normalize native operator contracts. Inventory compatibility-shaped `epiphanyState` JSON and misleading `runtime_spine_store` path names, identify living consumers, then rename native contracts or define bounded typed migrations without recreating Codex authority.
next_action: Audit the live Hands -> Soul -> Modeling -> Mind -> Self loop against its fresh-repository exit evidence. Verify each required receipt, admission, and negative-bypass proof from current artifacts/source, then close the first missing proof without adding route or summary authority.

View file

@ -679,7 +679,7 @@ if ($Mode -eq "status" -or $Mode -eq "mvp") {
$statusArgs = @(
"--source", "native",
"--cwd", $Workspace,
"--thread-state-store", (Join-Path $Root "state\thread-state.msgpack"),
"--store", $runtimeStore,
"--json",
"--result", $statusJson
)