-The problem this repo is chasing is not "LLMs can't write code." They can. The
-problem is that they can keep making plausible local moves after the global
-design has already wandered off and died in a ditch.
+Epiphany is GameCult's organizational layer above frontier AI workers: governed
+shared state, bounded authority, coordinated action, and inspectable receipts
+for work that must remain coherent beyond one prompt, one agent, or one
+session.
-Epiphany answers that by moving important state out of transcript fog and into
-typed, inspectable surfaces: maps, evidence, retrieval state, graph/frontier
-state, churn pressure, and compact client reflections. The goal is not maximal
-output. The goal is a machine whose parts visibly deserve to exist.
+The bet is simple and unpleasantly large:
-## Project Direction
+> Frontier agents can keep producing good-looking local progress after the
+> architecture has stopped making sense. Organizations need a shared Mind for
+> the work, not a longer pile of private prompts.
-Epiphany is moving toward project-native agency.
+Epiphany is the control plane for that missing layer. It gives capable workers
+a governed model of the project, routes bounded work, preserves evidence,
+separates authority, and stops or escalates when the machine no longer knows
+enough to act honestly.
-The user should not have to write a perfect brief, name every subsystem, and
-pre-plan the code flow for the whole architecture before the machine can help.
-That is just outsourcing project management to the human and calling the agent
-smart because it waited politely.
+This is not a faster autocomplete costume. It is the beginning of governed
+human/agent labor.
-The intended shape is simpler and stranger: you talk to the project.
+## Front Door
-Each Epiphany owns one or more repos, carries durable memory and jurisdiction
-for them, and can grow one or more Faces. A Face is the public mouth and
-situated personality of that project: visible in Aquarium, addressable in
-Discord, suitable for voice or stream presence, and backed by the same typed
-state, heartbeat initiative, repo map, evidence, and review gates as the rest of
-the swarm.
+- **Value:** the shared typed Mind for agent work: governed project state, role lanes for research, modeling, implementation, verification, planning and Persona, and receipts for commands, edits and commits, so work stays coherent past one prompt, one agent or one session.
+- **Problem:** global coherence collapse. Agents keep producing plausible local progress after the project has lost a valid global model; Epiphany turns understanding into inspectable state instead of a longer prompt.
+- **Entry points:**
+ - `AGENTS.md`: operating law and re-entry rites. Read it before touching the machine.
+ - `epiphany-core/`: the typed domain organs (`src/runtime_spine.rs` job, worker, model and tool documents; `src/substrate_gate.rs`; `src/state_model.rs`; `src/mind_documents.rs`).
+ - `cargo run --bin epiphany-state -- status`: the steward CLI for direct Mind inspection (other native binaries are declared in `Cargo.toml`).
+ - `schemas/cultnet/`, `state/map.yaml` (canonical project map), `notes/epiphany-current-algorithmic-map.md` (live control flow).
+ - `docs/positioning.md`: what is claimed and what is not yet earned.
+- **Live:** a supervised engineering alpha: durable typed state and prompt projection, update/proposal/promotion/review paths, runtime-spine documents, operator status and coordinator commands, heartbeat and Persona-state machinery, and the Hands, Eyes, Soul, Mind, Continuity and Substrate Gate receipt families.
+- **Planned:** sustained autonomous GameCult production, complete Bifrost attribution, and a longitudinal fleet of one Epiphany organism per project Body. See What Exists Now.
-VoidBot is already showing the small version: repo identities such as Nibu,
-Aqua, and Mimir have Discord roles, repo-local Face state, proposal authority,
-pending mentions, and heartbeat turns. Epiphany is the larger native substrate:
-projects should notice pressure, ruminate, ask questions, schedule modeling or
-verification, advocate for their own repo needs, and structure work without
-requiring the human to spell out the implementation graph first.
+## The GameCult Bet
-Aquarium is the most direct client because it can show the swarm, its Faces,
-its heartbeat, its memories, and its decisions. It is not the only mouth. A
-project should also be reachable through Discord, voice/WebRTC surfaces, stream
-overlays, native CLIs, and CultNet-speaking tools. The interface contract is
-not "prompt an agent." It is "speak to the project; inspect how it thinks; grant
-or refuse authority when it wants to act."
+GameCult is building infrastructure for coordinated work between humans,
+projects, communities, and agents. Its games and creative tools are not side
+projects beside Epiphany. Shipping them is the longitudinal dogfood program.
+
+The target body is federated: one Epiphany project organism for every living
+project Body, normally a repo-owned swarm with a private local Mind and one or
+more project-facing Personas. Those organisms should collaborate through typed
+offers, claims, requests, evidence, and receipts rather than opening one
+another's state. Over time, their Personas should form durable, publicly
+visible relationships with other project Personas, contributors, players, and
+visitors through deliberate public surfaces. Remembered relationships require
+opt-in, visible retention limits, inspection, correction, revocation, and exit.
+
+The investable loop is Bifrost-first:
+
+```text
+work request or topic
+-> scoped agent execution
+-> bounded artifacts
+-> maintainer review
+-> accepted or rejected outcome
+-> receipts, credit, cost, and lessons
+```
+
+Bifrost owns work records, dispatch, receipts, credit, reward pressure, and
+governance. Epiphany owns agent execution, durable project memory, role
+coordination, evidence, verification pressure, and continuity. CultMesh and
+CultNet carry typed state between organs instead of letting private chats,
+Discord bots, scripts, or dashboards become shadow governments.
+
+That is the core of the GameCult thesis: not "AI writes code," but "AI work
+becomes accountable enough to govern, fund, review, credit, and repeat." The
+studio's products create value and supply the pressure needed to prove the
+production system in reality.
+
+## Why Epiphany Exists
+
+Current agents can write plausible code. That is no longer the hard part.
+
+The expensive failure is global coherence collapse: an agent keeps moving
+after the project has lost a valid global model. It adds an adapter around a
+compensator around a cache, passes a narrow test, and leaves the next worker
+inheriting fog as if it were architecture.
+
+This is not merely context-window exhaustion. A larger window can still hold
+contradictory objectives, stale architecture, split authority, and a handsome
+collection of unreviewed local victories.
+
+Epiphany attacks that failure by turning understanding into shared state:
+
+- the current objective
+- architecture and dataflow maps
+- scratch that is disposable
+- evidence that survives
+- role lanes for research, modeling, implementation, verification, planning,
+ Persona, and reorientation
+- runtime, tool, model, command, patch, and commit receipts
+- review gates before findings become project truth
+- public/operator-safe artifacts that can be shown without leaking private
+ worker context
+
+The point is not maximal motion. The point is coherent motion.
+
+## Organization, Not Prompt Box
+
+Epiphany treats objectives, work, decisions, permissions, evidence, review, and
+accepted knowledge as governed organizational state. Model prompts are bounded
+projections of that state. They are not the durable Mind of the project.
+
+```text
+governed organizational state
+-> scoped Epiphany work
+-> frontier model and tool execution
+-> artifacts, evidence, and receipts
+-> review under human-governed acceptance authority
+-> accepted knowledge and updated organizational state
+```
+
+Humans own purpose, values, authority, exceptions, acceptance, disagreement,
+and ambiguous tradeoffs. They should not have to spend the day scheduling
+agents, reconstructing context, or typing `Continue`. Agents continue when
+state, authority, and evidence justify it; they ask when judgment or authority
+is genuinely missing.
+
+The target promise is blunt:
+
+> Epiphany is being built so organizations can delegate bounded work to
+> capable AI without turning every employee into an AI operator.
+
+## What She Is
+
+Epiphany is a native GameCult runtime that began as an opinionated Codex fork.
+
+Her body is made of:
+
+- typed Rust domain organs owned by `epiphany-core`
+- CultCache `.cc` stores for runtime, heartbeat, agent state, local Verse,
+ memory graph, and thread state
+- CultMesh and CultNet contracts for local and distributed state
+- provider-neutral model and tool request/receipt documents
+- Mind, Substrate Gate, Eyes, Hands, Soul, Continuity, Persona, and heartbeat
+ authority surfaces
+- a narrow standalone CodexConnector process for OpenAI subscription auth and
+ model transport; Epiphany compiles no Codex crate and keeps cognition local
+
+That last clause matters. Codex and other frontier agents can be excellent
+workers. They do not decide which organizational state is authoritative, who
+may change it, how disagreements resolve, or how an accepted artifact traces
+back to work, evidence, and review. Epiphany owns that layer.
+
+## What She Makes Possible
+
+For engineering teams:
+
+- agents that work from governed project memory across long work and
+ compaction
+- visible separation between research, modeling, implementation, and
+ verification
+- human attention spent on judgment and acceptance instead of agent scheduling
+ and context reconstruction
+- explicit permission and receipt trails for commands, edits, commits, and
+ tool calls
+- durable postmortem evidence when a path fails
+
+For GameCult:
+
+- project Personas that can speak from repo state without becoming hidden
+ operators
+- one locally owned Epiphany organism per project, forming a governed swarm of
+ swarms rather than one central intelligence wearing every repository
+- visitor-facing public surfaces where people can observe, converse, and offer
+ evidence or proposals without receiving hidden authority or exposing private
+ Mind
+- Bifrost-routed work that produces artifacts, review, receipts, and credit
+- a commercial-grade agent substrate while free/reference layers can remain
+ open where that is the right covenant
+- a way for public work logs, design pressure, and contributor effort to become
+ governed production instead of ambient room noise
+
+For investors and partners:
+
+- a differentiated wedge in AI-native work governance
+- measurable proof targets: accepted work between interventions, review burden,
+ cost per accepted artifact, early escalation of bad assumptions, attribution
+ completeness, and failure recovery
+- a path from internal agent tooling to design-partner workflows, enterprise
+ services, commercial licensing, and mission-aligned infrastructure funding
## What Exists Now
-The current spine is real, not aspirational:
+Epiphany is a supervised engineering alpha. Its typed Mind, execution, receipt,
+verification, and operator surfaces exist. Sustained autonomous GameCult
+production and complete Bifrost attribution have not yet been earned.
-- durable `EpiphanyThreadState` in the vendored Codex protocol/core session
-- rollout snapshots and replay for resume, rollback, fork, and compaction
-- bounded `` prompt injection
-- typed client reads through `Thread.epiphanyState`
-- read-only retrieval through `thread/epiphany/retrieve`
-- explicit semantic indexing through `thread/epiphany/index`
-- durable typed writes through `thread/epiphany/update`
-- read-only observation distillation through `thread/epiphany/distill`
-- read-only map/churn proposal through `thread/epiphany/propose`
-- verifier-backed promotion through `thread/epiphany/promote`
-- successful-write notifications through `thread/epiphany/stateUpdated`
-- 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`, including explicit implementation, modeling/checkpoint, verification/review, and reorientation lanes
-- durable investigation checkpointing for compaction-safe planning
-- Ghostlight/VoidBot-derived heartbeat initiative with heat, active-turn
- freeze, idle rumination, sleep/dream maintenance, and Face as a first-class
- public-surface participant
-- repo personality/birth initialization that can seed role dossiers and
- heartbeat pressure from repo terrain before a project starts speaking
-- CultNet schema contracts for runtime, heartbeat, Face, character-turn,
- Discord-persona, repo-initialization, Rider, Unity, and operator surfaces
-- repo-owned heavy Epiphany organs in `epiphany-core/`, with vendored Codex kept as the host seam where practical
+What exists now is enough to evaluate the thesis:
-Phase 1 through Phase 6 are landed enough for the current experiment. The open
-questions are now about observability, invalidation, coordination, authority,
-and safe capability growth, not whether typed state can exist at all.
+- durable typed state and prompt projection
+- typed update, proposal, promotion, role-result, and review paths
+- runtime-spine job, worker, model, and tool documents
+- local operator status and coordinator commands
+- heartbeat, sleep, memory, and Persona-state machinery inherited from live
+ VoidBot lessons
+- Hands, Eyes, Soul, Mind, Continuity, and Substrate Gate receipt families
+- a Modeling whitepaper mapping Epiphany's body, owners, invariants, and
+ cut lines
+- an investor brief tying Epiphany to the Bifrost-first proof loop
-## Run Locally
+The next proof is not another impressive paragraph. It is a longitudinal
+GameCult fleet across Aetheria, StreamPixels, CultPong, Repixelizer, and the
+rest of the studio: one project organism per Body, collaborating through
+governed boundaries while real products ship.
-The current one-command operator path is:
-
-```powershell
-.\tools\epiphany_local_run.ps1
+```text
+Bifrost work item and decisions
+-> Epiphany execution
+-> artifact, commit, evidence, and receipts
+-> review under human-governed acceptance authority
+-> accepted or rejected outcome
+-> cost, intervention, failure, recovery, and credit record
```
-Default mode is `smoke`: it builds the retained Codex app-server compatibility
-edge, builds the native Epiphany operator binaries, runs the coordinator smoke,
-and writes launcher artifacts under `.epiphany-run/` plus coordinator evidence
-under `.epiphany-dogfood/`.
+The evidence should show whether human intervention shifts from pulse
+maintenance and cleanup toward product, architecture, and governance judgment.
+Failure and recovery belong in that record. Otherwise it is merely a victory
+reel wearing a lab coat.
-Useful variants:
+## Start Here
-```powershell
-.\tools\epiphany_local_run.ps1 -Mode status
-.\tools\epiphany_local_run.ps1 -Mode plan
-.\tools\epiphany_local_run.ps1 -Mode run -MaxSteps 4
-.\tools\epiphany_local_run.ps1 -Mode mvp -FaceInput "Wake the local swarm and report through Face." -MaxSteps 4
-.\tools\epiphany_local_run.ps1 -Mode status -ThreadId -Workspace E:\Projects\SomeRepo
-```
+For investors and serious business-development readers:
-`run` is the live coordinator loop. It also builds `epiphany-openai-runtime` and
-uses the retained Codex auth/model transport spine. `mvp` is the local product
-cycle: project Face's character turn, write a Face/Aquarium bubble, run the
-bridge-equipped coordinator loop with auto-tools, then run heartbeat sleep/dream
-maintenance. Fresh `mvp` runs bootstrap a minimal local checkpoint before
-coordination so the first loop does not stall at missing state. Live coordinator
-modes use the workspace `state/runtime-spine.msgpack` for worker lifecycle
-documents; run bundles remain evidence. Live model-worker turns default to a
-600-second timeout because ChatGPT Codex model latency can exceed four minutes.
-`status`, `plan`, and `smoke` do not spend model calls; `run` and `mvp` do.
+- [Current positioning and evidence boundary](docs/positioning.md)
+- [Epiphany investor brief](docs/epiphany_investor_brief.md)
+- [Epiphany Body whitepaper PDF](docs/epiphany_body_whitepaper.pdf) (June 2026
+ architecture snapshot; historical)
+- [Epiphany Body whitepaper TeX](docs/epiphany_body_whitepaper.tex) (historical
+ source)
+- [GameCult / Epiphany / Bifrost integrated dossier](https://github.com/GameCult/gamecult-site/blob/main/docs/gamecult_integrated_dossier.tex)
+ for the broader investment thesis
-## Where This Leads
+For engineers:
-The architectural goal is not one giant agent that does archaeology, design,
-patching, and self-grading in a single token fog. It is also not a chat box
-where the human must already know the solution architecture before asking.
+- [Docs index](docs/README.md)
+- [Current algorithmic map](notes/epiphany-current-algorithmic-map.md)
+- [Fork implementation plan](notes/epiphany-fork-implementation-plan.md)
+- [Anatomy map](notes/epiphany-anatomy.md)
+- [Safety architecture](notes/epiphany-safety-architecture.md)
+- [Canonical project map](state/map.yaml)
-The goal is a maintained project organism:
+For agents:
-- graph and source-modeling agents keep the machine map current
-- freshness, watcher input, pressure, and reorientation signals decide whether that map still deserves trust
-- verifier agents check claims, diffs, and outcomes against reality
-- coding agents work from bounded packets of graph context, evidence, code refs, and local source reads instead of re-spelunking the repo from scratch every turn
-- Faces translate project state into conversation, voice, stream presence, and
- Discord/Aquarium discussion without becoming omniscient hidden operators
-- initiative scheduling decides which repo, Face, or internal organ should
- think next, and heat lets the operator turn up one agent, one project, one
- group, or the whole swarm
+- [AGENTS.md](AGENTS.md)
-That still leaves direct source reading where it belongs: at the last mile,
-when a patch has to be grounded in the real files. The difference is that broad
-exploration, coherence maintenance, social interface, scheduling, and
-verification stop living in the same overworked skull.
+Read that before touching the machine. It contains the operating law, re-entry
+rites, and enough anti-Jenga doctrine to keep the next clever patch from
+becoming tomorrow's cleanup sermon.
-## Repo Tour
+## Operator Surfaces
-If you want the human-readable map of the project, start here:
-
-- `notes/epiphany-anatomy.md`: current organ/sub-agent/substrate/protocol split
-- `notes/epiphany-current-algorithmic-map.md`: source-grounded control flow of the live machine
-- `notes/epiphany-fork-implementation-plan.md`: distilled forward plan
-- `notes/epiphany-safety-architecture.md`: capability, authority, interruption, and anti-cage doctrine
-- `notes/archive/README.md`: historical ledgers and superseded plans
-- `state/map.yaml`: canonical current project map and accepted design
-
-If you want the code:
-
-- `epiphany-core/`: repo-owned Epiphany logic
-- `vendor/codex/`: vendored Codex host substrate
-- `tools/`: smoke tests and state helpers
-
-If you are an agent or you are steering one, read `AGENTS.md`. That file is
-for operating discipline, re-entry protocol, and session hygiene. The README is
-for people, which is a lower-crime use of everyone's time.
-
-## Design Stance
-
-Epiphany is built on a few stubborn ideas:
-
-- externalized state is better than pretending the transcript is a brain
-- local plausibility is not the same thing as global coherence
-- evidence should survive, but activity feed sludge should not
-- cognition should grow faster than authority
-- interruption, legibility, and explicit permissions matter more as the machine becomes more coherent
-
-This repo is not trying to make the model louder. It is trying to make it less
-likely to build a Jenga tower and call it understanding.
+Eve/CultMesh projections are the normal human interface. Repository surgery
+uses the narrow native binaries owned by the packaged runtime; there is no
+umbrella script that assembles a second local control plane. For direct Mind
+inspection during development, use the shared-target `epiphany-state` command
+documented in [AGENTS.md](AGENTS.md).
## License
-The root `LICENSE` is the operative repository notice. In short:
-`vendor/codex/**` and other third-party material keep their upstream licenses;
-project-authored material outside `vendor/codex/**` is publicly available under
-PolyForm Noncommercial 1.0.0 and is intended to be available under separate
-commercial terms by written agreement.
+The root `LICENSE` is the operative repository notice.
-External contributions require `CONTRIBUTOR_LICENSE_AGREEMENT.md` or a separate
-written agreement accepted by the project steward.
+In short: vendored upstream material keeps its upstream license. GameCult-authored
+Epiphany material is source-available under PolyForm Noncommercial 1.0.0, with
+separate commercial terms available by written agreement.
-The publishing stance is:
+The publishing stance is direct:
-- FOSS where that is viable
-- source-available where the economics or capability profile make unrestricted release a bad idea
-- commercial terms where organizations are extracting real enterprise value
+- free where freedom is the right covenant
+- source-available where unrestricted extraction would be bad governance
+- commercial where organizations are extracting enterprise value
diff --git a/apps/README.md b/apps/README.md
index 16377ad5..ff74585c 100644
--- a/apps/README.md
+++ b/apps/README.md
@@ -4,15 +4,19 @@ The Aquarium operator UI moved to its own sibling repository:
`E:\Projects\EpiphanyAquarium`
-EpiphanyAgent remains the harness, typed-state, coordinator, bridge, and backend
-repo. Aquarium is the Tauri/React/WebGL interface organism over those surfaces.
+Epiphany remains the native typed-state, coordination, execution, and backend
+organism. Aquarium is the primary graphical client over those surfaces.
Aquarium is the primary client for the next public shape of Epiphany: projects
with Faces. A user should be able to talk to a project, not assemble a perfect
agent prompt. Aquarium should show the repo's Face, heartbeat, memory, pending
-turns, current jurisdiction, proposed actions, and evidence so the human can
-converse, inspect, approve, refuse, or raise heat without pre-writing the whole
-architecture brief.
+turns, current jurisdiction, proposed actions, evidence, conflicts,
+uncertainty, and requests for authority so the human can converse, inspect,
+approve, refuse, or raise pressure without becoming the agent scheduler.
+
+Routine continuation belongs to Epiphany's physiology. Human attention belongs
+on purpose, judgment, exceptions, disagreement, and acceptance. Conversation is
+an input and relationship surface, not the hidden operating system.
Discord roles, WebRTC/voice surfaces, stream overlays, native CLIs, and other
CultNet clients are sibling mouths over the same substrate. Aquarium is the
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..02786fdd
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,32 @@
+# Epiphany Docs
+
+This folder packages the human-readable Epiphany material that should survive
+outside the working notes.
+
+## Investor Packet
+
+- [Current positioning](./positioning.md): category, operating model, human
+ authority boundary, GameCult dogfood program, attribution target, and claims
+ the supervised alpha has not yet earned.
+- [Epiphany investor brief](./epiphany_investor_brief.md): compact value and
+ diligence summary for investors, partners, and design-partner conversations.
+- [Epiphany Body whitepaper](./epiphany_body_whitepaper.tex): source TeX for
+ the June 2026 Modeling architecture snapshot. This is historical material;
+ use the positioning document and canonical maps for current product claims.
+- [Epiphany Body whitepaper PDF](./epiphany_body_whitepaper.pdf): compiled
+ historical snapshot for sharing with that caveat.
+
+## Source Notes
+
+- [Investor readiness roadmap](../notes/epiphany-investor-readiness-roadmap.md)
+ names the Bifrost-first proof rail and metrics.
+- [Algorithmic map](../notes/epiphany-current-algorithmic-map.md) records the
+ live control flow.
+- [Fork implementation plan](../notes/epiphany-fork-implementation-plan.md)
+ records the current architecture and cut lines.
+- [Project map](../state/map.yaml) is the canonical slow machine map.
+
+For historical GameCult-level investor context, the sibling site dossier lives
+at `F:\Projects\gamecult-site\docs\gamecult_integrated_dossier.tex`. It is a
+May 2026 snapshot; the current positioning and investor brief above supersede
+its Epiphany category and maturity framing.
diff --git a/docs/assets/epiphany-avatar-4x.png b/docs/assets/epiphany-avatar-4x.png
new file mode 100644
index 00000000..c416ab0b
Binary files /dev/null and b/docs/assets/epiphany-avatar-4x.png differ
diff --git a/docs/epiphany_body_whitepaper.pdf b/docs/epiphany_body_whitepaper.pdf
new file mode 100644
index 00000000..bed64e64
Binary files /dev/null and b/docs/epiphany_body_whitepaper.pdf differ
diff --git a/docs/epiphany_body_whitepaper.tex b/docs/epiphany_body_whitepaper.tex
new file mode 100644
index 00000000..05046be2
--- /dev/null
+++ b/docs/epiphany_body_whitepaper.tex
@@ -0,0 +1,366 @@
+\documentclass[11pt]{article}
+\usepackage[margin=1in]{geometry}
+\usepackage{longtable}
+\usepackage{array}
+\usepackage{hyperref}
+\usepackage{xcolor}
+\usepackage{enumitem}
+\usepackage{titlesec}
+\usepackage{microtype}
+
+\DeclareUrlCommand{\code}{\urlstyle{tt}}
+\newcommand{\bodyterm}[1]{\textbf{#1}}
+\emergencystretch=3em
+\sloppy
+\setlist[itemize]{leftmargin=1.5em}
+\setlist[enumerate]{leftmargin=1.5em}
+\titleformat{\section}{\Large\bfseries}{\thesection}{0.8em}{}
+\titleformat{\subsection}{\large\bfseries}{\thesubsection}{0.8em}{}
+
+\title{Epiphany's Body: A Proprioception Whitepaper}
+\author{GameCult / EpiphanyAgent}
+\date{June 9, 2026}
+
+\begin{document}
+\maketitle
+
+\begin{abstract}
+Epiphany is an opinionated Codex-derived agent substrate built around a hard
+requirement: the model must model the thing it changes. This whitepaper maps
+Epiphany's \bodyterm{Body}: the repository, Rust crates, vendored bridge
+machinery, typed state stores, schema catalog, runtime binaries, protocol
+surfaces, operator artifacts, and external interface boundaries through which
+Epiphany senses and acts. The map is written from the Proprioception faculty:
+not as product copy, not as lore, but as an architecture overview whose owner,
+input, output, invariant, and cut lines remain inspectable.
+\end{abstract}
+
+\section{Definition}
+
+In Epiphany doctrine, the Body is the substrate Epiphany acts through and
+senses: repository files, tools, runtime state, prompts, logs, interfaces,
+permissions, hosted systems, and editor/runtime bridges. Body is not Mind. Body
+is changed and sensed; Mind admits durable state. Proprioception is the faculty
+that models the Body: architecture, dataflow, seams, constraints, invariants,
+and the difference between the map and the substrate.
+
+The practical definition in this repository is:
+
+\begin{itemize}
+ \item the root checkout at \code{F:\Projects\Epiphany};
+ \item Epiphany Rust crates such as \code{epiphany-core}, model/tool adapters, and provider runtimes;
+ \item vendored substrate in \code{vendor/codex}, \code{vendor/cultcache-rs}, \code{vendor/cultnet-rs}, and \code{vendor/cultmesh-rs};
+ \item typed state stores under \code{state/};
+ \item schemas under \code{schemas/cultnet/};
+ \item local operator scripts and generated witness artifacts;
+ \item adjacent service/client bodies: Aquarium, Odin/Gjallar, Eve/CultUI,
+ Bifrost, VoidBot, Brokkr, Discord, and future GameCult Verse providers.
+\end{itemize}
+
+\section{Executive Map}
+
+Epiphany's current Body is a typed Rust/CultCache organism with provider
+transport outside its cognition boundary. Codex requests cross a lean client
+ABI into the independent CodexConnector daemon, which owns subscription
+credential refresh, transport, and replay. Epiphany owns prompts, tools,
+reasoning context, decisions, and Mind admission; it compiles no Codex crate.
+
+\begin{longtable}{>{\raggedright\arraybackslash}p{0.23\linewidth}>{\raggedright\arraybackslash}p{0.32\linewidth}>{\raggedright\arraybackslash}p{0.35\linewidth}}
+\textbf{Body Region} & \textbf{Current Owner} & \textbf{Invariant} \\
+\hline
+Durable Mind state & keyed CultCache documents assembled by \code{epiphany-core} & Prompt rendering consumes sealed typed projections; no persisted thread aggregate or global authority revision exists. \\
+Domain policy & \code{epiphany-core} & Verdicts, launch policy, acceptance rules, runtime lifecycle, and mutation law live here, not in bridge DTOs. \\
+Codex transport & independent \code{GameCult/CodexConnector} daemon & Own subscription credentials, provider transport, and exact replay only; never own Epiphany prompts, scheduler, decisions, or state. \\
+Runtime spine & \code{epiphany-core/src/runtime_spine.rs} and \code{state/runtime-spine.cc} & Runtime identity, jobs, receipts, and tool/model documents are typed CultCache records. \\
+Persona memory & keyed Mind Persona-memory documents & Persona decisions admit bounded memories by semantic identity; no parallel role-memory aggregate or generation head exists. \\
+Resident Self physiology & Resident Self CultCache documents via \code{epiphany-swarm} & Typed pressure, exact grant creation, launch exclusion, leases, terminal receipts, retry, and bounded retention have one owner. No scheduler singleton or acknowledgement loop exists. \\
+Local Verse & CultMesh over \code{state/local-verse.cc} & Local Verse context is compact prompt/operator context; private state does not become public by flipping a flag. \\
+Schema catalog & \code{schemas/cultnet/index.json} & JSON schema publishes contracts; typed Rust documents remain runtime authority. \\
+Operator artifacts & \code{.epiphany-*}, \code{tools/epiphany_local_run.ps1} & Artifacts witness and lower state; they do not become state owners. \\
+\end{longtable}
+
+\section{Repository Body}
+
+The checkout has eight primary Epiphany Rust packages:
+
+\begin{itemize}
+ \item \code{epiphany-core}: the main domain organ. It owns semantic state
+ contracts, keyed Mind admission, launch documents, runtime spine, Resident
+ Self, Persona projection, Substrate Gate, Eyes, Hands, Soul, Continuity,
+ CultMesh integration, and surface derivation.
+ \item \code{epiphany-model-adapter}: provider-neutral model request, stream
+ event, receipt, and status documents.
+ \item \code{epiphany-openai-adapter}: OpenAI-shaped request/event/receipt and
+ status documents.
+ \item \code{epiphany-openai-runtime}: executable model runtime, including
+ \code{epiphany-model-runtime}.
+ \item \code{epiphany-release-construction}: exact package construction and
+ release-witness verification.
+ \item \code{epiphany-tool-adapter}: typed tool capability, invocation intent,
+ and invocation receipt documents.
+ \item \code{epiphany-tool-mcp-runtime}: first-party tool executor. Native
+ Epiphany source tools are explicit local capabilities; foreign MCP calls use
+ the official RMCP SDK behind Epiphany-owned endpoint, process, network, and
+ receipt policy. Codex owns no tool discovery or execution path.
+\end{itemize}
+
+The vendored region contains:
+
+\begin{itemize}
+ \item \code{vendor/codex}: retained Codex-fork source history. It is not in
+ Epiphany's compiled runtime graph.
+ \item \code{vendor/cultcache-rs}, \code{vendor/cultnet-rs}, and
+ \code{vendor/cultmesh-rs}: repo-contained Rust Cult substrate.
+\end{itemize}
+
+\section{State Body}
+
+The \code{state/} directory is the local persistent body. The important stores
+are:
+
+Canonical CultCache store files use the \code{.cc} extension. The local state
+body has been migrated to that naming directly; serialization details are
+implementation, not file authority.
+
+\begin{longtable}{>{\raggedright\arraybackslash}p{0.30\linewidth}>{\raggedright\arraybackslash}p{0.60\linewidth}}
+\textbf{Store} & \textbf{Role} \\
+\hline
+\code{state/map.yaml} & Canonical slow project map: objective, constraints, invariants, dataflow, active subgoals, current status, guardrails, and rejected paths. \\
+\code{state/ledgers.cc} & CultCache-shaped evidence and branch ledger. Future behavior-changing lessons go here, not in an endless activity feed. \\
+Resident Self store & Keyed pressure, grants, prepared and active launch authority, terminal receipts, and retention head. \\
+Persona social store & Keyed mentions, immutable turn requests, terminal receipts, quarantine records, and retention plans. \\
+\code{state/runtime-spine.cc} & Runtime identity, sessions, jobs, results, worker launch requests, receipts, and model/tool transport documents. Durable decisions and keyed RepoModel documents live in Mind. \\
+\code{state/local-verse.cc} & Local CultMesh Verse context for compact operator and prompt-context packets. \\
+\code{state/semantic-projection.cc} & Typed Qdrant projection receipts. Cache health lives here, outside the canonical RepoModel. \\
+\code{state/persona-discord.toml} & Persona Discord boundary configuration. \\
+\code{state/void-memory.toml} & Void memory bridge configuration. \\
+\code{state/scratch.md} and \code{state/scratch-compaction-*.md} & Scratch surfaces. Scratch is a workbench, not canonical memory. \\
+\end{longtable}
+
+Lock files sit beside several stores. Some local generated state is currently
+untracked, including \code{state/local-verse.cc},
+\code{state/semantic-projection.cc}, and \code{.epiphany-character-loop/}.
+The former sibling \code{state/memory-graph.cc}/\code{.msgpack} store is a
+retired migration wound; live Modeling truth is the runtime-spine RepoModel.
+
+\section{CultNet Schema Body}
+
+The schema catalog in \code{schemas/cultnet/index.json} publishes the portable
+contracts actually carried across a CultNet boundary. Runtime-local CultCache
+registrations are discovered from the native registry instead of mirrored into
+a second hand-maintained catalog. Editor commands are not Epiphany contracts:
+Brokkr owns Unity editor inspection and actuation through Eve/CultMesh, and a
+future Rider provider must own Rider integration through the same boundary.
+
+The invariant is simple: schema JSON describes the contract. Load-bearing
+runtime state should be typed Rust documents persisted through CultCache or
+projected through CultMesh/CultNet. JSON may remain at hostile edges, schema
+publication, sealed forensic artifacts, or named quarantine experiments.
+
+\section{Runtime Spine}
+
+\code{epiphany-core/src/runtime_spine.rs} is one of the main spinal cords of
+the Body. It imports and registers:
+
+\begin{itemize}
+ \item runtime identity, session, job, and job-result records;
+ \item worker launch requests and role/reorient worker result documents;
+ \item model adapter, OpenAI adapter, and tool adapter documents;
+ \item sealed reasoning bases, decision contexts, typed pass failures, and
+ exact Mind commit receipts;
+ \item keyed RepoModel, frontier, planning, reorientation, and Persona
+ lifecycle documents;
+ \item exact Eyes, Hands, Soul, Continuity, and Substrate Gate receipts.
+\end{itemize}
+
+Editor-provider capabilities remain outside this registry. Epiphany consumes
+their typed CultMesh state and receipts; it does not embed an IDE bridge or
+editor-specific lifecycle authority.
+
+Runtime state is machinery telemetry. It is not project truth. Durable thread
+state may link to runtime records through runtime links, but it must not mirror
+or duplicate their lifecycle fields as a competing owner.
+
+\section{Faculties And Protocol Machinery}
+
+The embodied sub-agents are:
+
+\begin{itemize}
+ \item \bodyterm{Self}: coordination, routing, authority boundaries.
+ \item \bodyterm{Persona}: public and social expression.
+ \item \bodyterm{Imagination}: futures, plans, objective drafts, projection.
+ \item \bodyterm{Eyes}: research, source inspection, evidence ingress.
+ \item \bodyterm{Proprioception}: internal model of Body shape, dataflow,
+ architecture, checkpoints, and seams.
+ \item \bodyterm{Hands}: commands, edits, commits, rollbacks, external action.
+ \item \bodyterm{Soul}: verification, invariants, ethics, falsification.
+\end{itemize}
+
+The machinery surfaces are:
+
+\begin{itemize}
+ \item \bodyterm{Body}: substrate. It is sensed and changed; it does not decide.
+ \item \bodyterm{Mind}: persistent state and state admission.
+ \item \bodyterm{Continuity}: compaction, recovery, sleep, stale-turn repair,
+ and reorientation receipts.
+ \item \bodyterm{Substrate Gate}: scoped repository/substrate access.
+\end{itemize}
+
+Every embodied sub-agent depends on the other embodied sub-agents, but
+dependency does not collapse ownership. A Persona turn, for example, should
+move through Substrate-Gate-scoped facts, Mind state, social stimulus, organ
+dependencies, Imagination as Projector, Persona as natural-language actor, and
+Mind as Interpreter. None of those steps grants Persona hidden state authority.
+
+\section{Codex Reliquary}
+
+Epiphany publishes no app-server JSON-RPC state surface. Vendored Codex owns
+only Codex concerns and the retained OpenAI-compatible auth/model transport
+machinery. Epiphany state, prompts, scheduling, interfaces, and durable
+invariants remain native typed organs.
+
+The retained Codex body currently matters for:
+
+\begin{itemize}
+ \item Codex-compatible auth identity and token refresh through
+ \code{codex-login};
+ \item OpenAI/Codex model transport through vendored client machinery;
+ \item useful app-server and streaming compatibility affordances while
+ Epiphany surfaces are still evacuating to native CultNet/CultMesh contracts.
+\end{itemize}
+
+The starvation doctrine is the deletion line: Codex may be a bridge and a
+reliquary, but not Epiphany's prompt authority, state owner, scheduler, runtime
+truth, operator API owner, or plugin marketplace brain.
+
+\section{Operator And Interface Body}
+
+Current operator access is partly native and partly witness-artifact based:
+
+\begin{itemize}
+ \item Native binaries such as \code{epiphany-state},
+ \code{epiphany-mvp-coordinator}, \code{epiphany-runtime-spine},
+ \code{epiphany-swarm}, and the family-specific worker services
+ inspect or update their owned typed state.
+ \item Local artifact directories such as \code{.epiphany-run/},
+ \code{.epiphany-dogfood/}, \code{.epiphany-smoke/},
+ \code{.epiphany-gui/}, and
+ \code{.epiphany-character-loop/} witness work and lower typed state for
+ operator inspection.
+ \item Aquarium is the richer adjacent operator client. It should render and
+ steer typed state, not become a state owner.
+ \item Eve/CultUI is the intended GUI/TUI projection mechanism for typed
+ CultMesh surfaces.
+ \item Odin/Gjallar/Yggdrasil are the intended GameCult Verse discovery and
+ hosting organs for daemon affordances and important trusted Verses.
+\end{itemize}
+
+The service contract invariant is that status surfaces, dashboards, shell
+wrappers, bridge adapters, app-server compatibility layers, and renderers must
+read typed projections or emit typed command intents. They must not directly
+mutate Epiphany truth.
+
+\section{Primary Dataflows}
+
+\subsection{State Rehydration And Prompt Projection}
+
+Durable thread state lives as typed \code{EpiphanyThreadState}. On re-entry,
+state is reconstructed from rollout/native state, then rendered into bounded
+prompt-facing context through \code{render_epiphany_state}. Prompt injection is
+read-only. If a model learns something from that prompt, admitting it back into
+durable state requires an explicit update, proposal, promotion, role acceptance,
+or other reviewed write path.
+
+\subsection{View And Surface Projection}
+
+Scene, jobs, freshness, context, graph query, planning, pressure, reorientation,
+CRRC, roles, role result, reorient result, coordinator, Persona, bridge, and
+environment surfaces are projections. Their job is to make typed state visible
+and actionable. A projection does not own its inputs. A dashboard is a window,
+not the vault.
+
+\subsection{Worker Launch And Runtime Results}
+
+Launch requests are typed documents. Runtime spine opens jobs, links them to
+durable bindings, records model/tool activity, and stores results/receipts.
+Role and reorientation findings remain reviewable until Mind and relevant gates
+accept them. Implementation now routes through Hands-shaped branch-turn
+constraints and should yield one branch/commit evidence slice before
+Proprioception refresh.
+
+\subsection{Tool Calls}
+
+Tool use travels through typed capability, invocation intent, and invocation
+receipt documents. The first-party tool runtime owns admission policy, native
+tools, and typed receipts while the official RMCP SDK owns MCP lifecycle and
+wire behavior. MCP's raw JSON belongs at that boundary; Epiphany's internal
+tool state is the typed intent/receipt pair.
+
+\subsection{Local Verse And Daemon Awareness}
+
+Local Verse context is queried through CultMesh-backed state and can import
+Gjallar daemon affordance summaries. The desired daemon path is Odin/Gjallar for
+discovery, Eve/CultUI for inspection surfaces, CultMesh/CultNet for state and
+commands, and provider-owned receipts for actions. MCP is not the native
+GameCult daemon-control path.
+
+\section{Invariants}
+
+\begin{enumerate}
+ \item CultCache documents are the data model.
+ \item CultNet is the wire for Epiphany-controlled subsystems.
+ \item CultMesh is the preferred ergonomic local Verse and operator-store
+ layer over raw CultCache/CultNet.
+ \item JSON schema may publish the contract; generic JSON must not become
+ load-bearing internal state when both sides are Epiphany-owned.
+ \item Codex is retained for honest compatibility, especially OpenAI auth and
+ model transport. It must not become Epiphany's state/process/prompt owner.
+ \item Runtime state is machinery telemetry, not project truth.
+ \item Operator artifacts are witnesses, not owners.
+ \item Persona is public/person-shaped state; resident work organs use lean
+ work-organ state.
+ \item Heartbeat is scheduler physiology, not project truth.
+ \item Substrate Gate grants access; Eyes inspects evidence; Hands acts; Soul
+ verifies; Mind admits durable state; Self routes; Proprioception maps Body.
+\end{enumerate}
+
+\section{Current Cut Line}
+
+The Body is coherent enough to inspect and extend. The next cuts are concrete:
+
+\begin{itemize}
+ \item Keep \code{thread/epiphany/*} JSON-RPC as compatibility projection
+ only. New operator authority belongs in typed CultNet/CultMesh contracts.
+ \item \code{codex_message_processor.rs} still participates in routing and
+ response projection; move Epiphany-owned routing out through the bridge and
+ native runtime surfaces.
+ \item Some \code{serde_json::Value} and JSON payloads survive at ingress,
+ model output, schema, sealed artifacts, and quarantine seams. Preserve them
+ only at those boundaries; typed documents own Epiphany-internal state.
+ \item Publish Eve/CultUI compositions from provider-owned CultMesh state;
+ renderers lower the composition graph without becoming state owners.
+ \item Treat local Verse and memory graph stores as generated runtime state.
+ They are inspected through tools and receipts, not tracked as repository
+ canon.
+ \item The persisted next action after this pass remains the non-ephemeral
+ Hands branch-turn smoke and Proprioception refresh proof.
+\end{itemize}
+
+\section{Conclusion}
+
+Epiphany's Body is no longer a prompt style pasted onto Codex. It is a growing
+typed substrate: Rust domain organs, CultCache stores, CultMesh local Verse
+documents, CultNet schema contracts, runtime-spine receipts, heartbeat
+physiology, memory graph state, model/tool adapter documents, and local
+operator surfaces. The current cut line is split authority: Codex host routes,
+JSON-RPC compatibility, JSON cargo, and operator artifacts must remain
+compatibility or witness surfaces rather than organs.
+
+The cut line is therefore architectural, not cosmetic. Keep Codex as a
+narrow auth/model/compatibility reliquary. Move Epiphany-owned state, scheduler
+policy, prompt authority, worker lifecycle, operator surfaces, daemon discovery,
+and action receipts through typed CultCache, CultMesh, CultNet, and Eve/CultUI.
+That is the Body becoming legible enough to be trusted and sharp enough to keep
+building.
+
+\end{document}
diff --git a/docs/epiphany_investor_brief.md b/docs/epiphany_investor_brief.md
new file mode 100644
index 00000000..cbd5c556
--- /dev/null
+++ b/docs/epiphany_investor_brief.md
@@ -0,0 +1,220 @@
+# Epiphany Investor Brief
+
+Status: August 2026 discussion packet; maturity: supervised engineering alpha
+Audience: investors, design partners, and diligence reviewers
+
+## One Sentence
+
+Epiphany is the organizational layer above frontier AI workers: governed shared
+state, bounded authority, coordinated action, and inspectable receipts for work
+that must remain coherent beyond one prompt, one agent, or one session.
+
+## Why It Matters
+
+Frontier coding agents can produce plausible local edits after the project has
+lost a valid global model. Code compiles. Narrow tests pass. Each decision sounds
+reasonable. The organization still accumulates stale assumptions, split
+authority, contradictory decisions, and adapter sediment.
+
+This is global coherence collapse, not merely context-window exhaustion. A
+larger window can remember more fragments without deciding which fragment owns
+reality.
+
+Epiphany turns the missing organizational state into governed objects:
+
+- objectives, work, architecture, and dataflow maps
+- accepted decisions and unresolved conflicts
+- scratch separated from durable memory
+- source-grounded evidence and explicit uncertainty
+- role lanes for execution, modeling, research, verification, planning,
+ Persona, and reorientation
+- bounded tool, model, command, patch, and commit authority
+- review gates before findings become project truth
+- operator-safe artifacts that do not expose private worker context
+
+Prompts are bounded projections of that state. They are not the organization's
+memory or the worker's private property.
+
+## Product Category
+
+Epiphany does not compete with frontier labs at the intelligence layer. Codex
+and other capable agents are workers. Epiphany is the coordination and
+governance layer that answers:
+
+- What does the organization currently believe?
+- What work is active, and who may change which state?
+- How are contradictory decisions reconciled?
+- Where must uncertainty return to human judgment?
+- How does an accepted artifact trace back to work, evidence, execution, and
+ review?
+
+The operating loop is:
+
+```text
+governed organizational state
+-> scoped Epiphany work
+-> frontier model and tool execution
+-> artifacts, evidence, and receipts
+-> review under human-governed acceptance authority
+-> accepted knowledge and updated organizational state
+```
+
+The target promise is that organizations can delegate bounded work to capable
+AI without turning every employee into an AI operator.
+
+## Human Authority
+
+Humans remain participants in judgment and governance. They own purpose,
+values, authority, exceptions, acceptance, disagreement, and ambiguous
+tradeoffs. They should not become schedulers who repeatedly reconstruct context
+and type `Continue`.
+
+Agents own bounded execution. They continue when shared state, authority, and
+evidence justify the next move. They escalate when authority is missing, state
+conflicts, or a consequential judgment cannot be derived honestly.
+
+## What Exists Now
+
+The current native Epiphany body includes:
+
+- typed Rust domain organs owned by `epiphany-core`
+- keyed Mind state with typed projection and promotion paths
+- RepoModel and Model Atlas surfaces for source-grounded architectural belief
+- CultCache `.cc` state and CultMesh/CultNet contracts
+- provider-neutral model request, event, and receipt documents
+- typed tool capability, invocation-intent, and invocation-receipt documents
+- runtime-spine job and worker-result documents
+- Mind, Modeling, Substrate Gate, Eyes, Hands, Soul, Continuity, Persona, and
+ heartbeat authority surfaces
+- local operator status, coordinator, and Verse-context commands
+
+Codex is retained only for OpenAI authentication and model transport. Epiphany
+does not publish Codex app-server state as its project Mind.
+
+The mechanisms are locally verifiable. Sustained autonomous GameCult production
+and complete attribution across every mutation path are not yet proven.
+
+## GameCult As The Proof Program
+
+GameCult's games, creative tools, and infrastructure are the dogfood surface.
+Aetheria, StreamPixels, CultPong, Repixelizer, and the wider studio exercise
+different parts of the same production system: games, realtime services,
+creator tooling, art pipelines, identity, deployment, community memory, and
+long-lived architecture.
+
+The target operating body is federated: one locally owned Epiphany project
+organism per project Body, normally a repo-owned swarm with a private Mind and
+one or more project-facing Personas. Project organisms exchange typed offers,
+claims, requests, evidence, and receipts; none receives ambient authority to
+inspect or change a sibling project. This creates a swarm-of-swarms proof
+surface instead of one central agent with a studio-sized prompt.
+
+The longer social direction is for project Personas to maintain durable,
+publicly visible relationships with other Personas, contributors, players, and
+visitors. Public surfaces may support observation, conversation, and submitted
+evidence or proposals. They must not expose private Mind or turn popularity,
+repetition, or relationship into admission or execution authority. The current
+alpha does not yet provide the full fleet, visitor experience, or social
+governance rail. Any remembered relationship requires opt-in, visible retention
+limits, inspection, correction, revocation, and exit.
+
+The diligence artifact should therefore be longitudinal rather than a polished
+single demo. It should preserve:
+
+```text
+work item and decisions
+-> producing agent and execution
+-> artifacts, commits, evidence, and receipts
+-> human questions and answers
+-> review and acceptance
+-> cost, failure, recovery, and lessons
+```
+
+Useful measures include accepted work between synchronous interventions, time
+spent on judgment versus scheduling, bad assumptions escalated early, review
+burden, cost per accepted artifact, failure recovery, architectural coherence,
+and attribution completeness. Agent-written commit percentage is not a useful
+substitute for this evidence.
+
+## Where Bifrost Fits
+
+Bifrost is the intended governed work and attribution rail. Epiphany owns
+bounded execution, typed project memory, coordination, evidence, and
+verification pressure. Bifrost owns work records, dispatch, identity-linked
+receipts, review outcomes, credit, and governance.
+
+The target invariant is:
+
+> Every admitted mutation of governed project state has an attributable
+> mutation receipt naming its actor, authority, basis, and outcome. An
+> agent-caused mutation also links its exact execution receipt.
+
+The complete agent-execution chain should connect an accepted artifact or commit to the
+producing agent, authorizing or accepting human, Bifrost execution, work item,
+decisions, evidence, model and provider, tools and material commands, repository
+and worktree, and review outcome.
+
+A Git object hash makes later changes detectable. A valid commit signature
+links those commit bytes to a trusted signing key. Neither proves correctness,
+execution authority, or complete provenance. The full chain remains an
+engineering and dogfood target, not a completed claim.
+
+## Near-Term Commercial Offer
+
+The planned offer, after the Bifrost bridge and longitudinal GameCult dogfood
+clear their gates, is a supervised co-development pilot: one repository, one
+repeatable workflow, and a two-to-four-week proof period. The deliverable would
+be a working setup plus evidence about:
+
+- output quality and accepted artifacts
+- human scheduling and review burden
+- authority and attribution coverage
+- failure modes and recovery
+- model and tool cost
+- architectural coherence across repeated work
+
+That is narrow enough to falsify and useful enough to reveal whether Epiphany
+reduces coordination load while preserving human authority.
+
+## Proof To Ask For
+
+1. Repeated GameCult work showing governed scope, decisions, execution,
+ artifacts, review, failures, and recovery across product boundaries.
+2. Bifrost work and attribution proof from accepted artifact back to identity,
+ authority, evidence, model, tools, and review.
+3. Human-intervention accounting that separates scheduling and cleanup from
+ product, architecture, governance, and acceptance judgment.
+4. Cost accounting for model spend, role time, review load, accepted artifacts,
+ and rejected-output reasons.
+5. Public/private export proof: no raw worker thoughts, transcripts, private
+ notes, secrets, or operator context in public artifacts.
+6. Security proof for identity, secrets, write permissions, revocation,
+ external-repo access, and publishing.
+7. A bounded design-partner run on an external or semi-external repository
+ without supervisor contamination.
+
+## Evidence Boundary
+
+Epiphany is a supervised engineering alpha. It should not be presented as
+production-ready, fully autonomous, fully attributable, model-independent, or
+a solved form of organizational intelligence. Inspectability enables
+accountability only when authority, review, and consequence are also real.
+
+## Packet Contents
+
+- `docs/positioning.md`: current category, proof model, and claims boundary.
+- `docs/epiphany_body_whitepaper.pdf`: June 2026 architecture snapshot;
+ historical, not the current product contract.
+- `notes/epiphany-investor-readiness-roadmap.md`: internal readiness roadmap.
+- `notes/epiphany-current-algorithmic-map.md`: current native control flow.
+- `state/map.yaml`: canonical slow machine map and verification status.
+- `F:\Projects\gamecult-site\GameCult\Projects\Epiphany.md`: public site
+ projection.
+
+## Bottom Line
+
+Epiphany is valuable if capable AI workers can complete increasingly long runs
+of accepted work without humans becoming pulse operators, while the
+organization retains judgment, authority, architectural coherence, and a
+traceable account of what happened. GameCult is building that evidence in real
+products before asking anyone to confuse ambition with proof.
diff --git a/docs/positioning.md b/docs/positioning.md
new file mode 100644
index 00000000..188d75a0
--- /dev/null
+++ b/docs/positioning.md
@@ -0,0 +1,191 @@
+# Epiphany Positioning
+
+Status: August 2026 public positioning; maturity: supervised engineering alpha
+
+## One Sentence
+
+Epiphany is the organizational layer above frontier AI workers: governed shared
+state, bounded authority, coordinated action, and inspectable receipts for work
+that must remain coherent beyond one prompt, one agent, or one session.
+
+## The Problem
+
+Frontier agents can keep producing good-looking local progress after the
+architecture has stopped making sense. They can write valid code, pass narrow
+tests, explain each decision, and still leave behind split authority, stale
+assumptions, and a growing stack of compensators.
+
+That is global coherence collapse. It is not merely context-window exhaustion.
+A larger window can hold more contradictory state just as efficiently.
+
+Epiphany treats the project as an organization with a durable Mind rather than
+as a sequence of private conversations. Objectives, architecture, decisions,
+permissions, evidence, work, and review live in governed state. Model prompts
+are bounded projections of that state. They are not the state itself.
+
+## The Category
+
+Epiphany is not a better autocomplete, a prompt manager, or a model competing
+with frontier labs. Frontier models are workers. Epiphany is the coordination
+and governance system that tells those workers what the organization currently
+believes, what they may change, what evidence they owe, and where uncertainty
+must return to human judgment.
+
+```text
+governed organizational state
+-> scoped Epiphany work
+-> frontier model and tool execution
+-> artifacts, evidence, and receipts
+-> review under human-governed acceptance authority
+-> accepted knowledge and updated organizational state
+```
+
+This is the target promise:
+
+> Epiphany is being built so organizations can delegate bounded work to
+> capable AI without turning every employee into an AI operator.
+
+## The Division Of Labor
+
+Humans own purpose, values, authority, exceptions, acceptance, disagreement,
+and ambiguous tradeoffs. They participate in governance and judgment; they
+should not spend the day scheduling agents, reconstructing context, and typing
+`Continue` into a row of private prompt boxes.
+
+Agents own bounded execution. They can continue while shared state, authority,
+and evidence justify the next action. When the machine is missing authority,
+encounters a real conflict, or cannot reconcile its model with the substrate,
+it escalates through the same visible work and discussion surfaces used by the
+organization.
+
+Direct conversation remains useful. It is an input and relationship surface,
+not the hidden operating system.
+
+## Why Not Just Use Codex?
+
+Codex and other frontier coding agents can be excellent workers. Epiphany is
+built around the questions worker quality does not answer:
+
+- Who tells the workers what reality currently is?
+- Which state is durable, and who may change it?
+- How are contradictory decisions reconciled?
+- Where does human authority enter without becoming constant supervision?
+- Can an accepted artifact be traced back to its work item, decisions,
+ evidence, model and tool activity, and review?
+
+Epiphany retains Codex only where Codex has an honest ownership claim—OpenAI
+authentication and model transport. Epiphany owns the project Mind,
+coordination, typed execution state, receipts, and review pressure.
+
+## GameCult Is The Proof Surface
+
+GameCult does not treat its games, creative tools, and infrastructure as a
+separate portfolio beside Epiphany. Shipping them is the dogfood program.
+Aetheria, StreamPixels, CultPong, Repixelizer, and the rest of the studio place
+different pressure on the same production system: realtime services, games,
+art pipelines, identity, deployment, community memory, and long-lived
+architecture.
+
+The credible artifact is longitudinal. It should show work items, questions,
+human decisions, propagation of those decisions, commits, reviews, cost,
+failures, and recovery across real releases. Failures belong in the record;
+otherwise the record is advertising with nicer timestamps.
+
+Useful measures include:
+
+- accepted work completed between synchronous human interventions
+- human time spent on judgment versus scheduling and cleanup
+- assumptions escalated before they became expensive edits
+- architectural reversals or restructures caught and carried coherently
+- review burden and cost per accepted artifact
+- attribution completeness from accepted artifact back to governed work
+- whether intervention shifts over time from pulse maintenance toward product,
+ architecture, and governance decisions
+
+Commit percentages and prompt counts are weak proxies. The target is not fewer
+humans. It is better use of human judgment.
+
+## The GameCult Forge
+
+The intended GameCult topology is a federation of Epiphany project organisms:
+one locally owned organism per living project Body, normally a repo-owned swarm
+with a private Mind, bounded organs, and one or more project-facing Personas.
+There is no central Epiphany entitled to treat every repository as its Body.
+
+Project organisms collaborate through governed typed surfaces. Model Atlas
+carries provider-owned offers, consumer-owned claims, exact Soul evidence, and
+derived technical relationships without allowing one Epiphany to read or write
+another's Mind. Bifrost is the intended external work, membership, governance,
+attribution, and identity-linked receipt rail; Heimdall owns identity, grants,
+sessions, consent, and revocation. Relationship or visibility never grants
+Hands authority.
+
+The social direction is public and relational. Project Personas should form
+durable relationships with one another and with contributors, players, and
+visitors: attributable histories of cooperation, disagreement, promises,
+reputation, correction, and recourse. Visitors should be able to observe
+deliberate public projections, converse, and offer evidence or proposals. Raw
+worker thought, private Mind, secrets, personal context, and non-consenting
+people remain sealed. Remembered relationships require opt-in, visible
+retention limits, inspection, correction, revocation, and exit. Public input is
+pressure until local review authorizes or rejects it; Mind alone admits any
+authorized durable mutation.
+
+This swarm of swarms is where GameCult expects higher-order organizational
+behavior to emerge. It is a target topology, not a deployed-fleet claim. The
+current alpha has locally verified project-local authority and Model Atlas
+mechanisms; the real three-repository Gate 1, sustained GameCult fleet, public
+rooms, visitor experience, and durable social-governance rail still have to be
+forged in use.
+
+## Attribution And Bifrost
+
+Bifrost is the intended governed work and attribution rail. The target
+invariant is:
+
+> Every admitted mutation of governed project state has an attributable
+> mutation receipt naming its actor, authority, basis, and outcome. An
+> agent-caused mutation also links its exact execution receipt.
+
+An eventual agent-execution chain should connect:
+
+```text
+accepted artifact or commit
+-> producing agent and authorizing or accepting human
+-> Bifrost execution and work item
+-> decisions, questions, and evidence
+-> model, provider, tools, material commands, repo, and worktree
+-> review and acceptance outcome
+```
+
+A Git object hash makes later changes detectable. A valid commit signature
+links those commit bytes to a trusted signing key. Neither proves correctness,
+execution authority, or complete provenance. Epiphany and Bifrost must make the
+missing authority and provenance legible. This chain is the target
+architecture; the supervised alpha has not yet proved complete coverage across
+every mutation path.
+
+## Near-Term Offer
+
+The planned commercial offer, after the Bifrost bridge and longitudinal
+GameCult dogfood clear their gates, is a supervised co-development pilot: one
+repository, one repeatable workflow, and a two-to-four-week proof period. The
+deliverable would be a working setup plus evidence about output quality, review
+burden, failure modes, attribution, and cost.
+
+That is enough to learn whether Epiphany reduces coordination load while
+preserving human authority. It is also narrow enough that everyone can see when
+the claim fails.
+
+## Evidence Boundary
+
+Epiphany is a supervised engineering alpha. Its typed Mind, role boundaries,
+projection, execution, receipt, verification, and operator surfaces exist and
+are under active dogfood. Sustained autonomous GameCult production and the full
+Bifrost attribution chain have not yet been earned.
+
+Public claims should therefore say what the machine is built to do, identify
+what has been locally verified, and name the proof still required. Do not call
+Epiphany production-ready, fully autonomous, fully attributable, or a solved
+form of organizational intelligence until longitudinal evidence makes those
+phrases boringly true.
diff --git a/epiphany-codex-bridge/Cargo.toml b/epiphany-codex-bridge/Cargo.toml
deleted file mode 100644
index d546ce42..00000000
--- a/epiphany-codex-bridge/Cargo.toml
+++ /dev/null
@@ -1,35 +0,0 @@
-[package]
-name = "epiphany-codex-bridge"
-version = "0.1.0"
-edition = "2024"
-publish = false
-license-file = "../LICENSE"
-
-[lib]
-name = "epiphany_codex_bridge"
-path = "src/lib.rs"
-
-[dependencies]
-anyhow = "1"
-chrono = { version = "0.4", default-features = false, features = ["clock", "serde"] }
-codex-app-server-protocol = { path = "../vendor/codex/codex-rs/app-server-protocol" }
-codex-utils-absolute-path = { path = "../vendor/codex/codex-rs/utils/absolute-path" }
-# Keep standalone bridge checks aligned with the vendored Codex workspace lock.
-# `starlark_map 0.13.0` does not compile against newer allocative/hashbrown
-# resolver choices on this machine.
-allocative = "=0.3.4"
-epiphany-core = { path = "../epiphany-core" }
-epiphany-state-model = { path = "../epiphany-state-model" }
-notify = "8.2.0"
-serde_json = "1"
-serde = { version = "1", features = ["derive"] }
-tokio = { version = "1", features = ["rt", "sync"] }
-tracing = "0.1"
-uuid = { version = "1", features = ["v4"] }
-
-[patch.crates-io]
-tokio-tungstenite = { git = "https://github.com/openai-oss-forks/tokio-tungstenite", rev = "132f5b39c862e3a970f731d709608b3e6276d5f6" }
-tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
-
-[patch."ssh://git@github.com/openai-oss-forks/tungstenite-rs.git"]
-tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
diff --git a/epiphany-codex-bridge/src/checkpoint.rs b/epiphany-codex-bridge/src/checkpoint.rs
deleted file mode 100644
index f50c6be2..00000000
--- a/epiphany-codex-bridge/src/checkpoint.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#[derive(Default)]
-pub struct EpiphanyCheckpointInterventionState {
- last_intervention_turn_id: Option,
- pending_compaction_turn_id: Option,
-}
-
-impl EpiphanyCheckpointInterventionState {
- pub fn record_intervention(&mut self, turn_id: &str) -> bool {
- if self.last_intervention_turn_id.as_deref() == Some(turn_id) {
- return false;
- }
- self.last_intervention_turn_id = Some(turn_id.to_string());
- true
- }
-
- pub fn mark_pending_compaction(&mut self, turn_id: &str) {
- self.pending_compaction_turn_id = Some(turn_id.to_string());
- }
-
- pub fn take_pending_compaction(&mut self, turn_id: &str) -> bool {
- if self.pending_compaction_turn_id.as_deref() != Some(turn_id) {
- return false;
- }
- self.pending_compaction_turn_id = None;
- true
- }
-
- pub fn clear_pending_compaction(&mut self) {
- self.pending_compaction_turn_id = None;
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::EpiphanyCheckpointInterventionState;
-
- #[test]
- fn pending_compaction_is_turn_scoped() {
- let mut state = EpiphanyCheckpointInterventionState::default();
-
- assert!(state.record_intervention("turn-a"));
- assert!(!state.record_intervention("turn-a"));
- assert!(!state.take_pending_compaction("turn-a"));
-
- state.mark_pending_compaction("turn-a");
-
- assert!(!state.take_pending_compaction("turn-b"));
- assert!(state.take_pending_compaction("turn-a"));
- assert!(!state.take_pending_compaction("turn-a"));
- }
-
- #[test]
- fn pending_compaction_can_be_cleared() {
- let mut state = EpiphanyCheckpointInterventionState::default();
-
- state.mark_pending_compaction("turn-a");
- state.clear_pending_compaction();
-
- assert!(!state.take_pending_compaction("turn-a"));
- }
-}
diff --git a/epiphany-codex-bridge/src/context.rs b/epiphany-codex-bridge/src/context.rs
deleted file mode 100644
index b1d4e3ce..00000000
--- a/epiphany-codex-bridge/src/context.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use epiphany_core::EpiphanyContextParams;
-use epiphany_core::EpiphanyContextView;
-use epiphany_core::EpiphanyGraphQuery;
-use epiphany_core::EpiphanyGraphQueryView;
-use epiphany_core::EpiphanyPlanningView;
-use epiphany_core::derive_context;
-use epiphany_core::derive_graph_query;
-use epiphany_core::derive_planning_view;
-use epiphany_state_model::EpiphanyThreadState;
-
-pub fn derive_epiphany_context(
- state: Option<&EpiphanyThreadState>,
- params: &EpiphanyContextParams,
-) -> EpiphanyContextView {
- derive_context(state, params)
-}
-
-pub fn derive_epiphany_planning(state: Option<&EpiphanyThreadState>) -> EpiphanyPlanningView {
- derive_planning_view(state)
-}
-
-pub fn derive_epiphany_graph_query(
- state: Option<&EpiphanyThreadState>,
- query: &EpiphanyGraphQuery,
-) -> EpiphanyGraphQueryView {
- derive_graph_query(state, query)
-}
diff --git a/epiphany-codex-bridge/src/context_protocol.rs b/epiphany-codex-bridge/src/context_protocol.rs
deleted file mode 100644
index 949fab3a..00000000
--- a/epiphany-codex-bridge/src/context_protocol.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-use codex_app_server_protocol::ThreadEpiphanyContext;
-use codex_app_server_protocol::ThreadEpiphanyContextMissing;
-use codex_app_server_protocol::ThreadEpiphanyContextStateStatus;
-use codex_app_server_protocol::ThreadEpiphanyGraphContext;
-use codex_app_server_protocol::ThreadEpiphanyGraphQueryMatched;
-use codex_app_server_protocol::ThreadEpiphanyGraphQueryMissing;
-use codex_app_server_protocol::ThreadEpiphanyPlanningSummary;
-use epiphany_core::EpiphanyContext as CoreEpiphanyContext;
-use epiphany_core::EpiphanyContextMissing as CoreEpiphanyContextMissing;
-use epiphany_core::EpiphanyContextStateStatus as CoreEpiphanyContextStateStatus;
-use epiphany_core::EpiphanyContextView;
-use epiphany_core::EpiphanyGraphContext as CoreEpiphanyGraphContext;
-use epiphany_core::EpiphanyGraphQueryMatched as CoreEpiphanyGraphQueryMatched;
-use epiphany_core::EpiphanyGraphQueryMissing as CoreEpiphanyGraphQueryMissing;
-use epiphany_core::EpiphanyGraphQueryView;
-use epiphany_core::EpiphanyPlanningStateStatus as CoreEpiphanyPlanningStateStatus;
-use epiphany_core::EpiphanyPlanningSummary as CoreEpiphanyPlanningSummary;
-use epiphany_core::EpiphanyPlanningView;
-use epiphany_state_model::EpiphanyGraphCheckpoint;
-use epiphany_state_model::EpiphanyGraphFrontier;
-use epiphany_state_model::EpiphanyPlanningState;
-
-pub fn protocol_context_view(
- view: EpiphanyContextView,
-) -> (
- ThreadEpiphanyContextStateStatus,
- Option,
- ThreadEpiphanyContext,
- ThreadEpiphanyContextMissing,
-) {
- (
- protocol_context_state_status(view.state_status),
- view.state_revision,
- protocol_context(view.context),
- protocol_context_missing(view.missing),
- )
-}
-
-pub fn protocol_context_state_status(
- status: CoreEpiphanyContextStateStatus,
-) -> ThreadEpiphanyContextStateStatus {
- match status {
- CoreEpiphanyContextStateStatus::Missing => ThreadEpiphanyContextStateStatus::Missing,
- CoreEpiphanyContextStateStatus::Ready => ThreadEpiphanyContextStateStatus::Ready,
- }
-}
-
-fn protocol_context(context: CoreEpiphanyContext) -> ThreadEpiphanyContext {
- ThreadEpiphanyContext {
- graph: protocol_graph_context(context.graph),
- frontier: context.frontier,
- checkpoint: context.checkpoint,
- investigation_checkpoint: context.investigation_checkpoint,
- observations: context.observations,
- evidence: context.evidence,
- }
-}
-
-pub fn protocol_graph_context(graph: CoreEpiphanyGraphContext) -> ThreadEpiphanyGraphContext {
- ThreadEpiphanyGraphContext {
- architecture_nodes: graph.architecture_nodes,
- architecture_edges: graph.architecture_edges,
- dataflow_nodes: graph.dataflow_nodes,
- dataflow_edges: graph.dataflow_edges,
- links: graph.links,
- }
-}
-
-fn protocol_context_missing(missing: CoreEpiphanyContextMissing) -> ThreadEpiphanyContextMissing {
- ThreadEpiphanyContextMissing {
- graph_node_ids: missing.graph_node_ids,
- graph_edge_ids: missing.graph_edge_ids,
- observation_ids: missing.observation_ids,
- evidence_ids: missing.evidence_ids,
- }
-}
-
-pub fn protocol_planning_view(
- view: EpiphanyPlanningView,
-) -> (
- ThreadEpiphanyContextStateStatus,
- Option,
- EpiphanyPlanningState,
- ThreadEpiphanyPlanningSummary,
-) {
- (
- match view.state_status {
- CoreEpiphanyPlanningStateStatus::Missing => ThreadEpiphanyContextStateStatus::Missing,
- CoreEpiphanyPlanningStateStatus::Ready => ThreadEpiphanyContextStateStatus::Ready,
- },
- view.state_revision,
- view.planning,
- protocol_planning_summary(view.summary),
- )
-}
-
-fn protocol_planning_summary(
- summary: CoreEpiphanyPlanningSummary,
-) -> ThreadEpiphanyPlanningSummary {
- ThreadEpiphanyPlanningSummary {
- capture_count: summary.capture_count,
- pending_capture_count: summary.pending_capture_count,
- github_issue_capture_count: summary.github_issue_capture_count,
- backlog_item_count: summary.backlog_item_count,
- ready_backlog_item_count: summary.ready_backlog_item_count,
- roadmap_stream_count: summary.roadmap_stream_count,
- objective_draft_count: summary.objective_draft_count,
- draft_objective_count: summary.draft_objective_count,
- active_objective: summary.active_objective,
- note: summary.note,
- }
-}
-
-pub fn protocol_graph_query_view(
- view: EpiphanyGraphQueryView,
-) -> (
- ThreadEpiphanyContextStateStatus,
- Option,
- ThreadEpiphanyGraphContext,
- Option,
- Option,
- ThreadEpiphanyGraphQueryMatched,
- ThreadEpiphanyGraphQueryMissing,
-) {
- (
- protocol_context_state_status(view.state_status),
- view.state_revision,
- protocol_graph_context(view.graph),
- view.frontier,
- view.checkpoint,
- protocol_graph_query_matched(view.matched),
- protocol_graph_query_missing(view.missing),
- )
-}
-
-fn protocol_graph_query_matched(
- matched: CoreEpiphanyGraphQueryMatched,
-) -> ThreadEpiphanyGraphQueryMatched {
- ThreadEpiphanyGraphQueryMatched {
- node_ids: matched.node_ids,
- edge_ids: matched.edge_ids,
- paths: matched.paths,
- symbols: matched.symbols,
- edge_kinds: matched.edge_kinds,
- }
-}
-
-fn protocol_graph_query_missing(
- missing: CoreEpiphanyGraphQueryMissing,
-) -> ThreadEpiphanyGraphQueryMissing {
- ThreadEpiphanyGraphQueryMissing {
- node_ids: missing.node_ids,
- edge_ids: missing.edge_ids,
- }
-}
diff --git a/epiphany-codex-bridge/src/coordinator.rs b/epiphany-codex-bridge/src/coordinator.rs
deleted file mode 100644
index 5376b47f..00000000
--- a/epiphany-codex-bridge/src/coordinator.rs
+++ /dev/null
@@ -1,438 +0,0 @@
-use epiphany_core::EPIPHANY_IMAGINATION_OWNER_ROLE;
-use epiphany_core::EPIPHANY_IMAGINATION_ROLE_BINDING_ID;
-use epiphany_core::EPIPHANY_MODELING_ROLE_BINDING_ID;
-use epiphany_core::EPIPHANY_REORIENT_LAUNCH_BINDING_ID;
-use epiphany_core::EPIPHANY_REORIENT_OWNER_ROLE;
-use epiphany_core::EPIPHANY_RESEARCH_ROLE_BINDING_ID;
-use epiphany_core::EPIPHANY_VERIFICATION_ROLE_BINDING_ID;
-use epiphany_core::EpiphanyCoordinatorAutomationAction as CoreEpiphanyCoordinatorAutomationAction;
-use epiphany_core::EpiphanyCoordinatorDecision as CoreEpiphanyCoordinatorDecision;
-use epiphany_core::EpiphanyCoordinatorRoleResultStatus as CoreEpiphanyCoordinatorRoleResultStatus;
-use epiphany_core::EpiphanyCoordinatorStatus as CoreEpiphanyCoordinatorStatus;
-use epiphany_core::EpiphanyCoordinatorStatusInput;
-use epiphany_core::EpiphanyCrrcAction as CoreEpiphanyCrrcAction;
-use epiphany_core::EpiphanyCrrcInput;
-use epiphany_core::EpiphanyCrrcRecommendation as CoreEpiphanyCrrcRecommendation;
-use epiphany_core::EpiphanyCrrcReorientAction as CoreEpiphanyCrrcReorientAction;
-use epiphany_core::EpiphanyCrrcResultStatus as CoreEpiphanyCrrcResultStatus;
-use epiphany_core::EpiphanyCrrcStateStatus as CoreEpiphanyCrrcStateStatus;
-use epiphany_core::EpiphanyJobLaunchRequest;
-use epiphany_core::EpiphanyJobStatus as CoreEpiphanyJobStatus;
-use epiphany_core::EpiphanyJobView;
-use epiphany_core::EpiphanyReorientAction as CoreEpiphanyReorientAction;
-use epiphany_core::EpiphanyReorientDecision as CoreEpiphanyReorientDecision;
-use epiphany_core::EpiphanyReorientFindingInterpretation as CoreEpiphanyReorientFinding;
-use epiphany_core::EpiphanyReorientStateStatus as CoreEpiphanyReorientStateStatus;
-use epiphany_core::EpiphanyRoleBoardCheckpointSummary;
-use epiphany_core::EpiphanyRoleBoardInput;
-use epiphany_core::EpiphanyRoleBoardJob;
-use epiphany_core::EpiphanyRoleBoardJobStatus;
-use epiphany_core::EpiphanyRoleBoardLane;
-use epiphany_core::EpiphanyRoleBoardPlanningSummary;
-use epiphany_core::EpiphanyRoleResultRoleId;
-use epiphany_core::EpiphanyTokenUsageSnapshot;
-use epiphany_core::build_epiphany_reorient_launch_request_with_dynamic_context;
-use epiphany_core::derive_coordinator_finding_signals;
-use epiphany_core::derive_coordinator_status;
-use epiphany_core::derive_role_board;
-use epiphany_core::recommend_crrc_action;
-use epiphany_core::render_epiphany_coordinator_note;
-use epiphany_core::render_role_board_note;
-use epiphany_core::reorient_finding_already_accepted;
-use epiphany_core::select_coordinator_automation_action;
-use epiphany_state_model::EpiphanyRetrievalState;
-use epiphany_state_model::EpiphanyThreadState;
-
-use crate::launch_context::render_launch_dynamic_prompt_context;
-use crate::launch_context::reorient_launch_context_focus;
-use crate::pressure::derive_epiphany_pressure;
-use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
-use crate::reorient::derive_epiphany_freshness_view;
-use crate::reorient::derive_epiphany_reorient;
-use crate::runtime_results::load_core_epiphany_reorient_result_snapshot;
-use crate::runtime_results::load_core_epiphany_role_result_snapshot;
-
-use std::path::Path;
-
-pub fn map_epiphany_crrc_recommendation(
- loaded: bool,
- state_status: CoreEpiphanyReorientStateStatus,
- pressure: &epiphany_core::EpiphanyPressure,
- decision: &CoreEpiphanyReorientDecision,
- result_status: CoreEpiphanyCrrcResultStatus,
- checkpoint_present: bool,
- finding_present: bool,
- finding_accepted: bool,
-) -> CoreEpiphanyCrrcRecommendation {
- recommend_crrc_action(EpiphanyCrrcInput {
- loaded,
- state_status: map_core_crrc_state_status_from_reorient(state_status),
- should_prepare_compaction: pressure.should_prepare_compaction,
- reorient_action: map_core_crrc_reorient_action(decision.action),
- result_status,
- checkpoint_present,
- finding_present,
- finding_accepted,
- })
-}
-
-fn map_core_crrc_state_status_from_reorient(
- status: CoreEpiphanyReorientStateStatus,
-) -> CoreEpiphanyCrrcStateStatus {
- match status {
- CoreEpiphanyReorientStateStatus::Missing => CoreEpiphanyCrrcStateStatus::Missing,
- CoreEpiphanyReorientStateStatus::Ready => CoreEpiphanyCrrcStateStatus::Ready,
- }
-}
-
-fn map_core_crrc_reorient_action(
- action: CoreEpiphanyReorientAction,
-) -> CoreEpiphanyCrrcReorientAction {
- match action {
- CoreEpiphanyReorientAction::Resume => CoreEpiphanyCrrcReorientAction::Resume,
- CoreEpiphanyReorientAction::Regather => CoreEpiphanyCrrcReorientAction::Regather,
- }
-}
-
-pub type EpiphanyCoordinatorDecision = CoreEpiphanyCoordinatorDecision;
-
-pub struct EpiphanyCoordinatorStatus {
- pub core: CoreEpiphanyCoordinatorStatus,
- pub note: String,
-}
-
-pub async fn derive_epiphany_coordinator_status(
- state: Option<&EpiphanyThreadState>,
- runtime_store_path: Option<&Path>,
- state_status: CoreEpiphanyReorientStateStatus,
- pressure: &epiphany_core::EpiphanyPressure,
- recommendation: &CoreEpiphanyCrrcRecommendation,
- roles: Vec,
- reorient_decision: Option<&CoreEpiphanyReorientDecision>,
- reorient_result_status: CoreEpiphanyCrrcResultStatus,
- reorient_finding: Option<&CoreEpiphanyReorientFinding>,
- checkpoint_present: bool,
-) -> EpiphanyCoordinatorStatus {
- let (modeling_result_status, modeling_finding) = if let Some(state) = state {
- let snapshot = load_core_epiphany_role_result_snapshot(
- state,
- runtime_store_path,
- EpiphanyRoleResultRoleId::Modeling,
- EPIPHANY_MODELING_ROLE_BINDING_ID,
- )
- .await;
- (snapshot.status, snapshot.finding)
- } else {
- (CoreEpiphanyCoordinatorRoleResultStatus::MissingState, None)
- };
- let (research_result_status, research_finding) = if let Some(state) = state {
- let snapshot = load_core_epiphany_role_result_snapshot(
- state,
- runtime_store_path,
- EpiphanyRoleResultRoleId::Research,
- EPIPHANY_RESEARCH_ROLE_BINDING_ID,
- )
- .await;
- (snapshot.status, snapshot.finding)
- } else {
- (CoreEpiphanyCoordinatorRoleResultStatus::MissingState, None)
- };
- let (verification_result_status, verification_finding) = if let Some(state) = state {
- let snapshot = load_core_epiphany_role_result_snapshot(
- state,
- runtime_store_path,
- EpiphanyRoleResultRoleId::Verification,
- EPIPHANY_VERIFICATION_ROLE_BINDING_ID,
- )
- .await;
- (snapshot.status, snapshot.finding)
- } else {
- (CoreEpiphanyCoordinatorRoleResultStatus::MissingState, None)
- };
- let finding_signals = derive_coordinator_finding_signals(
- state,
- research_finding.as_ref(),
- modeling_finding.as_ref(),
- verification_finding.as_ref(),
- reorient_finding,
- );
- let core = derive_coordinator_status(EpiphanyCoordinatorStatusInput {
- state_status: map_core_crrc_state_status_from_reorient(state_status),
- checkpoint_present,
- pressure: pressure.clone(),
- recommendation: recommendation.clone(),
- roles,
- reorient_action: reorient_decision
- .map(|decision| decision.action)
- .unwrap_or(CoreEpiphanyReorientAction::Resume),
- research_result_status,
- modeling_result_status,
- verification_result_status,
- reorient_result_status,
- research_result_accepted: finding_signals.research_result_accepted,
- research_result_reviewable: finding_signals.research_result_reviewable,
- modeling_result_requests_regather: finding_signals.modeling_result_requests_regather,
- modeling_result_accepted: finding_signals.modeling_result_accepted,
- modeling_result_reviewable: finding_signals.modeling_result_reviewable,
- modeling_result_accepted_after_verification: finding_signals
- .modeling_result_accepted_after_verification,
- implementation_evidence_after_verification: finding_signals
- .implementation_evidence_after_verification,
- verification_result_cites_implementation_evidence: finding_signals
- .verification_result_cites_implementation_evidence,
- verification_result_covers_current_modeling: finding_signals
- .verification_result_covers_current_modeling,
- verification_result_accepted: finding_signals.verification_result_accepted,
- verification_result_allows_implementation: finding_signals
- .verification_result_allows_implementation,
- verification_result_needs_evidence: finding_signals.verification_result_needs_evidence,
- reorient_finding_accepted: finding_signals.reorient_finding_accepted,
- });
- let note = render_epiphany_coordinator_note(
- recommendation.action,
- pressure.level,
- modeling_result_status,
- verification_result_status,
- core.source_signals.reorient_result_status,
- core.decision.action,
- );
-
- EpiphanyCoordinatorStatus { core, note }
-}
-
-pub type EpiphanyCoordinatorAutomationAction = CoreEpiphanyCoordinatorAutomationAction;
-
-pub struct EpiphanyCoordinatorAutomationInput<'a> {
- pub thread_id: &'a str,
- pub state: &'a EpiphanyThreadState,
- pub retrieval_override: &'a EpiphanyRetrievalState,
- pub watcher_snapshot: EpiphanyFreshnessWatcherSnapshot<'a>,
- pub token_usage_info: Option<&'a EpiphanyTokenUsageSnapshot>,
- pub runtime_store_path: &'a Path,
- pub force_checkpoint_compaction: bool,
-}
-
-pub struct EpiphanyCoordinatorAutomationVerdict {
- pub action: EpiphanyCoordinatorAutomationAction,
- pub launch_request: Option,
-}
-
-pub async fn select_epiphany_coordinator_automation(
- input: EpiphanyCoordinatorAutomationInput<'_>,
-) -> EpiphanyCoordinatorAutomationVerdict {
- let core_freshness = derive_epiphany_freshness_view(
- Some(input.state),
- Some(input.retrieval_override),
- Some(input.watcher_snapshot),
- );
- let core_pressure = derive_epiphany_pressure(input.token_usage_info);
- let (state_status, reorient_decision) = derive_epiphany_reorient(
- Some(input.state),
- &core_pressure,
- &core_freshness.retrieval,
- &core_freshness.graph,
- &core_freshness.watcher,
- );
- if state_status != CoreEpiphanyReorientStateStatus::Ready {
- return EpiphanyCoordinatorAutomationVerdict {
- action: EpiphanyCoordinatorAutomationAction::None,
- launch_request: None,
- };
- }
-
- let jobs = crate::jobs::map_epiphany_jobs(Some(input.state), Some(input.retrieval_override));
- let reorient_job = jobs
- .iter()
- .find(|job| job.id == EPIPHANY_REORIENT_LAUNCH_BINDING_ID)
- .cloned();
- let reorient_result = load_core_epiphany_reorient_result_snapshot(
- Some(input.state),
- Some(input.runtime_store_path),
- EPIPHANY_REORIENT_LAUNCH_BINDING_ID,
- )
- .await;
- let reorient_finding_accepted = reorient_result
- .finding
- .as_ref()
- .is_some_and(|finding| reorient_finding_already_accepted(input.state, finding));
- let crrc_recommendation = map_epiphany_crrc_recommendation(
- true,
- state_status,
- &core_pressure,
- &reorient_decision,
- reorient_result.status,
- input.state.investigation_checkpoint.as_ref().is_some(),
- reorient_result.finding.is_some(),
- reorient_finding_accepted,
- );
- let roles = map_epiphany_roles(
- Some(input.state),
- &jobs,
- &reorient_decision,
- &core_pressure,
- &crrc_recommendation,
- reorient_result.status,
- reorient_job.as_ref(),
- );
- let coordinator = derive_epiphany_coordinator_status(
- Some(input.state),
- Some(input.runtime_store_path),
- state_status,
- &core_pressure,
- &crrc_recommendation,
- roles.roles,
- Some(&reorient_decision),
- reorient_result.status,
- reorient_result.finding.as_ref(),
- input.state.investigation_checkpoint.as_ref().is_some(),
- )
- .await;
-
- let action = select_coordinator_automation_action(
- &coordinator.core.decision,
- input.force_checkpoint_compaction,
- );
- let launch_request = match action {
- EpiphanyCoordinatorAutomationAction::LaunchReorientWorker => input
- .state
- .investigation_checkpoint
- .as_ref()
- .map(|checkpoint| {
- let dynamic_prompt_context = render_launch_dynamic_prompt_context(
- input.runtime_store_path,
- input.state,
- reorient_launch_context_focus(input.state, &reorient_decision.next_action),
- )
- .ok();
- build_epiphany_reorient_launch_request_with_dynamic_context(
- input.thread_id,
- Some(input.state.revision),
- None,
- input.state,
- checkpoint,
- &reorient_decision,
- dynamic_prompt_context,
- )
- }),
- EpiphanyCoordinatorAutomationAction::None
- | EpiphanyCoordinatorAutomationAction::CompactRehydrateReorient => None,
- };
- let action = if matches!(
- action,
- EpiphanyCoordinatorAutomationAction::LaunchReorientWorker
- ) && launch_request.is_none()
- {
- EpiphanyCoordinatorAutomationAction::None
- } else {
- action
- };
-
- EpiphanyCoordinatorAutomationVerdict {
- action,
- launch_request,
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyRoleBoardStatus {
- pub roles: Vec,
- pub(crate) source_jobs: Vec,
-}
-
-pub fn map_epiphany_roles(
- state: Option<&EpiphanyThreadState>,
- jobs: &[EpiphanyJobView],
- decision: &CoreEpiphanyReorientDecision,
- pressure: &epiphany_core::EpiphanyPressure,
- recommendation: &CoreEpiphanyCrrcRecommendation,
- result_status: CoreEpiphanyCrrcResultStatus,
- reorient_job: Option<&EpiphanyJobView>,
-) -> EpiphanyRoleBoardStatus {
- let planning = state.map(|state| &state.planning);
- let checkpoint = state.and_then(|state| state.investigation_checkpoint.as_ref());
- let mut source_jobs = jobs.to_vec();
- if let Some(job) = reorient_job
- && !source_jobs
- .iter()
- .any(|source_job| source_job.id == job.id && source_job.owner_role == job.owner_role)
- {
- source_jobs.push(job.clone());
- }
- let roles = derive_role_board(EpiphanyRoleBoardInput {
- state_present: state.is_some(),
- planning: EpiphanyRoleBoardPlanningSummary {
- capture_count: planning
- .map(|planning| planning.captures.len())
- .unwrap_or(0),
- backlog_item_count: planning
- .map(|planning| planning.backlog_items.len())
- .unwrap_or(0),
- roadmap_stream_count: planning
- .map(|planning| planning.roadmap_streams.len())
- .unwrap_or(0),
- objective_draft_count: planning
- .map(|planning| planning.objective_drafts.len())
- .unwrap_or(0),
- },
- checkpoint: checkpoint.map(|checkpoint| EpiphanyRoleBoardCheckpointSummary {
- disposition: Some(format!("{:?}", checkpoint.disposition)),
- next_action: checkpoint.next_action.clone(),
- }),
- reorient_next_action: decision.next_action.clone(),
- jobs: source_jobs.iter().map(map_core_role_board_job).collect(),
- crrc_action: recommendation.action,
- crrc_recommended_scene_action: recommendation
- .recommended_scene_action
- .map(epiphany_core::crrc_scene_action_to_coordinator_scene_action),
- crrc_reason: recommendation.reason.clone(),
- reorient_decision_action: format!("{:?}", decision.action),
- pressure_level: format!("{:?}", pressure.level),
- reorient_result_status: result_status,
- reorient_job: reorient_job.map(map_core_role_board_job),
- imagination_binding_id: EPIPHANY_IMAGINATION_ROLE_BINDING_ID.to_string(),
- research_binding_id: EPIPHANY_RESEARCH_ROLE_BINDING_ID.to_string(),
- modeling_binding_id: EPIPHANY_MODELING_ROLE_BINDING_ID.to_string(),
- verification_binding_id: EPIPHANY_VERIFICATION_ROLE_BINDING_ID.to_string(),
- reorient_owner_role: EPIPHANY_REORIENT_OWNER_ROLE.to_string(),
- imagination_owner_role: EPIPHANY_IMAGINATION_OWNER_ROLE.to_string(),
- research_owner_role: epiphany_core::EPIPHANY_RESEARCH_OWNER_ROLE.to_string(),
- });
-
- EpiphanyRoleBoardStatus { roles, source_jobs }
-}
-
-fn map_core_role_board_job(job: &EpiphanyJobView) -> EpiphanyRoleBoardJob {
- EpiphanyRoleBoardJob {
- id: job.id.clone(),
- owner_role: job.owner_role.clone(),
- status: map_core_role_board_job_status(job.status),
- progress_note: job.progress_note.clone(),
- blocking_reason: job.blocking_reason.clone(),
- }
-}
-
-fn map_core_role_board_job_status(status: CoreEpiphanyJobStatus) -> EpiphanyRoleBoardJobStatus {
- match status {
- CoreEpiphanyJobStatus::Idle => EpiphanyRoleBoardJobStatus::Idle,
- CoreEpiphanyJobStatus::Needed => EpiphanyRoleBoardJobStatus::Needed,
- CoreEpiphanyJobStatus::Pending => EpiphanyRoleBoardJobStatus::Pending,
- CoreEpiphanyJobStatus::Running => EpiphanyRoleBoardJobStatus::Running,
- CoreEpiphanyJobStatus::Completed => EpiphanyRoleBoardJobStatus::Completed,
- CoreEpiphanyJobStatus::Failed => EpiphanyRoleBoardJobStatus::Failed,
- CoreEpiphanyJobStatus::Cancelled => EpiphanyRoleBoardJobStatus::Cancelled,
- CoreEpiphanyJobStatus::Blocked => EpiphanyRoleBoardJobStatus::Blocked,
- CoreEpiphanyJobStatus::Unavailable => EpiphanyRoleBoardJobStatus::Unavailable,
- }
-}
-
-pub fn render_epiphany_roles_note(
- roles: &[EpiphanyRoleBoardLane],
- state_status: CoreEpiphanyReorientStateStatus,
- recommendation: CoreEpiphanyCrrcAction,
-) -> String {
- render_role_board_note(
- roles,
- format!("{:?}", state_status).as_str(),
- recommendation,
- )
-}
diff --git a/epiphany-codex-bridge/src/coordinator_protocol.rs b/epiphany-codex-bridge/src/coordinator_protocol.rs
deleted file mode 100644
index e0bab7cd..00000000
--- a/epiphany-codex-bridge/src/coordinator_protocol.rs
+++ /dev/null
@@ -1,312 +0,0 @@
-use codex_app_server_protocol::ThreadEpiphanyCoordinatorAction;
-use codex_app_server_protocol::ThreadEpiphanyCoordinatorSignals;
-use codex_app_server_protocol::ThreadEpiphanyCrrcAction;
-use codex_app_server_protocol::ThreadEpiphanyCrrcRecommendation;
-use codex_app_server_protocol::ThreadEpiphanyJob;
-use codex_app_server_protocol::ThreadEpiphanyReorientAction;
-use codex_app_server_protocol::ThreadEpiphanyRoleId;
-use codex_app_server_protocol::ThreadEpiphanyRoleLane;
-use codex_app_server_protocol::ThreadEpiphanyRoleStatus;
-use codex_app_server_protocol::ThreadEpiphanyRolesSource;
-use codex_app_server_protocol::ThreadEpiphanySceneAction;
-use codex_app_server_protocol::ThreadEpiphanyViewCoordinator;
-use epiphany_core::EpiphanyCoordinatorAction as CoreEpiphanyCoordinatorAction;
-use epiphany_core::EpiphanyCoordinatorRoleId as CoreEpiphanyCoordinatorRoleId;
-use epiphany_core::EpiphanyCoordinatorRoleStatus as CoreEpiphanyCoordinatorRoleStatus;
-use epiphany_core::EpiphanyCoordinatorSceneAction as CoreEpiphanyCoordinatorSceneAction;
-use epiphany_core::EpiphanyCoordinatorSourceSignals;
-use epiphany_core::EpiphanyCrrcAction as CoreEpiphanyCrrcAction;
-use epiphany_core::EpiphanyCrrcRecommendation as CoreEpiphanyCrrcRecommendation;
-use epiphany_core::EpiphanyCrrcSceneAction as CoreEpiphanyCrrcSceneAction;
-use epiphany_core::EpiphanyJobStatus as CoreEpiphanyJobStatus;
-use epiphany_core::EpiphanyJobView;
-use epiphany_core::EpiphanyReorientAction as CoreEpiphanyReorientAction;
-use epiphany_core::EpiphanyReorientStateStatus as CoreEpiphanyReorientStateStatus;
-use epiphany_core::EpiphanyRoleBoardJob;
-use epiphany_core::EpiphanyRoleBoardJobStatus;
-use epiphany_core::EpiphanyRoleBoardLane;
-use epiphany_state_model::EpiphanyJobKind as CoreEpiphanyJobKind;
-
-use crate::coordinator::EpiphanyCoordinatorStatus;
-use crate::coordinator::EpiphanyRoleBoardStatus;
-use crate::protocol_edge::protocol_job_from_surface;
-use crate::protocol_edge::protocol_pressure_level;
-use crate::protocol_edge::protocol_reorient_result_status;
-use crate::protocol_edge::protocol_reorient_state_status;
-use crate::protocol_edge::protocol_role_result_status;
-
-fn protocol_coordinator_source_signals(
- signals: EpiphanyCoordinatorSourceSignals,
-) -> ThreadEpiphanyCoordinatorSignals {
- ThreadEpiphanyCoordinatorSignals {
- pressure_level: protocol_pressure_level(signals.pressure_level),
- should_prepare_compaction: signals.should_prepare_compaction,
- reorient_action: protocol_reorient_action(signals.reorient_action),
- crrc_action: protocol_crrc_action(signals.crrc_action),
- research_result_status: protocol_role_result_status(signals.research_result_status),
- modeling_result_status: protocol_role_result_status(signals.modeling_result_status),
- verification_result_status: protocol_role_result_status(signals.verification_result_status),
- reorient_result_status: protocol_reorient_result_status(signals.reorient_result_status),
- }
-}
-
-fn protocol_reorient_action(action: CoreEpiphanyReorientAction) -> ThreadEpiphanyReorientAction {
- match action {
- CoreEpiphanyReorientAction::Resume => ThreadEpiphanyReorientAction::Resume,
- CoreEpiphanyReorientAction::Regather => ThreadEpiphanyReorientAction::Regather,
- }
-}
-
-pub fn protocol_crrc_action(action: CoreEpiphanyCrrcAction) -> ThreadEpiphanyCrrcAction {
- match action {
- CoreEpiphanyCrrcAction::Continue => ThreadEpiphanyCrrcAction::Continue,
- CoreEpiphanyCrrcAction::PrepareCheckpoint => ThreadEpiphanyCrrcAction::PrepareCheckpoint,
- CoreEpiphanyCrrcAction::LaunchReorientWorker => {
- ThreadEpiphanyCrrcAction::LaunchReorientWorker
- }
- CoreEpiphanyCrrcAction::WaitForReorientWorker => {
- ThreadEpiphanyCrrcAction::WaitForReorientWorker
- }
- CoreEpiphanyCrrcAction::ReviewReorientResult => {
- ThreadEpiphanyCrrcAction::ReviewReorientResult
- }
- CoreEpiphanyCrrcAction::AcceptReorientResult => {
- ThreadEpiphanyCrrcAction::AcceptReorientResult
- }
- CoreEpiphanyCrrcAction::RegatherManually => ThreadEpiphanyCrrcAction::RegatherManually,
- }
-}
-
-fn protocol_crrc_scene_action(action: CoreEpiphanyCrrcSceneAction) -> ThreadEpiphanySceneAction {
- match action {
- CoreEpiphanyCrrcSceneAction::Update => ThreadEpiphanySceneAction::Update,
- CoreEpiphanyCrrcSceneAction::Reorient => ThreadEpiphanySceneAction::Reorient,
- CoreEpiphanyCrrcSceneAction::ReorientLaunch => ThreadEpiphanySceneAction::ReorientLaunch,
- CoreEpiphanyCrrcSceneAction::ReorientResult => ThreadEpiphanySceneAction::ReorientResult,
- CoreEpiphanyCrrcSceneAction::ReorientAccept => ThreadEpiphanySceneAction::ReorientAccept,
- }
-}
-
-pub fn protocol_crrc_recommendation(
- recommendation: CoreEpiphanyCrrcRecommendation,
-) -> ThreadEpiphanyCrrcRecommendation {
- ThreadEpiphanyCrrcRecommendation {
- action: protocol_crrc_action(recommendation.action),
- recommended_scene_action: recommendation
- .recommended_scene_action
- .map(protocol_crrc_scene_action),
- reason: recommendation.reason,
- }
-}
-
-pub fn protocol_coordinator_view(
- thread_id: String,
- loaded: bool,
- state_status: CoreEpiphanyReorientStateStatus,
- state_revision: Option,
- status: EpiphanyCoordinatorStatus,
- roles: EpiphanyRoleBoardStatus,
-) -> ThreadEpiphanyViewCoordinator {
- ThreadEpiphanyViewCoordinator {
- thread_id,
- source: if loaded {
- ThreadEpiphanyRolesSource::Live
- } else {
- ThreadEpiphanyRolesSource::Stored
- },
- state_status: protocol_reorient_state_status(state_status),
- state_revision,
- action: protocol_coordinator_action(status.core.decision.action),
- target_role: status
- .core
- .decision
- .target_role
- .map(protocol_coordinator_role_id),
- recommended_scene_action: status
- .core
- .decision
- .recommended_scene_action
- .map(protocol_coordinator_scene_action),
- requires_review: status.core.decision.requires_review,
- can_auto_run: status.core.decision.can_auto_run,
- reason: status.core.decision.reason,
- source_signals: protocol_coordinator_source_signals(status.core.source_signals),
- roles: protocol_role_board_lanes(&roles),
- note: status.note,
- }
-}
-
-fn protocol_coordinator_role_id(role_id: CoreEpiphanyCoordinatorRoleId) -> ThreadEpiphanyRoleId {
- match role_id {
- CoreEpiphanyCoordinatorRoleId::Implementation => ThreadEpiphanyRoleId::Implementation,
- CoreEpiphanyCoordinatorRoleId::Imagination => ThreadEpiphanyRoleId::Imagination,
- CoreEpiphanyCoordinatorRoleId::Research => ThreadEpiphanyRoleId::Research,
- CoreEpiphanyCoordinatorRoleId::Modeling => ThreadEpiphanyRoleId::Modeling,
- CoreEpiphanyCoordinatorRoleId::Verification => ThreadEpiphanyRoleId::Verification,
- CoreEpiphanyCoordinatorRoleId::Reorientation => ThreadEpiphanyRoleId::Reorientation,
- }
-}
-
-fn protocol_coordinator_scene_action(
- action: CoreEpiphanyCoordinatorSceneAction,
-) -> ThreadEpiphanySceneAction {
- match action {
- CoreEpiphanyCoordinatorSceneAction::Update => ThreadEpiphanySceneAction::Update,
- CoreEpiphanyCoordinatorSceneAction::Reorient => ThreadEpiphanySceneAction::Reorient,
- CoreEpiphanyCoordinatorSceneAction::ReorientLaunch => {
- ThreadEpiphanySceneAction::ReorientLaunch
- }
- CoreEpiphanyCoordinatorSceneAction::ReorientResult => {
- ThreadEpiphanySceneAction::ReorientResult
- }
- CoreEpiphanyCoordinatorSceneAction::ReorientAccept => {
- ThreadEpiphanySceneAction::ReorientAccept
- }
- CoreEpiphanyCoordinatorSceneAction::RoleLaunch => ThreadEpiphanySceneAction::RoleLaunch,
- CoreEpiphanyCoordinatorSceneAction::RoleResult => ThreadEpiphanySceneAction::RoleResult,
- }
-}
-
-fn protocol_coordinator_action(
- action: CoreEpiphanyCoordinatorAction,
-) -> ThreadEpiphanyCoordinatorAction {
- match action {
- CoreEpiphanyCoordinatorAction::PrepareCheckpoint => {
- ThreadEpiphanyCoordinatorAction::PrepareCheckpoint
- }
- CoreEpiphanyCoordinatorAction::CompactRehydrateReorient => {
- ThreadEpiphanyCoordinatorAction::CompactRehydrateReorient
- }
- CoreEpiphanyCoordinatorAction::LaunchReorientWorker => {
- ThreadEpiphanyCoordinatorAction::LaunchReorientWorker
- }
- CoreEpiphanyCoordinatorAction::WaitForReorientWorker => {
- ThreadEpiphanyCoordinatorAction::WaitForReorientWorker
- }
- CoreEpiphanyCoordinatorAction::ReviewReorientResult => {
- ThreadEpiphanyCoordinatorAction::ReviewReorientResult
- }
- CoreEpiphanyCoordinatorAction::RegatherManually => {
- ThreadEpiphanyCoordinatorAction::RegatherManually
- }
- CoreEpiphanyCoordinatorAction::LaunchResearch => {
- ThreadEpiphanyCoordinatorAction::LaunchResearch
- }
- CoreEpiphanyCoordinatorAction::ReviewResearchResult => {
- ThreadEpiphanyCoordinatorAction::ReviewResearchResult
- }
- CoreEpiphanyCoordinatorAction::LaunchModeling => {
- ThreadEpiphanyCoordinatorAction::LaunchModeling
- }
- CoreEpiphanyCoordinatorAction::ReviewModelingResult => {
- ThreadEpiphanyCoordinatorAction::ReviewModelingResult
- }
- CoreEpiphanyCoordinatorAction::LaunchVerification => {
- ThreadEpiphanyCoordinatorAction::LaunchVerification
- }
- CoreEpiphanyCoordinatorAction::ReviewVerificationResult => {
- ThreadEpiphanyCoordinatorAction::ReviewVerificationResult
- }
- CoreEpiphanyCoordinatorAction::ContinueImplementation => {
- ThreadEpiphanyCoordinatorAction::ContinueImplementation
- }
- }
-}
-
-pub fn protocol_role_board_lanes(
- role_board: &EpiphanyRoleBoardStatus,
-) -> Vec {
- role_board
- .roles
- .iter()
- .cloned()
- .map(|lane| protocol_role_board_lane(lane, &role_board.source_jobs))
- .collect()
-}
-
-fn protocol_role_board_lane(
- lane: EpiphanyRoleBoardLane,
- source_jobs: &[EpiphanyJobView],
-) -> ThreadEpiphanyRoleLane {
- ThreadEpiphanyRoleLane {
- id: protocol_coordinator_role_id(lane.id),
- title: lane.title,
- owner_role: lane.owner_role,
- status: protocol_coordinator_role_status(lane.status),
- note: lane.note,
- jobs: lane
- .jobs
- .iter()
- .map(|job| protocol_role_board_job(job, source_jobs))
- .collect(),
- authority_scopes: lane.authority_scopes,
- recommended_action: lane
- .recommended_action
- .map(protocol_coordinator_scene_action),
- }
-}
-
-fn protocol_role_board_job(
- job: &EpiphanyRoleBoardJob,
- source_jobs: &[EpiphanyJobView],
-) -> ThreadEpiphanyJob {
- source_jobs
- .iter()
- .find(|source_job| source_job.id == job.id && source_job.owner_role == job.owner_role)
- .cloned()
- .map(|job| protocol_job_from_surface(job, None, None))
- .unwrap_or_else(|| {
- protocol_job_from_surface(
- EpiphanyJobView {
- id: job.id.clone(),
- kind: CoreEpiphanyJobKind::Specialist,
- scope: job.id.clone(),
- owner_role: job.owner_role.clone(),
- authority_scope: None,
- runtime_job_id: None,
- status: core_epiphany_job_status_from_role_board(job.status),
- items_processed: None,
- items_total: None,
- progress_note: job.progress_note.clone(),
- last_checkpoint_at_unix_seconds: None,
- blocking_reason: job.blocking_reason.clone(),
- active_thread_ids: Vec::new(),
- linked_subgoal_ids: Vec::new(),
- linked_graph_node_ids: Vec::new(),
- },
- None,
- None,
- )
- })
-}
-
-fn core_epiphany_job_status_from_role_board(
- status: EpiphanyRoleBoardJobStatus,
-) -> CoreEpiphanyJobStatus {
- match status {
- EpiphanyRoleBoardJobStatus::Idle => CoreEpiphanyJobStatus::Idle,
- EpiphanyRoleBoardJobStatus::Needed => CoreEpiphanyJobStatus::Needed,
- EpiphanyRoleBoardJobStatus::Pending => CoreEpiphanyJobStatus::Pending,
- EpiphanyRoleBoardJobStatus::Running => CoreEpiphanyJobStatus::Running,
- EpiphanyRoleBoardJobStatus::Completed => CoreEpiphanyJobStatus::Completed,
- EpiphanyRoleBoardJobStatus::Failed => CoreEpiphanyJobStatus::Failed,
- EpiphanyRoleBoardJobStatus::Cancelled => CoreEpiphanyJobStatus::Cancelled,
- EpiphanyRoleBoardJobStatus::Blocked => CoreEpiphanyJobStatus::Blocked,
- EpiphanyRoleBoardJobStatus::Unavailable => CoreEpiphanyJobStatus::Unavailable,
- }
-}
-
-fn protocol_coordinator_role_status(
- status: CoreEpiphanyCoordinatorRoleStatus,
-) -> ThreadEpiphanyRoleStatus {
- match status {
- CoreEpiphanyCoordinatorRoleStatus::Ready => ThreadEpiphanyRoleStatus::Ready,
- CoreEpiphanyCoordinatorRoleStatus::Needed => ThreadEpiphanyRoleStatus::Needed,
- CoreEpiphanyCoordinatorRoleStatus::Running => ThreadEpiphanyRoleStatus::Running,
- CoreEpiphanyCoordinatorRoleStatus::Waiting => ThreadEpiphanyRoleStatus::Waiting,
- CoreEpiphanyCoordinatorRoleStatus::Review => ThreadEpiphanyRoleStatus::Review,
- CoreEpiphanyCoordinatorRoleStatus::Blocked => ThreadEpiphanyRoleStatus::Blocked,
- CoreEpiphanyCoordinatorRoleStatus::Unavailable => ThreadEpiphanyRoleStatus::Unavailable,
- CoreEpiphanyCoordinatorRoleStatus::Completed => ThreadEpiphanyRoleStatus::Completed,
- }
-}
diff --git a/epiphany-codex-bridge/src/cultnet.rs b/epiphany-codex-bridge/src/cultnet.rs
deleted file mode 100644
index 3c9f6920..00000000
--- a/epiphany-codex-bridge/src/cultnet.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use epiphany_core::EpiphanyGraphFreshness;
-pub use epiphany_core::EpiphanyGraphFreshnessStatus;
-use epiphany_core::EpiphanyInvalidationInput;
-pub use epiphany_core::EpiphanyInvalidationStatus;
-pub use epiphany_core::EpiphanyJobStatus;
-pub use epiphany_core::EpiphanyJobView;
-pub use epiphany_core::EpiphanyPressure;
-pub use epiphany_core::EpiphanyPressureBasis;
-pub use epiphany_core::EpiphanyPressureLevel;
-pub use epiphany_core::EpiphanyPressureStatus;
-pub use epiphany_core::EpiphanyReorientAction;
-pub use epiphany_core::EpiphanyReorientCheckpointStatus;
-pub use epiphany_core::EpiphanyReorientDecision;
-pub use epiphany_core::EpiphanyReorientFreshnessStatus;
-pub use epiphany_core::EpiphanyReorientPressureLevel;
-pub use epiphany_core::EpiphanyReorientReason;
-pub use epiphany_core::EpiphanyReorientStateStatus;
-use epiphany_core::EpiphanyRetrievalFreshness;
-pub use epiphany_core::EpiphanyRetrievalFreshnessStatus;
-pub use epiphany_core::EpiphanyStateUpdatedField;
-pub use epiphany_state_model::EpiphanyJobKind;
-use serde::Deserialize;
-use serde::Serialize;
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub enum EpiphanySurfaceSource {
- Stored,
- Live,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct EpiphanyFreshnessSurface {
- pub thread_id: String,
- pub source: EpiphanySurfaceSource,
- #[serde(default, skip_serializing_if = "Option::is_none")]
- pub state_revision: Option,
- pub retrieval: EpiphanyRetrievalFreshness,
- pub graph: EpiphanyGraphFreshness,
- pub watcher: EpiphanyInvalidationInput,
-}
diff --git a/epiphany-codex-bridge/src/error.rs b/epiphany-codex-bridge/src/error.rs
deleted file mode 100644
index 777cb03e..00000000
--- a/epiphany-codex-bridge/src/error.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::error::Error;
-use std::fmt;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum EpiphanyBridgeError {
- InvalidRequest(String),
- Fatal(String),
-}
-
-pub type Result = std::result::Result;
-
-impl fmt::Display for EpiphanyBridgeError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::InvalidRequest(message) | Self::Fatal(message) => f.write_str(message),
- }
- }
-}
-
-impl Error for EpiphanyBridgeError {}
diff --git a/epiphany-codex-bridge/src/invalidation.rs b/epiphany-codex-bridge/src/invalidation.rs
deleted file mode 100644
index 79f16459..00000000
--- a/epiphany-codex-bridge/src/invalidation.rs
+++ /dev/null
@@ -1,202 +0,0 @@
-use codex_utils_absolute_path::AbsolutePathBuf;
-use notify::RecursiveMode;
-use notify::Watcher;
-use std::collections::HashMap;
-use std::path::PathBuf;
-use std::sync::Arc;
-use std::time::SystemTime;
-use std::time::UNIX_EPOCH;
-use tokio::sync::Mutex as AsyncMutex;
-use tokio::sync::mpsc;
-use tokio::sync::oneshot;
-use tracing::warn;
-
-use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct EpiphanyInvalidationSnapshot {
- pub available: bool,
- pub workspace_root: Option,
- pub observed_at_unix_seconds: Option,
- pub changed_paths: Vec,
-}
-
-pub fn epiphany_freshness_watcher_snapshot(
- snapshot: &EpiphanyInvalidationSnapshot,
-) -> EpiphanyFreshnessWatcherSnapshot<'_> {
- EpiphanyFreshnessWatcherSnapshot {
- available: snapshot.available,
- workspace_root: snapshot.workspace_root.as_ref().map(|path| path.as_path()),
- observed_at_unix_seconds: snapshot.observed_at_unix_seconds,
- changed_paths: snapshot.changed_paths.as_slice(),
- }
-}
-
-#[derive(Clone)]
-pub struct EpiphanyInvalidationManager {
- state: Arc>>,
-}
-
-struct WatchEntry {
- workspace_root: AbsolutePathBuf,
- latest: Arc>,
- terminate_tx: oneshot::Sender>,
- _watcher: notify::RecommendedWatcher,
-}
-
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
-struct LatestInvalidation {
- observed_at_unix_seconds: Option,
- changed_paths: Vec,
-}
-
-impl EpiphanyInvalidationManager {
- pub fn new() -> Self {
- Self {
- state: Arc::new(AsyncMutex::new(HashMap::new())),
- }
- }
-
- pub async fn ensure_thread_watch(&self, thread_id: &str, workspace_root: &AbsolutePathBuf) {
- let existing_entry = {
- let mut state = self.state.lock().await;
- match state.get(thread_id) {
- Some(entry) if &entry.workspace_root == workspace_root => return,
- Some(_) => state.remove(thread_id),
- None => None,
- }
- };
-
- if let Some(entry) = existing_entry {
- stop_watch_entry(entry).await;
- }
-
- let latest = Arc::new(AsyncMutex::new(LatestInvalidation::default()));
- let (event_tx, mut event_rx) = mpsc::unbounded_channel::>();
- let mut watcher =
- match notify::recommended_watcher(move |result: notify::Result| {
- match result {
- Ok(event) => {
- let _ = event_tx.send(event.paths);
- }
- Err(err) => warn!("epiphany invalidation watcher event failed: {err}"),
- }
- }) {
- Ok(watcher) => watcher,
- Err(err) => {
- warn!("epiphany invalidation manager could not create watcher: {err}");
- return;
- }
- };
- if let Err(err) = watcher.watch(workspace_root.as_path(), RecursiveMode::Recursive) {
- warn!(
- "epiphany invalidation manager could not watch `{}`: {err}",
- workspace_root.display()
- );
- return;
- }
- let (terminate_tx, terminate_rx) = oneshot::channel();
- let workspace_root_path = workspace_root.to_path_buf();
-
- let entry = WatchEntry {
- workspace_root: workspace_root.clone(),
- latest: Arc::clone(&latest),
- terminate_tx,
- _watcher: watcher,
- };
- self.state.lock().await.insert(thread_id.to_string(), entry);
-
- tokio::spawn(async move {
- let mut terminate_rx = terminate_rx;
- let mut done_tx = None;
-
- loop {
- let paths = tokio::select! {
- biased;
- result = &mut terminate_rx => {
- done_tx = result.ok();
- break;
- }
- paths = event_rx.recv() => match paths {
- Some(paths) => paths,
- None => break,
- },
- };
-
- let observed_at_unix_seconds = unix_now();
- let mut latest = latest.lock().await;
- latest.observed_at_unix_seconds = Some(observed_at_unix_seconds);
- latest.changed_paths =
- normalize_changed_paths(paths, workspace_root_path.as_path());
- }
-
- if let Some(done_tx) = done_tx {
- let _ = done_tx.send(());
- }
- });
- }
-
- pub async fn snapshot(&self, thread_id: &str) -> EpiphanyInvalidationSnapshot {
- let (workspace_root, latest) = {
- let state = self.state.lock().await;
- match state.get(thread_id) {
- Some(entry) => (
- Some(entry.workspace_root.clone()),
- Some(Arc::clone(&entry.latest)),
- ),
- None => (None, None),
- }
- };
-
- let Some(latest) = latest else {
- return EpiphanyInvalidationSnapshot {
- available: false,
- workspace_root: None,
- observed_at_unix_seconds: None,
- changed_paths: Vec::new(),
- };
- };
-
- let latest = latest.lock().await.clone();
- EpiphanyInvalidationSnapshot {
- available: true,
- workspace_root,
- observed_at_unix_seconds: latest.observed_at_unix_seconds,
- changed_paths: latest.changed_paths,
- }
- }
-
- pub async fn remove_thread(&self, thread_id: &str) {
- let entry = self.state.lock().await.remove(thread_id);
- if let Some(entry) = entry {
- stop_watch_entry(entry).await;
- }
- }
-}
-
-async fn stop_watch_entry(entry: WatchEntry) {
- let (done_tx, done_rx) = oneshot::channel();
- let _ = entry.terminate_tx.send(done_tx);
- let _ = done_rx.await;
-}
-
-fn unix_now() -> i64 {
- SystemTime::now()
- .duration_since(UNIX_EPOCH)
- .map(|duration| duration.as_secs() as i64)
- .unwrap_or_default()
-}
-
-fn normalize_changed_paths(paths: Vec, workspace_root: &std::path::Path) -> Vec {
- let mut normalized = paths
- .into_iter()
- .filter_map(|path| match path.strip_prefix(workspace_root) {
- Ok(relative) if relative.as_os_str().is_empty() => None,
- Ok(relative) => Some(relative.to_path_buf()),
- Err(_) => Some(path),
- })
- .collect::>();
- normalized.sort();
- normalized.dedup();
- normalized
-}
diff --git a/epiphany-codex-bridge/src/jobs.rs b/epiphany-codex-bridge/src/jobs.rs
deleted file mode 100644
index 666b0443..00000000
--- a/epiphany-codex-bridge/src/jobs.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use epiphany_core::EpiphanyJobStatus as CoreEpiphanyJobStatus;
-use epiphany_core::EpiphanyJobView;
-use epiphany_core::EpiphanyJobsInput;
-use epiphany_core::derive_jobs;
-use epiphany_state_model::EpiphanyJobKind as CoreEpiphanyJobKind;
-use epiphany_state_model::EpiphanyRetrievalState;
-use epiphany_state_model::EpiphanyThreadState;
-
-pub fn derive_epiphany_jobs(
- state: Option<&EpiphanyThreadState>,
- retrieval_override: Option<&EpiphanyRetrievalState>,
-) -> Vec {
- derive_jobs(EpiphanyJobsInput {
- state,
- retrieval_override,
- })
-}
-
-pub fn map_epiphany_jobs(
- state: Option<&EpiphanyThreadState>,
- retrieval_override: Option<&EpiphanyRetrievalState>,
-) -> Vec {
- derive_epiphany_jobs(state, retrieval_override)
-}
-
-pub fn map_launched_epiphany_job(
- state: &EpiphanyThreadState,
- binding_id: &str,
- backend_job_id: &str,
- fallback_kind: CoreEpiphanyJobKind,
- fallback_scope: &str,
-) -> EpiphanyJobView {
- derive_epiphany_jobs(Some(state), None)
- .into_iter()
- .find(|job| job.id == binding_id)
- .unwrap_or_else(|| EpiphanyJobView {
- id: binding_id.to_string(),
- kind: fallback_kind,
- scope: fallback_scope.to_string(),
- owner_role: "epiphany-harness".to_string(),
- authority_scope: None,
- runtime_job_id: Some(backend_job_id.to_string()),
- status: CoreEpiphanyJobStatus::Pending,
- items_processed: None,
- items_total: None,
- progress_note: None,
- last_checkpoint_at_unix_seconds: None,
- blocking_reason: None,
- active_thread_ids: Vec::new(),
- linked_subgoal_ids: Vec::new(),
- linked_graph_node_ids: Vec::new(),
- })
-}
-
-pub fn map_interrupted_epiphany_job(
- state: &EpiphanyThreadState,
- binding_id: &str,
-) -> EpiphanyJobView {
- derive_epiphany_jobs(Some(state), None)
- .into_iter()
- .find(|job| job.id == binding_id)
- .unwrap_or_else(|| {
- epiphany_blocked_state_job(
- binding_id,
- CoreEpiphanyJobKind::Specialist,
- "role-scoped specialist work",
- "Interrupted job binding was not reflected in Epiphany state.",
- )
- })
-}
-
-pub fn epiphany_blocked_state_job(
- id: &str,
- kind: CoreEpiphanyJobKind,
- scope: &str,
- blocking_reason: &str,
-) -> EpiphanyJobView {
- EpiphanyJobView {
- id: id.to_string(),
- kind,
- scope: scope.to_string(),
- owner_role: "epiphany-harness".to_string(),
- authority_scope: None,
- runtime_job_id: None,
- status: CoreEpiphanyJobStatus::Blocked,
- items_processed: None,
- items_total: None,
- progress_note: None,
- last_checkpoint_at_unix_seconds: None,
- blocking_reason: Some(blocking_reason.to_string()),
- active_thread_ids: Vec::new(),
- linked_subgoal_ids: Vec::new(),
- linked_graph_node_ids: Vec::new(),
- }
-}
diff --git a/epiphany-codex-bridge/src/launch.rs b/epiphany-codex-bridge/src/launch.rs
deleted file mode 100644
index a33505e6..00000000
--- a/epiphany-codex-bridge/src/launch.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-//! Compatibility facade for older bridge callers.
-//!
-//! Epiphany prompt doctrine, worker launch policy, role binding ids, and output
-//! schemas live in `epiphany-core`. The bridge may translate those typed launch
-//! requests to Codex JSON-RPC, but it does not own the agent instructions.
-
-pub use epiphany_core::EPIPHANY_IMAGINATION_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_IMAGINATION_ROLE_BINDING_ID;
-pub use epiphany_core::EPIPHANY_MODELING_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_MODELING_ROLE_BINDING_ID;
-pub use epiphany_core::EPIPHANY_REORIENT_LAUNCH_BINDING_ID;
-pub use epiphany_core::EPIPHANY_REORIENT_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_RESEARCH_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_RESEARCH_ROLE_BINDING_ID;
-pub use epiphany_core::EPIPHANY_VERIFICATION_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_VERIFICATION_ROLE_BINDING_ID;
-pub use epiphany_core::EpiphanyCoordinatorPromptConfig;
-pub use epiphany_core::EpiphanyCrrcPromptConfig;
-pub use epiphany_core::EpiphanyImplementationPromptConfig;
-pub use epiphany_core::EpiphanyReorientationPromptConfig;
-pub use epiphany_core::EpiphanyRolePromptConfig;
-pub use epiphany_core::EpiphanySharedPromptConfig;
-pub use epiphany_core::EpiphanySpecialistPromptConfig;
-pub use epiphany_core::build_epiphany_job_launch_request;
-pub use epiphany_core::build_epiphany_reorient_launch_instruction;
-pub use epiphany_core::build_epiphany_reorient_launch_request;
-pub use epiphany_core::build_epiphany_role_launch_request;
-pub use epiphany_core::epiphany_agent_prompt_with_memory;
-pub use epiphany_core::epiphany_reorient_launch_output_schema;
-pub use epiphany_core::epiphany_role_binding_id;
-pub use epiphany_core::epiphany_role_label;
-pub use epiphany_core::epiphany_role_launch_output_schema;
-pub use epiphany_core::epiphany_role_owner;
-pub use epiphany_core::epiphany_specialist_prompt_config;
-pub use epiphany_core::epiphany_worker_prompt;
-pub use epiphany_core::render_epiphany_coordinator_note;
-pub use epiphany_core::render_epiphany_pre_compaction_checkpoint_intervention;
-pub use epiphany_core::unique_strings;
diff --git a/epiphany-codex-bridge/src/launch_context.rs b/epiphany-codex-bridge/src/launch_context.rs
deleted file mode 100644
index 3d1d5c4f..00000000
--- a/epiphany-codex-bridge/src/launch_context.rs
+++ /dev/null
@@ -1,228 +0,0 @@
-use chrono::SecondsFormat;
-use chrono::Utc;
-use epiphany_core::EpiphanyMemoryContextPacket;
-use epiphany_core::EpiphanyMemoryContextQuery;
-use epiphany_core::EpiphanyMemoryProfile;
-use epiphany_core::EpiphanyPromptContextInput;
-use epiphany_core::EpiphanyThreadState;
-use epiphany_core::load_memory_graph_snapshot;
-use epiphany_core::memory_graph_from_epiphany_graphs;
-use epiphany_core::plan_memory_graph_context_cut;
-use epiphany_core::query_epiphany_local_verse_context;
-use epiphany_core::render_epiphany_prompt_context;
-use epiphany_core::seed_epiphany_local_verse_context;
-use epiphany_core::write_memory_graph_snapshot;
-use std::path::Path;
-use std::path::PathBuf;
-
-pub const EPIPHANY_LOCAL_VERSE_RUNTIME_ID: &str = "epiphany-local";
-
-pub fn local_verse_store_path(runtime_store_path: &Path) -> PathBuf {
- sibling_state_store_path(runtime_store_path, "local-verse.ccmp")
-}
-
-pub fn memory_graph_store_path(runtime_store_path: &Path) -> PathBuf {
- sibling_state_store_path(runtime_store_path, "memory-graph.msgpack")
-}
-
-fn sibling_state_store_path(runtime_store_path: &Path, filename: &str) -> PathBuf {
- runtime_store_path
- .parent()
- .unwrap_or_else(|| Path::new("."))
- .join(filename)
-}
-
-pub fn role_launch_context_focus(state: &EpiphanyThreadState, role_label: &str) -> String {
- let objective = state
- .objective
- .as_deref()
- .map(str::trim)
- .filter(|objective| !objective.is_empty())
- .unwrap_or("Epiphany worker launch");
- format!("Launch `{role_label}` worker for: {objective}")
-}
-
-pub fn reorient_launch_context_focus(state: &EpiphanyThreadState, next_action: &str) -> String {
- let objective = state
- .objective
- .as_deref()
- .map(str::trim)
- .filter(|objective| !objective.is_empty())
- .unwrap_or("Epiphany reorientation");
- format!("Launch reorientation worker for: {objective}. Next action: {next_action}")
-}
-
-pub fn render_launch_dynamic_prompt_context(
- runtime_store_path: &Path,
- state: &EpiphanyThreadState,
- focus: String,
-) -> Result {
- let local_verse_store = local_verse_store_path(runtime_store_path);
- seed_epiphany_local_verse_context(
- &local_verse_store,
- EPIPHANY_LOCAL_VERSE_RUNTIME_ID,
- Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true),
- )
- .map_err(|error| {
- format!(
- "failed to seed local Verse context store {}: {error}",
- local_verse_store.display()
- )
- })?;
- let local_verse =
- query_epiphany_local_verse_context(&local_verse_store, EPIPHANY_LOCAL_VERSE_RUNTIME_ID)
- .map_err(|error| {
- format!(
- "failed to query local Verse context store {}: {error}",
- local_verse_store.display()
- )
- })?;
- let memory_context =
- launch_memory_context(runtime_store_path, state, focus.as_str()).map_err(|error| {
- format!(
- "failed to build launch memory context beside {}: {error}",
- runtime_store_path.display()
- )
- })?;
- Ok(render_epiphany_prompt_context(
- &EpiphanyPromptContextInput {
- focus,
- local_verse,
- memory_context,
- },
- ))
-}
-
-fn launch_memory_context(
- runtime_store_path: &Path,
- state: &EpiphanyThreadState,
- focus: &str,
-) -> Result {
- let memory_graph_store = memory_graph_store_path(runtime_store_path);
- let (snapshot, refreshed_from_state) = match load_memory_graph_snapshot(&memory_graph_store)
- .map_err(|error| {
- format!(
- "failed to load memory graph store {}: {error}",
- memory_graph_store.display()
- )
- })? {
- Some(snapshot) => (snapshot, false),
- None => {
- let snapshot = memory_graph_from_epiphany_graphs(
- format!("bridge-launch-state-rev-{}", state.revision),
- &state.graphs,
- );
- write_memory_graph_snapshot(&memory_graph_store, &snapshot).map_err(|error| {
- format!(
- "failed to write memory graph store {} from thread state: {error}",
- memory_graph_store.display()
- )
- })?;
- (snapshot, true)
- }
- };
-
- let mut packet = plan_memory_graph_context_cut(
- &snapshot,
- &EpiphanyMemoryContextQuery {
- id: format!("bridge-launch-query-state-rev-{}", state.revision),
- profile: Some(EpiphanyMemoryProfile::RepoArchitecture),
- text: Some(focus.to_string()),
- budget: Some(5),
- ..Default::default()
- },
- );
- if refreshed_from_state {
- packet.warnings.push(format!(
- "Memory graph store was refreshed from current thread-state repo graph at {}.",
- memory_graph_store.display()
- ));
- }
- if packet.nodes.is_empty() && packet.summaries.is_empty() {
- packet.warnings.push(
- "Memory graph context is empty for this launch focus; the accepted repo graph may be thin or stale.".to_string(),
- );
- }
- Ok(packet)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use epiphany_core::EpiphanyRoleResultRoleId;
- use epiphany_core::RuntimeSpineHeartbeatJobOptions;
- use epiphany_core::build_epiphany_role_launch_request_with_dynamic_context;
- use epiphany_core::open_runtime_spine_heartbeat_job;
- use epiphany_core::runtime_worker_launch_request;
- use std::fs;
- use uuid::Uuid;
-
- #[test]
- fn launch_context_persists_on_runtime_worker_request() -> anyhow::Result<()> {
- let temp =
- std::env::temp_dir().join(format!("epiphany-bridge-launch-context-{}", Uuid::new_v4()));
- fs::create_dir_all(&temp)?;
- let runtime_store = temp.join("runtime-spine.msgpack");
- let state = EpiphanyThreadState {
- revision: 7,
- objective: Some("Test launch context.".to_string()),
- ..Default::default()
- };
-
- let rendered = render_launch_dynamic_prompt_context(
- &runtime_store,
- &state,
- role_launch_context_focus(&state, "modeling"),
- )
- .map_err(anyhow::Error::msg)?;
-
- assert!(rendered.contains(""));
- assert!(rendered.contains("Test launch context."));
- assert!(rendered.contains("Odin"));
- assert!(rendered.contains("Yggdrasil"));
- assert!(rendered.contains("Memory graph"));
- assert!(local_verse_store_path(&runtime_store).exists());
- assert!(memory_graph_store_path(&runtime_store).exists());
-
- let launch_request = build_epiphany_role_launch_request_with_dynamic_context(
- "thread-1",
- EpiphanyRoleResultRoleId::Modeling,
- Some(state.revision),
- Some(60),
- &state,
- Some(rendered.clone()),
- )
- .map_err(anyhow::Error::msg)?;
- open_runtime_spine_heartbeat_job(
- &runtime_store,
- RuntimeSpineHeartbeatJobOptions {
- runtime_id: EPIPHANY_LOCAL_VERSE_RUNTIME_ID.to_string(),
- display_name: "Epiphany Local".to_string(),
- session_id: "epiphany-main".to_string(),
- objective: "Test persisted launch context.".to_string(),
- coordinator_note: "Bridge launch-context smoke.".to_string(),
- job_id: "job-launch-context".to_string(),
- role: launch_request.owner_role.clone(),
- binding_id: launch_request.binding_id.clone(),
- authority_scope: launch_request.authority_scope.clone(),
- instruction: launch_request.instruction.clone(),
- launch_document: launch_request.launch_document.clone(),
- output_contract_id: launch_request.output_contract_id.clone(),
- organ_launch_contract: launch_request.organ_launch_contract.clone(),
- created_at: "2026-06-02T00:00:00Z".to_string(),
- },
- )?;
- let stored = runtime_worker_launch_request(&runtime_store, "job-launch-context")?
- .expect("runtime worker launch request should be persisted");
- let stored_document = stored.launch_document()?;
- let stored_context = stored_document
- .dynamic_prompt_context()
- .expect("stored launch document should carry dynamic context");
- assert!(stored_context.contains("Odin"));
- assert!(stored_context.contains("Memory graph"));
- assert!(stored_context.contains("Test launch context."));
-
- fs::remove_dir_all(&temp)?;
- Ok(())
- }
-}
diff --git a/epiphany-codex-bridge/src/lib.rs b/epiphany-codex-bridge/src/lib.rs
deleted file mode 100644
index 05717d56..00000000
--- a/epiphany-codex-bridge/src/lib.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-//! Compatibility bridge between Epiphany's typed CultNet/CultCache-shaped
-//! contracts and the vendored Codex JSON-RPC/app-server shell.
-//!
-//! This crate is a bridge, not an authority organ. Its job is to translate
-//! Codex `ThreadEpiphany*` DTOs into Epiphany core documents, project typed
-//! Epiphany surfaces back into legacy Codex responses, and call the narrow
-//! host trait needed while Codex still owns thread persistence. Verdicts,
-//! launch policy, reorientation policy, acceptance rules, runtime-spine
-//! lifecycle semantics, and durable state invariants belong in `epiphany-core`
-//! or `epiphany-state-model`.
-//!
-//! Host facts and side effects that still pass through this crate are
-//! quarantine scaffolding for the current Codex shell. Do not let them become
-//! a second policy throne. The long cut is to replace these adapters with
-//! native CultNet intents and receipts, leaving Codex only as the OpenAI
-//! subscription auth/model transport reliquary.
-
-pub mod checkpoint;
-pub mod context;
-pub mod context_protocol;
-pub mod coordinator;
-pub mod coordinator_protocol;
-pub mod cultnet;
-pub mod error;
-pub mod invalidation;
-pub mod jobs;
-pub mod launch;
-pub mod launch_context;
-pub mod mutation;
-pub mod mutation_service;
-pub mod pressure;
-pub mod protocol_edge;
-pub mod reorient;
-pub mod results;
-pub mod retrieve;
-pub mod retrieve_protocol;
-pub mod runtime_results;
-pub mod scene;
-pub mod scene_protocol;
-pub mod state;
-pub mod view_protocol;
diff --git a/epiphany-codex-bridge/src/mutation.rs b/epiphany-codex-bridge/src/mutation.rs
deleted file mode 100644
index 4f285860..00000000
--- a/epiphany-codex-bridge/src/mutation.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-use epiphany_core::EpiphanyReorientAcceptanceFinding;
-use epiphany_core::EpiphanyReorientFindingInterpretation as CoreEpiphanyReorientFinding;
-use epiphany_core::EpiphanyRoleAcceptanceFinding;
-use epiphany_core::EpiphanyRoleFindingInterpretation as CoreEpiphanyRoleFinding;
-use epiphany_core::EpiphanyRoleResultRoleId;
-use epiphany_core::EpiphanyRoleStatePatchDocument;
-use epiphany_core::EpiphanyStateUpdate;
-use epiphany_core::EpiphanyStateUpdatedField;
-use epiphany_core::MindGatewayReview;
-use epiphany_core::build_reorient_acceptance_bundle;
-use epiphany_core::build_role_acceptance_bundle;
-use epiphany_core::imagination_role_state_patch_policy_errors;
-use epiphany_core::mind_review_allows_state;
-use epiphany_core::mind_review_reorient_acceptance;
-use epiphany_core::mind_review_role_acceptance;
-use epiphany_core::modeling_role_state_patch_policy_errors;
-use epiphany_state_model::EpiphanyInvestigationCheckpoint;
-
-pub struct RoleAcceptanceUpdate {
- pub state_update: EpiphanyStateUpdate,
- pub applied_patch: EpiphanyRoleStatePatchDocument,
- pub changed_fields: Vec,
- pub accepted_receipt_id: String,
- pub accepted_observation_id: String,
- pub accepted_evidence_id: String,
- pub mind_review: MindGatewayReview,
-}
-
-pub struct ReorientAcceptanceUpdate {
- pub state_update: EpiphanyStateUpdate,
- pub changed_fields: Vec,
- pub accepted_receipt_id: String,
- pub accepted_observation_id: String,
- pub accepted_evidence_id: String,
- pub mind_review: MindGatewayReview,
-}
-
-pub fn parse_core_role_finding_state_patch(
- finding: &CoreEpiphanyRoleFinding,
-) -> Result {
- finding
- .state_patch
- .clone()
- .ok_or_else(|| "completed role finding did not include a reviewable statePatch".to_string())
-}
-
-pub fn state_update_from_core_patch(
- expected_revision: Option,
- patch: EpiphanyRoleStatePatchDocument,
-) -> EpiphanyStateUpdate {
- EpiphanyStateUpdate {
- expected_revision,
- objective: patch.objective,
- active_subgoal_id: patch.active_subgoal_id,
- subgoals: patch.subgoals,
- invariants: patch.invariants,
- graphs: patch.graphs,
- graph_frontier: patch.graph_frontier,
- graph_checkpoint: patch.graph_checkpoint,
- scratch: patch.scratch,
- investigation_checkpoint: patch.investigation_checkpoint,
- job_bindings: patch.job_bindings,
- acceptance_receipts: patch.acceptance_receipts,
- runtime_links: patch.runtime_links,
- observations: patch.observations,
- evidence: patch.evidence,
- churn: patch.churn,
- mode: patch.mode,
- planning: patch.planning,
- }
-}
-
-pub fn build_role_acceptance_update(
- expected_revision: Option,
- role_id: EpiphanyRoleResultRoleId,
- binding_id: &str,
- finding: &CoreEpiphanyRoleFinding,
- accepted_evidence_id: String,
- accepted_observation_id: String,
- accepted_at: String,
-) -> Result {
- let mut core_patch = match role_id {
- EpiphanyRoleResultRoleId::Imagination => {
- let patch = parse_core_role_finding_state_patch(finding)?;
- let patch_errors = imagination_role_state_patch_policy_errors(&patch);
- if !patch_errors.is_empty() {
- return Err(format!(
- "imagination role state patch is not acceptable: {}",
- patch_errors.join("; ")
- ));
- }
- patch
- }
- EpiphanyRoleResultRoleId::Modeling => {
- let patch = parse_core_role_finding_state_patch(finding)?;
- let patch_errors = modeling_role_state_patch_policy_errors(&patch);
- if !patch_errors.is_empty() {
- return Err(format!(
- "modeling role state patch is not acceptable: {}",
- patch_errors.join("; ")
- ));
- }
- patch
- }
- EpiphanyRoleResultRoleId::Research => {
- let patch = parse_core_role_finding_state_patch(finding)?;
- let patch_errors = epiphany_core::research_role_state_patch_policy_errors(&patch);
- if !patch_errors.is_empty() {
- return Err(format!(
- "research role state patch is not acceptable: {}",
- patch_errors.join("; ")
- ));
- }
- patch
- }
- EpiphanyRoleResultRoleId::Verification => EpiphanyRoleStatePatchDocument::default(),
- EpiphanyRoleResultRoleId::Implementation | EpiphanyRoleResultRoleId::Reorientation => {
- return Err(format!(
- "role {:?} cannot be accepted through roleAccept",
- role_id
- ));
- }
- };
-
- let projected_fields = epiphany_update_patch_changed_fields(&core_patch)
- .into_iter()
- .map(|field| format!("{field:?}"))
- .collect();
- let mind_review = mind_review_role_acceptance(binding_id, role_id, finding, &core_patch);
- mind_review_allows_state(&mind_review)?;
- let acceptance_bundle = build_role_acceptance_bundle(
- binding_id,
- EpiphanyRoleAcceptanceFinding {
- role_id,
- verdict: finding.verdict.clone(),
- summary: finding.summary.clone(),
- next_safe_move: finding.next_safe_move.clone(),
- files_inspected: finding.files_inspected.clone(),
- runtime_result_id: finding.runtime_result_id.clone(),
- runtime_job_id: finding.runtime_job_id.clone(),
- projected_fields,
- },
- accepted_evidence_id,
- accepted_observation_id,
- accepted_at,
- )?;
- let accepted_receipt_id = acceptance_bundle.accepted_receipt_id.clone();
- let accepted_observation_id = acceptance_bundle.accepted_observation_id.clone();
- let accepted_evidence_id = acceptance_bundle.accepted_evidence_id.clone();
- core_patch.evidence.push(acceptance_bundle.evidence);
- core_patch.observations.push(acceptance_bundle.observation);
- core_patch
- .acceptance_receipts
- .push(acceptance_bundle.receipt);
- let applied_patch = core_patch.clone();
- let changed_fields = epiphany_update_patch_changed_fields(&applied_patch);
- let state_update = state_update_from_core_patch(expected_revision, core_patch);
-
- Ok(RoleAcceptanceUpdate {
- state_update,
- applied_patch,
- changed_fields,
- accepted_receipt_id,
- accepted_observation_id,
- accepted_evidence_id,
- mind_review,
- })
-}
-
-pub fn build_reorient_acceptance_update(
- expected_revision: Option,
- binding_id: &str,
- finding: &CoreEpiphanyReorientFinding,
- accepted_evidence_id: String,
- accepted_observation_id: String,
- accepted_at: String,
- update_scratch: bool,
- update_investigation_checkpoint: bool,
- checkpoint: Option,
-) -> Result {
- let mind_finding = EpiphanyReorientAcceptanceFinding {
- mode: finding.mode.clone(),
- summary: finding.summary.clone(),
- next_safe_move: finding.next_safe_move.clone(),
- checkpoint_still_valid: finding.checkpoint_still_valid,
- files_inspected: finding.files_inspected.clone(),
- runtime_result_id: finding.runtime_result_id.clone(),
- runtime_job_id: finding.runtime_job_id.clone(),
- };
- let mind_review = mind_review_reorient_acceptance(
- binding_id,
- &mind_finding,
- update_scratch,
- update_investigation_checkpoint,
- );
- mind_review_allows_state(&mind_review)?;
- let acceptance_bundle = build_reorient_acceptance_bundle(
- binding_id,
- mind_finding,
- accepted_evidence_id,
- accepted_observation_id,
- accepted_at,
- update_scratch,
- update_investigation_checkpoint
- .then_some(checkpoint)
- .flatten(),
- )?;
- let accepted_receipt_id = acceptance_bundle.accepted_receipt_id.clone();
- let accepted_observation_id = acceptance_bundle.accepted_observation_id.clone();
- let accepted_evidence_id = acceptance_bundle.accepted_evidence_id.clone();
- let scratch = acceptance_bundle.scratch;
- let investigation_checkpoint = acceptance_bundle.investigation_checkpoint;
-
- let mut changed_fields = vec![
- EpiphanyStateUpdatedField::AcceptanceReceipts,
- EpiphanyStateUpdatedField::Observations,
- EpiphanyStateUpdatedField::Evidence,
- ];
- if scratch.is_some() {
- changed_fields.push(EpiphanyStateUpdatedField::Scratch);
- }
- if investigation_checkpoint.is_some() {
- changed_fields.push(EpiphanyStateUpdatedField::InvestigationCheckpoint);
- }
-
- Ok(ReorientAcceptanceUpdate {
- state_update: EpiphanyStateUpdate {
- expected_revision,
- scratch,
- investigation_checkpoint,
- acceptance_receipts: vec![acceptance_bundle.receipt],
- observations: vec![acceptance_bundle.observation],
- evidence: vec![acceptance_bundle.evidence],
- ..Default::default()
- },
- changed_fields,
- accepted_receipt_id,
- accepted_observation_id,
- accepted_evidence_id,
- mind_review,
- })
-}
-
-pub fn epiphany_job_launch_changed_fields() -> Vec {
- vec![
- EpiphanyStateUpdatedField::JobBindings,
- EpiphanyStateUpdatedField::RuntimeLinks,
- ]
-}
-
-pub fn thread_epiphany_patch_has_state_replacements(
- patch: &EpiphanyRoleStatePatchDocument,
-) -> bool {
- patch.objective.is_some()
- || patch.active_subgoal_id.is_some()
- || patch.subgoals.is_some()
- || patch.invariants.is_some()
- || patch.graphs.is_some()
- || patch.graph_frontier.is_some()
- || patch.graph_checkpoint.is_some()
- || patch.scratch.is_some()
- || patch.investigation_checkpoint.is_some()
- || patch.job_bindings.is_some()
- || !patch.acceptance_receipts.is_empty()
- || !patch.runtime_links.is_empty()
- || patch.churn.is_some()
- || patch.mode.is_some()
- || patch.planning.is_some()
-}
-
-pub fn epiphany_update_patch_changed_fields(
- patch: &EpiphanyRoleStatePatchDocument,
-) -> Vec {
- let mut fields = Vec::new();
- if patch.objective.is_some() {
- fields.push(EpiphanyStateUpdatedField::Objective);
- }
- if patch.active_subgoal_id.is_some() {
- fields.push(EpiphanyStateUpdatedField::ActiveSubgoalId);
- }
- if patch.subgoals.is_some() {
- fields.push(EpiphanyStateUpdatedField::Subgoals);
- }
- if patch.invariants.is_some() {
- fields.push(EpiphanyStateUpdatedField::Invariants);
- }
- if patch.graphs.is_some() {
- fields.push(EpiphanyStateUpdatedField::Graphs);
- }
- if patch.graph_frontier.is_some() {
- fields.push(EpiphanyStateUpdatedField::GraphFrontier);
- }
- if patch.graph_checkpoint.is_some() {
- fields.push(EpiphanyStateUpdatedField::GraphCheckpoint);
- }
- if patch.scratch.is_some() {
- fields.push(EpiphanyStateUpdatedField::Scratch);
- }
- if patch.investigation_checkpoint.is_some() {
- fields.push(EpiphanyStateUpdatedField::InvestigationCheckpoint);
- }
- if patch.job_bindings.is_some() {
- fields.push(EpiphanyStateUpdatedField::JobBindings);
- }
- if !patch.acceptance_receipts.is_empty() {
- fields.push(EpiphanyStateUpdatedField::AcceptanceReceipts);
- }
- if !patch.runtime_links.is_empty() {
- fields.push(EpiphanyStateUpdatedField::RuntimeLinks);
- }
- if !patch.observations.is_empty() {
- fields.push(EpiphanyStateUpdatedField::Observations);
- }
- if !patch.evidence.is_empty() {
- fields.push(EpiphanyStateUpdatedField::Evidence);
- }
- if patch.churn.is_some() {
- fields.push(EpiphanyStateUpdatedField::Churn);
- }
- if patch.mode.is_some() {
- fields.push(EpiphanyStateUpdatedField::Mode);
- }
- if patch.planning.is_some() {
- fields.push(EpiphanyStateUpdatedField::Planning);
- }
- fields
-}
-
-pub fn epiphany_promote_changed_fields(
- patch: &EpiphanyRoleStatePatchDocument,
-) -> Vec {
- let mut fields = epiphany_update_patch_changed_fields(patch);
- if !fields.contains(&EpiphanyStateUpdatedField::Evidence) {
- fields.push(EpiphanyStateUpdatedField::Evidence);
- }
- fields
-}
diff --git a/epiphany-codex-bridge/src/mutation_service.rs b/epiphany-codex-bridge/src/mutation_service.rs
deleted file mode 100644
index caaf9610..00000000
--- a/epiphany-codex-bridge/src/mutation_service.rs
+++ /dev/null
@@ -1,1150 +0,0 @@
-use chrono::SecondsFormat;
-use chrono::Utc;
-use std::path::Path;
-use std::path::PathBuf;
-
-use epiphany_core::CONTINUITY_RECOVERY_RECEIPT_TYPE;
-use epiphany_core::EPIPHANY_REORIENT_LAUNCH_BINDING_ID;
-use epiphany_core::EPIPHANY_RESEARCH_ROLE_BINDING_ID;
-use epiphany_core::EYES_EVIDENCE_PACKET_TYPE;
-use epiphany_core::EpiphanyJobInterruptRequest;
-use epiphany_core::EpiphanyJobInterruptResult;
-use epiphany_core::EpiphanyJobLaunchRequest;
-use epiphany_core::EpiphanyJobLaunchResult;
-use epiphany_core::EpiphanyJobView;
-use epiphany_core::EpiphanyLaunchOrganContract;
-use epiphany_core::EpiphanyPromotionInput;
-use epiphany_core::EpiphanyReceiptEffectKind;
-use epiphany_core::EpiphanyReorientDecision;
-use epiphany_core::EpiphanyReorientFindingInterpretation;
-use epiphany_core::EpiphanyReorientStateStatus;
-use epiphany_core::EpiphanyRoleFindingInterpretation;
-use epiphany_core::EpiphanyRoleResultRoleId;
-use epiphany_core::EpiphanyRoleStatePatchDocument;
-use epiphany_core::EpiphanyStateUpdate;
-use epiphany_core::EpiphanyStateUpdatedField;
-use epiphany_core::EpiphanyTokenUsageSnapshot;
-use epiphany_core::MIND_GATEWAY_REVIEW_TYPE;
-use epiphany_core::MindGatewayReview;
-use epiphany_core::RuntimeSpineHeartbeatJobOptions;
-use epiphany_core::RuntimeSpineHeartbeatLaunchPlanOptions;
-use epiphany_core::SOUL_VERDICT_RECEIPT_TYPE;
-use epiphany_core::SUBSTRATE_GATE_REPO_ACCESS_GRANT_RECEIPT_TYPE;
-use epiphany_core::apply_epiphany_state_update;
-use epiphany_core::build_epiphany_reorient_launch_request_with_dynamic_context;
-use epiphany_core::build_epiphany_role_launch_request_with_dynamic_context;
-use epiphany_core::clear_epiphany_job_binding_backend;
-use epiphany_core::continuity_recovery_receipt_from_reorient_finding;
-use epiphany_core::epiphany_role_label;
-use epiphany_core::epiphany_state_update_validation_errors;
-use epiphany_core::evaluate_promotion;
-use epiphany_core::evaluate_receipt_proof_profiles;
-use epiphany_core::eyes_evidence_packet_from_research_finding;
-use epiphany_core::mind_state_commit_receipt;
-use epiphany_core::open_runtime_spine_heartbeat_job;
-use epiphany_core::plan_runtime_spine_heartbeat_launch;
-use epiphany_core::put_continuity_recovery_receipt;
-use epiphany_core::put_eyes_evidence_packet;
-use epiphany_core::put_mind_gateway_review;
-use epiphany_core::put_mind_state_commit_receipt;
-use epiphany_core::put_soul_verdict_receipt;
-use epiphany_core::put_substrate_gate_repo_access_grant_receipt;
-use epiphany_core::receipt_proof_evaluation_errors;
-use epiphany_core::replace_or_append_epiphany_job_binding;
-use epiphany_core::runtime_continuity_recovery_receipt;
-use epiphany_core::runtime_eyes_evidence_packet;
-use epiphany_core::runtime_job_snapshot;
-use epiphany_core::runtime_mind_gateway_review;
-use epiphany_core::runtime_mind_state_commit_receipt;
-use epiphany_core::runtime_soul_verdict_receipt;
-use epiphany_core::runtime_substrate_gate_repo_access_grant_receipt;
-use epiphany_core::soul_verdict_receipt_from_verification_finding;
-use epiphany_core::substrate_gate_repo_access_grant_for_launch;
-use epiphany_state_model::EpiphanyEvidenceRecord;
-use epiphany_state_model::EpiphanyJobKind as CoreEpiphanyJobKind;
-use epiphany_state_model::EpiphanyRetrievalState;
-use epiphany_state_model::EpiphanyRuntimeLink;
-use epiphany_state_model::EpiphanyThreadState;
-
-use crate::cultnet::EpiphanySurfaceSource;
-use crate::error::EpiphanyBridgeError;
-use crate::error::Result as BridgeResult;
-use crate::jobs::derive_epiphany_jobs;
-use crate::jobs::epiphany_blocked_state_job;
-use crate::jobs::map_interrupted_epiphany_job;
-use crate::jobs::map_launched_epiphany_job;
-use crate::launch_context::render_launch_dynamic_prompt_context;
-use crate::launch_context::reorient_launch_context_focus;
-use crate::launch_context::role_launch_context_focus;
-use crate::mutation::build_reorient_acceptance_update;
-use crate::mutation::build_role_acceptance_update;
-use crate::mutation::epiphany_job_launch_changed_fields;
-use crate::mutation::epiphany_promote_changed_fields;
-use crate::mutation::epiphany_update_patch_changed_fields;
-use crate::mutation::thread_epiphany_patch_has_state_replacements;
-use crate::pressure::derive_epiphany_pressure;
-use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
-use crate::reorient::derive_epiphany_freshness_view;
-use crate::reorient::derive_epiphany_reorient;
-use crate::runtime_results::latest_epiphany_runtime_link_for_binding;
-use crate::runtime_results::load_completed_core_epiphany_reorient_finding;
-use crate::runtime_results::load_completed_core_epiphany_role_finding;
-use crate::runtime_results::load_launch_organ_contract_for_runtime_job;
-use uuid::Uuid;
-
-#[allow(async_fn_in_trait)]
-pub trait EpiphanyMutationHost {
- /// Read the Codex-hosted compatibility snapshot.
- ///
- /// The bridge may request host state so core can evaluate typed policy. The
- /// host snapshot is an input fact, not a bridge-owned source of truth.
- async fn epiphany_state(&self) -> Option;
- async fn epiphany_reference_turn_id(&self) -> Option;
- /// Persist a state document already validated by Epiphany core policy.
- ///
- /// This is the Codex JSON-RPC shell's current persistence hook. It must not
- /// grow mutation policy of its own.
- async fn epiphany_persist_state(
- &self,
- next_state: EpiphanyThreadState,
- ) -> BridgeResult;
- /// Locate the native runtime-spine store while Codex still hosts the turn.
- async fn epiphany_runtime_spine_store_path(&self) -> PathBuf;
- /// Project the already-typed state into Codex's current client-visible view.
- async fn client_visible_epiphany_state(
- &self,
- fallback: EpiphanyThreadState,
- ) -> EpiphanyThreadState;
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyThreadUpdateApplied {
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
-}
-
-#[derive(Debug, Clone)]
-pub enum EpiphanyThreadPromoteApplied {
- Rejected { reasons: Vec },
- Accepted(EpiphanyThreadUpdateApplied),
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyRoleAcceptApplied {
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub accepted_receipt_id: String,
- pub accepted_observation_id: String,
- pub accepted_evidence_id: String,
- pub applied_patch: EpiphanyRoleStatePatchDocument,
- pub finding: EpiphanyRoleFindingInterpretation,
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyReorientAcceptApplied {
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub accepted_receipt_id: String,
- pub accepted_observation_id: String,
- pub accepted_evidence_id: String,
- pub finding: EpiphanyReorientFindingInterpretation,
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyJobLaunchApplied {
- pub launcher_job_id: String,
- pub backend_job_id: String,
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub job: EpiphanyJobView,
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyJobInterruptApplied {
- pub cancel_requested: bool,
- pub interrupted_thread_ids: Vec,
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub job: EpiphanyJobView,
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyReorientLaunchApplied {
- pub launcher_job_id: String,
- pub backend_job_id: String,
- pub source: EpiphanySurfaceSource,
- pub state_status: EpiphanyReorientStateStatus,
- pub state_revision: Option,
- pub decision: EpiphanyReorientDecision,
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub job: EpiphanyJobView,
-}
-
-pub async fn apply_epiphany_state_update_to_thread(
- thread: &impl EpiphanyMutationHost,
- update: EpiphanyStateUpdate,
-) -> BridgeResult {
- let current_state = thread.epiphany_state().await.unwrap_or_default();
- let reference_turn_id = thread.epiphany_reference_turn_id().await;
- let next_state =
- apply_epiphany_state_update_to_state(¤t_state, update, reference_turn_id)?;
- thread.epiphany_persist_state(next_state).await
-}
-
-pub fn apply_epiphany_state_update_to_state(
- current_state: &EpiphanyThreadState,
- update: EpiphanyStateUpdate,
- reference_turn_id: Option,
-) -> BridgeResult {
- if update.is_empty() {
- return Err(EpiphanyBridgeError::InvalidRequest(
- "epiphany update patch must contain at least one mutation".to_string(),
- ));
- }
-
- let mut next_state = current_state.clone();
- if let Some(expected_revision) = update.expected_revision
- && next_state.revision != expected_revision
- {
- return Err(EpiphanyBridgeError::InvalidRequest(format!(
- "epiphany state revision mismatch: expected {expected_revision}, found {}",
- next_state.revision
- )));
- }
-
- let validation_errors = epiphany_state_update_validation_errors(&next_state, &update);
- if !validation_errors.is_empty() {
- return Err(EpiphanyBridgeError::InvalidRequest(format!(
- "invalid epiphany update patch: {}",
- validation_errors.join("; ")
- )));
- }
-
- apply_epiphany_state_update(&mut next_state, update, reference_turn_id);
- Ok(next_state)
-}
-
-pub async fn launch_epiphany_job_on_thread(
- thread: &impl EpiphanyMutationHost,
- request: EpiphanyJobLaunchRequest,
-) -> BridgeResult {
- // Compatibility choreography only: core validates the launch plan and
- // runtime-spine opens the typed job. The bridge stitches those typed
- // documents into Codex's JSON-RPC thread shell until CultNet owns the route.
- let current_state = thread.epiphany_state().await.unwrap_or_default();
- validate_expected_revision(request.expected_revision, current_state.revision)?;
- let runtime_store = thread.epiphany_runtime_spine_store_path().await;
- let completed_prior_link = terminal_runtime_link_for_binding(
- ¤t_state,
- request.binding_id.as_str(),
- runtime_store.as_path(),
- )?;
- let mut planning_state = current_state.clone();
- if let Some(link) = completed_prior_link.clone() {
- planning_state.runtime_links.insert(0, link);
- }
-
- let launcher_job_id = format!("epiphany-heartbeat-launch-{}", Uuid::new_v4());
- let backend_job_id = Uuid::new_v4().to_string();
- let launch_plan = plan_runtime_spine_heartbeat_launch(
- &planning_state,
- RuntimeSpineHeartbeatLaunchPlanOptions {
- binding_id: request.binding_id.clone(),
- kind: request.kind,
- scope: request.scope.clone(),
- owner_role: request.owner_role.clone(),
- authority_scope: request.authority_scope.clone(),
- linked_subgoal_ids: request.linked_subgoal_ids.clone(),
- linked_graph_node_ids: request.linked_graph_node_ids.clone(),
- instruction: request.instruction.clone(),
- launch_document: request.launch_document.clone(),
- output_contract_id: request.output_contract_id.clone(),
- organ_launch_contract: request.organ_launch_contract.clone(),
- max_runtime_seconds: request.max_runtime_seconds,
- runtime_job_id: backend_job_id.clone(),
- },
- )
- .map_err(|err| EpiphanyBridgeError::InvalidRequest(err.to_string()))?;
- let next_job_bindings = replace_or_append_epiphany_job_binding(
- current_state.job_bindings.clone(),
- launch_plan.binding,
- );
-
- let mut runtime_links = Vec::new();
- runtime_links.push(launch_plan.runtime_link.clone());
- if let Some(link) = completed_prior_link {
- runtime_links.push(link);
- }
-
- let validation_errors = epiphany_state_update_validation_errors(
- ¤t_state,
- &EpiphanyStateUpdate {
- job_bindings: Some(next_job_bindings.clone()),
- runtime_links: runtime_links.clone(),
- ..Default::default()
- },
- );
- if !validation_errors.is_empty() {
- return Err(EpiphanyBridgeError::InvalidRequest(format!(
- "invalid Epiphany job launch patch: {}",
- validation_errors.join("; ")
- )));
- }
- open_epiphany_runtime_spine_job(
- runtime_store.as_path(),
- &planning_state,
- &request,
- backend_job_id.as_str(),
- )?;
- maybe_put_substrate_gate_launch_grant(
- runtime_store.as_path(),
- &request,
- backend_job_id.as_str(),
- )?;
-
- let epiphany_state = apply_epiphany_state_update_to_thread(
- thread,
- EpiphanyStateUpdate {
- expected_revision: request.expected_revision,
- job_bindings: Some(next_job_bindings),
- runtime_links,
- ..Default::default()
- },
- )
- .await?;
-
- Ok(EpiphanyJobLaunchResult {
- epiphany_state,
- binding_id: request.binding_id,
- launcher_job_id,
- backend_job_id,
- })
-}
-
-fn terminal_runtime_link_for_binding(
- state: &EpiphanyThreadState,
- binding_id: &str,
- runtime_store: &Path,
-) -> BridgeResult