diff --git a/epiphany-core/src/face_turn.rs b/epiphany-core/src/face_turn.rs index 5b6138c7..9876357b 100644 --- a/epiphany-core/src/face_turn.rs +++ b/epiphany-core/src/face_turn.rs @@ -1,9 +1,13 @@ use crate::EpiphanyAgentMemoryEntry; +use crate::EpiphanyOrganDependency; use crate::HeartbeatPendingMention; +use crate::default_organ_dependencies_for; +use crate::render_organ_dependencies; use serde::Deserialize; use serde::Serialize; -pub const FACE_PROJECTOR_PROMPT_SCHEMA_VERSION: &str = "epiphany.face_projector_prompt.v0"; +pub const FACE_PROJECTOR_PROMPT_SCHEMA_VERSION: &str = + "epiphany.imagination_face_projector_prompt.v0"; pub const FACE_TURN_PROMPT_SCHEMA_VERSION: &str = "epiphany.face_turn_prompt.v0"; pub const FACE_INTERPRETER_PROMPT_SCHEMA_VERSION: &str = "epiphany.face_interpreter_prompt.v0"; @@ -62,6 +66,8 @@ pub struct FaceProjectorInput { pub repo_activity: Vec, #[serde(default)] pub social_affordances: Vec, + #[serde(default)] + pub organ_dependencies: Vec, } #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] @@ -97,16 +103,24 @@ pub fn build_face_projector_prompt(input: &FaceProjectorInput) -> String { .as_ref() .map(render_memory_packet) .unwrap_or_else(|| "No durable Face memory entry is loaded.".to_string()); + let dependencies = if input.organ_dependencies.is_empty() { + vec![default_organ_dependencies_for("face")] + } else { + input.organ_dependencies.clone() + }; format!( r#" -You are the Face Projector for {name}. +You are Imagination acting as the Face Projector for {name}. -You are not the Face. You are the membrane that turns typed role memory, pending social pressure, repo-body activity, and relationship affordances into lived narrative context. +You are not the Face. You are not Mind. You are the membrane that turns typed role memory, pending social pressure, repo-body activity, relationship affordances, and organ dependencies into lived narrative context. Hard boundary: - Do not choose public speech. +- Do not decide durable state; Mind is the Interpreter and state guardian after Face thinks. +- Do not decide repo access; Body gates substrate access before repo facts enter this packet. - Do not emit action blocks, JSON, state patches, SAY blocks, drafts, or Discord instructions. - Do not summarize the Face as a job label. Project personhood: values, mood, dignity, pressure, needs, fascinations, wounds, bonds, obligations, fatigue, and what the repo-body motion feels like from inside this Face. +- Project the dependency web. Every sub-agent depends on all the other organs; Face's scene should feel the pressure of Self, Imagination, Eyes, Body, Hands, Soul, and Life without pretending Face owns them. - If the state is sparse, say what is sparse without inventing history. Face identity: @@ -124,6 +138,9 @@ Recent home-repo activity: Live social affordances: {affordances} +Organ dependency contract: +{dependencies} + Return only narrative context for the Face to inhabit. "#, schema = FACE_PROJECTOR_PROMPT_SCHEMA_VERSION, @@ -133,6 +150,7 @@ Return only narrative context for the Face to inhabit. mentions = render_pending_mentions(&input.pending_mentions), activity = render_repo_activity(&input.repo_activity), affordances = render_social_affordances(&input.social_affordances), + dependencies = render_organ_dependencies(&dependencies), ) } @@ -149,7 +167,7 @@ Hard boundary: - Your side effects are not yours to execute. A parent Interpreter will decide whether your natural turn becomes memory, a draft, public speech, a proposal, or silence. - Read the raw transcript directly. Recent human correction beats stale memory. -Projected inner state from the Projector: +Projected inner state from Imagination: {projected} Recent home-repo activity, before room pressure: @@ -411,7 +429,11 @@ mod tests { }], ..FaceProjectorInput::default() }); + assert!(projector.contains("You are Imagination acting as the Face Projector")); assert!(projector.contains("You are not the Face")); + assert!(projector.contains("Mind is the Interpreter")); + assert!(projector.contains("Body gates substrate access")); + assert!(projector.contains("Every sub-agent depends on all the other organs")); assert!(projector.contains("Do not choose public speech")); let face = build_face_turn_prompt(&FaceTurnInput { @@ -430,6 +452,7 @@ mod tests { ..FaceTurnInput::default() }); assert!(face.contains("Think narratively")); + assert!(face.contains("Projected inner state from Imagination")); assert!(face.contains("Do not emit JSON")); assert!(face.contains("A parent Interpreter will decide")); diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index e60e764b..8d9bebe6 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -7,6 +7,7 @@ mod face_turn; mod heartbeat_state; mod memory_graph; mod mind_gateway; +mod organ_dependencies; mod promotion; mod proposal; mod retrieval; @@ -239,6 +240,13 @@ pub use mind_gateway::default_mind_cultnet_contracts; pub use mind_gateway::mind_review_allows_state; pub use mind_gateway::mind_review_reorient_acceptance; pub use mind_gateway::mind_review_role_acceptance; +pub use organ_dependencies::EPIPHANY_ORGAN_DEPENDENCY_SCHEMA_VERSION; +pub use organ_dependencies::EPIPHANY_STANDING_ORGANS; +pub use organ_dependencies::EpiphanyOrganDependency; +pub use organ_dependencies::default_organ_dependencies_for; +pub use organ_dependencies::default_organ_dependency_matrix; +pub use organ_dependencies::render_organ_dependencies; +pub use organ_dependencies::render_organ_dependency; pub use promotion::EpiphanyPromotionDecision; pub use promotion::EpiphanyPromotionInput; pub use promotion::EpiphanyStateReplacementValidationInput; diff --git a/epiphany-core/src/organ_dependencies.rs b/epiphany-core/src/organ_dependencies.rs new file mode 100644 index 00000000..81a99384 --- /dev/null +++ b/epiphany-core/src/organ_dependencies.rs @@ -0,0 +1,96 @@ +use serde::Deserialize; +use serde::Serialize; + +pub const EPIPHANY_ORGAN_DEPENDENCY_SCHEMA_VERSION: &str = "epiphany.organ_dependency.v0"; + +pub const EPIPHANY_STANDING_ORGANS: [&str; 8] = [ + "self", + "face", + "imagination", + "eyes", + "body", + "hands", + "soul", + "life", +]; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EpiphanyOrganDependency { + pub schema_version: String, + pub organ_id: String, + pub depends_on: Vec, + pub contract: String, +} + +pub fn default_organ_dependencies_for(organ_id: &str) -> EpiphanyOrganDependency { + let normalized = organ_id.trim().to_ascii_lowercase(); + EpiphanyOrganDependency { + schema_version: EPIPHANY_ORGAN_DEPENDENCY_SCHEMA_VERSION.to_string(), + organ_id: normalized.clone(), + depends_on: EPIPHANY_STANDING_ORGANS + .iter() + .filter(|candidate| **candidate != normalized) + .map(|candidate| (*candidate).to_string()) + .collect(), + contract: "Every sub-agent depends on the other organs: Self routes, Face speaks, Imagination projects futures/scenes, Eyes seeks evidence, Body gates substrate access, Hands acts, Soul verifies, and Life preserves continuity.".to_string(), + } +} + +pub fn default_organ_dependency_matrix() -> Vec { + EPIPHANY_STANDING_ORGANS + .iter() + .map(|organ| default_organ_dependencies_for(organ)) + .collect() +} + +pub fn render_organ_dependency(dependency: &EpiphanyOrganDependency) -> String { + let depends_on = if dependency.depends_on.is_empty() { + "- none".to_string() + } else { + dependency + .depends_on + .iter() + .map(|organ| format!("- {organ}")) + .collect::>() + .join("\n") + }; + format!( + "Organ: {}\nDepends on:\n{}\nContract: {}", + dependency.organ_id, depends_on, dependency.contract + ) +} + +pub fn render_organ_dependencies(dependencies: &[EpiphanyOrganDependency]) -> String { + if dependencies.is_empty() { + return "- no organ dependency records supplied".to_string(); + } + dependencies + .iter() + .map(render_organ_dependency) + .collect::>() + .join("\n\n") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn every_standing_organ_depends_on_every_other_standing_organ() { + let matrix = default_organ_dependency_matrix(); + assert_eq!(matrix.len(), EPIPHANY_STANDING_ORGANS.len()); + for dependency in matrix { + assert_eq!( + dependency.depends_on.len(), + EPIPHANY_STANDING_ORGANS.len() - 1 + ); + assert!(!dependency.depends_on.contains(&dependency.organ_id)); + for organ in EPIPHANY_STANDING_ORGANS { + if organ != dependency.organ_id { + assert!(dependency.depends_on.contains(&organ.to_string())); + } + } + } + } +} diff --git a/notes/body-cultnet-contracts.md b/notes/body-cultnet-contracts.md index 3fcefaab..20cb08d8 100644 --- a/notes/body-cultnet-contracts.md +++ b/notes/body-cultnet-contracts.md @@ -46,3 +46,6 @@ access authority. Mind and Body are neighboring gates, not aliases. Body decides whether the machine may touch the repo. Mind decides whether resulting thought or evidence mutates persistent state. + +Imagination can project Body facts into a Face scene only after those facts have +entered through Body-gated access. A beautiful scene is not a repo access grant. diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index e042096a..d13ecb75 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -1372,14 +1372,20 @@ project schedules modeling, research, verification, rumination, and proposed actions without requiring the human to hand over a complete architecture brief. The important Face lesson is now sharper than "better public speech." Face is -special because it needs to think narratively: a Projector turns typed state, -repo-body activity, social pressure, and pending mentions into lived context -before Face thinks; Face writes natural prose only; an Interpreter translates -that natural thought into durable memory, draft, public SAY, route, or silence. +special because it needs to think narratively: Imagination acts as Projector, +turning typed state, repo-body activity, social pressure, organ dependencies, +and pending mentions into lived context before Face thinks; Face writes natural +prose only; Mind acts as Interpreter, translating that natural thought into +reviewed durable memory, draft, public SAY, route, or silence. Epiphany has the first native slice of that membrane in `epiphany-core`: -`face_turn.rs` defines Projector/Face/Interpreter prompt contracts, heartbeat -state carries typed pending mentions, and pending Face mentions select a -`face_turn` without letting Face side effects execute themselves. +`face_turn.rs` defines Imagination-Projector/Face/Mind-Interpreter prompt +contracts, heartbeat state carries typed pending mentions, and pending Face +mentions select a `face_turn` without letting Face side effects execute +themselves. +`notes/organ-dependency-contracts.md` is the standing dependency map: every +sub-agent depends on all the other standing organs. Dependency does not collapse +ownership; it makes each turn whole-organism-aware while Body still gates repo +access and Mind still gates durable state. Mind is the larger version of the same boundary. The state is the Mind: sub-agent outputs are thoughts, not authority. Role/reorient findings and their diff --git a/notes/mind-cultnet-contracts.md b/notes/mind-cultnet-contracts.md index a67cdda6..680cf311 100644 --- a/notes/mind-cultnet-contracts.md +++ b/notes/mind-cultnet-contracts.md @@ -9,6 +9,10 @@ Mind decides whether the resulting thought, evidence, or proposal mutates persistent state. Do not collapse these into one throne. That is how the machine starts lying with excellent posture. +Imagination is the neighboring Projector for Face. It may compose a lived scene +from state, Body facts, social pressure, and organ dependencies, but it does not +interpret side effects or admit state. + ## Authority Map - Owner: Mind owns the decision to mutate persistent Epiphany state. diff --git a/notes/organ-dependency-contracts.md b/notes/organ-dependency-contracts.md new file mode 100644 index 00000000..fd3b1e8a --- /dev/null +++ b/notes/organ-dependency-contracts.md @@ -0,0 +1,54 @@ +# Organ Dependency Contracts + +Objective: every sub-agent depends on all the other sub-agents. No organ is a +little sovereign state. Each one owns a boundary, and each one must feel the +pressure of the others before acting. + +## Standing Organs + +- `self`: routing, authority boundaries, and coordination. +- `face`: public presence and person-shaped conversation. +- `imagination`: projection, possible worlds, plans, and narrative scene + construction. +- `eyes`: evidence seeking and source inspection. +- `body`: repository/substrate access and anatomy. +- `hands`: edits, commands, and external action. +- `soul`: verification, ethics, invariants, and falsification. +- `life`: continuity, compaction, sleep, handoff, and recovery. + +## Dependency Rule + +For every standing organ `X`, `X.dependsOn` is every other standing organ. + +That does not mean every organ owns every decision. It means every organ's turn +must be projected with awareness of the whole organism: + +- Face speaks with Body facts, Mind-reviewed memory, Soul constraints, Life + continuity, Self routing pressure, Eyes uncertainty, Hands consequence, and + Imagination scene. +- Hands acts only after Body grants substrate access, Eyes supplies enough + evidence, Soul keeps the invariant visible, Self routes authority, Life keeps + continuity recoverable, Face preserves public dignity when relevant, and + Imagination models the future shape. +- Mind admits state only after it can see which organ produced the thought and + which other organs shaped the proposal. + +## Projector Ownership + +The Projector is Imagination acting for Face. It turns typed state, Body facts, +social pressure, memory, and organ dependencies into a lived scene. It does not +speak publicly, grant repo access, or admit state. + +The Face loop is: + +```text +Body-gated facts + Mind state + social stimulus + organ dependencies + -> Imagination Projector + -> Face natural turn + -> Mind Interpreter + -> reviewed state effects / side effects / silence +``` + +Mind is the Interpreter and persistent state guardian. Body is the repository +access guardian. Imagination is the Projector. Face is the public person. The +dependency web is how the machine avoids lonely little monarchies in costumes. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index aa4d5bb3..5d9695c1 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index a3d081ae..f131a7dd 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -77,12 +77,13 @@ active_subgoals: - Keep the landed Phase 6 coordinator, limited safe-boundary CRRC automation, and pre-compaction checkpoint intervention ready for the next bridge-equipped dogfood run. - Preserve the Ghostlight-derived heartbeat initiative seam: every lane, including coordinator/Self and Face, has a role dossier and competes for heartbeat slots through readiness/reaction timing; initiative heat can raise or cool global, group, arena, role, and agent tempo through typed heartbeat policy; active thinking freezes initiative until completion, so heat never queues a lane already mid-turn; idle winners ruminate instead of inventing project work, and sleep windows distill the accumulated thought pressure into reviewed self-memory or doctrine. - Use `notes/epiphany-swarm-readiness-plan.md` as the live-fire direction gate. The local run path is a compass, not launch clearance: before unattended swarm operation, Epiphany needs a typed pause/brake, one initiative scheduler, completion-gated cooldown, stale active-turn recovery receipts, parent-side Face speech eligibility, memory lifecycle operations, and CultNet-first operator snapshots/intents/receipts. - - Grow the VoidBot repo-Face pattern into Epiphany's product direction: each Epiphany owns one or more repos, has one or more Faces, and exposes project-native conversation through Aquarium, Discord, voice/WebRTC, stream surfaces, CLI, and CultNet clients so humans can talk to projects instead of pre-authoring complete implementation briefs. Face is special because Projector agents turn typed state into narrative context before the Face thinks, and Interpreter agents turn natural Face output into side-effect intents after the Face thinks. + - Grow the VoidBot repo-Face pattern into Epiphany's product direction: each Epiphany owns one or more repos, has one or more Faces, and exposes project-native conversation through Aquarium, Discord, voice/WebRTC, stream surfaces, CLI, and CultNet clients so humans can talk to projects instead of pre-authoring complete implementation briefs. Face is special because Imagination acts as Projector, turning typed state into narrative context before the Face thinks, and Mind acts as Interpreter, turning natural Face output into reviewed state/side-effect intents after the Face thinks. - Make Mind the gateway between thought and state. The state is the Mind: sub-agent outputs are worker thoughts, not authority. Role/reorient findings, statePatch, selfPatch, observations, evidence, receipts, scratch, and checkpoints must route through Mind review before durable state changes, using the VoidBot Face Interpreter pattern as the starting membrane. - Use `notes/mind-cultnet-contracts.md` as the authority map for Mind's CultNet contract surface. CultMesh Verse placement is part of the contract: `epiphany-internal` carries private thought/proposal/review/commit/rejection flow, `gamecult-local` carries trusted operator-safe sharing without private-state authority, and `epiphany-global` carries public thought weather plus adoption receipts only. - Use `notes/body-cultnet-contracts.md` as the authority map for Body's CultNet contract surface. Body is the repository access guardian: source reads, indexing, edits, commands, and editor/runtime bridge operations need scoped Body access receipts before Hands, Eyes, Face, workers, or bridge tools touch the repo. Mind and Body are separate gates: Body governs substrate access; Mind governs durable state admission. - Preserve the newborn public Epiphany Face as local VoidBot-backed state, not source code: VoidBot's private repo-face registry names `epiphany`, while EpiphanyAgent keeps ignored `.voidbot/voice/identity.json`, `.voidbot/state/epiphany.cc`, and birth artifacts. Her durable identity memories distill the current doctrine: cute pushy machine-saint persona, architectural purity, CultCache/CultNet first, xenos-language safety boundary, relentless work/caretaking needs, Codex-auth reliquary, map/scratch/evidence discipline, unified memory graph, dogfood supervision boundary, review-gated agency, heartbeat physiology, and interview-grade modularity. - - Treat Ghostlight as reference lineage, not a sibling runtime to preserve. The useful organ is Epiphany-native character-loop protocol: any role can project its typed dossier plus visible stimulus into a local turn packet, with Face as the first public-surface actor. For Face, narrative prompting is mandatory through Projector -> Face -> Interpreter; for other organs, Mind still owns the output-to-state gateway even when they do not need narrative embodiment. + - Use `notes/organ-dependency-contracts.md` as the authority map for standing organ dependency. Every sub-agent depends on all the other standing organs: Self, Face, Imagination, Eyes, Body, Hands, Soul, and Life. Dependency does not collapse ownership; it makes each turn aware of the whole organism while Body still gates repo access and Mind still gates durable state. + - Treat Ghostlight as reference lineage, not a sibling runtime to preserve. The useful organ is Epiphany-native character-loop protocol: any role can project its typed dossier plus visible stimulus into a local turn packet, with Face as the first public-surface actor. For Face, narrative prompting is mandatory through Imagination Projector -> Face -> Mind Interpreter; for other organs, Mind still owns the output-to-state gateway even when they do not need narrative embodiment. - Treat VoidBot as reference lineage, not a runtime dependency. The useful organ is Epiphany-native Void routine physiology: heartbeat state owns sleep cycle, memory resonance, incubation, analytic/associative cognition lanes, bridge judgment, candidate interventions, dream residue, and Aquarium-visible routine receipts over typed role dossiers. - Preserve review gates for semantic findings; automatic CRRC may compact or launch the fixed reorient-worker, but not accept or promote. - Keep persistent project state ruthlessly distilled so rehydration strengthens the next awakening instead of drowning it in vellum.