diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 160669d6..a1b6d4e1 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -1931,6 +1931,13 @@ listing, state extraction, and agent control. Next remove the named variant entirely by making app-server's migration quarantine read raw rollout lines, recognize only `type=epiphany_state`, and strictly decode ordinary Codex lifecycle items needed for rollback-aware migration. +That deletion is complete: Codex `RolloutItem` and every core consumer have no +Epiphany legacy variant. App-server migration alone scans raw JSONL for the +exact old tag, validates typed payloads fail-closed, and combines them with +strictly decoded lifecycle items for rollback-aware recovery. Four migration +tests pass; obsolete core fixtures and its state-model dev dependency are gone. +Next audit app-server `epiphany_automation` and route dispatch for surviving +Codex-owned coordinator or scheduler decisions. ## Immediate Re-entry Instruction diff --git a/notes/native-coordinator-liberation-map.md b/notes/native-coordinator-liberation-map.md index 423f04b5..a2d47f1b 100644 --- a/notes/native-coordinator-liberation-map.md +++ b/notes/native-coordinator-liberation-map.md @@ -342,3 +342,15 @@ The deletion path is narrower: app-server's migration quarantine should read raw rollout lines, recognize only `type=epiphany_state`, decode its payload, and combine those migration records with strictly decoded Codex lifecycle items. Then `LegacyEpiphanyState` can leave Codex protocol and all core consumers. + +That final deletion is complete. `RolloutItem` has no Epiphany variant, and +protocol/core/rollout/state/app-server-protocol contain no legacy-state match. +App-server's migration quarantine reads raw JSONL, recognizes only the exact +historical `type=epiphany_state` tag, validates its payload into native +`EpiphanyStateItem`, and strictly decodes ordinary `RolloutLine` items needed +for turn and rollback semantics. Unknown ordinary lines remain parse failures +for the normal Codex loader; the migration scan ignores them without teaching +Codex global tolerance. Four quarantine tests prove raw-tag recognition, +latest-surviving selection, rollback rejection, and malformed-payload refusal. +Obsolete core legacy fixtures and the final core state-model dev dependency are +deleted. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 82a70699..aa45b1e4 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index 49d168c5..cd1244c1 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -659,4 +659,4 @@ current_status: - Service lifecycle receipt history is now event-only: `load_epiphany_cultmesh_daemon_service_lifecycle_receipts` filters out the `epiphany-local/daemon-service-lifecycle-receipt/latest` mirror, while `load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt` remains the latest-state reader. Focused unit test `service_lifecycle_receipt_history_excludes_latest_mirror` proves two per-receipt writes return exactly two history records and latest points at the second. Fresh smoke `verse-query-lifecycle-history-filter-smoke` and live overview/triage `local-20260618-145632-497-efac6f0d` / `local-20260618-145632-321-867947af` prove compact swarm sights still expose service lifecycle attention plus the present elevated runbook artifact without daemon pokes or service mutation. Do not use a broad unscoped cargo test filter for this check on Windows; it fans out across bin harnesses and hit a broken pipe during this pass. - `epiphany-verse-query seed-compact` is the compact seed receipt for wrappers and read-only rites. The older `seed` command still prints the full local Verse context for explicit debugging, but compact wrapper modes now avoid full `seed`/final `query` readback after the combined overview proof exposed Windows debug stack overflow from full-context serialization pressure. last_completed_repo_swarm_cut: Huginn live-fire has crossed the first real repo Body from Persona pressure to branch-local Hands commit and Soul/Mind closure, and now has repeatable closure and redacted-public-proof mouths. On `E:\Projects\Huginn` branch `epiphany/huginn/first-awakening`, `tools/epiphany_local_run.ps1 -Mode repo-persona-intake` accepted item `huginn-inspection-readback-livefire`, Weksa/Persona intake remained sealed, and `epiphany-work derive-plan` lowered it to model-authored safe family `repo.status_section` for `README.md` only. `tools/epiphany_local_run.ps1 -Mode repo-swarm-run` advanced four bounded pulses: run-from-plan, adopt-from-plan, execute-from-plan, and close-from-execute. Huginn commit `e9b07c38fceabbdc89ea35c2156326c80c0393a2` updated only `README.md`; closure receipt `.epiphany\work\work-close-huginn-inspection-readback-livefire.json` records status `closed`, Soul verdict `passed`, Mind state commit `repo-work-close-huginn-inspection-readback-livefire-mind-commit`, safe family `repo.status_section`, path scope `README.md`, Bifrost publication gate, and `privateStateExposed=false`. Verification also ran Huginn's TypeScript compiler through concrete Node path: `C:\Program Files\nodejs\node.exe E:\Projects\Huginn\node_modules\typescript\bin\tsc -p tsconfig.json` passed. Native verifier `epiphany-repo-livefire-closure-smoke --workspace E:\Projects\Huginn --item huginn-inspection-readback-livefire --expected-path README.md --expected-family repo.status_section --expected-gate awaiting-publication --expected-blocker bifrost-publication-missing` checks closure receipt, Mind map entry, overview gate/blocker, authority seals, and `git show` changed paths, returning `status=ok`, `soulVerdict=passed`, `publicationGate=Bifrost`, and `privateStateExposed=false`. Wrapper `tools/epiphany_local_run.ps1 -Mode repo-livefire-closure -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exposes the same read-only proof through the local operator mouth; artifact `local-20260621-190156-803-2f85ba15` printed commit, path, gate, blocker, Soul verdict, Mind commit receipt, and `privateStateExposed=False` without push, merge, publication, or target mutation. New wrapper `tools/epiphany_local_run.ps1 -Mode repo-work-public-proof -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exports the redacted proof bundle and repo-local Verse index without publishing; artifact `local-20260621-190645-345-4555b1dc` wrote `.epiphany\public\proof-bundles\repo-work-public-proof-huginn-inspection-readback-livefire.json`, proof id `repo-work-public-proof-huginn-inspection-readback-livefire`, SHA-256 `857545b199f3e37eb06c2e757e5cfc201958e46667bb1f8403fd333a22620f63`, nine artifact rows, zero publication rows, and `privateStateExposed=False`. Gjallar readback `local-20260621-190701-140-b9519ec6` sees the `REPO-WORK-PUBLIC-PROOF` row and action row from Huginn's repo-local Verse with the same SHA-256 while Bifrost publication remains missing. Launcher compact modes are now named compact operator-context modes instead of read-only modes, and `bifrost-public-proof` summaries print item, target public Verse, room, proof SHA-256, review receipts, and credit receipts so publication receipts are auditable without claiming upstream sync. - next_action: Delete `LegacyEpiphanyState` from `RolloutItem` by moving raw-line recognition into app-server's migration quarantine. The quarantine reader should recognize only `type=epiphany_state`, decode that payload fail-closed, strictly decode other lines as normal `RolloutLine` lifecycle items for rollback/turn boundaries, and preserve Codex's existing unknown/malformed parse-error behavior everywhere else. + next_action: Audit vendored app-server `epiphany_automation` and remaining Epiphany route dispatch as possible surviving coordinator/scheduler authority. Native coordinator/status/mutation/read organs now own live state and processes; retain only explicit client compatibility projection/actuation, and delete any automatic Codex turn-boundary or token-pressure behavior that can still decide Epiphany work. diff --git a/vendor/codex/codex-rs/Cargo.lock b/vendor/codex/codex-rs/Cargo.lock index 5fd6d056..43168521 100644 --- a/vendor/codex/codex-rs/Cargo.lock +++ b/vendor/codex/codex-rs/Cargo.lock @@ -2394,7 +2394,6 @@ dependencies = [ "dirs", "dunce", "env-flags", - "epiphany-state-model", "eventsource-stream", "futures", "http 1.4.0", diff --git a/vendor/codex/codex-rs/app-server-protocol/src/protocol/thread_history.rs b/vendor/codex/codex-rs/app-server-protocol/src/protocol/thread_history.rs index c6036d1e..c6090dbe 100644 --- a/vendor/codex/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/vendor/codex/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -232,9 +232,7 @@ impl ThreadHistoryBuilder { RolloutItem::EventMsg(event) => self.handle_event(event), RolloutItem::Compacted(payload) => self.handle_compacted(payload), RolloutItem::ResponseItem(item) => self.handle_response_item(item), - RolloutItem::TurnContext(_) - | RolloutItem::LegacyEpiphanyState(_) - | RolloutItem::SessionMeta(_) => {} + RolloutItem::TurnContext(_) | RolloutItem::SessionMeta(_) => {} } } diff --git a/vendor/codex/codex-rs/app-server/src/codex_message_processor/epiphany_thread_host.rs b/vendor/codex/codex-rs/app-server/src/codex_message_processor/epiphany_thread_host.rs index 5648ca44..ced69416 100644 --- a/vendor/codex/codex-rs/app-server/src/codex_message_processor/epiphany_thread_host.rs +++ b/vendor/codex/codex-rs/app-server/src/codex_message_processor/epiphany_thread_host.rs @@ -1,16 +1,12 @@ -use std::path::Path; - -use super::legacy_epiphany_rollout::latest_legacy_epiphany_state; +pub(super) use super::legacy_epiphany_rollout::load_epiphany_state_from_rollout_path; use codex_core::CodexThread; -use codex_core::RolloutRecorder; -use epiphany_state_model::EpiphanyThreadState; -use codex_protocol::protocol::InitialHistory; use codex_protocol::protocol::TokenUsageInfo; use epiphany_codex_bridge::mutation_service::EpiphanyMutationHost; use epiphany_codex_bridge::mutation_service::load_authoritative_accepted_state; use epiphany_codex_bridge::pressure::EpiphanyTokenUsageSnapshot; use epiphany_codex_bridge::state::client_visible_epiphany_state_for_paths; use epiphany_codex_bridge::state::thread_state_mirror_id_from_rollout_path; +use epiphany_state_model::EpiphanyThreadState; pub(super) struct EpiphanyCodexThreadHost<'a> { thread: &'a CodexThread, @@ -55,24 +51,6 @@ impl EpiphanyMutationHost for EpiphanyCodexThreadHost<'_> { } } -pub(super) async fn load_epiphany_state_from_rollout_path( - rollout_path: &Path, -) -> std::result::Result, String> { - let items = match RolloutRecorder::get_rollout_history(rollout_path) - .await - .map_err(|err| { - format!( - "failed to load rollout `{}` for Epiphany state: {err}", - rollout_path.display() - ) - })? { - InitialHistory::New | InitialHistory::Cleared => Vec::new(), - InitialHistory::Forked(items) => items, - InitialHistory::Resumed(resumed) => resumed.history, - }; - latest_legacy_epiphany_state(&items) -} - pub(super) async fn live_thread_epiphany_state( thread: &CodexThread, ) -> Option { diff --git a/vendor/codex/codex-rs/app-server/src/codex_message_processor/legacy_epiphany_rollout.rs b/vendor/codex/codex-rs/app-server/src/codex_message_processor/legacy_epiphany_rollout.rs index acedf8f4..4279190e 100644 --- a/vendor/codex/codex-rs/app-server/src/codex_message_processor/legacy_epiphany_rollout.rs +++ b/vendor/codex/codex-rs/app-server/src/codex_message_processor/legacy_epiphany_rollout.rs @@ -1,7 +1,16 @@ +use std::path::Path; + use codex_protocol::models::ResponseItem; -use epiphany_state_model::EpiphanyThreadState; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::RolloutItem; +use codex_protocol::protocol::RolloutLine; +use epiphany_state_model::EpiphanyStateItem; +use epiphany_state_model::EpiphanyThreadState; + +enum LegacyReplayItem { + Codex(RolloutItem), + Epiphany(EpiphanyStateItem), +} #[derive(Default)] struct LegacySegment { @@ -28,8 +37,8 @@ fn is_out_of_band(segment: &LegacySegment) -> bool { segment.turn_id.is_none() && !segment.user_turn && segment.state.is_some() } -pub(super) fn latest_legacy_epiphany_state( - items: &[RolloutItem], +fn latest_legacy_epiphany_state( + items: &[LegacyReplayItem], ) -> Result, String> { let mut state = None; let mut rollbacks = 0usize; @@ -46,15 +55,15 @@ pub(super) fn latest_legacy_epiphany_state( } match item { - RolloutItem::EventMsg(EventMsg::ThreadRolledBack(event)) => { + LegacyReplayItem::Codex(RolloutItem::EventMsg(EventMsg::ThreadRolledBack(event))) => { rollbacks = rollbacks .saturating_add(usize::try_from(event.num_turns).unwrap_or(usize::MAX)); } - RolloutItem::EventMsg(EventMsg::TurnComplete(event)) => { + LegacyReplayItem::Codex(RolloutItem::EventMsg(EventMsg::TurnComplete(event))) => { let segment = segment.get_or_insert_with(LegacySegment::default); segment.turn_id.get_or_insert_with(|| event.turn_id.clone()); } - RolloutItem::EventMsg(EventMsg::TurnAborted(event)) => { + LegacyReplayItem::Codex(RolloutItem::EventMsg(EventMsg::TurnAborted(event))) => { if let Some(turn_id) = &event.turn_id { segment .get_or_insert_with(LegacySegment::default) @@ -62,17 +71,16 @@ pub(super) fn latest_legacy_epiphany_state( .get_or_insert_with(|| turn_id.clone()); } } - RolloutItem::EventMsg(EventMsg::UserMessage(_)) => { + LegacyReplayItem::Codex(RolloutItem::EventMsg(EventMsg::UserMessage(_))) => { segment.get_or_insert_with(LegacySegment::default).user_turn = true; } - RolloutItem::ResponseItem(ResponseItem::Message { role, .. }) if role == "user" => { + LegacyReplayItem::Codex(RolloutItem::ResponseItem(ResponseItem::Message { + role, + .. + })) if role == "user" => { segment.get_or_insert_with(LegacySegment::default).user_turn = true; } - RolloutItem::LegacyEpiphanyState(payload) => { - let item: epiphany_state_model::EpiphanyStateItem = - serde_json::from_value(payload.clone()).map_err(|error| { - format!("invalid legacy Epiphany rollout payload: {error}") - })?; + LegacyReplayItem::Epiphany(item) => { let segment = segment.get_or_insert_with(LegacySegment::default); if segment.turn_id.is_none() { segment.turn_id = item.turn_id.clone(); @@ -83,7 +91,7 @@ pub(super) fn latest_legacy_epiphany_state( segment.state = Some(item.state.clone()); } } - RolloutItem::EventMsg(EventMsg::TurnStarted(event)) => { + LegacyReplayItem::Codex(RolloutItem::EventMsg(EventMsg::TurnStarted(event))) => { if segment.as_ref().is_some_and(|segment| { compatible(segment.turn_id.as_deref(), Some(event.turn_id.as_str())) }) && let Some(segment) = segment.take() @@ -91,11 +99,7 @@ pub(super) fn latest_legacy_epiphany_state( finish(segment, &mut state, &mut rollbacks); } } - RolloutItem::ResponseItem(_) - | RolloutItem::EventMsg(_) - | RolloutItem::Compacted(_) - | RolloutItem::TurnContext(_) - | RolloutItem::SessionMeta(_) => {} + LegacyReplayItem::Codex(_) => {} } } @@ -105,15 +109,49 @@ pub(super) fn latest_legacy_epiphany_state( Ok(state) } +pub(super) async fn load_epiphany_state_from_rollout_path( + path: &Path, +) -> Result, String> { + let text = tokio::fs::read_to_string(path) + .await + .map_err(|error| format!("failed to read rollout `{}`: {error}", path.display()))?; + let mut items = Vec::new(); + for line in text.lines().filter(|line| !line.trim().is_empty()) { + if let Some(item) = parse_replay_line(line)? { + items.push(item); + } + } + latest_legacy_epiphany_state(&items) +} + +fn parse_replay_line(line: &str) -> Result, String> { + let Ok(value) = serde_json::from_str::(line) else { + return Ok(None); + }; + if value.get("type").and_then(serde_json::Value::as_str) == Some("epiphany_state") { + let payload = value + .get("payload") + .cloned() + .ok_or_else(|| "legacy Epiphany rollout item is missing payload".to_string())?; + let item = serde_json::from_value(payload) + .map_err(|error| format!("invalid legacy Epiphany rollout payload: {error}"))?; + Ok(Some(LegacyReplayItem::Epiphany(item))) + } else { + Ok(serde_json::from_value::(value) + .ok() + .map(|line| LegacyReplayItem::Codex(line.item))) + } +} + #[cfg(test)] mod tests { use super::*; use codex_protocol::config_types::ModeKind; - use epiphany_state_model::EpiphanyStateItem; use codex_protocol::protocol::ThreadRolledBackEvent; use codex_protocol::protocol::TurnCompleteEvent; use codex_protocol::protocol::TurnStartedEvent; use codex_protocol::protocol::UserMessageEvent; + use epiphany_state_model::EpiphanyStateItem; fn state(id: &str) -> EpiphanyThreadState { EpiphanyThreadState { @@ -123,34 +161,37 @@ mod tests { } } - fn turn(id: &str, state: EpiphanyThreadState) -> Vec { + fn turn(id: &str, state: EpiphanyThreadState) -> Vec { vec![ - RolloutItem::EventMsg(EventMsg::TurnStarted(TurnStartedEvent { - turn_id: id.to_string(), - started_at: None, - model_context_window: None, - collaboration_mode_kind: ModeKind::Default, - })), - RolloutItem::EventMsg(EventMsg::UserMessage(UserMessageEvent { - message: id.to_string(), - images: None, - local_images: Vec::new(), - text_elements: Vec::new(), - })), - RolloutItem::LegacyEpiphanyState( - serde_json::to_value(EpiphanyStateItem { - turn_id: Some(id.to_string()), - state, - }) - .expect("serialize legacy Epiphany payload"), - ), - RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent { - turn_id: id.to_string(), - last_agent_message: None, - completed_at: None, - duration_ms: None, - time_to_first_token_ms: None, - })), + LegacyReplayItem::Codex(RolloutItem::EventMsg(EventMsg::TurnStarted( + TurnStartedEvent { + turn_id: id.to_string(), + started_at: None, + model_context_window: None, + collaboration_mode_kind: ModeKind::Default, + }, + ))), + LegacyReplayItem::Codex(RolloutItem::EventMsg(EventMsg::UserMessage( + UserMessageEvent { + message: id.to_string(), + images: None, + local_images: Vec::new(), + text_elements: Vec::new(), + }, + ))), + LegacyReplayItem::Epiphany(EpiphanyStateItem { + turn_id: Some(id.to_string()), + state, + }), + LegacyReplayItem::Codex(RolloutItem::EventMsg(EventMsg::TurnComplete( + TurnCompleteEvent { + turn_id: id.to_string(), + last_agent_message: None, + completed_at: None, + duration_ms: None, + time_to_first_token_ms: None, + }, + ))), ] } @@ -168,18 +209,43 @@ mod tests { let first = state("one"); let mut items = turn("one", first.clone()); items.extend(turn("two", state("two"))); - items.push(RolloutItem::EventMsg(EventMsg::ThreadRolledBack( - ThreadRolledBackEvent { num_turns: 1 }, + items.push(LegacyReplayItem::Codex(RolloutItem::EventMsg( + EventMsg::ThreadRolledBack(ThreadRolledBackEvent { num_turns: 1 }), ))); assert_eq!(latest_legacy_epiphany_state(&items), Ok(Some(first))); } #[test] fn rejects_malformed_legacy_state_payload() { - let items = vec![RolloutItem::LegacyEpiphanyState(serde_json::json!({ - "turn_id": "not-the-legacy-shape" - }))]; + let line = serde_json::json!({ + "timestamp": "2026-07-12T00:00:00Z", + "type": "epiphany_state", + "payload": { "turn_id": "not-the-legacy-shape" } + }); + assert!(parse_replay_line(&line.to_string()).is_err()); + } - assert!(latest_legacy_epiphany_state(&items).is_err()); + #[test] + fn recognizes_only_the_historical_raw_line_tag() { + let expected = state("raw-line"); + let line = serde_json::json!({ + "timestamp": "2026-07-12T00:00:00Z", + "type": "epiphany_state", + "payload": { + "turn_id": "raw-line", + "state": expected + } + }); + let Some(LegacyReplayItem::Epiphany(item)) = + parse_replay_line(&line.to_string()).expect("parse historical line") + else { + panic!("expected quarantined Epiphany migration item"); + }; + assert_eq!(item.turn_id.as_deref(), Some("raw-line")); + assert_eq!(item.state, state("raw-line")); + + assert!(parse_replay_line(r#"{"type":"future_unknown","payload":{}}"#) + .expect("unknown line should remain nonfatal to migration scan") + .is_none()); } } diff --git a/vendor/codex/codex-rs/core/Cargo.toml b/vendor/codex/codex-rs/core/Cargo.toml index bc718b9f..dac6db37 100644 --- a/vendor/codex/codex-rs/core/Cargo.toml +++ b/vendor/codex/codex-rs/core/Cargo.toml @@ -140,7 +140,6 @@ windows-sys = { version = "0.52", features = [ codex-shell-escalation = { workspace = true } [dev-dependencies] -epiphany-state-model = { path = "../../../../epiphany-state-model" } assert_cmd = { workspace = true } assert_matches = { workspace = true } codex-otel = { workspace = true } diff --git a/vendor/codex/codex-rs/core/src/agent/control.rs b/vendor/codex/codex-rs/core/src/agent/control.rs index b02271f1..7dd464f5 100644 --- a/vendor/codex/codex-rs/core/src/agent/control.rs +++ b/vendor/codex/codex-rs/core/src/agent/control.rs @@ -119,7 +119,6 @@ fn keep_forked_rollout_item(item: &RolloutItem) -> bool { // A forked child gets its own runtime config, including spawned-agent // instructions, so it must establish a fresh context diff baseline. RolloutItem::TurnContext(_) => false, - RolloutItem::LegacyEpiphanyState(_) => true, RolloutItem::Compacted(_) | RolloutItem::EventMsg(_) | RolloutItem::SessionMeta(_) => true, } } diff --git a/vendor/codex/codex-rs/core/src/session/rollout_reconstruction.rs b/vendor/codex/codex-rs/core/src/session/rollout_reconstruction.rs index 00126a3d..965024b8 100644 --- a/vendor/codex/codex-rs/core/src/session/rollout_reconstruction.rs +++ b/vendor/codex/codex-rs/core/src/session/rollout_reconstruction.rs @@ -182,7 +182,6 @@ impl Session { } } } - RolloutItem::LegacyEpiphanyState(_) => {} RolloutItem::EventMsg(EventMsg::TurnStarted(event)) => { // `TurnStarted` is the oldest boundary of the active reverse segment. if active_segment.as_ref().is_some_and(|active_segment| { @@ -275,7 +274,6 @@ impl Session { } RolloutItem::EventMsg(_) | RolloutItem::TurnContext(_) - | RolloutItem::LegacyEpiphanyState(_) | RolloutItem::SessionMeta(_) => {} } } diff --git a/vendor/codex/codex-rs/core/src/session/rollout_reconstruction_tests.rs b/vendor/codex/codex-rs/core/src/session/rollout_reconstruction_tests.rs index 4bb99e38..a865fa49 100644 --- a/vendor/codex/codex-rs/core/src/session/rollout_reconstruction_tests.rs +++ b/vendor/codex/codex-rs/core/src/session/rollout_reconstruction_tests.rs @@ -6,20 +6,12 @@ use codex_protocol::ThreadId; use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseItem; use codex_protocol::protocol::CompactedItem; -use epiphany_state_model::EpiphanyStateItem; -use epiphany_state_model::EpiphanyThreadState; use codex_protocol::protocol::InitialHistory; use codex_protocol::protocol::InterAgentCommunication; use codex_protocol::protocol::ResumedHistory; use pretty_assertions::assert_eq; use std::path::PathBuf; -fn legacy_epiphany_state(item: EpiphanyStateItem) -> RolloutItem { - RolloutItem::LegacyEpiphanyState( - serde_json::to_value(item).expect("serialize legacy Epiphany rollout payload"), - ) -} - fn user_message(text: &str) -> ResponseItem { ResponseItem::Message { id: None, @@ -44,16 +36,6 @@ fn assistant_message(text: &str) -> ResponseItem { } } -fn sample_epiphany_state(id: &str) -> EpiphanyThreadState { - EpiphanyThreadState { - revision: 1, - objective: Some(format!("Objective for {id}")), - active_subgoal_id: Some(format!("subgoal-{id}")), - last_updated_turn_id: Some(id.to_string()), - ..Default::default() - } -} - fn inter_agent_assistant_message(text: &str) -> ResponseItem { let communication = InterAgentCommunication::new( AgentPath::root(), @@ -114,162 +96,6 @@ async fn record_initial_history_resumed_bare_turn_context_does_not_hydrate_previ assert!(session.reference_context_item().await.is_none()); } -#[tokio::test] -async fn record_initial_history_resumed_accepts_legacy_epiphany_state_items() { - let (session, turn_context) = make_session_and_context().await; - let first_context_item = turn_context.to_turn_context_item(); - let first_turn_id = first_context_item - .turn_id - .clone() - .expect("turn context should have turn_id"); - let second_turn_id = "turn-2".to_string(); - let first_epiphany = sample_epiphany_state("turn-1"); - let second_epiphany = sample_epiphany_state("turn-2"); - - let rollout_items = vec![ - RolloutItem::EventMsg(EventMsg::TurnStarted( - codex_protocol::protocol::TurnStartedEvent { - turn_id: first_turn_id.clone(), - started_at: None, - model_context_window: Some(128_000), - collaboration_mode_kind: ModeKind::Default, - }, - )), - RolloutItem::EventMsg(EventMsg::UserMessage( - codex_protocol::protocol::UserMessageEvent { - message: "turn 1 user".to_string(), - images: None, - local_images: Vec::new(), - text_elements: Vec::new(), - }, - )), - RolloutItem::TurnContext(first_context_item), - legacy_epiphany_state(EpiphanyStateItem { - turn_id: Some(first_turn_id.clone()), - state: first_epiphany, - }), - RolloutItem::EventMsg(EventMsg::TurnComplete( - codex_protocol::protocol::TurnCompleteEvent { - turn_id: first_turn_id, - last_agent_message: None, - completed_at: None, - duration_ms: None, - time_to_first_token_ms: None, - }, - )), - RolloutItem::EventMsg(EventMsg::TurnStarted( - codex_protocol::protocol::TurnStartedEvent { - turn_id: second_turn_id.clone(), - started_at: None, - model_context_window: Some(128_000), - collaboration_mode_kind: ModeKind::Default, - }, - )), - RolloutItem::EventMsg(EventMsg::UserMessage( - codex_protocol::protocol::UserMessageEvent { - message: "turn 2 user".to_string(), - images: None, - local_images: Vec::new(), - text_elements: Vec::new(), - }, - )), - legacy_epiphany_state(EpiphanyStateItem { - turn_id: Some(second_turn_id.clone()), - state: second_epiphany.clone(), - }), - RolloutItem::EventMsg(EventMsg::TurnComplete( - codex_protocol::protocol::TurnCompleteEvent { - turn_id: second_turn_id, - last_agent_message: None, - completed_at: None, - duration_ms: None, - time_to_first_token_ms: None, - }, - )), - ]; - - session - .record_initial_history(InitialHistory::Resumed(ResumedHistory { - conversation_id: ThreadId::default(), - history: rollout_items, - rollout_path: PathBuf::from("resumed.jsonl"), - })) - .await; - - let _ = second_epiphany; -} - -#[tokio::test] -async fn record_initial_history_resumed_accepts_out_of_band_epiphany_state_before_first_turn() { - let (session, _turn_context) = make_session_and_context().await; - let epiphany_state = sample_epiphany_state("control-plane-update"); - - session - .record_initial_history(InitialHistory::Resumed(ResumedHistory { - conversation_id: ThreadId::default(), - history: vec![legacy_epiphany_state(EpiphanyStateItem { - turn_id: None, - state: epiphany_state.clone(), - })], - rollout_path: PathBuf::from("resumed.jsonl"), - })) - .await; - - let _ = epiphany_state; -} - -#[tokio::test] -async fn record_initial_history_resumed_accepts_out_of_band_epiphany_state_after_completed_turn() { - let (session, _turn_context) = make_session_and_context().await; - let turn_id = "turn-before-control-plane-update".to_string(); - let turn_state = sample_epiphany_state("turn-before-control-plane-update"); - let control_plane_state = sample_epiphany_state("control-plane-update"); - - session - .record_initial_history(InitialHistory::Resumed(ResumedHistory { - conversation_id: ThreadId::default(), - history: vec![ - RolloutItem::EventMsg(EventMsg::TurnStarted( - codex_protocol::protocol::TurnStartedEvent { - turn_id: turn_id.clone(), - started_at: None, - model_context_window: Some(128_000), - collaboration_mode_kind: ModeKind::Default, - }, - )), - RolloutItem::EventMsg(EventMsg::UserMessage( - codex_protocol::protocol::UserMessageEvent { - message: "before control-plane update".to_string(), - images: None, - local_images: Vec::new(), - text_elements: Vec::new(), - }, - )), - legacy_epiphany_state(EpiphanyStateItem { - turn_id: Some(turn_id.clone()), - state: turn_state, - }), - RolloutItem::EventMsg(EventMsg::TurnComplete( - codex_protocol::protocol::TurnCompleteEvent { - turn_id, - last_agent_message: None, - completed_at: None, - duration_ms: None, - time_to_first_token_ms: None, - }, - )), - legacy_epiphany_state(EpiphanyStateItem { - turn_id: None, - state: control_plane_state.clone(), - }), - ], - rollout_path: PathBuf::from("resumed.jsonl"), - })) - .await; - - let _ = control_plane_state; -} - #[tokio::test] async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lifecycle_turn_with_missing_turn_context_id() { @@ -454,88 +280,6 @@ async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_com ); } -#[tokio::test] -async fn reconstruct_history_ignores_legacy_epiphany_items_during_rollback() { - let (session, turn_context) = make_session_and_context().await; - let first_context_item = turn_context.to_turn_context_item(); - let first_turn_id = first_context_item - .turn_id - .clone() - .expect("turn context should have turn_id"); - let rolled_back_turn_id = "rolled-back-turn".to_string(); - - let rollout_items = vec![ - RolloutItem::EventMsg(EventMsg::TurnStarted( - codex_protocol::protocol::TurnStartedEvent { - turn_id: first_turn_id.clone(), - started_at: None, - model_context_window: Some(128_000), - collaboration_mode_kind: ModeKind::Default, - }, - )), - RolloutItem::EventMsg(EventMsg::UserMessage( - codex_protocol::protocol::UserMessageEvent { - message: "turn 1 user".to_string(), - images: None, - local_images: Vec::new(), - text_elements: Vec::new(), - }, - )), - RolloutItem::TurnContext(first_context_item), - legacy_epiphany_state(EpiphanyStateItem { - turn_id: Some(first_turn_id.clone()), - state: sample_epiphany_state("turn-1"), - }), - RolloutItem::EventMsg(EventMsg::TurnComplete( - codex_protocol::protocol::TurnCompleteEvent { - turn_id: first_turn_id, - last_agent_message: None, - completed_at: None, - duration_ms: None, - time_to_first_token_ms: None, - }, - )), - RolloutItem::EventMsg(EventMsg::TurnStarted( - codex_protocol::protocol::TurnStartedEvent { - turn_id: rolled_back_turn_id.clone(), - started_at: None, - model_context_window: Some(128_000), - collaboration_mode_kind: ModeKind::Default, - }, - )), - RolloutItem::EventMsg(EventMsg::UserMessage( - codex_protocol::protocol::UserMessageEvent { - message: "turn 2 user".to_string(), - images: None, - local_images: Vec::new(), - text_elements: Vec::new(), - }, - )), - legacy_epiphany_state(EpiphanyStateItem { - turn_id: Some(rolled_back_turn_id.clone()), - state: sample_epiphany_state("turn-2"), - }), - RolloutItem::EventMsg(EventMsg::TurnComplete( - codex_protocol::protocol::TurnCompleteEvent { - turn_id: rolled_back_turn_id, - last_agent_message: None, - completed_at: None, - duration_ms: None, - time_to_first_token_ms: None, - }, - )), - RolloutItem::EventMsg(EventMsg::ThreadRolledBack( - codex_protocol::protocol::ThreadRolledBackEvent { num_turns: 1 }, - )), - ]; - - let reconstructed = session - .reconstruct_history_from_rollout(&turn_context, &rollout_items) - .await; - - assert!(reconstructed.previous_turn_settings.is_some()); -} - #[tokio::test] async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_incomplete_turn() { let (session, turn_context) = make_session_and_context().await; @@ -1271,63 +1015,6 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis ); } -#[tokio::test] -async fn reconstruct_history_ignores_legacy_epiphany_items_during_compaction() { - let (session, turn_context) = make_session_and_context().await; - let previous_context_item = turn_context.to_turn_context_item(); - let previous_turn_id = previous_context_item - .turn_id - .clone() - .expect("turn context should have turn_id"); - let epiphany_state = sample_epiphany_state("turn-before-compaction"); - - let rollout_items = vec![ - RolloutItem::EventMsg(EventMsg::TurnStarted( - codex_protocol::protocol::TurnStartedEvent { - turn_id: previous_turn_id.clone(), - started_at: None, - model_context_window: Some(128_000), - collaboration_mode_kind: ModeKind::Default, - }, - )), - RolloutItem::EventMsg(EventMsg::UserMessage( - codex_protocol::protocol::UserMessageEvent { - message: "seed".to_string(), - images: None, - local_images: Vec::new(), - text_elements: Vec::new(), - }, - )), - RolloutItem::TurnContext(previous_context_item), - legacy_epiphany_state(EpiphanyStateItem { - turn_id: Some(previous_turn_id.clone()), - state: epiphany_state.clone(), - }), - RolloutItem::EventMsg(EventMsg::TurnComplete( - codex_protocol::protocol::TurnCompleteEvent { - turn_id: previous_turn_id, - last_agent_message: None, - completed_at: None, - duration_ms: None, - time_to_first_token_ms: None, - }, - )), - RolloutItem::Compacted(CompactedItem { - message: "summary after compaction".to_string(), - replacement_history: Some(vec![assistant_message("summary after compaction")]), - }), - ]; - - let reconstructed = session - .reconstruct_history_from_rollout(&turn_context, &rollout_items) - .await; - - assert_eq!( - reconstructed.history, - vec![assistant_message("summary after compaction")] - ); -} - #[tokio::test] async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_turn_for_compaction_accounting() { diff --git a/vendor/codex/codex-rs/core/src/session/tests.rs b/vendor/codex/codex-rs/core/src/session/tests.rs index 7a72f3c4..8c8b8554 100644 --- a/vendor/codex/codex-rs/core/src/session/tests.rs +++ b/vendor/codex/codex-rs/core/src/session/tests.rs @@ -75,24 +75,6 @@ use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::CompactedItem; use codex_protocol::protocol::ConversationAudioParams; use codex_protocol::protocol::CreditsSnapshot; -use epiphany_state_model::EpiphanyChurnState; -use epiphany_state_model::EpiphanyCodeRef; -use epiphany_state_model::EpiphanyEvidenceRecord; -use epiphany_state_model::EpiphanyGraph; -use epiphany_state_model::EpiphanyGraphCheckpoint; -use epiphany_state_model::EpiphanyGraphEdge; -use epiphany_state_model::EpiphanyGraphFrontier; -use epiphany_state_model::EpiphanyGraphLink; -use epiphany_state_model::EpiphanyGraphNode; -use epiphany_state_model::EpiphanyGraphs; -use epiphany_state_model::EpiphanyInvariant; -use epiphany_state_model::EpiphanyModeKind; -use epiphany_state_model::EpiphanyModeState; -use epiphany_state_model::EpiphanyObservation; -use epiphany_state_model::EpiphanyScratchPad; -use epiphany_state_model::EpiphanyStateItem; -use epiphany_state_model::EpiphanySubgoal; -use epiphany_state_model::EpiphanyThreadState; use codex_protocol::protocol::GranularApprovalConfig; use codex_protocol::protocol::InitialHistory; use codex_protocol::protocol::InterAgentCommunication; @@ -147,12 +129,6 @@ use std::time::Duration as StdDuration; mod guardian_tests; -fn legacy_epiphany_state(item: EpiphanyStateItem) -> RolloutItem { - RolloutItem::LegacyEpiphanyState( - serde_json::to_value(item).expect("serialize legacy Epiphany rollout payload"), - ) -} - #[test] fn codex_session_has_no_epiphany_state_custody() { let session_state = include_str!("../state/session.rs"); @@ -169,262 +145,11 @@ fn codex_session_has_no_epiphany_state_custody() { assert!(!codex_thread.contains("pub async fn epiphany_")); assert!(!core_lib.contains("epiphany_rollout")); assert!(!protocol.contains("pub use epiphany_state_model::")); - assert!(protocol.contains("LegacyEpiphanyState(serde_json::Value)")); - assert!(protocol.contains("#[serde(rename = \"epiphany_state\")]")); + assert!(!protocol.contains("LegacyEpiphanyState")); + assert!(!protocol.contains("epiphany_state")); assert!(!protocol_manifest.contains("epiphany-state-model")); } -fn sample_epiphany_state_for_prompt() -> EpiphanyThreadState { - EpiphanyThreadState { - revision: 7, - objective: Some("Keep the prompt path oriented around the real thread state.".to_string()), - active_subgoal_id: Some("phase2-prompt".to_string()), - subgoals: vec![ - EpiphanySubgoal { - id: "phase2-prompt".to_string(), - title: "Inject the structured state into build_initial_context.".to_string(), - status: "in_progress".to_string(), - summary: Some("Wire a compact developer fragment into the initial prompt bundle.".to_string()), - }, - EpiphanySubgoal { - id: "phase2-tests".to_string(), - title: "Add tests that catch prompt sludge.".to_string(), - status: "pending".to_string(), - summary: Some("Prove inclusion, omission, and bounded rendering.".to_string()), - }, - ], - invariants: vec![ - EpiphanyInvariant { - id: "canon".to_string(), - description: "Prompt text must not silently redefine the durable state.".to_string(), - status: "active".to_string(), - rationale: Some("We want the model reading state, not cosplaying authorship of it.".to_string()), - }, - EpiphanyInvariant { - id: "bounded".to_string(), - description: "The injected summary must stay compact and deterministic.".to_string(), - status: "active".to_string(), - rationale: Some("The whole point is to avoid turning the prompt into another haunted attic.".to_string()), - }, - ], - graphs: EpiphanyGraphs { - architecture: EpiphanyGraph { - nodes: vec![ - EpiphanyGraphNode { - id: "arch-session".to_string(), - title: "Session loop".to_string(), - purpose: "Owns the turn setup and initial prompt bundle.".to_string(), - mechanism: Some("Builds developer/contextual-user fragments before the first model request.".to_string()), - metaphor: Some("The foreman lining tools up before the crew starts swinging.".to_string()), - status: Some("verified".to_string()), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/session/mod.rs"), - start_line: Some(2433), - end_line: Some(2617), - symbol: Some("build_initial_context".to_string()), - note: Some("Phase 2 injection seam".to_string()), - }], - }, - EpiphanyGraphNode { - id: "arch-context".to_string(), - title: "Context fragments".to_string(), - purpose: "Render marked developer and contextual-user fragments.".to_string(), - mechanism: Some("Small typed renderers turn state into bounded prompt sections.".to_string()), - metaphor: Some("The bins on the wall where the right parts live.".to_string()), - status: Some("verified".to_string()), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/context/epiphany_state_instructions.rs"), - start_line: Some(1), - end_line: Some(220), - symbol: Some("EpiphanyStateInstructions".to_string()), - note: Some("New renderer".to_string()), - }], - }, - ], - edges: vec![EpiphanyGraphEdge { - source_id: "arch-session".to_string(), - target_id: "arch-context".to_string(), - kind: "renders".to_string(), - id: Some("edge-session-context".to_string()), - label: Some("injects".to_string()), - mechanism: Some("Calls the Epiphany renderer when thread state exists.".to_string()), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/session/mod.rs"), - start_line: Some(2502), - end_line: Some(2510), - symbol: Some("build_initial_context".to_string()), - note: Some("Epiphany insertion slot".to_string()), - }], - }], - }, - dataflow: EpiphanyGraph { - nodes: vec![ - EpiphanyGraphNode { - id: "flow-state".to_string(), - title: "Epiphany state snapshot".to_string(), - purpose: "Carries durable objective, graph, evidence, and churn state across turns.".to_string(), - mechanism: Some("Lives on SessionState and comes back during resume.".to_string()), - metaphor: Some("The map pinned to the workshop wall so nobody wanders off whistling.".to_string()), - status: Some("verified".to_string()), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/state/session.rs"), - start_line: Some(36), - end_line: Some(121), - symbol: Some("SessionState::epiphany_state".to_string()), - note: Some("Stored thread state".to_string()), - }], - }, - EpiphanyGraphNode { - id: "flow-prompt".to_string(), - title: "Prompt fragment".to_string(), - purpose: "Turns the durable state into a bounded developer instruction block.".to_string(), - mechanism: Some("Summarizes only active and recent state with line-anchored refs.".to_string()), - metaphor: Some("A folded field guide, not the entire filing cabinet.".to_string()), - status: Some("in_progress".to_string()), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/context/epiphany_state_instructions.rs"), - start_line: Some(1), - end_line: Some(220), - symbol: Some("render_epiphany_state".to_string()), - note: Some("Summary shaping".to_string()), - }], - }, - ], - edges: vec![EpiphanyGraphEdge { - source_id: "flow-state".to_string(), - target_id: "flow-prompt".to_string(), - kind: "summarized-as".to_string(), - id: Some("edge-state-prompt".to_string()), - label: Some("bounded summary".to_string()), - mechanism: Some("Keep frontier, evidence, and churn in view without dumping raw JSON.".to_string()), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/context/epiphany_state_instructions.rs"), - start_line: Some(32), - end_line: Some(220), - symbol: Some("render_epiphany_state".to_string()), - note: Some("Prompt shaping".to_string()), - }], - }], - }, - links: vec![EpiphanyGraphLink { - dataflow_node_id: "flow-prompt".to_string(), - architecture_node_id: "arch-context".to_string(), - relationship: Some("implemented-by".to_string()), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/context/epiphany_state_instructions.rs"), - start_line: Some(1), - end_line: Some(220), - symbol: Some("EpiphanyStateInstructions".to_string()), - note: Some("Renderer implementation".to_string()), - }], - }], - }, - graph_frontier: Some(EpiphanyGraphFrontier { - active_node_ids: vec!["arch-session".to_string(), "flow-prompt".to_string()], - active_edge_ids: vec!["edge-session-context".to_string()], - open_question_ids: vec!["q-boundary".to_string()], - open_gap_ids: vec!["gap-resume-proof".to_string()], - dirty_paths: vec![ - PathBuf::from("core/src/session/mod.rs"), - PathBuf::from("core/src/context/epiphany_state_instructions.rs"), - ], - }), - graph_checkpoint: Some(EpiphanyGraphCheckpoint { - checkpoint_id: "phase2-checkpoint".to_string(), - graph_revision: 7, - summary: Some("Prompt integration is the current frontier; GUI and retrieval stay dark.".to_string()), - frontier_node_ids: vec!["arch-session".to_string(), "flow-prompt".to_string()], - open_question_ids: vec!["q-boundary".to_string()], - open_gap_ids: vec!["gap-resume-proof".to_string()], - }), - investigation_checkpoint: None, - job_bindings: Vec::new(), - acceptance_receipts: Vec::new(), - runtime_links: Vec::new(), - scratch: Some(EpiphanyScratchPad { - summary: Some("Inject the state as a developer fragment, not as a user message.".to_string()), - hypothesis: Some("Keeping the block bounded will help resume without making prompt sludge.".to_string()), - next_probe: Some("Verify resumed sessions still inject the latest surviving snapshot.".to_string()), - notes: vec![ - "Do not dump raw JSON.".to_string(), - "Do not invent a public toggle yet.".to_string(), - ], - }), - observations: vec![ - EpiphanyObservation { - id: "obs-session-seam".to_string(), - summary: "build_initial_context already composes developer fragments in one place.".to_string(), - source_kind: "code-read".to_string(), - status: "accepted".to_string(), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/session/mod.rs"), - start_line: Some(2433), - end_line: Some(2617), - symbol: Some("build_initial_context".to_string()), - note: Some("Prompt assembly".to_string()), - }], - evidence_ids: vec!["ev-session-read".to_string()], - }, - EpiphanyObservation { - id: "obs-state-seam".to_string(), - summary: "Phase 1 already restores Epiphany state before future turns build context.".to_string(), - source_kind: "test".to_string(), - status: "accepted".to_string(), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/session/rollout_reconstruction.rs"), - start_line: Some(1), - end_line: Some(220), - symbol: Some("RolloutReconstruction".to_string()), - note: Some("Resume path".to_string()), - }], - evidence_ids: vec!["ev-resume-read".to_string()], - }, - ], - recent_evidence: vec![ - EpiphanyEvidenceRecord { - id: "ev-session-read".to_string(), - kind: "research".to_string(), - status: "ok".to_string(), - summary: "Confirmed the prompt builder already has a clean insertion point after collaboration-mode instructions.".to_string(), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/session/mod.rs"), - start_line: Some(2498), - end_line: Some(2511), - symbol: Some("build_initial_context".to_string()), - note: Some("Insertion window".to_string()), - }], - }, - EpiphanyEvidenceRecord { - id: "ev-resume-read".to_string(), - kind: "test".to_string(), - status: "ok".to_string(), - summary: "Phase 1 tests already prove the latest surviving Epiphany snapshot is restored on resume.".to_string(), - code_refs: vec![EpiphanyCodeRef { - path: PathBuf::from("core/src/session/rollout_reconstruction_tests.rs"), - start_line: Some(110), - end_line: Some(191), - symbol: Some("record_initial_history_resumed_hydrates_epiphany_state_from_latest_surviving_turn".to_string()), - note: Some("Resume proof".to_string()), - }], - }, - ], - churn: Some(EpiphanyChurnState { - understanding_status: "stable".to_string(), - diff_pressure: "low".to_string(), - graph_freshness: Some("fresh".to_string()), - warning: Some("Keep the fragment bounded; do not turn it into another transcript dump.".to_string()), - unexplained_writes: Some(0), - }), - retrieval: None, - mode: Some(EpiphanyModeState { - name: "epiphany".to_string(), - kind: Some(EpiphanyModeKind::Default), - }), - planning: Default::default(), - last_updated_turn_id: Some("phase2-turn".to_string()), - } -} - struct InstructionsTestCase { slug: &'static str, expects_apply_patch_description: bool, @@ -577,10 +302,6 @@ fn developer_input_texts(items: &[ResponseItem]) -> Vec<&str> { .collect() } -fn joined_developer_input_text(items: &[ResponseItem]) -> String { - developer_input_texts(items).join("\n\n") -} - fn user_input_texts(items: &[ResponseItem]) -> Vec<&str> { items .iter() @@ -5152,7 +4873,7 @@ async fn record_context_updates_and_set_reference_context_item_persists_baseline } #[tokio::test] -async fn record_context_updates_does_not_persist_epiphany_state() { +async fn record_context_updates_persists_turn_context() { let (session, turn_context) = make_session_and_context().await; let config = session.get_config().await; let recorder = RolloutRecorder::new( @@ -5195,59 +4916,6 @@ async fn record_context_updates_does_not_persist_epiphany_state() { .iter() .any(|item| matches!(item, RolloutItem::TurnContext(_))) ); - assert!( - !resumed - .history - .iter() - .any(|item| matches!(item, RolloutItem::LegacyEpiphanyState(_))) - ); -} - -#[tokio::test] -async fn record_context_updates_and_set_reference_context_item_skips_epiphany_state_when_none() { - let (session, turn_context) = make_session_and_context().await; - let config = session.get_config().await; - let recorder = RolloutRecorder::new( - config.as_ref(), - RolloutRecorderParams::new( - ThreadId::default(), - /*forked_from_id*/ None, - SessionSource::Exec, - BaseInstructions::default(), - Vec::new(), - EventPersistenceMode::Limited, - ), - /*state_db_ctx*/ None, - /*state_builder*/ None, - ) - .await - .expect("create rollout recorder"); - let rollout_path = recorder.rollout_path().to_path_buf(); - { - let mut rollout = session.services.rollout.lock().await; - *rollout = Some(recorder); - } - - session - .record_context_updates_and_set_reference_context_item(&turn_context) - .await; - session.ensure_rollout_materialized().await; - session.flush_rollout().await.expect("rollout should flush"); - - let InitialHistory::Resumed(resumed) = RolloutRecorder::get_rollout_history(&rollout_path) - .await - .expect("read rollout history") - else { - panic!("expected resumed rollout history"); - }; - - assert!( - !resumed - .history - .iter() - .any(|item| matches!(item, RolloutItem::LegacyEpiphanyState(_))), - "epiphany state should not be persisted when session state is empty" - ); } #[tokio::test] @@ -5323,59 +4991,6 @@ async fn build_initial_context_prepends_model_switch_message() { assert!(text.contains("")); } -#[tokio::test] -async fn build_initial_context_omits_epiphany_state_block_when_absent() { - let (session, turn_context) = make_session_and_context().await; - - let initial_context = session.build_initial_context(&turn_context).await; - let developer_text = joined_developer_input_text(&initial_context); - - assert!(!developer_text.contains("")); -} - -#[tokio::test] -async fn build_initial_context_does_not_inject_resumed_epiphany_state() { - let (session, turn_context) = make_session_and_context().await; - let turn_context_item = turn_context.to_turn_context_item(); - let turn_id = turn_context_item - .turn_id - .clone() - .expect("turn context should have turn_id"); - let epiphany_state = sample_epiphany_state_for_prompt(); - - session - .record_initial_history(InitialHistory::Resumed(ResumedHistory { - conversation_id: ThreadId::default(), - history: vec![ - RolloutItem::EventMsg(EventMsg::TurnStarted(TurnStartedEvent { - turn_id: turn_id.clone(), - started_at: None, - model_context_window: Some(128_000), - collaboration_mode_kind: ModeKind::Default, - })), - RolloutItem::EventMsg(EventMsg::UserMessage(UserMessageEvent { - message: "resume the thread".to_string(), - images: None, - local_images: Vec::new(), - text_elements: Vec::new(), - })), - RolloutItem::TurnContext(turn_context_item), - legacy_epiphany_state(EpiphanyStateItem { - turn_id: Some(turn_id), - state: epiphany_state, - }), - ], - rollout_path: PathBuf::from("/tmp/phase2-resume.jsonl"), - })) - .await; - - let initial_context = session.build_initial_context(&turn_context).await; - let developer_text = joined_developer_input_text(&initial_context); - - assert!(!developer_text.contains("")); - assert!(!developer_text.contains("Checkpoint: `phase2-checkpoint` (graph revision 7)")); -} - #[tokio::test] async fn record_context_updates_and_set_reference_context_item_persists_full_reinjection_to_rollout() { diff --git a/vendor/codex/codex-rs/protocol/src/protocol.rs b/vendor/codex/codex-rs/protocol/src/protocol.rs index 03951cb3..9ba2e4b5 100644 --- a/vendor/codex/codex-rs/protocol/src/protocol.rs +++ b/vendor/codex/codex-rs/protocol/src/protocol.rs @@ -94,8 +94,6 @@ pub const ENVIRONMENT_CONTEXT_OPEN_TAG: &str = ""; pub const ENVIRONMENT_CONTEXT_CLOSE_TAG: &str = ""; pub const COLLABORATION_MODE_OPEN_TAG: &str = ""; pub const COLLABORATION_MODE_CLOSE_TAG: &str = ""; -pub const EPIPHANY_STATE_OPEN_TAG: &str = ""; -pub const EPIPHANY_STATE_CLOSE_TAG: &str = ""; pub const REALTIME_CONVERSATION_OPEN_TAG: &str = ""; pub const REALTIME_CONVERSATION_CLOSE_TAG: &str = ""; pub const USER_MESSAGE_BEGIN: &str = "## My request for Codex:"; @@ -2943,8 +2941,6 @@ pub enum RolloutItem { ResponseItem(ResponseItem), Compacted(CompactedItem), TurnContext(TurnContextItem), - #[serde(rename = "epiphany_state")] - LegacyEpiphanyState(serde_json::Value), EventMsg(EventMsg), } @@ -5103,27 +5099,6 @@ mod tests { Ok(()) } - #[test] - fn legacy_epiphany_state_envelope_preserves_opaque_payload() -> Result<()> { - let payload = json!({ - "turn_id": "turn-123", - "state": { - "revision": 7, - "objective": "historical compatibility only" - } - }); - let item = RolloutItem::LegacyEpiphanyState(payload.clone()); - let encoded = serde_json::to_value(&item)?; - assert_eq!(encoded["type"], "epiphany_state"); - assert_eq!(encoded["payload"], payload); - - let reparsed: RolloutItem = serde_json::from_value(encoded)?; - let RolloutItem::LegacyEpiphanyState(reparsed_payload) = reparsed else { - panic!("expected opaque legacy Epiphany rollout payload"); - }; - assert_eq!(reparsed_payload, payload); - Ok(()) - } /// Serialize Event to verify that its JSON representation has the expected /// amount of nesting. #[test] diff --git a/vendor/codex/codex-rs/rollout/src/list.rs b/vendor/codex/codex-rs/rollout/src/list.rs index a2f12c2a..bdb71988 100644 --- a/vendor/codex/codex-rs/rollout/src/list.rs +++ b/vendor/codex/codex-rs/rollout/src/list.rs @@ -1127,9 +1127,6 @@ async fn read_head_summary(path: &Path, head_limit: usize) -> io::Result { // Not included in `head`; skip. } - RolloutItem::LegacyEpiphanyState(_) => { - // Not included in `head`; skip. - } RolloutItem::Compacted(_) => { // Not included in `head`; skip. } @@ -1186,7 +1183,6 @@ pub async fn read_head_for_summary(path: &Path) -> io::Result {} } } diff --git a/vendor/codex/codex-rs/rollout/src/metadata.rs b/vendor/codex/codex-rs/rollout/src/metadata.rs index b1a159c8..58d55a88 100644 --- a/vendor/codex/codex-rs/rollout/src/metadata.rs +++ b/vendor/codex/codex-rs/rollout/src/metadata.rs @@ -73,7 +73,6 @@ pub fn builder_from_items( RolloutItem::ResponseItem(_) | RolloutItem::Compacted(_) | RolloutItem::TurnContext(_) - | RolloutItem::LegacyEpiphanyState(_) | RolloutItem::EventMsg(_) => None, }) && let Some(builder) = builder_from_session_meta(session_meta, rollout_path) { @@ -128,7 +127,6 @@ pub async fn extract_metadata_from_rollout( RolloutItem::ResponseItem(_) | RolloutItem::Compacted(_) | RolloutItem::TurnContext(_) - | RolloutItem::LegacyEpiphanyState(_) | RolloutItem::EventMsg(_) => None, }), parse_errors, diff --git a/vendor/codex/codex-rs/rollout/src/policy.rs b/vendor/codex/codex-rs/rollout/src/policy.rs index ad067d9e..188e6fb4 100644 --- a/vendor/codex/codex-rs/rollout/src/policy.rs +++ b/vendor/codex/codex-rs/rollout/src/policy.rs @@ -18,7 +18,6 @@ pub fn is_persisted_response_item(item: &RolloutItem, mode: EventPersistenceMode // Persist Codex executive markers so we can analyze flows (e.g., compaction, API turns). RolloutItem::Compacted(_) | RolloutItem::TurnContext(_) - | RolloutItem::LegacyEpiphanyState(_) | RolloutItem::SessionMeta(_) => true, } } diff --git a/vendor/codex/codex-rs/rollout/src/recorder.rs b/vendor/codex/codex-rs/rollout/src/recorder.rs index a88f8a0e..cd93b6d5 100644 --- a/vendor/codex/codex-rs/rollout/src/recorder.rs +++ b/vendor/codex/codex-rs/rollout/src/recorder.rs @@ -880,9 +880,6 @@ impl RolloutRecorder { RolloutItem::TurnContext(item) => { items.push(RolloutItem::TurnContext(item)); } - RolloutItem::LegacyEpiphanyState(item) => { - items.push(RolloutItem::LegacyEpiphanyState(item)); - } RolloutItem::EventMsg(_ev) => { items.push(RolloutItem::EventMsg(_ev)); } @@ -1846,7 +1843,6 @@ async fn resume_candidate_matches_cwd( RolloutItem::SessionMeta(_) | RolloutItem::ResponseItem(_) | RolloutItem::Compacted(_) - | RolloutItem::LegacyEpiphanyState(_) | RolloutItem::EventMsg(_) => None, }) { diff --git a/vendor/codex/codex-rs/state/src/extract.rs b/vendor/codex/codex-rs/state/src/extract.rs index 87915002..580d576a 100644 --- a/vendor/codex/codex-rs/state/src/extract.rs +++ b/vendor/codex/codex-rs/state/src/extract.rs @@ -22,7 +22,7 @@ pub fn apply_rollout_item( RolloutItem::TurnContext(turn_ctx) => apply_turn_context(metadata, turn_ctx), RolloutItem::EventMsg(event) => apply_event_msg(metadata, event), RolloutItem::ResponseItem(item) => apply_response_item(metadata, item), - RolloutItem::Compacted(_) | RolloutItem::LegacyEpiphanyState(_) => {} + RolloutItem::Compacted(_) => {} } if metadata.model_provider.is_empty() { metadata.model_provider = default_provider.to_string(); @@ -38,8 +38,7 @@ pub fn rollout_item_affects_thread_metadata(item: &RolloutItem) -> bool { ) => true, RolloutItem::EventMsg(_) | RolloutItem::ResponseItem(_) - | RolloutItem::Compacted(_) - | RolloutItem::LegacyEpiphanyState(_) => false, + | RolloutItem::Compacted(_) => false, } } diff --git a/vendor/codex/codex-rs/state/src/runtime/threads.rs b/vendor/codex/codex-rs/state/src/runtime/threads.rs index ea42a08d..6c50e7e1 100644 --- a/vendor/codex/codex-rs/state/src/runtime/threads.rs +++ b/vendor/codex/codex-rs/state/src/runtime/threads.rs @@ -973,7 +973,6 @@ pub(super) fn extract_dynamic_tools(items: &[RolloutItem]) -> Option None, }) } @@ -984,7 +983,6 @@ pub(super) fn extract_memory_mode(items: &[RolloutItem]) -> Option { RolloutItem::ResponseItem(_) | RolloutItem::Compacted(_) | RolloutItem::TurnContext(_) - | RolloutItem::LegacyEpiphanyState(_) | RolloutItem::EventMsg(_) => None, }) }