Move role result policy into bridge

This commit is contained in:
Meta Vens 2026-06-09 06:05:04 +01:00
commit 1fc871ef73
6 changed files with 64 additions and 42 deletions

View file

@ -38,6 +38,7 @@ use crate::cultnet::EpiphanySurfaceSource;
use crate::error::EpiphanyBridgeError;
use crate::error::Result as BridgeResult;
use crate::jobs::map_epiphany_jobs;
use crate::launch::epiphany_role_binding_id;
use crate::pressure::derive_epiphany_pressure;
use crate::protocol_edge::protocol_context_params_to_core;
use crate::protocol_edge::protocol_distill_params_to_core;
@ -52,6 +53,7 @@ use crate::protocol_edge::protocol_reorient_source;
use crate::protocol_edge::protocol_reorient_state_status;
use crate::protocol_edge::protocol_role_finding;
use crate::protocol_edge::protocol_role_id_from_core;
use crate::protocol_edge::protocol_role_id_to_core;
use crate::protocol_edge::protocol_role_result_status;
use crate::protocol_edge::protocol_roles_source;
use crate::protocol_edge::protocol_view_lens_from_core;
@ -528,6 +530,38 @@ pub async fn map_epiphany_role_result_response(
}
}
pub async fn map_thread_epiphany_role_result_response(
params: ThreadEpiphanyRoleResultParams,
loaded: bool,
state: Option<&EpiphanyThreadState>,
runtime_store_path: Option<&Path>,
) -> BridgeResult<ThreadEpiphanyRoleResultResponse> {
let ThreadEpiphanyRoleResultParams {
thread_id,
role_id,
binding_id,
} = params;
let role_id = protocol_role_id_to_core(role_id);
let default_binding_id =
epiphany_role_binding_id(role_id).map_err(EpiphanyBridgeError::InvalidRequest)?;
let binding_id = binding_id.unwrap_or_else(|| default_binding_id.to_string());
Ok(
map_epiphany_role_result_response(EpiphanyRoleResultResponseInput {
thread_id,
role_id,
source: if loaded {
EpiphanySurfaceSource::Live
} else {
EpiphanySurfaceSource::Stored
},
binding_id,
state,
runtime_store_path,
})
.await,
)
}
pub struct EpiphanyReorientResultResponseInput<'a> {
pub thread_id: String,
pub source: EpiphanySurfaceSource,

View file

