From c247709647f50350de689cbb5b220fc3aebf6bb8 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 12 Jul 2026 23:50:39 +0100 Subject: [PATCH] Derive cluster daemon heartbeat status --- .../src/bin/epiphany-cluster-daemon.rs | 18 +----------------- ...onceptual-substitution-audit-2026-07-12.md | 9 +++++++++ notes/fresh-workspace-handoff.md | 3 +++ state/ledgers.msgpack | Bin 447159 -> 447509 bytes state/map.yaml | 2 +- 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-cluster-daemon.rs b/epiphany-core/src/bin/epiphany-cluster-daemon.rs index 9ce0f1f7..caf84036 100644 --- a/epiphany-core/src/bin/epiphany-cluster-daemon.rs +++ b/epiphany-core/src/bin/epiphany-cluster-daemon.rs @@ -81,7 +81,7 @@ fn write_heartbeat(args: &Args, iteration: u64) -> Result Result, } impl Args { @@ -146,10 +141,8 @@ impl Args { let mut store = PathBuf::from(".epiphany-run/cultmesh/local-verse.ccmp"); let mut runtime_id = "epiphany-local".to_string(); let mut daemon_id = None; - let mut daemon_status = "ready".to_string(); let mut interval_seconds = 60_u64; let mut max_iterations = 1_u64; - let mut note = None; while let Some(arg) = values.next() { match arg.as_str() { @@ -160,9 +153,6 @@ impl Args { "--daemon-id" => { daemon_id = Some(values.next().context("missing --daemon-id value")?) } - "--daemon-status" => { - daemon_status = values.next().context("missing --daemon-status value")? - } "--interval-seconds" => { interval_seconds = values .next() @@ -175,24 +165,18 @@ impl Args { .context("missing --max-iterations value")? .parse()?; } - "--note" => note = Some(values.next().context("missing --note value")?), other => anyhow::bail!("unknown argument {other:?}"), } } let daemon_id = daemon_id.context("cluster daemon requires --daemon-id")?; - if !matches!(daemon_status.as_str(), "ready" | "degraded" | "down") { - anyhow::bail!("--daemon-status must be ready, degraded, or down"); - } Ok(Self { command, store, runtime_id, daemon_id, - daemon_status, interval_seconds, max_iterations, - note, }) } } diff --git a/notes/conceptual-substitution-audit-2026-07-12.md b/notes/conceptual-substitution-audit-2026-07-12.md index 11ff5866..bb0c1053 100644 --- a/notes/conceptual-substitution-audit-2026-07-12.md +++ b/notes/conceptual-substitution-audit-2026-07-12.md @@ -420,3 +420,12 @@ matching runtime job, binding, role, authority scope, allowed operation, and path coverage. Patch, command, and commit receipts also require the matching approved Hands review. Missing grants, mismatched paths, and attempts to mutate under a read-only planning grant are negative-tested refusals. + +## Caller-selected daemon liveness + +`epiphany-cluster-daemon` accepted `--daemon-status ready|degraded|down` and +wrote that caller choice as the owning daemon's liveness. It also accepted an +unproven note for the status document. Both inputs are deleted. Reaching the +heartbeat write derives `ready`; command failure writes no heartbeat, while +degradation/down must come from timeout, failed restart, or supervisor +observation rather than a caller describing the desired dashboard color. diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index d69ee53e..fc589083 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -106,6 +106,9 @@ The confirmed conceptual substitutions have been cut: - Hands persistence resolves its grant rather than trusting an ID label. Grant identity/scope/operations/paths and approved review must match each intent and patch/command/commit consequence; grants are immutable. +- cluster-daemon heartbeat no longer accepts caller liveness or note fields. + A successful owning-body heartbeat derives `ready`; degraded/down require + observed supervisor or timeout evidence. The presentation boundary is now plain: `swarm overview` is a generic compact read-only projection. Gjallar is a downstream TUI application on Nightwing and is not an Epiphany organ, provider, owner, runtime, or architectural dependency. Eve/CultUI graphs may be lowered or composited downstream without Epiphany caring which presentation client does it. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 9ee869052d30b7d3c66d90432b29c9e46497fd3f..d6932cc370548a6e609ca45009ed680fdb3c4f8c 100644 GIT binary patch delta 300 zcmWlSF-yci5QR-Vx3RGd1Z7YVi!%x$$XQwma*dtcCOb)1_jbMA&4pAJ7M2zgQVR+; zf?#p~K$|P%{)zqqC&kA+-s8=izsBub{1FA~$A_b%ldG>4w*33t38q1?d*6l+Z5R;! zT_py@+Pn?f_D}cz%{B&o>FN154w7!MU{R#x3^h6jTno^~Bjgg5aNX7m+q_HQvdS`w z^GboKwbaFaYD5Dia_dv%9t3){6RD;1GUG}$P+RHIfkiHwQ_2g=1&RYfeOjm~m{!sv zcsW5+`61+7Diq{9PhW>%EV$|x?QA3+X_GqA+)JYq7-K|=h delta 57 zcmbQbLVEjB=?xN$+$QE$24+#m7}zdO*{sZ1$jGSLJe8?^Dib3RgJ@?Ngc9 Hlr8`O5>OGY diff --git a/state/map.yaml b/state/map.yaml index 4927a471..37ba00e8 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -660,4 +660,4 @@ current_status: - Service lifecycle receipt history is now event-only: `load_epiphany_cultmesh_daemon_service_lifecycle_receipts` filters out the `epiphany-local/daemon-service-lifecycle-receipt/latest` mirror, while `load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt` remains the latest-state reader. Focused unit test `service_lifecycle_receipt_history_excludes_latest_mirror` proves two per-receipt writes return exactly two history records and latest points at the second. Fresh smoke `verse-query-lifecycle-history-filter-smoke` and live overview/triage `local-20260618-145632-497-efac6f0d` / `local-20260618-145632-321-867947af` prove compact swarm sights still expose service lifecycle attention plus the present elevated runbook artifact without daemon pokes or service mutation. Do not use a broad unscoped cargo test filter for this check on Windows; it fans out across bin harnesses and hit a broken pipe during this pass. - `epiphany-verse-query seed-compact` is the compact seed receipt for wrappers and read-only rites. The older `seed` command still prints the full local Verse context for explicit debugging, but compact wrapper modes now avoid full `seed`/final `query` readback after the combined overview proof exposed Windows debug stack overflow from full-context serialization pressure. last_completed_repo_swarm_cut: Huginn live-fire has crossed the first real repo Body from Persona pressure to branch-local Hands commit and Soul/Mind closure, and now has repeatable closure and redacted-public-proof mouths. On `E:\Projects\Huginn` branch `epiphany/huginn/first-awakening`, `tools/epiphany_local_run.ps1 -Mode repo-persona-intake` accepted item `huginn-inspection-readback-livefire`, Weksa/Persona intake remained sealed, and `epiphany-work derive-plan` lowered it to model-authored safe family `repo.status_section` for `README.md` only. `tools/epiphany_local_run.ps1 -Mode repo-swarm-run` advanced four bounded pulses: run-from-plan, adopt-from-plan, execute-from-plan, and close-from-execute. Huginn commit `e9b07c38fceabbdc89ea35c2156326c80c0393a2` updated only `README.md`; closure receipt `.epiphany\work\work-close-huginn-inspection-readback-livefire.json` records status `closed`, Soul verdict `passed`, Mind state commit `repo-work-close-huginn-inspection-readback-livefire-mind-commit`, safe family `repo.status_section`, path scope `README.md`, Bifrost publication gate, and `privateStateExposed=false`. Verification also ran Huginn's TypeScript compiler through concrete Node path: `C:\Program Files\nodejs\node.exe E:\Projects\Huginn\node_modules\typescript\bin\tsc -p tsconfig.json` passed. Native verifier `epiphany-repo-livefire-closure-smoke --workspace E:\Projects\Huginn --item huginn-inspection-readback-livefire --expected-path README.md --expected-family repo.status_section --expected-gate awaiting-publication --expected-blocker bifrost-publication-missing` checks closure receipt, Mind map entry, overview gate/blocker, authority seals, and `git show` changed paths, returning `status=ok`, `soulVerdict=passed`, `publicationGate=Bifrost`, and `privateStateExposed=false`. Wrapper `tools/epiphany_local_run.ps1 -Mode repo-livefire-closure -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exposes the same read-only proof through the local operator mouth; artifact `local-20260621-190156-803-2f85ba15` printed commit, path, gate, blocker, Soul verdict, Mind commit receipt, and `privateStateExposed=False` without push, merge, publication, or target mutation. New wrapper `tools/epiphany_local_run.ps1 -Mode repo-work-public-proof -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exports the redacted proof bundle and repo-local Verse index without publishing; artifact `local-20260621-190645-345-4555b1dc` wrote `.epiphany\public\proof-bundles\repo-work-public-proof-huginn-inspection-readback-livefire.json`, proof id `repo-work-public-proof-huginn-inspection-readback-livefire`, SHA-256 `857545b199f3e37eb06c2e757e5cfc201958e46667bb1f8403fd333a22620f63`, nine artifact rows, zero publication rows, and `privateStateExposed=False`. swarm overview readback `local-20260621-190701-140-b9519ec6` sees the `REPO-WORK-PUBLIC-PROOF` row and action row from Huginn's repo-local Verse with the same SHA-256 while Bifrost publication remains missing. Launcher compact modes are now named compact operator-context modes instead of read-only modes, and `bifrost-public-proof` summaries print item, target public Verse, room, proof SHA-256, review receipts, and credit receipts so publication receipts are auditable without claiming upstream sync. - next_action: Continue the conceptual-substitution modeling pass beyond receipt writers. Publication and closure authority is single-sourced; Substrate Gate owns fixed grant policies; Hands intents and consequences now resolve immutable grants plus approved reviews and enforce identity/operation/path scope. Inspect daemon lifecycle writers next, then remaining projections/caches/adapters for substituted authority. + next_action: Continue the conceptual-substitution modeling pass beyond receipt writers. Publication/closure/Hands authority is single-sourced; successful cluster-daemon heartbeat now derives ready and cannot accept caller liveness prose. Continue auditing daemon-supervisor and verse-query lifecycle writers, especially fixture-only lifecycle receipts and any status that is not derived from an observed process/service consequence; then inspect remaining projections/caches/adapters.