From c9e9a352bde640d03a2e2394de1b22477a23ee96 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 19 Jul 2026 05:51:27 +0100 Subject: [PATCH] Expose exact resident readiness refusals --- epiphany-core/src/resident_readiness.rs | 117 ++++++++++++++++++++---- notes/fresh-workspace-handoff.md | 33 +++++++ state/ledgers.msgpack | Bin 531336 -> 531736 bytes state/map.yaml | 2 +- 4 files changed, 134 insertions(+), 18 deletions(-) diff --git a/epiphany-core/src/resident_readiness.rs b/epiphany-core/src/resident_readiness.rs index 0c8c3466..2fbf7de6 100644 --- a/epiphany-core/src/resident_readiness.rs +++ b/epiphany-core/src/resident_readiness.rs @@ -482,7 +482,7 @@ fn provider_is_fresh( created_at_rfc3339: None, executable_path: PathBuf::from(&value.process_executable_path), }) == ProcessInstanceObservation::ExactAlive; - let ready = provider_matches_authority( + let failures = provider_authority_failures( &value, owner, request.release_runtime_id, @@ -494,12 +494,63 @@ fn provider_is_fresh( request.freshness_millis, exact_process, ); - if !ready { + if !failures.is_empty() { reasons.push(format!( - "{owner} provider readiness is stale or release-substituted" + "{owner} provider readiness failed predicates: {}", + failures.join(",") )); } - ready + failures.is_empty() +} + +#[allow(clippy::too_many_arguments)] +fn provider_authority_failures( + value: &ResidentProviderReadiness, + owner: &str, + runtime_id: &str, + release_id: &str, + witness: &str, + source_commit: Option<&str>, + executable: Option<&Path>, + now_millis: u64, + freshness_millis: u64, + exact_process_alive: bool, +) -> Vec<&'static str> { + let mut failures = Vec::new(); + if value.provider != owner { + failures.push("owner"); + } + if value.runtime_id != runtime_id { + failures.push("runtime"); + } + if value.release_id != release_id { + failures.push("release"); + } + if value.release_witness_sha256 != witness { + failures.push("witness"); + } + if !source_commit.is_some_and(|commit| commit == value.source_commit) { + failures.push("source-commit"); + } + if !executable.is_some_and(|path| { + canonical_or_absolute(path) + == canonical_or_absolute(Path::new(&value.process_executable_path)) + }) + { + failures.push("executable"); + } + if value.status != "ready" { + failures.push("provider-status"); + } + if !exact_process_alive { + failures.push("process-incarnation"); + } + if now_millis < value.observed_at_millis { + failures.push("future-observation"); + } else if now_millis.saturating_sub(value.observed_at_millis) > freshness_millis { + failures.push("freshness"); + } + failures } #[allow(clippy::too_many_arguments)] @@ -515,19 +566,19 @@ fn provider_matches_authority( freshness_millis: u64, exact_process_alive: bool, ) -> bool { - value.provider == owner - && value.runtime_id == runtime_id - && value.release_id == release_id - && value.release_witness_sha256 == witness - && source_commit.is_some_and(|commit| commit == value.source_commit) - && executable.is_some_and(|path| { - canonical_or_absolute(path) - == canonical_or_absolute(Path::new(&value.process_executable_path)) - }) - && value.status == "ready" - && exact_process_alive - && now_millis >= value.observed_at_millis - && now_millis.saturating_sub(value.observed_at_millis) <= freshness_millis + provider_authority_failures( + value, + owner, + runtime_id, + release_id, + witness, + source_commit, + executable, + now_millis, + freshness_millis, + exact_process_alive, + ) + .is_empty() } fn distinct_physical_paths(left: &Path, right: &Path) -> bool { @@ -770,6 +821,38 @@ mod tests { assert!(reasons[0].contains("PID was reused")); } + #[test] + fn provider_authority_reports_exact_failed_predicates() { + let mut value = provider(); + value.runtime_id = "wrong-runtime".into(); + value.release_id = "wrong-release".into(); + value.status = "warming".into(); + value.observed_at_millis = 2_000; + let executable = PathBuf::from(&value.process_executable_path); + + assert_eq!( + provider_authority_failures( + &value, + "heartbeat", + "ygg", + "release-a", + &value.release_witness_sha256, + Some("commit-a"), + Some(&executable), + 1_500, + 180_000, + false, + ), + vec![ + "runtime", + "release", + "provider-status", + "process-incarnation", + "future-observation", + ] + ); + } + #[test] fn aggregate_pair_warms_on_missing_and_rejects_wrong_release() -> Result<()> { let temp = tempfile::tempdir()?; diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 97b06491..bd2a3750 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -2918,3 +2918,36 @@ transaction is already exact-replay idempotent, so no speculative current-claim query is needed in front of it. Current claim sight is recovery output, not recovery input. A source-order test makes the authority ordering explicit. Full library passes 574/574 with one ignored; supervisor authority tests pass 24/24. + +## Ordinary organizational product and current readiness refusal (2026-07-19) + +The Yggdrasil body is the normal organizational Epiphany product, not a special +experiment or dogfood mode. Persistent Modeling maps the authorized domain. +Resident Self may derive direction from the admitted map and ask Imagination +for bounded proposals without waiting for an instruction. Organization members +talk to the repository Persona; their attributed conversation becomes +additional feedback pressure. Conversation is not the ignition key and cannot +adopt Mind state, authorize Hands, grant Persona public speech, cross Bifrost, +or ask Idunn to deploy. Those remain distinct explicit authorities. + +Exact candidate `9e1fa0f527b3bff2c5a709eff640b0d8d2f3b82d` consumed recovery +directive `6f1dc0c8-b8a5-48d0-add5-761b17368fbf`, replaced historical claim +`c6df4335-7080-4d5f-80fc-4fa18a9d16ce` with current claim +`2a355736-3792-4f0f-8633-a246219bcf1b`, and completed a 14,793-point local +Qdrant projection through Yggdrasil's GTX 1080-backed Ollama route. Its three +service owners remain active with zero restarts and the all-scope deployment +brake engaged. It is not deployed: Idunn's exact transaction PGID `1245215` +still owns the candidate, `deployment.env` is absent, and typed resident +readiness remains `warming` because both provider comparisons refuse. + +Both provider rows continue to refresh, name the exact release +`sha256-0a15262fd4c240a0131755aa6eb63b4eb7feff12e7cc4f49128fbb001887b1f2`, +witness `sha256-49ae1afcf11d18c0e2807ea53f54dba35df4280f6596e848c5cfc50328e01aea`, +source commit, executable, and local status `ready`. The old diagnostic +`stale or release-substituted` collapses owner, runtime, release, witness, +source, executable, provider status, process incarnation, future time, and +freshness into one useless phrase. Replace that opaque boolean with the same +fail-closed predicates plus operator-safe failed-predicate names; do not relax +admission. Keep the bounded diagnosis window while the Idunn transaction and +brake remain exact. If transaction ownership or the brake disappears, or any +protected surface actuates, use the existing rollback boundary immediately. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index bd749beaf88084a8fb83980fe1ebe8ebd25dc9f6..ca27fbe540f128982461926458c765f49f2058ff 100644 GIT binary patch delta 459 zcmYL_Jxc>Y5Qe?@l~PbauoS3j#?)p#GWuLQCs{2V0WE fAY>jh8HzGQ#Y?Nfi3Bt(n^op^8vp autonomous bounded Imagination proposal, with classified organization feedback through Persona as an additional pressure path; explicit Mind adoption -> Hands consequence -> Bifrost release -> Idunn deployment remain separate gates. Prove replay/tamper refusal and that conversation alone grants no Mind, Hands, Persona-speech, release, or deployment authority. No host reboot is authorized." + next_action: "Candidate 9e1fa0f remains inside exact Idunn transaction PGID 1245215 with the all-scope brake engaged and no deployment.env witness. Recovery and 14,793-point Yggdrasil-local GPU projection succeeded; three providers are alive with zero restarts. Typed resident readiness still refuses both provider comparisons although their rows refresh and report ready. Finish the fail-closed per-predicate diagnostic cut, terminate only through Idunn's transaction boundary when the successor is ready, then Bifrost-authorize and Idunn-deploy that exact successor under brake. Require exact release/witness/source/process diagnostics, signed aggregate health, and final deployment.env before the Starfire-offline ordinary-product rehearsal: persistent Modeling map -> autonomous bounded Imagination proposal, with organization feedback through Persona as additional attributed pressure; explicit Mind adoption -> Hands consequence -> Bifrost release -> Idunn deployment remain separate gates. Prove replay/tamper refusal and that conversation alone grants no Mind, Hands, Persona-speech, release, or deployment authority. No host reboot is authorized."