diff --git a/epiphany-codex-bridge/src/retrieve_protocol.rs b/epiphany-codex-bridge/src/retrieve_protocol.rs index a23ca566..5336a34e 100644 --- a/epiphany-codex-bridge/src/retrieve_protocol.rs +++ b/epiphany-codex-bridge/src/retrieve_protocol.rs @@ -9,6 +9,33 @@ use epiphany_core::EpiphanyRetrieveResponse as CoreEpiphanyRetrieveResponse; use epiphany_core::EpiphanyRetrieveResult as CoreEpiphanyRetrieveResult; use epiphany_core::EpiphanyRetrieveResultKind as CoreEpiphanyRetrieveResultKind; use epiphany_state_model::EpiphanyRetrievalState; +use std::path::PathBuf; + +use crate::error::EpiphanyBridgeError; +use crate::error::Result as BridgeResult; +use crate::retrieve::normalize_thread_epiphany_retrieve_query; +use crate::retrieve::retrieve_epiphany_for_paths; + +pub async fn retrieve_thread_epiphany_for_paths( + workspace_root: PathBuf, + codex_home: PathBuf, + query: String, + limit: Option, + path_prefixes: Vec, +) -> BridgeResult { + let query = normalize_thread_epiphany_retrieve_query(query, limit, path_prefixes) + .map_err(EpiphanyBridgeError::InvalidRequest)?; + let response = retrieve_epiphany_for_paths(workspace_root, codex_home, query) + .await + .map_err(|err| { + EpiphanyBridgeError::Fatal(format!("failed to retrieve Epiphany results: {err}")) + })?; + protocol_retrieve_response(response).map_err(|err| { + EpiphanyBridgeError::Fatal(format!( + "failed to project Epiphany retrieve response: {err}" + )) + }) +} pub fn protocol_retrieve_response( response: CoreEpiphanyRetrieveResponse, diff --git a/notes/epiphany-current-algorithmic-map.md b/notes/epiphany-current-algorithmic-map.md index c3d0ac5a..39be1087 100644 --- a/notes/epiphany-current-algorithmic-map.md +++ b/notes/epiphany-current-algorithmic-map.md @@ -464,14 +464,12 @@ Code refs: The app-server handler: 1. parses the thread id. -2. trims and rejects empty queries. -3. rejects zero limits. -4. requires the thread to be loaded. -5. clamps limit to Epiphany bounds. -6. calls `epiphany-codex-bridge::retrieve_thread_epiphany`. -7. maps core results into app-server protocol DTOs. +2. requires the thread to be loaded. +3. reads the loaded thread config and Codex home as host facts. +4. calls `epiphany-codex-bridge::retrieve_protocol::retrieve_thread_epiphany_for_paths`. +5. maps bridge errors to JSON-RPC invalid-request or internal-error responses. -`retrieve_thread_epiphany` snapshots the host config, extracts `cwd` as workspace root, gets Codex home from the host seam, and runs `epiphany_core::retrieve_workspace` in `spawn_blocking`. +`retrieve_thread_epiphany_for_paths` owns raw request normalization, including query trimming, empty-query rejection, zero-limit rejection, limit clamping, and path-prefix handling. It then runs `epiphany_core::retrieve_workspace` through the bridge retrieval worker and projects typed core results into the legacy Codex JSON-RPC retrieve response. `epiphany-core::retrieve_workspace`: diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index ec287014..5139f487 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -842,6 +842,13 @@ 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. +The retrieve read route has now lost its local normalization/projection opinion +too. `epiphany-codex-bridge::retrieve_protocol::retrieve_thread_epiphany_for_paths` +owns raw query normalization, core retrieval invocation, and Codex JSON-RPC +retrieve response projection. App-server keeps thread-id parsing, loaded-thread +lookup, config/Codex-home fact supply, response emission, and bridge-error to +JSON-RPC mapping. + 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 intent/result/receipt documents internally and normal MCP JSON-RPC externally. diff --git a/state/ledgers.cc b/state/ledgers.cc index f7ad5efa..b2d7304b 100644 Binary files a/state/ledgers.cc and b/state/ledgers.cc differ diff --git a/state/map.yaml b/state/map.yaml index 82dd27cb..f23d00e5 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -472,8 +472,10 @@ current_status: `ThreadEpiphanyScene` plus scene-action DTOs for view responses. Retrieval follows the boundary too: `retrieve.rs` executes normalization, indexing, state lookup, and typed retrieval responses; `retrieve_protocol.rs` - owns Codex JSON-RPC retrieve/index response projection and absolute-path DTO - validation. + owns Codex JSON-RPC retrieve/index response projection, absolute-path DTO + validation, and the route-facing retrieve service that normalizes raw + request fields before invoking core retrieval. App-server supplies loaded + thread cwd/Codex-home facts and maps bridge errors to JSON-RPC responses. View response assembly no longer owns private lens/source/reorient-status projection helpers; those small enum conversions route through `protocol_edge`, and the Codex response assembler is now named diff --git a/vendor/codex/codex-rs/app-server/src/codex_message_processor/epiphany_read_routes.rs b/vendor/codex/codex-rs/app-server/src/codex_message_processor/epiphany_read_routes.rs index 48286c2a..be3c884a 100644 --- a/vendor/codex/codex-rs/app-server/src/codex_message_processor/epiphany_read_routes.rs +++ b/vendor/codex/codex-rs/app-server/src/codex_message_processor/epiphany_read_routes.rs @@ -3,6 +3,7 @@ use codex_core::CodexThread; use codex_protocol::ThreadId; use codex_protocol::protocol::EpiphanyRetrievalState; use epiphany_codex_bridge::cultnet::EpiphanySurfaceSource; +use epiphany_codex_bridge::error::EpiphanyBridgeError; use epiphany_codex_bridge::invalidation::epiphany_freshness_watcher_snapshot; use epiphany_codex_bridge::launch::EPIPHANY_REORIENT_LAUNCH_BINDING_ID; use epiphany_codex_bridge::launch::epiphany_role_binding_id; @@ -18,9 +19,7 @@ use epiphany_codex_bridge::protocol_edge::protocol_graph_query_to_core; use epiphany_codex_bridge::protocol_edge::protocol_role_id_to_core; use epiphany_codex_bridge::protocol_edge::protocol_view_lenses_to_core; use epiphany_codex_bridge::retrieve::epiphany_retrieval_state_for_paths; -use epiphany_codex_bridge::retrieve::normalize_thread_epiphany_retrieve_query; -use epiphany_codex_bridge::retrieve::retrieve_epiphany_for_paths; -use epiphany_codex_bridge::retrieve_protocol::protocol_retrieve_response; +use epiphany_codex_bridge::retrieve_protocol::retrieve_thread_epiphany_for_paths; use epiphany_codex_bridge::view_protocol::EpiphanyFreshnessResponseInput; use epiphany_codex_bridge::view_protocol::EpiphanyReorientResultResponseInput; use epiphany_codex_bridge::view_protocol::EpiphanyRoleResultResponseInput; @@ -434,15 +433,6 @@ impl CodexMessageProcessor { } }; - let query = match normalize_thread_epiphany_retrieve_query(query, limit, path_prefixes) { - Ok(query) => query, - Err(message) => { - self.send_invalid_request_error(request_id, message.to_string()) - .await; - return; - } - }; - let thread = match self.thread_manager.get_thread(thread_uuid).await { Ok(thread) => thread, Err(_) => { @@ -457,21 +447,29 @@ impl CodexMessageProcessor { let config = thread.config_snapshot().await; let codex_home = thread.codex_home().await; - let response = - match retrieve_epiphany_for_paths(config.cwd.to_path_buf(), codex_home, query) - .await - .and_then(protocol_retrieve_response) - { - Ok(response) => response, - Err(err) => { - self.send_internal_error( - request_id, - format!("failed to retrieve Epiphany results for {thread_uuid}: {err}"), - ) - .await; - return; - } - }; + let response = match retrieve_thread_epiphany_for_paths( + config.cwd.to_path_buf(), + codex_home, + query, + limit, + path_prefixes, + ) + .await + { + Ok(response) => response, + Err(EpiphanyBridgeError::InvalidRequest(message)) => { + self.send_invalid_request_error(request_id, message).await; + return; + } + Err(err) => { + self.send_internal_error( + request_id, + format!("failed to retrieve Epiphany results for {thread_uuid}: {err}"), + ) + .await; + return; + } + }; self.outgoing.send_response(request_id, response).await; }