From a60d0b27d5db4ceb96ff8d78e185132ffd3ceedb Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 21 Jun 2026 15:20:06 +0100 Subject: [PATCH] Add deployment handoff to repo swarm MVP gate --- .../bin/epiphany-repo-swarm-mvp-gate-smoke.rs | 48 ++++++++++++++++++ notes/fresh-workspace-handoff.md | 2 +- state/ledgers.msgpack | Bin 375987 -> 376337 bytes state/map.yaml | 2 +- tools/epiphany_local_run.ps1 | 4 ++ 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-repo-swarm-mvp-gate-smoke.rs b/epiphany-core/src/bin/epiphany-repo-swarm-mvp-gate-smoke.rs index e62514c5..ff20c321 100644 --- a/epiphany-core/src/bin/epiphany-repo-swarm-mvp-gate-smoke.rs +++ b/epiphany-core/src/bin/epiphany-repo-swarm-mvp-gate-smoke.rs @@ -23,6 +23,7 @@ struct Args { fresh_repo_summary: Option, readiness_summary: Option, bifrost_accounting_summary: Option, + deployment_handoff_summary: Option, daemon_survival_summary: Option, } @@ -33,6 +34,7 @@ impl Args { let mut fresh_repo_summary = None; let mut readiness_summary = None; let mut bifrost_accounting_summary = None; + let mut deployment_handoff_summary = None; let mut daemon_survival_summary = None; let mut args = env::args().skip(1).peekable(); while let Some(arg) = args.next() { @@ -49,6 +51,10 @@ impl Args { bifrost_accounting_summary = Some(take_path(&mut args, "--bifrost-accounting-summary")?) } + "--deployment-handoff-summary" => { + deployment_handoff_summary = + Some(take_path(&mut args, "--deployment-handoff-summary")?) + } "--daemon-survival-summary" => { daemon_survival_summary = Some(take_path(&mut args, "--daemon-survival-summary")?) @@ -62,6 +68,7 @@ impl Args { fresh_repo_summary, readiness_summary, bifrost_accounting_summary, + deployment_handoff_summary, daemon_survival_summary, }) } @@ -99,6 +106,9 @@ fn run_smoke(args: Args) -> Result { let bifrost_accounting_summary = args .bifrost_accounting_summary .unwrap_or_else(|| latest_summary(&args.smoke_root, "repo-bifrost-accounting-bundle-")); + let deployment_handoff_summary = args + .deployment_handoff_summary + .unwrap_or_else(|| latest_summary(&args.smoke_root, "repo-deployment-config-family-")); let daemon_survival_summary = args .daemon_survival_summary .unwrap_or_else(|| latest_summary(&args.smoke_root, "daemon-survival-rehearsal-")); @@ -106,11 +116,13 @@ fn run_smoke(args: Args) -> Result { let fresh = read_json(&fresh_repo_summary)?; let readiness = read_json(&readiness_summary)?; let bifrost = read_json(&bifrost_accounting_summary)?; + let deployment_handoff = read_json(&deployment_handoff_summary)?; let daemon_survival = read_json(&daemon_survival_summary)?; verify_fresh_repo(&fresh)?; verify_readiness(&readiness)?; verify_bifrost_accounting(&bifrost)?; + verify_deployment_handoff(&deployment_handoff)?; verify_daemon_survival(&daemon_survival)?; let gate_rows = vec![ @@ -161,6 +173,11 @@ fn run_smoke(args: Args) -> Result { "Bifrost", "readiness, artifact acceptance, and metrics accounting rows are closed", ), + green( + "idunn-deployment-handoff", + "Idunn", + "deployment config, operator runbook, and aftercare receipt readback are sealed", + ), green( "long-running-daemon-proof", "Idunn", @@ -204,10 +221,12 @@ fn run_smoke(args: Args) -> Result { "freshRepoSummary": fresh_repo_summary, "readinessSummary": readiness_summary, "bifrostAccountingSummary": bifrost_accounting_summary, + "deploymentHandoffSummary": deployment_handoff_summary, "daemonSurvivalSummary": daemon_survival_summary, "freshRepoSmokeDir": fresh["smokeDir"], "readinessSmokeDir": readiness["smokeDir"], "bifrostAccountingSmokeDir": bifrost["smokeDir"], + "deploymentHandoffSmokeDir": deployment_handoff["smokeDir"], "daemonSurvivalSmokeDir": daemon_survival["smokeDir"], "mvpReady": false, "demoReady": true, @@ -332,6 +351,35 @@ fn verify_daemon_survival(value: &Value) -> Result<()> { require_bool(value, &["privateStateExposed"], false) } +fn verify_deployment_handoff(value: &Value) -> Result<()> { + require_eq( + value, + &["schemaVersion"], + "epiphany.repo_deployment_config_family_smoke.v0", + )?; + require_eq(value, &["status"], "ok")?; + require_bool(value, &["deploymentConfigEnabled"], false)?; + require_eq( + value, + &["deploymentConfigAuditStatus"], + "ready-for-idunn-review", + )?; + require_bool(value, &["readyForIdunnReview"], true)?; + require_eq( + value, + &["deploymentExecutionRunbookStatus"], + "ready-for-operator-git-push", + )?; + require_eq(value, &["deploymentAftercareAuditStatus"], "complete")?; + require_bool(value, &["deploymentComplete"], true)?; + require_eq(value, &["idunnDeploymentReceiptSource"], "cultmesh")?; + require_eq(value, &["idunnAftercareAuditReceiptSource"], "cultmesh")?; + require_eq(value, &["deploymentTrigger"], "git-push-observed-by-idunn")?; + require_eq(value, &["deploymentOwner"], "Idunn")?; + require_bool(value, &["deploymentAuthority"], false)?; + require_bool(value, &["privateStateExposed"], false) +} + fn green(gate: &str, owner: &str, evidence: &str) -> Value { json!({ "gate": gate, diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 1938c782..4b797a2e 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -194,7 +194,7 @@ remembers doctrine; the branch remembers the blade. - `bifrost-publication` is the compact non-mutating Bifrost publication proof; use it to prove body-change routing, credit, and GitHub publication receipt state without performing GitHub mutation. Its JSON now points back to compact swarm overview and tool-directory readback. - `bifrost-artifact-acceptance` and `bifrost-metrics` are compact Bifrost/Maintainer closure rites for the safe-family planning/accounting lanes. They write typed accepted-artifact and metrics receipts from explicit artifact/public-proof/review/model-spend/review-load/credit refs, verify latest receipt readback, and let `bifrost-ledger` close `artifact-acceptance-request` and `metrics-request` rows from Bifrost-owned receipts instead of request cargo. The request-family smokes now prove both states: `.epiphany-smoke\repo-artifact-acceptance-request-family-20260621-130520` and `.epiphany-smoke\repo-metrics-request-family-20260621-130635` first assert open request rows, then write final receipts and assert closed rows; wrapper proof `local-20260621-140740-750-2815f6f7` read the closed metrics row with `privateStateExposed=False`. `epiphany-repo-bifrost-accounting-bundle-smoke` consumes the closed family summaries and emits one operator-safe aggregate receipt; wrapper mode `tools/epiphany_local_run.ps1 -Mode bifrost-accounting-bundle` now builds/runs that verifier, accepts optional exact summary paths, writes normal operator run receipts, and proved bundle `.epiphany-smoke\repo-bifrost-accounting-bundle-20260621-132815` via wrapper artifact `local-20260621-142716-268-d6bc58b4` with final Bifrost receipt ids, `planningAuthorityOnly=true`, and `privateStateExposed=false`. - `daemon-survival-rehearsal` is the bounded Idunn physiology proof. `epiphany-daemon-survival-rehearsal-smoke` writes a durable restart policy for `epiphany-daemon-self`, runs `epiphany-daemon-supervisor serve --max-iterations 2 --force --loop-interval-seconds 0`, verifies two scheduler pulses and the scheduler receipt row, and keeps service-manager mutation/elevation/private-state exposure false. Wrapper proof `tools/epiphany_local_run.ps1 -Mode daemon-survival-rehearsal -SkipBuild` emitted `.epiphany-smoke\daemon-survival-rehearsal-20260621-135723` via artifact `local-20260621-145723-011-1175e273`. -- `repo-swarm-mvp-gate` is the compact aggregate MVP proof rite. `epiphany-repo-swarm-mvp-gate-smoke` consumes the latest fresh-repo MVP, repo-work readiness, Bifrost accounting-bundle, and daemon survival summaries, verifies the green proof rows, and leaves only Idunn elevated service execution as an explicit warning gate instead of laundering it into completion. Wrapper mode `tools/epiphany_local_run.ps1 -Mode repo-swarm-mvp-gate` proved `.epiphany-smoke\repo-swarm-mvp-gate-20260621-135754` via wrapper artifact `local-20260621-145752-946-d1d4d118`: `demoReady=True`, `mvpReady=False`, `green=12`, `warnings=1`, `blockers=0`, and `privateStateExposed=False`. +- `repo-swarm-mvp-gate` is the compact aggregate MVP proof rite. `epiphany-repo-swarm-mvp-gate-smoke` consumes the latest fresh-repo MVP, repo-work readiness, Bifrost accounting-bundle, Idunn deployment handoff, and daemon survival summaries, verifies the green proof rows, and leaves only Idunn elevated service/install/start/remote execution as an explicit warning gate instead of laundering it into completion. Wrapper mode `tools/epiphany_local_run.ps1 -Mode repo-swarm-mvp-gate -RepoSwarmMvpDeploymentHandoffSummaryPath .\.epiphany-smoke\repo-deployment-config-family-20260621-141231\summary.json` proved `.epiphany-smoke\repo-swarm-mvp-gate-20260621-141554` via wrapper artifact `local-20260621-151512-514-a0c77e3f`: `demoReady=True`, `mvpReady=False`, `green=13`, `warnings=1`, `blockers=0`, and `privateStateExposed=False`. This is live-fire ready for a controlled repo Body; unattended/elevated production service or deployment execution remains an operator-granted Idunn rite. - `bifrost-ledger` is the compact Bifrost/Imagination readback rite; use it after collaboration, publication, accepted-artifact, or metrics writes to see the latest body-change, public-proof, accepted-artifact, metrics, GitHub, feedback, consensus, credit/review-count, and accounting closure rows without opening the full local Verse. - `tool-directory` is the non-mutating daemon tool sight rite; it shows which globally available daemon-hosted tools any agent can invoke through typed intents and receipts, while still exposing host readiness. - `tool-invoke` now embeds compact readbacks for common daemon-hosted tools. Status calls return `daemonStatusReadback`, Eve calls return `eveConnectionReadback`, Self `service-health` returns Idunn-owned `serviceHealthReadback`, Self `service-policy-directory` returns Idunn-owned `servicePolicyDirectoryReadback`, Self `swarm-online-runbook` returns Idunn-owned `swarmOnlineRunbookReadback`, and Hands/Soul authority tools return `authorityToolReadback` with gate, input contract, receipt contract, intent/receipt routes, host cluster, and private-state seal. This proves global tool ergonomics without moving action, verification, or daemon lifecycle ownership into the wrapper; live proofs routed Persona to Hands `repo-action` (`local-20260619-021628-143-7bf7f2e0`), Soul `verify` (`local-20260619-021701-458-852cfa6f`), Self `swarm-online-runbook` (`local-20260619-032244-273-acb3c6a4`), and Self `service-policy-directory` (`local-20260619-035238-138-633f3ff0`) with `privateStateExposed=false`. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 69b8e0288d2dd65618ea126e92e1830e0f1d9452..037d248beb12c66041b626eb71978c936e4457c2 100644 GIT binary patch delta 303 zcmXwzJxc>Y5Qe?PtE{vLiWmkg&3U(%FOrbL(n1gs3oF;V$z^eG_uSpfM=2?64H{Bg z*b6DdVC~Pb7cAU>7SBxazRWy}@6zpfIIumHxMYX~0p&S;Pz=$AOiK|3oyZ0gKRQLL17t aZ>KW8Jt3_)jxfp%lLBaN`cg47KKunU=4mJZ delta 53 zcmbREM{M&?u?-T8+y(|#CKgf07+7~t*sRQ0$jI2#Je8?^Dib3RgJ@