Collapse semantic state contracts into core

This commit is contained in:
Meta Vens 2026-08-24 18:29:58 +02:00
commit 07529fb521
20 changed files with 99 additions and 300 deletions

99
Cargo.lock generated
View file

@ -507,12 +507,6 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "dyn-clone"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "ed25519"
version = "2.2.3"
@ -551,7 +545,6 @@ dependencies = [
"epiphany-model-adapter",
"epiphany-openai-adapter",
"epiphany-release-construction",
"epiphany-state-model",
"epiphany-tool-adapter",
"ghostlight-persona-projection",
"ignore",
@ -649,15 +642,6 @@ dependencies = [
"uuid",
]
[[package]]
name = "epiphany-state-model"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
"ts-rs",
]
[[package]]
name = "epiphany-tool-adapter"
version = "0.1.0"
@ -1867,30 +1851,6 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "schemars"
version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615"
dependencies = [
"dyn-clone",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.119",
]
[[package]]
name = "security-framework"
version = "3.7.0"
@ -1964,17 +1924,6 @@ dependencies = [
"syn 3.0.3",
]
[[package]]
name = "serde_derive_internals"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "serde_json"
version = "1.0.151"
@ -2177,15 +2126,6 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "2.0.20"
@ -2414,30 +2354,6 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "ts-rs"
version = "11.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4994acea2522cd2b3b85c1d9529a55991e3ad5e25cdcd3de9d505972c4379424"
dependencies = [
"serde_json",
"thiserror",
"ts-rs-macros",
"uuid",
]
[[package]]
name = "ts-rs-macros"
version = "11.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee6ff59666c9cbaec3533964505d39154dc4e0a56151fdea30a09ed0301f62e2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
"termcolor",
]
[[package]]
name = "typenum"
version = "1.20.1"
@ -3047,18 +2963,3 @@ name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
[[patch.unused]]
name = "tungstenite"
version = "0.27.0"
source = "git+https://github.com/openai-oss-forks/tungstenite-rs?rev=9200079d3b54a1ff51072e24d81fd354f085156f#9200079d3b54a1ff51072e24d81fd354f085156f"
[[patch.unused]]
name = "tokio-tungstenite"
version = "0.28.0"
source = "git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=132f5b39c862e3a970f731d709608b3e6276d5f6#132f5b39c862e3a970f731d709608b3e6276d5f6"
[[patch.unused]]
name = "tungstenite"
version = "0.27.0"
source = "git+https://github.com/openai-oss-forks/tungstenite-rs?rev=9200079d3b54a1ff51072e24d81fd354f085156f#9200079d3b54a1ff51072e24d81fd354f085156f"

View file

@ -5,7 +5,6 @@ members = [
"epiphany-openai-adapter",
"epiphany-openai-runtime",
"epiphany-release-construction",
"epiphany-state-model",
"epiphany-tool-adapter",
"epiphany-tool-mcp-runtime",
]
@ -54,13 +53,6 @@ incremental = true
[dev-dependencies]
tempfile = "3"
[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" }
[[bin]]
name = "epiphany-release"
path = "epiphany-core/src/bin/epiphany-release.rs"

View file

@ -120,15 +120,15 @@ Epiphany is a native GameCult runtime that began as an opinionated Codex fork.
Her body is made of:
- typed Rust domain organs in `epiphany-core` and `epiphany-state-model`
- 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
- Codex retained only for honest OpenAI subscription auth and model transport;
Epiphany does not publish a Codex-owned project-state surface
- 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

View file

@ -48,7 +48,7 @@ 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}, \code{epiphany-state-model}, model/tool adapters, and OpenAI transport crates;
\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/};
@ -59,20 +59,19 @@ The practical definition in this repository is:
\section{Executive Map}
Epiphany's current Body is a hybrid machine in transition. Its center of gravity
has moved into typed Rust/CultCache organs, but compatibility arteries still
run through vendored Codex. The live target is not a cleaner pile of Codex
routes. The target is an Epiphany-native CultCache/CultMesh/CultNet body with a
relatively vanilla Codex-derived reliquary retained for OpenAI subscription
auth and model transport.
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. \\
Vendored Codex & \code{vendor/codex} & Retain host/app-server/auth/model compatibility where useful; do not let Codex own Epiphany prompts, scheduler, or state. \\
Runtime spine & \code{epiphany-core/src/runtime_spine.rs} and \code{state/runtime-spine.cc} & Runtime identity, jobs, events, receipts, tool/model documents are typed CultCache records. \\
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. \\
@ -82,27 +81,21 @@ Operator artifacts & \code{.epiphany-*}, \code{tools/epiphany_local_run.ps1} & A
\section{Repository Body}
The checkout has nine primary Epiphany Rust crates:
The checkout has eight primary Epiphany Rust packages:
\begin{itemize}
\item \code{epiphany-core}: the main domain organ. It owns state-update
validation, launch documents, runtime spine, Resident Self, Persona
projection, Substrate Gate, Mind, Eyes, Hands, Soul, Continuity, CultMesh
integration, surface derivation, smokes, and local operator binaries.
\item \code{epiphany-state-model}: the durable \code{EpiphanyThreadState}
type plus \code{render_epiphany_state}. This is the typed Mind surface that
prompt fragments and views read.
\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-auth-spine}: Codex-derived auth boundary over
\code{codex-login}. It preserves honest Codex-compatible credential and token
behavior rather than impersonating it from scratch.
\item \code{epiphany-openai-codex-spine}: model transport over vendored Codex
client machinery.
\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
@ -114,8 +107,8 @@ The checkout has nine primary Epiphany Rust crates:
The vendored region contains:
\begin{itemize}
\item \code{vendor/codex}: the Codex-derived host and compatibility substrate.
It is tracked directly, not as a submodule.
\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}

