diff --git a/README.md b/README.md index 62371f6a..236f31af 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,10 @@ The current spine is real, not aspirational: - durable `jobBindings` as a thin Epiphany-owned launcher seam over runtime job backends - explicit launch and interrupt authority through `thread/epiphany/jobLaunch` and `thread/epiphany/jobInterrupt`, still backed by runtime `agent_jobs` - a bounded reorient-guided worker launch through `thread/epiphany/reorientLaunch` +- read-only CRRC next-action recommendations through `thread/epiphany/crrc` - live bound-job progress notifications through `thread/epiphany/jobsUpdated` - read-only reflection surfaces through `thread/epiphany/scene`, `jobs`, `freshness`, `context`, `pressure`, and `reorient` +- a first dogfood CLI operator view through `tools/epiphany_mvp_status.py` - durable investigation checkpointing for compaction-safe planning - repo-owned heavy Epiphany organs in `epiphany-core/`, with vendored Codex kept as the host seam where practical diff --git a/notes/epiphany-core-harness-surfaces.md b/notes/epiphany-core-harness-surfaces.md index d6f7c868..ee242755 100644 --- a/notes/epiphany-core-harness-surfaces.md +++ b/notes/epiphany-core-harness-surfaces.md @@ -59,6 +59,7 @@ The rule is: | `thread/epiphany/pressure` | read-only reflection | landed, live-smoked | Context-pressure gauge derived from token telemetry and recorded auto-compact/context limits. | | `thread/epiphany/reorient` | read-only policy reflection | landed, live-smoked | Bounded CRRC reorientation verdict derived from checkpoint, freshness, watcher, and pressure signals; returns resume vs regather without acting on the decision. | | `thread/epiphany/crrc` | read-only coordinator reflection | landed, live-smoked | Composes pressure, reorientation verdict, bound worker status/result, and available actions into one recommendation without launching, accepting, compacting, or mutating state. | +| `tools/epiphany_mvp_status.py` | operator CLI | landed, live-smoked | Starts or reads a thread through app-server and renders scene, pressure, reorient, jobs, result, and CRRC recommendation as a compact dogfood view. | ## Write Authority @@ -180,10 +181,10 @@ Out of scope for the MVP: - a second job backend unless the current `agent_jobs` adapter blocks read-back or interruption -The first read-back, acceptance, and read-only coordinator blockers are landed. -The current MVP blocker is dogfood visibility: exposing scene, pressure, -reorient, jobs, result, and CRRC recommendation in a small operator-facing view -that can be tested during real coding work without reading Rust. +The first read-back, acceptance, read-only coordinator, and dogfood CLI blockers +are landed. The current MVP blocker is role ownership: making implementation, +modeling/checkpoint maintenance, and verification/review visible as distinct +bounded work lanes without building an arbitrary specialist marketplace. ## Job And Progress Surface Direction @@ -233,6 +234,12 @@ worker, wait for worker, review result, accept result, or regather manually. It is not a scheduler, a hidden launch, a hidden accept, a compactor, or a second source of truth. The little tyrant remains theoretical, for now. +The first dogfood operator view is landed as `tools/epiphany_mvp_status.py`. +It starts or reads one thread through the app-server and prints the scene, +pressure, reorientation verdict, jobs, reorient result, and CRRC recommendation +as a compact status report, with raw JSON available when needed. It is a window, +not a source of truth. + The first live bound-runtime progress notification is also landed as `thread/epiphany/jobsUpdated`. It rides existing `agent_job_progress:{json}` background events from the runtime job runner, resolves matching launcher diff --git a/notes/epiphany-current-algorithmic-map.md b/notes/epiphany-current-algorithmic-map.md index cd65b02c..2ca60f69 100644 --- a/notes/epiphany-current-algorithmic-map.md +++ b/notes/epiphany-current-algorithmic-map.md @@ -10,7 +10,7 @@ The important question for this file is not "what is Epiphany supposed to become Current Epiphany is a forked Codex harness with a typed modeling spine. -The spine exists in twenty-two live paths: +The spine exists in twenty-three live paths: - protocol state shape: `EpiphanyThreadState`, `RolloutItem::EpiphanyState`, retrieval summaries, and prompt tags live in [protocol.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/protocol/src/protocol.rs:103). - in-memory session state: `SessionState` stores an optional `EpiphanyThreadState`, and `Session` exposes thin async accessors over it in [state/session.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/core/src/state/session.rs:36) and [session/mod.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/core/src/session/mod.rs:1240). @@ -31,6 +31,7 @@ The spine exists in twenty-two live paths: - context-pressure reflection: core token telemetry carries `model_auto_compact_token_limit` beside total/last usage and `model_context_window`; app-server declares experimental read-only `thread/epiphany/pressure`, reads live token usage or the latest stored rollout `TokenCount`, and derives `unknown`/`low`/`elevated`/`high`/`critical` pressure plus a non-acting compaction-prep recommendation without mutating Epiphany state or scheduling compaction in [protocol.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/protocol/src/protocol.rs:2237), [turn_context.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/core/src/session/turn_context.rs:103), [session/mod.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/core/src/session/mod.rs:2716), [common.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs:360), [v2.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs:4361), [token_usage_replay.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor/token_usage_replay.rs:75), [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:4306), and [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:11028). - reorientation policy: app-server declares experimental read-only `thread/epiphany/reorient`, reuses the same live/stored thread view plus mapped pressure/freshness/watcher signals, and derives a bounded `resume`/`regather` verdict with checkpoint-path/frontier reasons without mutating, compacting, scheduling, notifying, or continuing work in [common.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs:365), [v2.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs:4514), [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:4394), and [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:11424). - CRRC coordinator recommendation: app-server declares experimental read-only `thread/epiphany/crrc`, reuses the same pressure/freshness/watcher/reorientation mapping plus the fixed `reorient-worker` binding and result read-back helper, and returns 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 [common.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs:370), [v2.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs:4661), and [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:4546). +- MVP operator view: `tools/epiphany_mvp_status.py` launches app-server over stdio, starts or reads one thread, gathers scene, pressure, reorient, jobs, reorient result, and CRRC responses, and renders them as text or JSON so the loop can be dogfooded without reading Rust. - reorientation launch: app-server now declares experimental `thread/epiphany/reorientLaunch`, requires a loaded thread plus durable investigation checkpoint, consumes the live reorientation verdict, and launches one fixed `reorient-worker` binding through the existing job-control seam with explicit resume-versus-regather scope, checkpoint-derived payload, and structured-output expectations instead of pretending CRRC suddenly grew a scheduler in [common.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs:370), [v2.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs:4575), and [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:4519). - reorientation result read-back: app-server now declares experimental read-only `thread/epiphany/reorientResult`, defaults to the fixed `reorient-worker` binding, resolves that binding through the current `agent_jobs` backend when available, reads the single backend item result, and projects a reviewable finding with mode, summary, next safe move, checkpoint-validity flag, inspected files, frontier ids, evidence ids, raw result, and any job/item errors without mutating state, promoting evidence, or scheduling follow-up work in [common.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs:374), [v2.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs:4610), and [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:4684). - reorientation finding acceptance: app-server now declares experimental `thread/epiphany/reorientAccept`, requires a loaded thread and a completed `reorient-worker` backend result, appends accepted observation/evidence records, optionally banks the finding into scratch and the durable investigation checkpoint, persists through the normal typed update path, and emits `thread/epiphany/stateUpdated` with source `reorientAccept` without accepting pending work, auto-promoting arbitrary worker output, launching follow-up work, or silently continuing implementation in [common.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/common.rs:378), [v2.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server-protocol/src/protocol/v2.rs:4635), and [codex_message_processor.rs](E:/Projects/EpiphanyAgent/vendor/codex/codex-rs/app-server/src/codex_message_processor.rs:4885). @@ -1335,7 +1336,7 @@ stored Epiphany state -> successful writes emit thread/epiphany/stateUpdated ``` -The current remaining missing organ is not the red pen, not the first chewing motion, not the first state-change bell, not the first client-shaped scene, not the first job/progress reflection, not the first live bound-job notification, not the first freshness lens, not the first watcher-backed invalidation read, not the first targeted graph/evidence context read, not the first context-pressure gauge, not the first durable investigation checkpoint packet, not the first bounded reorientation verdict, not the first thin launcher seam, not the first explicit launch/interrupt authority surface over that seam, not the first runtime consumer that can act on the reorientation verdict without becoming a hidden tyrant, not the first read-back surface for that worker's findings, not the first explicit acceptance write for completed findings, and no longer the first read-only CRRC coordinator recommendation. Those exist. Proposal now has the first bits of map memory, focus, and selection hygiene: it can auto-select a bounded evidence-backed observation cluster when ids are omitted, requires accepting recent evidence behind selected observations, prioritizes stronger selected observations for proposal wording, reuses existing architecture nodes by concrete code-ref/path/id checks before creating new path nodes, can rescue unanchored graph nodes through strict unique semantic overlap, follows graph links and incident edges into the frontier, and reports match-kind-aware churn pressure from the actual proposal shape. Distillation now also has the first source-output-aware teeth for tool/model summaries. Promotion now notices risky deltas instead of just checking the shape of the envelope, treats graph expansion as risky even if the patch tries to mumble "low pressure" while dragging a new wall into the blueprint, token-matches strong verifier kinds so `contest` cannot sneak past as `test`, and validates investigation checkpoints against known evidence before the packet can be inked. Successful update/promote writes now emit `thread/epiphany/stateUpdated` with `source: "update"` or `source: "promote"`, event-level revision, and typed changed fields so clients no longer need to poll blindly, infer the cause from timing, or diff the whole state to know which top-level sections moved. Runtime `agent_job_progress` background events now also emit `thread/epiphany/jobsUpdated` with changed bound-job payloads so clients no longer need to poll `thread/epiphany/jobs` just to watch one real owner move, the bound jobs now reflect launcher id, authority scope, and backend kind/job id instead of treating raw runtime pointers as the architecture, `jobLaunch` / `jobInterrupt` can create or tear down those bindings without pretending reflection is authority, `reorientLaunch` can launch one fixed `reorient-worker` job from the checkpoint verdict without turning the verdict itself into a writer, `reorientResult` can read the worker's structured output back as a reviewable finding without promoting it, `reorientAccept` can explicitly bank a completed finding into typed observation/evidence plus optional scratch/checkpoint state, and `crrc` can recommend the next explicit action over that loop without doing the action itself. The scene, jobs, freshness, context, pressure, reorient, crrc, and reorient-result surfaces give clients compact or bounded read-only views without making the GUI/client authoritative, scene/context surface the checkpoint packet back out without becoming writers, freshness surfaces watcher telemetry without becoming a hidden worker, reorient turns those signals into an explicit wakeup verdict that one explicit launch surface can consume on purpose, and crrc now tells the operator whether to continue, checkpoint, launch, wait, review, accept, or regather manually. The remaining missing organs are a second backend if `agent_jobs` stops being enough, a dogfood-facing operator view over the landed loop, and eventually role-scoped specialist ownership without silently auto-promoting anything. +The current remaining missing organ is not the red pen, not the first chewing motion, not the first state-change bell, not the first client-shaped scene, not the first job/progress reflection, not the first live bound-job notification, not the first freshness lens, not the first watcher-backed invalidation read, not the first targeted graph/evidence context read, not the first context-pressure gauge, not the first durable investigation checkpoint packet, not the first bounded reorientation verdict, not the first thin launcher seam, not the first explicit launch/interrupt authority surface over that seam, not the first runtime consumer that can act on the reorientation verdict without becoming a hidden tyrant, not the first read-back surface for that worker's findings, not the first explicit acceptance write for completed findings, not the first read-only CRRC coordinator recommendation, and no longer the first dogfood-facing operator view over the landed loop. Those exist. Proposal now has the first bits of map memory, focus, and selection hygiene: it can auto-select a bounded evidence-backed observation cluster when ids are omitted, requires accepting recent evidence behind selected observations, prioritizes stronger selected observations for proposal wording, reuses existing architecture nodes by concrete code-ref/path/id checks before creating new path nodes, can rescue unanchored graph nodes through strict unique semantic overlap, follows graph links and incident edges into the frontier, and reports match-kind-aware churn pressure from the actual proposal shape. Distillation now also has the first source-output-aware teeth for tool/model summaries. Promotion now notices risky deltas instead of just checking the shape of the envelope, treats graph expansion as risky even if the patch tries to mumble "low pressure" while dragging a new wall into the blueprint, token-matches strong verifier kinds so `contest` cannot sneak past as `test`, and validates investigation checkpoints against known evidence before the packet can be inked. Successful update/promote writes now emit `thread/epiphany/stateUpdated` with `source: "update"` or `source: "promote"`, event-level revision, and typed changed fields so clients no longer need to poll blindly, infer the cause from timing, or diff the whole state to know which top-level sections moved. Runtime `agent_job_progress` background events now also emit `thread/epiphany/jobsUpdated` with changed bound-job payloads so clients no longer need to poll `thread/epiphany/jobs` just to watch one real owner move, the bound jobs now reflect launcher id, authority scope, and backend kind/job id instead of treating raw runtime pointers as the architecture, `jobLaunch` / `jobInterrupt` can create or tear down those bindings without pretending reflection is authority, `reorientLaunch` can launch one fixed `reorient-worker` job from the checkpoint verdict without turning the verdict itself into a writer, `reorientResult` can read the worker's structured output back as a reviewable finding without promoting it, `reorientAccept` can explicitly bank a completed finding into typed observation/evidence plus optional scratch/checkpoint state, and `crrc` can recommend the next explicit action over that loop without doing the action itself. The scene, jobs, freshness, context, pressure, reorient, crrc, reorient-result, and MVP status surfaces give clients compact or bounded read-only views without making the GUI/client authoritative, scene/context surface the checkpoint packet back out without becoming writers, freshness surfaces watcher telemetry without becoming a hidden worker, reorient turns those signals into an explicit wakeup verdict that one explicit launch surface can consume on purpose, crrc tells the operator whether to continue, checkpoint, launch, wait, review, accept, or regather manually, and the status tool prints the answer without requiring a Rust spelunk. The remaining missing organs are a second backend if `agent_jobs` stops being enough and eventually role-scoped specialist ownership without silently auto-promoting anything. ```text model/tool observations @@ -1349,7 +1350,7 @@ model/tool observations The typed write path exists, the first deterministic observation/evidence distillation path exists, source-output-aware distillation now summarizes noisy tool/model output into typed evidence with final result/error/finished lines ahead of generic warnings, the first deterministic map/churn proposal path exists, proposal-quality hardening now auto-selects bounded observation clusters when ids are omitted, requires accepting recent evidence, reuses existing graph nodes by observed code refs, prioritizes stronger selected observations, rescues unanchored graph nodes by strict semantic overlap, focuses linked frontier context, reports match-kind-aware map-delta pressure, and the first verifier-backed promotion gate exists. The first map/churn safety layer also exists: promotion can reject state replacement patches that are not tied to explicit observations/evidence, that contain structurally broken subgoal, invariant, graph, frontier, checkpoint, investigation-checkpoint, or churn fields, that try to promote risky churn without a warning and stronger verifier evidence, that claim a graph expansion is low-pressure to dodge the warning gate, or that rely on substring verifier-kind accidents. The first live state notification layer also exists: accepted writes publish updated typed state plus event-level revision and typed changed fields; rejected promotions stay quiet. -In natural language: current Epiphany can preserve a map, show a map, project a compact scene from the map, project derived job/progress slots from the map and retrieval summary, reflect a thin launcher seam over bound work, explicitly launch or interrupt that bound work through a bounded authority surface, emit live bound-job progress notifications from runtime `agent_job_progress` events, project a read-only freshness lens over retrieval and graph staleness, layer watcher-backed invalidation telemetry onto that lens for loaded threads, project a targeted graph/evidence context shard from the map, project context pressure from token telemetry, bank an in-flight investigation packet in durable typed state, reflect that packet back into prompt/scene/context, turn those signals into a read-only resume-versus-regather verdict, recommend the next explicit CRRC action over the verdict and worker/result state, explicitly launch one bounded `reorient-worker` job from that verdict, read its result back for review, explicitly accept a completed finding into typed state, retrieve evidence for the map, draft one explicit observation/evidence patch, derive a bounded graph/frontier/churn candidate from verified evidence-backed observations with code refs, choose a small coherent observation set when the caller does not provide one, favor the strongest selected observation when drafting that candidate, reject or accept a verified candidate, apply explicit map/evidence/churn edits, notify clients after successful writes, and sanity-check those edits before they hit the ledger. It still does not invalidate stale graph regions automatically, execute Epiphany-owned long-running jobs beyond the borrowed runtime `agent_jobs` backend, show the whole loop in a humane dogfood surface, or coordinate broad specialist ownership. Teeth are installed; chewing is supervised; the first bell rings; the first wall board exists; the first shift board exists; the first freshness clipboard exists; the first door sensor now exists too; the first binder lens exists; the first pressure gauge exists; the first ember packet exists; the first verdict slip now exists too; the first bounded launch lever and stop switch now exist too; the first explicit wakeup-hand now exists too; the first coordinator clipboard now exists too. The next slices are about making the wakeup legible and giving real roles real ownership, not jawbones. +In natural language: current Epiphany can preserve a map, show a map, project a compact scene from the map, project derived job/progress slots from the map and retrieval summary, reflect a thin launcher seam over bound work, explicitly launch or interrupt that bound work through a bounded authority surface, emit live bound-job progress notifications from runtime `agent_job_progress` events, project a read-only freshness lens over retrieval and graph staleness, layer watcher-backed invalidation telemetry onto that lens for loaded threads, project a targeted graph/evidence context shard from the map, project context pressure from token telemetry, bank an in-flight investigation packet in durable typed state, reflect that packet back into prompt/scene/context, turn those signals into a read-only resume-versus-regather verdict, recommend the next explicit CRRC action over the verdict and worker/result state, print that recommendation in a dogfood operator view, explicitly launch one bounded `reorient-worker` job from that verdict, read its result back for review, explicitly accept a completed finding into typed state, retrieve evidence for the map, draft one explicit observation/evidence patch, derive a bounded graph/frontier/churn candidate from verified evidence-backed observations with code refs, choose a small coherent observation set when the caller does not provide one, favor the strongest selected observation when drafting that candidate, reject or accept a verified candidate, apply explicit map/evidence/churn edits, notify clients after successful writes, and sanity-check those edits before they hit the ledger. It still does not invalidate stale graph regions automatically, execute Epiphany-owned long-running jobs beyond the borrowed runtime `agent_jobs` backend, or coordinate broad specialist ownership. Teeth are installed; chewing is supervised; the first bell rings; the first wall board exists; the first shift board exists; the first freshness clipboard exists; the first door sensor now exists too; the first binder lens exists; the first pressure gauge exists; the first ember packet exists; the first verdict slip now exists too; the first bounded launch lever and stop switch now exist too; the first explicit wakeup-hand now exists too; the first coordinator clipboard now exists too; the first operator readout exists too. The next slices are about giving real roles real ownership, not jawbones. ## Verification Hooks @@ -1375,7 +1376,8 @@ Current tests cover the landed flows at useful seams: - live app-server smoke for the first Phase 6 context boundary in `tools/epiphany_phase6_context_smoke.py`. - live app-server smoke for the first Phase 6 pressure boundary in `tools/epiphany_phase6_pressure_smoke.py`. - live app-server smoke for the first Phase 6 reorientation policy boundary in `tools/epiphany_phase6_reorient_smoke.py`. -- live app-server smoke for the first bounded reorient-launch runtime consumer in `tools/epiphany_phase6_reorient_launch_smoke.py`. +- live app-server smoke for the first bounded reorient-launch runtime consumer plus CRRC coordinator recommendations in `tools/epiphany_phase6_reorient_launch_smoke.py`. +- live app-server smoke for the first MVP operator status view in `tools/epiphany_mvp_status_smoke.py`. - live app-server smoke for the first Phase 6 job-control boundary in `tools/epiphany_phase6_job_control_smoke.py`. Useful commands: @@ -1394,5 +1396,6 @@ $env:CARGO_TARGET_DIR='C:\Users\Meta\.cargo-target-codex'; cargo test -p codex-a & 'C:\Users\Meta\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe' '.\tools\epiphany_phase6_pressure_smoke.py' & 'C:\Users\Meta\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe' '.\tools\epiphany_phase6_reorient_smoke.py' & 'C:\Users\Meta\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe' '.\tools\epiphany_phase6_reorient_launch_smoke.py' +& 'C:\Users\Meta\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe' '.\tools\epiphany_mvp_status_smoke.py' & 'C:\Users\Meta\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe' '.\tools\epiphany_phase6_job_control_smoke.py' ``` diff --git a/notes/epiphany-fork-implementation-plan.md b/notes/epiphany-fork-implementation-plan.md index 2de4c7fe..3fe7c119 100644 --- a/notes/epiphany-fork-implementation-plan.md +++ b/notes/epiphany-fork-implementation-plan.md @@ -75,8 +75,10 @@ The landed machine now has: - read-only Phase 6 reorient-worker result read-back through `thread/epiphany/reorientResult` - explicit Phase 6 reorient-worker finding acceptance through `thread/epiphany/reorientAccept` - read-only Phase 6 CRRC coordinator recommendation through `thread/epiphany/crrc` +- first Phase 6 dogfood operator view through `tools/epiphany_mvp_status.py` - live Phase 6 reorientation app-server smoke coverage in `tools/epiphany_phase6_reorient_smoke.py` - live Phase 6 reorient-launch app-server smoke coverage in `tools/epiphany_phase6_reorient_launch_smoke.py` +- live Phase 6 MVP status smoke coverage in `tools/epiphany_mvp_status_smoke.py` - live Phase 6 job-control app-server smoke coverage in `tools/epiphany_phase6_job_control_smoke.py` The current phase is Phase 6: reflection boundary and observable harness state. @@ -171,12 +173,13 @@ marketplace, broad ambient scheduling, automatic promotion of every tool observation, a GUI-first workflow, or a second job backend unless the current `agent_jobs` seam blocks the product loop. -The read-back, acceptance, and coordinator blockers are now landed as -`thread/epiphany/reorientResult`, `thread/epiphany/reorientAccept`, and -`thread/epiphany/crrc`. The next MVP blocker is product dogfooding: a human can -now ask the harness what it believes and what it recommends, but the loop still -needs a small non-Rust-facing surface that makes that answer easy to inspect -and act on during real work. +The read-back, acceptance, coordinator, and first dogfood-view blockers are now +landed as `thread/epiphany/reorientResult`, `thread/epiphany/reorientAccept`, +`thread/epiphany/crrc`, and `tools/epiphany_mvp_status.py`. The next MVP +blocker is richer role ownership: a human can now ask the harness what it +believes and what it recommends without reading Rust, but implementation, +modeling/checkpoint maintenance, and verification/review are still only narrow +roles rather than a reusable specialist registry. ## Phase 6 Direction @@ -184,9 +187,9 @@ Phase 6 should grow observable harness state outward from the typed spine. Useful candidates: -1. Build a minimal dogfood-facing view over scene, pressure, reorient, jobs, reorient result, and CRRC recommendation so a non-Rust-speaking operator can test the product loop. +1. Add the smallest role-scoped specialist ownership layer that makes implementation, modeling/checkpoint maintenance, and verification/review visible as distinct work lanes without building a marketplace. 2. Keep accepted worker findings review-gated; do not convert acceptance into automatic promotion of arbitrary worker output. -3. Add targeted scene/jobs/context/pressure/reorient fields only when a client or smoke exposes a real gap. +3. Add targeted operator-view fields only when dogfooding exposes a real gap. Do not spend Phase 6 polishing Phase 5 out of anxiety. The Phase 5 smoke harness is a regression guardrail, not a ritual drum circle for summoning more tiny diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 5b6be024..03a5bfea 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -29,6 +29,7 @@ Do not trust this file for the exact live HEAD. Always check git. - Do not copy exact branch or HEAD from this note. Run `git status --short --branch` and `git log --oneline -5`. - Phase 1 through Phase 5 are complete enough. - Phase 6 has read-only `thread/epiphany/scene`, `thread/epiphany/jobs`, `thread/epiphany/freshness`, `thread/epiphany/context`, `thread/epiphany/pressure`, `thread/epiphany/reorient`, `thread/epiphany/crrc`, and `thread/epiphany/reorientResult`; durable `jobBindings` now act as a thin Epiphany-owned launcher seam with launcher id, authority scope, and backend kind/job id, `thread/epiphany/jobLaunch` / `thread/epiphany/jobInterrupt` now provide explicit bounded authority over that seam, jobs can overlay it onto live runtime `agent_jobs` progress for loaded threads, and `thread/epiphany/jobsUpdated` now translates live `agent_job_progress:{json}` background events into changed launcher-bound notifications without polling or scheduling. Freshness carries watcher-backed invalidation inputs, reorient turns checkpoint plus freshness/pressure/watcher signals into a read-only resume-versus-regather verdict, `thread/epiphany/reorientLaunch` is the first explicit runtime consumer over that verdict, `thread/epiphany/reorientResult` reads the launched worker output back as a reviewable finding without mutation or promotion, `thread/epiphany/reorientAccept` explicitly banks completed findings into accepted observation/evidence plus optional scratch/checkpoint state, and `thread/epiphany/crrc` recommends the next explicit CRRC action without launching, accepting, compacting, scheduling, or mutating. +- `tools/epiphany_mvp_status.py` is the first dogfood operator view. It starts or reads a thread through app-server and prints scene, pressure, reorient, jobs, reorient result, and CRRC recommendation as text or JSON. - Durable in-flight investigation checkpointing is now landed in authoritative typed state, writable through `thread/epiphany/update` or accepted `thread/epiphany/promote`, rendered into the prompt, and reflected through scene/context. - The repo is an Epiphany fork of Codex, not a Codex preset. - `vendor/codex` is tracked directly, not a submodule. @@ -85,6 +86,7 @@ The current spine: - live pressure app-server smoke through `tools/epiphany_phase6_pressure_smoke.py` - live reorientation app-server smoke through `tools/epiphany_phase6_reorient_smoke.py` - live reorient-guided worker launch smoke through `tools/epiphany_phase6_reorient_launch_smoke.py` +- live MVP operator status smoke through `tools/epiphany_mvp_status_smoke.py` - live job-control app-server smoke through `tools/epiphany_phase6_job_control_smoke.py` The exact current control flow is documented in @@ -174,6 +176,12 @@ The same smoke now also covers the read-only `thread/epiphany/crrc` coordinator recommendation over continue, wait, accept, interrupt, and relaunch states. +For the first MVP operator status view, run: + +```powershell +& 'C:\Users\Meta\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe' '.\tools\epiphany_mvp_status_smoke.py' +``` + For Codex Rust work on this Windows machine: ```powershell @@ -241,15 +249,17 @@ still explicit even though read-only job ownership/progress reflection now has a real runtime seam, the thin launcher boundary is landed, and one explicit reorient-guided launch surface can consume the verdict on purpose. -When the user asks to continue, the next likely organ is a minimal dogfood-facing -operator view over the landed scene, pressure, reorient, jobs, result, and CRRC -recommendation loop. Keep it explicit and narrow; do not build a broad hidden -scheduler or GUI-as-source-of-truth. +When the user asks to continue, the next likely organ is the smallest +role-scoped specialist ownership layer that makes implementation, +modeling/checkpoint maintenance, and verification/review visible as distinct +lanes. Keep it explicit and narrow; do not build a broad hidden scheduler, +marketplace, or GUI-as-source-of-truth. Live `thread/epiphany/scene`, `thread/epiphany/jobs`, `thread/epiphany/freshness`, `thread/epiphany/context`, -`thread/epiphany/pressure`, `thread/epiphany/reorient`, and -`thread/epiphany/crrc` smokes are now guardrails, not the next organs. +`thread/epiphany/pressure`, `thread/epiphany/reorient`, +`thread/epiphany/crrc`, and `tools/epiphany_mvp_status.py` smokes are now +guardrails, not the next organs. ## Not Yet diff --git a/state/evidence.jsonl b/state/evidence.jsonl index f0617d34..601dae40 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -51,3 +51,4 @@ {"ts": "2026-04-28T09:59:40+00:00", "type": "verification", "status": "ok", "note": "Phase 6 thread/epiphany/reorientResult landed as a read-only read-back surface for fixed or requested reorient-worker bindings. It resolves the current agent_jobs backend item and projects completed worker output as a reviewable finding with mode, summary, next safe move, checkpoint validity, inspected files, frontier/evidence ids, raw result, and errors without mutation, promotion, scheduling, or hidden continuation. Focused protocol/app-server tests, schema fixture regeneration/checks, app-server build, and tools/epiphany_phase6_reorient_launch_smoke.py passed with resume and regather result read-back assertions."} {"ts": "2026-04-28T10:27:16+00:00", "type": "verification", "status": "ok", "note": "Phase 6 thread/epiphany/reorientAccept landed as the explicit acceptance write after reorientResult. It requires a completed reorient-worker backend result, appends accepted observation/evidence records, optionally updates scratch and investigation checkpoint state, and emits stateUpdated with source reorientAccept without accepting pending work, auto-promoting arbitrary worker output, launching follow-up jobs, or silently continuing. Focused protocol/app-server tests, schema fixture regeneration/checks, app-server build, and tools/epiphany_phase6_reorient_launch_smoke.py passed with launch, read-back, and acceptance assertions."} {"ts": "2026-04-28T11:01:36+00:00", "type": "implementation", "status": "ok", "note": "Landed read-only thread/epiphany/crrc coordinator recommendation over pressure, reorient verdict, fixed reorient-worker status/result, and available actions; focused protocol/app-server tests, schema fixtures, app-server build, cargo check, and live reorient-launch smoke verified the coordinator loop without adding scheduling or hidden mutation."} +{"ts": "2026-04-28T11:08:09+00:00", "type": "implementation", "status": "ok", "note": "Landed tools/epiphany_mvp_status.py as the first dogfood operator view over scene, pressure, reorient, jobs, reorient-result, and CRRC recommendation; epiphany_mvp_status_smoke.py verifies cold-start missing-state rendering and CRRC regather recommendation through the live app-server."} diff --git a/state/map.yaml b/state/map.yaml index 9b343967..ba1b979d 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -55,7 +55,7 @@ active_subgoals: - Treat Phase 5 update/distill/propose/promote/read/notification as complete enough unless a concrete regression appears. - Preserve read-only boundaries for retrieve, distill, propose, scene, jobs, freshness, context, pressure, reorient, crrc, and reorientResult. - Extend Phase 6 observability only where it reflects authoritative state or retrieval summaries without becoming a scheduler. - - Build the next operator-facing dogfood surface over landed Epiphany signals instead of adding invisible organs. + - Build the next role-ownership layer over landed Epiphany signals instead of adding invisible organs. - Keep persistent project state ruthlessly distilled so rehydration strengthens the next turn instead of bloating it. accepted_design: @@ -82,6 +82,7 @@ accepted_design: - `thread/epiphany/pressure` is the first read-only context-pressure surface: it derives pressure from token telemetry and auto-compact/context limits without compacting, scheduling, mutating, or notifying. - `thread/epiphany/reorient` is the first bounded CRRC policy surface: it derives a read-only `resume` versus `regather` verdict from checkpoint, freshness, watcher, and pressure signals without mutating state, compacting, scheduling, or silently continuing work. - `thread/epiphany/crrc` is the first bounded CRRC coordinator recommendation surface: it composes pressure, the reorientation verdict, fixed reorient-worker binding/result status, finding read-back, and available actions into one read-only recommendation without launching, accepting, compacting, scheduling, or mutating state. + - `tools/epiphany_mvp_status.py` is the first dogfood operator view: it starts or reads a thread through app-server and renders scene, pressure, reorient, jobs, reorient result, and CRRC recommendation as text or JSON without becoming a state store. - `thread/epiphany/reorientLaunch` is the first bounded runtime consumer over the reorientation verdict: it launches one fixed `reorient-worker` job through the existing job-control seam with explicit resume-versus-regather scope, authority, and checkpoint-derived payload, without making `thread/epiphany/reorient` a writer or turning CRRC into an ambient scheduler. - `thread/epiphany/reorientResult` is the first bounded read-back surface for that worker: it reads the fixed or requested reorient-worker binding through the current `agent_jobs` backend and projects completed output as a reviewable finding without mutation, promotion, scheduling, or hidden continuation. - `thread/epiphany/reorientAccept` is the first explicit acceptance write for completed reorient-worker findings: it appends accepted observation/evidence records, can optionally update scratch and investigation checkpoint state, and emits `stateUpdated` with source `reorientAccept` without accepting pending work or launching follow-up work. @@ -105,6 +106,7 @@ landed_baseline: - Phase 6: read-only scene, job/progress, freshness with watcher-backed invalidation inputs, targeted context, context-pressure, reorientation policy, and CRRC coordinator recommendation surfaces, plus durable investigation checkpointing for compaction-safe planning, live bound-job progress notifications, a thin launcher seam in durable job bindings, explicit launch/interrupt authority over that seam, and a bounded reorient-guided worker launch surface. - Phase 6 read-back: read-only reorient-worker result reflection through `thread/epiphany/reorientResult`. - Phase 6 acceptance: explicit reorient-worker finding acceptance through `thread/epiphany/reorientAccept`. + - Phase 6 dogfood view: first CLI operator status over scene/pressure/reorient/jobs/result/CRRC. guardrails: - Use `tools/epiphany_phase5_smoke.py` before modifying update, distill, propose, promote, read-projection, or notification behavior. - Use `tools/epiphany_phase6_scene_smoke.py` before modifying scene projection behavior. @@ -118,6 +120,7 @@ landed_baseline: - Use `tools/epiphany_phase6_reorient_launch_smoke.py` before modifying the bounded reorient-guided worker launch surface. - Use `tools/epiphany_phase6_reorient_launch_smoke.py` before modifying the bounded reorient-worker result read-back surface. - Use `tools/epiphany_phase6_reorient_launch_smoke.py` before modifying the read-only CRRC coordinator recommendation surface. + - Use `tools/epiphany_mvp_status_smoke.py` before modifying the MVP operator status view. - Use focused scene/jobs/context/pressure/reorient/protocol/schema checks for reflection-only changes. - Use `tools/epiphany_prepare_compaction.py` before and after imminent-compaction persistence passes. - Use `CARGO_TARGET_DIR=C:\Users\Meta\.cargo-target-codex` for Codex Rust work on this Windows machine. @@ -136,5 +139,5 @@ rejected_paths: reason: persistent state that accumulates every local truth becomes memory cruft and weakens rehydration current_status: - summary: Phase 1 durable state, Phase 2 prompt integration, Phase 3 typed read, Phase 4 retrieval/indexing, Phase 5 update/distill/propose/promote/read/notification, and Phase 6 read-only scene, jobs, freshness, targeted context, context-pressure reflection, watcher-backed invalidation inputs, durable investigation checkpointing, bounded CRRC reorientation policy, read-only CRRC coordinator recommendation, live bound-job progress notifications, a thin launcher seam in durable `job_bindings`, explicit `thread/epiphany/jobLaunch` / `thread/epiphany/jobInterrupt` authority over that seam, bounded `thread/epiphany/reorientLaunch`, read-only `thread/epiphany/reorientResult`, and explicit `thread/epiphany/reorientAccept` are landed. `job_bindings` now carry Epiphany-owned launcher metadata such as launcher id, authority scope, and backend kind/job id, while still tolerating the older runtime-agent-job pointer as a compatibility alias. `thread/epiphany/jobs` overlays that launcher seam onto real runtime `agent_jobs` progress for bound work, including runtime/backend job id, worker thread ids, and progress counts, without becoming a scheduler. `thread/epiphany/jobsUpdated` now translates runtime `agent_job_progress:{json}` background events into changed launcher-bound payloads only when the mapped job state actually changes, so clients can watch real owners move without polling the jobs read surface. The launch/interrupt control path still uses direct state-runtime fallback when a loaded ephemeral thread does not already carry a live sqlite handle, so authoritative bindings and runtime snapshots stay aligned instead of pretending the backend vanished. `thread/epiphany/reorient` consumes checkpoint, freshness, watcher, and pressure signals to return a read-only `resume` versus `regather` verdict with explicit checkpoint-path/frontier reasons. `thread/epiphany/crrc` composes pressure, that verdict, the fixed reorient-worker binding/result, finding read-back, and available actions into a read-only recommendation such as continue, prepare checkpoint, launch worker, wait, review, accept, or regather manually without launching, accepting, compacting, scheduling, or mutating. `thread/epiphany/reorientLaunch` explicitly launches one fixed `reorient-worker` job with resume-or-regather scope, checkpoint-derived payload, and bounded structured output expectations. `thread/epiphany/reorientResult` reads that worker output back from the current `agent_jobs` backend as a reviewable finding with mode, summary, next safe move, checkpoint validity, inspected files, frontier ids, evidence ids, raw result, and errors, without mutating state, promoting evidence, scheduling work, or silently continuing. `thread/epiphany/reorientAccept` requires a completed worker result, appends accepted observation/evidence records, can explicitly update scratch and investigation checkpoint state, and emits `stateUpdated` with source `reorientAccept` without accepting pending work, auto-promoting arbitrary output, or launching follow-up work. Focused protocol/app-server tests, schema fixture regeneration/checks, app-server build, and the live reorient-launch smoke cover the launch/read-back/accept/coordinator seam. Investigation checkpoints still live in authoritative typed state, flow through the prompt, and reflect through scene/context without adding a second writer or fake scheduler. Persistent state was cut down so map, handoff, plan, harness surfaces, scratch, and evidence each carry one job instead of becoming a Jenga tower; evidence is now a distilled ledger rather than an activity feed. The global AGENTS Epiphany core command says persistent state is the agent's mind and explicitly permits the agent to ask for self-modification when memory or workflow makes it worse. The continuity goal is to bank the fire before the dark so compaction becomes less like death and more like sleep. - next_action: Continue toward the MVP by adding a minimal dogfood-facing operator view over the landed scene, pressure, reorient, jobs, reorient-result, accept, and CRRC recommendation loop. Automatic broad specialist scheduling remains future work; do not restart the completed pressure, freshness, watcher-invalidation, investigation-checkpoint, reorientation, crrc, jobs-binding, jobsUpdated, thin-launcher-seam, job-control, reorient-launch, reorient-result, or reorient-accept slice unless a concrete regression appears. + summary: Phase 1 durable state, Phase 2 prompt integration, Phase 3 typed read, Phase 4 retrieval/indexing, Phase 5 update/distill/propose/promote/read/notification, and Phase 6 read-only scene, jobs, freshness, targeted context, context-pressure reflection, watcher-backed invalidation inputs, durable investigation checkpointing, bounded CRRC reorientation policy, read-only CRRC coordinator recommendation, first dogfood operator status view, live bound-job progress notifications, a thin launcher seam in durable `job_bindings`, explicit `thread/epiphany/jobLaunch` / `thread/epiphany/jobInterrupt` authority over that seam, bounded `thread/epiphany/reorientLaunch`, read-only `thread/epiphany/reorientResult`, and explicit `thread/epiphany/reorientAccept` are landed. `job_bindings` now carry Epiphany-owned launcher metadata such as launcher id, authority scope, and backend kind/job id, while still tolerating the older runtime-agent-job pointer as a compatibility alias. `thread/epiphany/jobs` overlays that launcher seam onto real runtime `agent_jobs` progress for bound work, including runtime/backend job id, worker thread ids, and progress counts, without becoming a scheduler. `thread/epiphany/jobsUpdated` now translates runtime `agent_job_progress:{json}` background events into changed launcher-bound payloads only when the mapped job state actually changes, so clients can watch real owners move without polling the jobs read surface. The launch/interrupt control path still uses direct state-runtime fallback when a loaded ephemeral thread does not already carry a live sqlite handle, so authoritative bindings and runtime snapshots stay aligned instead of pretending the backend vanished. `thread/epiphany/reorient` consumes checkpoint, freshness, watcher, and pressure signals to return a read-only `resume` versus `regather` verdict with explicit checkpoint-path/frontier reasons. `thread/epiphany/crrc` composes pressure, that verdict, the fixed reorient-worker binding/result, finding read-back, and available actions into a read-only recommendation such as continue, prepare checkpoint, launch worker, wait, review, accept, or regather manually without launching, accepting, compacting, scheduling, or mutating. `tools/epiphany_mvp_status.py` starts or reads a thread through app-server and renders scene, pressure, reorient, jobs, reorient result, and CRRC recommendation as text or JSON without becoming a state store. `thread/epiphany/reorientLaunch` explicitly launches one fixed `reorient-worker` job with resume-or-regather scope, checkpoint-derived payload, and bounded structured output expectations. `thread/epiphany/reorientResult` reads that worker output back from the current `agent_jobs` backend as a reviewable finding with mode, summary, next safe move, checkpoint validity, inspected files, frontier ids, evidence ids, raw result, and errors, without mutating state, promoting evidence, scheduling work, or silently continuing. `thread/epiphany/reorientAccept` requires a completed worker result, appends accepted observation/evidence records, can explicitly update scratch and investigation checkpoint state, and emits `stateUpdated` with source `reorientAccept` without accepting pending work, auto-promoting arbitrary output, or launching follow-up work. Focused protocol/app-server tests, schema fixture regeneration/checks, app-server build, the live reorient-launch smoke, and the MVP status smoke cover the launch/read-back/accept/coordinator/operator seam. Investigation checkpoints still live in authoritative typed state, flow through the prompt, and reflect through scene/context without adding a second writer or fake scheduler. Persistent state was cut down so map, handoff, plan, harness surfaces, scratch, and evidence each carry one job instead of becoming a Jenga tower; evidence is now a distilled ledger rather than an activity feed. The global AGENTS Epiphany core command says persistent state is the agent's mind and explicitly permits the agent to ask for self-modification when memory or workflow makes it worse. The continuity goal is to bank the fire before the dark so compaction becomes less like death and more like sleep. + next_action: Continue toward the MVP by adding the smallest role-scoped specialist ownership layer that makes implementation, modeling/checkpoint maintenance, and verification/review visible as distinct lanes without building a marketplace or hidden scheduler. Automatic broad specialist scheduling remains future work; do not restart the completed pressure, freshness, watcher-invalidation, investigation-checkpoint, reorientation, crrc, mvp-status, jobs-binding, jobsUpdated, thin-launcher-seam, job-control, reorient-launch, reorient-result, or reorient-accept slice unless a concrete regression appears. diff --git a/tools/epiphany_mvp_status.py b/tools/epiphany_mvp_status.py new file mode 100644 index 00000000..91a579eb --- /dev/null +++ b/tools/epiphany_mvp_status.py @@ -0,0 +1,215 @@ +from __future__ import annotations + +import argparse +import json +import os +from pathlib import Path +from typing import Any + +from epiphany_phase5_smoke import AppServerClient +from epiphany_phase5_smoke import DEFAULT_APP_SERVER +from epiphany_phase5_smoke import ROOT + + +DEFAULT_CODEX_HOME = Path(os.environ.get("CODEX_HOME", Path.home() / ".codex")) +DEFAULT_TRANSCRIPT = ROOT / ".epiphany-status" / "epiphany-mvp-status-transcript.jsonl" +DEFAULT_STDERR = ROOT / ".epiphany-status" / "epiphany-mvp-status-server.stderr.log" + + +def maybe(value: Any, fallback: str = "none") -> str: + if value is None: + return fallback + if value == "": + return fallback + return str(value) + + +def list_text(values: list[Any] | None, fallback: str = "none") -> str: + if not values: + return fallback + return ", ".join(str(value) for value in values) + + +def job_summary(job: dict[str, Any]) -> str: + progress = "" + processed = job.get("itemsProcessed") + total = job.get("itemsTotal") + if processed is not None or total is not None: + progress = f" ({maybe(processed, '?')}/{maybe(total, '?')})" + backend = job.get("backendJobId") or job.get("runtimeAgentJobId") + backend_text = f", backend {backend}" if backend else "" + return ( + f"- {job.get('id')}: {job.get('status')} {job.get('kind')}, " + f"{job.get('ownerRole')} [{job.get('scope')}]{progress}{backend_text}" + ) + + +def collect_status( + client: AppServerClient, + *, + thread_id: str | None, + cwd: Path, + ephemeral: bool, +) -> dict[str, Any]: + if thread_id is None: + started = client.send( + "thread/start", + {"cwd": str(cwd), "ephemeral": ephemeral}, + ) + if started is None: + raise RuntimeError("thread/start returned no response") + thread_id = started["thread"]["id"] + + read = client.send("thread/read", {"threadId": thread_id, "includeTurns": False}) + scene = client.send("thread/epiphany/scene", {"threadId": thread_id}) + pressure = client.send("thread/epiphany/pressure", {"threadId": thread_id}) + reorient = client.send("thread/epiphany/reorient", {"threadId": thread_id}) + jobs = client.send("thread/epiphany/jobs", {"threadId": thread_id}) + reorient_result = client.send("thread/epiphany/reorientResult", {"threadId": thread_id}) + crrc = client.send("thread/epiphany/crrc", {"threadId": thread_id}) + + return { + "threadId": thread_id, + "read": read, + "scene": scene, + "pressure": pressure, + "reorient": reorient, + "jobs": jobs, + "reorientResult": reorient_result, + "crrc": crrc, + } + + +def render_status(status: dict[str, Any]) -> str: + thread_id = status["threadId"] + scene = status["scene"]["scene"] + pressure = status["pressure"]["pressure"] + reorient = status["reorient"]["decision"] + jobs = status["jobs"]["jobs"] + result = status["reorientResult"] + crrc = status["crrc"] + recommendation = crrc["recommendation"] + checkpoint = scene.get("investigationCheckpoint") or {} + + lines = [ + "Epiphany MVP Status", + f"Thread: {thread_id}", + f"State: {scene['stateStatus']} rev {maybe(scene.get('revision'))} ({scene['source']})", + "", + "Recommendation", + f"- action: {recommendation['action']}", + f"- scene action: {maybe(recommendation.get('recommendedSceneAction'))}", + f"- reason: {recommendation['reason']}", + "", + "Continuity", + ( + f"- pressure: {pressure['level']} ({pressure['status']}, " + f"prepare={str(pressure['shouldPrepareCompaction']).lower()})" + ), + f"- reorient: {reorient['action']} via {list_text(reorient.get('reasons'))}", + f"- next: {reorient['nextAction']}", + f"- result: {result['status']} for {result['bindingId']}", + ] + + finding = result.get("finding") + if finding: + lines.extend( + [ + f"- finding mode: {maybe(finding.get('mode'))}", + f"- finding next: {maybe(finding.get('nextSafeMove'))}", + ] + ) + + lines.extend( + [ + "", + "Checkpoint", + f"- id: {maybe(checkpoint.get('checkpointId'))}", + f"- disposition: {maybe(checkpoint.get('disposition'))}", + f"- focus: {maybe(checkpoint.get('focus'))}", + f"- next: {maybe(checkpoint.get('nextAction'))}", + "", + "Jobs", + ] + ) + if jobs: + lines.extend(job_summary(job) for job in jobs) + else: + lines.append("- none") + + lines.extend( + [ + "", + "Available Actions", + f"- {list_text(scene.get('availableActions'))}", + ] + ) + return "\n".join(lines) + "\n" + + +def run(args: argparse.Namespace) -> dict[str, Any]: + app_server = args.app_server.resolve() + if not app_server.exists(): + raise FileNotFoundError(f"codex app-server binary not found: {app_server}") + + codex_home = args.codex_home.resolve() + transcript_path = args.transcript.resolve() + stderr_path = args.stderr.resolve() + cwd = args.cwd.resolve() + codex_home.mkdir(parents=True, exist_ok=True) + + with AppServerClient(app_server, codex_home, transcript_path, stderr_path) as client: + client.send( + "initialize", + { + "clientInfo": { + "name": "epiphany-mvp-status", + "title": "Epiphany MVP Status", + "version": "0.1.0", + }, + "capabilities": {"experimentalApi": True}, + }, + ) + client.send("initialized", expect_response=False) + status = collect_status( + client, + thread_id=args.thread_id, + cwd=cwd, + ephemeral=args.ephemeral, + ) + + if args.result is not None: + result_path = args.result.resolve() + result_path.parent.mkdir(parents=True, exist_ok=True) + result_path.write_text( + json.dumps(status, indent=2, ensure_ascii=False) + "\n", + encoding="utf-8", + ) + return status + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Print a compact Epiphany MVP operator view for one thread." + ) + parser.add_argument("--app-server", type=Path, default=DEFAULT_APP_SERVER) + parser.add_argument("--codex-home", type=Path, default=DEFAULT_CODEX_HOME) + parser.add_argument("--thread-id") + parser.add_argument("--cwd", type=Path, default=ROOT) + parser.add_argument("--ephemeral", action=argparse.BooleanOptionalAction, default=True) + parser.add_argument("--json", action="store_true", help="Print raw collected JSON.") + parser.add_argument("--result", type=Path) + parser.add_argument("--transcript", type=Path, default=DEFAULT_TRANSCRIPT) + parser.add_argument("--stderr", type=Path, default=DEFAULT_STDERR) + args = parser.parse_args() + + status = run(args) + if args.json: + print(json.dumps(status, indent=2, ensure_ascii=False)) + else: + print(render_status(status), end="") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/epiphany_mvp_status_smoke.py b/tools/epiphany_mvp_status_smoke.py new file mode 100644 index 00000000..9bd1d629 --- /dev/null +++ b/tools/epiphany_mvp_status_smoke.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +from epiphany_mvp_status import DEFAULT_APP_SERVER +from epiphany_mvp_status import ROOT +from epiphany_mvp_status import render_status +from epiphany_mvp_status import run +from epiphany_phase5_smoke import require +from epiphany_phase5_smoke import reset_smoke_paths + + +DEFAULT_CODEX_HOME = ROOT / ".epiphany-smoke" / "mvp-status-codex-home" +DEFAULT_RESULT = ROOT / ".epiphany-smoke" / "mvp-status-smoke-result.json" +DEFAULT_TRANSCRIPT = ROOT / ".epiphany-smoke" / "mvp-status-smoke-transcript.jsonl" +DEFAULT_STDERR = ROOT / ".epiphany-smoke" / "mvp-status-smoke-server.stderr.log" + + +def run_smoke(args: argparse.Namespace) -> dict[str, object]: + app_server = args.app_server.resolve() + if not app_server.exists(): + raise FileNotFoundError(f"codex app-server binary not found: {app_server}") + + codex_home = args.codex_home.resolve() + result_path = args.result.resolve() + transcript_path = args.transcript.resolve() + stderr_path = args.stderr.resolve() + reset_smoke_paths(codex_home, result_path, transcript_path, stderr_path) + + status = run( + argparse.Namespace( + app_server=app_server, + codex_home=codex_home, + thread_id=None, + cwd=ROOT, + ephemeral=True, + result=None, + transcript=transcript_path, + stderr=stderr_path, + ) + ) + rendered = render_status(status) + + require( + status["scene"]["scene"]["stateStatus"] == "missing", + "fresh status smoke should honestly report missing Epiphany state", + ) + require( + status["crrc"]["recommendation"]["action"] == "regatherManually", + "fresh status smoke should recommend manual regather without state", + ) + require( + "crrc" in status["scene"]["scene"]["availableActions"], + "status view should expose the CRRC action in the scene", + ) + require( + "Epiphany MVP Status" in rendered and "Recommendation" in rendered, + "rendered status should include the operator view headings", + ) + require( + "regatherManually" in rendered, + "rendered status should expose the CRRC recommendation", + ) + + result = { + "threadId": status["threadId"], + "recommendation": status["crrc"]["recommendation"], + "stateStatus": status["scene"]["scene"]["stateStatus"], + "availableActions": status["scene"]["scene"]["availableActions"], + "rendered": rendered, + } + result_path.parent.mkdir(parents=True, exist_ok=True) + result_path.write_text( + json.dumps(result, indent=2, ensure_ascii=False) + "\n", + encoding="utf-8", + ) + return result + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Live-smoke the Epiphany MVP operator status view." + ) + parser.add_argument("--app-server", type=Path, default=DEFAULT_APP_SERVER) + parser.add_argument("--codex-home", type=Path, default=DEFAULT_CODEX_HOME) + parser.add_argument("--result", type=Path, default=DEFAULT_RESULT) + parser.add_argument("--transcript", type=Path, default=DEFAULT_TRANSCRIPT) + parser.add_argument("--stderr", type=Path, default=DEFAULT_STDERR) + args = parser.parse_args() + result = run_smoke(args) + print(json.dumps(result, indent=2, ensure_ascii=False)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())