diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index ad0c0188..fcf09966 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -184,6 +184,7 @@ pub use surfaces::EpiphanyReorientAcceptanceFinding; pub use surfaces::EpiphanyReorientAction; pub use surfaces::EpiphanyReorientCheckpointStatus; pub use surfaces::EpiphanyReorientDecision; +pub use surfaces::EpiphanyReorientFindingInterpretation; pub use surfaces::EpiphanyReorientFreshnessStatus; pub use surfaces::EpiphanyReorientInput; pub use surfaces::EpiphanyReorientPressureLevel; @@ -228,6 +229,7 @@ pub use surfaces::derive_pressure_view; pub use surfaces::derive_role_board; pub use surfaces::derive_scene; pub use surfaces::imagination_role_state_patch_policy_errors; +pub use surfaces::interpret_reorient_finding; pub use surfaces::interpret_role_finding; pub use surfaces::modeling_role_state_patch_policy_errors; pub use surfaces::recommend_coordinator_action; diff --git a/epiphany-core/src/surfaces/mod.rs b/epiphany-core/src/surfaces/mod.rs index bbfc32f7..8ab2f66a 100644 --- a/epiphany-core/src/surfaces/mod.rs +++ b/epiphany-core/src/surfaces/mod.rs @@ -92,6 +92,7 @@ pub use role_board::role_board_job_status_to_role_status; pub use role_result::EpiphanyAcceptanceBundle; pub use role_result::EpiphanyReorientAcceptanceBundle; pub use role_result::EpiphanyReorientAcceptanceFinding; +pub use role_result::EpiphanyReorientFindingInterpretation; pub use role_result::EpiphanyRoleAcceptanceFinding; pub use role_result::EpiphanyRoleFindingInterpretation; pub use role_result::EpiphanyRoleResultRoleId; @@ -100,6 +101,7 @@ pub use role_result::EpiphanyRoleSelfPersistenceStatus; pub use role_result::build_reorient_acceptance_bundle; pub use role_result::build_role_acceptance_bundle; pub use role_result::imagination_role_state_patch_policy_errors; +pub use role_result::interpret_reorient_finding; pub use role_result::interpret_role_finding; pub use role_result::modeling_role_state_patch_policy_errors; pub use role_result::review_role_self_patch; diff --git a/epiphany-core/src/surfaces/role_result.rs b/epiphany-core/src/surfaces/role_result.rs index 999586c1..a11d23d8 100644 --- a/epiphany-core/src/surfaces/role_result.rs +++ b/epiphany-core/src/surfaces/role_result.rs @@ -68,6 +68,22 @@ pub struct EpiphanyReorientAcceptanceFinding { pub runtime_job_id: Option, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EpiphanyReorientFindingInterpretation { + pub mode: Option, + pub summary: Option, + pub next_safe_move: Option, + pub checkpoint_still_valid: Option, + pub files_inspected: Vec, + pub frontier_node_ids: Vec, + pub evidence_ids: Vec, + pub artifact_refs: Vec, + pub runtime_result_id: Option, + pub runtime_job_id: Option, + pub job_error: Option, + pub item_error: Option, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct EpiphanyAcceptanceBundle { pub accepted_receipt_id: String, @@ -147,6 +163,29 @@ pub fn interpret_role_finding( } } +pub fn interpret_reorient_finding( + raw_result: &serde_json::Value, + job_error: Option, + item_error: Option, +) -> EpiphanyReorientFindingInterpretation { + EpiphanyReorientFindingInterpretation { + mode: json_string_field(raw_result, "mode"), + summary: json_string_field(raw_result, "summary"), + next_safe_move: json_string_field(raw_result, "nextSafeMove"), + checkpoint_still_valid: raw_result + .get("checkpointStillValid") + .and_then(serde_json::Value::as_bool), + files_inspected: json_string_array_field(raw_result, "filesInspected"), + frontier_node_ids: json_string_array_field(raw_result, "frontierNodeIds"), + evidence_ids: json_string_array_field(raw_result, "evidenceIds"), + artifact_refs: json_string_array_field(raw_result, "artifactRefs"), + runtime_result_id: json_string_field(raw_result, "runtimeResultId"), + runtime_job_id: json_string_field(raw_result, "runtimeJobId"), + job_error, + item_error, + } +} + pub fn build_role_acceptance_bundle( binding_id: &str, role: EpiphanyRoleAcceptanceFinding, @@ -1074,6 +1113,31 @@ mod tests { assert_eq!(finding.runtime_result_id.as_deref(), Some("result-1")); } + #[test] + fn projects_reorient_structured_output() { + let finding = interpret_reorient_finding( + &serde_json::json!({ + "mode": "resume", + "summary": "Checkpoint is still warm.", + "nextSafeMove": "Continue the bounded cut.", + "checkpointStillValid": true, + "filesInspected": ["state/map.yaml"], + "frontierNodeIds": ["node-1"], + "evidenceIds": ["ev-1"], + "artifactRefs": ["artifact:reorient"], + "runtimeResultId": "result-1", + "runtimeJobId": "job-1" + }), + None, + None, + ); + + assert_eq!(finding.mode.as_deref(), Some("resume")); + assert_eq!(finding.checkpoint_still_valid, Some(true)); + assert_eq!(finding.frontier_node_ids, vec!["node-1"]); + assert_eq!(finding.runtime_job_id.as_deref(), Some("job-1")); + } + #[test] fn reviews_acceptable_self_patch() { let finding = interpret_role_finding( diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index dada2c88..314fb9e5 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -32,7 +32,7 @@ remembers doctrine; the branch remembers the blade. ## Current Orientation - Do not copy exact branch or HEAD from this note. Run `git status --short --branch` and `git log --oneline -5`. -- Top priority is still foundation cleanup until the documented rebuild audit is closed. Read `notes/epiphany-architectural-teardown.md` before touching Epiphany control-plane code. The May 2026 suspicion pass found that the app-server Epiphany control plane had become architectural Jenga: too much policy, projection, lifecycle glue, prompt packet assembly, coordinator sequencing, and test authority lives in `vendor/codex/codex-rs/app-server/src/codex_message_processor.rs`. The rebuild has moved scene projection, freshness derivation, pressure policy, targeted context shards, bounded graph traversal, job/progress view derivation, planning view derivation, reorientation resume/regather verdict policy, pure CRRC recommendation policy, fixed-lane coordinator decision policy, role-board projection policy, role-result interpretation/self-persistence review policy, and role/reorient acceptance bundle policy into `epiphany-core`; typed acceptance receipts replaced summary-string identity for live accept paths, runtime links are dual-written on launch, and result read-back now prefers runtime links. +- Top priority is still foundation cleanup until the documented rebuild audit is closed. Read `notes/epiphany-architectural-teardown.md` before touching Epiphany control-plane code. The May 2026 suspicion pass found that the app-server Epiphany control plane had become architectural Jenga: too much policy, projection, lifecycle glue, prompt packet assembly, coordinator sequencing, and test authority lives in `vendor/codex/codex-rs/app-server/src/codex_message_processor.rs`. The rebuild has moved scene projection, freshness derivation, pressure policy, targeted context shards, bounded graph traversal, job/progress view derivation, planning view derivation, reorientation resume/regather verdict policy, pure CRRC recommendation policy, fixed-lane coordinator decision policy, role-board projection policy, role/reorient result interpretation, role self-persistence review policy, and role/reorient acceptance bundle policy into `epiphany-core`; typed acceptance receipts replaced summary-string identity for live accept paths, runtime links are dual-written on launch, and result read-back now prefers runtime links. - Read `notes/epiphany-ideal-architecture-rebuild-plan.md` immediately after the teardown. It defines the smallest coherent replacement architecture: durable `EpiphanyState`, runtime-spine-owned `RuntimeState`, separate role memory/heartbeat state, `epiphany-core` as policy owner, app-server as adapter, Aquarium as reflector, typed acceptance receipts, and derived view lenses instead of a protocol verb zoo. - Do not continue Aquarium UI, bridge, Face, or dogfood expansion until the teardown has a source-grounded cleanup slice plan. Epiphany is the foundation; patches on patches are not a purification rite, they are how the altar becomes load-bearing garbage. - Phase 1 through Phase 5 are complete enough. @@ -369,7 +369,7 @@ Phase 6 bridge/UI trail. Landed rebuild cuts: `epiphany-core/src/surfaces/` exists, pressure view derivation/tests, pure CRRC recommendation policy/tests, fixed-lane coordinator decision policy/tests, role-board projection policy/tests, role-result interpretation/self-persistence review policy/tests, and role/reorient -acceptance bundle policy/tests, scene projection/tests, freshness derivation/tests, targeted context and graph traversal derivation/tests, planning view derivation/tests, reorientation resume/regather verdict policy/tests, and job/progress view derivation/tests live in core, live acceptance writes typed receipts keyed by runtime result id, +acceptance bundle policy/tests, scene projection/tests, freshness derivation/tests, targeted context and graph traversal derivation/tests, planning view derivation/tests, reorientation resume/regather verdict policy/tests, role/reorient result interpretation/tests, and job/progress view derivation/tests live in core, live acceptance writes typed receipts keyed by runtime result id, summary-string acceptance identity is gone for live paths, launches dual-write runtime links, result read-back prefers those runtime links, normal public `raw_result` is sealed, MVP consumers use `thread/epiphany/view`, heartbeat diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index c899a59b..3237cad6 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index 2d761394..822226e5 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -272,5 +272,5 @@ rejected_paths: reason: persistent state that accumulates every local truth becomes memory cruft and weakens rehydration current_status: - summary: Phase 1 durable state through Phase 6 coordinator/specialist/CRRC/backend organs are landed, and the May 2026 rebuild has cut the main app-server control-plane tumor down to routing/adaptation for the documented MVP surfaces. Scene projection, freshness derivation, pressure, targeted context, bounded graph traversal, job/progress view derivation, planning view derivation, reorientation resume/regather verdicts, CRRC, coordinator, role-board, role-result interpretation/self-persistence review, and role/reorient acceptance bundle policy now live in `epiphany-core`; live duplicate-acceptance checks use runtime result receipt identity instead of summary strings; launch writes durable `runtime_links`; role/reorient result read-back follows runtime links; and `jobBindings` no longer store launcher/backend/progress lifecycle fields. + summary: Phase 1 durable state through Phase 6 coordinator/specialist/CRRC/backend organs are landed, and the May 2026 rebuild has cut the main app-server control-plane tumor down to routing/adaptation for the documented MVP surfaces. Scene projection, freshness derivation, pressure, targeted context, bounded graph traversal, job/progress view derivation, planning view derivation, reorientation resume/regather verdicts, CRRC, coordinator, role-board, role/reorient result interpretation, role self-persistence review, and role/reorient acceptance bundle policy now live in `epiphany-core`; live duplicate-acceptance checks use runtime result receipt identity instead of summary strings; launch writes durable `runtime_links`; role/reorient result read-back follows runtime links; and `jobBindings` no longer store launcher/backend/progress lifecycle fields. next_action: Audit the remaining success criteria in `notes/epiphany-ideal-architecture-rebuild-plan.md` after the context/graph extraction commit. If no app-server-owned Epiphany policy cluster remains in the documented migration scope, mark the rebuild migration complete enough to defend, commit the persistence update, and only then resume outward Aquarium/bridge/Face/dogfood expansion. diff --git a/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs b/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs index b5d2300f..fe59dff7 100644 --- a/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs +++ b/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs @@ -543,6 +543,7 @@ use epiphany_core::EpiphanyPressureStatus as CoreEpiphanyPressureStatus; use epiphany_core::EpiphanyReorientAcceptanceFinding; use epiphany_core::EpiphanyReorientAction as CoreEpiphanyReorientAction; use epiphany_core::EpiphanyReorientCheckpointStatus as CoreEpiphanyReorientCheckpointStatus; +use epiphany_core::EpiphanyReorientFindingInterpretation; use epiphany_core::EpiphanyReorientFreshnessStatus as CoreEpiphanyReorientFreshnessStatus; use epiphany_core::EpiphanyReorientInput; use epiphany_core::EpiphanyReorientPressureLevel as CoreEpiphanyReorientPressureLevel; @@ -589,6 +590,7 @@ use epiphany_core::derive_pressure_view; use epiphany_core::derive_role_board; use epiphany_core::derive_scene; use epiphany_core::imagination_role_state_patch_policy_errors; +use epiphany_core::interpret_reorient_finding; use epiphany_core::interpret_role_finding; use epiphany_core::modeling_role_state_patch_policy_errors; use epiphany_core::recommend_coordinator_action; @@ -13295,21 +13297,29 @@ fn map_epiphany_reorient_finding( job_error: Option, item_error: Option, ) -> ThreadEpiphanyReorientFinding { - ThreadEpiphanyReorientFinding { - mode: json_string_field(&raw_result, "mode"), - summary: json_string_field(&raw_result, "summary"), - next_safe_move: json_string_field(&raw_result, "nextSafeMove"), - checkpoint_still_valid: raw_result - .get("checkpointStillValid") - .and_then(serde_json::Value::as_bool), - files_inspected: json_string_array_field(&raw_result, "filesInspected"), - frontier_node_ids: json_string_array_field(&raw_result, "frontierNodeIds"), - evidence_ids: json_string_array_field(&raw_result, "evidenceIds"), - artifact_refs: json_string_array_field(&raw_result, "artifactRefs"), - runtime_result_id: json_string_field(&raw_result, "runtimeResultId"), - runtime_job_id: json_string_field(&raw_result, "runtimeJobId"), + map_protocol_reorient_finding(interpret_reorient_finding( + &raw_result, job_error, item_error, + )) +} + +fn map_protocol_reorient_finding( + finding: EpiphanyReorientFindingInterpretation, +) -> ThreadEpiphanyReorientFinding { + ThreadEpiphanyReorientFinding { + mode: finding.mode, + summary: finding.summary, + next_safe_move: finding.next_safe_move, + checkpoint_still_valid: finding.checkpoint_still_valid, + files_inspected: finding.files_inspected, + frontier_node_ids: finding.frontier_node_ids, + evidence_ids: finding.evidence_ids, + artifact_refs: finding.artifact_refs, + runtime_result_id: finding.runtime_result_id, + runtime_job_id: finding.runtime_job_id, + job_error: finding.job_error, + item_error: finding.item_error, } } @@ -13422,13 +13432,6 @@ fn epiphany_imagination_finding_has_reviewable_state_patch( .is_some_and(|patch| imagination_role_accept_patch_errors(patch).is_empty()) } -fn json_string_field(value: &serde_json::Value, key: &str) -> Option { - value - .get(key) - .and_then(serde_json::Value::as_str) - .map(str::to_string) -} - fn role_finding_runtime_result_id(finding: &ThreadEpiphanyRoleFinding) -> Option { finding.runtime_result_id.clone() } @@ -13445,20 +13448,6 @@ fn reorient_finding_runtime_job_id(finding: &ThreadEpiphanyReorientFinding) -> O finding.runtime_job_id.clone() } -fn json_string_array_field(value: &serde_json::Value, key: &str) -> Vec { - value - .get(key) - .and_then(serde_json::Value::as_array) - .map(|values| { - values - .iter() - .filter_map(serde_json::Value::as_str) - .map(str::to_string) - .collect() - }) - .unwrap_or_default() -} - fn render_epiphany_role_result_note( role_id: ThreadEpiphanyRoleId, status: ThreadEpiphanyRoleResultStatus,