Keep reorient decisions core-shaped

This commit is contained in:
Meta Vens 2026-05-19 22:11:58 +01:00
commit 12eac8e190
6 changed files with 60 additions and 84 deletions

View file

@ -7,7 +7,6 @@ use codex_app_server_protocol::ThreadEpiphanyJobKind;
use codex_app_server_protocol::ThreadEpiphanyJobStatus;
use codex_app_server_protocol::ThreadEpiphanyPressure;
use codex_app_server_protocol::ThreadEpiphanyReorientAction;
use codex_app_server_protocol::ThreadEpiphanyReorientDecision;
use codex_app_server_protocol::ThreadEpiphanyReorientFinding;
use codex_app_server_protocol::ThreadEpiphanyReorientResultStatus;
use codex_app_server_protocol::ThreadEpiphanyReorientStateStatus;
@ -39,6 +38,8 @@ 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::EpiphanyReorientDecision as CoreEpiphanyReorientDecision;
use epiphany_core::EpiphanyReorientStateStatus as CoreEpiphanyReorientStateStatus;
use epiphany_core::EpiphanyRoleBoardCheckpointSummary;
use epiphany_core::EpiphanyRoleBoardInput;
use epiphany_core::EpiphanyRoleBoardJob;
@ -71,7 +72,6 @@ use crate::pressure::map_epiphany_pressure;
use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
use crate::reorient::derive_epiphany_freshness_view;
use crate::reorient::derive_epiphany_reorient;
use crate::reorient::map_epiphany_reorient;
use crate::runtime_results::load_epiphany_reorient_result_snapshot;
use crate::runtime_results::load_epiphany_role_result_snapshot;
@ -80,54 +80,45 @@ use std::path::Path;
pub fn map_epiphany_crrc_recommendation(
loaded: bool,
state_status: ThreadEpiphanyReorientStateStatus,
state_status: CoreEpiphanyReorientStateStatus,
pressure: &epiphany_core::EpiphanyPressure,
decision: &ThreadEpiphanyReorientDecision,
result_status: ThreadEpiphanyReorientResultStatus,
decision: &CoreEpiphanyReorientDecision,
result_status: CoreEpiphanyCrrcResultStatus,
checkpoint_present: bool,
finding_present: bool,
finding_accepted: bool,
) -> CoreEpiphanyCrrcRecommendation {
recommend_crrc_action(EpiphanyCrrcInput {
loaded,
state_status: map_core_crrc_state_status(state_status),
state_status: map_core_crrc_state_status_from_reorient(state_status),
should_prepare_compaction: pressure.should_prepare_compaction,
reorient_action: map_core_crrc_reorient_action(decision.action),
result_status: map_core_crrc_result_status(result_status),
result_status,
checkpoint_present,
finding_present,
finding_accepted,
})
}
fn map_core_crrc_state_status(
status: ThreadEpiphanyReorientStateStatus,
fn map_core_crrc_state_status_from_reorient(
status: CoreEpiphanyReorientStateStatus,
) -> CoreEpiphanyCrrcStateStatus {
match status {
ThreadEpiphanyReorientStateStatus::Missing => CoreEpiphanyCrrcStateStatus::Missing,
ThreadEpiphanyReorientStateStatus::Ready => CoreEpiphanyCrrcStateStatus::Ready,
CoreEpiphanyReorientStateStatus::Missing => CoreEpiphanyCrrcStateStatus::Missing,
CoreEpiphanyReorientStateStatus::Ready => CoreEpiphanyCrrcStateStatus::Ready,
}
}
fn map_core_crrc_reorient_action(
action: ThreadEpiphanyReorientAction,
action: CoreEpiphanyReorientAction,
) -> CoreEpiphanyCrrcReorientAction {
match action {
ThreadEpiphanyReorientAction::Resume => CoreEpiphanyCrrcReorientAction::Resume,
ThreadEpiphanyReorientAction::Regather => CoreEpiphanyCrrcReorientAction::Regather,
CoreEpiphanyReorientAction::Resume => CoreEpiphanyCrrcReorientAction::Resume,
CoreEpiphanyReorientAction::Regather => CoreEpiphanyCrrcReorientAction::Regather,
}
}
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(
pub fn map_core_crrc_result_status(
status: ThreadEpiphanyReorientResultStatus,
) -> CoreEpiphanyCrrcResultStatus {
match status {
@ -291,11 +282,11 @@ pub struct EpiphanyCoordinatorStatus {
pub async fn derive_epiphany_coordinator_status(
state: Option<&EpiphanyThreadState>,
runtime_store_path: Option<&Path>,
state_status: ThreadEpiphanyReorientStateStatus,
state_status: CoreEpiphanyReorientStateStatus,
pressure: &epiphany_core::EpiphanyPressure,
recommendation: &CoreEpiphanyCrrcRecommendation,
roles: Vec<EpiphanyRoleBoardLane>,
reorient_decision: Option<&ThreadEpiphanyReorientDecision>,
reorient_decision: Option<&CoreEpiphanyReorientDecision>,
reorient_result_status: ThreadEpiphanyReorientResultStatus,
reorient_finding: Option<&ThreadEpiphanyReorientFinding>,
checkpoint_present: bool,
@ -376,7 +367,6 @@ pub async fn derive_epiphany_coordinator_status(
should_prepare_compaction: pressure.should_prepare_compaction,
reorient_action: reorient_decision
.map(|decision| decision.action)
.map(map_core_reorient_action_from_protocol)
.unwrap_or(CoreEpiphanyReorientAction::Resume),
crrc_action: recommendation.action,
modeling_result_status: map_core_coordinator_role_result_status(modeling_result_status),
@ -506,21 +496,14 @@ pub async fn select_epiphany_coordinator_automation(
);
let core_pressure = derive_epiphany_pressure(input.token_usage_info);
let pressure = map_epiphany_pressure(input.token_usage_info);
let (state_status, reorient_decision) = map_epiphany_reorient(
let (state_status, reorient_decision) = derive_epiphany_reorient(
Some(input.state),
&core_pressure,
&core_freshness.retrieval,
&core_freshness.graph,
&core_freshness.watcher,
);
let (_core_state_status, core_reorient_decision) = derive_epiphany_reorient(
Some(input.state),
&core_pressure,
&core_freshness.retrieval,
&core_freshness.graph,
&core_freshness.watcher,
);
if state_status != ThreadEpiphanyReorientStateStatus::Ready {
if state_status != CoreEpiphanyReorientStateStatus::Ready {
return EpiphanyCoordinatorAutomationVerdict {
action: EpiphanyCoordinatorAutomationAction::None,
launch_request: None,
@ -538,6 +521,7 @@ pub async fn select_epiphany_coordinator_automation(
EPIPHANY_REORIENT_LAUNCH_BINDING_ID,
)
.await;
let core_reorient_result_status = map_core_crrc_result_status(reorient_result_status);
let reorient_finding_accepted = reorient_finding
.as_ref()
.is_some_and(|finding| epiphany_reorient_finding_already_accepted(input.state, finding));
@ -546,7 +530,7 @@ pub async fn select_epiphany_coordinator_automation(
state_status,
&core_pressure,
&reorient_decision,
reorient_result_status,
core_reorient_result_status,
input.state.investigation_checkpoint.as_ref().is_some(),
reorient_finding.is_some(),
reorient_finding_accepted,
@ -557,7 +541,7 @@ pub async fn select_epiphany_coordinator_automation(
&reorient_decision,
&pressure,
&crrc_recommendation,
reorient_result_status,
core_reorient_result_status,
reorient_job.as_ref(),
);
let coordinator = derive_epiphany_coordinator_status(
@ -590,7 +574,7 @@ pub async fn select_epiphany_coordinator_automation(
None,
input.state,
checkpoint,
&core_reorient_decision,
&reorient_decision,
)
}),
EpiphanyCoordinatorAutomationAction::None
@ -613,7 +597,7 @@ pub async fn select_epiphany_coordinator_automation(
}
pub fn map_epiphany_coordinator(
state_status: ThreadEpiphanyReorientStateStatus,
state_status: CoreEpiphanyReorientStateStatus,
checkpoint_present: bool,
pressure: &epiphany_core::EpiphanyPressure,
recommendation: &CoreEpiphanyCrrcRecommendation,
@ -631,7 +615,7 @@ pub fn map_epiphany_coordinator(
reorient_finding_accepted: bool,
) -> EpiphanyCoordinatorDecision {
recommend_coordinator_action(EpiphanyCoordinatorInput {
state_status: map_core_crrc_state_status(state_status),
state_status: map_core_crrc_state_status_from_reorient(state_status),
checkpoint_present,
should_prepare_compaction: pressure.should_prepare_compaction,
recommendation: EpiphanyCoordinatorCrrcRecommendation {
@ -1012,10 +996,10 @@ pub struct EpiphanyRoleBoardStatus {
pub fn map_epiphany_roles(
state: Option<&EpiphanyThreadState>,
jobs: &[ThreadEpiphanyJob],
decision: &ThreadEpiphanyReorientDecision,
decision: &CoreEpiphanyReorientDecision,
pressure: &ThreadEpiphanyPressure,
recommendation: &CoreEpiphanyCrrcRecommendation,
result_status: ThreadEpiphanyReorientResultStatus,
result_status: CoreEpiphanyCrrcResultStatus,
reorient_job: Option<&ThreadEpiphanyJob>,
) -> EpiphanyRoleBoardStatus {
let planning = state.map(|state| &state.planning);
@ -1057,7 +1041,7 @@ pub fn map_epiphany_roles(
crrc_reason: recommendation.reason.clone(),
reorient_decision_action: format!("{:?}", decision.action),
pressure_level: format!("{:?}", pressure.level),
reorient_result_status: map_core_crrc_result_status(result_status),
reorient_result_status: result_status,
reorient_job: reorient_job.map(map_core_role_board_job),
imagination_binding_id: EPIPHANY_IMAGINATION_ROLE_BINDING_ID.to_string(),
modeling_binding_id: EPIPHANY_MODELING_ROLE_BINDING_ID.to_string(),

View file

@ -163,24 +163,6 @@ fn map_core_epiphany_invalidation_input(
}
}
pub fn map_epiphany_reorient(
state: Option<&EpiphanyThreadState>,
pressure: &EpiphanyPressure,
retrieval: &CoreEpiphanyRetrievalFreshness,
graph: &CoreEpiphanyGraphFreshness,
watcher: &CoreEpiphanyInvalidationInput,
) -> (
ThreadEpiphanyReorientStateStatus,
ThreadEpiphanyReorientDecision,
) {
let (state_status, decision) =
derive_epiphany_reorient(state, pressure, retrieval, graph, watcher);
(
map_protocol_reorient_state_status(state_status),
map_protocol_reorient_decision(decision),
)
}
pub fn derive_epiphany_reorient(
state: Option<&EpiphanyThreadState>,
pressure: &EpiphanyPressure,
@ -249,15 +231,13 @@ fn map_core_reorient_watcher_status(
status: CoreEpiphanyInvalidationStatus,
) -> CoreEpiphanyReorientFreshnessStatus {
match status {
CoreEpiphanyInvalidationStatus::Unavailable => {
CoreEpiphanyReorientFreshnessStatus::Unknown
}
CoreEpiphanyInvalidationStatus::Unavailable => CoreEpiphanyReorientFreshnessStatus::Unknown,
CoreEpiphanyInvalidationStatus::Clean => CoreEpiphanyReorientFreshnessStatus::Clean,
CoreEpiphanyInvalidationStatus::Changed => CoreEpiphanyReorientFreshnessStatus::Changed,
}
}
fn map_protocol_reorient_state_status(
pub fn map_protocol_reorient_state_status(
status: CoreEpiphanyReorientStateStatus,
) -> ThreadEpiphanyReorientStateStatus {
match status {
@ -266,7 +246,7 @@ fn map_protocol_reorient_state_status(
}
}
fn map_protocol_reorient_decision(
pub fn map_protocol_reorient_decision(
decision: epiphany_core::EpiphanyReorientDecision,
) -> ThreadEpiphanyReorientDecision {
ThreadEpiphanyReorientDecision {

View file

@ -16,6 +16,7 @@ use crate::context::map_epiphany_graph_query;
use crate::context::map_epiphany_planning;
use crate::coordinator::derive_epiphany_coordinator_status;
use crate::coordinator::epiphany_reorient_finding_already_accepted;
use crate::coordinator::map_core_crrc_result_status;
use crate::coordinator::map_epiphany_coordinator_view;
use crate::coordinator::map_epiphany_crrc_recommendation;
use crate::coordinator::map_epiphany_roles;
@ -30,7 +31,9 @@ use crate::pressure::derive_epiphany_pressure;
use crate::pressure::map_epiphany_pressure;
use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
use crate::reorient::derive_epiphany_freshness_view;
use crate::reorient::map_epiphany_reorient;
use crate::reorient::derive_epiphany_reorient;
use crate::reorient::map_protocol_reorient_decision;
use crate::reorient::map_protocol_reorient_state_status;
use crate::runtime_results::load_epiphany_reorient_result_snapshot;
use crate::runtime_results::load_epiphany_role_result_snapshot;
use crate::scene::map_core_epiphany_scene_action;
@ -182,11 +185,11 @@ pub async fn map_epiphany_view_response(
let pressure = needs_pressure.then(|| map_epiphany_pressure(token_usage_info));
let core_freshness = needs_reorientation_inputs
.then(|| derive_epiphany_freshness_view(state, retrieval_override, watcher_snapshot));
let (state_revision, reorient_state_status, reorient_decision) =
let (state_revision, core_reorient_state_status, core_reorient_decision) =
if let (Some(freshness), Some(core_pressure)) =
(core_freshness.as_ref(), core_pressure.as_ref())
{
let (state_status, decision) = map_epiphany_reorient(
let (state_status, decision) = derive_epiphany_reorient(
state,
core_pressure,
&freshness.retrieval,
@ -195,8 +198,16 @@ pub async fn map_epiphany_view_response(
);
(freshness.state_revision, state_status, Some(decision))
} else {
(None, ThreadEpiphanyReorientStateStatus::Missing, None)
(
None,
epiphany_core::EpiphanyReorientStateStatus::Missing,
None,
)
};
let reorient_state_status = map_protocol_reorient_state_status(core_reorient_state_status);
let reorient_decision = core_reorient_decision
.clone()
.map(map_protocol_reorient_decision);
let jobs = if needs_jobs {
map_epiphany_jobs(state, retrieval_override)
} else {
@ -230,15 +241,16 @@ 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 core_reorient_result_status = map_core_crrc_result_status(reorient_result_status);
let recommendation = if let (Some(core_pressure), Some(decision)) =
(core_pressure.as_ref(), reorient_decision.as_ref())
(core_pressure.as_ref(), core_reorient_decision.as_ref())
{
Some(map_epiphany_crrc_recommendation(
loaded,
reorient_state_status,
core_reorient_state_status,
core_pressure,
decision,
reorient_result_status,
core_reorient_result_status,
checkpoint_present,
reorient_finding.is_some(),
reorient_finding_accepted,
@ -248,7 +260,7 @@ pub async fn map_epiphany_view_response(
};
let roles = if let (Some(pressure), Some(decision), Some(recommendation)) = (
pressure.as_ref(),
reorient_decision.as_ref(),
core_reorient_decision.as_ref(),
recommendation.as_ref(),
) {
Some(map_epiphany_roles(
@ -257,7 +269,7 @@ pub async fn map_epiphany_view_response(
decision,
pressure,
recommendation,
reorient_result_status,
core_reorient_result_status,
reorient_job.as_ref(),
))
} else {
@ -273,11 +285,11 @@ pub async fn map_epiphany_view_response(
let status = derive_epiphany_coordinator_status(
state,
runtime_store_path,
reorient_state_status,
core_reorient_state_status,
core_pressure,
recommendation,
roles.roles.clone(),
reorient_decision.as_ref(),
core_reorient_decision.as_ref(),
reorient_result_status,
reorient_finding.as_ref(),
checkpoint_present,

View file

@ -48,7 +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, source signals, CRRC recommendations, and role-board lanes as core-shaped types, core CRRC/coordinator/role-board surfaces serialize natively, and `ThreadEpiphany*` projection happens at the legacy view emission boundary. Keep cutting remaining result/reorient inputs until Aquarium/CultNet can read coordinator surfaces without JSON-RPC DTO authority.
- Coordinator/reorient decision/status is less contaminated now: `epiphany-codex-bridge` stores reorient decisions, coordinator decisions, source signals, CRRC recommendations, and role-board lanes as core-shaped types, core CRRC/coordinator/role-board surfaces serialize natively, and `ThreadEpiphany*` projection happens at the legacy view emission boundary. Keep cutting remaining result 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

@ -311,10 +311,10 @@ current_status:
reorient launch documents are built from typed core decisions, reorient
launch mutation results return typed decision/state-status values from the
bridge, and core reorient decisions are serializable CultNet-ready state.
Coordinator decisions, coordinator source signals, CRRC recommendations,
and role-board lanes now remain core-shaped inside the bridge; app-server
still projects those typed surfaces into `ThreadEpiphany*` responses at the
legacy JSON-RPC edge. The bridge still
Reorient decisions, coordinator decisions, coordinator source signals, CRRC
recommendations, and role-board lanes now remain core-shaped inside the
bridge; app-server still projects those typed surfaces into
`ThreadEpiphany*` responses at the legacy JSON-RPC edge. 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/reorient 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.
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.