Move Epiphany notification shaping to bridge

This commit is contained in:
Meta Vens 2026-05-13 03:57:22 +01:00
commit bd3e3cbb70
5 changed files with 67 additions and 43 deletions

View file

@ -3,6 +3,8 @@ use std::path::PathBuf;
use codex_app_server_protocol::ThreadEpiphanyReorientFinding;
use codex_app_server_protocol::ThreadEpiphanyRoleFinding;
use codex_app_server_protocol::ThreadEpiphanyRoleId;
use codex_app_server_protocol::ThreadEpiphanyStateUpdatedNotification;
use codex_app_server_protocol::ThreadEpiphanyStateUpdatedSource;
use codex_app_server_protocol::ThreadEpiphanyStateUpdatedField;
use codex_app_server_protocol::ThreadEpiphanyUpdatePatch;
use codex_core::EpiphanyStateUpdate;
@ -99,6 +101,22 @@ pub fn state_update_from_thread_patch(
}
}
pub fn epiphany_state_updated_notification(
thread_id: String,
source: ThreadEpiphanyStateUpdatedSource,
revision: u64,
changed_fields: Vec<ThreadEpiphanyStateUpdatedField>,
epiphany_state: codex_protocol::protocol::EpiphanyThreadState,
) -> ThreadEpiphanyStateUpdatedNotification {
ThreadEpiphanyStateUpdatedNotification {
thread_id,
source,
revision,
changed_fields,
epiphany_state,
}
}
pub fn imagination_role_accept_patch_errors(patch: &ThreadEpiphanyUpdatePatch) -> Vec<String> {
imagination_role_state_patch_policy_errors(&core_state_patch_from_protocol(patch))
}

View file

@ -535,6 +535,10 @@ The twenty-eighth cut made reorient acceptance return its core
`EpiphanyStateUpdate` from the bridge, so the route no longer assembles the
scratch/checkpoint/receipt/evidence update fields after receiving the bridge
bundle. `epiphany_mutation_routes.rs` is about 1,070 lines.
The twenty-ninth cut moved repeated Epiphany state-updated notification shaping
into `epiphany-codex-bridge/src/mutation.rs`. This did not materially shrink
the route file, but it removed another duplicated protocol-shape authority from
the mutation handlers. `epiphany_mutation_routes.rs` is about 1,071 lines.
Also: MCP itself is allowed to be JSON. The target is not "replace MCP JSON";
the target is an Epiphany-owned boundary that speaks typed Epiphany
@ -542,7 +546,8 @@ intent/result/receipt documents internally and normal MCP JSON-RPC externally.
Continue with the actual whale-carcass cut: carve remaining route-level mutation
orchestration into explicit typed bridge/service calls, starting with launch
response/notification shaping and interrupt result projection. Success is a
response shaping and then reassessing whether the next clean cut is worth
making or whether the remaining code is honest Codex edge glue. Success is a
visibly smaller processor and less mutation authority in Codex, not merely
nicer payload names or another adapter reliquary. Do not resume Rider, Unity,
Aquarium, Face, dogfood, planning, app, skill, marketplace, or bridge expansion

Binary file not shown.

View file

