From 40beb6a99cb590cafde1af60f8dc6f4f5bd5bc02 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 14 Aug 2026 03:34:54 +0200 Subject: [PATCH] Project Research continuation from lifecycle --- epiphany-core/src/bin/epiphany-mvp-status.rs | 5 +-- epiphany-core/src/lib.rs | 1 + epiphany-core/src/resident_self.rs | 39 +++++--------------- epiphany-core/src/runtime_spine.rs | 39 +++++++++++++++++++- 4 files changed, 49 insertions(+), 35 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-mvp-status.rs b/epiphany-core/src/bin/epiphany-mvp-status.rs index a3b92aa7..791099e5 100644 --- a/epiphany-core/src/bin/epiphany-mvp-status.rs +++ b/epiphany-core/src/bin/epiphany-mvp-status.rs @@ -38,7 +38,6 @@ use epiphany_core::derive_scene; use epiphany_core::read_accepted_coordinator_state; use epiphany_core::recommend_crrc_action; use epiphany_core::recommend_reorientation; -use epiphany_core::RepoFrontierResearchLifecycleStage; use epiphany_core::runtime_repo_frontier_research_lifecycle; use epiphany_core::runtime_has_actionable_hands_frontier; use epiphany_core::runtime_job_snapshot; @@ -482,8 +481,8 @@ fn run_native_status(args: &Args, include_auxiliary_status: bool) -> Result Result { match action { - // Research launch currency belongs to the exact current frontier - // lifecycle. Uncovered means that Mind still lacks accepted coverage; - // it does not mean another worker is launchable while an exact attempt - // is running or awaiting review. - "launchResearch" => Ok(!matches!( - crate::runtime_repo_frontier_research_lifecycle(runtime_store)?.stage, - crate::RepoFrontierResearchLifecycleStage::LaunchReady - )), // These legacy checkpoint lanes do not yet expose an exact current // request projection. Keep their existing role-slot behavior explicit // rather than pretending it is the same authority as Research. @@ -1216,10 +1208,17 @@ pub(crate) fn resident_self_safe_continuation_action( runtime_store: &Path, receipt: &crate::EpiphanyCoordinatorRunReceipt, ) -> Result> { + if matches!( + receipt.final_action.as_str(), + "launchResearch" | "waitForResearchResult" | "reviewResearchResult" + ) { + return Ok(crate::runtime_repo_frontier_research_lifecycle(runtime_store)? + .continuation_action() + .map(|action| action.as_str().to_string())); + } let direct = matches!( receipt.final_action.as_str(), - "launchResearch" - | "launchModeling" + "launchModeling" | "launchVerification" | "startFrontierPlanning" | "launchImagination" @@ -1238,16 +1237,6 @@ pub(crate) fn resident_self_safe_continuation_action( return Ok(Some(receipt.final_action.clone())); } let action = match receipt.final_action.as_str() { - "reviewResearchResult" - if role_projection_is_terminal_for_continuation( - runtime_store, - &receipt.thread_id, - crate::EpiphanyRoleResultRoleId::Research, - crate::EPIPHANY_RESEARCH_ROLE_BINDING_ID, - )? => - { - Some("reviewResearchResult") - } "reviewModelingResult" if role_projection_is_terminal_for_continuation( runtime_store, @@ -1268,16 +1257,6 @@ pub(crate) fn resident_self_safe_continuation_action( { Some("reviewVerificationResult") } - "waitForResearchResult" - if role_projection_is_terminal_for_continuation( - runtime_store, - &receipt.thread_id, - crate::EpiphanyRoleResultRoleId::Research, - crate::EPIPHANY_RESEARCH_ROLE_BINDING_ID, - )? => - { - Some("reviewResearchResult") - } "waitForModelingResult" if role_projection_is_terminal_for_continuation( runtime_store, diff --git a/epiphany-core/src/runtime_spine.rs b/epiphany-core/src/runtime_spine.rs index 26c811f7..db7531dd 100644 --- a/epiphany-core/src/runtime_spine.rs +++ b/epiphany-core/src/runtime_spine.rs @@ -9170,6 +9170,21 @@ pub enum RepoFrontierResearchLifecycleStage { ResultReady, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RepoFrontierResearchContinuationAction { + LaunchResearch, + ReviewResearchResult, +} + +impl RepoFrontierResearchContinuationAction { + pub fn as_str(self) -> &'static str { + match self { + Self::LaunchResearch => "launchResearch", + Self::ReviewResearchResult => "reviewResearchResult", + } + } +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RepoFrontierResearchLifecycle { @@ -9179,6 +9194,21 @@ pub struct RepoFrontierResearchLifecycle { pub worker_job_id: Option, } +impl RepoFrontierResearchLifecycle { + pub fn continuation_action(&self) -> Option { + match self.stage { + RepoFrontierResearchLifecycleStage::LaunchReady => { + Some(RepoFrontierResearchContinuationAction::LaunchResearch) + } + RepoFrontierResearchLifecycleStage::ResultReady => { + Some(RepoFrontierResearchContinuationAction::ReviewResearchResult) + } + RepoFrontierResearchLifecycleStage::Terminal + | RepoFrontierResearchLifecycleStage::WorkerRunning => None, + } + } +} + /// Projects the next exact actionable Eyes frontier through request, worker, /// review, and accepted-packet lifecycle. This is the launch-currency owner: /// an uncovered frontier is not launchable while its current attempt is still @@ -17746,8 +17776,8 @@ pub(crate) mod tests { &eyes_store, &continuation_receipt, )?, - None, - "the exact current terminal result owns review; stale launch authority is gone" + Some("reviewResearchResult".into()), + "the exact lifecycle replaces stale launch provenance with current review authority" ); let covered = EyesEvidencePacket { schema_version: EYES_EVIDENCE_PACKET_SCHEMA_VERSION.into(), @@ -17793,6 +17823,11 @@ pub(crate) mod tests { } })?; assert!(runtime_has_uncovered_actionable_eyes_frontier(&eyes_store)?); + assert_eq!( + runtime_repo_frontier_research_lifecycle(&eyes_store)? + .continuation_action(), + Some(RepoFrontierResearchContinuationAction::LaunchResearch) + ); let second_research_request = select_and_commit_repo_frontier_research_request( &eyes_store, "2026-07-13T04:06:00Z",