@ -36,7 +36,7 @@ The spine exists in more than twenty-five live paths:
- reorientation policy: the `reorient` view lens reuses the same live/stored thread view plus mapped pressure/freshness/watcher signals, then adapts those inputs into pure `epiphany-core` verdict policy. Core derives the bounded `resume`/`regather` decision with checkpoint-path/frontier reasons; app-server only maps the core decision back to protocol shape, without mutating, compacting, scheduling, notifying, or continuing work in [reorient.rs](E:/Projects/EpiphanyAgent/epiphany-core/src/surfaces/reorient.rs:1), [v2.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs:4514), and [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:15296).
- CRRC coordinator recommendation: the `crrc` view lens reuses pressure/freshness/watcher/reorientation mapping plus the fixed `reorient-worker` binding and result read-back helper, recognizes already accepted reorientation findings so an accepted result is not recommended for acceptance again, and calls pure `epiphany-core` CRRC policy to return one bounded recommendation such as continue, prepare checkpoint, launch worker, wait, review, accept, or regather manually without mutating, launching, accepting, compacting, notifying, scheduling, or silently continuing work in [v2.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs:4661), [crrc.rs](E:/Projects/EpiphanyAgent/epiphany-core/src/surfaces/crrc.rs:60), and [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:4546).
- role ownership projection: the `roles` view lens reuses the same state/jobs/pressure/reorient/result/CRRC signals as the coordinator loop, and projects implementation, Imagination/planning, modeling/checkpoint, verification/review, and reorientation lanes with owner roles, status, linked jobs, authority scopes, and recommended scene actions without launching, scheduling, accepting, compacting, notifying, or mutating state. App-server adapts concrete protocol jobs and thread state, while the pure role-board projection policy now lives in [role_board.rs](E:/Projects/EpiphanyAgent/epiphany-core/src/surfaces/role_board.rs:70).
- role specialist launch/read-back/acceptance: app-server declares experimental `thread/epiphany/roleLaunch`, read-only `thread/epiphany/roleResult`, and write-gated `thread/epiphany/roleAccept`. `roleLaunch` accepts fixed Imagination/planning, modeling/checkpoint, and verification/review role ids, builds bounded specialist payloads from authoritative Epiphany state, routes them through the heartbeat-backed `epiphany_launch_job` seam, opens a typed runtime-spine job receipt, and emits the normal `jobLaunch` state update for `jobBindings` only. `roleResult` resolves heartbeat bindings through typed runtime-spine job results and seals legacy `agent_jobs` bindings, then adapts worker JSON through core role-result interpretation in [role_result.rs](E:/Projects/EpiphanyAgent/epiphany-core/src/surfaces/role_result.rs:45), projecting structured output as a reviewable finding with verdict, summary, next safe move, inspected files, frontier/evidence ids, optional `statePatch`, optional `selfPatch`, coordinator `selfPersistence` review, and errors without mutation, promotion, scheduling, or hidden continuation. `selfPatch` is a Ghostlight-shaped lane-memory request, not project truth: core accepts only role-matched, bounded, evidence-grounded memory/goal/value/private-note mutations and refuses objectives, graphs, checkpoints, scratch, planning, jobs, authority, code edits, or raw transcripts with reasons. `roleAccept` accepts completed heartbeat findings from typed runtime-spine results, accepts completed Imagination findings only when they contain a valid planning-only patch with draft Objective Draft review gates, accepts completed modeling/checkpoint findings only with a modeling-safe `statePatch`, applies accepted project patches through the existing Epiphany state validator, and uses core acceptance bundle policy to build the audit observation, evidence, and typed receipt. GUI/coordinator accept paths then apply accepted `selfPatch` requests to typed CultCache role dossiers in `state/agents.cc` through the native `epiphany-agent-memory-store` binary. Implementation stays owned by the main coding agent, verification output remains review-only, and reorientation stays on the CRRC-specific `reorientLaunch` / `reorientResult` / `reorientAccept` path.
- role specialist launch/read-back/acceptance: app-server declares experimental `thread/epiphany/roleLaunch`, read-only `thread/epiphany/roleResult`, and write-gated `thread/epiphany/roleAccept`. `roleLaunch` accepts fixed Imagination/planning, modeling/checkpoint, and verification/review role ids, builds bounded specialist payloads from authoritative Epiphany state, routes them through the heartbeat-backed `epiphany_launch_job` seam, opens a typed runtime-spine job receipt, and emits the normal `jobLaunch` state update for `jobBindings` only. `roleResult` route handling now delegates protocol role-id conversion, default binding selection, unsupported-role rejection, and response projection to `epiphany-codex-bridge::view_protocol::map_thread_epiphany_role_result_response`; app-server supplies only loaded/stored state and runtime-store host facts. The role-result surface resolves heartbeat bindings through typed runtime-spine job results and seals legacy `agent_jobs` bindings, then adapts worker JSON through core role-result interpretation in [role_result.rs](E:/Projects/EpiphanyAgent/epiphany-core/src/surfaces/role_result.rs:45), projecting structured output as a reviewable finding with verdict, summary, next safe move, inspected files, frontier/evidence ids, optional `statePatch`, optional `selfPatch`, coordinator `selfPersistence` review, and errors without mutation, promotion, scheduling, or hidden continuation. `selfPatch` is a Ghostlight-shaped lane-memory request, not project truth: core accepts only role-matched, bounded, evidence-grounded memory/goal/value/private-note mutations and refuses objectives, graphs, checkpoints, scratch, planning, jobs, authority, code edits, or raw transcripts with reasons. `roleAccept` accepts completed heartbeat findings from typed runtime-spine results, accepts completed Imagination findings only when they contain a valid planning-only patch with draft Objective Draft review gates, accepts completed modeling/checkpoint findings only with a modeling-safe `statePatch`, applies accepted project patches through the existing Epiphany state validator, and uses core acceptance bundle policy to build the audit observation, evidence, and typed receipt. GUI/coordinator accept paths then apply accepted `selfPatch` requests to typed CultCache role dossiers in `state/agents.cc` through the native `epiphany-agent-memory-store` binary. Implementation stays owned by the main coding agent, verification output remains review-only, and reorientation stays on the CRRC-specific `reorientLaunch` / `reorientResult` / `reorientAccept` path.
- shared prompt memory projection and role dossiers: the prompt config now carries `[shared].persistent_memory` in [epiphany_specialists.toml](E:/Projects/EpiphanyAgent/epiphany-core/src/prompts/epiphany_specialists.toml:2). App-server parses that block through the bridge, prepends it with `epiphany_agent_prompt_with_memory` for embodied lanes, and keeps reorientation as a Continuity worker/protocol path rather than a role dossier. The base `<epiphany_state>` doctrine reinforces the Perfect Machine rule through [prompt.rs](E:/Projects/EpiphanyAgent/epiphany-state-model/src/prompt.rs:31) and [epiphany_doctrine.md](E:/Projects/EpiphanyAgent/epiphany-state-model/src/prompts/epiphany_doctrine.md:1). Individual Ghostlight-shaped role dossiers now live in typed CultCache `state/agents.cc` for embodied sub-agent lanes, and the native `epiphany-agent-memory-store` binary validates, reviews, and applies bounded self-memory patches through the Rust store.
- fixed-lane coordinator: the `coordinator` view lens composes role, pressure, reorient, CRRC, role result, and reorient result signals, and returns one current action without mutation. App-server assembles host/protocol inputs, but the pure fixed-lane decision ladder now lives in `epiphany-core` in [coordinator.rs](E:/Projects/EpiphanyAgent/epiphany-core/src/surfaces/coordinator.rs:132). Review acceptance and implementation clearance are intentionally different: an accepted verification finding clears implementation only when the verifier verdict is `pass`; accepted `needs-evidence`, `needs-review`, or `fail` findings route back toward modeling/checkpoint strengthening before code work resumes. `regatherManually` is now fallback, not a supervisor-puppeteering excuse: completed unaccepted modeling findings stop at `reviewModelingResult`, modeling acceptance precedes verification, and fixed lane actions are considered before manual regather.
- MVP operator view: native `epiphany-mvp-status` launches app-server over stdio, starts or reads one thread, gathers scene, planning, pressure, reorient, jobs, roles, Imagination/modeling/verification role results, reorient result, CRRC responses, heartbeat, and Persona bubble artifacts, and renders them as text or JSON so the loop can be dogfooded without Python owning the product surface.

