diff --git a/epiphany-codex-bridge/src/mutation.rs b/epiphany-codex-bridge/src/mutation.rs index 518761ac..7e046ac1 100644 --- a/epiphany-codex-bridge/src/mutation.rs +++ b/epiphany-codex-bridge/src/mutation.rs @@ -18,7 +18,8 @@ use epiphany_state_model::EpiphanyInvestigationCheckpoint; use crate::results::map_core_role_result_role_id; pub struct RoleAcceptanceUpdate { - pub patch: ThreadEpiphanyUpdatePatch, + pub state_update: EpiphanyStateUpdate, + pub applied_patch: ThreadEpiphanyUpdatePatch, pub changed_fields: Vec, pub accepted_receipt_id: String, pub accepted_observation_id: String, @@ -93,6 +94,13 @@ pub fn protocol_patch_from_core( pub fn state_update_from_thread_patch( expected_revision: Option, patch: ThreadEpiphanyUpdatePatch, +) -> EpiphanyStateUpdate { + state_update_from_core_patch(expected_revision, core_state_patch_from_protocol(&patch)) +} + +pub fn state_update_from_core_patch( + expected_revision: Option, + patch: EpiphanyRoleStatePatchDocument, ) -> EpiphanyStateUpdate { EpiphanyStateUpdate { expected_revision, @@ -141,6 +149,7 @@ pub fn modeling_role_accept_patch_errors(patch: &ThreadEpiphanyUpdatePatch) -> V } pub fn build_role_acceptance_update( + expected_revision: Option, role_id: ThreadEpiphanyRoleId, binding_id: &str, finding: &CoreEpiphanyRoleFinding, @@ -209,11 +218,13 @@ pub fn build_role_acceptance_update( core_patch .acceptance_receipts .push(acceptance_bundle.receipt); - let patch = protocol_patch_from_core(core_patch); - let changed_fields = epiphany_update_patch_changed_fields(&patch); + let applied_patch = protocol_patch_from_core(core_patch.clone()); + let changed_fields = epiphany_update_patch_changed_fields(&applied_patch); + let state_update = state_update_from_core_patch(expected_revision, core_patch); Ok(RoleAcceptanceUpdate { - patch, + state_update, + applied_patch, changed_fields, accepted_receipt_id, accepted_observation_id, diff --git a/epiphany-codex-bridge/src/mutation_service.rs b/epiphany-codex-bridge/src/mutation_service.rs index cb2121eb..1483a616 100644 --- a/epiphany-codex-bridge/src/mutation_service.rs +++ b/epiphany-codex-bridge/src/mutation_service.rs @@ -391,6 +391,7 @@ pub async fn apply_thread_epiphany_role_accept( )?; let accepted_prefix = epiphany_role_label(role_id); let acceptance_update = build_role_acceptance_update( + expected_revision, role_id, binding_id, &finding, @@ -404,12 +405,9 @@ pub async fn apply_thread_epiphany_role_accept( let accepted_observation_id = acceptance_update.accepted_observation_id.clone(); let accepted_evidence_id = acceptance_update.accepted_evidence_id.clone(); let changed_fields = acceptance_update.changed_fields.clone(); - let applied_patch = acceptance_update.patch.clone(); - let epiphany_state = apply_epiphany_state_update_to_thread( - thread, - state_update_from_thread_patch(expected_revision, acceptance_update.patch), - ) - .await?; + let applied_patch = acceptance_update.applied_patch.clone(); + let epiphany_state = + apply_epiphany_state_update_to_thread(thread, acceptance_update.state_update).await?; let epiphany_state = thread.client_visible_epiphany_state(epiphany_state).await; Ok(EpiphanyRoleAcceptApplied { diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index f2981d47..93a6f0ae 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -55,6 +55,7 @@ remembers doctrine; the branch remembers the blade. - Acceptance/mutation now builds role/reorient receipts, evidence, observations, scratch, and checkpoint updates from core typed finding interpretations. Protocol findings remain as legacy response payloads and helper residue; delete those wrappers once view/result responses are also typed internally. - The old protocol-shaped result helper layer is deleted: no protocol finding runtime-id helpers, no protocol result-note renderers, and no dead protocol reorient scratch/checkpoint builders remain in the bridge. Legacy view/result/accept responses may still carry `ThreadEpiphany*Finding`, but they are projections, not bridge policy input. - Runtime result view responses now project directly from typed result snapshots; the old protocol tuple wrappers in `runtime_results.rs` are gone, and runtime-result tests assert core typed statuses. +- Role acceptance now applies core `EpiphanyStateUpdate` from typed findings; `ThreadEpiphanyUpdatePatch` survives in that path only as legacy accept-response projection. - 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. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 9df73780..42fb5beb 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index cc92df64..98a06ac2 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -325,7 +325,9 @@ current_status: legacy accept response cargo. The duplicate protocol-shaped result helper layer has been deleted, and result view responses now project directly from typed runtime result snapshots instead of protocol tuple wrappers; the tuple - wrappers themselves are gone. The bridge still + wrappers themselves are gone. Role acceptance now produces a core + `EpiphanyStateUpdate`; `ThreadEpiphanyUpdatePatch` is retained there only as + legacy accept-response projection. 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.