Keep coordinator decisions core-shaped

This commit is contained in:
Meta Vens 2026-05-19 21:51:42 +01:00
commit c45cd1bf46
7 changed files with 216 additions and 152 deletions

View file

@ -38,6 +38,7 @@ use epiphany_core::EpiphanyCrrcResultStatus as CoreEpiphanyCrrcResultStatus;
use epiphany_core::EpiphanyCrrcSceneAction as CoreEpiphanyCrrcSceneAction;
use epiphany_core::EpiphanyCrrcStateStatus as CoreEpiphanyCrrcStateStatus;
use epiphany_core::EpiphanyJobLaunchRequest;
use epiphany_core::EpiphanyReorientAction as CoreEpiphanyReorientAction;
use epiphany_core::EpiphanyRoleBoardCheckpointSummary;
use epiphany_core::EpiphanyRoleBoardInput;
use epiphany_core::EpiphanyRoleBoardJob;
@ -80,7 +81,7 @@ use std::path::Path;
pub fn map_epiphany_crrc_recommendation(
loaded: bool,
state_status: ThreadEpiphanyReorientStateStatus,
pressure: &ThreadEpiphanyPressure,
pressure: &epiphany_core::EpiphanyPressure,
decision: &ThreadEpiphanyReorientDecision,
result_status: ThreadEpiphanyReorientResultStatus,
checkpoint_present: bool,
@ -117,6 +118,15 @@ fn map_core_crrc_reorient_action(
}
}
fn map_core_reorient_action_from_protocol(
action: ThreadEpiphanyReorientAction,
) -> CoreEpiphanyReorientAction {
match action {
ThreadEpiphanyReorientAction::Resume => CoreEpiphanyReorientAction::Resume,
ThreadEpiphanyReorientAction::Regather => CoreEpiphanyReorientAction::Regather,
}
}
fn map_core_crrc_result_status(
status: ThreadEpiphanyReorientResultStatus,
) -> CoreEpiphanyCrrcResultStatus {
@ -141,6 +151,79 @@ fn map_core_crrc_result_status(
}
}
fn map_protocol_coordinator_source_signals(
signals: EpiphanyCoordinatorSourceSignals,
) -> ThreadEpiphanyCoordinatorSignals {
ThreadEpiphanyCoordinatorSignals {
pressure_level: map_protocol_pressure_level(signals.pressure_level),
should_prepare_compaction: signals.should_prepare_compaction,
reorient_action: map_protocol_reorient_action(signals.reorient_action),
crrc_action: map_core_crrc_action(signals.crrc_action),
modeling_result_status: map_protocol_coordinator_role_result_status(
signals.modeling_result_status,
),
verification_result_status: map_protocol_coordinator_role_result_status(
signals.verification_result_status,
),
reorient_result_status: map_protocol_crrc_result_status(signals.reorient_result_status),
}
}
fn map_protocol_pressure_level(
level: epiphany_core::EpiphanyPressureLevel,
) -> codex_app_server_protocol::ThreadEpiphanyPressureLevel {
match level {
epiphany_core::EpiphanyPressureLevel::Unknown => {
codex_app_server_protocol::ThreadEpiphanyPressureLevel::Unknown
}
epiphany_core::EpiphanyPressureLevel::Low => {
codex_app_server_protocol::ThreadEpiphanyPressureLevel::Low
}
epiphany_core::EpiphanyPressureLevel::Elevated => {
codex_app_server_protocol::ThreadEpiphanyPressureLevel::Elevated
}
epiphany_core::EpiphanyPressureLevel::High => {
codex_app_server_protocol::ThreadEpiphanyPressureLevel::High
}
epiphany_core::EpiphanyPressureLevel::Critical => {
codex_app_server_protocol::ThreadEpiphanyPressureLevel::Critical
}
}
}
fn map_protocol_reorient_action(
action: CoreEpiphanyReorientAction,
) -> ThreadEpiphanyReorientAction {
match action {
CoreEpiphanyReorientAction::Resume => ThreadEpiphanyReorientAction::Resume,
CoreEpiphanyReorientAction::Regather => ThreadEpiphanyReorientAction::Regather,
}
}
fn map_protocol_crrc_result_status(
status: CoreEpiphanyCrrcResultStatus,
) -> ThreadEpiphanyReorientResultStatus {
match status {
CoreEpiphanyCrrcResultStatus::MissingState => {
ThreadEpiphanyReorientResultStatus::MissingState
}
CoreEpiphanyCrrcResultStatus::MissingBinding => {
ThreadEpiphanyReorientResultStatus::MissingBinding
}
CoreEpiphanyCrrcResultStatus::BackendUnavailable => {
ThreadEpiphanyReorientResultStatus::BackendUnavailable
}
CoreEpiphanyCrrcResultStatus::BackendMissing => {
ThreadEpiphanyReorientResultStatus::BackendMissing
}
CoreEpiphanyCrrcResultStatus::Pending => ThreadEpiphanyReorientResultStatus::Pending,
CoreEpiphanyCrrcResultStatus::Running => ThreadEpiphanyReorientResultStatus::Running,
CoreEpiphanyCrrcResultStatus::Completed => ThreadEpiphanyReorientResultStatus::Completed,
CoreEpiphanyCrrcResultStatus::Failed => ThreadEpiphanyReorientResultStatus::Failed,
CoreEpiphanyCrrcResultStatus::Cancelled => ThreadEpiphanyReorientResultStatus::Cancelled,
}
}
fn map_core_crrc_action(action: CoreEpiphanyCrrcAction) -> ThreadEpiphanyCrrcAction {
match action {
CoreEpiphanyCrrcAction::Continue => ThreadEpiphanyCrrcAction::Continue,
@ -183,18 +266,21 @@ fn map_core_crrc_recommendation(
}
}
pub struct EpiphanyCoordinatorDecision {
pub action: ThreadEpiphanyCoordinatorAction,
pub target_role: Option<ThreadEpiphanyRoleId>,
pub recommended_scene_action: Option<ThreadEpiphanySceneAction>,
pub requires_review: bool,
pub can_auto_run: bool,
pub reason: String,
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: ThreadEpiphanyCoordinatorSignals,
pub source_signals: EpiphanyCoordinatorSourceSignals,
pub roles: Vec<ThreadEpiphanyRoleLane>,
pub note: String,
pub modeling_result_accepted: bool,
@ -206,7 +292,7 @@ pub async fn derive_epiphany_coordinator_status(
state: Option<&EpiphanyThreadState>,
runtime_store_path: Option<&Path>,
state_status: ThreadEpiphanyReorientStateStatus,
pressure: &ThreadEpiphanyPressure,
pressure: &epiphany_core::EpiphanyPressure,
recommendation: &ThreadEpiphanyCrrcRecommendation,
roles: Vec<ThreadEpiphanyRoleLane>,
reorient_decision: Option<&ThreadEpiphanyReorientDecision>,
@ -285,16 +371,19 @@ 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 = ThreadEpiphanyCoordinatorSignals {
let source_signals = EpiphanyCoordinatorSourceSignals {
pressure_level: pressure.level,
should_prepare_compaction: pressure.should_prepare_compaction,
reorient_action: reorient_decision
.map(|decision| decision.action)
.unwrap_or(ThreadEpiphanyReorientAction::Resume),
crrc_action: recommendation.action,
modeling_result_status,
verification_result_status,
reorient_result_status,
.map(map_core_reorient_action_from_protocol)
.unwrap_or(CoreEpiphanyReorientAction::Resume),
crrc_action: map_core_crrc_action_from_protocol(recommendation.action),
modeling_result_status: map_core_coordinator_role_result_status(modeling_result_status),
verification_result_status: map_core_coordinator_role_result_status(
verification_result_status,
),
reorient_result_status: map_core_crrc_result_status(reorient_result_status),
};
let decision = map_epiphany_coordinator(
state_status,
@ -316,11 +405,11 @@ pub async fn derive_epiphany_coordinator_status(
);
let note = render_epiphany_coordinator_note(
recommendation.action,
pressure.level,
map_protocol_pressure_level(pressure.level),
modeling_result_status,
verification_result_status,
reorient_result_status,
decision.action,
map_protocol_coordinator_action(decision.action),
);
EpiphanyCoordinatorStatus {
@ -350,13 +439,19 @@ pub fn map_epiphany_coordinator_view(
},
state_status,
state_revision,
action: status.decision.action,
target_role: status.decision.target_role,
recommended_scene_action: status.decision.recommended_scene_action,
action: map_protocol_coordinator_action(status.decision.action),
target_role: status
.decision
.target_role
.map(map_protocol_coordinator_role_id),
recommended_scene_action: status
.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: status.source_signals,
source_signals: map_protocol_coordinator_source_signals(status.source_signals),
roles: status.roles,
note: status.note,
}
@ -372,9 +467,7 @@ pub enum EpiphanyCoordinatorAutomationAction {
pub fn map_epiphany_coordinator_automation_action(
decision: &EpiphanyCoordinatorDecision,
) -> EpiphanyCoordinatorAutomationAction {
map_protocol_coordinator_automation_action(coordinator_automation_action(
&map_core_coordinator_decision_from_protocol(decision),
))
map_protocol_coordinator_automation_action(coordinator_automation_action(decision))
}
pub fn select_epiphany_coordinator_automation_action(
@ -382,7 +475,7 @@ pub fn select_epiphany_coordinator_automation_action(
force_checkpoint_compaction: bool,
) -> EpiphanyCoordinatorAutomationAction {
map_protocol_coordinator_automation_action(select_coordinator_automation_action(
&map_core_coordinator_decision_from_protocol(decision),
decision,
force_checkpoint_compaction,
))
}
@ -450,7 +543,7 @@ pub async fn select_epiphany_coordinator_automation(
let crrc_recommendation = map_epiphany_crrc_recommendation(
true,
state_status,
&pressure,
&core_pressure,
&reorient_decision,
reorient_result_status,
input.state.investigation_checkpoint.as_ref().is_some(),
@ -470,7 +563,7 @@ pub async fn select_epiphany_coordinator_automation(
Some(input.state),
Some(input.runtime_store_path),
state_status,
&pressure,
&core_pressure,
&crrc_recommendation,
roles,
Some(&reorient_decision),
@ -521,10 +614,10 @@ pub async fn select_epiphany_coordinator_automation(
pub fn map_epiphany_coordinator(
state_status: ThreadEpiphanyReorientStateStatus,
checkpoint_present: bool,
pressure: &ThreadEpiphanyPressure,
pressure: &epiphany_core::EpiphanyPressure,
recommendation: &ThreadEpiphanyCrrcRecommendation,
roles: &[ThreadEpiphanyRoleLane],
signals: &ThreadEpiphanyCoordinatorSignals,
signals: &EpiphanyCoordinatorSourceSignals,
modeling_result_accepted: bool,
modeling_result_reviewable: bool,
modeling_result_accepted_after_verification: bool,
@ -536,19 +629,15 @@ pub fn map_epiphany_coordinator(
verification_result_needs_evidence: bool,
reorient_finding_accepted: bool,
) -> EpiphanyCoordinatorDecision {
map_core_coordinator_decision(recommend_coordinator_action(EpiphanyCoordinatorInput {
recommend_coordinator_action(EpiphanyCoordinatorInput {
state_status: map_core_crrc_state_status(state_status),
checkpoint_present,
should_prepare_compaction: pressure.should_prepare_compaction,
recommendation: map_core_coordinator_crrc_recommendation(recommendation),
roles: roles.iter().map(map_core_coordinator_role_lane).collect(),
signals: EpiphanyCoordinatorSignals {
modeling_result_status: map_core_coordinator_role_result_status(
signals.modeling_result_status,
),
verification_result_status: map_core_coordinator_role_result_status(
signals.verification_result_status,
),
modeling_result_status: signals.modeling_result_status,
verification_result_status: signals.verification_result_status,
},
modeling_result_accepted,
modeling_result_reviewable,
@ -560,7 +649,7 @@ pub fn map_epiphany_coordinator(
verification_result_allows_implementation,
verification_result_needs_evidence,
reorient_finding_accepted,
}))
})
}
fn map_core_coordinator_crrc_recommendation(
@ -625,12 +714,6 @@ fn map_protocol_coordinator_role_id(
}
}
fn map_core_coordinator_role_id_from_protocol(
role_id: ThreadEpiphanyRoleId,
) -> CoreEpiphanyCoordinatorRoleId {
map_core_coordinator_role_id(role_id)
}
fn map_core_coordinator_role_status(
status: ThreadEpiphanyRoleStatus,
) -> CoreEpiphanyCoordinatorRoleStatus {
@ -674,6 +757,34 @@ fn map_core_coordinator_role_result_status(
}
}
fn map_protocol_coordinator_role_result_status(
status: CoreEpiphanyCoordinatorRoleResultStatus,
) -> ThreadEpiphanyRoleResultStatus {
match status {
CoreEpiphanyCoordinatorRoleResultStatus::MissingState => {
ThreadEpiphanyRoleResultStatus::MissingState
}
CoreEpiphanyCoordinatorRoleResultStatus::MissingBinding => {
ThreadEpiphanyRoleResultStatus::MissingBinding
}
CoreEpiphanyCoordinatorRoleResultStatus::BackendUnavailable => {
ThreadEpiphanyRoleResultStatus::BackendUnavailable
}
CoreEpiphanyCoordinatorRoleResultStatus::BackendMissing => {
ThreadEpiphanyRoleResultStatus::BackendMissing
}
CoreEpiphanyCoordinatorRoleResultStatus::Pending => ThreadEpiphanyRoleResultStatus::Pending,
CoreEpiphanyCoordinatorRoleResultStatus::Running => ThreadEpiphanyRoleResultStatus::Running,
CoreEpiphanyCoordinatorRoleResultStatus::Completed => {
ThreadEpiphanyRoleResultStatus::Completed
}
CoreEpiphanyCoordinatorRoleResultStatus::Failed => ThreadEpiphanyRoleResultStatus::Failed,
CoreEpiphanyCoordinatorRoleResultStatus::Cancelled => {
ThreadEpiphanyRoleResultStatus::Cancelled
}
}
}
fn map_core_coordinator_scene_action_from_protocol(
action: ThreadEpiphanySceneAction,
) -> CoreEpiphanyCoordinatorSceneAction {
@ -733,46 +844,6 @@ fn map_protocol_coordinator_scene_action(
}
}
fn map_core_coordinator_action_from_protocol(
action: ThreadEpiphanyCoordinatorAction,
) -> CoreEpiphanyCoordinatorAction {
match action {
ThreadEpiphanyCoordinatorAction::PrepareCheckpoint => {
CoreEpiphanyCoordinatorAction::PrepareCheckpoint
}
ThreadEpiphanyCoordinatorAction::CompactRehydrateReorient => {
CoreEpiphanyCoordinatorAction::CompactRehydrateReorient
}
ThreadEpiphanyCoordinatorAction::LaunchReorientWorker => {
CoreEpiphanyCoordinatorAction::LaunchReorientWorker
}
ThreadEpiphanyCoordinatorAction::WaitForReorientWorker => {
CoreEpiphanyCoordinatorAction::WaitForReorientWorker
}
ThreadEpiphanyCoordinatorAction::ReviewReorientResult => {
CoreEpiphanyCoordinatorAction::ReviewReorientResult
}
ThreadEpiphanyCoordinatorAction::RegatherManually => {
CoreEpiphanyCoordinatorAction::RegatherManually
}
ThreadEpiphanyCoordinatorAction::LaunchModeling => {
CoreEpiphanyCoordinatorAction::LaunchModeling
}
ThreadEpiphanyCoordinatorAction::ReviewModelingResult => {
CoreEpiphanyCoordinatorAction::ReviewModelingResult
}
ThreadEpiphanyCoordinatorAction::LaunchVerification => {
CoreEpiphanyCoordinatorAction::LaunchVerification
}
ThreadEpiphanyCoordinatorAction::ReviewVerificationResult => {
CoreEpiphanyCoordinatorAction::ReviewVerificationResult
}
ThreadEpiphanyCoordinatorAction::ContinueImplementation => {
CoreEpiphanyCoordinatorAction::ContinueImplementation
}
}
}
fn map_protocol_coordinator_action(
action: CoreEpiphanyCoordinatorAction,
) -> ThreadEpiphanyCoordinatorAction {
@ -813,38 +884,6 @@ fn map_protocol_coordinator_action(
}
}
fn map_core_coordinator_decision_from_protocol(
decision: &EpiphanyCoordinatorDecision,
) -> CoreEpiphanyCoordinatorDecision {
CoreEpiphanyCoordinatorDecision {
action: map_core_coordinator_action_from_protocol(decision.action),
target_role: decision
.target_role
.map(map_core_coordinator_role_id_from_protocol),
recommended_scene_action: decision
.recommended_scene_action
.map(map_core_coordinator_scene_action_from_protocol),
requires_review: decision.requires_review,
can_auto_run: decision.can_auto_run,
reason: decision.reason.clone(),
}
}
fn map_core_coordinator_decision(
decision: CoreEpiphanyCoordinatorDecision,
) -> EpiphanyCoordinatorDecision {
EpiphanyCoordinatorDecision {
action: map_protocol_coordinator_action(decision.action),
target_role: decision.target_role.map(map_protocol_coordinator_role_id),
recommended_scene_action: decision
.recommended_scene_action
.map(map_protocol_coordinator_scene_action),
requires_review: decision.requires_review,
can_auto_run: decision.can_auto_run,
reason: decision.reason,
}
}
fn map_protocol_coordinator_automation_action(
action: CoreEpiphanyCoordinatorAutomationAction,
) -> EpiphanyCoordinatorAutomationAction {

View file

@ -228,21 +228,22 @@ pub async fn map_epiphany_view_response(
let reorient_finding_accepted = reorient_finding.as_ref().is_some_and(|finding| {
state.is_some_and(|state| epiphany_reorient_finding_already_accepted(state, finding))
});
let recommendation =
if let (Some(pressure), Some(decision)) = (pressure.as_ref(), reorient_decision.as_ref()) {
Some(map_epiphany_crrc_recommendation(
loaded,
reorient_state_status,
pressure,
decision,
reorient_result_status,
checkpoint_present,
reorient_finding.is_some(),
reorient_finding_accepted,
))
} else {
None
};
let recommendation = if let (Some(core_pressure), Some(decision)) =
(core_pressure.as_ref(), reorient_decision.as_ref())
{
Some(map_epiphany_crrc_recommendation(
loaded,
reorient_state_status,
core_pressure,
decision,
reorient_result_status,
checkpoint_present,
reorient_finding.is_some(),
reorient_finding_accepted,
))
} else {
None
};
let roles = if let (Some(pressure), Some(decision), Some(recommendation)) = (
pressure.as_ref(),
reorient_decision.as_ref(),
@ -261,14 +262,16 @@ pub async fn map_epiphany_view_response(
None
};
let coordinator_response = if lenses.contains(&ThreadEpiphanyViewLens::Coordinator) {
if let (Some(pressure), Some(recommendation), Some(roles)) =
(pressure.as_ref(), recommendation.as_ref(), roles.clone())
{
if let (Some(core_pressure), Some(recommendation), Some(roles)) = (
core_pressure.as_ref(),
recommendation.as_ref(),
roles.clone(),
) {
let status = derive_epiphany_coordinator_status(
state,
runtime_store_path,
reorient_state_status,
pressure,
core_pressure,
recommendation,
roles,
reorient_decision.as_ref(),

View file

@ -1,8 +1,11 @@
use super::EpiphanyCrrcAction;
use super::EpiphanyCrrcSceneAction;
use super::EpiphanyCrrcStateStatus;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCoordinatorRoleId {
Implementation,
Imagination,
@ -11,7 +14,8 @@ pub enum EpiphanyCoordinatorRoleId {
Reorientation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCoordinatorRoleStatus {
Ready,
Needed,
@ -23,7 +27,8 @@ pub enum EpiphanyCoordinatorRoleStatus {
Completed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCoordinatorRoleResultStatus {
MissingState,
MissingBinding,
@ -36,7 +41,8 @@ pub enum EpiphanyCoordinatorRoleResultStatus {
Cancelled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCoordinatorAction {
PrepareCheckpoint,
CompactRehydrateReorient,
@ -51,7 +57,8 @@ pub enum EpiphanyCoordinatorAction {
ContinueImplementation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCoordinatorSceneAction {
Update,
Reorient,
@ -62,26 +69,30 @@ pub enum EpiphanyCoordinatorSceneAction {
RoleResult,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCoordinatorAutomationAction {
None,
CompactRehydrateReorient,
LaunchReorientWorker,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EpiphanyCoordinatorCrrcRecommendation {
pub action: EpiphanyCrrcAction,
pub recommended_scene_action: Option<EpiphanyCoordinatorSceneAction>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EpiphanyCoordinatorSignals {
pub modeling_result_status: EpiphanyCoordinatorRoleResultStatus,
pub verification_result_status: EpiphanyCoordinatorRoleResultStatus,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EpiphanyCoordinatorRoleLane {
pub id: EpiphanyCoordinatorRoleId,
pub status: EpiphanyCoordinatorRoleStatus,
@ -107,7 +118,8 @@ pub struct EpiphanyCoordinatorInput {
pub reorient_finding_accepted: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EpiphanyCoordinatorDecision {
pub action: EpiphanyCoordinatorAction,
pub target_role: Option<EpiphanyCoordinatorRoleId>,

View file

@ -1,16 +1,22 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCrrcStateStatus {
Missing,
Ready,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCrrcReorientAction {
Resume,
Regather,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCrrcResultStatus {
MissingState,
MissingBinding,
@ -23,7 +29,8 @@ pub enum EpiphanyCrrcResultStatus {
Cancelled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCrrcAction {
Continue,
PrepareCheckpoint,
@ -34,7 +41,8 @@ pub enum EpiphanyCrrcAction {
RegatherManually,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum EpiphanyCrrcSceneAction {
Update,
Reorient,
@ -43,7 +51,8 @@ pub enum EpiphanyCrrcSceneAction {
ReorientAccept,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EpiphanyCrrcRecommendation {
pub action: EpiphanyCrrcAction,
pub recommended_scene_action: Option<EpiphanyCrrcSceneAction>,

View file

@ -48,6 +48,7 @@ remembers doctrine; the branch remembers the blade.
- `epiphany-codex-bridge` no longer depends on vendored `codex-core` at all. Retrieval takes workspace/Codex-home paths, invalidation owns a native `notify` watcher, runtime-result acceptance takes typed state plus runtime-store path, live rollout/thread reads moved into app-server `epiphany_thread_host`, and mutation policy depends on the small `EpiphanyMutationHost` trait implemented by app-server's `EpiphanyCodexThreadHost` wrapper. The bridge owns Epiphany law; vendored app-server owns CodexThread access.
- `epiphany-codex-bridge` also no longer depends on `codex-protocol`. Bridge durable-state imports point at `epiphany-state-model`, token pressure takes native `EpiphanyTokenUsageSnapshot`, app-server maps Codex token telemetry at the host wall, Codex token usage rollout replay lives in `codex_message_processor/token_usage_replay.rs`, and bridge errors are `EpiphanyBridgeError`. The only remaining vendored bridge dependencies are app-server protocol DTOs and absolute path validation.
- The first bridge JSON-RPC starvation cuts are landed. Freshness now returns a serializable `EpiphanyFreshnessSurface`, job launch/interrupt mutation results carry typed `EpiphanyJobView` plus separate host-edge launcher/backend ids, reorient/pre-compaction decisions consume typed `EpiphanyPressure`, reorient policy consumes typed freshness directly, and reorient launch documents/results use typed core reorient decisions/status before app-server projects them into legacy JSON-RPC DTOs. Continue by cutting the full view/coordinator board into typed surfaces, not by inventing adapters with nicer uniforms.
- Coordinator decision/status is less contaminated now: `epiphany-codex-bridge` stores coordinator decisions and source signals as core-shaped types, core CRRC/coordinator surfaces serialize natively, and `ThreadEpiphany*` projection happens at the legacy view emission boundary. Keep cutting remaining role-board/result/reorient inputs until Aquarium/CultNet can read coordinator surfaces without JSON-RPC DTO authority.
- 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.

View file

@ -134,7 +134,7 @@ accepted_design:
- The `reorient` view lens derives a bounded read-only `resume` versus `regather` verdict from checkpoint, freshness, watcher, and pressure signals without mutating state, compacting, scheduling, or silently continuing work.
- The `crrc` view lens composes pressure, the reorientation verdict, fixed reorient-worker binding/result status, finding read-back, and available actions into one read-only recommendation without launching, accepting, compacting, scheduling, or mutating state.
- A narrow auditable coordinator is central to the MVP because implementation, modeling/checkpoint, verification/review, and CRRC automation feed each other's machine-signals. CRRC itself is harness workflow automation, not a specialist-agent soul: it watches pressure/continuity, ensures persistence, triggers compaction/rehydration/reorientation when needed, and may launch a bounded reorient-worker specialist when semantic regathering is required.
- The `coordinator` view lens is the harness-native fixed-lane coordinator surface: it composes roles, pressure, reorient, CRRC, roleResult, and reorientResult into a read-only action recommendation with target role, source signals, review requirements, automation eligibility, reason, and current lane summaries without mutating state or launching work.
- The `coordinator` view lens is the harness-native fixed-lane coordinator surface: it composes roles, pressure, reorient, CRRC, roleResult, and reorientResult into a read-only action recommendation with target role, source signals, review requirements, automation eligibility, reason, and current lane summaries without mutating state or launching work. Coordinator decision and source-signal authority now stays core-shaped inside `epiphany-codex-bridge`; `ThreadEpiphany*` projection is a legacy app-server emission step, not the internal decision model.
- Coordinator implementation clearance is stricter than review acceptance: an accepted verification/review finding only opens the implementation gate when its verdict is `pass`; accepted `needs-evidence`, `needs-review`, or `fail` findings send the loop back toward modeling/checkpoint strengthening or reorientation instead of blessing a sick machine.
- Coordinator regather handling is now fixed-lane first, not supervisor improvisation: `regatherManually` is a fallback only after reorient/modeling/verification review and launch lanes cannot advance the state, completed modeling findings must be reviewed before verification, and the CLI coordinator's explicit test-only `--auto-review` mode may accept modeling state patches before launching verification while production semantics remain review-gated.
- Native `epiphany-mvp-coordinator` is the first auditable coordinator runner: it drives the fixed single-user lanes through app-server APIs, opens a native runtime-spine session, records native runtime job/result receipts for launched specialists and reorient workers when terminal results arrive, keeps semantic findings review-gated by default, and writes coordinator summaries, JSONL steps, rendered snapshots, transcript, stderr, runtime-spine status, and final next-action artifacts. It refuses direct backend-completion mutation; full specialist completion smoke must use live workers while the execution path is cauterized into CultNet.