View file

@ -862,6 +862,13 @@ well. App-server still gathers host-owned live retrieval and watcher facts, but
protocol response projection. `epiphany_read_routes.rs` is about 559 lines
after this cut.
Role-result route policy followed. App-server still parses the thread id, loads
the live/stored thread view, looks up the runtime-store path, and maps bridge
errors to JSON-RPC; `map_thread_epiphany_role_result_response` now owns protocol
role-id conversion, default binding selection, unsupported-role rejection, and
response projection. `epiphany_read_routes.rs` is about 540 lines after this
cut.
Context and graph-query route-level conversion followed. App-server still
parses thread ids, loads live/stored thread views, and emits JSON-RPC
responses, but `map_thread_epiphany_context_response` and

Binary file not shown.

View file

@ -82,7 +82,7 @@ active_subgoals:
- Use `notes/epiphany-investor-readiness-roadmap.md` as this Codex operator's investor-scale todo rail and as the optional Epiphany Imagination sub-agent planning rail. Angel capital is fuel for compute, review capacity, legal diligence, infrastructure, and public proof, not a governance throne. The operator roadmap is now: make the local Mom MVP a repeatable proof bundle; build the Bifrost-first external-work bridge; add model-spend/review-load/accepted-artifact accounting; prove fresh-repo operation without supervisor contamination; and keep public/operator-safe exports sealed against private worker/operator/agent context. Imagination should translate world-scale Colossus pressure into Bifrost-first Objective Drafts with consent, maintainer review, receipts/ledger evidence, compute/output metrics, public/private export safety, and bounded proof artifacts.
- The May 2026 teardown/rebuild migration is archived under `notes/archive/epiphany-ideal-architecture-rebuild-plan.md` unless a concrete regression reopens it. Preserve the new foundation: Epiphany view/coordinator policy lives in `epiphany-core`, runtime-spine owns job/result lifecycle identity through `runtime_links`, duplicate acceptance is receipt-keyed, public findings stay typed/sealed, view expansion requires a core contract, and app-server remains routing/adaptation rather than a second policy throne.
- Treat Phase 5 update/distill/propose/promote/read/notification as complete enough unless a concrete regression appears; distill/propose route-level response construction now lives in the bridge, with app-server supplying loaded-thread state as host fact and mapping bridge errors to JSON-RPC.
- Preserve read-only boundaries for retrieve, distill, propose, freshness, context, graphQuery, roleResult, reorientResult, and the canonical view lenses for scene, jobs, roles, planning, pressure, reorient, crrc, and coordinator; freshness response construction and context/graphQuery route-level DTO-to-core conversion now live in bridge view protocol mappers rather than app-server read routes.
- Preserve read-only boundaries for retrieve, distill, propose, freshness, context, graphQuery, roleResult, reorientResult, and the canonical view lenses for scene, jobs, roles, planning, pressure, reorient, crrc, and coordinator; freshness response construction, roleResult route role/binding policy, and context/graphQuery route-level DTO-to-core conversion now live in bridge view protocol mappers rather than app-server read routes.
- Use `notes/epiphany-memory-graph-unified-plan.md` as the source-grounded memory architecture direction. The repo fractal dataflow graph and agent memory are one `EpiphanyMemoryGraph` substrate with repo, role, short-term, incubation, agency, candidate-intervention, and evidence profiles. Qdrant stores rebuildable semantic embeddings for typed graph documents; it is never canonical memory. The first live skeleton now exists in `epiphany-state-model` plus `epiphany-core::memory_graph`: typed graph documents, stable ids, profile/lifecycle validation, freshness propagation, context cuts, a CultCache store seam, and the native `epiphany-memory-graph` status/validate/context/smoke CLI. Do not add repo scanners, sleep runners, Qdrant cache plumbing, CultNet advertisement, or prompt integration before routing them through this shared substrate.
- Keep the landed Phase 6 coordinator, limited safe-boundary CRRC automation, and pre-compaction checkpoint intervention ready for the next bridge-equipped dogfood run.
- Preserve the Ghostlight-derived heartbeat initiative seam: every lane, including coordinator/Self and Persona, has a organ-state record and competes for heartbeat slots through readiness/reaction timing; initiative heat can raise or cool global, group, arena, role, and agent tempo through typed heartbeat policy; active thinking freezes initiative until completion, so heat never queues a lane already mid-turn; idle winners ruminate instead of inventing project work, and sleep windows distill the accumulated thought pressure into reviewed self-memory or doctrine.

