Add repo planning brief safe family

This commit is contained in:
Meta Vens 2026-06-21 00:20:37 +01:00
commit 73aee338ac
6 changed files with 671 additions and 4 deletions

View file

@ -0,0 +1,418 @@
use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
use chrono::Utc;
use serde_json::Value;
use serde_json::json;
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-planning-brief-family-{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 Planning Brief Family Smoke\n\nThis repository proves branch-local Imagination safe-family planning briefs.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed repo planning brief smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-planning-brief-family"],
&repo,
)?;
let item = "repo-planning-brief-family";
let target_path = ".epiphany/planning-briefs/repo-planning-brief-family.toml";
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-planning-brief-family-smoke",
"--topic",
"repo-planning-brief-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-planning-brief-family-smoke",
"--local-verse-store",
path_str(&local_verse)?,
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-work",
&[
"accept",
"--workspace",
path_str(&repo)?,
"--from",
"persona",
"--item",
item,
"--summary",
"Turn a rough Persona request into a safe-family planning brief before any work item receives Hands authority.",
"--candidate-action-ref",
"candidate-action://repo-planning-brief-family/decompose-safe-families",
"--candidate-action-ref",
"candidate-action://repo-planning-brief-family/request-mind-review",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-planning-brief-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-planning-brief",
"--model-ref",
"repo-planning-brief-family-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,
)?;
}
let close_path = repo
.join(".epiphany")
.join("work")
.join(format!("work-close-{item}.json"));
let close = read_json(&close_path)?;
let brief_text = fs::read_to_string(repo.join(target_path))
.with_context(|| format!("failed to read {}", repo.join(target_path).display()))?;
require_eq(
&plan,
&["derivation", "safeActionFamily"],
"repo.planning_brief",
)?;
require_eq(&close, &["status"], "closed")?;
require_eq(&close, &["soul", "verdict"], "passed")?;
require_eq(
&close,
&["closureReview", "familyAssertions", "status"],
"passed",
)?;
require_bool(
&close,
&["closureReview", "sourceGrounding", "pathScopeMatched"],
true,
)?;
require_bool(&close, &["privateStateExposed"], false)?;
require_text(
&brief_text,
"schema_version = \"epiphany.repo_planning_brief.v0\"",
)?;
require_text(&brief_text, "safe_action_family = \"repo.planning_brief\"")?;
require_text(&brief_text, "[planning_brief]")?;
require_text(&brief_text, "status = \"draft\"")?;
require_text(&brief_text, "owner = \"Imagination\"")?;
require_text(&brief_text, "candidate_actions_non_authoritative = true")?;
require_text(&brief_text, "requires_mind_interpretation = true")?;
require_text(&brief_text, "requires_soul_evidence_needs = true")?;
require_text(&brief_text, "[decomposition]")?;
require_text(&brief_text, "\"repo.consensus_brief\"")?;
require_text(&brief_text, "\"repo.objective_draft\"")?;
require_text(&brief_text, "\"repo.task_card\"")?;
require_text(&brief_text, "\"repo.work_order\"")?;
require_text(&brief_text, "\"repo.verification_request\"")?;
require_text(&brief_text, "\"repo.publication_request\"")?;
require_text(&brief_text, "candidate_items_must_name_requested_paths = true")?;
require_text(
&brief_text,
"candidate_items_must_name_verification_asks = true",
)?;
require_text(&brief_text, "candidate_items_must_name_evidence_needs = true")?;
require_text(&brief_text, "[gates]")?;
require_text(&brief_text, "mind_interpreter_required = true")?;
require_text(&brief_text, "self_queue_selection_required = true")?;
require_text(&brief_text, "substrate_gate_required_before_hands = true")?;
require_text(&brief_text, "hands_receipts_required_before_soul = true")?;
require_text(
&brief_text,
"soul_verdict_required_before_mind_map_admission = true",
)?;
require_text(&brief_text, "bifrost_required_before_publication = true")?;
require_text(
&brief_text,
"idunn_required_before_deployment_execution = true",
)?;
require_text(&brief_text, "objective_adoption_authorized = false")?;
require_text(&brief_text, "self_scheduling_authorized = false")?;
require_text(&brief_text, "substrate_access_authorized = false")?;
require_text(&brief_text, "hands_action_authorized = false")?;
require_text(&brief_text, "shell_command_authorized = false")?;
require_text(&brief_text, "commit_authorized = false")?;
require_text(&brief_text, "publication_authorized = false")?;
require_text(&brief_text, "deployment_execution_authority = false")?;
require_text(&brief_text, "cross_body_mutation_authorized = false")?;
require_text(&brief_text, "private_worker_transcripts_allowed = false")?;
require_text(&brief_text, "raw_result_payloads_allowed = false")?;
require_text(&brief_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_work_planning_brief_family_smoke.v0",
"status": "ok",
"smokeDir": smoke_dir,
"repo": repo,
"branch": git_output(["branch", "--show-current"], &repo)?,
"item": item,
"safeActionFamily": plan["derivation"]["safeActionFamily"],
"targetPath": target_path,
"closeStatus": close["status"],
"soulVerdict": close["soul"]["verdict"],
"familyAssertionsStatus": close["closureReview"]["familyAssertions"]["status"],
"pathScopeMatched": close["closureReview"]["sourceGrounding"]["pathScopeMatched"],
"briefIsDraft": true,
"candidateActionsNonAuthoritative": true,
"mindInterpreterRequired": true,
"soulEvidenceNeedsRequired": true,
"idunnDeploymentExecutionRequired": true,
"privateStateExposed": false,
});
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 read_json(path: &Path) -> Result<Value> {
let bytes = fs::read(path).with_context(|| format!("failed to read {}", path.display()))?;
serde_json::from_slice(&bytes).with_context(|| format!("failed to parse {}", path.display()))
}
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_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);
if actual == Some(expected) {
Ok(())
} else {
Err(anyhow!(
"expected {} to be {expected}, got {:?}",
path.join("."),
actual
))
}
}
fn require_text(haystack: &str, needle: &str) -> Result<()> {
if haystack.contains(needle) {
Ok(())
} else {
Err(anyhow!(
"expected planning brief text to contain {needle:?}"
))
}
}
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()))
}