@ -278,5 +278,5 @@ rejected_paths:
reason: making Epiphany cleaner inside Codex still preserves the wrong organ; Codex must be starved down to OpenAI subscription auth/model transport, while Epiphany data and subsystem communication move to typed CultCache/CultNet.
current_status:
summary: The Codex starvation pass has five typing receipts, seventeen processor cuts, and now a real physical extraction: `epiphany-codex-bridge` lives outside `vendor/codex` and owns the Codex-facing Epiphany adapters for scene, jobs, context/planning/graph query, retrieval, result projection, runtime-spine result adaptation, launch/prompt doctrine, mutation document mechanics, live-state projection, pressure/pre-compaction rendering, freshness/reorientation projection, CRRC/coordinator/role-board projection, and acceptance/evidence signal helpers. Vendored app-server now retains only `epiphany_invalidation.rs` as a root Epiphany module because watcher lifecycle is still app-server machinery; `codex_message_processor.rs` still contains route dispatch and mutation orchestration. The processor is about 10,339 lines, `epiphany_mutation_routes.rs` is about 1,070 lines, and `epiphany_state_helpers.rs` is down to a 19-line rollout-state loader after moving typed mutation helpers, reviewability checks, completed runtime-result acceptance loading, live-state projection, launched/interrupted job fallback projection, role/reorient acceptance update bundle construction including its core state update, and protocol patch-to-core state-update projection out to the bridge. This is progress, not absolution: the bridge is still Codex-facing compatibility, not the final CultNet runtime, and route-level launch/update/promote/interrupt orchestration still lives inside the Codex processor. MCP itself is correctly JSON at its protocol edge; the target is typed Epiphany intent/result/receipt wrappers around MCP, not replacing MCP JSON.
next_action: Continue Codex starvation by carving remaining route-level mutation orchestration into explicit outside-vendor service calls, starting with launch response/notification shaping and interrupt result projection. Do not resume app/skill/marketplace expansion.
summary: The Codex starvation pass has five typing receipts, seventeen processor cuts, and now a real physical extraction: `epiphany-codex-bridge` lives outside `vendor/codex` and owns the Codex-facing Epiphany adapters for scene, jobs, context/planning/graph query, retrieval, result projection, runtime-spine result adaptation, launch/prompt doctrine, mutation document mechanics, live-state projection, pressure/pre-compaction rendering, freshness/reorientation projection, CRRC/coordinator/role-board projection, and acceptance/evidence signal helpers. Vendored app-server now retains only `epiphany_invalidation.rs` as a root Epiphany module because watcher lifecycle is still app-server machinery; `codex_message_processor.rs` still contains route dispatch and mutation orchestration. The processor is about 10,339 lines, `epiphany_mutation_routes.rs` is about 1,071 lines, and `epiphany_state_helpers.rs` is down to a 19-line rollout-state loader after moving typed mutation helpers, reviewability checks, completed runtime-result acceptance loading, live-state projection, launched/interrupted job fallback projection, role/reorient acceptance update bundle construction including its core state update, protocol patch-to-core state-update projection, and state-updated notification shaping out to the bridge. This is progress, not absolution: the bridge is still Codex-facing compatibility, not the final CultNet runtime, and route-level launch/update/promote/interrupt orchestration still lives inside the Codex processor. MCP itself is correctly JSON at its protocol edge; the target is typed Epiphany intent/result/receipt wrappers around MCP, not replacing MCP JSON.
next_action: Continue Codex starvation by carving remaining route-level mutation orchestration into explicit outside-vendor service calls, starting with launch response shaping and then reassessing whether the next clean cut is worth making or whether the remaining code is honest Codex edge glue. Do not resume app/skill/marketplace expansion.

View file