View file

@ -77,7 +77,7 @@ conflicts, or a consequential judgment cannot be derived honestly.
The current native Epiphany body includes:
- typed Rust domain organs in `epiphany-core` and `epiphany-state-model`
- 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
@ -86,7 +86,7 @@ The current native Epiphany body includes:
- runtime-spine job and worker-result documents
- Mind, Modeling, Substrate Gate, Eyes, Hands, Soul, Continuity, Persona, and
heartbeat authority surfaces
- local operator status, coordinator, smoke, and Verse-context commands
- 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.

View file

@ -21,7 +21,6 @@ epiphany-openai-adapter = { path = "../epiphany-openai-adapter" }
epiphany-release-construction = { path = "../epiphany-release-construction" }
epiphany-model-adapter = { path = "../epiphany-model-adapter" }
epiphany-tool-adapter = { path = "../epiphany-tool-adapter" }
epiphany-state-model = { path = "../epiphany-state-model" }
ghostlight-persona-projection = { git = "https://github.com/GameCult/Ghostlight.git", rev = "22281891cbf9258db80c15a9fd465e6fa251e7dd", package = "ghostlight-persona-projection" }
ed25519-dalek = "2"
ignore = "0.4.23"

View file

@ -3406,7 +3406,7 @@ fn resolve_body_modeling_work(
#[cfg(test)]
mod tests {
use super::*;
use epiphany_state_model::{
use crate::state_model::{
EpiphanyMemoryDomain, EpiphanyMemoryLifecycle, EpiphanyMemoryNode, EpiphanyMemoryNodeKind,
RepoFrontierItem, RepoFrontierStatus,
};
@ -5792,12 +5792,12 @@ mod tests {
research_cache.put(&research_context.context_id, &research_context)?;
let stale_research_store = temp.path().join("stale-research-output.cc");
std::fs::copy(&store, &stale_research_store)?;
let evidence = epiphany_state_model::EpiphanyEvidenceRecord {
let evidence = crate::EpiphanyEvidenceRecord {
id: "research-evidence-1".into(),
kind: "external-source".into(),
status: "ok".into(),
summary: "The bounded external claim is supported.".into(),
code_refs: vec![epiphany_state_model::EpiphanyCodeRef {
code_refs: vec![crate::EpiphanyCodeRef {
path: "epiphany-core/src/current_work.rs".into(),
start_line: Some(1),
end_line: None,
@ -5805,7 +5805,7 @@ mod tests {
note: None,
}],
};
let observation = epiphany_state_model::EpiphanyObservation {
let observation = crate::EpiphanyObservation {
id: "research-observation-1".into(),
summary: "External evidence answers the exact frontier question.".into(),
source_kind: "research".into(),

View file

@ -32,6 +32,7 @@ mod runtime_spine;
mod runtime_store_backend;
mod runtime_worker_attempt;
mod soul_gateway;
mod state_model;
mod state_ledger;
mod substrate_gate;
mod surfaces;
@ -99,11 +100,6 @@ pub use cultmesh_integration::{
};
pub use current_work::*;
pub use epiphany_state_model::EpiphanyMemoryAnchor;
pub use epiphany_state_model::EpiphanyMemoryDomain;
pub use epiphany_state_model::EpiphanyMemoryEdge;
pub use epiphany_state_model::EpiphanyMemoryLifecycle;
pub use epiphany_state_model::EpiphanyMemoryNode;
pub use hands_gateway::*;
pub use idunn_provider_health::{
EPIPHANY_IDUNN_PROVIDER_HEALTH_ADMISSION_SCHEMA, EPIPHANY_IDUNN_PROVIDER_HEALTH_ADMISSION_TYPE,
@ -133,13 +129,7 @@ pub use imagination_consideration::{
validate_candidate as validate_imagination_consideration_candidate,
validate_current_request as validate_current_imagination_consideration_request,
};
pub use memory_graph::EpiphanyMemoryEdgeKind;
pub use memory_graph::EpiphanyMemoryGraphSnapshot;
pub use memory_graph::EpiphanyMemoryGraphValidationError;
pub use memory_graph::EpiphanyMemoryNodeKind;
pub use memory_graph::RepoFrontierAdoptedPlan;
pub use memory_graph::RepoFrontierItem;
pub use memory_graph::RepoFrontierStatus;
pub use memory_graph::validate_memory_graph_snapshot;
pub use mind_documents::*;
pub use packaged_release::{
@ -301,6 +291,7 @@ pub use runtime_spine::select_and_commit_repo_frontier_route;
pub use runtime_spine::terminalize_model_pass_failure_session;
pub(crate) use runtime_worker_attempt::{RuntimeTypedRequestRef, WorkerProcessStatus};
pub use soul_gateway::*;
pub use state_model::*;
pub use state_ledger::EpiphanyBranchRecord;
pub use state_ledger::EpiphanyLedgerEvidenceRecord;
pub use state_ledger::EpiphanyStateLedgerEntry;

View file

@ -1,16 +1,5 @@
pub mod validation;
pub use epiphany_state_model::EpiphanyMemoryDomain;
pub use epiphany_state_model::EpiphanyMemoryEdge;
pub use epiphany_state_model::EpiphanyMemoryEdgeKind;
pub use epiphany_state_model::EpiphanyMemoryGraphSnapshot;
pub use epiphany_state_model::EpiphanyMemoryLifecycle;
pub use epiphany_state_model::EpiphanyMemoryNode;
pub use epiphany_state_model::EpiphanyMemoryNodeKind;
pub use epiphany_state_model::RepoFrontierAdoptedPlan;
pub use epiphany_state_model::RepoFrontierItem;
pub use epiphany_state_model::RepoFrontierStatus;
pub use validation::EpiphanyMemoryGraphValidationError;
pub(crate) use validation::frontier_item_has_routeable_repository_scope;
pub(crate) use validation::repo_paths_are_canonical_and_safe;

View file

@ -1,9 +1,9 @@
use super::EpiphanyMemoryDomain;
use super::EpiphanyMemoryEdge;
use super::EpiphanyMemoryGraphSnapshot;
use super::EpiphanyMemoryLifecycle;
use super::EpiphanyMemoryNode;
use super::RepoFrontierStatus;
use crate::EpiphanyMemoryDomain;
use crate::EpiphanyMemoryEdge;
use crate::EpiphanyMemoryGraphSnapshot;
use crate::EpiphanyMemoryLifecycle;
use crate::EpiphanyMemoryNode;
use crate::RepoFrontierStatus;
use std::collections::{HashMap, HashSet};
pub(crate) fn repo_paths_are_canonical_and_safe(paths: &[String]) -> bool {
@ -23,7 +23,7 @@ pub(crate) fn repo_paths_are_canonical_and_safe(paths: &[String]) -> bool {
}
pub(crate) fn frontier_item_has_routeable_repository_scope(
item: &epiphany_state_model::RepoFrontierItem,
item: &crate::RepoFrontierItem,
) -> bool {
!item.repository_scope.is_empty() && repo_paths_are_canonical_and_safe(&item.repository_scope)
}

View file

@ -2,7 +2,7 @@ use std::path::Path;
use anyhow::{Result, anyhow};
use cultcache_rs::{CultCache, CultCacheEnvelope, DatabaseEntry};
use epiphany_state_model::{
use crate::state_model::{
EpiphanyEvidenceRecord, EpiphanyInvariant, EpiphanyInvestigationCheckpoint,
EpiphanyModeState, EpiphanyObservation, EpiphanySubgoal,
};

View file

@ -68,10 +68,10 @@ impl From<EpiphanyRoleWorkerLaunchDocument> for EpiphanyRolePassAuthorityProject
pub struct EpiphanyRepoModelPromptProjection {
pub identity: crate::EpiphanyRepoModelIdentityDocument,
pub projection_digest: String,
pub domains: Vec<epiphany_state_model::EpiphanyMemoryDomain>,
pub nodes: Vec<epiphany_state_model::EpiphanyMemoryNode>,
pub edges: Vec<epiphany_state_model::EpiphanyMemoryEdge>,
pub frontier: Vec<epiphany_state_model::RepoFrontierItem>,
pub domains: Vec<crate::EpiphanyMemoryDomain>,
pub nodes: Vec<crate::EpiphanyMemoryNode>,
pub edges: Vec<crate::EpiphanyMemoryEdge>,
pub frontier: Vec<crate::RepoFrontierItem>,
pub claim_obligations: Vec<crate::EpiphanyRepoModelClaimObligationsDocument>,
pub surface_offers: Vec<crate::AtlasSurfaceOffer>,
pub dependency_claims: Vec<crate::AtlasDependencyClaim>,
@ -104,16 +104,16 @@ pub struct EpiphanyMindPromptProjection {
pub projection_digest: String,
pub objective: Option<String>,
pub active_subgoal_id: Option<String>,
pub subgoals: Vec<epiphany_state_model::EpiphanySubgoal>,
pub invariants: Vec<epiphany_state_model::EpiphanyInvariant>,
pub observations: Vec<epiphany_state_model::EpiphanyObservation>,
pub evidence: Vec<epiphany_state_model::EpiphanyEvidenceRecord>,
pub subgoals: Vec<crate::EpiphanySubgoal>,
pub invariants: Vec<crate::EpiphanyInvariant>,
pub observations: Vec<crate::EpiphanyObservation>,
pub evidence: Vec<crate::EpiphanyEvidenceRecord>,
pub verification_audits: Vec<crate::EpiphanyMindVerificationAuditDocument>,
pub reorientation_decisions: Vec<crate::EpiphanyMindReorientationDecisionDocument>,
pub reorientation_failures: Vec<crate::EpiphanyMindReorientationPassFailureDocument>,
pub agent_pass_admission_refusals: Vec<crate::EpiphanyAgentPassAdmissionRefusal>,
pub investigation_checkpoint: Option<epiphany_state_model::EpiphanyInvestigationCheckpoint>,
pub mode: Option<epiphany_state_model::EpiphanyModeState>,
pub investigation_checkpoint: Option<crate::EpiphanyInvestigationCheckpoint>,
pub mode: Option<crate::EpiphanyModeState>,
pub repository_body_observation: Option<crate::RepositoryBodyObservationBasis>,
pub repo_model: Option<EpiphanyRepoModelPromptProjection>,
}
@ -2627,7 +2627,7 @@ mod tests {
let make = |key: &str, summary: &str| -> Result<CultCacheEnvelope> {
let cache = runtime_spine_cache(&store)?;
let document = crate::EpiphanyMindObservationDocument {
value: epiphany_state_model::EpiphanyObservation {
value: crate::EpiphanyObservation {
id: key.into(),
summary: summary.into(),
source_kind: "test".into(),

View file

@ -19,10 +19,10 @@ pub struct EpiphanyReorientationStateProjection {
pub runtime_id: String,
pub objective: Option<String>,
pub active_subgoal_id: Option<String>,
pub investigation_checkpoint: Option<epiphany_state_model::EpiphanyInvestigationCheckpoint>,
pub mode: Option<epiphany_state_model::EpiphanyModeState>,
pub investigation_checkpoint: Option<crate::EpiphanyInvestigationCheckpoint>,
pub mode: Option<crate::EpiphanyModeState>,
pub repository_body_observation: Option<crate::RepositoryBodyObservationBasis>,
pub frontier: Vec<epiphany_state_model::RepoFrontierItem>,
pub frontier: Vec<crate::RepoFrontierItem>,
pub projection_digest: String,
}
@ -1060,7 +1060,7 @@ mod tests {
cache.put(
"unrelated-observation",
&crate::EpiphanyMindObservationDocument {
value: epiphany_state_model::EpiphanyObservation {
value: crate::EpiphanyObservation {
id: "unrelated-observation".into(),
summary: "Persona observed an unrelated social fact.".into(),
..Default::default()

View file

@ -3,7 +3,7 @@ use std::path::Path;
use anyhow::{Result, anyhow};
use cultcache_rs::{CultCache, CultCacheEnvelope, DatabaseEntry};
use epiphany_state_model::{
use crate::state_model::{
EpiphanyMemoryDomain, EpiphanyMemoryEdge, EpiphanyMemoryGraphSnapshot, EpiphanyMemoryNode,
RepoFrontierItem,
};
@ -835,7 +835,7 @@ pub fn plan_repo_model_mutation(
{
insert_strong_envelope(&mut strong, existing)?;
}
node.lifecycle = epiphany_state_model::EpiphanyMemoryLifecycle::Retired;
node.lifecycle = crate::EpiphanyMemoryLifecycle::Retired;
nodes.insert(node_id.clone(), node.clone());
insert_envelope(
&mut writes,
@ -879,7 +879,7 @@ pub fn plan_repo_model_mutation(
.get_envelope::<EpiphanyRepoModelEdgeDocument>(edge_id)?
.ok_or_else(|| anyhow!("RepoModel edge lost its envelope"))?;
insert_strong_envelope(&mut strong, existing)?;
edge.lifecycle = epiphany_state_model::EpiphanyMemoryLifecycle::Retired;
edge.lifecycle = crate::EpiphanyMemoryLifecycle::Retired;
edges.insert(edge_id.clone(), edge.clone());
insert_envelope(
&mut writes,
@ -1319,9 +1319,9 @@ fn require_semantic_id(value: &str, label: &str) -> Result<()> {
fn frontier_is_unresolved(item: &RepoFrontierItem) -> bool {
matches!(
item.status,
epiphany_state_model::RepoFrontierStatus::Proposed
| epiphany_state_model::RepoFrontierStatus::Active
| epiphany_state_model::RepoFrontierStatus::Blocked
crate::RepoFrontierStatus::Proposed
| crate::RepoFrontierStatus::Active
| crate::RepoFrontierStatus::Blocked
)
}
@ -1509,9 +1509,9 @@ fn validate_claim_obligations(
if !item.target_claim_ids.contains(&obligation.node_id)
|| !matches!(
item.status,
epiphany_state_model::RepoFrontierStatus::Proposed
| epiphany_state_model::RepoFrontierStatus::Active
| epiphany_state_model::RepoFrontierStatus::Blocked
crate::RepoFrontierStatus::Proposed
| crate::RepoFrontierStatus::Active
| crate::RepoFrontierStatus::Blocked
)
{
return Err(anyhow!("RepoModel claim obligation is not live"));
@ -1521,9 +1521,9 @@ fn validate_claim_obligations(
for item in frontier.iter().filter(|item| {
matches!(
item.status,
epiphany_state_model::RepoFrontierStatus::Proposed
| epiphany_state_model::RepoFrontierStatus::Active
| epiphany_state_model::RepoFrontierStatus::Blocked
crate::RepoFrontierStatus::Proposed
| crate::RepoFrontierStatus::Active
| crate::RepoFrontierStatus::Blocked
)
}) {
for node_id in &item.target_claim_ids {
@ -1542,7 +1542,7 @@ fn validate_claim_obligations(
mod tests {
use super::*;
use crate::{RuntimeSpineInitOptions, initialize_runtime_spine};
use epiphany_state_model::{
use crate::state_model::{
EpiphanyMemoryEdgeKind, EpiphanyMemoryLifecycle, EpiphanyMemoryNodeKind, RepoFrontierStatus,
};

View file

@ -418,7 +418,7 @@ pub struct RepoFrontierRoute {
#[cultcache(key = 11)]
pub authorized_paths: Vec<String>,
#[cultcache(key = 12, default)]
pub adopted_plan: Option<epiphany_state_model::RepoFrontierAdoptedPlan>,
pub adopted_plan: Option<crate::RepoFrontierAdoptedPlan>,
#[cultcache(key = 13)]
pub selected_at: String,
}

View file

@ -1,83 +1,70 @@
//! Core-owned semantic state contracts.
use std::path::PathBuf;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use ts_rs::TS;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanySubgoal {
pub id: String,
pub title: String,
pub status: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub summary: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyInvariant {
pub id: String,
pub description: String,
pub status: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub rationale: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyCodeRef {
pub path: PathBuf,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "number | null")]
pub start_line: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "number | null")]
pub end_line: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub symbol: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub note: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case")]
pub enum EpiphanyInvestigationDisposition {
#[default]
ResumeReady,
RegatherRequired,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyInvestigationCheckpoint {
pub checkpoint_id: String,
pub kind: String,
pub disposition: EpiphanyInvestigationDisposition,
pub focus: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub summary: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub next_action: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub captured_at_turn_id: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub open_questions: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<EpiphanyCodeRef>")]
pub code_refs: Vec<EpiphanyCodeRef>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub evidence_ids: Vec<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyObservation {
pub id: String,
pub summary: String,
@ -89,7 +76,7 @@ pub struct EpiphanyObservation {
pub evidence_ids: Vec<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyEvidenceRecord {
pub id: String,
pub kind: String,
@ -99,16 +86,15 @@ pub struct EpiphanyEvidenceRecord {
pub code_refs: Vec<EpiphanyCodeRef>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyModeState {
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "ModeKind | null")]
pub kind: Option<EpiphanyModeKind>,
}
#[derive(
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, JsonSchema, TS, Default,
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, Default,
)]
#[serde(rename_all = "snake_case")]
pub enum EpiphanyModeKind {
@ -123,36 +109,30 @@ pub enum EpiphanyModeKind {
Default,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyMemoryGraphSnapshot {
pub graph_id: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<EpiphanyMemoryDomain>")]
pub domains: Vec<EpiphanyMemoryDomain>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<EpiphanyMemoryNode>")]
pub nodes: Vec<EpiphanyMemoryNode>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<EpiphanyMemoryEdge>")]
pub edges: Vec<EpiphanyMemoryEdge>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<RepoFrontierItem>")]
pub frontier: Vec<RepoFrontierItem>,
}
/// A durable piece of unfinished repository anatomy. This is Modeling-owned state,
/// not a scheduler job or a presentation card.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct RepoFrontierItem {
pub id: String,
pub migration_body: String,
pub question: String,
pub gap: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub target_claim_ids: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
/// Canonical repository-relative path ceiling for this wound. This is the
/// scope that downstream Planning may narrow and Hands may eventually
/// change; inspected files and evidence provenance belong elsewhere.
@ -162,36 +142,28 @@ pub struct RepoFrontierItem {
/// propose this payload, but only the dedicated model transition may make
/// it part of Modeling-owned truth.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "RepoFrontierAdoptedPlan | null")]
pub adopted_plan: Option<RepoFrontierAdoptedPlan>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub dependency_item_ids: Vec<String>,
#[serde(default)]
pub status: RepoFrontierStatus,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub evidence_refs: Vec<String>,
/// Exact immutable public sources selected upstream for Eyes. These are
/// causal retrieval inputs, not evidence produced by Modeling.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub public_source_refs: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub created_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub updated_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub retired_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub superseded_by: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct RepoFrontierAdoptedPlan {
pub planning_request_id: String,
pub result_id: String,
@ -199,18 +171,14 @@ pub struct RepoFrontierAdoptedPlan {
pub candidate_id: String,
pub candidate_sha256: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub safe_paths: Vec<String>,
pub action: String,
pub command: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub checks: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub stop_conditions: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub rollback_steps: Vec<String>,
pub commit_message: String,
}
@ -225,9 +193,8 @@ impl RepoFrontierAdoptedPlan {
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case")]
pub enum RepoFrontierStatus {
#[default]
Proposed,
@ -238,22 +205,20 @@ pub enum RepoFrontierStatus {
Superseded,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyMemoryDomain {
pub id: String,
pub title: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub description: Option<String>,
#[serde(default)]
pub lifecycle: EpiphanyMemoryLifecycle,
}
#[derive(
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, JsonSchema, TS, Default,
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, Default,
)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case")]
pub enum EpiphanyMemoryLifecycle {
#[default]
Observed,
@ -264,10 +229,9 @@ pub enum EpiphanyMemoryLifecycle {
}
#[derive(
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, JsonSchema, TS, Default,
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, Default,
)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case")]
pub enum EpiphanyMemoryNodeKind {
#[default]
Domain,
@ -283,7 +247,7 @@ pub enum EpiphanyMemoryNodeKind {
Other,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyMemoryNode {
pub id: String,
pub domain_id: String,
@ -294,26 +258,21 @@ pub struct EpiphanyMemoryNode {
pub tension: String,
pub action_implication: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<EpiphanyMemoryAnchor>")]
pub anchors: Vec<EpiphanyMemoryAnchor>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<string>")]
pub source_hashes: Vec<String>,
#[serde(default)]
pub lifecycle: EpiphanyMemoryLifecycle,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub created_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub updated_at: Option<String>,
}
#[derive(
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, JsonSchema, TS, Default,
Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, Default,
)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case")]
pub enum EpiphanyMemoryEdgeKind {
#[default]
Owns,
@ -332,7 +291,7 @@ pub enum EpiphanyMemoryEdgeKind {
Other,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyMemoryEdge {
pub id: String,
pub source_id: String,
@ -340,27 +299,22 @@ pub struct EpiphanyMemoryEdge {
pub kind: EpiphanyMemoryEdgeKind,
pub claim: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[ts(type = "Array<EpiphanyMemoryAnchor>")]
pub anchors: Vec<EpiphanyMemoryAnchor>,
#[serde(default)]
pub lifecycle: EpiphanyMemoryLifecycle,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct EpiphanyMemoryAnchor {
pub id: String,
pub kind: String,
pub target: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "EpiphanyCodeRef | null")]
pub code_ref: Option<EpiphanyCodeRef>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub evidence_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub source_hash: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(type = "string | null")]
pub note: Option<String>,
}

View file

@ -1,7 +1,7 @@
use anyhow::{Result, anyhow};
use epiphany_state_model::EpiphanyEvidenceRecord;
use epiphany_state_model::EpiphanyInvestigationCheckpoint;
use epiphany_state_model::EpiphanyObservation;
use crate::state_model::EpiphanyEvidenceRecord;
use crate::state_model::EpiphanyInvestigationCheckpoint;
use crate::state_model::EpiphanyObservation;
use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;

View file

@ -1,19 +0,0 @@
[package]
name = "epiphany-state-model"
version = "0.1.0"
edition = "2024"
publish = false
license-file = "../LICENSE"
[lib]
name = "epiphany_state_model"
path = "src/lib.rs"
[dependencies]
schemars = "0.8"
serde = { version = "1", features = ["derive"] }
ts-rs = { version = "11", features = [
"uuid-impl",
"serde-json-impl",
"no-serde-warnings",
] }

View file

@ -188,11 +188,11 @@ application. `codex-core` re-exports the contract only as a compatibility
alias, and `CodexThread` now calls native state-update functions around its
remaining revision check, persistence validation, and rollout/session writeback.
The credential extraction overcut has been corrected. Codex file/keyring/auto
auth, env API key handling, ChatGPT token refresh, account metadata parsing,
and header-client setup remain in vendored `codex-login`. The redundant
Epiphany re-export crate is gone; the root workspace carries the Codex
`tokio-tungstenite` / `tungstenite` patches required for standalone builds.
This paragraph describes the superseded embedded-auth phase. Exact `ed7357a2`
later removed Codex credential and transport anatomy from Epiphany entirely;
the independent CodexConnector owns that boundary. The unused root
`tokio-tungstenite` / `tungstenite` patches are gone with the compiled Codex
graph.
The point is ownership: Epiphany calls a model adapter; it does not live inside
the Codex host brain.

View file

@ -7,14 +7,13 @@ of app-server routes.
## Objective
Build an inspectable native organism whose typed state, runtime, organ gates,
memory, scheduling, interfaces, and social crossings can operate without Codex
owning Epiphany cognition. Retain Codex-derived code only where it provides an
earned OpenAI-compatible authentication or model-transport capability.
memory, scheduling, interfaces, and social crossings operate without Codex
owning Epiphany cognition. OpenAI subscription authentication and model
transport belong to the independent CodexConnector daemon, not Epiphany's body.
## Current Mechanism
- `epiphany-state-model` owns shared typed semantic contracts; durable Mind is keyed CultCache owned by `epiphany-core`.
- `epiphany-core` owns keyed Mind admission, runtime spine, organ gates,
- `epiphany-core` owns the semantic contracts, keyed Mind admission, runtime spine, organ gates,
Resident Self physiology, Persona, and CultMesh integration. Coordinator policy,
status, and every migrated work family consume keyed Mind plus exact runtime
receipts. Persisted `EpiphanyThreadStateEntry`, the in-memory