Unify coordinator work projection
This commit is contained in:
parent
99e883968c
commit
2bcbf2687d
9 changed files with 41 additions and 53 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::{Context, Result};
|
||||
use crate::{
|
||||
EpiphanyCoordinatorInput, EpiphanyCrrcAction, EpiphanyCurrentWorkProjection,
|
||||
EpiphanyRoleBoardInput, RepoFrontierPlanningLifecycle, RepoFrontierPlanningLifecycleStage,
|
||||
EpiphanyCoordinatorInput, EpiphanyCurrentWorkProjection, EpiphanyRoleBoardInput,
|
||||
RepoFrontierPlanningLifecycle, RepoFrontierPlanningLifecycleStage,
|
||||
RepoFrontierResearchLifecycle, RepoFrontierResearchLifecycleStage, derive_role_board,
|
||||
};
|
||||
use serde_json::{Value, json};
|
||||
|
|
@ -23,38 +23,25 @@ const MAX_OPERATOR_TEXT_CHARS: usize = 1200;
|
|||
pub fn native_coordinator_json(runtime_store: &Path, thread_id: &str) -> Result<Value> {
|
||||
let store_path = absolute_path(runtime_store)?;
|
||||
|
||||
let mind = if store_path.exists() {
|
||||
Some(
|
||||
crate::assemble_mind_view(&store_path).with_context(|| {
|
||||
format!("failed to assemble keyed Mind {}", store_path.display())
|
||||
})?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let current_work = if mind.is_some() {
|
||||
crate::project_current_work(&store_path)
|
||||
.context("failed to derive current work from keyed Mind and runtime receipts")?
|
||||
} else {
|
||||
empty_current_work()
|
||||
};
|
||||
let latest_reorientation_decision = mind
|
||||
let projected_work = store_path
|
||||
.exists()
|
||||
.then(|| {
|
||||
crate::project_current_work(&store_path)
|
||||
.context("failed to derive current work from keyed Mind and runtime receipts")
|
||||
})
|
||||
.transpose()?;
|
||||
let mind_present = projected_work.is_some();
|
||||
let projection_digest = projected_work
|
||||
.as_ref()
|
||||
.and_then(|mind| mind.reorientation_decisions.last());
|
||||
let crrc_action =
|
||||
if latest_reorientation_decision.is_some_and(|decision| decision.mode == "regather") {
|
||||
EpiphanyCrrcAction::RegatherManually
|
||||
} else {
|
||||
EpiphanyCrrcAction::Continue
|
||||
};
|
||||
.map(|work| work.mind_projection_digest.clone());
|
||||
let current_work = projected_work.unwrap_or_else(empty_current_work);
|
||||
|
||||
let roles = derive_role_board(EpiphanyRoleBoardInput {
|
||||
mind_present: mind.is_some(),
|
||||
mind_present,
|
||||
current_work: current_work.clone(),
|
||||
});
|
||||
let coordinator = crate::recommend_coordinator_action(EpiphanyCoordinatorInput {
|
||||
mind_present: mind.is_some(),
|
||||
crrc_action,
|
||||
mind_present,
|
||||
current_work: current_work.clone(),
|
||||
});
|
||||
Ok(sanitize_for_operator(json!({
|
||||
|
|
@ -62,8 +49,8 @@ pub fn native_coordinator_json(runtime_store: &Path, thread_id: &str) -> Result<
|
|||
"read": {
|
||||
"source": "native",
|
||||
"mindStore": store_path,
|
||||
"mindPresent": mind.is_some(),
|
||||
"projectionDigest": mind.as_ref().map(|mind| mind.projection_digest.as_str()),
|
||||
"mindPresent": mind_present,
|
||||
"projectionDigest": projection_digest,
|
||||
},
|
||||
"roles": {"threadId": thread_id, "source": "native", "roles": roles},
|
||||
"currentWork": current_work,
|
||||
|
|
@ -74,6 +61,7 @@ pub fn native_coordinator_json(runtime_store: &Path, thread_id: &str) -> Result<
|
|||
fn empty_current_work() -> EpiphanyCurrentWorkProjection {
|
||||
EpiphanyCurrentWorkProjection {
|
||||
mind_projection_digest: String::new(),
|
||||
operator_regather_required: false,
|
||||
body_modeling: None,
|
||||
research: RepoFrontierResearchLifecycle {
|
||||
stage: RepoFrontierResearchLifecycleStage::Terminal,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ pub enum EpiphanyAgentPassAdmissionRefusalKind {
|
|||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpiphanyCurrentWorkProjection {
|
||||
pub mind_projection_digest: String,
|
||||
pub operator_regather_required: bool,
|
||||
pub body_modeling: Option<EpiphanyBodyModelingCurrentWorkProjection>,
|
||||
pub research: crate::RepoFrontierResearchLifecycle,
|
||||
pub frontier_planning: crate::RepoFrontierPlanningLifecycle,
|
||||
|
|
@ -519,8 +520,13 @@ pub fn project_current_work(store_path: impl AsRef<Path>) -> Result<EpiphanyCurr
|
|||
} else {
|
||||
(Vec::new(), None)
|
||||
};
|
||||
let operator_regather_required = mind
|
||||
.reorientation_decisions
|
||||
.last()
|
||||
.is_some_and(|decision| decision.mode == "regather");
|
||||
Ok(EpiphanyCurrentWorkProjection {
|
||||
mind_projection_digest: mind.projection_digest,
|
||||
operator_regather_required,
|
||||
body_modeling,
|
||||
research: crate::runtime_spine::repo_frontier_research_lifecycle(&cache)?,
|
||||
frontier_planning: crate::runtime_spine::repo_frontier_planning_lifecycle(&cache)?,
|
||||
|
|
|
|||
|
|
@ -298,7 +298,6 @@ pub use surfaces::EpiphanyCoordinatorAction;
|
|||
pub use surfaces::EpiphanyCoordinatorDecision;
|
||||
pub use surfaces::EpiphanyCoordinatorInput;
|
||||
pub use surfaces::EpiphanyCoordinatorRoleStatus;
|
||||
pub use surfaces::EpiphanyCrrcAction;
|
||||
pub use surfaces::EpiphanyCrrcResultStatus;
|
||||
pub use surfaces::EpiphanyReorientFindingInterpretation;
|
||||
pub use surfaces::EpiphanyReorientWorkerLaunchDocument;
|
||||
|
|
|
|||
|
|
@ -986,10 +986,10 @@ mod tests {
|
|||
let result = crate::EpiphanyRuntimeReorientWorkerResult {
|
||||
result_id: "reorientation-result".into(),
|
||||
job_id: job_id.clone(),
|
||||
mode: "resume".into(),
|
||||
summary: "The sealed checkpoint remains coherent.".into(),
|
||||
next_safe_move: "Continue the keyed migration.".into(),
|
||||
checkpoint_still_valid: Some(true),
|
||||
mode: "regather".into(),
|
||||
summary: "The sealed checkpoint requires fresh external evidence.".into(),
|
||||
next_safe_move: "Regather before resuming the keyed migration.".into(),
|
||||
checkpoint_still_valid: Some(false),
|
||||
files_inspected: Vec::new(),
|
||||
frontier_node_ids: Vec::new(),
|
||||
evidence_ids: Vec::new(),
|
||||
|
|
@ -1028,7 +1028,17 @@ mod tests {
|
|||
accept_reorientation_result(&store, &job_id, "2026-08-18T10:00:07Z")?,
|
||||
receipt
|
||||
);
|
||||
assert!(crate::project_current_work(&store)?.reorientation.is_none());
|
||||
let current_work = crate::project_current_work(&store)?;
|
||||
assert!(current_work.reorientation.is_none());
|
||||
assert!(current_work.operator_regather_required);
|
||||
assert_eq!(
|
||||
crate::recommend_coordinator_action(crate::EpiphanyCoordinatorInput {
|
||||
mind_present: true,
|
||||
current_work,
|
||||
})
|
||||
.action,
|
||||
crate::EpiphanyCoordinatorAction::RegatherManually
|
||||
);
|
||||
let mut accepted = crate::runtime_spine_cache(&store)?;
|
||||
accepted.pull_all_backing_stores()?;
|
||||
assert!(
|
||||
|
|
|
|||
|
|
@ -969,7 +969,6 @@ pub(crate) fn resident_self_current_work_action(
|
|||
let projection_digest = current_work.projection_digest()?;
|
||||
let decision = crate::recommend_coordinator_action(crate::EpiphanyCoordinatorInput {
|
||||
mind_present: true,
|
||||
crrc_action: crate::EpiphanyCrrcAction::Continue,
|
||||
current_work,
|
||||
});
|
||||
if !matches!(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use super::EpiphanyCrrcAction;
|
||||
use crate::EpiphanyCurrentWorkProjection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -46,7 +45,6 @@ pub enum EpiphanyCoordinatorAction {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EpiphanyCoordinatorInput {
|
||||
pub mind_present: bool,
|
||||
pub crrc_action: EpiphanyCrrcAction,
|
||||
pub current_work: EpiphanyCurrentWorkProjection,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
EpiphanyAgentPassContinuationAction, EpiphanyCoordinatorAction, EpiphanyCoordinatorDecision,
|
||||
EpiphanyCoordinatorInput, EpiphanyCrrcAction, RepoFrontierPlanningLifecycleStage,
|
||||
EpiphanyCoordinatorInput, RepoFrontierPlanningLifecycleStage,
|
||||
RepoFrontierResearchContinuationAction,
|
||||
};
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ pub fn recommend_coordinator_action(
|
|||
);
|
||||
}
|
||||
|
||||
if input.crrc_action == EpiphanyCrrcAction::RegatherManually {
|
||||
if input.current_work.operator_regather_required {
|
||||
return decision(
|
||||
EpiphanyCoordinatorAction::RegatherManually,
|
||||
"The accepted continuity decision requires explicit operator regather.",
|
||||
|
|
|
|||
|
|
@ -14,14 +14,3 @@ pub enum EpiphanyCrrcResultStatus {
|
|||
Failed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EpiphanyCrrcAction {
|
||||
Continue,
|
||||
LaunchReorientWorker,
|
||||
WaitForReorientWorker,
|
||||
ReviewReorientResult,
|
||||
AcceptReorientResult,
|
||||
RegatherManually,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ mod worker_launch;
|
|||
|
||||
pub use coordinator_contract::*;
|
||||
pub use coordinator_decision::recommend_coordinator_action;
|
||||
pub use crrc::EpiphanyCrrcAction;
|
||||
pub use crrc::EpiphanyCrrcResultStatus;
|
||||
pub use research_decision::EpiphanyResearchDecision;
|
||||
pub use role_board::EpiphanyRoleBoardInput;
|
||||
|
|
|
|||
Reference in a new issue