View file

@ -6,28 +6,25 @@ 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;
use epiphany_codex_bridge::protocol_edge::core_epiphany_view_needs_jobs;
use epiphany_codex_bridge::protocol_edge::core_epiphany_view_needs_pressure;
use epiphany_codex_bridge::protocol_edge::core_epiphany_view_needs_reorientation_inputs;
use epiphany_codex_bridge::protocol_edge::core_epiphany_view_needs_runtime_store;
use epiphany_codex_bridge::protocol_edge::default_core_epiphany_view_lenses;
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_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;
use epiphany_codex_bridge::view_protocol::EpiphanyViewResponseInput;
use epiphany_codex_bridge::view_protocol::map_epiphany_freshness_response;
use epiphany_codex_bridge::view_protocol::map_epiphany_reorient_result_response;
use epiphany_codex_bridge::view_protocol::map_epiphany_role_result_response;
use epiphany_codex_bridge::view_protocol::map_epiphany_view_response;
use epiphany_codex_bridge::view_protocol::map_thread_epiphany_context_response;
use epiphany_codex_bridge::view_protocol::map_thread_epiphany_distill_response;
use epiphany_codex_bridge::view_protocol::map_thread_epiphany_graph_query_response;
use epiphany_codex_bridge::view_protocol::map_thread_epiphany_propose_response;
use epiphany_codex_bridge::view_protocol::map_thread_epiphany_role_result_response;
use super::CodexMessageProcessor;
use super::ConnectionRequestId;
@ -149,23 +146,7 @@ impl CodexMessageProcessor {
request_id: ConnectionRequestId,
params: ThreadEpiphanyRoleResultParams,
) {
let ThreadEpiphanyRoleResultParams {
thread_id,
role_id,
binding_id,
} = params;
let core_role_id = protocol_role_id_to_core(role_id);
let binding_id = match binding_id {
Some(binding_id) => binding_id,
None => match epiphany_role_binding_id(core_role_id) {
Ok(binding_id) => binding_id.to_string(),
Err(message) => {
self.send_invalid_request_error(request_id, message).await;
return;
}
},
};
let thread_id = params.thread_id.clone();
let thread_uuid = match ThreadId::from_string(&thread_id) {
Ok(id) => id,
@ -188,31 +169,31 @@ impl CodexMessageProcessor {
return;
}
};
let source = if loaded_thread.is_some() {
EpiphanySurfaceSource::Live
} else {
EpiphanySurfaceSource::Stored
};
if let Err(message) = epiphany_role_binding_id(core_role_id) {
self.send_invalid_request_error(request_id, message).await;
return;
}
let loaded = loaded_thread.is_some();
let runtime_store_path = if let Some(loaded_thread) = loaded_thread.as_ref() {
Some(loaded_thread.epiphany_runtime_spine_store_path().await)
} else {
None
};
let response = map_epiphany_role_result_response(EpiphanyRoleResultResponseInput {
thread_id: thread_uuid.to_string(),
role_id: core_role_id,
source,
binding_id,
state: thread.epiphany_state.as_ref(),
runtime_store_path: runtime_store_path.as_deref(),
})
.await;
let response = match map_thread_epiphany_role_result_response(
params,
loaded,
thread.epiphany_state.as_ref(),
runtime_store_path.as_deref(),
)
.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, err.to_string()).await;
return;
}
};
self.outgoing.send_response(request_id, response).await;
}