From 30a1e4aa19efe8606cb0ec2591cd0d81ba3cfa59 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 13 May 2026 10:26:35 +0100 Subject: [PATCH] Move distill propose reads into bridge --- epiphany-codex-bridge/src/view.rs | 61 ++++++++++++++++++ notes/fresh-workspace-handoff.md | 6 +- state/ledgers.msgpack | Bin 90907 -> 91177 bytes state/map.yaml | 2 +- .../epiphany_read_routes.rs | 59 +++-------------- 5 files changed, 76 insertions(+), 52 deletions(-) diff --git a/epiphany-codex-bridge/src/view.rs b/epiphany-codex-bridge/src/view.rs index b8c174dc..cebff3a8 100644 --- a/epiphany-codex-bridge/src/view.rs +++ b/epiphany-codex-bridge/src/view.rs @@ -1,6 +1,10 @@ use std::path::Path; use codex_app_server_protocol::*; +use codex_core::EpiphanyDistillInput; +use codex_core::EpiphanyMapProposalInput; +use codex_core::distill_observation; +use codex_core::propose_map_update; use codex_protocol::protocol::EpiphanyRetrievalState; use codex_protocol::protocol::EpiphanyThreadState; use codex_protocol::protocol::TokenUsageInfo as CoreTokenUsageInfo; @@ -497,3 +501,60 @@ pub async fn map_epiphany_reorient_result_response( note, } } + +pub fn map_epiphany_distill_response( + expected_revision: u64, + params: ThreadEpiphanyDistillParams, +) -> std::result::Result { + let ThreadEpiphanyDistillParams { + source_kind, + status, + text, + subject, + evidence_kind, + code_refs, + .. + } = params; + let proposal = distill_observation(EpiphanyDistillInput { + source_kind, + status, + text, + subject, + evidence_kind, + code_refs, + }) + .map_err(|err| err.to_string())?; + + Ok(ThreadEpiphanyDistillResponse { + expected_revision, + patch: ThreadEpiphanyUpdatePatch { + observations: vec![proposal.observation], + evidence: vec![proposal.evidence], + ..Default::default() + }, + }) +} + +pub fn map_epiphany_propose_response( + state: EpiphanyThreadState, + observation_ids: Vec, +) -> std::result::Result { + let expected_revision = state.revision; + let proposal = propose_map_update(EpiphanyMapProposalInput { + state, + observation_ids, + }) + .map_err(|err| err.to_string())?; + + Ok(ThreadEpiphanyProposeResponse { + expected_revision, + patch: ThreadEpiphanyUpdatePatch { + observations: vec![proposal.observation], + evidence: vec![proposal.evidence], + graphs: Some(proposal.graphs), + graph_frontier: Some(proposal.graph_frontier), + churn: Some(proposal.churn), + ..Default::default() + }, + }) +} diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index b2186361..8fef4a9d 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -720,7 +720,11 @@ Freshness/context/graph-query response construction is also bridge-owned now. `ThreadEpiphanyContextResponse`, and `ThreadEpiphanyGraphQueryResponse` from typed state plus host-supplied watcher/retrieval inputs. App-server still owns loading and watcher registration because those are host lifecycle seams. -`epiphany_read_routes.rs` is about 620 lines after this cut. +`epiphany_read_routes.rs` is about 620 lines after this cut. The distill and +propose patch-response builders have followed into the same bridge view module; +app-server still checks that the target thread is loaded and maps errors onto +JSON-RPC responses, but it no longer shapes those patches itself. +`epiphany_read_routes.rs` is about 579 lines after this cut. 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 diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 6f3c3e6e10de25a20085e146649c9cbaa2dfd537..b360e0a8fcd6c6294af26a53680345a7dbc6cac5 100644 GIT binary patch delta 149 zcmbPzjCJJ+)(Of?$?rF+PGe+z+q{Qy`yNI{&&27k5*dYAj7+TzCNmz>lDm1@H@_@3 zMIj}#xFjuYUMsf3Eg}nT7h3wSS0)?FX#FW$& z-I9!=)Wj5p|%w)yc7kmV1GZ|pa5ru)S{yNB8A+ id, @@ -516,15 +507,8 @@ impl CodexMessageProcessor { .await .map(|state| state.revision) .unwrap_or(0); - let proposal = match distill_observation(EpiphanyDistillInput { - source_kind, - status, - text, - subject, - evidence_kind, - code_refs, - }) { - Ok(proposal) => proposal, + let response = match map_epiphany_distill_response(expected_revision, params) { + Ok(response) => response, Err(err) => { self.send_invalid_request_error( request_id, @@ -534,14 +518,6 @@ impl CodexMessageProcessor { return; } }; - let response = ThreadEpiphanyDistillResponse { - expected_revision, - patch: ThreadEpiphanyUpdatePatch { - observations: vec![proposal.observation], - evidence: vec![proposal.evidence], - ..Default::default() - }, - }; self.outgoing.send_response(request_id, response).await; } @@ -551,10 +527,8 @@ impl CodexMessageProcessor { request_id: ConnectionRequestId, params: ThreadEpiphanyProposeParams, ) { - let ThreadEpiphanyProposeParams { - thread_id, - observation_ids, - } = params; + let ThreadEpiphanyProposeParams { thread_id, .. } = ¶ms; + let thread_id = thread_id.clone(); let thread_uuid = match ThreadId::from_string(&thread_id) { Ok(id) => id, @@ -588,12 +562,8 @@ impl CodexMessageProcessor { return; } }; - let expected_revision = state.revision; - let proposal = match codex_core::propose_map_update(EpiphanyMapProposalInput { - state, - observation_ids, - }) { - Ok(proposal) => proposal, + let response = match map_epiphany_propose_response(state, params.observation_ids) { + Ok(response) => response, Err(err) => { self.send_invalid_request_error( request_id, @@ -603,17 +573,6 @@ impl CodexMessageProcessor { return; } }; - let response = ThreadEpiphanyProposeResponse { - expected_revision, - patch: ThreadEpiphanyUpdatePatch { - observations: vec![proposal.observation], - evidence: vec![proposal.evidence], - graphs: Some(proposal.graphs), - graph_frontier: Some(proposal.graph_frontier), - churn: Some(proposal.churn), - ..Default::default() - }, - }; self.outgoing.send_response(request_id, response).await; }