Move coordinator judgment into core
This commit is contained in:
parent
f3984d293e
commit
3d4ed26b0f
9 changed files with 461 additions and 285 deletions
|
|
@ -15,15 +15,14 @@ use codex_app_server_protocol::ThreadEpiphanySceneAction;
|
|||
use codex_app_server_protocol::ThreadEpiphanyViewCoordinator;
|
||||
use epiphany_core::EpiphanyCoordinatorAction as CoreEpiphanyCoordinatorAction;
|
||||
use epiphany_core::EpiphanyCoordinatorAutomationAction as CoreEpiphanyCoordinatorAutomationAction;
|
||||
use epiphany_core::EpiphanyCoordinatorCrrcRecommendation;
|
||||
use epiphany_core::EpiphanyCoordinatorDecision as CoreEpiphanyCoordinatorDecision;
|
||||
use epiphany_core::EpiphanyCoordinatorInput;
|
||||
use epiphany_core::EpiphanyCoordinatorRoleId as CoreEpiphanyCoordinatorRoleId;
|
||||
use epiphany_core::EpiphanyCoordinatorRoleLane as CoreEpiphanyCoordinatorRoleLane;
|
||||
use epiphany_core::EpiphanyCoordinatorRoleResultStatus as CoreEpiphanyCoordinatorRoleResultStatus;
|
||||
use epiphany_core::EpiphanyCoordinatorRoleStatus as CoreEpiphanyCoordinatorRoleStatus;
|
||||
use epiphany_core::EpiphanyCoordinatorSceneAction as CoreEpiphanyCoordinatorSceneAction;
|
||||
use epiphany_core::EpiphanyCoordinatorSignals;
|
||||
use epiphany_core::EpiphanyCoordinatorSourceSignals;
|
||||
use epiphany_core::EpiphanyCoordinatorStatus as CoreEpiphanyCoordinatorStatus;
|
||||
use epiphany_core::EpiphanyCoordinatorStatusInput;
|
||||
use epiphany_core::EpiphanyCrrcAction as CoreEpiphanyCrrcAction;
|
||||
use epiphany_core::EpiphanyCrrcInput;
|
||||
use epiphany_core::EpiphanyCrrcRecommendation as CoreEpiphanyCrrcRecommendation;
|
||||
|
|
@ -47,10 +46,9 @@ use epiphany_core::EpiphanyRoleBoardPlanningSummary;
|
|||
use epiphany_core::EpiphanyRoleFindingInterpretation as CoreEpiphanyRoleFinding;
|
||||
use epiphany_core::EpiphanyRoleResultRoleId;
|
||||
use epiphany_core::EpiphanyTokenUsageSnapshot;
|
||||
use epiphany_core::coordinator_automation_action;
|
||||
use epiphany_core::derive_coordinator_status;
|
||||
use epiphany_core::derive_role_board;
|
||||
use epiphany_core::modeling_role_state_patch_policy_errors;
|
||||
use epiphany_core::recommend_coordinator_action;
|
||||
use epiphany_core::recommend_crrc_action;
|
||||
use epiphany_core::render_role_board_note;
|
||||
use epiphany_core::select_coordinator_automation_action;
|
||||
|
|
@ -236,24 +234,9 @@ pub fn map_protocol_crrc_recommendation(
|
|||
|
||||
pub type EpiphanyCoordinatorDecision = CoreEpiphanyCoordinatorDecision;
|
||||
|
||||
pub struct EpiphanyCoordinatorSourceSignals {
|
||||
pub pressure_level: epiphany_core::EpiphanyPressureLevel,
|
||||
pub should_prepare_compaction: bool,
|
||||
pub reorient_action: CoreEpiphanyReorientAction,
|
||||
pub crrc_action: CoreEpiphanyCrrcAction,
|
||||
pub modeling_result_status: CoreEpiphanyCoordinatorRoleResultStatus,
|
||||
pub verification_result_status: CoreEpiphanyCoordinatorRoleResultStatus,
|
||||
pub reorient_result_status: CoreEpiphanyCrrcResultStatus,
|
||||
}
|
||||
|
||||
pub struct EpiphanyCoordinatorStatus {
|
||||
pub decision: EpiphanyCoordinatorDecision,
|
||||
pub source_signals: EpiphanyCoordinatorSourceSignals,
|
||||
pub roles: Vec<EpiphanyRoleBoardLane>,
|
||||
pub core: CoreEpiphanyCoordinatorStatus,
|
||||
pub note: String,
|
||||
pub modeling_result_accepted: bool,
|
||||
pub verification_result_accepted: bool,
|
||||
pub reorient_finding_accepted: bool,
|
||||
}
|
||||
|
||||
pub async fn derive_epiphany_coordinator_status(
|
||||
|
|
@ -351,24 +334,18 @@ pub async fn derive_epiphany_coordinator_status(
|
|||
let reorient_finding_accepted = reorient_finding.is_some_and(|finding| {
|
||||
state.is_some_and(|state| epiphany_reorient_finding_already_accepted(state, finding))
|
||||
});
|
||||
let source_signals = EpiphanyCoordinatorSourceSignals {
|
||||
pressure_level: pressure.level,
|
||||
should_prepare_compaction: pressure.should_prepare_compaction,
|
||||
let core = derive_coordinator_status(EpiphanyCoordinatorStatusInput {
|
||||
state_status: map_core_crrc_state_status_from_reorient(state_status),
|
||||
checkpoint_present,
|
||||
pressure: pressure.clone(),
|
||||
recommendation: recommendation.clone(),
|
||||
roles,
|
||||
reorient_action: reorient_decision
|
||||
.map(|decision| decision.action)
|
||||
.unwrap_or(CoreEpiphanyReorientAction::Resume),
|
||||
crrc_action: recommendation.action,
|
||||
modeling_result_status,
|
||||
verification_result_status,
|
||||
reorient_result_status,
|
||||
};
|
||||
let decision = map_epiphany_coordinator(
|
||||
state_status,
|
||||
checkpoint_present,
|
||||
pressure,
|
||||
recommendation,
|
||||
&roles,
|
||||
&source_signals,
|
||||
modeling_result_accepted,
|
||||
modeling_result_reviewable,
|
||||
modeling_result_accepted_after_verification,
|
||||
|
|
@ -379,25 +356,17 @@ pub async fn derive_epiphany_coordinator_status(
|
|||
verification_result_allows_implementation,
|
||||
verification_result_needs_evidence,
|
||||
reorient_finding_accepted,
|
||||
);
|
||||
});
|
||||
let note = render_epiphany_coordinator_note(
|
||||
recommendation.action,
|
||||
pressure.level,
|
||||
modeling_result_status,
|
||||
verification_result_status,
|
||||
source_signals.reorient_result_status,
|
||||
decision.action,
|
||||
core.source_signals.reorient_result_status,
|
||||
core.decision.action,
|
||||
);
|
||||
|
||||
EpiphanyCoordinatorStatus {
|
||||
decision,
|
||||
source_signals,
|
||||
roles,
|
||||
note,
|
||||
modeling_result_accepted,
|
||||
verification_result_accepted,
|
||||
reorient_finding_accepted,
|
||||
}
|
||||
EpiphanyCoordinatorStatus { core, note }
|
||||
}
|
||||
|
||||
pub fn map_epiphany_coordinator_view(
|
||||
|
|
@ -417,46 +386,27 @@ pub fn map_epiphany_coordinator_view(
|
|||
},
|
||||
state_status: map_protocol_reorient_state_status(state_status),
|
||||
state_revision,
|
||||
action: map_protocol_coordinator_action(status.decision.action),
|
||||
action: map_protocol_coordinator_action(status.core.decision.action),
|
||||
target_role: status
|
||||
.core
|
||||
.decision
|
||||
.target_role
|
||||
.map(map_protocol_coordinator_role_id),
|
||||
recommended_scene_action: status
|
||||
.core
|
||||
.decision
|
||||
.recommended_scene_action
|
||||
.map(map_protocol_coordinator_scene_action),
|
||||
requires_review: status.decision.requires_review,
|
||||
can_auto_run: status.decision.can_auto_run,
|
||||
reason: status.decision.reason,
|
||||
source_signals: map_protocol_coordinator_source_signals(status.source_signals),
|
||||
requires_review: status.core.decision.requires_review,
|
||||
can_auto_run: status.core.decision.can_auto_run,
|
||||
reason: status.core.decision.reason,
|
||||
source_signals: map_protocol_coordinator_source_signals(status.core.source_signals),
|
||||
roles: map_protocol_role_board_lanes(&roles),
|
||||
note: status.note,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EpiphanyCoordinatorAutomationAction {
|
||||
None,
|
||||
CompactRehydrateReorient,
|
||||
LaunchReorientWorker,
|
||||
}
|
||||
|
||||
pub fn map_epiphany_coordinator_automation_action(
|
||||
decision: &EpiphanyCoordinatorDecision,
|
||||
) -> EpiphanyCoordinatorAutomationAction {
|
||||
map_protocol_coordinator_automation_action(coordinator_automation_action(decision))
|
||||
}
|
||||
|
||||
pub fn select_epiphany_coordinator_automation_action(
|
||||
decision: &EpiphanyCoordinatorDecision,
|
||||
force_checkpoint_compaction: bool,
|
||||
) -> EpiphanyCoordinatorAutomationAction {
|
||||
map_protocol_coordinator_automation_action(select_coordinator_automation_action(
|
||||
decision,
|
||||
force_checkpoint_compaction,
|
||||
))
|
||||
}
|
||||
pub type EpiphanyCoordinatorAutomationAction = CoreEpiphanyCoordinatorAutomationAction;
|
||||
|
||||
pub struct EpiphanyCoordinatorAutomationInput<'a> {
|
||||
pub thread_id: &'a str,
|
||||
|
|
@ -544,8 +494,8 @@ pub async fn select_epiphany_coordinator_automation(
|
|||
)
|
||||
.await;
|
||||
|
||||
let action = select_epiphany_coordinator_automation_action(
|
||||
&coordinator.decision,
|
||||
let action = select_coordinator_automation_action(
|
||||
&coordinator.core.decision,
|
||||
input.force_checkpoint_compaction,
|
||||
);
|
||||
let launch_request = match action {
|
||||
|
|
@ -582,64 +532,6 @@ pub async fn select_epiphany_coordinator_automation(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn map_epiphany_coordinator(
|
||||
state_status: CoreEpiphanyReorientStateStatus,
|
||||
checkpoint_present: bool,
|
||||
pressure: &epiphany_core::EpiphanyPressure,
|
||||
recommendation: &CoreEpiphanyCrrcRecommendation,
|
||||
roles: &[EpiphanyRoleBoardLane],
|
||||
signals: &EpiphanyCoordinatorSourceSignals,
|
||||
modeling_result_accepted: bool,
|
||||
modeling_result_reviewable: bool,
|
||||
modeling_result_accepted_after_verification: bool,
|
||||
implementation_evidence_after_verification: bool,
|
||||
verification_result_cites_implementation_evidence: bool,
|
||||
verification_result_covers_current_modeling: bool,
|
||||
verification_result_accepted: bool,
|
||||
verification_result_allows_implementation: bool,
|
||||
verification_result_needs_evidence: bool,
|
||||
reorient_finding_accepted: bool,
|
||||
) -> EpiphanyCoordinatorDecision {
|
||||
recommend_coordinator_action(EpiphanyCoordinatorInput {
|
||||
state_status: map_core_crrc_state_status_from_reorient(state_status),
|
||||
checkpoint_present,
|
||||
should_prepare_compaction: pressure.should_prepare_compaction,
|
||||
recommendation: EpiphanyCoordinatorCrrcRecommendation {
|
||||
action: recommendation.action,
|
||||
recommended_scene_action: recommendation
|
||||
.recommended_scene_action
|
||||
.map(epiphany_core::crrc_scene_action_to_coordinator_scene_action),
|
||||
},
|
||||
roles: roles
|
||||
.iter()
|
||||
.map(map_core_coordinator_role_lane_from_role_board)
|
||||
.collect(),
|
||||
signals: EpiphanyCoordinatorSignals {
|
||||
modeling_result_status: signals.modeling_result_status,
|
||||
verification_result_status: signals.verification_result_status,
|
||||
},
|
||||
modeling_result_accepted,
|
||||
modeling_result_reviewable,
|
||||
modeling_result_accepted_after_verification,
|
||||
implementation_evidence_after_verification,
|
||||
verification_result_cites_implementation_evidence,
|
||||
verification_result_covers_current_modeling,
|
||||
verification_result_accepted,
|
||||
verification_result_allows_implementation,
|
||||
verification_result_needs_evidence,
|
||||
reorient_finding_accepted,
|
||||
})
|
||||
}
|
||||
|
||||
fn map_core_coordinator_role_lane_from_role_board(
|
||||
role: &EpiphanyRoleBoardLane,
|
||||
) -> CoreEpiphanyCoordinatorRoleLane {
|
||||
CoreEpiphanyCoordinatorRoleLane {
|
||||
id: role.id,
|
||||
status: role.status,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_protocol_coordinator_role_id(
|
||||
role_id: CoreEpiphanyCoordinatorRoleId,
|
||||
) -> ThreadEpiphanyRoleId {
|
||||
|
|
@ -740,20 +632,6 @@ fn map_protocol_coordinator_action(
|
|||
}
|
||||
}
|
||||
|
||||
fn map_protocol_coordinator_automation_action(
|
||||
action: CoreEpiphanyCoordinatorAutomationAction,
|
||||
) -> EpiphanyCoordinatorAutomationAction {
|
||||
match action {
|
||||
CoreEpiphanyCoordinatorAutomationAction::None => EpiphanyCoordinatorAutomationAction::None,
|
||||
CoreEpiphanyCoordinatorAutomationAction::CompactRehydrateReorient => {
|
||||
EpiphanyCoordinatorAutomationAction::CompactRehydrateReorient
|
||||
}
|
||||
CoreEpiphanyCoordinatorAutomationAction::LaunchReorientWorker => {
|
||||
EpiphanyCoordinatorAutomationAction::LaunchReorientWorker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn epiphany_reorient_finding_already_accepted(
|
||||
state: &EpiphanyThreadState,
|
||||
finding: &CoreEpiphanyReorientFinding,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use std::path::Path;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use codex_app_server_protocol::ThreadEpiphanyReorientWorkerLaunchDocument;
|
||||
|
|
@ -12,15 +11,13 @@ use epiphany_core::EpiphanyJobLaunchRequest;
|
|||
use epiphany_core::EpiphanyPressureLevel as CoreEpiphanyPressureLevel;
|
||||
use epiphany_core::EpiphanyReorientAction as CoreEpiphanyReorientAction;
|
||||
use epiphany_core::EpiphanyReorientDecision as CoreEpiphanyReorientDecision;
|
||||
use epiphany_core::EpiphanyReorientFreshnessStatus as CoreEpiphanyReorientFreshnessStatus;
|
||||
use epiphany_core::EpiphanyReorientPressureLevel as CoreEpiphanyReorientPressureLevel;
|
||||
use epiphany_core::EpiphanyReorientReason as CoreEpiphanyReorientReason;
|
||||
use epiphany_core::EpiphanyReorientLaunchRequestInput;
|
||||
use epiphany_core::EpiphanyReorientWorkerLaunchDocument;
|
||||
use epiphany_core::EpiphanyRoleResultRoleId;
|
||||
use epiphany_core::EpiphanyRoleWorkerLaunchDocument;
|
||||
use epiphany_core::EpiphanyWorkerLaunchDocument;
|
||||
use epiphany_core::build_reorient_job_launch_request;
|
||||
use epiphany_state_model::EpiphanyInvestigationCheckpoint;
|
||||
use epiphany_state_model::EpiphanyInvestigationDisposition;
|
||||
use epiphany_state_model::EpiphanyJobKind as CoreEpiphanyJobKind;
|
||||
use epiphany_state_model::EpiphanyThreadState;
|
||||
|
||||
|
|
@ -487,88 +484,18 @@ pub fn build_epiphany_reorient_launch_request(
|
|||
checkpoint: &EpiphanyInvestigationCheckpoint,
|
||||
decision: &CoreEpiphanyReorientDecision,
|
||||
) -> EpiphanyJobLaunchRequest {
|
||||
let linked_subgoal_ids = epiphany_active_subgoal_ids(Some(state));
|
||||
let linked_graph_node_ids = unique_strings(
|
||||
epiphany_active_graph_node_ids(Some(state))
|
||||
.into_iter()
|
||||
.chain(decision.active_frontier_node_ids.iter().cloned()),
|
||||
);
|
||||
let checkpoint_next_action = checkpoint
|
||||
.next_action
|
||||
.clone()
|
||||
.unwrap_or_else(|| decision.next_action.clone());
|
||||
let authority_scope = match decision.action {
|
||||
CoreEpiphanyReorientAction::Resume => "epiphany.reorient.resume",
|
||||
CoreEpiphanyReorientAction::Regather => "epiphany.reorient.regather",
|
||||
};
|
||||
let scope = match decision.action {
|
||||
CoreEpiphanyReorientAction::Resume => "reorient-guided checkpoint resume",
|
||||
CoreEpiphanyReorientAction::Regather => "reorient-guided checkpoint regather",
|
||||
};
|
||||
let instruction = build_epiphany_reorient_launch_instruction(decision.action);
|
||||
let launch_document =
|
||||
EpiphanyWorkerLaunchDocument::Reorient(EpiphanyReorientWorkerLaunchDocument {
|
||||
thread_id: thread_id.to_string(),
|
||||
mode: reorient_action_label(decision.action).to_string(),
|
||||
checkpoint_id: checkpoint.checkpoint_id.clone(),
|
||||
checkpoint_kind: checkpoint.kind.clone(),
|
||||
checkpoint_disposition: investigation_disposition_label(checkpoint.disposition)
|
||||
.to_string(),
|
||||
checkpoint_focus: Some(checkpoint.focus.clone()),
|
||||
checkpoint_summary: checkpoint.summary.clone(),
|
||||
checkpoint_next_action,
|
||||
checkpoint_open_questions: checkpoint.open_questions.clone(),
|
||||
checkpoint_evidence_ids: checkpoint.evidence_ids.clone(),
|
||||
checkpoint_code_refs: checkpoint.code_refs.clone(),
|
||||
decision_reasons: decision
|
||||
.reasons
|
||||
.iter()
|
||||
.map(|reason| reorient_reason_label(*reason).to_string())
|
||||
.collect(),
|
||||
decision_note: decision.note.clone(),
|
||||
pressure_level: reorient_pressure_level_label(decision.pressure_level).to_string(),
|
||||
retrieval_status: reorient_freshness_status_label(decision.retrieval_status)
|
||||
.to_string(),
|
||||
graph_status: reorient_freshness_status_label(decision.graph_status).to_string(),
|
||||
watcher_status: reorient_freshness_status_label(decision.watcher_status).to_string(),
|
||||
checkpoint_dirty_paths: decision
|
||||
.checkpoint_dirty_paths
|
||||
.iter()
|
||||
.map(path_to_display_string)
|
||||
.collect(),
|
||||
checkpoint_changed_paths: decision
|
||||
.checkpoint_changed_paths
|
||||
.iter()
|
||||
.map(path_to_display_string)
|
||||
.collect(),
|
||||
scratch: state.scratch.clone(),
|
||||
graphs: Some(state.graphs.clone()),
|
||||
recent_evidence: state.recent_evidence.iter().take(8).cloned().collect(),
|
||||
recent_observations: state.observations.iter().take(8).cloned().collect(),
|
||||
active_frontier_node_ids: decision.active_frontier_node_ids.clone(),
|
||||
linked_subgoal_ids: linked_subgoal_ids.clone(),
|
||||
linked_graph_node_ids: linked_graph_node_ids.clone(),
|
||||
});
|
||||
let output_contract_id = launch_document.output_contract_id().to_string();
|
||||
|
||||
EpiphanyJobLaunchRequest {
|
||||
build_reorient_job_launch_request(EpiphanyReorientLaunchRequestInput {
|
||||
thread_id,
|
||||
expected_revision,
|
||||
binding_id: EPIPHANY_REORIENT_LAUNCH_BINDING_ID.to_string(),
|
||||
kind: CoreEpiphanyJobKind::Specialist,
|
||||
scope: scope.to_string(),
|
||||
owner_role: EPIPHANY_REORIENT_OWNER_ROLE.to_string(),
|
||||
authority_scope: authority_scope.to_string(),
|
||||
linked_subgoal_ids: epiphany_active_subgoal_ids(Some(state)),
|
||||
linked_graph_node_ids: unique_strings(
|
||||
epiphany_active_graph_node_ids(Some(state))
|
||||
.into_iter()
|
||||
.chain(decision.active_frontier_node_ids.iter().cloned()),
|
||||
),
|
||||
instruction,
|
||||
launch_document,
|
||||
output_contract_id,
|
||||
max_runtime_seconds,
|
||||
}
|
||||
binding_id: EPIPHANY_REORIENT_LAUNCH_BINDING_ID,
|
||||
owner_role: EPIPHANY_REORIENT_OWNER_ROLE,
|
||||
instruction,
|
||||
state,
|
||||
checkpoint,
|
||||
decision,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn build_epiphany_reorient_launch_instruction(action: CoreEpiphanyReorientAction) -> String {
|
||||
|
|
@ -741,56 +668,3 @@ fn epiphany_active_graph_node_ids(state: Option<&EpiphanyThreadState>) -> Vec<St
|
|||
.map(|frontier| frontier.active_node_ids.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn path_to_display_string(path: impl AsRef<Path>) -> String {
|
||||
path.as_ref().to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
fn reorient_action_label(action: CoreEpiphanyReorientAction) -> &'static str {
|
||||
match action {
|
||||
CoreEpiphanyReorientAction::Resume => "resume",
|
||||
CoreEpiphanyReorientAction::Regather => "regather",
|
||||
}
|
||||
}
|
||||
|
||||
fn investigation_disposition_label(disposition: EpiphanyInvestigationDisposition) -> &'static str {
|
||||
match disposition {
|
||||
EpiphanyInvestigationDisposition::ResumeReady => "resume_ready",
|
||||
EpiphanyInvestigationDisposition::RegatherRequired => "regather_required",
|
||||
}
|
||||
}
|
||||
|
||||
fn reorient_reason_label(reason: CoreEpiphanyReorientReason) -> &'static str {
|
||||
match reason {
|
||||
CoreEpiphanyReorientReason::MissingState => "missingState",
|
||||
CoreEpiphanyReorientReason::MissingCheckpoint => "missingCheckpoint",
|
||||
CoreEpiphanyReorientReason::CheckpointRequestedRegather => "checkpointRequestedRegather",
|
||||
CoreEpiphanyReorientReason::CheckpointPathsDirty => "checkpointPathsDirty",
|
||||
CoreEpiphanyReorientReason::CheckpointPathsChanged => "checkpointPathsChanged",
|
||||
CoreEpiphanyReorientReason::FrontierChanged => "frontierChanged",
|
||||
CoreEpiphanyReorientReason::UnanchoredCheckpointWhileStateStale => {
|
||||
"unanchoredCheckpointWhileStateStale"
|
||||
}
|
||||
CoreEpiphanyReorientReason::CheckpointReady => "checkpointReady",
|
||||
}
|
||||
}
|
||||
|
||||
fn reorient_pressure_level_label(level: CoreEpiphanyReorientPressureLevel) -> &'static str {
|
||||
match level {
|
||||
CoreEpiphanyReorientPressureLevel::Unknown => "unknown",
|
||||
CoreEpiphanyReorientPressureLevel::Low => "low",
|
||||
CoreEpiphanyReorientPressureLevel::Medium => "medium",
|
||||
CoreEpiphanyReorientPressureLevel::High => "high",
|
||||
CoreEpiphanyReorientPressureLevel::Critical => "critical",
|
||||
}
|
||||
}
|
||||
|
||||
fn reorient_freshness_status_label(status: CoreEpiphanyReorientFreshnessStatus) -> &'static str {
|
||||
match status {
|
||||
CoreEpiphanyReorientFreshnessStatus::Unknown => "unknown",
|
||||
CoreEpiphanyReorientFreshnessStatus::Clean => "clean",
|
||||
CoreEpiphanyReorientFreshnessStatus::Dirty => "dirty",
|
||||
CoreEpiphanyReorientFreshnessStatus::Stale => "stale",
|
||||
CoreEpiphanyReorientFreshnessStatus::Changed => "changed",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,6 +236,9 @@ pub use surfaces::EpiphanyCoordinatorRoleResultStatus;
|
|||
pub use surfaces::EpiphanyCoordinatorRoleStatus;
|
||||
pub use surfaces::EpiphanyCoordinatorSceneAction;
|
||||
pub use surfaces::EpiphanyCoordinatorSignals;
|
||||
pub use surfaces::EpiphanyCoordinatorSourceSignals;
|
||||
pub use surfaces::EpiphanyCoordinatorStatus;
|
||||
pub use surfaces::EpiphanyCoordinatorStatusInput;
|
||||
pub use surfaces::EpiphanyCrrcAction;
|
||||
pub use surfaces::EpiphanyCrrcInput;
|
||||
pub use surfaces::EpiphanyCrrcRecommendation;
|
||||
|
|
@ -275,6 +278,7 @@ pub use surfaces::EpiphanyReorientDecision;
|
|||
pub use surfaces::EpiphanyReorientFindingInterpretation;
|
||||
pub use surfaces::EpiphanyReorientFreshnessStatus;
|
||||
pub use surfaces::EpiphanyReorientInput;
|
||||
pub use surfaces::EpiphanyReorientLaunchRequestInput;
|
||||
pub use surfaces::EpiphanyReorientPressureLevel;
|
||||
pub use surfaces::EpiphanyReorientReason;
|
||||
pub use surfaces::EpiphanyReorientStateStatus;
|
||||
|
|
@ -312,10 +316,12 @@ pub use surfaces::EpiphanyWorkerLaunchDocument;
|
|||
pub use surfaces::REORIENT_WORKER_OUTPUT_CONTRACT_ID;
|
||||
pub use surfaces::ROLE_WORKER_OUTPUT_CONTRACT_ID;
|
||||
pub use surfaces::build_reorient_acceptance_bundle;
|
||||
pub use surfaces::build_reorient_job_launch_request;
|
||||
pub use surfaces::build_role_acceptance_bundle;
|
||||
pub use surfaces::coordinator_automation_action;
|
||||
pub use surfaces::crrc_scene_action_to_coordinator_scene_action;
|
||||
pub use surfaces::derive_context;
|
||||
pub use surfaces::derive_coordinator_status;
|
||||
pub use surfaces::derive_freshness;
|
||||
pub use surfaces::derive_graph_query;
|
||||
pub use surfaces::derive_jobs;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
use super::EpiphanyCrrcAction;
|
||||
use super::EpiphanyCrrcSceneAction;
|
||||
use super::EpiphanyCrrcStateStatus;
|
||||
use super::EpiphanyPressure;
|
||||
use super::EpiphanyPressureLevel;
|
||||
use super::EpiphanyReorientAction;
|
||||
use super::EpiphanyRoleBoardLane;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
|
|
@ -91,6 +95,18 @@ pub struct EpiphanyCoordinatorSignals {
|
|||
pub verification_result_status: EpiphanyCoordinatorRoleResultStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpiphanyCoordinatorSourceSignals {
|
||||
pub pressure_level: EpiphanyPressureLevel,
|
||||
pub should_prepare_compaction: bool,
|
||||
pub reorient_action: EpiphanyReorientAction,
|
||||
pub crrc_action: EpiphanyCrrcAction,
|
||||
pub modeling_result_status: EpiphanyCoordinatorRoleResultStatus,
|
||||
pub verification_result_status: EpiphanyCoordinatorRoleResultStatus,
|
||||
pub reorient_result_status: super::EpiphanyCrrcResultStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpiphanyCoordinatorRoleLane {
|
||||
|
|
@ -129,6 +145,36 @@ pub struct EpiphanyCoordinatorDecision {
|
|||
pub reason: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EpiphanyCoordinatorStatusInput {
|
||||
pub state_status: EpiphanyCrrcStateStatus,
|
||||
pub checkpoint_present: bool,
|
||||
pub pressure: EpiphanyPressure,
|
||||
pub recommendation: super::EpiphanyCrrcRecommendation,
|
||||
pub roles: Vec<EpiphanyRoleBoardLane>,
|
||||
pub reorient_action: EpiphanyReorientAction,
|
||||
pub modeling_result_status: EpiphanyCoordinatorRoleResultStatus,
|
||||
pub verification_result_status: EpiphanyCoordinatorRoleResultStatus,
|
||||
pub reorient_result_status: super::EpiphanyCrrcResultStatus,
|
||||
pub modeling_result_accepted: bool,
|
||||
pub modeling_result_reviewable: bool,
|
||||
pub modeling_result_accepted_after_verification: bool,
|
||||
pub implementation_evidence_after_verification: bool,
|
||||
pub verification_result_cites_implementation_evidence: bool,
|
||||
pub verification_result_covers_current_modeling: bool,
|
||||
pub verification_result_accepted: bool,
|
||||
pub verification_result_allows_implementation: bool,
|
||||
pub verification_result_needs_evidence: bool,
|
||||
pub reorient_finding_accepted: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EpiphanyCoordinatorStatus {
|
||||
pub decision: EpiphanyCoordinatorDecision,
|
||||
pub source_signals: EpiphanyCoordinatorSourceSignals,
|
||||
pub roles: Vec<EpiphanyRoleBoardLane>,
|
||||
}
|
||||
|
||||
pub fn crrc_scene_action_to_coordinator_scene_action(
|
||||
action: EpiphanyCrrcSceneAction,
|
||||
) -> EpiphanyCoordinatorSceneAction {
|
||||
|
|
@ -141,6 +187,70 @@ pub fn crrc_scene_action_to_coordinator_scene_action(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn derive_coordinator_status(
|
||||
input: EpiphanyCoordinatorStatusInput,
|
||||
) -> EpiphanyCoordinatorStatus {
|
||||
let source_signals = EpiphanyCoordinatorSourceSignals {
|
||||
pressure_level: input.pressure.level,
|
||||
should_prepare_compaction: input.pressure.should_prepare_compaction,
|
||||
reorient_action: input.reorient_action,
|
||||
crrc_action: input.recommendation.action,
|
||||
modeling_result_status: input.modeling_result_status,
|
||||
verification_result_status: input.verification_result_status,
|
||||
reorient_result_status: input.reorient_result_status,
|
||||
};
|
||||
let coordinator_roles = input
|
||||
.roles
|
||||
.iter()
|
||||
.map(coordinator_role_lane_from_role_board)
|
||||
.collect();
|
||||
let decision = recommend_coordinator_action(EpiphanyCoordinatorInput {
|
||||
state_status: input.state_status,
|
||||
checkpoint_present: input.checkpoint_present,
|
||||
should_prepare_compaction: input.pressure.should_prepare_compaction,
|
||||
recommendation: EpiphanyCoordinatorCrrcRecommendation {
|
||||
action: input.recommendation.action,
|
||||
recommended_scene_action: input
|
||||
.recommendation
|
||||
.recommended_scene_action
|
||||
.map(crrc_scene_action_to_coordinator_scene_action),
|
||||
},
|
||||
roles: coordinator_roles,
|
||||
signals: EpiphanyCoordinatorSignals {
|
||||
modeling_result_status: input.modeling_result_status,
|
||||
verification_result_status: input.verification_result_status,
|
||||
},
|
||||
modeling_result_accepted: input.modeling_result_accepted,
|
||||
modeling_result_reviewable: input.modeling_result_reviewable,
|
||||
modeling_result_accepted_after_verification: input
|
||||
.modeling_result_accepted_after_verification,
|
||||
implementation_evidence_after_verification: input
|
||||
.implementation_evidence_after_verification,
|
||||
verification_result_cites_implementation_evidence: input
|
||||
.verification_result_cites_implementation_evidence,
|
||||
verification_result_covers_current_modeling: input
|
||||
.verification_result_covers_current_modeling,
|
||||
verification_result_accepted: input.verification_result_accepted,
|
||||
verification_result_allows_implementation: input.verification_result_allows_implementation,
|
||||
verification_result_needs_evidence: input.verification_result_needs_evidence,
|
||||
reorient_finding_accepted: input.reorient_finding_accepted,
|
||||
});
|
||||
EpiphanyCoordinatorStatus {
|
||||
decision,
|
||||
source_signals,
|
||||
roles: input.roles,
|
||||
}
|
||||
}
|
||||
|
||||
fn coordinator_role_lane_from_role_board(
|
||||
lane: &EpiphanyRoleBoardLane,
|
||||
) -> EpiphanyCoordinatorRoleLane {
|
||||
EpiphanyCoordinatorRoleLane {
|
||||
id: lane.id,
|
||||
status: lane.status,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recommend_coordinator_action(
|
||||
input: EpiphanyCoordinatorInput,
|
||||
) -> EpiphanyCoordinatorDecision {
|
||||
|
|
|
|||
|
|
@ -23,8 +23,12 @@ pub use coordinator::EpiphanyCoordinatorRoleResultStatus;
|
|||
pub use coordinator::EpiphanyCoordinatorRoleStatus;
|
||||
pub use coordinator::EpiphanyCoordinatorSceneAction;
|
||||
pub use coordinator::EpiphanyCoordinatorSignals;
|
||||
pub use coordinator::EpiphanyCoordinatorSourceSignals;
|
||||
pub use coordinator::EpiphanyCoordinatorStatus;
|
||||
pub use coordinator::EpiphanyCoordinatorStatusInput;
|
||||
pub use coordinator::coordinator_automation_action;
|
||||
pub use coordinator::crrc_scene_action_to_coordinator_scene_action;
|
||||
pub use coordinator::derive_coordinator_status;
|
||||
pub use coordinator::recommend_coordinator_action;
|
||||
pub use coordinator::select_coordinator_automation_action;
|
||||
pub use crrc::EpiphanyCrrcAction;
|
||||
|
|
@ -124,8 +128,10 @@ pub use scene::EpiphanySceneStatusCount;
|
|||
pub use scene::EpiphanySceneSubgoal;
|
||||
pub use scene::derive_scene;
|
||||
pub use state_patch::EpiphanyRoleStatePatchDocument;
|
||||
pub use worker_launch::EpiphanyReorientLaunchRequestInput;
|
||||
pub use worker_launch::EpiphanyReorientWorkerLaunchDocument;
|
||||
pub use worker_launch::EpiphanyRoleWorkerLaunchDocument;
|
||||
pub use worker_launch::EpiphanyWorkerLaunchDocument;
|
||||
pub use worker_launch::REORIENT_WORKER_OUTPUT_CONTRACT_ID;
|
||||
pub use worker_launch::ROLE_WORKER_OUTPUT_CONTRACT_ID;
|
||||
pub use worker_launch::build_reorient_job_launch_request;
|
||||
|
|
|
|||
|
|
@ -6,12 +6,23 @@ use epiphany_state_model::EpiphanyGraphFrontier;
|
|||
use epiphany_state_model::EpiphanyGraphs;
|
||||
use epiphany_state_model::EpiphanyInvariant;
|
||||
use epiphany_state_model::EpiphanyInvestigationCheckpoint;
|
||||
use epiphany_state_model::EpiphanyInvestigationDisposition;
|
||||
use epiphany_state_model::EpiphanyJobKind;
|
||||
use epiphany_state_model::EpiphanyObservation;
|
||||
use epiphany_state_model::EpiphanyPlanningState;
|
||||
use epiphany_state_model::EpiphanyScratchPad;
|
||||
use epiphany_state_model::EpiphanySubgoal;
|
||||
use epiphany_state_model::EpiphanyThreadState;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::EpiphanyJobLaunchRequest;
|
||||
use crate::EpiphanyReorientAction;
|
||||
use crate::EpiphanyReorientDecision;
|
||||
use crate::EpiphanyReorientFreshnessStatus;
|
||||
use crate::EpiphanyReorientPressureLevel;
|
||||
use crate::EpiphanyReorientReason;
|
||||
|
||||
pub const ROLE_WORKER_OUTPUT_CONTRACT_ID: &str = "epiphany.worker.role_result.v0";
|
||||
pub const REORIENT_WORKER_OUTPUT_CONTRACT_ID: &str = "epiphany.worker.reorient_result.v0";
|
||||
|
|
@ -120,3 +131,285 @@ pub struct EpiphanyReorientWorkerLaunchDocument {
|
|||
#[serde(default)]
|
||||
pub linked_graph_node_ids: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct EpiphanyReorientLaunchRequestInput<'a> {
|
||||
pub thread_id: &'a str,
|
||||
pub expected_revision: Option<u64>,
|
||||
pub max_runtime_seconds: Option<u64>,
|
||||
pub binding_id: &'a str,
|
||||
pub owner_role: &'a str,
|
||||
pub instruction: String,
|
||||
pub state: &'a EpiphanyThreadState,
|
||||
pub checkpoint: &'a EpiphanyInvestigationCheckpoint,
|
||||
pub decision: &'a EpiphanyReorientDecision,
|
||||
}
|
||||
|
||||
pub fn build_reorient_job_launch_request(
|
||||
input: EpiphanyReorientLaunchRequestInput<'_>,
|
||||
) -> EpiphanyJobLaunchRequest {
|
||||
let linked_subgoal_ids = active_subgoal_ids(input.state);
|
||||
let linked_graph_node_ids = unique_strings(
|
||||
active_graph_node_ids(input.state)
|
||||
.into_iter()
|
||||
.chain(input.decision.active_frontier_node_ids.iter().cloned()),
|
||||
);
|
||||
let launch_document =
|
||||
EpiphanyWorkerLaunchDocument::Reorient(build_reorient_worker_launch_document(
|
||||
input.thread_id,
|
||||
input.state,
|
||||
input.checkpoint,
|
||||
input.decision,
|
||||
linked_subgoal_ids.clone(),
|
||||
linked_graph_node_ids.clone(),
|
||||
));
|
||||
let output_contract_id = launch_document.output_contract_id().to_string();
|
||||
|
||||
EpiphanyJobLaunchRequest {
|
||||
expected_revision: input.expected_revision,
|
||||
binding_id: input.binding_id.to_string(),
|
||||
kind: EpiphanyJobKind::Specialist,
|
||||
scope: reorient_launch_scope(input.decision.action).to_string(),
|
||||
owner_role: input.owner_role.to_string(),
|
||||
authority_scope: reorient_launch_authority_scope(input.decision.action).to_string(),
|
||||
linked_subgoal_ids,
|
||||
linked_graph_node_ids,
|
||||
instruction: input.instruction,
|
||||
launch_document,
|
||||
output_contract_id,
|
||||
max_runtime_seconds: input.max_runtime_seconds,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_reorient_worker_launch_document(
|
||||
thread_id: &str,
|
||||
state: &EpiphanyThreadState,
|
||||
checkpoint: &EpiphanyInvestigationCheckpoint,
|
||||
decision: &EpiphanyReorientDecision,
|
||||
linked_subgoal_ids: Vec<String>,
|
||||
linked_graph_node_ids: Vec<String>,
|
||||
) -> EpiphanyReorientWorkerLaunchDocument {
|
||||
EpiphanyReorientWorkerLaunchDocument {
|
||||
thread_id: thread_id.to_string(),
|
||||
mode: reorient_action_label(decision.action).to_string(),
|
||||
checkpoint_id: checkpoint.checkpoint_id.clone(),
|
||||
checkpoint_kind: checkpoint.kind.clone(),
|
||||
checkpoint_disposition: investigation_disposition_label(checkpoint.disposition).to_string(),
|
||||
checkpoint_focus: Some(checkpoint.focus.clone()),
|
||||
checkpoint_summary: checkpoint.summary.clone(),
|
||||
checkpoint_next_action: checkpoint
|
||||
.next_action
|
||||
.clone()
|
||||
.unwrap_or_else(|| decision.next_action.clone()),
|
||||
checkpoint_open_questions: checkpoint.open_questions.clone(),
|
||||
checkpoint_evidence_ids: checkpoint.evidence_ids.clone(),
|
||||
checkpoint_code_refs: checkpoint.code_refs.clone(),
|
||||
decision_reasons: decision
|
||||
.reasons
|
||||
.iter()
|
||||
.map(|reason| reorient_reason_label(*reason).to_string())
|
||||
.collect(),
|
||||
decision_note: decision.note.clone(),
|
||||
pressure_level: reorient_pressure_level_label(decision.pressure_level).to_string(),
|
||||
retrieval_status: reorient_freshness_status_label(decision.retrieval_status).to_string(),
|
||||
graph_status: reorient_freshness_status_label(decision.graph_status).to_string(),
|
||||
watcher_status: reorient_freshness_status_label(decision.watcher_status).to_string(),
|
||||
checkpoint_dirty_paths: decision
|
||||
.checkpoint_dirty_paths
|
||||
.iter()
|
||||
.map(path_to_display_string)
|
||||
.collect(),
|
||||
checkpoint_changed_paths: decision
|
||||
.checkpoint_changed_paths
|
||||
.iter()
|
||||
.map(path_to_display_string)
|
||||
.collect(),
|
||||
scratch: state.scratch.clone(),
|
||||
graphs: Some(state.graphs.clone()),
|
||||
recent_evidence: state.recent_evidence.iter().take(8).cloned().collect(),
|
||||
recent_observations: state.observations.iter().take(8).cloned().collect(),
|
||||
active_frontier_node_ids: decision.active_frontier_node_ids.clone(),
|
||||
linked_subgoal_ids,
|
||||
linked_graph_node_ids,
|
||||
}
|
||||
}
|
||||
|
||||
fn active_subgoal_ids(state: &EpiphanyThreadState) -> Vec<String> {
|
||||
state
|
||||
.active_subgoal_id
|
||||
.clone()
|
||||
.map(|id| vec![id])
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn active_graph_node_ids(state: &EpiphanyThreadState) -> Vec<String> {
|
||||
state
|
||||
.graph_frontier
|
||||
.as_ref()
|
||||
.map(|frontier| frontier.active_node_ids.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn unique_strings(values: impl IntoIterator<Item = String>) -> Vec<String> {
|
||||
let mut unique = Vec::new();
|
||||
for value in values {
|
||||
if !unique.iter().any(|existing| existing == &value) {
|
||||
unique.push(value);
|
||||
}
|
||||
}
|
||||
unique
|
||||
}
|
||||
|
||||
fn path_to_display_string(path: impl AsRef<Path>) -> String {
|
||||
path.as_ref().to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
fn reorient_launch_authority_scope(action: EpiphanyReorientAction) -> &'static str {
|
||||
match action {
|
||||
EpiphanyReorientAction::Resume => "epiphany.reorient.resume",
|
||||
EpiphanyReorientAction::Regather => "epiphany.reorient.regather",
|
||||
}
|
||||
}
|
||||
|
||||
fn reorient_launch_scope(action: EpiphanyReorientAction) -> &'static str {
|
||||
match action {
|
||||
EpiphanyReorientAction::Resume => "reorient-guided checkpoint resume",
|
||||
EpiphanyReorientAction::Regather => "reorient-guided checkpoint regather",
|
||||
}
|
||||
}
|
||||
|
||||
fn reorient_action_label(action: EpiphanyReorientAction) -> &'static str {
|
||||
match action {
|
||||
EpiphanyReorientAction::Resume => "resume",
|
||||
EpiphanyReorientAction::Regather => "regather",
|
||||
}
|
||||
}
|
||||
|
||||
fn investigation_disposition_label(disposition: EpiphanyInvestigationDisposition) -> &'static str {
|
||||
match disposition {
|
||||
EpiphanyInvestigationDisposition::ResumeReady => "resume_ready",
|
||||
EpiphanyInvestigationDisposition::RegatherRequired => "regather_required",
|
||||
}
|
||||
}
|
||||
|
||||
fn reorient_reason_label(reason: EpiphanyReorientReason) -> &'static str {
|
||||
match reason {
|
||||
EpiphanyReorientReason::MissingState => "missingState",
|
||||
EpiphanyReorientReason::MissingCheckpoint => "missingCheckpoint",
|
||||
EpiphanyReorientReason::CheckpointRequestedRegather => "checkpointRequestedRegather",
|
||||
EpiphanyReorientReason::CheckpointPathsDirty => "checkpointPathsDirty",
|
||||
EpiphanyReorientReason::CheckpointPathsChanged => "checkpointPathsChanged",
|
||||
EpiphanyReorientReason::FrontierChanged => "frontierChanged",
|
||||
EpiphanyReorientReason::UnanchoredCheckpointWhileStateStale => {
|
||||
"unanchoredCheckpointWhileStateStale"
|
||||
}
|
||||
EpiphanyReorientReason::CheckpointReady => "checkpointReady",
|
||||
}
|
||||
}
|
||||
|
||||
fn reorient_pressure_level_label(level: EpiphanyReorientPressureLevel) -> &'static str {
|
||||
match level {
|
||||
EpiphanyReorientPressureLevel::Unknown => "unknown",
|
||||
EpiphanyReorientPressureLevel::Low => "low",
|
||||
EpiphanyReorientPressureLevel::Medium => "medium",
|
||||
EpiphanyReorientPressureLevel::High => "high",
|
||||
EpiphanyReorientPressureLevel::Critical => "critical",
|
||||
}
|
||||
}
|
||||
|
||||
fn reorient_freshness_status_label(status: EpiphanyReorientFreshnessStatus) -> &'static str {
|
||||
match status {
|
||||
EpiphanyReorientFreshnessStatus::Unknown => "unknown",
|
||||
EpiphanyReorientFreshnessStatus::Clean => "clean",
|
||||
EpiphanyReorientFreshnessStatus::Dirty => "dirty",
|
||||
EpiphanyReorientFreshnessStatus::Stale => "stale",
|
||||
EpiphanyReorientFreshnessStatus::Changed => "changed",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use epiphany_state_model::EpiphanyCodeRef;
|
||||
use epiphany_state_model::EpiphanyGraphFrontier;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn reorient_launch_request_is_composed_from_typed_state() {
|
||||
let state = EpiphanyThreadState {
|
||||
revision: 7,
|
||||
active_subgoal_id: Some("sg-1".to_string()),
|
||||
graph_frontier: Some(EpiphanyGraphFrontier {
|
||||
active_node_ids: vec!["node-a".to_string()],
|
||||
active_edge_ids: Vec::new(),
|
||||
open_question_ids: Vec::new(),
|
||||
open_gap_ids: Vec::new(),
|
||||
dirty_paths: Vec::new(),
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
let checkpoint = EpiphanyInvestigationCheckpoint {
|
||||
checkpoint_id: "ix-1".to_string(),
|
||||
kind: "implementation".to_string(),
|
||||
disposition: EpiphanyInvestigationDisposition::RegatherRequired,
|
||||
focus: "runtime seam".to_string(),
|
||||
summary: Some("resume here".to_string()),
|
||||
next_action: None,
|
||||
captured_at_turn_id: Some("turn-1".to_string()),
|
||||
open_questions: Vec::new(),
|
||||
code_refs: vec![EpiphanyCodeRef {
|
||||
path: PathBuf::from("src/lib.rs"),
|
||||
start_line: None,
|
||||
end_line: None,
|
||||
symbol: None,
|
||||
note: None,
|
||||
}],
|
||||
evidence_ids: vec!["ev-1".to_string()],
|
||||
};
|
||||
let decision = EpiphanyReorientDecision {
|
||||
action: EpiphanyReorientAction::Regather,
|
||||
checkpoint_status: crate::EpiphanyReorientCheckpointStatus::RegatherRequired,
|
||||
checkpoint_id: Some("ix-1".to_string()),
|
||||
pressure_level: EpiphanyReorientPressureLevel::High,
|
||||
retrieval_status: EpiphanyReorientFreshnessStatus::Stale,
|
||||
graph_status: EpiphanyReorientFreshnessStatus::Changed,
|
||||
watcher_status: EpiphanyReorientFreshnessStatus::Dirty,
|
||||
reasons: vec![EpiphanyReorientReason::FrontierChanged],
|
||||
checkpoint_dirty_paths: vec![PathBuf::from("src/lib.rs")],
|
||||
checkpoint_changed_paths: vec![PathBuf::from("src/main.rs")],
|
||||
active_frontier_node_ids: vec!["node-b".to_string()],
|
||||
next_action: "Regather the seam.".to_string(),
|
||||
note: "continuity moved".to_string(),
|
||||
};
|
||||
|
||||
let request = build_reorient_job_launch_request(EpiphanyReorientLaunchRequestInput {
|
||||
thread_id: "thread-1",
|
||||
expected_revision: Some(state.revision),
|
||||
max_runtime_seconds: Some(60),
|
||||
binding_id: "reorient-worker",
|
||||
owner_role: "epiphany-reorient",
|
||||
instruction: "do the reorientation".to_string(),
|
||||
state: &state,
|
||||
checkpoint: &checkpoint,
|
||||
decision: &decision,
|
||||
});
|
||||
|
||||
assert_eq!(request.binding_id, "reorient-worker");
|
||||
assert_eq!(request.scope, "reorient-guided checkpoint regather");
|
||||
assert_eq!(request.authority_scope, "epiphany.reorient.regather");
|
||||
assert_eq!(request.linked_subgoal_ids, vec!["sg-1"]);
|
||||
assert_eq!(
|
||||
request.linked_graph_node_ids,
|
||||
vec!["node-a".to_string(), "node-b".to_string()]
|
||||
);
|
||||
let EpiphanyWorkerLaunchDocument::Reorient(document) = request.launch_document else {
|
||||
panic!("expected reorient launch document");
|
||||
};
|
||||
assert_eq!(document.mode, "regather");
|
||||
assert_eq!(document.checkpoint_next_action, "Regather the seam.");
|
||||
assert_eq!(document.decision_reasons, vec!["frontierChanged"]);
|
||||
assert_eq!(document.pressure_level, "high");
|
||||
assert_eq!(document.retrieval_status, "stale");
|
||||
assert_eq!(document.graph_status, "changed");
|
||||
assert_eq!(document.watcher_status, "dirty");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ remembers doctrine; the branch remembers the blade.
|
|||
- View-lens orchestration now uses bridge-native `EpiphanyViewLens` selectors. App-server converts `ThreadEpiphanyViewLens` at the request wall, and the bridge maps back only for the legacy response echo.
|
||||
- Coordinator status derivation now receives core `EpiphanyCrrcResultStatus` for reorient result state; `ThreadEpiphanyReorientResultStatus` is projection-only for coordinator/view responses.
|
||||
- Coordinator view response assembly now receives core reorient state and role-board status; `ThreadEpiphanyReorientStateStatus` / `ThreadEpiphanyRoleLane` are projected inside the response builder.
|
||||
- Coordinator judgment is no longer bridge-owned. `epiphany-core` now exposes `EpiphanyCoordinatorStatusInput` -> `EpiphanyCoordinatorStatus`; the bridge gathers runtime snapshots and accepted-finding facts, then core derives source signals and the coordinator decision. Reorient worker launch composition is also core-owned through `EpiphanyReorientLaunchRequestInput` -> `EpiphanyJobLaunchRequest`; bridge supplies the prompt instruction plus retained compatibility binding/owner constants and performs the host launch side effect.
|
||||
- MCP remains JSON because MCP is a JSON protocol. The latest processor cut only moved MCP refresh/OAuth/status/resource/tool-call route handling into `codex_message_processor/mcp_routes.rs`, reducing the root processor to about 8,977 lines; it did not claim MCP payloads are CultNet or make MCP an Epiphany-owned runtime contract.
|
||||
- Codex account auth route handling remains in vendored Codex but now lives in `codex_message_processor/auth_routes.rs`: API-key login, ChatGPT browser/device-code/external-token login, logout, auth status, account, rate limits, and add-credits nudge handling. This preserves Codex ownership of subscription auth while cutting the root processor to about 8,094 lines.
|
||||
- One-off command execution and command stream write/resize/terminate route handling now live in `codex_message_processor/command_routes.rs`; `CommandExecManager` remains the lifecycle owner, while the root processor is about 7,800 lines.
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -371,7 +371,15 @@ current_status:
|
|||
result state instead of protocol `ThreadEpiphanyReorientResultStatus`.
|
||||
Coordinator view response assembly now receives core reorient state and
|
||||
role-board status, projecting `ThreadEpiphanyReorientStateStatus` /
|
||||
`ThreadEpiphanyRoleLane` only while building the legacy response.
|
||||
`ThreadEpiphanyRoleLane` only while building the legacy response. The next
|
||||
rude cut landed: coordinator status derivation is a typed `epiphany-core`
|
||||
seam (`EpiphanyCoordinatorStatusInput` -> `EpiphanyCoordinatorStatus`), so
|
||||
bridge code gathers runtime/acceptance facts but no longer owns the
|
||||
coordinator decision assembly. Reorient worker launch-request/document
|
||||
composition also moved behind a typed core seam
|
||||
(`EpiphanyReorientLaunchRequestInput` -> `EpiphanyJobLaunchRequest`);
|
||||
bridge supplies only the prompt instruction and retained compatibility
|
||||
binding/owner constants before performing host side effects.
|
||||
The bridge still depends on vendored Codex for app-server protocol DTOs and
|
||||
absolute path validation, so the purification is not done.
|
||||
next_action: Continue Codex starvation and CultNet liberation by cutting bridge-internal `ThreadEpiphany*` authority. Prioritize role-result/reorient-result DTO coupling next: derive typed CultNet surfaces first, push JSON-RPC projection into app-server, and keep MCP/OpenAI JSON only at their true protocol/text edges. Do not add compatibility adapters unless they protect a named ownership invariant.
|
||||
|
|
|
|||
Reference in a new issue