@ -22,6 +22,7 @@ use epiphany_codex_bridge::mutation::build_reorient_acceptance_update;
use epiphany_codex_bridge::mutation::build_role_acceptance_update;
use epiphany_codex_bridge::mutation::epiphany_job_launch_changed_fields;
use epiphany_codex_bridge::mutation::epiphany_promote_changed_fields;
use epiphany_codex_bridge::mutation::epiphany_state_updated_notification;
use epiphany_codex_bridge::mutation::epiphany_update_patch_changed_fields;
use epiphany_codex_bridge::mutation::state_update_from_thread_patch;
use epiphany_codex_bridge::mutation::thread_epiphany_patch_has_state_replacements;
@ -144,13 +145,13 @@ impl CodexMessageProcessor {
.await;
self.outgoing
.send_server_notification(ServerNotification::ThreadEpiphanyStateUpdated(
ThreadEpiphanyStateUpdatedNotification {
thread_id: thread_uuid.to_string(),
source: ThreadEpiphanyStateUpdatedSource::JobLaunch,
revision: epiphany_state.revision,
epiphany_state_updated_notification(
thread_uuid.to_string(),
ThreadEpiphanyStateUpdatedSource::JobLaunch,
epiphany_state.revision,
changed_fields,
epiphany_state,
},
),
))
.await;
}
@ -306,13 +307,13 @@ impl CodexMessageProcessor {
.await;
self.outgoing
.send_server_notification(ServerNotification::ThreadEpiphanyStateUpdated(
ThreadEpiphanyStateUpdatedNotification {
thread_id: thread_uuid.to_string(),
source: ThreadEpiphanyStateUpdatedSource::RoleAccept,
revision: epiphany_state.revision,
epiphany_state_updated_notification(
thread_uuid.to_string(),
ThreadEpiphanyStateUpdatedSource::RoleAccept,
epiphany_state.revision,
changed_fields,
epiphany_state,
},
),
))
.await;
}
@ -469,13 +470,13 @@ impl CodexMessageProcessor {
.await;
self.outgoing
.send_server_notification(ServerNotification::ThreadEpiphanyStateUpdated(
ThreadEpiphanyStateUpdatedNotification {
thread_id: thread_uuid.to_string(),
source: ThreadEpiphanyStateUpdatedSource::JobLaunch,
revision: epiphany_state.revision,
epiphany_state_updated_notification(
thread_uuid.to_string(),
ThreadEpiphanyStateUpdatedSource::JobLaunch,
epiphany_state.revision,
changed_fields,
epiphany_state,
},
),
))
.await;
}
@ -631,13 +632,13 @@ impl CodexMessageProcessor {
.await;
self.outgoing
.send_server_notification(ServerNotification::ThreadEpiphanyStateUpdated(
ThreadEpiphanyStateUpdatedNotification {
thread_id: thread_uuid.to_string(),
source: ThreadEpiphanyStateUpdatedSource::ReorientAccept,
revision: epiphany_state.revision,
epiphany_state_updated_notification(
thread_uuid.to_string(),
ThreadEpiphanyStateUpdatedSource::ReorientAccept,
epiphany_state.revision,
changed_fields,
epiphany_state,
},
),
))
.await;
}
@ -788,13 +789,13 @@ impl CodexMessageProcessor {
self.outgoing.send_response(request_id, response).await;
self.outgoing
.send_server_notification(ServerNotification::ThreadEpiphanyStateUpdated(
ThreadEpiphanyStateUpdatedNotification {
thread_id: thread_uuid.to_string(),
source: ThreadEpiphanyStateUpdatedSource::Promote,
revision: epiphany_state.revision,
epiphany_state_updated_notification(
thread_uuid.to_string(),
ThreadEpiphanyStateUpdatedSource::Promote,
epiphany_state.revision,
changed_fields,
epiphany_state,
},
),
))
.await;
}
@ -859,13 +860,13 @@ impl CodexMessageProcessor {
self.outgoing.send_response(request_id, response).await;
self.outgoing
.send_server_notification(ServerNotification::ThreadEpiphanyStateUpdated(
ThreadEpiphanyStateUpdatedNotification {
thread_id: thread_uuid.to_string(),
source: ThreadEpiphanyStateUpdatedSource::Update,
revision: epiphany_state.revision,
epiphany_state_updated_notification(
thread_uuid.to_string(),
ThreadEpiphanyStateUpdatedSource::Update,
epiphany_state.revision,
changed_fields,
epiphany_state,
},
),
))
.await;
}
@ -970,13 +971,13 @@ impl CodexMessageProcessor {
.await;
self.outgoing
.send_server_notification(ServerNotification::ThreadEpiphanyStateUpdated(
ThreadEpiphanyStateUpdatedNotification {
thread_id: thread_uuid.to_string(),
source: ThreadEpiphanyStateUpdatedSource::JobLaunch,
revision: epiphany_state.revision,
epiphany_state_updated_notification(
thread_uuid.to_string(),
ThreadEpiphanyStateUpdatedSource::JobLaunch,
epiphany_state.revision,
changed_fields,
epiphany_state,
},
),
))
.await;
}
@ -1057,13 +1058,13 @@ impl CodexMessageProcessor {
.await;
self.outgoing
.send_server_notification(ServerNotification::ThreadEpiphanyStateUpdated(
ThreadEpiphanyStateUpdatedNotification {
thread_id: thread_uuid.to_string(),
source: ThreadEpiphanyStateUpdatedSource::JobInterrupt,
revision: epiphany_state.revision,
epiphany_state_updated_notification(
thread_uuid.to_string(),
ThreadEpiphanyStateUpdatedSource::JobInterrupt,
epiphany_state.revision,
changed_fields,
epiphany_state,
},
),
))
.await;
}