diff --git a/epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs b/epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs index bd80518e..c75347b1 100644 --- a/epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs +++ b/epiphany-core/src/bin/epiphany-persona-feedback-ingress.rs @@ -3,11 +3,33 @@ use epiphany_core::{ import_bifrost_persona_feedback_deliveries, validate_bifrost_persona_feedback_source, validate_persona_feedback_store_separation, }; -use serde_json::json; +use serde::Serialize; use std::collections::BTreeMap; use std::env; use std::path::PathBuf; +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +struct IngressProjection { + schema_version: &'static str, + status: &'static str, + runtime_id: String, + repository: String, + persona_id: String, + applicable_delivery_count: usize, + present_pressure_count: usize, + authority: &'static str, + private_state_exposed: bool, +} + +fn import_projection_status(present_pressure_count: usize) -> &'static str { + if present_pressure_count == 0 { + "no-applicable-deliveries" + } else { + "pressure-present" + } +} + fn main() -> Result<()> { let mut args = env::args().skip(1); let command = args.next().ok_or_else(|| anyhow!("use status or import"))?; @@ -29,7 +51,7 @@ fn main() -> Result<()> { let runtime_id = required("--runtime-id")?; let repository = required("--repository")?; let persona_id = required("--persona-id")?; - let (status, delivery_count, admitted_count) = match command.as_str() { + let (status, applicable_delivery_count, present_pressure_count) = match command.as_str() { "status" => ( "ready", validate_bifrost_persona_feedback_source( @@ -66,23 +88,52 @@ fn main() -> Result<()> { &repository, &persona_id, )?; - ("admitted", admitted.len(), admitted.len()) + ( + import_projection_status(admitted.len()), + admitted.len(), + admitted.len(), + ) } _ => return Err(anyhow!("unknown command {command:?}; use status or import")), }; println!( "{}", - serde_json::to_string_pretty(&json!({ - "schemaVersion": "epiphany.persona_feedback.ingress_projection.v0", - "status": status, - "runtimeId": runtime_id, - "repository": repository, - "personaId": persona_id, - "deliveryCount": delivery_count, - "admittedCount": admitted_count, - "authority": "resident-pressure-only", - "privateStateExposed": false, - }))? + serde_json::to_string_pretty(&IngressProjection { + schema_version: "epiphany.persona_feedback.ingress_projection.v1", + status, + runtime_id, + repository, + persona_id, + applicable_delivery_count, + present_pressure_count, + authority: "resident-pressure-only", + private_state_exposed: false, + })? ); Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn import_projection_does_not_call_absence_admission() { + assert_eq!(import_projection_status(0), "no-applicable-deliveries"); + assert_eq!(import_projection_status(1), "pressure-present"); + let encoded = serde_json::to_value(IngressProjection { + schema_version: "epiphany.persona_feedback.ingress_projection.v1", + status: import_projection_status(0), + runtime_id: "epiphany-yggdrasil".into(), + repository: "GameCult/Alien".into(), + persona_id: "epiphany".into(), + applicable_delivery_count: 0, + present_pressure_count: 0, + authority: "resident-pressure-only", + private_state_exposed: false, + }) + .expect("projection serializes"); + assert_eq!(encoded["status"], "no-applicable-deliveries"); + assert!(encoded.get("admittedCount").is_none()); + } +} diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 54e1a912..d6069bea 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -3260,3 +3260,32 @@ Next: run the Starfire-offline real Discord/Persona feedback rehearsal wholly on Ygg, proving replay/tamper refusal and byte-identical Mind, Hands, release, and deployment stores. Then audit the Discord operator surface needed during the move. No wake grant and no host reboot are authorized. + +## Live organizational feedback half proved; projection lie cut (2026-07-19) + +The Ygg production Bifrost feedback provider is ready with six typed bindings. +The live stores contain one real VoidBot Discord observation, one Bifrost-signed +delivery, and one Epiphany local pressure admission. Re-import through deployed +154d is byte-identical across the delivery, admitted-feedback, Mind, runtime, +and deployment stores. An alien signing identity is refused before writes. A +substituted repository finds zero applicable deliveries and writes no +feedback/Mind/runtime state. + +That zero-delivery probe exposed a diagnostic conceptual substitution: +`epiphany.persona_feedback.ingress_projection.v0` printed `status=admitted` and +`admittedCount=0`. No consumer depends on it. Successor source deletes the v0 +lie and emits typed v1 status `pressure-present` or +`no-applicable-deliveries`, with `applicableDeliveryCount` and +`presentPressureCount`. Its focused test and binary check pass. + +Source inspection proves the local Persona response path is independent of +observation export: VoidBot queues the repo-Persona turn first, then launches +the three-attempt export asynchronously. Export failure therefore cannot +suppress the local response. + +The final live pressure-to-Imagination scheduling step is intentionally not +run while the all-scope brake is engaged. Do not release it to flatter the +smoke. Modeling is mapping the separate move-period Discord operator nerve; +before July 22, essential status/sleep/wake/directive/review must not depend on +Starfire or improvised SSH, and Persona conversation must remain pressure +rather than Mind/Hands/release/deployment authority. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index d8ad8c96..cdd53d34 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index f1d174e8..0abba760 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -798,6 +798,7 @@ current_status: - Exact state-boundary commit `36f687eaa34153a166b5860087c28f8847244823` is deployed on Yggdrasil through Bifrost authority `release:GameCult/Epiphany:refs/heads/main:36f687eaa34153a166b5860087c28f8847244823` and Idunn request `manual:redeploy:yggdrasil-epiphany:manual:redeploy:yggdrasil-epiphany:unix:1784452916`. Release `sha256-a9afe96abf5b104da3d25bf5e11b967de546c57a230fa155b3cbb98c3b176385` and witness `sha256-f6b4c68054ce9566002e46d49e8773924d3518afdd02798e1a09f1778359d3c2` passed signed active health admission and produced `deployment.env` at 2026-07-19T09:23:14Z. Idunn, supervisor, Heartbeat, and resident Self are active with zero restarts; the full typed check passes; the all-scope deployment brake remains engaged. The live proof required Odin verifier `64bb679`, which reads the root-owned pinned Epiphany identity without creating a writer lock; `/etc/gamecult/idunn/epiphany-health-identity.ccmp.lock` is absent. - Successor `2d21c48d7425c3d6d692e506e1981f92991d82ac` was refused by live Yggdrasil admission. Its resident Self restart-looped because autonomous proposal promotion treated absent thread state as fatal. Idunn published failed health and did not admit the candidate. The owner-level correction makes missing thread state an inert, byte-identical no-work result while retaining errors for malformed present authority; the negative test and full 579/0/1 library proof pass. Cancelling the failed actuator then exposed Idunn's missing restart recovery: exact unresolved request heads survived without a result and blocked supersession. Odin commit `15a744c826f0aa2e8cc322a6543ea8a9afcd852a` CAS-terminalizes only exact prior-incarnation requests as failed on startup and passes 51/51 tests; Ygg runs binary SHA-256 `c441b9e58e85aff1d869b1e07b0a12a4795c6805619ce640184dbdcfce4e7e03`. Ops commits `584b94c` and `46425f9` move packaging before outage and seal package directories immutable but traversable. - Corrected Epiphany commit `154dc1eadd98dda25916ee40e7130770e145e874` is admitted on Yggdrasil. Bifrost authority digest is `d7e21f11d758e3ebaa46945ddd7acca1417ab8f8a81c3ec1932f3d5e0109e72f`; release is `sha256-16c51bb3b4914578213f0d0b64e40e17982ad45832e073d747db903509f237ed`; witness is `sha256-85702cf922ea32c07457630a7911b2b9196c8b58ee4baa642185a0b77902f234`; Idunn request is `deploy:yggdrasil-epiphany:unix:1784456326`; manifest v2 published at `2026-07-19T10:20:04Z`. The full typed check passes, signed health names exact source/release/witness and all four managed services terminal-current, supervisor and Heartbeat have zero restarts, and resident Self is stable on one MainPID with no restart growth after historical counter 10. Its operator projection reports `status=braked`, revision zero, no active turn, and no private state exposure. GPU embedding remains 100% on the GTX 1080. + - The Starfire-independent live feedback half is proved on Ygg. The production Bifrost provider is ready with six typed bindings; one real VoidBot Discord observation is one signed delivery and one local Epiphany pressure admission. Re-import through the deployed 154d binary is byte-identical across delivery, admitted-feedback, Mind, runtime, and deployment stores. An alien signing identity is refused before writes. A substituted repository selects zero applicable deliveries and writes no feedback/Mind/runtime state, but exposed a diagnostic conceptual substitution: ingress projection v0 said `status=admitted` with zero deliveries. The successor source deletes `admittedCount` and v0's false admission status; typed v1 reports `pressure-present` or `no-applicable-deliveries` with applicable-delivery and present-pressure counts. Focused projection proof passes. The live all-scope brake intentionally prevents the final feedback-to-Imagination scheduling proof; do not release it merely to make the smoke green. - Exact successor `aa3d2330062a34145cb70b527e02fa00215eac1b` passed local proof but was revoked before deployment because live packaging repeated `Permission denied` when creating a random staging directory directly under the shared root-owned release directory. This disproved the predecessor-cleanup race hypothesis. The builder's long-lived ownership lease over `/srv/epiphany/app/releases` was the incoherent boundary; no package, service, or witness was published from this attempt. - Release construction is now generation-scoped. The packager creates its random staging sibling beneath the exact source-commit directory, then atomically renames to the final release id within that same directory, preserving canonical absolute witness paths. Idunn keeps the shared release root root-owned and grants `epiphany-builder` only the exact commit directory during construction; cleanup removes only nested staging and seals that generation root-owned. Candidate `03e1afd24546a7ca37e900c47ca26ae257b14161` proved this boundary by sealing immutable release `sha256-fe7f25ff60d84ae9316d7b4aa2833bd5d1b65189c9d08cc64e903a83d8f35268`; its first app publication could not traverse the still builder-owned 0750 generation parent. Cleanup sealed the parent and an automatic exact-package retry started all three services. The actuator must seal the exact generation parent root-owned 0755 before app-owned publication, not only during cleanup. - Candidate `03e1afd24546a7ca37e900c47ca26ae257b14161` was not deployed. Projection and Heartbeat were healthy and braked, but resident Self opened the shared resident store as if every row belonged to its schema catalog and rejected the legitimate `epiphany.resident_cognition.provider_readiness` row. The exact process group was terminated, all three services were stopped, `active-release.env` was removed, and no deployment witness exists. Resident Self now constructs an owner-filtered typed view from raw envelopes, admits only its six owned document families, rejects duplicate owned identities, and preserves foreign readiness rows during writes. Full core proof passes 572/572 with one ignored. @@ -807,4 +808,4 @@ current_status: - Candidate `b8517d9d7905eb62314db675cc2f0688510aa5bd` proved stale launch terminalization and current-policy replacement launch: supervisor PID `1147968` launched replacement workspace projector PID `1148157`, whose authenticated ready heartbeat advanced while the engaged brake held. Recovery still stalled because the old Body claim could be read only through current-claim authentication, which correctly rejected its historical policy before the mismatch recovery branch. The candidate was rolled back and revoked; no deployment witness exists. Claim sight now has two explicit authorities: current authentication is required for provider projection work and rejects stale launches; recovery authentication proves the old signed claim/body/route lineage only. Supervisor recovery and directive writing use the recovery reader, while old launch authentication inside the atomic lease-transfer transaction is historical and the replacement launch/heartbeat remain current-policy evidence. The full causal test performs an actual policy rotation and proves current refusal, historical recovery, directive fencing, lease transfer, successor current sight, and replay/tamper boundaries. Full core passes 573/573 with one ignored; all binaries compile. - Candidate `351355d3baee2d475f84168136380d2f50197ef8` authenticated the historical claim and started all three owners under the brake, but recovery refused because the claim named an older launch than the current replacement's direct parent. Repeated failed candidate deployments had formed a valid signed replacement chain, while recovery still assumed one direct old-to-new edge. The exact Idunn process group was terminated, all services stopped, active pointer and witness removed, and Bifrost authority revoked. No deployment witness exists. Recovery now authenticates the complete immutable chain from the claim's historical launch to the live current-policy descendant: every intermediate launch is host-signed, every parent termination id and envelope digest is exact, chronology is ordered, cycles and broken edges refuse, and the selected endpoint must be current. Directive writing, receipt verification, atomic lease transfer, and supervisor resume share this proof. Typed refusal now exposes the exact lineage fault instead of swallowing it. The causal recovery test contains a real intermediate generation and still proves the full fenced transaction. Full library passes 573/573 with one ignored; supervisor authority tests pass 24/24. - Candidate `a70fe275195740ecefc2984b32ebd8ae93658c18` proved the full signed multi-generation chain and emitted recovery directive `06165fb6-97bd-4c27-97e3-38af03dec72d` from historical claim `c6df4335-7080-4d5f-80fc-4fa18a9d16ce` to current launch `9414c32f-f53c-450c-bc19-a69f5ba04a29`. The replacement projector nevertheless kept refusing stale-policy claim sight because its pulse authenticated the not-yet-created current successor claim before looking for the recovery directive. Supervisor replayed the same directive without mutating Body, exposing a circular ordering fault. The exact Idunn process group was terminated, services stopped, pointer and witness removed, and Bifrost authority revoked; no deployment witness exists. Projector recovery directive consumption now precedes all ordinary projection work and invokes the already idempotent atomic transfer directly. Current claim sight is an output of recovery, never a prerequisite for it. Full library now passes 574/574 with one ignored; supervisor authority tests pass 24/24. - next_action: "Treat exact braked 154dc1ea as the certified organizational resident baseline. Run the Starfire-offline Persona/Discord organizational-feedback rehearsal entirely on Yggdrasil: real VoidBot writer -> Bifrost signature/delivery -> Epiphany ingress -> resident consideration/proposal, proving replay/tamper refusal and byte-identical Mind/Hands/release/deployment stores. Then audit Discord operator controls needed to direct the swarm while Starfire is packed. Conversation/proposal alone grants no Mind, Hands, Persona-speech, release, or deployment authority. No host reboot is authorized." + next_action: "Commit/push the honest Persona-feedback ingress v1 projection, then integrate the move-period Discord operator map. Live Ygg already proves real Discord observation -> Bifrost signature -> Epiphany pressure, replay idempotence, alien signer refusal, and no feedback/Mind/runtime/deployment mutation on hostile target selection. Keep the all-scope brake engaged; the feedback-to-Imagination live scheduling step requires a later explicit wake grant. Before July 22, close any mapped gap that would make essential status/sleep/wake/directive/review depend on Starfire or ad hoc SSH while preserving that conversation/proposal alone grants no Mind, Hands, Persona-speech, release, or deployment authority. No host reboot is authorized."