From 74cd4234c4f5f5be18edd953280767d08d1ea4ea Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 21 Jun 2026 12:09:23 +0100 Subject: [PATCH] Validate upstream sync readiness --- .../bin/epiphany-repo-work-readiness-smoke.rs | 65 ++++++- epiphany-core/src/bin/epiphany-work.rs | 159 ++++++++++++++++-- notes/epiphany-repo-swarm-mvp-contract.md | 26 +-- notes/fresh-workspace-handoff.md | 2 +- state/ledgers.msgpack | Bin 370168 -> 370523 bytes state/map.yaml | 4 +- 6 files changed, 228 insertions(+), 28 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-repo-work-readiness-smoke.rs b/epiphany-core/src/bin/epiphany-repo-work-readiness-smoke.rs index 9a6b48c8..efce810c 100644 --- a/epiphany-core/src/bin/epiphany-repo-work-readiness-smoke.rs +++ b/epiphany-core/src/bin/epiphany-repo-work-readiness-smoke.rs @@ -84,6 +84,7 @@ fn run_smoke(args: Args) -> Result { let item = "repo-work-readiness"; let local_verse = repo.join(".epiphany").join("local-verse.ccmp"); + let work_dir = repo.join(".epiphany").join("work"); cargo_json( &manifest, "epiphany-repo", @@ -212,7 +213,7 @@ fn run_smoke(args: Args) -> Result { .join(".epiphany") .join("work") .join(format!("work-close-{item}.json")); - cargo_json( + let publish = cargo_json( &manifest, "epiphany-work", &[ @@ -223,6 +224,8 @@ fn run_smoke(args: Args) -> Result { path_str(&root)?, "--item", item, + "--artifact-dir", + path_str(&work_dir)?, "--closure-receipt", path_str(&close_receipt)?, "--local-verse-store", @@ -250,6 +253,30 @@ fn run_smoke(args: Args) -> Result { ], &root, )?; + git(["branch", "-f", "main", "HEAD"], &repo)?; + let sync = cargo_json( + &manifest, + "epiphany-work", + &[ + "sync", + "--workspace", + path_str(&repo)?, + "--item", + item, + "--publish-receipt", + publish + .get("receiptPath") + .and_then(Value::as_str) + .ok_or_else(|| anyhow!("publish result missing receiptPath"))?, + "--artifact-dir", + path_str(&work_dir)?, + "--upstream-ref", + "main", + "--merge-receipt", + "maintainer-merge:repo-work-readiness-smoke", + ], + &root, + )?; let deployment_aftercare_fixture = repo .join(".epiphany") .join("work") @@ -326,8 +353,8 @@ fn run_smoke(args: Args) -> Result { &["schemaVersion"], "epiphany.repo_work_readiness.v0", )?; - require_eq(&readiness, &["status"], "not-ready")?; - require_u64(&readiness, &["missingRequiredCount"], 1)?; + require_eq(&readiness, &["status"], "ready")?; + require_u64(&readiness, &["missingRequiredCount"], 0)?; require_bool(&readiness, &["authority", "sightOnly"], true)?; require_bool( &readiness, @@ -377,7 +404,15 @@ fn run_smoke(args: Args) -> Result { require_row(&readiness, "bifrost-publication", true)?; require_row_field_u64(&readiness, "bifrost-publication", "creditReceiptCount", 1)?; require_row_field_u64(&readiness, "bifrost-publication", "changedPathCount", 1)?; - require_row(&readiness, "upstream-main-sync", false)?; + require_row(&readiness, "upstream-main-sync", true)?; + require_row_field_u64(&readiness, "upstream-main-sync", "mergeReceiptCount", 1)?; + require_row_field_bool(&readiness, "upstream-main-sync", "ancestryProved", true)?; + require_row_field_bool( + &readiness, + "upstream-main-sync", + "publishReceiptMatches", + true, + )?; require_row(&readiness, "idunn-lifecycle", true)?; require_row(&readiness, "deployment-aftercare", true)?; require_row(&readiness, "tool-directory", true)?; @@ -417,6 +452,9 @@ fn run_smoke(args: Args) -> Result { "branch": git_output(["branch", "--show-current"], &repo)?, "item": item, "publicProofOutput": public_proof["outputPath"], + "publishStatus": publish["status"], + "syncStatus": sync["status"], + "upstreamMainSynced": sync["authority"]["upstreamMainSynced"], "readinessStatus": readiness["status"], "missingRequiredCount": readiness["missingRequiredCount"], "readinessVerseProjection": readiness["verseProjection"], @@ -599,6 +637,25 @@ fn require_row_field_u64(value: &Value, kind: &str, field: &str, expected: u64) } } +fn require_row_field_bool(value: &Value, kind: &str, field: &str, expected: bool) -> Result<()> { + let rows = value + .get("rows") + .and_then(Value::as_array) + .ok_or_else(|| anyhow!("readiness output did not include rows"))?; + let row = rows + .iter() + .find(|row| row.get("kind").and_then(Value::as_str) == Some(kind)) + .ok_or_else(|| anyhow!("missing readiness row {kind:?}"))?; + let actual = row.get(field).and_then(Value::as_bool).unwrap_or(!expected); + if actual == expected { + Ok(()) + } else { + Err(anyhow!( + "expected readiness row {kind:?} field {field:?} to be {expected}, got {actual}" + )) + } +} + fn require_tui_row_contains(value: &Value, path: &[&str], needle: &str) -> Result<()> { let rows = path .iter() diff --git a/epiphany-core/src/bin/epiphany-work.rs b/epiphany-core/src/bin/epiphany-work.rs index a9e64e64..d560921a 100644 --- a/epiphany-core/src/bin/epiphany-work.rs +++ b/epiphany-core/src/bin/epiphany-work.rs @@ -12076,10 +12076,6 @@ fn run_readiness(args: ReadinessArgs) -> Result { .is_some(); let publish_receipt = read_json_if_exists(&publish_receipt_path)?; let sync_receipt = read_json_if_exists(&sync_receipt_path)?; - let upstream_synced = sync_receipt - .as_ref() - .and_then(sync_receipt_upstream_main_synced) - .unwrap_or(false); let mut rows = vec![ readiness_path_row( @@ -12156,13 +12152,11 @@ fn run_readiness(args: ReadinessArgs) -> Result { "Redacted public proof bundle exists.", )?, bifrost_publication_readiness_row(&publish_receipt_path, publish_receipt.as_ref())?, - readiness_path_row( - "upstream-main-sync", - "Bifrost/GitHub", - "epiphany.repo_work_sync.v0", + upstream_main_sync_readiness_row( + &workspace, &sync_receipt_path, - upstream_synced, - "Published commit is contained by upstream main.", + sync_receipt.as_ref(), + publish_receipt.as_ref(), )?, ]; let default_idunn_lifecycle_receipt = artifact_dir.join("repo-work-service-audit.json"); @@ -14314,6 +14308,151 @@ fn bifrost_publication_readiness_row(path: &Path, receipt: Option<&Value>) -> Re })) } +fn upstream_main_sync_readiness_row( + workspace: &Path, + path: &Path, + receipt: Option<&Value>, + publish_receipt: Option<&Value>, +) -> Result { + let Some(receipt) = receipt else { + return Ok(readiness_missing_row( + "upstream-main-sync", + "Bifrost/GitHub", + "epiphany.repo_work_sync_receipt.v0 + git merge-base ancestry proof", + "Run epiphany-work sync after maintainer/Bifrost merge authority so upstream main containment is proved.", + )); + }; + + let schema_ok = string_from_json(receipt, &["schemaVersion"]).as_deref() + == Some("epiphany.repo_work_sync_receipt.v0"); + let status_synced = + string_from_json(receipt, &["status"]).as_deref() == Some("upstream-main-synced"); + let upstream_main_synced = + bool_from_json(receipt, &["authority", "upstreamMainSynced"]) == Some(true) + || bool_from_json(receipt, &["upstreamMainSynced"]) == Some(true); + let publication_authorized = + bool_from_json(receipt, &["authority", "publicationAuthorized"]) == Some(true); + let merge_authorized = bool_from_json(receipt, &["authority", "mergeAuthorized"]) == Some(true); + let private_sealed = bool_from_json(receipt, &["authority", "privateStateExposed"]) + == Some(false) + && bool_from_json(receipt, &["privateStateExposed"]).unwrap_or(false) == false; + let upstream_ref = string_from_json(receipt, &["upstreamRef"]); + let upstream_commit_sha = string_from_json(receipt, &["upstreamCommitSha"]); + let published_commit_sha = string_from_json(receipt, &["publishedCommitSha"]); + let merge_receipt_count = receipt + .get("mergeReceipts") + .and_then(Value::as_array) + .map(Vec::len) + .unwrap_or(0); + let commit_receipt_id = string_from_json(receipt, &["handsReceipts", "commitReceiptId"]); + let pr_receipt_id = string_from_json(receipt, &["handsReceipts", "prReceiptId"]); + let bifrost_publication_receipt_id = + string_from_json(receipt, &["bifrost", "publicationReceiptId"]); + let github_publication_receipt_id = + string_from_json(receipt, &["bifrost", "githubPublicationReceiptId"]); + let ledger_entry_id = string_from_json(receipt, &["bifrost", "ledgerEntryId"]); + + let mut upstream_ref_resolved = false; + let mut upstream_ref_matches_receipt = false; + let mut published_commit_resolved = false; + let mut ancestry_proved = false; + if let (Some(upstream_ref), Some(upstream_commit_sha), Some(published_commit_sha)) = ( + upstream_ref.as_ref(), + upstream_commit_sha.as_ref(), + published_commit_sha.as_ref(), + ) { + let resolved_upstream = git_output(workspace, &["rev-parse", "--verify", upstream_ref]); + if let Ok(resolved) = resolved_upstream { + upstream_ref_resolved = true; + upstream_ref_matches_receipt = resolved == *upstream_commit_sha; + } + published_commit_resolved = + git_status_success(workspace, &["cat-file", "-e", published_commit_sha])?; + ancestry_proved = git_status_success( + workspace, + &[ + "merge-base", + "--is-ancestor", + published_commit_sha, + upstream_ref, + ], + )?; + } + + let publish_receipt_matches = publish_receipt.is_some_and(|publish| { + string_from_json(publish, &["handsReceipts", "commitSha"]) == published_commit_sha + && string_from_json(publish, &["handsReceipts", "commitReceiptId"]) == commit_receipt_id + && string_from_json(publish, &["handsReceipts", "prReceiptId"]) == pr_receipt_id + && string_from_json(publish, &["bifrost", "publicationReceiptId"]) + == bifrost_publication_receipt_id + && string_from_json(publish, &["bifrost", "githubPublicationReceiptId"]) + == github_publication_receipt_id + && string_from_json(publish, &["bifrost", "ledgerEntryId"]) == ledger_entry_id + }); + + let satisfied = schema_ok + && status_synced + && upstream_main_synced + && publication_authorized + && merge_authorized + && private_sealed + && merge_receipt_count > 0 + && upstream_ref_resolved + && upstream_ref_matches_receipt + && published_commit_resolved + && ancestry_proved + && publish_receipt_matches + && commit_receipt_id + .as_ref() + .is_some_and(|id| !id.trim().is_empty()) + && pr_receipt_id + .as_ref() + .is_some_and(|id| !id.trim().is_empty()) + && bifrost_publication_receipt_id + .as_ref() + .is_some_and(|id| !id.trim().is_empty()) + && github_publication_receipt_id + .as_ref() + .is_some_and(|id| !id.trim().is_empty()) + && ledger_entry_id + .as_ref() + .is_some_and(|id| !id.trim().is_empty()); + + Ok(json!({ + "kind": "upstream-main-sync", + "owner": "Bifrost/GitHub", + "requiredSchema": "epiphany.repo_work_sync_receipt.v0 + git merge-base ancestry proof", + "evidenceRef": existing_path_value(path), + "artifactStatus": if path.exists() { "present" } else { "missing" }, + "schemaVersion": string_from_json(receipt, &["schemaVersion"]).unwrap_or_else(|| "missing".to_string()), + "documentStatus": string_from_json(receipt, &["status"]).unwrap_or_else(|| "missing".to_string()), + "upstreamRef": upstream_ref.unwrap_or_else(|| "missing".to_string()), + "upstreamCommitSha": upstream_commit_sha.unwrap_or_else(|| "missing".to_string()), + "publishedCommitSha": published_commit_sha.unwrap_or_else(|| "missing".to_string()), + "mergeReceiptCount": merge_receipt_count, + "commitReceiptId": commit_receipt_id.unwrap_or_else(|| "missing".to_string()), + "prReceiptId": pr_receipt_id.unwrap_or_else(|| "missing".to_string()), + "bifrostPublicationReceiptId": bifrost_publication_receipt_id.unwrap_or_else(|| "missing".to_string()), + "githubPublicationReceiptId": github_publication_receipt_id.unwrap_or_else(|| "missing".to_string()), + "ledgerEntryId": ledger_entry_id.unwrap_or_else(|| "missing".to_string()), + "upstreamMainSynced": upstream_main_synced, + "publicationAuthorized": publication_authorized, + "mergeAuthorized": merge_authorized, + "upstreamRefResolved": upstream_ref_resolved, + "upstreamRefMatchesReceipt": upstream_ref_matches_receipt, + "publishedCommitResolved": published_commit_resolved, + "ancestryProved": ancestry_proved, + "publishReceiptMatches": publish_receipt_matches, + "privateStateExposed": !private_sealed, + "satisfied": satisfied, + "status": if satisfied { "satisfied" } else { "missing" }, + "note": "Sync receipt proves the published commit is contained by the named upstream ref after maintainer/Bifrost merge authority.", + "readinessApprovalAuthorized": false, + "serviceLifecycleAuthority": false, + "handsActionAuthorized": false + })) +} + fn idunn_lifecycle_readiness_row(path: &Path) -> Result { let document = read_json_if_exists(path)?; let schema_version = document diff --git a/notes/epiphany-repo-swarm-mvp-contract.md b/notes/epiphany-repo-swarm-mvp-contract.md index fc79575d..c99676dd 100644 --- a/notes/epiphany-repo-swarm-mvp-contract.md +++ b/notes/epiphany-repo-swarm-mvp-contract.md @@ -1646,16 +1646,20 @@ CultMesh `gamecult.bifrost.body_change_publication_receipt.v0` and `gamecult.bifrost.github_publication_receipt.v0` rows, requiring matching Bifrost/GitHub receipt ids, ledger id, Hands PR receipt id, PR URL, nonempty credit and changed-path evidence, no upstream-main sync claim, no merge claim, -and no private-state exposure. Native smoke -`.epiphany-smoke\repo-work-readiness-20260621-104757` now reports `not-ready` -with only one missing row, `upstream-main-sync`; writes readiness id -`repo-work-readiness-repo-work-readiness`; and Gjallar reports -`repoWorkReadinessCount=1` without private-state exposure. Wrapper proof -`local-20260621-115019-563-f4cec9fa` prints the same one-gap readiness mouth. -This is still sight only: Bifrost/GitHub keep publication ownership, Idunn -keeps lifecycle ownership, Odin/Gjallar keep discovery/sight, and no readiness -approval, publication, sync, service mutation, Hands action, or private-state -authority is granted. +and no private-state exposure. The `upstream-main-sync` row now validates +`epiphany.repo_work_sync_receipt.v0` plus live `git merge-base --is-ancestor` +proof, requiring the published commit, upstream ref, upstream commit, nonempty +merge/sync authority receipts, Hands PR/commit ids, Bifrost/GitHub publication +ids, ledger id, and matching publish receipt. Native smoke +`.epiphany-smoke\repo-work-readiness-20260621-110524` now reports `ready` with +`missingRequiredCount=0`, `syncStatus=upstream-main-synced`, +`upstreamMainSynced=true`, readiness id `repo-work-readiness-repo-work-readiness`, +and Gjallar `repoWorkReadinessCount=1` without private-state exposure. Wrapper +proof `local-20260621-120641-609-72d32f64` prints the same no-gap readiness +mouth. This is still sight only: Bifrost/GitHub keep publication/sync ownership, +Idunn keeps lifecycle ownership, Odin/Gjallar keep discovery/sight, and no +readiness approval, publication, sync, service mutation, Hands action, or +private-state authority is granted. Bifrost public-proof publication transport is now the closure after local proof sight. `epiphany-verse-query bifrost-public-proof --public-proof-id @@ -1913,7 +1917,7 @@ temptation wearing clean robes. | Self scheduling | `tick` and `serve` prove one-step branch-local advancement, brake refusal, active-turn refusal, cooldown, and stale-turn recovery; `tick` now routes executed branch-local work through the existing Soul/Modeling/Mind `close` gate; `queue-run` selects tick-actionable rows from the typed repo-work queue and delegates to `tick`; `epiphany-swarm run` is the bounded operator mouth over that queue/tick physiology; `repo-work-service-plan`, `repo-work-service-runbook`, `repo-work-service-launch`, and `repo-work-service-audit` write Idunn lifecycle receipts/artifacts for the same queue-run command and prove non-mutating launch/readiness closure. | Keep any future queue-run service install/start mutation behind Idunn and explicit elevated operator authority. | | Branch-local Hands work | `adopt` and `execute` create approved Hands gates, run planned commands, stage declared paths, commit on `epiphany/*`, and write receipts. | Keep mutation branch-contained and receipt-backed; broaden only through typed plan families, not ad hoc shell freedom. | | Soul/Modeling/Mind closure | `close` verifies the Hands commit, writes `epiphany.repo_work_closure_review.v0`, refuses path-scope mismatches, refuses missing/tampered/non-affirmative Mind adoption proof, runs known safe-family content assertions, optionally gates on model-authored closure verdicts, can require verification output to cite declared changed paths with `--require-source-grounding`, writes Soul/Modeling/Mind receipts, admits a compact typed repo map entry into `.epiphany/state/repo-work-map.msgpack`, and mirrors that admitted fact into local Verse as `epiphany.cultmesh.repo_work_map_entry.v0`. | Keep extending closure toward source-grounded semantic review and richer semantic map lenses, while preserving deterministic local closure for simple mechanical work. | -| Repo work sight | `overview` emits compact proof rows, an `epiphany.repo_work_intake_consensus_readback.v0` from the accept/plan chain, and typed `epiphany.cultmesh.repo_work_overview.v0` event documents plus a latest key; `readiness` now emits `epiphany.repo_work_readiness_report.v0` and mirrors `epiphany.cultmesh.repo_work_readiness.v0` over the MVP proof rows, including Soul's safe-family planning matrix readback, Idunn repo-work service audit validation, Odin/Gjallar tool-directory validation, and Bifrost/GitHub publication receipt-chain validation while naming upstream-main sync as the remaining readiness gap without approving readiness; the CultMesh TUI rows include compact `CONSENSUS` and `REPO-WORK-READINESS` readbacks showing Persona/public feedback ids, Imagination consensus route, public/candidate ref counts, safe family, readiness gaps, and authority denials without private payloads; `close` mirrors Mind-admitted map facts as `epiphany.cultmesh.repo_work_map_entry.v0`; Gjallar enumerates overview history, readiness rows, map rows, semantic rows, closure rows, family lens rows, path lens rows, branch lens rows, stage lens rows, gate lens rows, and public-proof rows without private-state exposure; Persona's Eve surface and Eve connection readbacks expose peer-readable gate/blocker/next-action rows; `queue-run` consumes the same overview queue for branch-local scheduler pulses. | Deepen Bifrost-first external work accounting and semantic map readback without moving action authority out of Hands/Self/Bifrost. | +| Repo work sight | `overview` emits compact proof rows, an `epiphany.repo_work_intake_consensus_readback.v0` from the accept/plan chain, and typed `epiphany.cultmesh.repo_work_overview.v0` event documents plus a latest key; `readiness` now emits `epiphany.repo_work_readiness_report.v0` and mirrors `epiphany.cultmesh.repo_work_readiness.v0` over the MVP proof rows, including Soul's safe-family planning matrix readback, Idunn repo-work service audit validation, Odin/Gjallar tool-directory validation, Bifrost/GitHub publication receipt-chain validation, and upstream-main sync receipt plus git ancestry validation while still granting no readiness approval; the CultMesh TUI rows include compact `CONSENSUS` and `REPO-WORK-READINESS` readbacks showing Persona/public feedback ids, Imagination consensus route, public/candidate ref counts, safe family, readiness gaps, and authority denials without private payloads; `close` mirrors Mind-admitted map facts as `epiphany.cultmesh.repo_work_map_entry.v0`; Gjallar enumerates overview history, readiness rows, map rows, semantic rows, closure rows, family lens rows, path lens rows, branch lens rows, stage lens rows, gate lens rows, and public-proof rows without private-state exposure; Persona's Eve surface and Eve connection readbacks expose peer-readable gate/blocker/next-action rows; `queue-run` consumes the same overview queue for branch-local scheduler pulses. | Deepen Bifrost-first external work accounting and semantic map readback without moving action authority out of Hands/Self/Bifrost. | | Publication | `publish` routes Bifrost/GitHub receipts from closure or explicit Soul/Mind refs. | Keep publication Bifrost-owned; do not let scheduler publish. | | Upstream main sync | `sync` proves the published commit is contained by upstream main after explicit merge/sync authority. | Treat upstream-main sync as a required final proof for published work. | | Daemon survival | Idunn service lifecycle receipts and runbooks exist outside repo-work tick authority. | Preserve Idunn as lifecycle owner; repo swarm may request or inspect service state, not impersonate daemon keeping. | diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index f2ba6278..30a92028 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -171,7 +171,7 @@ remembers doctrine; the branch remembers the blade. - 2026-06-21: Idunn-hosted repo-work queue-run lifecycle now has audit/readiness closure. `epiphany-daemon-supervisor repo-work-service-audit` reads the typed service lifecycle receipts for `epiphany-repo-work-queue-runner`, requires planned install-plan, written local runbook artifact, completed launch with exit code `0`, and no private-state exposure, then writes a `repo-work-service-audit` receipt. Native smoke `.epiphany-smoke\repo-work-service-lifecycle-20260621-004202` proves plan/runbook/launch/audit with `auditStatus=complete`, `auditRunbookArtifactStatus=present`, `auditLaunchExitCode=0`, `mutatesServiceManager=false`, `requiresElevatedAuthority=false`, and `privateStateExposed=false`. Wrapper proofs `local-20260621-014302-362-31bbef47`, `local-20260621-014337-108-cbd99615`, `local-20260621-014413-125-09e183c5`, and `local-20260621-014558-197-f6951806` prove plan/runbook/launch/audit ergonomics; the final audit summary reports `missing=none`, `failed=none`, and `nextSafeMove=continue repo-swarm MVP planner/interpreter hardening`. Remaining Idunn service work is optional elevated install/start execution under explicit operator authority, not Self scheduling. - 2026-06-21: Repo-work MVP readiness sight now has a first-class local wrapper. `tools/epiphany_local_run.ps1 -Mode repo-work-readiness -Workspace -RepoWorkItem ` invokes `epiphany-work readiness`, accepts optional `-RepoWorkPublicProof`, `-RepoWorkIdunnLifecycleReceipt`, `-RepoWorkDeploymentAftercareReceipt`, `-RepoWorkDeploymentAftercareReceiptRef`, and `-RepoWorkToolDirectoryReceipt`, and prints satisfied/missing readiness rows plus authority denials. It writes readiness sight only: no readiness approval, publication, service lifecycle, Hands action, deployment, cross-body mutation, or private-state exposure. Wrapper proof `local-20260621-111351-678-c3f7c714` against `.epiphany-smoke\repo-work-readiness-20260621-101053\repo-body` reported `status=not-ready`, missing `bifrost-publication`, `upstream-main-sync`, `idunn-lifecycle`, and `tool-directory`, while `deployment-aftercare` was satisfied and all authority booleans stayed false. `gjallar`/`swarm-overview` and `swarm-triage` wrapper summaries forward Rust-owned `repoWorkReadinessTuiRows`; earlier proof `local-20260621-105450-620-0fc13242` printed the compact `REPO-WORK-READINESS` row through Gjallar. - 2026-06-21: Repo deployment handoff/readback now has first-class local wrappers. `tools/epiphany_local_run.ps1 -Mode repo-deployment-config-audit`, `-Mode repo-deployment-runbook`, and `-Mode repo-deployment-aftercare-audit` invoke the existing Rust `epiphany-work` deployment audit, operator runbook, and aftercare audit surfaces, adding compact summaries for Idunn readiness, the exact operator `git push` route, runbook SHA-256, CultMesh receipt refs, and authority denials. Wrapper proofs `local-20260621-110141-130-fa8f91d7`, `local-20260621-110200-679-a03614ce`, and `local-20260621-110219-492-c870e2da` against `.epiphany-smoke\repo-deployment-config-family-20260620-223203\repo-body` reported `ready-for-idunn-review`, `ready-for-operator-git-push`, and complete Idunn aftercare with deployment/git-push/service/Hands/private-state authority false. These wrappers do not SSH, deploy, or run `git push`; they are the operator/Idunn handoff and aftercare sight rite. -- 2026-06-21: Repo-work readiness now includes the family-friendly safe-family planning depth row, receipt-shaped Idunn/tool-directory validation, and Bifrost/GitHub publication receipt-chain validation. `epiphany-work readiness` inspects `closureReview.familyAssertions.safeFamilyPlanning` from the close receipt and satisfies `safe-family-planning` only for Soul-owned `epiphany.repo_work_safe_family_planning_readback.v0` over `repo.planning_brief` with all expected candidate families, requirements, gates, matrix groups, matrix controls, closure proofs, authority denials, and private-state seal intact. It satisfies `idunn-lifecycle` only from `epiphany.repo_work_service_audit.v0` with complete Idunn-owned repo-work service proof, zero missing/failed checks, no service-manager mutation, no elevation requirement, and private-state seal; satisfies `tool-directory` only from `epiphany.cultmesh.daemon_tool_directory.v0` with nonempty globally available receipt-gated daemon tools, ready hosts, invoke command hints, and private-state seal; and satisfies `bifrost-publication` only when the local publish artifact matches the latest repo-local CultMesh Bifrost body-change and GitHub publication receipts, including ledger id, Hands PR id, PR URL, credit rows, changed paths, no upstream-main sync claim, no merge claim, and no private-state exposure. Native smoke `.epiphany-smoke\repo-work-readiness-20260621-104757` now runs the readiness proof through `repo-planning-brief` cargo, sealed Idunn/tool artifacts, and a real `epiphany-work publish`, proving `safe-family-planning`, `idunn-lifecycle`, `deployment-aftercare`, `tool-directory`, and `bifrost-publication` satisfied with `missingRequiredCount=1` for only upstream-main sync. Wrapper proof `local-20260621-115019-563-f4cec9fa` prints the same one-gap row without granting readiness, scheduling, Hands, publication, deployment, service lifecycle, durable state commit, cross-body mutation, or private-state authority. +- 2026-06-21: Repo-work readiness now includes the family-friendly safe-family planning depth row, receipt-shaped Idunn/tool-directory validation, Bifrost/GitHub publication receipt-chain validation, and upstream-main sync receipt/ancestry validation. `epiphany-work readiness` inspects `closureReview.familyAssertions.safeFamilyPlanning` from the close receipt and satisfies `safe-family-planning` only for Soul-owned `epiphany.repo_work_safe_family_planning_readback.v0` over `repo.planning_brief` with all expected candidate families, requirements, gates, matrix groups, matrix controls, closure proofs, authority denials, and private-state seal intact. It satisfies `idunn-lifecycle` only from `epiphany.repo_work_service_audit.v0` with complete Idunn-owned repo-work service proof, zero missing/failed checks, no service-manager mutation, no elevation requirement, and private-state seal; satisfies `tool-directory` only from `epiphany.cultmesh.daemon_tool_directory.v0` with nonempty globally available receipt-gated daemon tools, ready hosts, invoke command hints, and private-state seal; satisfies `bifrost-publication` only when the local publish artifact matches latest repo-local CultMesh Bifrost body-change and GitHub publication receipts; and satisfies `upstream-main-sync` only when `epiphany.repo_work_sync_receipt.v0` proves nonempty merge/sync authority receipts, matching publish/Bifrost/GitHub/Hands ids, private-state seal, and live git ancestry that the published commit is contained by the named upstream ref. Native smoke `.epiphany-smoke\repo-work-readiness-20260621-110524` now runs the readiness proof through `repo-planning-brief` cargo, sealed Idunn/tool artifacts, real `epiphany-work publish`, disposable upstream-main merge proof, and `epiphany-work sync`, proving all sixteen rows satisfied with `status=ready`, `missingRequiredCount=0`, `syncStatus=upstream-main-synced`, and `upstreamMainSynced=true`. Wrapper proof `local-20260621-120641-609-72d32f64` prints the same no-gap row without granting readiness, scheduling, Hands, publication, deployment, service lifecycle, durable state commit, cross-body mutation, or private-state authority. - 2026-06-20: Mind now has explicit repo-work safe-family and requested-path guards before branch-local Hands authority. `adopt --from-plan` treats unsupported plan-derived safe-family labels as refused interpreter decisions, writes `epiphany.repo_work_mind_adoption_decision.v0` with `status=refused-unsupported-safe-family`, keeps `actionItemAccepted=false` and `safeFamilyRecognized=false`, grants no Hands/durable-state/service/publication/cross-body/private-state authority, and writes no normal adoption receipt. It also compares the sorted action-item `requestedPaths` against the sorted plan action `changedPaths`; mismatches write `status=refused-requested-path-mismatch`, keep `safeFamilyRecognized=true` but `requestedPathsMatchPlan=false`, point the next gate at `imagination.replan_with_matching_requested_paths`, and grant no Hands/durable-state/service/publication/cross-body/private-state authority. Focused smokes `.epiphany-smoke\repo-mind-safe-family-guard-20260620-194425` and `.epiphany-smoke\repo-mind-path-guard-20260620-194239` prove both refusal paths; earlier positive smokes `.epiphany-smoke\repo-planning-facets-20260620-190916` and `.epiphany-smoke\closure-model-gate-20260620-190916` prove recognized planning facets and closure model gates still pass. Current remaining repo-swarm MVP organs are deeper interpreter semantics beyond adoption refusal, more useful repo-owned configuration/action families, richer closure depth, and Idunn-owned queue-run service lifecycle under explicit operator authority. - 2026-06-20: Mind now also refuses plan-derived repo work that is not evidence-ready. `derive-plan` embeds verification asks in the Imagination action-item receipt, `adopt --from-plan` records verification asks and planning evidence needs in `epiphany.repo_work_mind_interpretation.v0`, and empty verification asks or evidence needs write `status=refused-missing-evidence-needs` with next gate `imagination.replan_with_explicit_soul_evidence_needs`. The refusal grants no Hands, durable-state, service, publication, cross-body, or private-state authority and writes no adoption receipt. Focused proof `.epiphany-smoke\repo-mind-evidence-guard-20260620-224426` tampers both arrays empty and proves the refusal; regression `.epiphany-smoke\repo-planning-facets-20260620-224428` proves normal planning facets still close through Soul/Modeling/Mind. - 2026-06-20: `repo-eve-surface` is now live as repo-owned Eve/CultUI surface contract cargo. `epiphany-work derive-plan --action-family repo-eve-surface` writes `.epiphany/eve-surfaces/.toml` with safe family `repo.eve_surface`, compact agent TUI and GUI lowering contracts, local/public Verse routing, Odin discovery, provider-owned surface identity, Persona/human collaboration flags, feedback routing to Imagination, and denials for renderer ownership, rendering/state/publication/service/cross-body authority, private Verse rummaging, and private-state exposure. Soul closure assertions inspect schema, family, summary, surface routing, Verse routing, CultUI contracts, collaboration route, authority seals, and private-state seal. Focused smoke `.epiphany-smoke\repo-eve-surface-family-20260620-165927` ran init -> online -> accept -> repo-eve-surface derive-plan -> tick run/adopt/execute/close; Hands committed only `.epiphany/eve-surfaces/repo-eve-surface-family.toml`, Soul passed with `pathScopeMatched=true`, `familyAssertions.status=passed`, `hasCultUiContracts=true`, `hasVerseRouting=true`, `odinDiscoverable=true`, `feedbackRoutesToImagination=true`, `rendererOwnsTruth=false`, `renderingAuthority=false`, `stateAuthority=false`, `publicationAuthority=false`, `serviceLifecycleAuthority=false`, `crossBodyMutationAuthority=false`, `privateVerseRummaging=false`, and `privateStateExposed=false`. Current remaining repo-swarm MVP organs are deeper interpreter/adoption semantics, more useful repo-owned configuration/action families, and Idunn-owned queue-run service lifecycle under explicit operator authority. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 33a33f30da30f8593bd91df99fdc697073da0768..6dacfa14a8db2c7d11b57f29b8341c4e603263e6 100644 GIT binary patch delta 269 zcmXAiF-yZh7=}&EErOFJP;mG_a7($n#$#}ZA^*po*h2%~#Ew8yt(`;u`gLKX;m5bX1$&r=Zsj`JF# zECW.json` is `epiphany.repo_work_publish_receipt.v0` with publication authorized, upstream-main sync unclaimed, merge unclaimed, and private-state sealed; when latest `gamecult.bifrost.body_change_publication_receipt.v0` and `gamecult.bifrost.github_publication_receipt.v0` rows match the publish artifact's Bifrost/GitHub receipt ids, ledger id, Hands PR receipt id, PR URL, credit rows, and changed paths; and when both receipts keep `privateStateExposed=false`. Native smoke `.epiphany-smoke\repo-work-readiness-20260621-104757` now drives the readiness proof through repo-planning-brief cargo, sealed Idunn/tool artifacts, deployment-aftercare, and a real `epiphany-work publish`, proving `safe-family-planning`, `idunn-lifecycle`, `deployment-aftercare`, `tool-directory`, and `bifrost-publication` satisfied with `missingRequiredCount=1` for only upstream-main sync; wrapper proof `local-20260621-115019-563-f4cec9fa` printed the same one-gap row at the operator mouth. - next_action: Continue repo-swarm MVP work from the documented Epiphany Online cut order in `notes/epiphany-repo-swarm-mvp-contract.md`. The next useful cuts are upstream-main sync proof after explicit publication/merge authority, deeper Bifrost-first external-work accounting if ledger/publication readback needs more cargo, another useful repo-owned safe action family if the review loop needs more cargo, or explicit elevated/operator Idunn execution proof only when the human grants that authority. Persona-to-Imagination consensus readback, Mind-owned interpreter brief cargo, safe-family planning depth, Gjallar closure/readiness map rows, Bifrost ledger accounting rows, readiness wrapper mouth, repo deployment handoff/readback wrappers, readiness deployment-aftercare closure, readiness safe-family planning closure, readiness Idunn/tool-directory receipt validation, and readiness Bifrost/GitHub publication-chain validation are sealed; preserve Idunn service lifecycle ownership, Bifrost publication/upstream-main ownership, Mind durable-state admission, and existing CultMesh/Odin/Eve tool directories. Windows service install/start/deployment execution still requires explicit elevated operator authority. + last_completed_repo_swarm_cut: Repo-work readiness can now reach `ready` from typed receipt evidence without granting action authority. `epiphany-work readiness` validates `bifrost-publication` from the local publish artifact plus matching repo-local CultMesh Bifrost/GitHub receipts, and validates `upstream-main-sync` only when `epiphany.repo_work_sync_receipt.v0` has status `upstream-main-synced`, nonempty merge/sync authority receipts, matching publish/Bifrost/GitHub/Hands ids, private-state seal, and live git ancestry proof that the published commit is contained by the named upstream ref. Native smoke `.epiphany-smoke\repo-work-readiness-20260621-110524` now drives repo-planning-brief cargo, sealed Idunn/tool artifacts, deployment-aftercare, real `epiphany-work publish`, disposable upstream-main merge proof, and `epiphany-work sync`, proving all sixteen readiness rows satisfied with `status=ready`, `missingRequiredCount=0`, `syncStatus=upstream-main-synced`, and `upstreamMainSynced=true`; wrapper proof `local-20260621-120641-609-72d32f64` printed the same no-gap readiness mouth while keeping readiness approval, scheduling, Hands, publication, deployment, service lifecycle, durable state commit, cross-body mutation, and private-state authority false. + next_action: Continue repo-swarm MVP work from the documented Epiphany Online cut order in `notes/epiphany-repo-swarm-mvp-contract.md`. The next useful cuts are turning the ready sight receipt into a Maintainer/Soul/Mind/Bifrost readiness review request/adoption path, deeper Bifrost-first external-work accounting if ledger/publication readback needs more cargo, another useful repo-owned safe action family if the review loop needs more cargo, or explicit elevated/operator Idunn execution proof only when the human grants that authority. Persona-to-Imagination consensus readback, Mind-owned interpreter brief cargo, safe-family planning depth, Gjallar closure/readiness map rows, Bifrost ledger accounting rows, readiness wrapper mouth, repo deployment handoff/readback wrappers, readiness deployment-aftercare closure, readiness safe-family planning closure, readiness Idunn/tool-directory receipt validation, readiness Bifrost/GitHub publication-chain validation, and readiness upstream-main sync validation are sealed; preserve Idunn service lifecycle ownership, Bifrost publication/upstream-main ownership, Mind durable-state admission, and existing CultMesh/Odin/Eve tool directories. Windows service install/start/deployment execution still requires explicit elevated operator authority.