From 462869ed75d1964fc87a7ad2f2d33fedaac9823c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 20 Jun 2026 03:43:26 +0100 Subject: [PATCH] Publish repo work proof rows to CultMesh --- epiphany-core/src/bin/epiphany-verse-query.rs | 194 ++++++++++++++++++ epiphany-core/src/bin/epiphany-work.rs | 117 ++++++++++- epiphany-core/src/cultmesh_integration.rs | 143 +++++++++++++ epiphany-core/src/lib.rs | 7 + notes/epiphany-repo-swarm-mvp-contract.md | 27 ++- notes/fresh-workspace-handoff.md | 1 + state/ledgers.msgpack | Bin 317058 -> 317695 bytes state/map.yaml | 4 +- 8 files changed, 488 insertions(+), 5 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-verse-query.rs b/epiphany-core/src/bin/epiphany-verse-query.rs index 6205c6fe..761ec512 100644 --- a/epiphany-core/src/bin/epiphany-verse-query.rs +++ b/epiphany-core/src/bin/epiphany-verse-query.rs @@ -21,6 +21,7 @@ use epiphany_core::EpiphanyCultMeshEveSurfaceStateEntry; use epiphany_core::EpiphanyCultMeshImaginationConsensusReceiptEntry; use epiphany_core::EpiphanyCultMeshOdinAdvertisementEntry; use epiphany_core::EpiphanyCultMeshRepoWorkOverviewEntry; +use epiphany_core::EpiphanyCultMeshRepoWorkPublicProofEntry; use epiphany_core::EpiphanyCultMeshSwarmBrakeEntry; use epiphany_core::EpiphanyCultMeshWorkLoopTelemetryEntry; use epiphany_core::EpiphanyLocalVerseContext; @@ -48,6 +49,7 @@ use epiphany_core::load_epiphany_cultmesh_daemon_service_lifecycle_receipts; use epiphany_core::load_epiphany_cultmesh_daemon_tool_directory; use epiphany_core::load_epiphany_cultmesh_eve_surface_directory; use epiphany_core::load_epiphany_cultmesh_repo_work_overviews; +use epiphany_core::load_epiphany_cultmesh_repo_work_public_proofs; use epiphany_core::load_epiphany_cultmesh_swarm_brake; use epiphany_core::load_latest_epiphany_cultmesh_agent_state_soa_summary; use epiphany_core::load_latest_epiphany_cultmesh_bifrost_body_change_publication_intent; @@ -61,6 +63,7 @@ use epiphany_core::load_latest_epiphany_cultmesh_eve_connection_intent; use epiphany_core::load_latest_epiphany_cultmesh_eve_connection_receipt; use epiphany_core::load_latest_epiphany_cultmesh_imagination_consensus_receipt; use epiphany_core::load_latest_epiphany_cultmesh_repo_work_overview; +use epiphany_core::load_latest_epiphany_cultmesh_repo_work_public_proof; use epiphany_core::open_epiphany_cultmesh_node; use epiphany_core::query_epiphany_local_verse_context; use epiphany_core::seed_epiphany_local_verse_context; @@ -3442,6 +3445,7 @@ fn run_cli() -> Result<()> { &[], &[missing_artifact_action], &[], + &[], ); if !missing_artifact_rows.iter().any(|row| { row.priority == 50 @@ -3491,6 +3495,7 @@ fn run_cli() -> Result<()> { &[], &[synthetic_runbook_action], &[], + &[], ); if !synthetic_artifact_rows.iter().any(|row| { row.priority == 50 @@ -3945,10 +3950,13 @@ struct SwarmOverviewReport { service_execution_failed_check_tui_rows: Vec, repo_work_overview_rows: Vec, repo_work_overview_tui_rows: Vec, + repo_work_public_proof_rows: Vec, + repo_work_public_proof_tui_rows: Vec, latest_repo_work_overview_id: Option, latest_repo_work_gate: Option, latest_repo_work_blocker: Option, latest_repo_work_next_safe_move: Option, + latest_repo_work_public_proof: Option, topology_report: ClusterTopologyReport, daemon_report: DaemonLivenessReport, surface_report: EveSurfaceReport, @@ -3976,6 +3984,27 @@ struct RepoWorkOverviewRow { private_state_exposed: bool, } +#[derive(Clone, Serialize)] +#[serde(rename_all = "camelCase")] +struct RepoWorkPublicProofRow { + public_proof_id: String, + workspace: String, + item: String, + branch: String, + current_gate: String, + blocker: String, + next_safe_move: String, + changed_path_count: usize, + commit_sha: String, + soul_verdict: String, + upstream_main_synced: bool, + artifact_row_count: u32, + publication_row_count: u32, + public_proof_ref: String, + public_proof_sha256: String, + private_state_exposed: bool, +} + #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase")] struct SwarmActionRow { @@ -4060,10 +4089,14 @@ struct SwarmOverviewOutput { repo_work_overview_count: usize, repo_work_overview_rows: Vec, repo_work_overview_tui_rows: Vec, + repo_work_public_proof_count: usize, + repo_work_public_proof_rows: Vec, + repo_work_public_proof_tui_rows: Vec, latest_repo_work_overview: Option, latest_repo_work_gate: Option, latest_repo_work_blocker: Option, latest_repo_work_next_safe_move: Option, + latest_repo_work_public_proof: Option, policy_covered_count: usize, policy_enabled_count: usize, policy_disabled_count: usize, @@ -4127,10 +4160,14 @@ impl SwarmOverviewOutput { repo_work_overview_count: report.repo_work_overview_rows.len(), repo_work_overview_rows: report.repo_work_overview_rows, repo_work_overview_tui_rows: report.repo_work_overview_tui_rows, + repo_work_public_proof_count: report.repo_work_public_proof_rows.len(), + repo_work_public_proof_rows: report.repo_work_public_proof_rows, + repo_work_public_proof_tui_rows: report.repo_work_public_proof_tui_rows, latest_repo_work_overview: report.latest_repo_work_overview_id, latest_repo_work_gate: report.latest_repo_work_gate, latest_repo_work_blocker: report.latest_repo_work_blocker, latest_repo_work_next_safe_move: report.latest_repo_work_next_safe_move, + latest_repo_work_public_proof: report.latest_repo_work_public_proof, policy_covered_count: report.policy_report.covered_count, policy_enabled_count: report.policy_report.enabled_count, policy_disabled_count: report.policy_report.disabled_count, @@ -4186,10 +4223,14 @@ struct SwarmTriageOutput { repo_work_overview_count: usize, repo_work_overview_rows: Vec, repo_work_overview_tui_rows: Vec, + repo_work_public_proof_count: usize, + repo_work_public_proof_rows: Vec, + repo_work_public_proof_tui_rows: Vec, latest_repo_work_overview: Option, latest_repo_work_gate: Option, latest_repo_work_blocker: Option, latest_repo_work_next_safe_move: Option, + latest_repo_work_public_proof: Option, poked_daemon_count: usize, pokes: Vec, commands: serde_json::Value, @@ -4248,10 +4289,14 @@ impl SwarmTriageOutput { repo_work_overview_count: report.repo_work_overview_rows.len(), repo_work_overview_rows: report.repo_work_overview_rows, repo_work_overview_tui_rows: report.repo_work_overview_tui_rows, + repo_work_public_proof_count: report.repo_work_public_proof_rows.len(), + repo_work_public_proof_rows: report.repo_work_public_proof_rows, + repo_work_public_proof_tui_rows: report.repo_work_public_proof_tui_rows, latest_repo_work_overview: report.latest_repo_work_overview_id, latest_repo_work_gate: report.latest_repo_work_gate, latest_repo_work_blocker: report.latest_repo_work_blocker, latest_repo_work_next_safe_move: report.latest_repo_work_next_safe_move, + latest_repo_work_public_proof: report.latest_repo_work_public_proof, poked_daemon_count, pokes, commands: json!({ @@ -4451,6 +4496,7 @@ fn swarm_action_rows( service_execution_failed_check_rows: &[EpiphanyServiceExecutionAuditCheck], service_execution_runbook_actions: &[ServiceExecutionRunbookAction], repo_work_overviews: &[EpiphanyCultMeshRepoWorkOverviewEntry], + repo_work_public_proofs: &[EpiphanyCultMeshRepoWorkPublicProofEntry], ) -> (Vec, Vec) { let mut rows = Vec::new(); let mut service_execution_check_counts = BTreeMap::::new(); @@ -4698,6 +4744,12 @@ fn swarm_action_rows( private_state_exposed: runbook_action.private_state_exposed, }); } + for (index, public_proof) in repo_work_public_proofs.iter().take(5).enumerate() { + rows.push(repo_work_public_proof_action_row( + public_proof, + 60 + index as u32, + )); + } if rows.is_empty() { rows.push(SwarmActionRow { priority: 100, @@ -4801,6 +4853,59 @@ fn repo_work_peer_tui_rows(rows: &[RepoWorkOverviewRow]) -> Vec { .collect() } +fn repo_work_public_proof_rows( + public_proofs: &[EpiphanyCultMeshRepoWorkPublicProofEntry], +) -> (Vec, Vec) { + let rows = public_proofs + .iter() + .map(repo_work_public_proof_row) + .collect::>(); + let tui_rows = rows + .iter() + .map(repo_work_public_proof_tui_row) + .collect::>(); + (rows, tui_rows) +} + +fn repo_work_public_proof_row( + proof: &EpiphanyCultMeshRepoWorkPublicProofEntry, +) -> RepoWorkPublicProofRow { + RepoWorkPublicProofRow { + public_proof_id: proof.public_proof_id.clone(), + workspace: proof.workspace.clone(), + item: proof.item.clone(), + branch: proof.branch.clone(), + current_gate: proof.current_gate.clone(), + blocker: proof.blocker.clone(), + next_safe_move: proof.next_safe_move.clone(), + changed_path_count: proof.changed_paths.len(), + commit_sha: proof.commit_sha.clone(), + soul_verdict: proof.soul_verdict.clone(), + upstream_main_synced: proof.upstream_main_synced, + artifact_row_count: proof.artifact_row_count, + publication_row_count: proof.publication_row_count, + public_proof_ref: proof.public_proof_ref.clone(), + public_proof_sha256: proof.public_proof_sha256.clone(), + private_state_exposed: proof.private_state_exposed, + } +} + +fn repo_work_public_proof_tui_row(row: &RepoWorkPublicProofRow) -> String { + format!( + "REPO-WORK-PUBLIC-PROOF | item={} | gate={} | branch={} | commit={} | artifacts={} | publicationRows={} | upstreamMainSynced={} | proof={} | sha256={} | private={}", + row.item, + row.current_gate, + row.branch, + row.commit_sha, + row.artifact_row_count, + row.publication_row_count, + row.upstream_main_synced, + row.public_proof_ref, + row.public_proof_sha256, + row.private_state_exposed + ) +} + fn repo_work_overview_action_row( overview: &EpiphanyCultMeshRepoWorkOverviewEntry, priority: u32, @@ -4849,6 +4954,55 @@ fn repo_work_overview_action_row( } } +fn repo_work_public_proof_action_row( + proof: &EpiphanyCultMeshRepoWorkPublicProofEntry, + priority: u32, +) -> SwarmActionRow { + SwarmActionRow { + priority, + family: "repo-work-public-proof".to_string(), + status: proof.current_gate.clone(), + lifecycle_owner: "Gjallar".to_string(), + hosted_body: "repo-work".to_string(), + action: format!( + "Read redacted public proof {} for item {}; Bifrost owns any public publication or credit consequence.", + proof.public_proof_id, proof.item + ), + wrapper_mode: "repo-work-public-proof".to_string(), + wrapper_command: format!( + "epiphany-work export-proof --workspace \"{}\" --item \"{}\" --local-verse-store ", + proof.workspace, proof.item + ), + operator_artifact_ref: proof.public_proof_ref.clone(), + operator_artifact_status: if proof.public_proof_ref == "none" { + "none".to_string() + } else { + "external-ref".to_string() + }, + operator_artifact_sha256: proof.public_proof_sha256.clone(), + operator_artifact_execution_command: "none".to_string(), + operator_aftercare_command: "none".to_string(), + completion_audit_wrapper_mode: "bifrost-ledger".to_string(), + completion_audit_wrapper_command: WRAPPER_BIFROST_LEDGER_COMMAND.to_string(), + authority_gate: "repo.work.public_proof_readback".to_string(), + effect_class: "repo-work-public-proof-readback".to_string(), + mutates_state: false, + requires_elevated_authority: false, + service_execution_failed_check_count: 0, + service_execution_missing_check_count: 0, + service_id: "none".to_string(), + service_route: "none".to_string(), + reason: format!( + "Redacted proof has artifacts={} publicationRows={} upstreamMainSynced={} sha256={}", + proof.artifact_row_count, + proof.publication_row_count, + proof.upstream_main_synced, + proof.public_proof_sha256 + ), + private_state_exposed: proof.private_state_exposed, + } +} + fn swarm_action_tui_row(row: &SwarmActionRow) -> String { format!( "{:03} | {} | {} | {} | {} | owner={} | hostedBody={} | service={} | route={} | command={} | mutates={} | elevated={} | failedChecks={} | missingChecks={} | artifact={} | sha256={} | exec={} | audit={} | aftercare={}", @@ -5230,12 +5384,40 @@ fn load_repo_work_overview_queue( Ok((latest_repo_work_overview, repo_work_overviews)) } +fn load_repo_work_public_proofs( + args: &Args, +) -> Result<( + Option, + Vec, +)> { + let latest_public_proof = + load_latest_epiphany_cultmesh_repo_work_public_proof(&args.store, args.runtime_id.clone())?; + let mut public_proofs = + load_epiphany_cultmesh_repo_work_public_proofs(&args.store, args.runtime_id.clone())?; + if let Some(latest) = latest_public_proof.as_ref() { + if !public_proofs + .iter() + .any(|proof| proof.public_proof_id == latest.public_proof_id) + { + public_proofs.push(latest.clone()); + public_proofs.sort_by(|a, b| { + b.generated_at + .cmp(&a.generated_at) + .then_with(|| a.public_proof_id.cmp(&b.public_proof_id)) + }); + } + } + Ok((latest_public_proof, public_proofs)) +} + fn load_swarm_overview_report(args: &Args) -> Result { let topology = load_epiphany_cultmesh_cluster_topology(&args.store, args.runtime_id.clone())?; let topology_report = cluster_topology_report(&topology); let liveness = load_epiphany_cultmesh_daemon_liveness(&args.store, args.runtime_id.clone())?; let daemon_report = daemon_liveness_report(&liveness); let (latest_repo_work_overview, repo_work_overviews) = load_repo_work_overview_queue(args)?; + let (latest_repo_work_public_proof, repo_work_public_proofs) = + load_repo_work_public_proofs(args)?; let directory = load_epiphany_cultmesh_eve_surface_directory(&args.store, args.runtime_id.clone())?; let surface_report = eve_surface_report(&directory, &repo_work_overviews); @@ -5448,6 +5630,8 @@ fn load_swarm_overview_report(args: &Args) -> Result { .collect::>(); let (repo_work_overview_rows, repo_work_overview_tui_rows) = repo_work_overview_rows(&repo_work_overviews); + let (repo_work_public_proof_rows, repo_work_public_proof_tui_rows) = + repo_work_public_proof_rows(&repo_work_public_proofs); let (swarm_action_rows, swarm_action_tui_rows) = swarm_action_rows( &liveness_status, &tool_host_attention_rows, @@ -5456,6 +5640,7 @@ fn load_swarm_overview_report(args: &Args) -> Result { &service_execution_failed_check_rows, &service_execution_runbook_actions, &repo_work_overviews, + &repo_work_public_proofs, ); let private_state_exposed = daemon_report .rows @@ -5466,6 +5651,9 @@ fn load_swarm_overview_report(args: &Args) -> Result { || repo_work_overviews .iter() .any(|overview| overview.private_state_exposed) + || repo_work_public_proofs + .iter() + .any(|proof| proof.private_state_exposed) || service_execution_private_state_exposed || service_lifecycle_rows .iter() @@ -5482,6 +5670,9 @@ fn load_swarm_overview_report(args: &Args) -> Result { let latest_repo_work_next_safe_move = latest_repo_work_overview .as_ref() .map(|overview| overview.next_safe_move.clone()); + let latest_repo_work_public_proof = latest_repo_work_public_proof + .as_ref() + .map(|proof| proof.public_proof_id.clone()); Ok(SwarmOverviewReport { status, liveness_status, @@ -5506,10 +5697,13 @@ fn load_swarm_overview_report(args: &Args) -> Result { service_execution_failed_check_tui_rows, repo_work_overview_rows, repo_work_overview_tui_rows, + repo_work_public_proof_rows, + repo_work_public_proof_tui_rows, latest_repo_work_overview_id, latest_repo_work_gate, latest_repo_work_blocker, latest_repo_work_next_safe_move, + latest_repo_work_public_proof, topology_report, daemon_report, surface_report, diff --git a/epiphany-core/src/bin/epiphany-work.rs b/epiphany-core/src/bin/epiphany-work.rs index 0363d48b..ab78af1b 100644 --- a/epiphany-core/src/bin/epiphany-work.rs +++ b/epiphany-core/src/bin/epiphany-work.rs @@ -5,7 +5,9 @@ use chrono::DateTime; use chrono::Utc; use epiphany_core::EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID; use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_SCHEMA_VERSION; +use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION; use epiphany_core::EpiphanyCultMeshRepoWorkOverviewEntry; +use epiphany_core::EpiphanyCultMeshRepoWorkPublicProofEntry; use epiphany_core::HANDS_ACTION_INTENT_SCHEMA_VERSION; use epiphany_core::HANDS_COMMAND_RECEIPT_TYPE; use epiphany_core::HANDS_COMMIT_RECEIPT_TYPE; @@ -45,6 +47,7 @@ use epiphany_core::runtime_hands_action_review; use epiphany_core::runtime_hands_commit_receipt; use epiphany_core::runtime_latest_hands_receipt_chain_after; use epiphany_core::write_epiphany_cultmesh_repo_work_overview; +use epiphany_core::write_epiphany_cultmesh_repo_work_public_proof; use serde_json::Value; use serde_json::json; use sha2::Digest; @@ -272,6 +275,8 @@ struct ExportProofArgs { accept_receipt: Option, artifact_dir: Option, output: Option, + local_verse_store: Option, + runtime_id: String, } #[derive(Clone, Debug)] @@ -978,6 +983,8 @@ fn parse_export_proof_args(args: impl Iterator) -> Result) -> Result accept_receipt = Some(take_path(&mut args, "--accept-receipt")?), "--artifact-dir" => artifact_dir = Some(take_path(&mut args, "--artifact-dir")?), "--output" | "--export-path" => output = Some(take_path(&mut args, "--output")?), + "--local-verse-store" | "--store" => { + local_verse_store = Some(take_path(&mut args, "--local-verse-store")?); + } + "--runtime-id" => runtime_id = take_string(&mut args, "--runtime-id")?, other => return Err(anyhow!("unexpected export-proof argument {other:?}")), } } @@ -996,6 +1007,8 @@ fn parse_export_proof_args(args: impl Iterator) -> Result Result { }); let public_bundle = repo_work_public_proof_bundle(&overview)?; write_json(&output, &public_bundle)?; + let public_proof_sha256 = file_sha256(&output)?; + let local_verse_store = args + .local_verse_store + .unwrap_or_else(|| workspace.join(".epiphany").join("local-verse.ccmp")); + let artifact_row_count = public_bundle + .get("artifactRows") + .and_then(Value::as_array) + .map(|rows| rows.len()) + .unwrap_or(0); + let publication_row_count = public_bundle + .get("publicationRows") + .and_then(Value::as_array) + .map(|rows| rows.len()) + .unwrap_or(0); + let public_proof_tui_rows = repo_work_public_proof_tui_rows( + &public_bundle, + &output, + &public_proof_sha256, + artifact_row_count, + publication_row_count, + ); + let entry = EpiphanyCultMeshRepoWorkPublicProofEntry { + schema_version: EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION.to_string(), + runtime_id: args.runtime_id.clone(), + verse_id: EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID.to_string(), + public_proof_id: format!("repo-work-public-proof-{item_slug}"), + generated_at: string_from_json(&public_bundle, &["generatedAt"]) + .unwrap_or_else(|| Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true)), + workspace: workspace.display().to_string(), + item: item.clone(), + branch: string_from_json(&public_bundle, &["branch"]).unwrap_or_else(|| "unknown".to_string()), + current_gate: string_from_json(&public_bundle, &["currentGate"]) + .unwrap_or_else(|| "unknown".to_string()), + blocker: string_from_json(&public_bundle, &["blocker"]).unwrap_or_else(|| "none".to_string()), + next_safe_move: string_from_json(&public_bundle, &["nextSafeMove"]) + .unwrap_or_else(|| "none".to_string()), + changed_paths: public_bundle + .get("changedPaths") + .and_then(Value::as_array) + .map(|paths| { + paths + .iter() + .filter_map(Value::as_str) + .map(ToString::to_string) + .collect::>() + }) + .unwrap_or_default(), + commit_sha: string_from_json(&public_bundle, &["commitSha"]).unwrap_or_else(|| "none".to_string()), + soul_verdict: string_from_json(&public_bundle, &["soulVerdict"]).unwrap_or_else(|| "none".to_string()), + upstream_main_synced: public_bundle + .get("upstreamMainSynced") + .and_then(Value::as_bool) + .unwrap_or(false), + artifact_row_count: artifact_row_count as u32, + publication_row_count: publication_row_count as u32, + public_proof_ref: output.display().to_string(), + public_proof_sha256: public_proof_sha256.clone(), + tui_rows: public_proof_tui_rows, + private_state_exposed: false, + notes: vec![ + "Repo work public proof is a redacted local Verse index for public/Bifrost transport; raw receipt bodies, local receipt paths, worker thought, and private Verse contents remain sealed.".to_string(), + "Gjallar/Odin may discover this proof, but Bifrost still owns publication, labor ledger, credit, and public consequence.".to_string(), + ], + }; + let written_public_proof = + write_epiphany_cultmesh_repo_work_public_proof(&local_verse_store, entry)?; + let verse_projection = json!({ + "localVerseStore": local_verse_store, + "documentType": "epiphany.cultmesh.repo_work_public_proof", + "publicProofId": written_public_proof.public_proof_id, + "latestKey": "gamecult-local/repo-work-public-proof/latest", + "publicProofRef": written_public_proof.public_proof_ref, + "publicProofSha256": written_public_proof.public_proof_sha256, + "tuiRows": written_public_proof.tui_rows, + "privateStateExposed": written_public_proof.private_state_exposed + }); Ok(json!({ "schemaVersion": "epiphany.repo_work_public_proof_export.v0", "status": "public-proof-exported", "workspace": workspace, "item": item, "outputPath": output, + "outputSha256": public_proof_sha256, "sourceOverviewReceiptPath": overview["receiptPath"], "publicProofBundle": public_bundle, + "verseProjection": verse_projection, "privateStateExposed": false, "nextSafeMove": "Share the public proof bundle with maintainers or Bifrost; keep raw worker thoughts and local receipt bodies sealed." })) @@ -4748,6 +4839,30 @@ fn repo_work_public_artifact_row(row: &Value) -> Value { }) } +fn repo_work_public_proof_tui_rows( + bundle: &Value, + output: &Path, + sha256: &str, + artifact_row_count: usize, + publication_row_count: usize, +) -> Vec { + vec![format!( + "PUBLIC-PROOF | item={} | gate={} | branch={} | commit={} | artifacts={} | publicationRows={} | upstreamMainSynced={} | proof={} | sha256={} | private=false", + string_from_json(bundle, &["item"]).unwrap_or_else(|| "unknown".to_string()), + string_from_json(bundle, &["currentGate"]).unwrap_or_else(|| "unknown".to_string()), + string_from_json(bundle, &["branch"]).unwrap_or_else(|| "unknown".to_string()), + string_from_json(bundle, &["commitSha"]).unwrap_or_else(|| "none".to_string()), + artifact_row_count, + publication_row_count, + bundle + .get("upstreamMainSynced") + .and_then(Value::as_bool) + .unwrap_or(false), + output.display(), + sha256 + )] +} + fn sync_receipt_upstream_main_synced(receipt: &Value) -> Option { receipt .get("upstreamMainSynced") @@ -5358,7 +5473,7 @@ fn print_usage() { publish --workspace [--item ] --change-summary --justification --verification-receipt --review-receipt --ledger-entry-id --pull-request-url --pull-request-title \n\ sync --workspace [--item ] [--publish-receipt ] [--upstream-ref origin/main] --merge-receipt \n\ overview --workspace [--item ] [--accept-receipt ] [--no-write]\n\ - export-proof --workspace [--item ] [--accept-receipt ] [--output ]\n\ + export-proof --workspace [--item ] [--accept-receipt ] [--output ] [--local-verse-store ] [--runtime-id repo-swarm-local]\n\ tick --workspace [--item ] [--local-verse-store ] [--runtime-store ] [--dry-run]\n\ queue-run --workspace [--local-verse-store ] [--runtime-id repo-swarm-local] [--max-items 1] [--dry-run]" ); diff --git a/epiphany-core/src/cultmesh_integration.rs b/epiphany-core/src/cultmesh_integration.rs index 7b650cb7..276a93a7 100644 --- a/epiphany-core/src/cultmesh_integration.rs +++ b/epiphany-core/src/cultmesh_integration.rs @@ -76,6 +76,12 @@ pub const EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_SCHEMA_VERSION: &str = "epiphany.cultmesh.repo_work_overview.v0"; pub const EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_LATEST_KEY: &str = "gamecult-local/repo-work-overview/latest"; +pub const EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_TYPE: &str = + "epiphany.cultmesh.repo_work_public_proof"; +pub const EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION: &str = + "epiphany.cultmesh.repo_work_public_proof.v0"; +pub const EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_LATEST_KEY: &str = + "gamecult-local/repo-work-public-proof/latest"; pub const EPIPHANY_CULTMESH_VERSE_POLICY_TYPE: &str = "epiphany.cultmesh.verse_policy"; pub const EPIPHANY_CULTMESH_VERSE_POLICY_SCHEMA_VERSION: &str = "epiphany.cultmesh.verse_policy.v0"; pub const EPIPHANY_CULTMESH_GLOBAL_ROOM_POLICY_TYPE: &str = "epiphany.cultmesh.global_room_policy"; @@ -740,6 +746,58 @@ pub struct EpiphanyCultMeshRepoWorkOverviewEntry { pub notes: Vec, } +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "epiphany.cultmesh.repo_work_public_proof", + schema = "EpiphanyCultMeshRepoWorkPublicProofEntry" +)] +pub struct EpiphanyCultMeshRepoWorkPublicProofEntry { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub runtime_id: String, + #[cultcache(key = 2)] + pub verse_id: String, + #[cultcache(key = 3)] + pub public_proof_id: String, + #[cultcache(key = 4)] + pub generated_at: String, + #[cultcache(key = 5)] + pub workspace: String, + #[cultcache(key = 6)] + pub item: String, + #[cultcache(key = 7)] + pub branch: String, + #[cultcache(key = 8)] + pub current_gate: String, + #[cultcache(key = 9)] + pub blocker: String, + #[cultcache(key = 10)] + pub next_safe_move: String, + #[cultcache(key = 11)] + pub changed_paths: Vec, + #[cultcache(key = 12)] + pub commit_sha: String, + #[cultcache(key = 13)] + pub soul_verdict: String, + #[cultcache(key = 14)] + pub upstream_main_synced: bool, + #[cultcache(key = 15)] + pub artifact_row_count: u32, + #[cultcache(key = 16)] + pub publication_row_count: u32, + #[cultcache(key = 17)] + pub public_proof_ref: String, + #[cultcache(key = 18)] + pub public_proof_sha256: String, + #[cultcache(key = 19)] + pub tui_rows: Vec, + #[cultcache(key = 20)] + pub private_state_exposed: bool, + #[cultcache(key = 21)] + pub notes: Vec, +} + #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] #[cultcache( type = "epiphany.cultmesh.verse_policy", @@ -2034,6 +2092,7 @@ cultmesh_documents!(EpiphanyCultMeshDocuments { EpiphanyCultMeshWorkLoopTelemetryEntry => EPIPHANY_CULTMESH_WORK_LOOP_TELEMETRY_SCHEMA_VERSION, EpiphanyCultMeshAgentStateSoaSummaryEntry => EPIPHANY_CULTMESH_AGENT_STATE_SOA_SUMMARY_SCHEMA_VERSION, EpiphanyCultMeshRepoWorkOverviewEntry => EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_SCHEMA_VERSION, + EpiphanyCultMeshRepoWorkPublicProofEntry => EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION, EpiphanyCultMeshVersePolicyEntry => EPIPHANY_CULTMESH_VERSE_POLICY_SCHEMA_VERSION, EpiphanyCultMeshGlobalRoomPolicyEntry => EPIPHANY_CULTMESH_GLOBAL_ROOM_POLICY_SCHEMA_VERSION, EpiphanyCultMeshClusterTopologyEntry => EPIPHANY_CULTMESH_CLUSTER_TOPOLOGY_SCHEMA_VERSION, @@ -4181,6 +4240,48 @@ pub fn load_epiphany_cultmesh_repo_work_overviews( Ok(overviews) } +pub fn write_epiphany_cultmesh_repo_work_public_proof( + store_path: impl AsRef, + proof: EpiphanyCultMeshRepoWorkPublicProofEntry, +) -> Result { + validate_repo_work_public_proof(&proof)?; + let mut node = open_epiphany_cultmesh_node(&store_path, proof.runtime_id.clone())?; + let written = node.put(proof.public_proof_id.clone(), &proof)?; + node.put( + EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_LATEST_KEY, + &written, + )?; + node.flush()?; + Ok(written) +} + +pub fn load_latest_epiphany_cultmesh_repo_work_public_proof( + store_path: impl AsRef, + runtime_id: impl Into, +) -> Result> { + let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; + node.get(EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_LATEST_KEY) +} + +pub fn load_epiphany_cultmesh_repo_work_public_proofs( + store_path: impl AsRef, + runtime_id: impl Into, +) -> Result> { + let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; + let mut proofs = node + .get_all_with_keys::()? + .into_iter() + .filter(|(key, _)| key != EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_LATEST_KEY) + .map(|(_, proof)| proof) + .collect::>(); + proofs.sort_by(|a, b| { + b.generated_at + .cmp(&a.generated_at) + .then_with(|| a.public_proof_id.cmp(&b.public_proof_id)) + }); + Ok(proofs) +} + fn validate_repo_work_overview(overview: &EpiphanyCultMeshRepoWorkOverviewEntry) -> Result<()> { if overview.private_state_exposed { return Err(anyhow!("repo work overview must not expose private state")); @@ -4215,6 +4316,48 @@ fn validate_repo_work_overview(overview: &EpiphanyCultMeshRepoWorkOverviewEntry) Ok(()) } +fn validate_repo_work_public_proof(proof: &EpiphanyCultMeshRepoWorkPublicProofEntry) -> Result<()> { + if proof.private_state_exposed { + return Err(anyhow!( + "repo work public proof must not expose private state" + )); + } + if proof.schema_version != EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION { + return Err(anyhow!( + "repo work public proof schema_version must be {:?}", + EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION + )); + } + if proof.verse_id != EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID { + return Err(anyhow!( + "repo work public proof belongs in local-area Verse {:?}", + EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID + )); + } + if proof.public_proof_id.trim().is_empty() || proof.item.trim().is_empty() { + return Err(anyhow!( + "repo work public proof requires public_proof_id and item" + )); + } + if proof.public_proof_ref.trim().is_empty() || proof.public_proof_sha256.trim().is_empty() { + return Err(anyhow!( + "repo work public proof requires artifact ref and sha256" + )); + } + if proof.tui_rows.is_empty() { + return Err(anyhow!("repo work public proof requires compact TUI rows")); + } + if proof.tui_rows.iter().any(|row| { + let lower = row.to_ascii_lowercase(); + lower.contains("rawresult") || lower.contains("receipt body") || lower.contains("thought") + }) { + return Err(anyhow!( + "repo work public proof rows must not expose raw worker payload names" + )); + } + Ok(()) +} + pub fn seed_epiphany_local_verse_context( store_path: impl AsRef, runtime_id: impl Into, diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index b6bc5513..1f419b6d 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -206,6 +206,9 @@ pub use cultmesh_integration::EPIPHANY_CULTMESH_PERSONA_SPEECH_AUDIT_TYPE; pub use cultmesh_integration::EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_LATEST_KEY; pub use cultmesh_integration::EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_SCHEMA_VERSION; pub use cultmesh_integration::EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_TYPE; +pub use cultmesh_integration::EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_LATEST_KEY; +pub use cultmesh_integration::EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION; +pub use cultmesh_integration::EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_TYPE; pub use cultmesh_integration::EPIPHANY_CULTMESH_ROLE_REVIEW_EVENT_LATEST_KEY; pub use cultmesh_integration::EPIPHANY_CULTMESH_ROLE_REVIEW_EVENT_SCHEMA_VERSION; pub use cultmesh_integration::EPIPHANY_CULTMESH_ROLE_REVIEW_EVENT_TYPE; @@ -259,6 +262,7 @@ pub use cultmesh_integration::EpiphanyCultMeshOperatorSnapshotEntry; pub use cultmesh_integration::EpiphanyCultMeshOperatorStatusEntry; pub use cultmesh_integration::EpiphanyCultMeshPersonaSpeechAuditEntry; pub use cultmesh_integration::EpiphanyCultMeshRepoWorkOverviewEntry; +pub use cultmesh_integration::EpiphanyCultMeshRepoWorkPublicProofEntry; pub use cultmesh_integration::EpiphanyCultMeshRoleReviewEventEntry; pub use cultmesh_integration::EpiphanyCultMeshSoulContractEntry; pub use cultmesh_integration::EpiphanyCultMeshStatusEntry; @@ -315,6 +319,7 @@ pub use cultmesh_integration::load_epiphany_cultmesh_eve_surface_directory; pub use cultmesh_integration::load_epiphany_cultmesh_operator_snapshot; pub use cultmesh_integration::load_epiphany_cultmesh_operator_status; pub use cultmesh_integration::load_epiphany_cultmesh_repo_work_overviews; +pub use cultmesh_integration::load_epiphany_cultmesh_repo_work_public_proofs; pub use cultmesh_integration::load_epiphany_cultmesh_status; pub use cultmesh_integration::load_epiphany_cultmesh_swarm_brake; pub use cultmesh_integration::load_latest_epiphany_cultmesh_agent_state_soa_summary; @@ -338,6 +343,7 @@ pub use cultmesh_integration::load_latest_epiphany_cultmesh_operator_run_receipt pub use cultmesh_integration::load_latest_epiphany_cultmesh_operator_snapshot; pub use cultmesh_integration::load_latest_epiphany_cultmesh_persona_speech_audit; pub use cultmesh_integration::load_latest_epiphany_cultmesh_repo_work_overview; +pub use cultmesh_integration::load_latest_epiphany_cultmesh_repo_work_public_proof; pub use cultmesh_integration::load_latest_epiphany_cultmesh_role_review_event; pub use cultmesh_integration::load_latest_epiphany_cultmesh_work_loop_telemetry; pub use cultmesh_integration::open_epiphany_cultmesh_node; @@ -376,6 +382,7 @@ pub use cultmesh_integration::write_epiphany_cultmesh_operator_snapshot; pub use cultmesh_integration::write_epiphany_cultmesh_operator_status; pub use cultmesh_integration::write_epiphany_cultmesh_persona_speech_audit; pub use cultmesh_integration::write_epiphany_cultmesh_repo_work_overview; +pub use cultmesh_integration::write_epiphany_cultmesh_repo_work_public_proof; pub use cultmesh_integration::write_epiphany_cultmesh_role_review_event; pub use cultmesh_integration::write_epiphany_cultmesh_soul_contracts; pub use cultmesh_integration::write_epiphany_cultmesh_status; diff --git a/notes/epiphany-repo-swarm-mvp-contract.md b/notes/epiphany-repo-swarm-mvp-contract.md index 7c40419b..5f113e0d 100644 --- a/notes/epiphany-repo-swarm-mvp-contract.md +++ b/notes/epiphany-repo-swarm-mvp-contract.md @@ -714,6 +714,26 @@ default public proof path, carried eight artifact rows and three publication rows, exposed zero artifact path fields, kept `rawReceiptBodies=false`, and reported `private=false`. +The first public-proof Verse transport smoke made that export discoverable +through local CultMesh/Gjallar sight without handing publication authority to +the exporter. `epiphany-work export-proof --local-verse-store \.epiphany\local-verse.ccmp` +now writes `epiphany.cultmesh.repo_work_public_proof.v0` under +`gamecult-local/repo-work-public-proof/latest`, carrying item, gate, branch, +commit, artifact/publication row counts, upstream-main sync truth, public proof +artifact ref, SHA-256, compact `PUBLIC-PROOF` TUI rows, and +`privateStateExposed=false`. `epiphany-verse-query swarm-overview` reads that +history and emits `repoWorkPublicProofRows`, `repoWorkPublicProofTuiRows`, +`latestRepoWorkPublicProof`, plus non-mutating priority 60+ +`repo-work-public-proof` action rows with `authorityGate=repo.work.public_proof_readback`, +`effectClass=repo-work-public-proof-readback`, `mutatesState=false`, and +`requiresElevatedAuthority=false`. Smoke artifacts +`.epiphany-smoke\checklist-note-20260620-031347\14-export-proof-verse.json` +and `15-swarm-overview-public-proof.json` proved latest +`repo-work-public-proof-checklist-request`, SHA-256 +`e781e09c2ba340c8818d3ef95e54085ccd0c92c6a3b5f73cc4878fb224e49dff`, one +public proof row, one public proof action row, no mutation/elevation, and +`private=false`. + The first Verse projection smoke proved the local CultMesh sight path: overview mirrored `repo-work-overview-verse-overview-request` into the repo-local Verse, `epiphany-verse-query smoke --store --runtime-id repo-swarm-local` @@ -1179,8 +1199,11 @@ Required organs before MVP: `epiphany-work export-proof` now writes a redacted `epiphany.repo_work_public_proof_bundle.v0` artifact under `.epiphany/public/proof-bundles/` with local paths and raw receipt bodies - removed. Remaining work is Bifrost/public Verse transport and UX polish, not - basic local public-proof export or Bifrost/GitHub/sync row visibility. + removed, and mirrors an `epiphany.cultmesh.repo_work_public_proof.v0` row + into local Verse for Gjallar/Odin sight. Remaining work is Bifrost public + publication/credit transport beyond local Verse plus UX polish, not basic + local public-proof export, local CultMesh readback, or Bifrost/GitHub/sync + row visibility. Scheduler authority is intentionally narrow. It may advance `accept -> plan -> run -> adopt -> execute` only when each upstream receipt diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 43062fed..65f1674e 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -113,6 +113,7 @@ remembers doctrine; the branch remembers the blade. - 2026-06-20: Local proof-bundle packaging is live. `epiphany-work overview` now embeds `epiphany.repo_work_proof_bundle.v0` with generated time, gate/blocker/next-safe-move, compact TUI rows, expected artifact paths, present/missing artifact status, document schema/status, SHA-256 receipt hashes, and `privateStateExposed=false`. Disposable proof `.epiphany-smoke\tick-close-20260620-025526\08-overview-proof-bundle.json` reported six present artifacts from accept through close with hashes, missing publish/sync rows, `awaiting-publication` / `bifrost-publication-missing`, and no private-state exposure. The next cut is richer model-authored safe families or published/credited proof-bundle depth, not another local proof-bundle wrapper. - 2026-06-20: Published/credited proof-bundle rows are live. `epiphany-work overview` now adds `publicationRows` to `epiphany.repo_work_proof_bundle.v0`, lifting Bifrost intent/publication/GitHub/ledger/credit/PR fields, Hands commit/PR fields, and upstream-main ancestry fields from publish/sync receipts without granting publication, merge, scheduler, service lifecycle, cross-repo, or private-state authority. Disposable proof `.epiphany-smoke\checklist-note-20260620-031347\12-overview-published-proof.json` ran close -> publish -> sync -> overview after the checklist safe-family proof; overview reported `complete-or-awaiting-new-work`, `upstreamMainSynced=true` from `authority.upstreamMainSynced`, three publication rows, and `privateStateExposed=false`. The next cut is richer public/export packaging outside the local bundle or model-authored closure, not basic Bifrost/GitHub/sync row visibility. - 2026-06-20: Public proof export is live. `epiphany-work export-proof` calls overview, distills the local `epiphany.repo_work_proof_bundle.v0` into redacted `epiphany.repo_work_public_proof_bundle.v0`, and writes `.epiphany/public/proof-bundles/repo-work-public-proof-.json` by default without raw receipt bodies, local receipt paths, expected paths, worker thought, publication authority, or private Verse exposure. Disposable proof `.epiphany-smoke\checklist-note-20260620-031347\13-export-proof.json` reported eight artifact rows, three publication rows, zero artifact path fields, `rawReceiptBodies=false`, and `private=false`. The next cut is Bifrost/public Verse transport for exported proof, richer model-authored safe-family breadth, or richer model-authored closure; not another local public-proof export wrapper. +- 2026-06-20: Public proof local Verse transport is live. `epiphany-work export-proof --local-verse-store \.epiphany\local-verse.ccmp` now mirrors each redacted export as `epiphany.cultmesh.repo_work_public_proof.v0` under `gamecult-local/repo-work-public-proof/latest`, with compact `PUBLIC-PROOF` TUI rows, artifact/publication row counts, public proof artifact ref, SHA-256, upstream-main sync truth, and `privateStateExposed=false`. `epiphany-verse-query swarm-overview` reads those rows as `repoWorkPublicProofRows` / `repoWorkPublicProofTuiRows`, exposes `latestRepoWorkPublicProof`, and adds non-mutating/non-elevated `repo-work-public-proof` action rows owned by Gjallar sight while Bifrost still owns publication/credit consequence. Disposable proofs `.epiphany-smoke\checklist-note-20260620-031347\14-export-proof-verse.json` and `15-swarm-overview-public-proof.json` reported latest `repo-work-public-proof-checklist-request`, one public proof row, one action row, SHA-256 `e781e09c2ba340c8818d3ef95e54085ccd0c92c6a3b5f73cc4878fb224e49dff`, `mutates=false`, `elevated=false`, and `private=false`. The next cut is Bifrost/public publication transport beyond local Verse, richer safe-family breadth, or richer model-authored closure. - 2026-06-20: Gjallar/swarm-overview now exposes repo-work overview history as first-class compact sight, Persona's public Eve surface lowers the same queue for peer-readable collaboration, and Self has a first runnable queue surface over it. `SwarmOverviewOutput` and `SwarmTriageOutput` include `repoWorkOverviewCount`, `repoWorkOverviewRows`, `repoWorkOverviewTuiRows`, `latestRepoWorkOverview`, `latestRepoWorkGate`, `latestRepoWorkBlocker`, and `latestRepoWorkNextSafeMove`; the shared `swarmActionRows` queue gets priority 35 `repo-work-overview` rows owned by Gjallar, hosted body `repo-work`, authority gate `repo.work.overview`, effect class `repo-work-readback`, no mutation, no elevation, proof-bundle ref, and private-state seal. `eve-surfaces`, direct `connect-eve`, and the globally invokable Persona `eve-connect` daemon tool readback expose public `REPO-WORK-PEER` rows with item, gate, blocker, next safe move, branch, publication, sync, and `private=false`. `epiphany-work queue-run` reads the same typed queue, selects current-repo rows at `ready-to-run`, `ready-to-adopt`, `ready-to-execute`, or `awaiting-closure`, delegates to `tick`, refreshes overview after real advancement, and wrapper `repo-work-queue-run` exposes the operator surface. Disposable proofs `.epiphany-smoke\gjallar-repo-work-queue-20260620-012027`, `.epiphany-smoke\eve-repo-work-queue-20260620-013322`, `.epiphany-smoke\queue-run-20260620-014314`, and wrapper artifact `local-20260620-014627-174-aada0241` prove two-item queue sight, Eve lowering, direct queue-run advancement, and wrapper dry-run without publication, merge, service lifecycle mutation, elevation, cross-repo mutation, or private-state exposure. The next cut is richer Persona-to-Imagination plan derivation, not another queue display surface. - `service-execution-runbook` makes that next cut repeatable: it generates the exact elevated wrapper command sequence without mutating the service manager, continues after per-step failure to preserve more receipts, runs `service-execution-audit` in `finally`, exits nonzero if any step failed, and seals a typed runbook lifecycle receipt. Run the generated artifact only with explicit operator authority. - `service-execution-audit` is the non-mutating acceptance proof after the elevated rite: it reports `complete` only when typed lifecycle receipts prove the runbook witness plus expected elevated chain, and otherwise reports the missing/failed sealed checks. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 2a3b1c6a4a98a33cb18d1b04ca337faa3678fabb..428dd4d1806f83d9c482604842dc8bc32468dd9b 100644 GIT binary patch delta 525 zcmY+A!EVz)5Qgh?PxKfG5K*O(xO#)*tQ)5lz4TlTa6?FBy&gA99Iv~(vALj1?SUr< zehLH?5=cA%XAnq8z>PBpo`7!RR;Y*7YG%Hf|DQR1-TimoeS6#6V&N`hk3VgY@4w#N z^^QHSced=jTy{M7R{!RQWrzIv+H5}{H=57y2_dc_Y|cM=J^x4N@FA88YNcmTE|Odd zD78`<;PX;xYoJgy%%#>!H^0A;{jMymf?Nrn!@(lAhiInF-!}wqw%t$H-Tf-?p_X`@7IeO_+{)tUQkk~OTv(}!HQ9$pb2UTL{QN@hoje&Z z+S+PKTA?=Be`XxL8aarlskxq09RqOqXe?sT>LHIj-cidim= zr5cYH4)j44cyj$fZj*Hy{`>X8OnDgX0FL4T24fK>e8>V3$AdT>Vm6L2VnG}Ukp^NM xiXA>oqHHu2g2kgaOTv&L8>d<3!}>I6?q@tV=mX|h-Ep4Nt3;_~<>EH%UjSH9x- adopt-from-plan -> execute-from-plan -> close-from-execute` then no-ops before publication gates, local CultMesh swarm-brake refusal that writes `refused-by-swarm-brake` without creating a run/adopt/execute/close receipt, active-turn refusal through `work-tick-active-.json`, explicit completion-anchored cooldown refusal through `work-tick-last-.json`, stale active-turn recovery that records `physiology.recoveredActiveTurn.recovered=true`, Self-owned `epiphany-work serve` cadence that writes `work-scheduler-serve-.json`, bounded serve proof `advanced:run-from-plan -> refused-by-cooldown:none` without adoption, unbounded zero-interval refusal, deterministic `epiphany-work close` proof that consumes execute receipts, verifies the Hands commit, writes Soul verdict plus Modeling summary plus Mind gateway/state-commit receipts, scheduler proof `.epiphany-smoke\tick-close-20260620-025526` that `epiphany-swarm run --max-iterations 4` reached `awaiting-publication` through `close-from-execute` with Soul passed and Mind committed, local `epiphany-work overview` proof bundle `epiphany.repo_work_proof_bundle.v0` that reports pre-plan `awaiting-plan`/`plan-receipt-missing` and post-close `awaiting-publication`/`bifrost-publication-missing` with branch, commit, changed paths, Soul verdict, compact TUI rows, expected receipt artifact paths, present/missing artifact statuses, document schemas/statuses, SHA-256 receipt hashes, publication rows for Bifrost/GitHub/credit/PR/upstream-main sync, and private seals, public `epiphany-work export-proof` packaging that writes redacted `epiphany.repo_work_public_proof_bundle.v0` artifacts without local receipt paths, raw receipt bodies, worker thought, or private Verse exposure, typed local Verse projection as `epiphany.cultmesh.repo_work_overview.v0` with latest-key/event-history readback through Gjallar plus peer-readable Persona Eve lowering, `epiphany-work queue-run` selection over tick-actionable queue rows through `awaiting-closure` with wrapper `repo-work-queue-run`, Idunn-owned non-mutating `repo-work-service-plan`/`repo-work-service-runbook` receipts for the same queue-run command, `publish --closure-receipt` consumption of the close receipt's Soul/Mind refs, post-publication tick `noop:none`, and upstream-main ancestry proof after explicit merge receipt. Remaining MVP organs are deeper model-authored safe-family breadth, Bifrost/public Verse transport for exported proof, and richer model-authored closure; the scheduler may advance only one safe receipt-backed branch-local step per pulse and must not publish, merge, mutate services, cross repo boundaries, expose private state, or impersonate Idunn. + - Use `notes/epiphany-repo-swarm-mvp-contract.md` as the authority correction and migration plan for repo-swarm autonomy. Autonomous branch-local work inside an Epiphany-owned repo Body is in scope and desired; the safety boundary is typed authority, branch containment, interruptibility, receipts, private-state sealing, and Bifrost-gated publication/merge/escalation, not asking a human before every local edit. Seventeen native repo-swarm front doors are live and documented there: `epiphany-repo init`, `epiphany-swarm online`, `epiphany-swarm run`, `epiphany-work accept`, `epiphany-work persona-intake`, `epiphany-work derive-plan`, `epiphany-work plan`, `epiphany-work run`, `epiphany-work adopt --from-plan`, `epiphany-work execute --from-plan`, `epiphany-work close`, `epiphany-work overview`, `epiphany-work export-proof`, `epiphany-work tick`, `epiphany-work queue-run`, `epiphany-work publish`, and `epiphany-work sync`. Fresh-repo smokes proved the chain with `privateStateExposed=false`, including deterministic Persona/Bifrost pressure-to-plan derivation (`append-worklog`, `planning-note`, and `checklist-note`) into `EPIPHANY_WORKLOG.md`, contained markdown planning notes, or contained markdown checklists, typed Imagination action-item receipts (`epiphany.repo_work_imagination_action_items_receipt.v0`) that carry model provenance, safe family, requested paths, verification asks, stop conditions, escalation reasons, and `operatorAuthoredShellDetails=false` before deterministic safe-family command lowering, plan-backed branch-local commit creation, a speech-audited repo Persona intake mouth that records public discussion refs plus candidate action refs before delegating to `accept`, a bounded `epiphany-swarm run` mouth that delegates queue selection to `epiphany-work queue-run` and item actuation to `epiphany-work tick`, a Self-owned tick pulse that advances `run-from-plan -> adopt-from-plan -> execute-from-plan -> close-from-execute` then no-ops before publication gates, local CultMesh swarm-brake refusal that writes `refused-by-swarm-brake` without creating a run/adopt/execute/close receipt, active-turn refusal through `work-tick-active-.json`, explicit completion-anchored cooldown refusal through `work-tick-last-.json`, stale active-turn recovery that records `physiology.recoveredActiveTurn.recovered=true`, Self-owned `epiphany-work serve` cadence that writes `work-scheduler-serve-.json`, bounded serve proof `advanced:run-from-plan -> refused-by-cooldown:none` without adoption, unbounded zero-interval refusal, deterministic `epiphany-work close` proof that consumes execute receipts, verifies the Hands commit, writes Soul verdict plus Modeling summary plus Mind gateway/state-commit receipts, scheduler proof `.epiphany-smoke\tick-close-20260620-025526` that `epiphany-swarm run --max-iterations 4` reached `awaiting-publication` through `close-from-execute` with Soul passed and Mind committed, local `epiphany-work overview` proof bundle `epiphany.repo_work_proof_bundle.v0` that reports pre-plan `awaiting-plan`/`plan-receipt-missing` and post-close `awaiting-publication`/`bifrost-publication-missing` with branch, commit, changed paths, Soul verdict, compact TUI rows, expected receipt artifact paths, present/missing artifact statuses, document schemas/statuses, SHA-256 receipt hashes, publication rows for Bifrost/GitHub/credit/PR/upstream-main sync, and private seals, public `epiphany-work export-proof` packaging that writes redacted `epiphany.repo_work_public_proof_bundle.v0` artifacts and mirrors `epiphany.cultmesh.repo_work_public_proof.v0` rows into local Verse for Gjallar/Odin sight without local receipt paths, raw receipt bodies, worker thought, or private Verse exposure, typed local Verse projection as `epiphany.cultmesh.repo_work_overview.v0` with latest-key/event-history readback through Gjallar plus peer-readable Persona Eve lowering, `epiphany-work queue-run` selection over tick-actionable queue rows through `awaiting-closure` with wrapper `repo-work-queue-run`, Idunn-owned non-mutating `repo-work-service-plan`/`repo-work-service-runbook` receipts for the same queue-run command, `publish --closure-receipt` consumption of the close receipt's Soul/Mind refs, post-publication tick `noop:none`, and upstream-main ancestry proof after explicit merge receipt. Remaining MVP organs are deeper model-authored safe-family breadth, Bifrost/public publication transport beyond local Verse, and richer model-authored closure; the scheduler may advance only one safe receipt-backed branch-local step per pulse and must not publish, merge, mutate services, cross repo boundaries, expose private state, or impersonate Idunn. - Gjallar/swarm-overview now projects typed repo-work overview history into the compact global sight report, Persona's public Eve surface lowers the same queue for peers, and Self has a first runnable queue surface over it. `epiphany-verse-query gjallar` reads all `epiphany.cultmesh.repo_work_overview.v0` event documents from local Verse, excludes the `latest` mirror, preserves latest scalar fields, emits multi-item `repoWorkOverviewRows`/TUI rows, and publishes bounded priority 35-39 non-mutating `repo-work-overview` action rows with `owner=Gjallar`, `hostedBody=repo-work`, `authorityGate=repo.work.overview`, `mutatesState=false`, `requiresElevatedAuthority=false`, proof-bundle refs, current gate/blocker/next-safe-move, and `privateStateExposed=false`. `epiphany-verse-query eve-surfaces`, `connect-eve`, and globally invokable Persona `eve-connect` tool readbacks expose compact `REPO-WORK-PEER` rows with item, gate, blocker, next safe move, branch, publication/sync state, and private seal for the public Persona surface only. `epiphany-work queue-run` selects current-repo rows at `ready-to-run`, `ready-to-adopt`, or `ready-to-execute`, delegates action to `tick`, refreshes overview after real advancement, and writes `epiphany.repo_work_queue_run_receipt.v0`; wrapper mode `tools/epiphany_local_run.ps1 -Mode repo-work-queue-run` exposes the same surface. Disposable proofs `.epiphany-smoke\gjallar-repo-work-queue-20260620-012027`, `.epiphany-smoke\eve-repo-work-queue-20260620-013322`, `.epiphany-smoke\queue-run-20260620-014314`, and wrapper artifact `local-20260620-014627-174-aada0241` showed two-item queues through sight, public Eve, direct queue-run, and wrapper dry-run without publication, merge, service lifecycle mutation, elevation, cross-repo mutation, or private-state exposure. - Agent memory lifecycle now has a first typed v0 operation surface in `epiphany-core::agent_memory`: `AgentMemoryLifecycleOperation` can revise, retire, crystallize, prune, and merge bounded memory records after role/agent review, and `epiphany-agent-memory-store review-lifecycle|apply-lifecycle` exposes the path at the operator edge. This closes the first explicit lifecycle-operation slice from the swarm-readiness gate; it does not yet make sleep silently mutate identity or project truth. - Persona public speech now has a parent-side eligibility receipt at the Discord/Aquarium mouth edge. `epiphany.persona_speech_audit.v0` records action kind, content fingerprint, opening/topic keys, recent-window counts, repeated opening/topic counts, channel saturation, and allow/block reasons. `epiphany-persona-discord post` blocks repeated public openings before token/webhook work; draft and bubble still emit audit receipts for operator inspection. The compatibility JSON artifact remains for display, but the durable witness is now `epiphany.cultmesh.persona_speech_audit.v0` in CultMesh with latest-key projection through local Verse context. Local MVP Persona bubbles now write that durable witness to `.epiphany-run/cultmesh/local-verse.ccmp`, not a separate mouth-side store. This is posting-edge policy, not a Persona prompt wish. @@ -634,4 +634,4 @@ current_status: - `tools/epiphany_local_run.ps1 -Mode swarm-online-runbook` now emits an explicit Idunn preflight summary before the operator elevation boundary. Its JSON and one-line summary report `preflightStatus`, child artifact present/hash-verified/mismatch/missing counts, aggregate service execution failed/missing check counts, child preflight rows with expected/actual SHA-256s, and private-state exposure. Live proof `local-20260619-025627-410-9724e2f6` generated the non-mutating parent artifact with `preflightStatus=ready-for-elevated-operator`, two child runbooks present, two hashes verified, zero mismatches, zero missing artifacts, eleven failed sealed service checks, zero missing checks, explicit aftercare audits, and `privateStateExposed=false`. The remaining scar is still explicit elevated operator execution followed by complete Idunn audits, not missing parent/child artifact readiness. - 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. - next_action: Continue repo-swarm MVP work from the documented Epiphany Online cut order in `notes/epiphany-repo-swarm-mvp-contract.md`. Typed Gjallar repo-work history/queue sight, peer-readable Persona Eve lowering, Self-owned `epiphany-work queue-run`, bounded `epiphany-swarm run`, execute-to-close scheduler handoff through `close-from-execute`, deterministic `derive-plan` families `append-worklog`, `planning-note`, and `checklist-note`, typed Imagination action-item receipts over allowlisted safe families, hash-backed local proof bundles with Bifrost/GitHub/credit/PR/upstream-main publication rows, redacted `epiphany-work export-proof` public bundles, Idunn-hosted non-mutating queue-run lifecycle plan/runbook receipts, and the speech-audited `epiphany-work persona-intake` mouth plus wrapper `repo-persona-intake` are live with `privateStateExposed=false`; the next cut is Bifrost/public Verse transport for exported proof, deeper model-authored safe-family breadth, or richer model-authored closure. Preserve Idunn service lifecycle ownership and existing CultMesh/Odin/Eve tool directories; service install/start execution still requires explicit elevated operator authority. + next_action: Continue repo-swarm MVP work from the documented Epiphany Online cut order in `notes/epiphany-repo-swarm-mvp-contract.md`. Typed Gjallar repo-work history/queue sight, peer-readable Persona Eve lowering, Self-owned `epiphany-work queue-run`, bounded `epiphany-swarm run`, execute-to-close scheduler handoff through `close-from-execute`, deterministic `derive-plan` families `append-worklog`, `planning-note`, and `checklist-note`, typed Imagination action-item receipts over allowlisted safe families, hash-backed local proof bundles with Bifrost/GitHub/credit/PR/upstream-main publication rows, redacted `epiphany-work export-proof` public bundles plus local Verse `epiphany.cultmesh.repo_work_public_proof.v0` Gjallar readback, Idunn-hosted non-mutating queue-run lifecycle plan/runbook receipts, and the speech-audited `epiphany-work persona-intake` mouth plus wrapper `repo-persona-intake` are live with `privateStateExposed=false`; the next cut is Bifrost/public publication transport beyond local Verse, deeper model-authored safe-family breadth, or richer model-authored closure. Preserve Idunn service lifecycle ownership and existing CultMesh/Odin/Eve tool directories; service install/start execution still requires explicit elevated operator authority.