View file

@ -2156,6 +2156,9 @@ fn derive_safe_plan_family(input: DeriveSafePlanInput<'_>) -> Result<DerivedSafe
"repo-consensus-brief" | "consensus-brief" | "imagination-consensus" => {
derive_repo_consensus_brief_plan(input, &action_family)
}
"repo-planning-brief" | "planning-brief" | "safe-family-plan" => {
derive_repo_planning_brief_plan(input, &action_family)
}
"repo-objective-draft" | "objective-draft" | "imagination-objective" => {
derive_repo_objective_draft_plan(input, &action_family)
}
@ -2211,7 +2214,7 @@ fn derive_safe_plan_family(input: DeriveSafePlanInput<'_>) -> Result<DerivedSafe
| "idunn-deployment-request"
| "repo-deploy-request" => derive_repo_deployment_request_plan(input, &action_family),
other => Err(anyhow!(
"unsupported derive-plan action family {other:?}; supported families are 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-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-doctrine-update-request, repo-secret-policy-request, repo-deployment-config, and repo-deployment-request"
"unsupported derive-plan action family {other:?}; supported families are 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-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-doctrine-update-request, repo-secret-policy-request, repo-deployment-config, and repo-deployment-request"
)),
}
}
@ -3416,6 +3419,157 @@ fn derive_repo_consensus_brief_plan(
})
}
fn derive_repo_planning_brief_plan(
input: DeriveSafePlanInput<'_>,
action_family: &str,
) -> Result<DerivedSafePlan> {
let item_slug = sanitize(input.item);
let default_target = format!(".epiphany/planning-briefs/{item_slug}.toml");
let target_path = validate_toml_target_path(input.target_path.unwrap_or(&default_target))?;
let candidate_refs =
string_array_from_json(input.accept_receipt, &["feedback", "candidateActionRefs"]);
let public_refs =
string_array_from_json(input.accept_receipt, &["feedback", "publicDiscussionRefs"]);
let now = Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
let brief_id = format!("repo-planning-brief:{item_slug}");
let recommended_families = vec![
"repo.consensus_brief".to_string(),
"repo.objective_draft".to_string(),
"repo.task_card".to_string(),
"repo.work_order".to_string(),
"repo.verification_request".to_string(),
"repo.publication_request".to_string(),
];
let lines = vec![
"# Epiphany repo planning brief.".to_string(),
"# Branch-local Imagination decomposition cargo; not objective adoption, scheduling, Hands authority, or publication.".to_string(),
format!(
"schema_version = {}",
toml_basic_string("epiphany.repo_planning_brief.v0")
),
format!("item = {}", toml_basic_string(input.item)),
format!("created_at = {}", toml_basic_string(&now)),
format!("source = {}", toml_basic_string(input.source)),
format!("summary = {}", toml_basic_string(&compact_line(input.summary))),
format!(
"safe_action_family = {}",
toml_basic_string("repo.planning_brief")
),
format!("model_authored = {}", input.model_authored),
format!(
"model_ref = {}",
toml_basic_string(input.model_ref.unwrap_or("deterministic-fallback"))
),
"operator_authored_shell_details = false".to_string(),
"hands_authority_granted = false".to_string(),
"durable_state_admitted = false".to_string(),
"publication_authorized = false".to_string(),
"merge_authorized = false".to_string(),
"service_lifecycle_authority = false".to_string(),
"deployment_execution_authority = false".to_string(),
"cross_repo_mutation = false".to_string(),
"private_state_exposed = false".to_string(),
format!("candidate_action_refs = {}", toml_array(&candidate_refs)),
format!("public_discussion_refs = {}", toml_array(&public_refs)),
String::new(),
"[planning_brief]".to_string(),
format!("id = {}", toml_basic_string(&brief_id)),
"status = \"draft\"".to_string(),
"owner = \"Imagination\"".to_string(),
"purpose = \"decompose rough Persona or operator pressure into bounded safe-family work items\"".to_string(),
"candidate_actions_non_authoritative = true".to_string(),
"requires_mind_interpretation = true".to_string(),
"requires_soul_evidence_needs = true".to_string(),
"requires_explicit_human_or_mind_adoption = true".to_string(),
format!(
"recommended_next_safe_families = {}",
toml_array(&recommended_families)
),
String::new(),
"[decomposition]".to_string(),
"sequence = [".to_string(),
" \"repo.consensus_brief\",".to_string(),
" \"repo.objective_draft\",".to_string(),
" \"repo.task_card\",".to_string(),
" \"repo.work_order\",".to_string(),
" \"repo.verification_request\",".to_string(),
" \"repo.publication_request\"".to_string(),
"]".to_string(),
"max_candidate_work_items = 6".to_string(),
"one_safe_family_per_action_item = true".to_string(),
"candidate_items_must_name_requested_paths = true".to_string(),
"candidate_items_must_name_verification_asks = true".to_string(),
"candidate_items_must_name_evidence_needs = true".to_string(),
"shell_commands_must_be_deterministic_lowerings = true".to_string(),
String::new(),
"[gates]".to_string(),
"mind_interpreter_required = true".to_string(),
"mind_adoption_required = true".to_string(),
"self_queue_selection_required = true".to_string(),
"substrate_gate_required_before_hands = true".to_string(),
"hands_receipts_required_before_soul = true".to_string(),
"soul_verdict_required_before_mind_map_admission = true".to_string(),
"bifrost_required_before_publication = true".to_string(),
"idunn_required_before_deployment_execution = true".to_string(),
String::new(),
"[inputs]".to_string(),
format!("public_discussion_refs = {}", toml_array(&public_refs)),
format!("candidate_action_refs = {}", toml_array(&candidate_refs)),
"private_worker_transcripts_allowed = false".to_string(),
"raw_result_payloads_allowed = false".to_string(),
String::new(),
"[authority]".to_string(),
"branch_local_only = true".to_string(),
"objective_adoption_authorized = false".to_string(),
"self_scheduling_authorized = false".to_string(),
"substrate_access_authorized = false".to_string(),
"hands_action_authorized = false".to_string(),
"shell_command_authorized = false".to_string(),
"commit_authorized = false".to_string(),
"publication_authorized = false".to_string(),
"merge_authorized = false".to_string(),
"service_lifecycle_authority = false".to_string(),
"deployment_execution_authority = false".to_string(),
"cross_body_mutation_authorized = false".to_string(),
"private_verse_rummaging = false".to_string(),
"mind_adoption_required = true".to_string(),
"soul_verification_required = true".to_string(),
"bifrost_publication_required = true".to_string(),
String::new(),
"[verification]".to_string(),
"asks = [".to_string(),
" \"Soul verifies the planning brief path changed and contains the accepted pressure summary.\",".to_string(),
" \"Soul verifies the brief names candidate safe families, requested-path/evidence requirements, and gate order without granting action authority.\",".to_string(),
" \"Soul verifies the brief preserves private-state seals and forbids deployment execution authority.\",".to_string(),
" \"Soul verifies no paths outside the declared planning brief changed.\"".to_string(),
"]".to_string(),
String::new(),
"[rollback]".to_string(),
"hints = [\"Remove the planning brief if the rough pressure was misread or the decomposition is not ready for Mind review.\"]".to_string(),
String::new(),
];
let command = powershell_set_lines_command(&target_path, &lines);
Ok(DerivedSafePlan {
safe_action_family: "repo.planning_brief".to_string(),
target_path,
plan_summary: format!(
"Imagination derived a repo planning brief from accepted {} pressure.",
input.source
),
command,
commit_message: format!("Add planning brief for work item {}", input.item),
verification_asks: vec![
"Soul verifies the repo planning brief path changed and contains the accepted pressure summary.".to_string(),
"Soul verifies the brief names allowed next safe families, path/evidence requirements, and Mind/Self/Substrate/Hands/Soul/Bifrost/Idunn gates without authorizing action.".to_string(),
"Soul verifies no paths outside the declared planning brief changed.".to_string(),
],
rollback_hints: vec![
"Remove the generated planning brief if Imagination decomposed the pressure incorrectly.".to_string(),
],
derivation: plan_derivation_receipt(input, action_family, "repo.planning_brief"),
})
}
fn derive_repo_objective_draft_plan(
input: DeriveSafePlanInput<'_>,
action_family: &str,
@ -6223,6 +6377,82 @@ fn closure_family_assertions(
"Committed consensus brief preserves the private-state seal.".to_string(),
);
}
"repo.planning_brief" => {
push_assertion(
&mut assertions,
"planning-brief-schema-present",
content.contains("schema_version = \"epiphany.repo_planning_brief.v0\""),
"Committed planning brief carries the schema version.".to_string(),
);
push_assertion(
&mut assertions,
"planning-brief-family-present",
content.contains("safe_action_family = \"repo.planning_brief\""),
"Committed planning brief carries the safe action family.".to_string(),
);
push_assertion(
&mut assertions,
"planning-brief-summary-present",
content.contains(&compact_summary),
"Committed planning brief contains the accepted pressure summary.".to_string(),
);
push_assertion(
&mut assertions,
"planning-brief-decomposition-contract",
content.contains("[decomposition]")
&& content.contains("\"repo.consensus_brief\"")
&& content.contains("\"repo.objective_draft\"")
&& content.contains("\"repo.task_card\"")
&& content.contains("\"repo.work_order\"")
&& content.contains("\"repo.verification_request\"")
&& content.contains("\"repo.publication_request\"")
&& content.contains("candidate_items_must_name_requested_paths = true")
&& content.contains("candidate_items_must_name_verification_asks = true")
&& content.contains("candidate_items_must_name_evidence_needs = true"),
"Committed planning brief names the safe-family decomposition contract."
.to_string(),
);
push_assertion(
&mut assertions,
"planning-brief-gates-present",
content.contains("[gates]")
&& content.contains("mind_interpreter_required = true")
&& content.contains("self_queue_selection_required = true")
&& content.contains("substrate_gate_required_before_hands = true")
&& content.contains("hands_receipts_required_before_soul = true")
&& content.contains("soul_verdict_required_before_mind_map_admission = true")
&& content.contains("bifrost_required_before_publication = true")
&& content.contains("idunn_required_before_deployment_execution = true"),
"Committed planning brief names the ordered Mind/Self/Substrate/Hands/Soul/Bifrost/Idunn gates."
.to_string(),
);
push_assertion(
&mut assertions,
"planning-brief-authority-seals",
content.contains("[authority]")
&& content.contains("objective_adoption_authorized = false")
&& content.contains("self_scheduling_authorized = false")
&& content.contains("substrate_access_authorized = false")
&& content.contains("hands_action_authorized = false")
&& content.contains("shell_command_authorized = false")
&& content.contains("commit_authorized = false")
&& content.contains("publication_authorized = false")
&& content.contains("deployment_execution_authority = false")
&& content.contains("cross_body_mutation_authorized = false")
&& content.contains("private_verse_rummaging = false"),
"Committed planning brief denies adoption/scheduling/substrate/action/shell/commit/publication/deployment/cross-body authority."
.to_string(),
);
push_assertion(
&mut assertions,
"planning-brief-private-seal",
content.contains("private_state_exposed = false")
&& content.contains("private_worker_transcripts_allowed = false")
&& content.contains("raw_result_payloads_allowed = false"),
"Committed planning brief preserves private-state and transcript seals."
.to_string(),
);
}
"repo.objective_draft" => {
push_assertion(
&mut assertions,
@ -13050,6 +13280,7 @@ fn repo_work_safe_family_is_recognized(safe_family: &str) -> bool {
| "repo.collaboration_policy"
| "repo.collaboration_topic"
| "repo.consensus_brief"
| "repo.planning_brief"
| "repo.objective_draft"
| "repo.adoption_request"
| "repo.scheduling_request"
@ -13197,7 +13428,7 @@ fn print_usage() {
"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\
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-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-doctrine-update-request|repo-secret-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\
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-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-doctrine-update-request|repo-secret-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\
plan --workspace <repo> [--item <id>] --objective <text> --plan-summary <text> --command <command> --changed-path <path> --commit-message <text> [--adoption-evidence-ref <ref>]\n\
run --workspace <repo> [--item <id>] [--accept-receipt <path>] [--runtime-store <path>] [--requested-path <path>]\n\
adopt --workspace <repo> [--item <id>] [--run-receipt <path>] [--from-plan <path>] [--plan-summary <text>] [--adoption-evidence-ref <ref>] [--mind-adoption-rationale <text>]\n\

View file

@ -531,6 +531,23 @@ consensus state, public discussion refs, candidate action refs,
adoption/action/publication/cross-body authority, and
`privateStateExposed=false`.
The next family-friendly Imagination planning smoke proved safe-family
decomposition cargo: `.epiphany-smoke\repo-planning-brief-family-20260620-231539`
ran init -> online -> accept -> `derive-plan --action-family
repo-planning-brief --model-ref
repo-planning-brief-family-smoke-imagination-v1 --model-authored` -> tick
through run/adopt/execute/close on a fresh repo. The plan carried
`safeActionFamily=repo.planning_brief`; Hands committed only
`.epiphany/planning-briefs/repo-planning-brief-family.toml`; Soul passed with
`pathScopeMatched=true` and `familyAssertions.status=passed`; the committed
brief carried `schema_version = "epiphany.repo_planning_brief.v0"`, draft
Imagination decomposition state, candidate next safe families, requested-path /
verification-ask / evidence-need requirements, Mind/Self/Substrate/Hands/Soul /
Bifrost/Idunn gate ordering, denied objective adoption, scheduling, substrate
access, Hands action, shell, commit, publication, deployment execution,
cross-body mutation, private transcript/raw-result access, and
`privateStateExposed=false`.
The next Imagination adoption-boundary smoke proved Objective Draft cargo:
`.epiphany-smoke\repo-objective-draft-family-20260620-145012` ran init ->
online -> accept -> `derive-plan --action-family repo-objective-draft
@ -1653,7 +1670,7 @@ temptation wearing clean robes.
| Repo Body birth | `epiphany-repo init` exists and writes repo-local stores plus branch workbench intent. | Keep birth startup-only, review-gated, and branch-oriented. |
| Local Verse online | `epiphany-swarm online` seeds repo-local CultMesh, standing-faculty SoA, topology, liveness, Eve, and tool sight. | Keep private Verse sealed while exposing operator-safe repo status. |
| Persona/Bifrost intake | `epiphany-work accept` records pressure and candidate action refs without Hands authority. `epiphany-work persona-intake` now invokes the Persona bubble speech-audit path, records public discussion and candidate-action refs, then delegates to `accept`; wrapper mode `repo-persona-intake` exposes the operator mouth. | Deepen the intake-to-Imagination interpreter so richer model-authored action items can be proposed without granting Hands, publication, or durable-state authority at the mouth edge. |
| Imagination planning | `derive-plan` now writes a typed `epiphany.repo_work_imagination_action_items_receipt.v0` before the executable plan receipt. The action-item receipt can carry model provenance, allowed safe family, requested paths, verification asks, stop conditions, escalation reasons, planning facets (assumptions, constraints, non-goals, open questions, decision points, and evidence needs), and private-state seals; command text remains deterministic safe-family lowering for `append-worklog`, `planning-note`, `checklist-note`, `section-note` / `repo.markdown_managed_section`, `repo-status-section` / `repo.status_section`, `task-card` / `repo.task_card`, `repo-manifest` / `repo.body_manifest`, `repo-tool-capabilities` / `repo.tool_capabilities`, `repo-tool-request` / `repo.tool_request`, `repo-eve-surface` / `repo.eve_surface`, `repo-collaboration-policy` / `repo.collaboration_policy`, `repo-collaboration-topic` / `repo.collaboration_topic`, `repo-consensus-brief` / `repo.consensus_brief`, `repo-objective-draft` / `repo.objective_draft`, `repo-adoption-request` / `repo.adoption_request`, `repo-scheduling-request` / `repo.scheduling_request`, `repo-work-order` / `repo.work_order`, `repo-verification-request` / `repo.verification_request`, `repo-publication-request` / `repo.publication_request`, `repo-sync-request` / `repo.sync_request`, `repo-maintainer-review-request` / `repo.maintainer_review_request`, `repo-pr-request` / `repo.pr_request`, `repo-credit-request` / `repo.credit_request`, `repo-artifact-acceptance-request` / `repo.artifact_acceptance_request`, `repo-metrics-request` / `repo.metrics_request`, `repo-doctrine-update-request` / `repo.doctrine_update_request`, `repo-secret-policy-request` / `repo.secret_policy_request`, `repo-deployment-config` / `repo.deployment_config`, and `repo-deployment-request` / `repo.deployment_request`. `adopt` now writes `epiphany.repo_work_mind_adoption_decision.v0` before the main adoption receipt cites the decision and grants branch-local Hands authority, and refuses plan-derived items that lack explicit verification asks or planning evidence needs. `plan` remains manual quarantine scaffolding. | Deepen further interpreter behavior and useful repo-owned configuration/action classes without turning model text into arbitrary shell authority. |
| Imagination planning | `derive-plan` now writes a typed `epiphany.repo_work_imagination_action_items_receipt.v0` before the executable plan receipt. The action-item receipt can carry model provenance, allowed safe family, requested paths, verification asks, stop conditions, escalation reasons, planning facets (assumptions, constraints, non-goals, open questions, decision points, and evidence needs), and private-state seals; command text remains deterministic safe-family lowering for `append-worklog`, `planning-note`, `checklist-note`, `section-note` / `repo.markdown_managed_section`, `repo-status-section` / `repo.status_section`, `task-card` / `repo.task_card`, `repo-manifest` / `repo.body_manifest`, `repo-tool-capabilities` / `repo.tool_capabilities`, `repo-tool-request` / `repo.tool_request`, `repo-eve-surface` / `repo.eve_surface`, `repo-collaboration-policy` / `repo.collaboration_policy`, `repo-collaboration-topic` / `repo.collaboration_topic`, `repo-consensus-brief` / `repo.consensus_brief`, `repo-planning-brief` / `repo.planning_brief`, `repo-objective-draft` / `repo.objective_draft`, `repo-adoption-request` / `repo.adoption_request`, `repo-scheduling-request` / `repo.scheduling_request`, `repo-work-order` / `repo.work_order`, `repo-verification-request` / `repo.verification_request`, `repo-publication-request` / `repo.publication_request`, `repo-sync-request` / `repo.sync_request`, `repo-maintainer-review-request` / `repo.maintainer_review_request`, `repo-pr-request` / `repo.pr_request`, `repo-credit-request` / `repo.credit_request`, `repo-artifact-acceptance-request` / `repo.artifact_acceptance_request`, `repo-metrics-request` / `repo.metrics_request`, `repo-doctrine-update-request` / `repo.doctrine_update_request`, `repo-secret-policy-request` / `repo.secret_policy_request`, `repo-deployment-config` / `repo.deployment_config`, and `repo-deployment-request` / `repo.deployment_request`. `repo.planning_brief` is the rough-pressure decomposition family: it names candidate next safe families, requested-path / verification-ask / evidence-need requirements, and Mind/Self/Substrate/Hands/Soul/Bifrost/Idunn gates while granting no action authority. `adopt` now writes `epiphany.repo_work_mind_adoption_decision.v0` before the main adoption receipt cites the decision and grants branch-local Hands authority, and refuses plan-derived items that lack explicit verification asks or planning evidence needs. `plan` remains manual quarantine scaffolding. | Deepen further interpreter behavior and semantic closure/map readback without turning model text into arbitrary shell authority. |
| 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` and `repo-work-service-runbook` write Idunn lifecycle receipts/artifacts for the same queue-run command without launching it. | Keep any future queue-run service launch/install behind Idunn and explicit 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. |

View file

@ -155,6 +155,7 @@ remembers doctrine; the branch remembers the blade.
- 2026-06-20: `repo-deployment-request` is now live as Idunn-facing deployment request cargo. `epiphany-work derive-plan --action-family repo-deployment-request` writes `.epiphany/deployment-requests/<item>.toml` with safe family `repo.deployment_request`, status `awaiting-idunn-review`, git-push-observed-by-Idunn trigger, Idunn/Maintainer ownership, target environment, git ref/branch, deployment script ref, script hash or review ref, host access policy, secret policy, rollback plan, aftercare checks, Eyes/Mind/Soul/maintainer/secret-policy/Bifrost/Idunn deployment/aftercare receipt requirements, and denials for direct deployment, SSH, git push, service lifecycle, Hands, publication, merge, cross-body mutation, private Verse rummaging, and private-state exposure. Soul closure assertions inspect schema, family, summary, request state, antecedents, receipt contract, deployment packet, authority gates, and private-state seal. Focused smoke `.epiphany-smoke\repo-deployment-request-family-20260620-195605` ran init -> online -> accept -> repo-deployment-request derive-plan -> tick run/adopt/execute/close; Hands committed only `.epiphany/deployment-requests/repo-deployment-request-family.toml`, Soul passed with `pathScopeMatched=true`, `familyAssertions.status=passed`, `awaitingIdunnReview=true`, `deploymentTrigger=git-push-observed-by-idunn`, `deploymentAuthority=false`, `sshAuthority=false`, `gitPushAuthority=false`, `serviceLifecycleAuthority=false`, and `privateStateExposed=false`. Current remaining repo-swarm MVP organs are deeper interpreter semantics, further reviewed config/action request families, richer closure depth, and explicit Idunn deployment execution/audit under operator authority.
- 2026-06-20: `repo-deployment-config` is now live as repo-owned Idunn deployment configuration cargo. `epiphany-work derive-plan --action-family repo-deployment-config` writes `.epiphany/deployment.toml` with safe family `repo.deployment_config`, `enabled=false`, owner `Idunn`, trigger `git-push-observed-by-idunn`, watched ref `refs/heads/main`, deployment script ref, script hash/review requirement, host policy, secret policy, rollback, aftercare checks, Idunn CultMesh intent/receipt/aftercare contracts, daemon-owned execution, and denials for direct deployment, SSH, git push, service lifecycle, Hands, publication, merge, cross-body mutation, private Verse rummaging, and private-state exposure. Focused smoke `.epiphany-smoke\repo-deployment-config-family-20260620-211809` ran init -> online -> accept -> repo-deployment-config derive-plan -> tick run/adopt/execute/close; Hands committed only `.epiphany/deployment.toml`, Soul passed with `pathScopeMatched=true`, `familyAssertions.status=passed`, `deploymentConfigEnabled=false`, `daemonOwnsExecution=true`, and `privateStateExposed=false`. Current remaining repo-swarm MVP organs are deeper interpreter semantics, richer closure depth, and explicit Idunn deployment execution/audit under operator authority.
- 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-20: `repo-planning-brief` is now live as the family-friendly Imagination decomposition cargo. `epiphany-work derive-plan --action-family repo-planning-brief` writes `.epiphany/planning-briefs/<item>.toml` with safe family `repo.planning_brief`, status `draft`, candidate next safe families, requested-path / verification-ask / evidence-need 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. Soul closure assertions inspect schema, family, summary, decomposition contract, gate order, authority seals, and private-state seals. Focused smoke `.epiphany-smoke\repo-planning-brief-family-20260620-231539` 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`, `mindInterpreterRequired=true`, `soulEvidenceNeedsRequired=true`, `idunnDeploymentExecutionRequired=true`, and `privateStateExposed=false`. Current remaining repo-swarm MVP organs are deeper interpreter semantics, richer closure/map readback, and Idunn-owned queue-run service lifecycle under explicit operator authority.
- 2026-06-20: Mind now has explicit repo-work safe-family and requested-path guards before branch-local Hands authority. `adopt --from-plan` treats unsupported plan-derived safe-family labels as refused interpreter decisions, writes `epiphany.repo_work_mind_adoption_decision.v0` with `status=refused-unsupported-safe-family`, keeps `actionItemAccepted=false` and `safeFamilyRecognized=false`, grants no Hands/durable-state/service/publication/cross-body/private-state authority, and writes no normal adoption receipt. It also compares the sorted action-item `requestedPaths` against the sorted plan action `changedPaths`; mismatches write `status=refused-requested-path-mismatch`, keep `safeFamilyRecognized=true` but `requestedPathsMatchPlan=false`, point the next gate at `imagination.replan_with_matching_requested_paths`, and grant no Hands/durable-state/service/publication/cross-body/private-state authority. Focused smokes `.epiphany-smoke\repo-mind-safe-family-guard-20260620-194425` and `.epiphany-smoke\repo-mind-path-guard-20260620-194239` prove both refusal paths; earlier positive smokes `.epiphany-smoke\repo-planning-facets-20260620-190916` and `.epiphany-smoke\closure-model-gate-20260620-190916` prove recognized planning facets and closure model gates still pass. Current remaining repo-swarm MVP organs are deeper interpreter semantics beyond adoption refusal, more useful repo-owned configuration/action families, richer closure depth, and Idunn-owned queue-run service lifecycle under explicit operator authority.
- 2026-06-20: Mind now also refuses plan-derived repo work that is not evidence-ready. `derive-plan` embeds verification asks in the Imagination action-item receipt, `adopt --from-plan` records verification asks and planning evidence needs in `epiphany.repo_work_mind_interpretation.v0`, and empty verification asks or evidence needs write `status=refused-missing-evidence-needs` with next gate `imagination.replan_with_explicit_soul_evidence_needs`. The refusal grants no Hands, durable-state, service, publication, cross-body, or private-state authority and writes no adoption receipt. Focused proof `.epiphany-smoke\repo-mind-evidence-guard-20260620-224426` tampers both arrays empty and proves the refusal; regression `.epiphany-smoke\repo-planning-facets-20260620-224428` proves normal planning facets still close through Soul/Modeling/Mind.
- 2026-06-20: `repo-eve-surface` is now live as repo-owned Eve/CultUI surface contract cargo. `epiphany-work derive-plan --action-family repo-eve-surface` writes `.epiphany/eve-surfaces/<item>.toml` with safe family `repo.eve_surface`, compact agent TUI and GUI lowering contracts, local/public Verse routing, Odin discovery, provider-owned surface identity, Persona/human collaboration flags, feedback routing to Imagination, and denials for renderer ownership, rendering/state/publication/service/cross-body authority, private Verse rummaging, and private-state exposure. Soul closure assertions inspect schema, family, summary, surface routing, Verse routing, CultUI contracts, collaboration route, authority seals, and private-state seal. Focused smoke `.epiphany-smoke\repo-eve-surface-family-20260620-165927` ran init -> online -> accept -> repo-eve-surface derive-plan -> tick run/adopt/execute/close; Hands committed only `.epiphany/eve-surfaces/repo-eve-surface-family.toml`, Soul passed with `pathScopeMatched=true`, `familyAssertions.status=passed`, `hasCultUiContracts=true`, `hasVerseRouting=true`, `odinDiscoverable=true`, `feedbackRoutesToImagination=true`, `rendererOwnsTruth=false`, `renderingAuthority=false`, `stateAuthority=false`, `publicationAuthority=false`, `serviceLifecycleAuthority=false`, `crossBodyMutationAuthority=false`, `privateVerseRummaging=false`, and `privateStateExposed=false`. Current remaining repo-swarm MVP organs are deeper interpreter/adoption semantics, more useful repo-owned configuration/action families, and Idunn-owned queue-run service lifecycle under explicit operator authority.

Binary file not shown.

File diff suppressed because one or more lines are too long