Add repo work readiness sight
This commit is contained in:
parent
59430685be
commit
bce9e192ae
6 changed files with 869 additions and 35 deletions
431
epiphany-core/src/bin/epiphany-repo-work-readiness-smoke.rs
Normal file
431
epiphany-core/src/bin/epiphany-repo-work-readiness-smoke.rs
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
use anyhow::anyhow;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use chrono::Utc;
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse()?;
|
||||
let result = run_smoke(args)?;
|
||||
println!("{}", serde_json::to_string_pretty(&result)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Args {
|
||||
root: PathBuf,
|
||||
smoke_root: PathBuf,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
fn parse() -> Result<Self> {
|
||||
let mut root = env::current_dir().context("failed to resolve current directory")?;
|
||||
let mut smoke_root = root.join(".epiphany-smoke");
|
||||
let mut args = env::args().skip(1).peekable();
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"--root" => root = take_path(&mut args, "--root")?,
|
||||
"--smoke-root" => smoke_root = take_path(&mut args, "--smoke-root")?,
|
||||
other => return Err(anyhow!("unexpected argument {other:?}")),
|
||||
}
|
||||
}
|
||||
Ok(Self { root, smoke_root })
|
||||
}
|
||||
}
|
||||
|
||||
fn run_smoke(args: Args) -> Result<Value> {
|
||||
let root = args
|
||||
.root
|
||||
.canonicalize()
|
||||
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
|
||||
let manifest = root.join("epiphany-core").join("Cargo.toml");
|
||||
if !manifest.exists() {
|
||||
return Err(anyhow!(
|
||||
"could not find epiphany-core manifest at {}",
|
||||
manifest.display()
|
||||
));
|
||||
}
|
||||
fs::create_dir_all(&args.smoke_root)
|
||||
.with_context(|| format!("failed to create {}", args.smoke_root.display()))?;
|
||||
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
|
||||
let smoke_dir = args.smoke_root.join(format!("repo-work-readiness-{stamp}"));
|
||||
if smoke_dir.exists() {
|
||||
fs::remove_dir_all(&smoke_dir)
|
||||
.with_context(|| format!("failed to clear {}", smoke_dir.display()))?;
|
||||
}
|
||||
fs::create_dir_all(&smoke_dir)
|
||||
.with_context(|| format!("failed to create {}", smoke_dir.display()))?;
|
||||
|
||||
let repo = smoke_dir.join("repo-body");
|
||||
fs::create_dir_all(&repo).with_context(|| format!("failed to create {}", repo.display()))?;
|
||||
git(["init"], &repo)?;
|
||||
git(
|
||||
["config", "user.email", "epiphany-smoke@example.invalid"],
|
||||
&repo,
|
||||
)?;
|
||||
git(["config", "user.name", "Epiphany Smoke"], &repo)?;
|
||||
fs::write(
|
||||
repo.join("README.md"),
|
||||
"# Repo Work Readiness Smoke\n\nThis repository proves readiness sight without readiness approval.\n",
|
||||
)
|
||||
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
|
||||
git(["add", "README.md"], &repo)?;
|
||||
git(
|
||||
["commit", "-m", "Seed repo work readiness smoke body"],
|
||||
&repo,
|
||||
)?;
|
||||
git(["switch", "-c", "epiphany/repo-work-readiness"], &repo)?;
|
||||
|
||||
let item = "repo-work-readiness";
|
||||
let local_verse = repo.join(".epiphany").join("local-verse.ccmp");
|
||||
cargo_json(
|
||||
&manifest,
|
||||
"epiphany-repo",
|
||||
&[
|
||||
"init",
|
||||
"--workspace",
|
||||
path_str(&repo)?,
|
||||
"--epiphany-root",
|
||||
path_str(&root)?,
|
||||
"--swarm-id",
|
||||
"repo-work-readiness-smoke",
|
||||
"--topic",
|
||||
"repo-work-readiness",
|
||||
],
|
||||
&root,
|
||||
)?;
|
||||
cargo_json(
|
||||
&manifest,
|
||||
"epiphany-swarm",
|
||||
&[
|
||||
"online",
|
||||
"--workspace",
|
||||
path_str(&repo)?,
|
||||
"--epiphany-root",
|
||||
path_str(&root)?,
|
||||
"--runtime-id",
|
||||
"repo-work-readiness-smoke",
|
||||
"--local-verse-store",
|
||||
path_str(&local_verse)?,
|
||||
],
|
||||
&root,
|
||||
)?;
|
||||
cargo_json(
|
||||
&manifest,
|
||||
"epiphany-work",
|
||||
&[
|
||||
"accept",
|
||||
"--workspace",
|
||||
path_str(&repo)?,
|
||||
"--from",
|
||||
"persona",
|
||||
"--item",
|
||||
item,
|
||||
"--summary",
|
||||
"Prove repo-work readiness sight can name missing publication and lifecycle gates without granting authority.",
|
||||
"--candidate-action-ref",
|
||||
"candidate-action://repo-work-readiness/checklist",
|
||||
"--public-discussion-ref",
|
||||
"epiphany-global/persona-collaboration/repo-work-readiness",
|
||||
],
|
||||
&root,
|
||||
)?;
|
||||
cargo_json(
|
||||
&manifest,
|
||||
"epiphany-work",
|
||||
&[
|
||||
"derive-plan",
|
||||
"--workspace",
|
||||
path_str(&repo)?,
|
||||
"--item",
|
||||
item,
|
||||
"--action-family",
|
||||
"checklist-note",
|
||||
"--model-ref",
|
||||
"repo-work-readiness-smoke-imagination-v1",
|
||||
"--model-authored",
|
||||
],
|
||||
&root,
|
||||
)?;
|
||||
for _ in 0..4 {
|
||||
cargo_json(
|
||||
&manifest,
|
||||
"epiphany-work",
|
||||
&[
|
||||
"tick",
|
||||
"--workspace",
|
||||
path_str(&repo)?,
|
||||
"--epiphany-root",
|
||||
path_str(&root)?,
|
||||
"--item",
|
||||
item,
|
||||
"--cooldown-seconds",
|
||||
"0",
|
||||
],
|
||||
&root,
|
||||
)?;
|
||||
}
|
||||
cargo_json(
|
||||
&manifest,
|
||||
"epiphany-work",
|
||||
&[
|
||||
"queue-run",
|
||||
"--workspace",
|
||||
path_str(&repo)?,
|
||||
"--local-verse-store",
|
||||
path_str(&local_verse)?,
|
||||
"--runtime-id",
|
||||
"repo-work-readiness-smoke",
|
||||
"--max-items",
|
||||
"1",
|
||||
"--dry-run",
|
||||
],
|
||||
&root,
|
||||
)?;
|
||||
let public_proof = cargo_json(
|
||||
&manifest,
|
||||
"epiphany-work",
|
||||
&[
|
||||
"export-proof",
|
||||
"--workspace",
|
||||
path_str(&repo)?,
|
||||
"--item",
|
||||
item,
|
||||
"--local-verse-store",
|
||||
path_str(&local_verse)?,
|
||||
"--runtime-id",
|
||||
"repo-work-readiness-smoke",
|
||||
],
|
||||
&root,
|
||||
)?;
|
||||
let readiness = cargo_json(
|
||||
&manifest,
|
||||
"epiphany-work",
|
||||
&["readiness", "--workspace", path_str(&repo)?, "--item", item],
|
||||
&root,
|
||||
)?;
|
||||
|
||||
require_eq(
|
||||
&readiness,
|
||||
&["schemaVersion"],
|
||||
"epiphany.repo_work_readiness.v0",
|
||||
)?;
|
||||
require_eq(&readiness, &["status"], "not-ready")?;
|
||||
require_u64(&readiness, &["missingRequiredCount"], 4)?;
|
||||
require_bool(&readiness, &["authority", "sightOnly"], true)?;
|
||||
require_bool(
|
||||
&readiness,
|
||||
&["authority", "readinessApprovalAuthorized"],
|
||||
false,
|
||||
)?;
|
||||
require_bool(&readiness, &["authority", "publicationAuthorized"], false)?;
|
||||
require_bool(&readiness, &["authority", "deploymentAuthority"], false)?;
|
||||
require_bool(
|
||||
&readiness,
|
||||
&["authority", "serviceLifecycleAuthority"],
|
||||
false,
|
||||
)?;
|
||||
require_bool(&readiness, &["authority", "handsActionAuthorized"], false)?;
|
||||
require_bool(&readiness, &["authority", "privateStateExposed"], false)?;
|
||||
require_row(&readiness, "repo-init", true)?;
|
||||
require_row(&readiness, "swarm-online", true)?;
|
||||
require_row(&readiness, "persona-intake", true)?;
|
||||
require_row(&readiness, "imagination-plan", true)?;
|
||||
require_row(&readiness, "self-queue-run", true)?;
|
||||
require_row(&readiness, "hands-branch-work", true)?;
|
||||
require_row(&readiness, "soul-closure", true)?;
|
||||
require_row(&readiness, "modeling-mind-admission", true)?;
|
||||
require_row(&readiness, "public-proof", true)?;
|
||||
require_row(&readiness, "bifrost-publication", false)?;
|
||||
require_row(&readiness, "upstream-main-sync", false)?;
|
||||
require_row(&readiness, "idunn-lifecycle", false)?;
|
||||
require_row(&readiness, "tool-directory", false)?;
|
||||
require_row(&readiness, "private-state-redaction", true)?;
|
||||
|
||||
let summary = json!({
|
||||
"schemaVersion": "epiphany.repo_work_readiness_smoke.v0",
|
||||
"status": "ok",
|
||||
"smokeDir": smoke_dir,
|
||||
"repo": repo,
|
||||
"branch": git_output(["branch", "--show-current"], &repo)?,
|
||||
"item": item,
|
||||
"publicProofOutput": public_proof["outputPath"],
|
||||
"readinessStatus": readiness["status"],
|
||||
"missingRequiredCount": readiness["missingRequiredCount"],
|
||||
"sightOnly": readiness["authority"]["sightOnly"],
|
||||
"readinessApprovalAuthorized": readiness["authority"]["readinessApprovalAuthorized"],
|
||||
"publicationAuthorized": readiness["authority"]["publicationAuthorized"],
|
||||
"deploymentAuthority": readiness["authority"]["deploymentAuthority"],
|
||||
"serviceLifecycleAuthority": readiness["authority"]["serviceLifecycleAuthority"],
|
||||
"handsActionAuthorized": readiness["authority"]["handsActionAuthorized"],
|
||||
"privateStateExposed": readiness["privateStateExposed"],
|
||||
});
|
||||
write_json(&smoke_dir.join("summary.json"), &summary)?;
|
||||
Ok(summary)
|
||||
}
|
||||
|
||||
fn cargo_json(manifest: &Path, bin: &str, args: &[&str], cwd: &Path) -> Result<Value> {
|
||||
let output = Command::new("cargo")
|
||||
.arg("run")
|
||||
.arg("--quiet")
|
||||
.arg("--manifest-path")
|
||||
.arg(manifest)
|
||||
.arg("--bin")
|
||||
.arg(bin)
|
||||
.arg("--")
|
||||
.args(args)
|
||||
.current_dir(cwd)
|
||||
.output()
|
||||
.with_context(|| format!("failed to run cargo bin {bin}"))?;
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!(
|
||||
"{bin} failed with status {:?}\nstdout:\n{}\nstderr:\n{}",
|
||||
output.status.code(),
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
));
|
||||
}
|
||||
serde_json::from_slice(&output.stdout).with_context(|| {
|
||||
format!(
|
||||
"{bin} did not emit JSON on stdout:\n{}",
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn git<const N: usize>(args: [&str; N], cwd: &Path) -> Result<()> {
|
||||
let output = Command::new("git")
|
||||
.args(args)
|
||||
.current_dir(cwd)
|
||||
.output()
|
||||
.with_context(|| format!("failed to run git in {}", cwd.display()))?;
|
||||
if output.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"git failed in {} with status {:?}\nstdout:\n{}\nstderr:\n{}",
|
||||
cwd.display(),
|
||||
output.status.code(),
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn git_output<const N: usize>(args: [&str; N], cwd: &Path) -> Result<String> {
|
||||
let output = Command::new("git")
|
||||
.args(args)
|
||||
.current_dir(cwd)
|
||||
.output()
|
||||
.with_context(|| format!("failed to run git in {}", cwd.display()))?;
|
||||
if output.status.success() {
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"git failed in {} with status {:?}\nstdout:\n{}\nstderr:\n{}",
|
||||
cwd.display(),
|
||||
output.status.code(),
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn write_json(path: &Path, value: &Value) -> Result<()> {
|
||||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent)
|
||||
.with_context(|| format!("failed to create {}", parent.display()))?;
|
||||
}
|
||||
fs::write(path, serde_json::to_vec_pretty(value)?)
|
||||
.with_context(|| format!("failed to write {}", path.display()))
|
||||
}
|
||||
|
||||
fn require_eq(value: &Value, path: &[&str], expected: &str) -> Result<()> {
|
||||
let actual = path
|
||||
.iter()
|
||||
.try_fold(value, |current, key| current.get(*key))
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("<missing>");
|
||||
if actual == expected {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"expected {} to be {expected:?}, got {actual:?}",
|
||||
path.join(".")
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn require_u64(value: &Value, path: &[&str], expected: u64) -> Result<()> {
|
||||
let actual = path
|
||||
.iter()
|
||||
.try_fold(value, |current, key| current.get(*key))
|
||||
.and_then(Value::as_u64)
|
||||
.unwrap_or(u64::MAX);
|
||||
if actual == expected {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"expected {} to be {expected:?}, got {actual:?}",
|
||||
path.join(".")
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn require_bool(value: &Value, path: &[&str], expected: bool) -> Result<()> {
|
||||
let actual = path
|
||||
.iter()
|
||||
.try_fold(value, |current, key| current.get(*key))
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(!expected);
|
||||
if actual == expected {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"expected {} to be {expected:?}, got {actual:?}",
|
||||
path.join(".")
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn require_row(value: &Value, kind: &str, expected_satisfied: 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("satisfied")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(!expected_satisfied);
|
||||
if actual == expected_satisfied {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"expected readiness row {kind:?} satisfied={expected_satisfied}, got {actual}"
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn take_path(
|
||||
args: &mut std::iter::Peekable<impl Iterator<Item = String>>,
|
||||
flag: &str,
|
||||
) -> Result<PathBuf> {
|
||||
args.next()
|
||||
.map(PathBuf::from)
|
||||
.with_context(|| format!("missing value for {flag}"))
|
||||
}
|
||||
|
||||
fn path_str(path: &Path) -> Result<&str> {
|
||||
path.to_str()
|
||||
.ok_or_else(|| anyhow!("path is not valid UTF-8: {}", path.display()))
|
||||
}
|
||||
|
|
@ -1,30 +1,8 @@
|
|||
use anyhow::anyhow;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use anyhow::anyhow;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_MAP_ENTRY_LATEST_KEY;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_MAP_ENTRY_SCHEMA_VERSION;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_SCHEMA_VERSION;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION;
|
||||
use epiphany_core::EpiphanyCultMeshRepoWorkMapEntry;
|
||||
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;
|
||||
use epiphany_core::HANDS_PATCH_RECEIPT_TYPE;
|
||||
use epiphany_core::HANDS_PR_RECEIPT_TYPE;
|
||||
use epiphany_core::HandsActionIntent;
|
||||
use epiphany_core::MIND_GATEWAY_REVIEW_SCHEMA_VERSION;
|
||||
use epiphany_core::MindGatewayDecision;
|
||||
use epiphany_core::MindGatewayReview;
|
||||
use epiphany_core::RuntimeSpineInitOptions;
|
||||
use epiphany_core::SOUL_VERDICT_RECEIPT_SCHEMA_VERSION;
|
||||
use epiphany_core::SUBSTRATE_GATE_REPO_ACCESS_GRANT_RECEIPT_SCHEMA_VERSION;
|
||||
use epiphany_core::SoulVerdictReceipt;
|
||||
use epiphany_core::SubstrateGateRepoAccessGrantReceipt;
|
||||
use epiphany_core::hands_action_review_for_intent;
|
||||
use epiphany_core::hands_command_receipt_for_review;
|
||||
use epiphany_core::hands_commit_receipt_for_review;
|
||||
|
|
@ -56,10 +34,32 @@ use epiphany_core::runtime_latest_hands_receipt_chain_after;
|
|||
use epiphany_core::write_epiphany_cultmesh_repo_work_map_entry;
|
||||
use epiphany_core::write_epiphany_cultmesh_repo_work_overview;
|
||||
use epiphany_core::write_epiphany_cultmesh_repo_work_public_proof;
|
||||
use epiphany_core::EpiphanyCultMeshRepoWorkMapEntry;
|
||||
use epiphany_core::EpiphanyCultMeshRepoWorkOverviewEntry;
|
||||
use epiphany_core::EpiphanyCultMeshRepoWorkPublicProofEntry;
|
||||
use epiphany_core::HandsActionIntent;
|
||||
use epiphany_core::MindGatewayDecision;
|
||||
use epiphany_core::MindGatewayReview;
|
||||
use epiphany_core::RuntimeSpineInitOptions;
|
||||
use epiphany_core::SoulVerdictReceipt;
|
||||
use epiphany_core::SubstrateGateRepoAccessGrantReceipt;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_MAP_ENTRY_LATEST_KEY;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_MAP_ENTRY_SCHEMA_VERSION;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_OVERVIEW_SCHEMA_VERSION;
|
||||
use epiphany_core::EPIPHANY_CULTMESH_REPO_WORK_PUBLIC_PROOF_SCHEMA_VERSION;
|
||||
use epiphany_core::HANDS_ACTION_INTENT_SCHEMA_VERSION;
|
||||
use epiphany_core::HANDS_COMMAND_RECEIPT_TYPE;
|
||||
use epiphany_core::HANDS_COMMIT_RECEIPT_TYPE;
|
||||
use epiphany_core::HANDS_PATCH_RECEIPT_TYPE;
|
||||
use epiphany_core::HANDS_PR_RECEIPT_TYPE;
|
||||
use epiphany_core::MIND_GATEWAY_REVIEW_SCHEMA_VERSION;
|
||||
use epiphany_core::SOUL_VERDICT_RECEIPT_SCHEMA_VERSION;
|
||||
use epiphany_core::SUBSTRATE_GATE_REPO_ACCESS_GRANT_RECEIPT_SCHEMA_VERSION;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
use sha2::Digest;
|
||||
use sha2::Sha256;
|
||||
use std::env;
|
||||
|
|
@ -124,6 +124,9 @@ fn main() -> Result<()> {
|
|||
"publish" => run_publish(parse_publish_args(args)?),
|
||||
"sync" | "sync-main" => run_sync(parse_sync_args(args)?),
|
||||
"overview" | "proof-bundle" | "status" => run_overview(parse_overview_args(args)?),
|
||||
"readiness" | "readiness-report" | "mvp-readiness" => {
|
||||
run_readiness(parse_readiness_args(args)?)
|
||||
}
|
||||
"deployment-config-audit" | "audit-deployment-config" | "idunn-deployment-audit" => {
|
||||
run_deployment_config_audit(parse_deployment_config_audit_args(args)?)
|
||||
}
|
||||
|
|
@ -334,6 +337,18 @@ struct OverviewArgs {
|
|||
write_receipt: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ReadinessArgs {
|
||||
workspace: PathBuf,
|
||||
item: Option<String>,
|
||||
accept_receipt: Option<PathBuf>,
|
||||
artifact_dir: Option<PathBuf>,
|
||||
public_proof: Option<PathBuf>,
|
||||
idunn_lifecycle_receipt: Option<PathBuf>,
|
||||
tool_directory_receipt: Option<PathBuf>,
|
||||
write_receipt: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct DeploymentConfigAuditArgs {
|
||||
workspace: PathBuf,
|
||||
|
|
@ -1134,6 +1149,48 @@ fn parse_overview_args(args: impl Iterator<Item = String>) -> Result<OverviewArg
|
|||
})
|
||||
}
|
||||
|
||||
fn parse_readiness_args(args: impl Iterator<Item = String>) -> Result<ReadinessArgs> {
|
||||
let mut workspace = None;
|
||||
let mut item = None;
|
||||
let mut accept_receipt = None;
|
||||
let mut artifact_dir = None;
|
||||
let mut public_proof = None;
|
||||
let mut idunn_lifecycle_receipt = None;
|
||||
let mut tool_directory_receipt = None;
|
||||
let mut write_receipt = true;
|
||||
|
||||
let mut args = args.peekable();
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"--workspace" => workspace = Some(take_path(&mut args, "--workspace")?),
|
||||
"--item" => item = Some(take_string(&mut args, "--item")?),
|
||||
"--accept-receipt" => accept_receipt = Some(take_path(&mut args, "--accept-receipt")?),
|
||||
"--artifact-dir" => artifact_dir = Some(take_path(&mut args, "--artifact-dir")?),
|
||||
"--public-proof" | "--public-proof-ref" => {
|
||||
public_proof = Some(take_path(&mut args, "--public-proof")?);
|
||||
}
|
||||
"--idunn-lifecycle-receipt" | "--service-lifecycle-receipt" => {
|
||||
idunn_lifecycle_receipt = Some(take_path(&mut args, "--idunn-lifecycle-receipt")?);
|
||||
}
|
||||
"--tool-directory-receipt" | "--tool-directory-ref" => {
|
||||
tool_directory_receipt = Some(take_path(&mut args, "--tool-directory-receipt")?);
|
||||
}
|
||||
"--no-write" | "--read-only" => write_receipt = false,
|
||||
other => return Err(anyhow!("unexpected readiness argument {other:?}")),
|
||||
}
|
||||
}
|
||||
Ok(ReadinessArgs {
|
||||
workspace: workspace.context("missing --workspace")?,
|
||||
item,
|
||||
accept_receipt,
|
||||
artifact_dir,
|
||||
public_proof,
|
||||
idunn_lifecycle_receipt,
|
||||
tool_directory_receipt,
|
||||
write_receipt,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_deployment_config_audit_args(
|
||||
args: impl Iterator<Item = String>,
|
||||
) -> Result<DeploymentConfigAuditArgs> {
|
||||
|
|
@ -1467,9 +1524,9 @@ fn run_accept(args: AcceptArgs) -> Result<Value> {
|
|||
.join("swarm-online")
|
||||
.join("repo-swarm-online-receipt.json")
|
||||
});
|
||||
let online_receipt = read_json(&online_receipt_path).with_context(
|
||||
|| "repo swarm online receipt is required; run epiphany-swarm online first",
|
||||
)?;
|
||||
let online_receipt = read_json(&online_receipt_path).with_context(|| {
|
||||
"repo swarm online receipt is required; run epiphany-swarm online first"
|
||||
})?;
|
||||
let local_verse_store = args.local_verse_store.unwrap_or_else(|| {
|
||||
path_from_json(&online_receipt, &["localVerseStore"])
|
||||
.unwrap_or_else(|| workspace.join(".epiphany").join("local-verse.ccmp"))
|
||||
|
|
@ -1630,9 +1687,9 @@ fn run_persona_intake(args: PersonaIntakeArgs) -> Result<Value> {
|
|||
.join("swarm-online")
|
||||
.join("repo-swarm-online-receipt.json")
|
||||
});
|
||||
let online_receipt = read_json(&online_receipt_path).with_context(
|
||||
|| "repo swarm online receipt is required; run epiphany-swarm online first",
|
||||
)?;
|
||||
let online_receipt = read_json(&online_receipt_path).with_context(|| {
|
||||
"repo swarm online receipt is required; run epiphany-swarm online first"
|
||||
})?;
|
||||
let local_verse_store = args.local_verse_store.clone().unwrap_or_else(|| {
|
||||
path_from_json(&online_receipt, &["localVerseStore"])
|
||||
.unwrap_or_else(|| workspace.join(".epiphany").join("local-verse.ccmp"))
|
||||
|
|
@ -8391,8 +8448,7 @@ fn closure_family_assertions(
|
|||
&mut assertions,
|
||||
"readiness-review-request-private-seal",
|
||||
content.contains("private_state_exposed = false"),
|
||||
"Committed readiness review request preserves the private-state seal."
|
||||
.to_string(),
|
||||
"Committed readiness review request preserves the private-state seal.".to_string(),
|
||||
);
|
||||
}
|
||||
"repo.doctrine_update_request" => {
|
||||
|
|
@ -11923,6 +11979,282 @@ fn run_overview(args: OverviewArgs) -> Result<Value> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn run_readiness(args: ReadinessArgs) -> Result<Value> {
|
||||
let workspace = args
|
||||
.workspace
|
||||
.canonicalize()
|
||||
.with_context(|| format!("failed to resolve {}", args.workspace.display()))?;
|
||||
ensure_git_repo(&workspace)?;
|
||||
let artifact_dir = args
|
||||
.artifact_dir
|
||||
.clone()
|
||||
.unwrap_or_else(|| workspace.join(".epiphany").join("work"));
|
||||
fs::create_dir_all(&artifact_dir)
|
||||
.with_context(|| format!("failed to create {}", artifact_dir.display()))?;
|
||||
|
||||
let overview = run_overview(OverviewArgs {
|
||||
workspace: workspace.clone(),
|
||||
item: args.item.clone(),
|
||||
accept_receipt: args.accept_receipt.clone(),
|
||||
artifact_dir: Some(artifact_dir.clone()),
|
||||
write_receipt: args.write_receipt,
|
||||
})?;
|
||||
let item = overview
|
||||
.get("item")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("work-item")
|
||||
.to_string();
|
||||
let item_slug = sanitize(&item);
|
||||
let accept_receipt_path = resolve_accept_receipt(&workspace, Some(&item), args.accept_receipt)?;
|
||||
let plan_receipt_path = work_receipt_path(&workspace, "plan", &item);
|
||||
let execute_receipt_path = work_receipt_path(&workspace, "execute", &item);
|
||||
let close_receipt_path = work_receipt_path(&workspace, "close", &item);
|
||||
let queue_run_receipt_path = artifact_dir.join("work-queue-run.json");
|
||||
let publish_receipt_path = work_receipt_path(&workspace, "publish", &item);
|
||||
let sync_receipt_path = work_receipt_path(&workspace, "sync", &item);
|
||||
let init_receipt_path = workspace
|
||||
.join(".epiphany")
|
||||
.join("repo-init")
|
||||
.join("repo-swarm-init-receipt.json");
|
||||
let online_receipt_path = workspace
|
||||
.join(".epiphany")
|
||||
.join("swarm-online")
|
||||
.join("repo-swarm-online-receipt.json");
|
||||
let public_proof_path = args.public_proof.unwrap_or_else(|| {
|
||||
workspace
|
||||
.join(".epiphany")
|
||||
.join("public")
|
||||
.join("proof-bundles")
|
||||
.join(format!("repo-work-public-proof-{item_slug}.json"))
|
||||
});
|
||||
let readiness_receipt_path = artifact_dir.join(format!("work-readiness-{item_slug}.json"));
|
||||
|
||||
let close_receipt = read_json_if_exists(&close_receipt_path)?;
|
||||
let close_status = close_receipt
|
||||
.as_ref()
|
||||
.and_then(|receipt| receipt.get("status").and_then(Value::as_str));
|
||||
let soul_passed = close_receipt
|
||||
.as_ref()
|
||||
.and_then(|receipt| string_from_json(receipt, &["soul", "verdict"]))
|
||||
.as_deref()
|
||||
== Some("passed");
|
||||
let modeling_map_admitted = close_receipt
|
||||
.as_ref()
|
||||
.and_then(|receipt| bool_from_json(receipt, &["authority", "durableStateAdmitted"]))
|
||||
.unwrap_or(false)
|
||||
|| close_receipt
|
||||
.as_ref()
|
||||
.and_then(|receipt| string_from_json(receipt, &["mind", "stateCommitReceiptId"]))
|
||||
.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(
|
||||
"repo-init",
|
||||
"Self",
|
||||
"epiphany.repo_swarm_init_receipt.v0",
|
||||
&init_receipt_path,
|
||||
init_receipt_path.exists(),
|
||||
"Fresh repo was initialized as an Epiphany Body.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"swarm-online",
|
||||
"Self/Gjallar",
|
||||
"epiphany.repo_swarm_online_receipt.v0",
|
||||
&online_receipt_path,
|
||||
online_receipt_path.exists(),
|
||||
"Repo-local swarm published compact CultMesh sight.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"persona-intake",
|
||||
"Persona/Imagination",
|
||||
"epiphany.repo_work_accept_receipt.v0",
|
||||
&accept_receipt_path,
|
||||
accept_receipt_path.exists(),
|
||||
"Persona or Bifrost pressure was accepted without Hands authority.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"imagination-plan",
|
||||
"Imagination",
|
||||
"epiphany.repo_work_action_plan_receipt.v0",
|
||||
&plan_receipt_path,
|
||||
plan_receipt_path.exists(),
|
||||
"Imagination produced action-item/plan cargo.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"self-queue-run",
|
||||
"Self",
|
||||
"epiphany.repo_work_queue_run_receipt.v0",
|
||||
&queue_run_receipt_path,
|
||||
queue_run_receipt_path.exists(),
|
||||
"Self queue-run pulse selected or advanced repo work.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"hands-branch-work",
|
||||
"Hands",
|
||||
"epiphany.repo_work_execute_receipt.v0",
|
||||
&execute_receipt_path,
|
||||
execute_receipt_path.exists(),
|
||||
"Hands executed branch-local work with receipts.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"soul-closure",
|
||||
"Soul",
|
||||
"epiphany.repo_work_closure_receipt.v0",
|
||||
&close_receipt_path,
|
||||
close_status == Some("closed") && soul_passed,
|
||||
"Soul passed closure for the Hands consequence.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"modeling-mind-admission",
|
||||
"Modeling/Mind",
|
||||
"epiphany.mind.state_commit_receipt",
|
||||
&close_receipt_path,
|
||||
modeling_map_admitted,
|
||||
"Modeling map update was admitted through Mind.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"public-proof",
|
||||
"Bifrost/Gjallar",
|
||||
"epiphany.repo_work_public_proof_bundle.v0",
|
||||
&public_proof_path,
|
||||
public_proof_path.exists(),
|
||||
"Redacted public proof bundle exists.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"bifrost-publication",
|
||||
"Bifrost",
|
||||
"gamecult.bifrost.publication_receipt.v0",
|
||||
&publish_receipt_path,
|
||||
publish_receipt.is_some(),
|
||||
"Bifrost/GitHub publication receipt exists.",
|
||||
)?,
|
||||
readiness_path_row(
|
||||
"upstream-main-sync",
|
||||
"Bifrost/GitHub",
|
||||
"epiphany.repo_work_sync.v0",
|
||||
&sync_receipt_path,
|
||||
upstream_synced,
|
||||
"Published commit is contained by upstream main.",
|
||||
)?,
|
||||
];
|
||||
if let Some(path) = args.idunn_lifecycle_receipt.as_ref() {
|
||||
rows.push(readiness_path_row(
|
||||
"idunn-lifecycle",
|
||||
"Idunn",
|
||||
"epiphany.cultmesh.daemon_service_lifecycle_receipt.v0",
|
||||
path,
|
||||
path.exists(),
|
||||
"Idunn lifecycle receipt was supplied for the repo-work pulse.",
|
||||
)?);
|
||||
} else {
|
||||
rows.push(readiness_missing_row(
|
||||
"idunn-lifecycle",
|
||||
"Idunn",
|
||||
"epiphany.cultmesh.daemon_service_lifecycle_receipt.v0",
|
||||
"Supply --idunn-lifecycle-receipt after Idunn service audit/readiness proof.",
|
||||
));
|
||||
}
|
||||
if let Some(path) = args.tool_directory_receipt.as_ref() {
|
||||
rows.push(readiness_path_row(
|
||||
"tool-directory",
|
||||
"Odin/Gjallar",
|
||||
"epiphany.cultmesh.daemon_tool_directory_readback.v0",
|
||||
path,
|
||||
path.exists(),
|
||||
"Global daemon tool directory readback was supplied.",
|
||||
)?);
|
||||
} else {
|
||||
rows.push(readiness_missing_row(
|
||||
"tool-directory",
|
||||
"Odin/Gjallar",
|
||||
"epiphany.cultmesh.daemon_tool_directory_readback.v0",
|
||||
"Supply --tool-directory-receipt from the compact daemon tool directory sight rite.",
|
||||
));
|
||||
}
|
||||
rows.push(json!({
|
||||
"kind": "private-state-redaction",
|
||||
"owner": "Soul/Bifrost",
|
||||
"requiredSchema": "epiphany.private_state_redaction_report.v0",
|
||||
"evidenceRef": overview["proofBundle"].get("bundleId").cloned().unwrap_or(Value::String("missing".to_string())),
|
||||
"satisfied": overview
|
||||
.get("privateStateExposed")
|
||||
.and_then(Value::as_bool)
|
||||
.map(|exposed| !exposed)
|
||||
.unwrap_or(false),
|
||||
"status": if overview.get("privateStateExposed").and_then(Value::as_bool) == Some(false) { "satisfied" } else { "missing" },
|
||||
"note": "Readiness sight observed privateStateExposed=false on overview/proof-bundle projection."
|
||||
}));
|
||||
|
||||
let missing_rows = rows
|
||||
.iter()
|
||||
.filter(|row| row.get("satisfied").and_then(Value::as_bool) != Some(true))
|
||||
.count();
|
||||
let verdict = if missing_rows == 0 {
|
||||
"ready"
|
||||
} else {
|
||||
"not-ready"
|
||||
};
|
||||
let next_safe_move = if missing_rows == 0 {
|
||||
"Route this sight receipt to Maintainer/Soul/Mind/Bifrost review; readiness approval is still external to this command."
|
||||
} else {
|
||||
"Complete the missing readiness rows, then rerun epiphany-work readiness before asking for review."
|
||||
};
|
||||
let now = Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
|
||||
let receipt = json!({
|
||||
"schemaVersion": "epiphany.repo_work_readiness_report.v0",
|
||||
"createdAt": now,
|
||||
"workspace": workspace,
|
||||
"item": item,
|
||||
"status": verdict,
|
||||
"verdict": verdict,
|
||||
"missingRequiredCount": missing_rows,
|
||||
"overviewReceiptPath": overview["receiptPath"],
|
||||
"proofBundleId": overview["proofBundle"]["bundleId"],
|
||||
"rows": rows,
|
||||
"allowedVerdicts": ["ready", "ready-with-caveats", "not-ready", "needs-human-review"],
|
||||
"authority": {
|
||||
"owner": "Soul/Mind/Bifrost/Maintainer",
|
||||
"sightOnly": true,
|
||||
"readinessApprovalAuthorized": false,
|
||||
"durableStateCommitAuthorized": false,
|
||||
"publicationAuthorized": false,
|
||||
"bifrostPublicationAuthorized": false,
|
||||
"githubPrAuthorized": false,
|
||||
"mergeAuthorized": false,
|
||||
"upstreamSyncAuthorized": false,
|
||||
"deploymentAuthority": false,
|
||||
"serviceLifecycleAuthority": false,
|
||||
"handsActionAuthorized": false,
|
||||
"crossBodyMutationAuthorized": false,
|
||||
"privateVerseRummaging": false,
|
||||
"privateStateExposed": false
|
||||
},
|
||||
"privateStateExposed": false,
|
||||
"nextSafeMove": next_safe_move
|
||||
});
|
||||
if args.write_receipt {
|
||||
write_json(&readiness_receipt_path, &receipt)?;
|
||||
}
|
||||
Ok(json!({
|
||||
"schemaVersion": "epiphany.repo_work_readiness.v0",
|
||||
"status": verdict,
|
||||
"workspace": receipt["workspace"],
|
||||
"item": receipt["item"],
|
||||
"receiptPath": if args.write_receipt { Value::String(readiness_receipt_path.display().to_string()) } else { Value::Null },
|
||||
"missingRequiredCount": missing_rows,
|
||||
"rows": receipt["rows"],
|
||||
"authority": receipt["authority"],
|
||||
"privateStateExposed": false,
|
||||
"nextSafeMove": receipt["nextSafeMove"]
|
||||
}))
|
||||
}
|
||||
|
||||
fn run_deployment_config_audit(args: DeploymentConfigAuditArgs) -> Result<Value> {
|
||||
let workspace = args
|
||||
.workspace
|
||||
|
|
@ -13601,6 +13933,54 @@ fn existing_path_value(path: &Path) -> Value {
|
|||
}
|
||||
}
|
||||
|
||||
fn readiness_path_row(
|
||||
kind: &str,
|
||||
owner: &str,
|
||||
required_schema: &str,
|
||||
path: &Path,
|
||||
satisfied: bool,
|
||||
note: &str,
|
||||
) -> Result<Value> {
|
||||
let document = read_json_if_exists(path)?;
|
||||
let schema_version = document
|
||||
.as_ref()
|
||||
.and_then(|value| string_from_json(value, &["schemaVersion"]))
|
||||
.unwrap_or_else(|| "missing".to_string());
|
||||
let document_status = document
|
||||
.as_ref()
|
||||
.and_then(|value| string_from_json(value, &["status"]))
|
||||
.unwrap_or_else(|| "missing".to_string());
|
||||
Ok(json!({
|
||||
"kind": kind,
|
||||
"owner": owner,
|
||||
"requiredSchema": required_schema,
|
||||
"evidenceRef": existing_path_value(path),
|
||||
"artifactStatus": if path.exists() { "present" } else { "missing" },
|
||||
"schemaVersion": schema_version,
|
||||
"documentStatus": document_status,
|
||||
"satisfied": satisfied,
|
||||
"status": if satisfied { "satisfied" } else { "missing" },
|
||||
"note": note,
|
||||
"privateStateExposed": false
|
||||
}))
|
||||
}
|
||||
|
||||
fn readiness_missing_row(kind: &str, owner: &str, required_schema: &str, note: &str) -> Value {
|
||||
json!({
|
||||
"kind": kind,
|
||||
"owner": owner,
|
||||
"requiredSchema": required_schema,
|
||||
"evidenceRef": Value::Null,
|
||||
"artifactStatus": "missing",
|
||||
"schemaVersion": "missing",
|
||||
"documentStatus": "missing",
|
||||
"satisfied": false,
|
||||
"status": "missing",
|
||||
"note": note,
|
||||
"privateStateExposed": false
|
||||
})
|
||||
}
|
||||
|
||||
fn read_json_if_exists(path: &Path) -> Result<Option<Value>> {
|
||||
if path.exists() {
|
||||
read_json(path).map(Some)
|
||||
|
|
@ -14402,7 +14782,11 @@ fn string_array_field(value: &Value, field: &str) -> Vec<String> {
|
|||
}
|
||||
|
||||
fn default_if_empty(values: Vec<String>, defaults: Vec<String>) -> Vec<String> {
|
||||
if values.is_empty() { defaults } else { values }
|
||||
if values.is_empty() {
|
||||
defaults
|
||||
} else {
|
||||
values
|
||||
}
|
||||
}
|
||||
|
||||
fn adopted_action_item_from_plan(plan: &Value) -> Value {
|
||||
|
|
@ -14633,7 +15017,7 @@ fn sanitize(value: &str) -> String {
|
|||
|
||||
fn print_usage() {
|
||||
eprintln!(
|
||||
"usage: epiphany-work <persona-intake|accept|derive-plan|plan|run|adopt|execute|close|publish|sync|overview|deployment-config-audit|deployment-execution-runbook|deployment-aftercare-audit|export-proof|tick|queue-run|serve> ...\n\
|
||||
"usage: epiphany-work <persona-intake|accept|derive-plan|plan|run|adopt|execute|close|publish|sync|overview|readiness|deployment-config-audit|deployment-execution-runbook|deployment-aftercare-audit|export-proof|tick|queue-run|serve> ...\n\
|
||||
persona-intake --workspace <repo> --item <id> --message <text> [--topic <topic>] [--store <local-verse.ccmp>] [--runtime-id <id>]\n\
|
||||
accept --workspace <repo> --from <persona|bifrost|persona-or-bifrost> --item <id> [--summary <text>] [--topic <topic>] [--store <local-verse.ccmp>] [--runtime-id <id>] [--online-receipt <path>] [--public-discussion-ref <ref>] [--candidate-action-ref <ref>]\n\
|
||||
derive-plan --workspace <repo> [--item <id>] [--accept-receipt <path>] [--action-family append-worklog|planning-note|checklist-note|section-note|repo-status-section|task-card|repo-manifest|repo-tool-capabilities|repo-tool-request|repo-eve-surface|repo-collaboration-policy|repo-collaboration-topic|repo-consensus-brief|repo-planning-brief|repo-interpreter-brief|repo-objective-draft|repo-adoption-request|repo-scheduling-request|repo-work-order|repo-verification-request|repo-publication-request|repo-sync-request|repo-maintainer-review-request|repo-pr-request|repo-credit-request|repo-artifact-acceptance-request|repo-metrics-request|repo-readiness-review-request|repo-doctrine-update-request|repo-secret-policy-request|repo-dependency-policy-request|repo-deployment-config|repo-deployment-request] [--target-path <path>] [--model-ref <ref>] [--model-authored] [--action-summary <text>] [--verification-ask <text>] [--stop-condition <text>] [--escalation-reason <text>] [--assumption <text>] [--constraint <text>] [--non-goal <text>] [--open-question <text>] [--decision-point <text>] [--evidence-need <text>]\n\
|
||||
|
|
@ -14645,6 +15029,7 @@ fn print_usage() {
|
|||
publish --workspace <repo> [--item <id>] --change-summary <text> --justification <text> --verification-receipt <ref> --review-receipt <ref> --ledger-entry-id <id> --pull-request-url <url> --pull-request-title <text>\n\
|
||||
sync --workspace <repo> [--item <id>] [--publish-receipt <path>] [--upstream-ref origin/main] --merge-receipt <ref>\n\
|
||||
overview --workspace <repo> [--item <id>] [--accept-receipt <path>] [--no-write]\n\
|
||||
readiness --workspace <repo> [--item <id>] [--accept-receipt <path>] [--public-proof <path>] [--idunn-lifecycle-receipt <path>] [--tool-directory-receipt <path>] [--no-write]\n\
|
||||
deployment-config-audit --workspace <repo> [--artifact-dir <path>] [--no-write]\n\
|
||||
deployment-execution-runbook --workspace <repo> [--artifact-dir <path>] [--remote origin] [--no-write]\n\
|
||||
deployment-aftercare-audit --workspace <repo> [--artifact-dir <path>] [--local-verse-store <path>] [--runtime-id <id>] [--runbook-receipt <path>] [--idunn-deployment-receipt-ref <ref>|--idunn-deployment-receipt <path>] [--aftercare-audit-receipt-ref <ref>|--aftercare-audit-receipt <path>] [--no-write]\n\
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ epiphany-work adopt --workspace <repo> --item <id> --from-plan <plan-receipt>
|
|||
epiphany-work execute --workspace <repo> --item <id> --from-plan <plan-receipt>
|
||||
epiphany-work close --workspace <repo> --item <id>
|
||||
epiphany-work overview --workspace <repo> --item <id>
|
||||
epiphany-work readiness --workspace <repo> --item <id>
|
||||
epiphany-work tick --workspace <repo> --item <id>
|
||||
epiphany-work serve --workspace <repo> --item <id> --max-iterations <n>
|
||||
epiphany-work publish --workspace <repo> --closure-receipt <close-receipt>
|
||||
|
|
@ -1604,6 +1605,21 @@ and `15-swarm-overview-public-proof.json` proved latest
|
|||
public proof row, one public proof action row, no mutation/elevation, and
|
||||
`private=false`.
|
||||
|
||||
Repo-work readiness sight now packages the same proof trail into a reviewable
|
||||
MVP readiness report without approving readiness. `epiphany-work readiness`
|
||||
inspects repo init, swarm online, Persona intake, Imagination plan, Self
|
||||
queue-run, Hands branch work, Soul closure, Modeling/Mind admission, redacted
|
||||
public proof, Bifrost publication, upstream-main sync, Idunn lifecycle, daemon
|
||||
tool directory, and private-state redaction rows, then writes
|
||||
`.epiphany/work/work-readiness-<item>.json` as
|
||||
`epiphany.repo_work_readiness_report.v0`. The command is sight only: it denies
|
||||
readiness approval, durable state commit, publication, PR, merge, sync,
|
||||
deployment, service lifecycle, Hands action, cross-body mutation, private Verse
|
||||
rummaging, and private-state exposure. Smoke
|
||||
`.epiphany-smoke\repo-work-readiness-20260621-092053` proved a partial local
|
||||
work path reports `not-ready` with four missing rows: Bifrost publication,
|
||||
upstream-main sync, Idunn lifecycle, and tool directory.
|
||||
|
||||
Bifrost public-proof publication transport is now the closure after local
|
||||
proof sight. `epiphany-verse-query bifrost-public-proof --public-proof-id <id>
|
||||
--ledger-entry-id <id> --review-receipt <id> --credit-receipt <id>` selects an
|
||||
|
|
@ -1860,7 +1876,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; the CultMesh TUI rows now include a compact `CONSENSUS` readback showing Persona/public feedback ids, Imagination consensus route, public/candidate ref counts, safe family, and authority denials without private payloads; `close` mirrors Mind-admitted map facts as `epiphany.cultmesh.repo_work_map_entry.v0`; Gjallar enumerates overview history, 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` over the MVP proof rows and names missing Bifrost/upstream/Idunn/tool-directory gates without approving readiness; the CultMesh TUI rows include compact `CONSENSUS` readback showing Persona/public feedback ids, Imagination consensus route, public/candidate ref counts, safe family, and authority denials without private payloads; `close` mirrors Mind-admitted map facts as `epiphany.cultmesh.repo_work_map_entry.v0`; Gjallar enumerates overview history, 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. |
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ remembers doctrine; the branch remembers the blade.
|
|||
- 2026-06-20: `derive-plan` action-item receipts now carry richer model-authored planning facets without widening command authority, and `adopt --from-plan` now preserves the chosen Imagination action item in the Mind adoption receipt. New CLI fields `--assumption`, `--constraint`, `--non-goal`, `--open-question`, `--decision-point`, and `--evidence-need` are recorded under `planningFacets` in `epiphany.repo_work_imagination_action_items_receipt.v0`, mirrored into the plan derivation's `actionItemReceipt`, then copied into `epiphany.repo_work_adoption_receipt.v0` as `adoptedActionItem`; deterministic defaults are emitted when a model does not supply them. Focused smoke `.epiphany-smoke\repo-planning-facets-20260620-164958` ran init -> online -> accept -> model-authored `derive-plan --action-family planning-note` with all facet fields -> tick run/adopt/execute/close; the action-item receipt preserved assumptions, constraints, non-goals, open questions, decision points, and evidence needs while `handsAuthorityGranted=false`, `durableStateAdmitted=false`, `handsCommandAuthority=false`, `durableStateAuthority=false`, and `privateStateExposed=false`; the adoption receipt preserved `adoptedActionItem.safeActionFamily=repo.markdown_planning_note`, planning facets, `adoptedActionItem.handsCommandAuthority=false`, `adoptedActionItem.durableStateAuthority=false`, `adoptedActionItem.publicationAuthorized=false`, `authority.handsAuthorityGranted=true`, `authority.durableStateAdmitted=false`, and `privateStateExposed=false`; Soul closure passed with family assertions and path scope matched. 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.
|
||||
- 2026-06-21: `repo-planning-brief` is live as richer family-friendly Imagination decomposition cargo, and Soul closure now emits a typed safe-family planning readback for its full matrix. `epiphany-work derive-plan --action-family repo-planning-brief` writes `.epiphany/planning-briefs/<item>.toml` with safe family `repo.planning_brief`, status `draft`, twenty-one candidate next safe families grouped as preparation, adoption/queue, execution/review, publication/accounting, and policy/deployment, requested-path / verification-ask / evidence-need / owner / authority-denial / closure-proof requirements, and Mind/Self/Substrate/Hands/Soul/Bifrost/Idunn gate ordering while denying objective adoption, scheduling, substrate access, Hands action, shell, commit, publication, deployment execution, service lifecycle, cross-body mutation, private transcripts, raw-result payloads, and private-state exposure. Closure `familyAssertions.safeFamilyPlanning` now carries `epiphany.repo_work_safe_family_planning_readback.v0` with candidate-family rows/count, grouped matrix rows, matrix control flags, closure proof flags, planning requirement flags, gate flags, authority-denial flags, and the private-state seal. Focused smoke `.epiphany-smoke\repo-planning-brief-family-20260621-090158` ran init -> online -> accept -> repo-planning-brief derive-plan -> tick run/adopt/execute/close; Hands committed only `.epiphany/planning-briefs/repo-planning-brief-family.toml`, Soul passed with `pathScopeMatched=true`, `familyAssertions.status=passed`, `candidateNextSafeFamilyCount=21`, `allMatrixGroupsComplete=true`, `matrixControlsPresent=true`, `allClosureProofsPresent=true`, `allRequiredGatesPresent=true`, `authorityDenied=true`, and `privateStateExposed=false`. Current remaining repo-swarm MVP organs are deeper interpreter semantics, richer closure/map readback, another useful repo-owned safe family if needed, or Idunn-owned queue-run service lifecycle under explicit operator authority.
|
||||
- 2026-06-21: `repo-readiness-review-request` is live as the family-friendly MVP readiness review gate. `epiphany-work derive-plan --action-family repo-readiness-review-request` writes `.epiphany/readiness-reviews/<item>.toml` with safe family `repo.readiness_review_request`, status `awaiting-mvp-readiness-review`, requested owner `Maintainer/Soul/Mind/Bifrost`, proof-bundle/readiness packet requirements for repo init, online swarm, Persona intake, Imagination planning, Self queue-run, Hands branch work, Soul closure, Modeling map update, Mind admission, Bifrost publication, upstream-main sync, Idunn lifecycle, global tool directory, and private-state redaction, while denying readiness approval, durable state commit, publication, Bifrost publication, PR, merge, upstream sync, deployment, service lifecycle, Hands action, cross-body mutation, private Verse rummaging, and private-state exposure. Focused smoke `.epiphany-smoke\repo-readiness-review-request-family-20260621-090003` ran init -> online -> accept -> repo-readiness-review-request derive-plan -> tick run/adopt/execute/close; Hands committed only `.epiphany/readiness-reviews/repo-readiness-review-request-family.toml`, Soul passed with `pathScopeMatched=true`, `familyAssertions.status=passed`, `awaitingMvpReadinessReview=true`, `idunnLifecycleRequired=true`, `toolDirectoryRequired=true`, and `privateStateExposed=false`. The planning-brief matrix now counts twenty-one families and includes this readiness review in publication/accounting; smoke `.epiphany-smoke\repo-planning-brief-family-20260621-090158` proved `candidateNextSafeFamilyCount=21`.
|
||||
- 2026-06-21: `epiphany-work readiness` is live as a non-mutating repo-work MVP readiness sight rite. It reuses overview/proof-bundle state, inspects repo init, online swarm, Persona intake, Imagination plan, Self queue-run, Hands execute, Soul closure, Modeling/Mind admission, redacted public proof, Bifrost publication, upstream-main sync, Idunn lifecycle, daemon tool directory, and private-state redaction rows, then writes `.epiphany/work/work-readiness-<item>.json` with schema `epiphany.repo_work_readiness_report.v0`. It can return `ready` only when all rows are satisfied, but it does not approve readiness or grant durable state, publication, PR, merge, sync, deployment, service lifecycle, Hands action, cross-body, or private Verse authority. Focused smoke `.epiphany-smoke\repo-work-readiness-20260621-092053` ran fresh repo init -> online -> accept -> checklist plan/tick close -> queue-run dry-run -> public-proof export -> readiness; it reported `not-ready`, `missingRequiredCount=4` for Bifrost publication, upstream-main sync, Idunn lifecycle, and tool directory, while local work/proof rows were satisfied, `sightOnly=true`, and `privateStateExposed=false`.
|
||||
- 2026-06-21: `repo-interpreter-brief` is live as Mind-owned interpretation cargo between Imagination consensus and downstream action-family adoption. `epiphany-work derive-plan --action-family repo-interpreter-brief` writes `.epiphany/interpreter-briefs/<item>.toml` with safe family `repo.interpreter_brief`, status `draft`, owner `Mind`, source `Imagination`, consensus/safe-family/path/verification/evidence requirements, semantic checks for intent/scope/paths/verification/evidence/rollback/non-goals/questions/consensus, candidate next safe families, and Mind/Soul/Bifrost/Hands/Substrate/Idunn gates while denying direct state commit, objective adoption, scheduling, substrate access, Hands action, shell, commit, publication, deployment execution, service lifecycle, cross-body mutation, private transcripts, raw-result payloads, and private-state exposure. Focused smoke `.epiphany-smoke\repo-interpreter-brief-family-20260621-010858` ran init -> online -> accept -> repo-interpreter-brief derive-plan -> tick run/adopt/execute/close; Hands committed only `.epiphany/interpreter-briefs/repo-interpreter-brief-family.toml`, Soul passed with `pathScopeMatched=true`, `familyAssertions.status=passed`, `mindOwnsInterpretation=true`, `candidateActionsNonAuthoritative=true`, `directStateCommitAuthorized=false`, `handsActionAuthorized=false`, and `privateStateExposed=false`.
|
||||
- 2026-06-20: Gjallar repo-work map sight now includes semantic stage lenses. `epiphany-verse-query gjallar`, swarm overview, and swarm triage expose `repoWorkMapStageLensRows` plus `REPO-WORK-MAP-STAGE` rows derived from Mind-admitted local Verse map entries, grouping safe families into stages and owning organs such as `imagination-planning` / `Imagination`, `hands-execution-request` / `Hands`, `soul-verification-request` / `Soul`, `bifrost-publication-accounting` / `Bifrost`, and `idunn-deployment` / `Idunn`. Focused smoke `.epiphany-smoke\repo-close-mind-adoption-guard-20260620-232414` proves the stage lens for accepted `repo.markdown_planning_note` work reports `stage=imagination-planning`, `owner=Imagination`, latest item/commit/Mind commit receipt, Bifrost gate, and `privateStateExposed=false`. This is sight only; Gjallar still does not schedule, publish, merge, deploy, keep daemons alive, or admit Mind state.
|
||||
- 2026-06-20: Gjallar repo-work map sight now includes next-publication-gate lenses. `epiphany-verse-query gjallar`, swarm overview, and swarm triage expose `repoWorkMapGateLensRows` plus `REPO-WORK-MAP-GATE` rows derived from the same Mind-admitted local Verse map entries, grouping accepted consequences by publication gate and naming the owning gate organ. Focused smoke `.epiphany-smoke\repo-close-mind-adoption-guard-20260620-233353` proves accepted `repo.markdown_planning_note` work reports `gate=Bifrost`, `owner=Bifrost`, latest item/commit/Mind commit receipt, `sightOnly=true`, `publicationAuthorized=false`, and `privateStateExposed=false`. This is sight only; Bifrost still owns publication/credit/upstream review and Gjallar does not schedule, publish, merge, deploy, keep daemons alive, or admit Mind state.
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -91,6 +91,7 @@ active_subgoals:
|
|||
- Use `notes/epiphany-repo-swarm-mvp-contract.md` as the repo-swarm autonomy authority map. Autonomous branch-local work inside an Epiphany-owned repo Body is in scope and desired; the safety boundary is typed authority, branch containment, interruption, receipts, private-state sealing, and Bifrost-gated publication/merge/escalation, not asking a human before every local edit. Current safe-family cargo includes repo manifest, tool capability manifest, daemon-hosted tool request cargo, Eve/CultUI surface contract, repo collaboration policy, collaboration topics, consensus/objective/adoption/scheduling/work-order/verification/publication/sync/review/PR/credit/artifact/metrics/doctrine-update/secret-policy/deployment requests, repo deployment config, action-item receipts, Mind adoption interpretation/decision receipts, explicit Mind safe-family refusal proof `.epiphany-smoke\repo-mind-safe-family-guard-20260620-194425`, explicit Mind requested-path/plan changed-path refusal proof `.epiphany-smoke\repo-mind-path-guard-20260620-194239`, overview/public-proof/Gjallar/Eve readbacks, typed swarm-run stop classification, Idunn non-mutating queue-run lifecycle receipts, and fresh-repo upstream-main proof. Latest deployment proof `.epiphany-smoke\repo-deployment-config-family-20260620-221205` shows `repo.deployment_config` closes through Soul, `deployment-config-audit` reports `ready-for-idunn-review`, `deployment-execution-runbook` reports `ready-for-operator-git-push`, and `deployment-aftercare-audit` ingests local Verse/CultMesh Idunn deployment/aftercare receipt refs with source `cultmesh`, status `complete`, `deploymentComplete=true`, `daemonOwnsExecution=true`, no repo-agent execution/deployment/SSH/git-push/service/Hands/publication/merge/cross-body authority, and `privateStateExposed=false`; explicit Idunn receipt files remain only compatibility reliquaries. Latest deployment request proof `.epiphany-smoke\repo-deployment-request-family-20260620-195605` shows `repo.deployment_request` closes through Soul while requesting reviewed git-push-observed-by-Idunn deployment with script/host/secret/rollback/aftercare requirements and no deployment/SSH/git-push/service authority. Latest security cargo proof `.epiphany-smoke\repo-secret-policy-request-family-20260620-193046` shows `repo.secret_policy_request` closes through Soul while requesting reviewed secret/write/export/deployment policy without exposing secrets or granting write/deployment/publication authority. Governance proof `.epiphany-smoke\repo-doctrine-update-request-family-20260620-192140` shows `repo.doctrine_update_request` closes through Soul while requesting reviewed `AGENTS.md` doctrine work without mutating doctrine or granting Hands/service/publication authority. Swarm-run stop proofs now include `.epiphany-smoke\fresh-repo-mvp-20260620-180024` for `iteration-limit` / Self / `self.scheduler-iteration-limit` with upstream-main sync and public-proof export, plus `.epiphany-smoke\swarm-stop-classification-20260620-184717` for `queue-empty` / Gjallar / `repo.work.overview`, `dry-run-preview` / Self / `ready-to-run`, `authority-gated` / Bifrost / `awaiting-publication`, and `authority-gated` / Bifrost/GitHub / `awaiting-upstream-sync`; all stop packets are non-mutating, non-elevated, and `privateStateExposed=false`. Native proof `.epiphany-smoke\repo-work-service-lifecycle-20260620-185853` now proves Idunn-owned non-mutating repo-work queue-run service plan/runbook receipts for exact service id `epiphany-repo-work-queue-runner`, receipt-directory readback, runbook SHA-256 `f2ec67c4f8243a3ebc2f9e915b6b9f5ae2ac2d99d2cdb86905b54667adc456f8`, `hostedBody=repo-work`, no service-manager mutation, no launch, no elevation, and `privateStateExposed=false`.
|
||||
- Repo dependency/supply-chain policy request cargo is live. `repo-dependency-policy-request` lowers to safe family `repo.dependency_policy_request` and writes `.epiphany/dependency-policy-requests/<item>.toml` with manifest inventory, lockfile policy, package-manager command review, network fetch policy, vulnerability/license/vendored-code/update-cadence requirements, Eyes/Soul/Mind/maintainer/Bifrost/dependency-audit receipt refs, and denials for dependency update, package install, lockfile mutation, network fetch, CI mutation, Hands, publication, merge, deployment, service lifecycle, cross-body mutation, private Verse rummaging, and private-state exposure. Proof `.epiphany-smoke\repo-dependency-policy-request-family-20260621-083433` closes through Soul with `familyAssertionsStatus=passed`, `pathScopeMatched=true`, `awaitingDependencyPolicyReview=true`, all direct dependency/package/network/CI authorities false, and `privateStateExposed=false`.
|
||||
- Repo planning brief cargo now carries the family-friendly safe-family matrix. `repo-planning-brief` still lowers to safe family `repo.planning_brief` and writes `.epiphany/planning-briefs/<item>.toml`, but it now names twenty-one candidate next safe families across preparation, adoption/queue, execution/review, publication/accounting, and policy/deployment groups, including `repo.readiness_review_request` for redacted repo-swarm MVP proof-bundle review before readiness claims. Each candidate must name owner, requested paths, verification asks, evidence needs, authority denials, and closure proofs. Closure `safeFamilyPlanning` readback now reports grouped matrix completeness, matrix controls, and closure proof presence while granting no scheduling, substrate, Hands, shell, commit, publication, deployment, service lifecycle, cross-body, private-transcript, raw-result, or private-state authority. Proof `.epiphany-smoke\repo-planning-brief-family-20260621-090158` closes through Soul with `candidateNextSafeFamilyCount=21`, `allMatrixGroupsComplete=true`, `matrixControlsPresent=true`, `allClosureProofsPresent=true`, `authorityDenied=true`, and `privateStateExposed=false`.
|
||||
- Repo-work readiness sight is live. `epiphany-work readiness` reuses the existing overview/proof-bundle artery, inspects repo init, swarm online, Persona intake, Imagination plan, Self queue-run, Hands execute, Soul closure, Modeling/Mind admission, public proof, Bifrost publication, upstream-main sync, Idunn lifecycle, daemon tool directory, and private-state redaction rows, then writes `.epiphany/work/work-readiness-<item>.json` as `epiphany.repo_work_readiness_report.v0`. It is sight only: no readiness approval, durable state commit, publication, PR, merge, sync, deployment, service lifecycle, Hands action, cross-body mutation, private Verse rummaging, or private-state exposure authority. Proof `.epiphany-smoke\repo-work-readiness-20260621-092053` drove a fresh repo through init/online/intake/checklist execution/closure/queue-run/public-proof export; readiness reported `not-ready`, `missingRequiredCount=4` for Bifrost publication, upstream-main sync, Idunn lifecycle, and tool directory, while local work/proof rows were satisfied and authority denials held.
|
||||
- Repo-swarm Mind interpretation cargo is live. `repo-interpreter-brief` lowers to safe family `repo.interpreter_brief` and writes `.epiphany/interpreter-briefs/<item>.toml` as draft Mind-owned interpretation from Imagination consensus, with semantic checks, candidate safe families, required Mind/Soul/Bifrost/Hands/Substrate/Idunn gates, and explicit denials for direct state commit, objective adoption, scheduling, substrate access, Hands action, shell, commit, publication, deployment execution, service lifecycle, cross-body mutation, private transcripts/raw results, and private-state exposure. Proof `.epiphany-smoke\repo-interpreter-brief-family-20260621-010858` closes through Soul with `familyAssertions.status=passed`, `mindOwnsInterpretation=true`, `candidateActionsNonAuthoritative=true`, `directStateCommitAuthorized=false`, `handsActionAuthorized=false`, and `privateStateExposed=false`.
|
||||
- Idunn-hosted repo-work queue-run lifecycle now has plan/runbook/launch/audit closure under explicit operator authority. `epiphany-daemon-supervisor repo-work-service-audit` reads all 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 with `status=complete` or `incomplete`. Native proof `.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 operator plan/runbook/launch/audit ergonomics, with audit reporting no missing or failed checks. Basic queue-run service lifecycle readiness is sealed; remaining Idunn work is optional elevated install/start execution under explicit operator authority, not Self scheduling authority.
|
||||
- Gjallar/Odin sight now exposes Idunn deployment receipt refs without taking Idunn's execution throne. `EpiphanyLocalVerseContext`, `receipt-directory`, `swarm-overview`, `swarm-triage`, and `gjallar` surface latest `gamecult.idunn.deployment_receipt.v0` and `gamecult.idunn.deployment_aftercare_audit.v0` as compact `idunnDeploymentReceiptRows` / `IDUNN-DEPLOYMENT` rows with owner `Idunn`, watched/checked refs, source/result refs, aftercare ids, follow-up readback command, and `privateStateExposed=false`. Smoke `.epiphany-smoke\repo-deployment-config-family-20260620-223203` proves the aftercare audit still ingests CultMesh refs and Gjallar reports `gjallarIdunnDeploymentReceiptCount=2`, latest deployment receipt `fixture-idunn-deployment`, latest aftercare receipt `fixture-idunn-aftercare`, and no private-state exposure. This is citeable discovery only; deployment still happens by explicit operator `git push` observed by Idunn.
|
||||
|
|
|
|||
Reference in a new issue