Delete unowned executable surfaces

This commit is contained in:
Meta Vens 2026-08-23 01:32:47 +02:00
commit 1d5a1f1793
51 changed files with 87 additions and 19339 deletions

View file

@ -20,27 +20,11 @@ name = "epiphany-semantic-recovery-smoke"
path = "src/bin/epiphany-semantic-recovery-smoke.rs"
required-features = ["semantic-recovery-smoke"]
[[bin]]
name = "epiphany-atlas-publisher"
path = "src/bin/epiphany-atlas-publisher.rs"
[[bin]]
name = "epiphany-model-entanglement-projector"
path = "src/bin/epiphany-model-entanglement-projector.rs"
[[bin]]
name = "epiphany-atlas-impact-ingress"
path = "src/bin/epiphany-atlas-impact-ingress.rs"
[[bin]]
name = "epiphany-workspace-coverage-recovery-smoke"
path = "src/bin/epiphany-workspace-coverage-recovery-smoke.rs"
required-features = ["workspace-coverage-recovery-smoke"]
[[bin]]
name = "epiphany-release"
path = "src/bin/epiphany-release.rs"
[[bin]]
name = "epiphany-agent-memory-store"
path = "src/bin/epiphany-agent-memory-store.rs"
@ -61,42 +45,14 @@ path = "src/bin/epiphany-cluster-daemon.rs"
name = "epiphany-cultmesh-smoke"
path = "src/bin/epiphany-cultmesh-smoke.rs"
[[bin]]
name = "epiphany-daemon-supervisor"
path = "src/bin/epiphany-daemon-supervisor.rs"
[[bin]]
name = "epiphany-daemon-survival-rehearsal-smoke"
path = "src/bin/epiphany-daemon-survival-rehearsal-smoke.rs"
[[bin]]
name = "epiphany-frontier-proposal"
path = "src/bin/epiphany-frontier-proposal.rs"
[[bin]]
name = "epiphany-hands-action"
path = "src/bin/epiphany-hands-action.rs"
[[bin]]
name = "epiphany-hands-action-smoke"
path = "src/bin/epiphany-hands-action-smoke.rs"
[[bin]]
name = "epiphany-heartbeat-store"
path = "src/bin/epiphany-heartbeat-store.rs"
[[bin]]
name = "epiphany-host-identity"
path = "src/bin/epiphany-host-identity.rs"
[[bin]]
name = "epiphany-memory-semantic"
path = "src/bin/epiphany-memory-semantic.rs"
[[bin]]
name = "epiphany-memory-semantic-projector"
path = "src/bin/epiphany-memory-semantic-projector.rs"
[[bin]]
name = "epiphany-mvp-coordinator-smoke"
path = "src/bin/epiphany-mvp-coordinator-smoke.rs"
@ -121,30 +77,14 @@ path = "src/bin/epiphany-persona-discord-crossing-fixture.rs"
name = "epiphany-persona-discord-rudp-client-fixture"
path = "src/bin/epiphany-persona-discord-rudp-client-fixture.rs"
[[bin]]
name = "epiphany-persona-discord-permit"
path = "src/bin/epiphany-persona-discord-permit.rs"
[[bin]]
name = "epiphany-persona-discord-permit-identity"
path = "src/bin/epiphany-persona-discord-permit-identity.rs"
[[bin]]
name = "epiphany-persona-feedback-causal-smoke"
path = "src/bin/epiphany-persona-feedback-causal-smoke.rs"
[[bin]]
name = "epiphany-persona-feedback-ingress"
path = "src/bin/epiphany-persona-feedback-ingress.rs"
[[bin]]
name = "epiphany-persona-memory-recall-smoke"
path = "src/bin/epiphany-persona-memory-recall-smoke.rs"
[[bin]]
name = "epiphany-persona-mouth-identity"
path = "src/bin/epiphany-persona-mouth-identity.rs"
[[bin]]
name = "epiphany-public-source-gate-probe"
path = "src/bin/epiphany-public-source-gate-probe.rs"
@ -162,102 +102,6 @@ path = "src/bin/epiphany-persona-reddit.rs"
name = "epiphany-prepare-compaction"
path = "src/bin/epiphany-prepare-compaction.rs"
[[bin]]
name = "epiphany-repo"
path = "src/bin/epiphany-repo.rs"
[[bin]]
name = "epiphany-repo-adoption-request-family-smoke"
path = "src/bin/epiphany-repo-adoption-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-birth-runner"
path = "src/bin/epiphany-repo-birth-runner.rs"
[[bin]]
name = "epiphany-repo-closure-source-grounding-smoke"
path = "src/bin/epiphany-repo-closure-source-grounding-smoke.rs"
[[bin]]
name = "epiphany-repo-credit-request-family-smoke"
path = "src/bin/epiphany-repo-credit-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-dependency-policy-family-smoke"
path = "src/bin/epiphany-repo-dependency-policy-family-smoke.rs"
[[bin]]
name = "epiphany-repo-deployment-request-family-smoke"
path = "src/bin/epiphany-repo-deployment-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-interpreter-brief-family-smoke"
path = "src/bin/epiphany-repo-interpreter-brief-family-smoke.rs"
[[bin]]
name = "epiphany-repo-livefire-closure-smoke"
path = "src/bin/epiphany-repo-livefire-closure-smoke.rs"
[[bin]]
name = "epiphany-repo-maintainer-review-request-family-smoke"
path = "src/bin/epiphany-repo-maintainer-review-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-objective-draft-family-smoke"
path = "src/bin/epiphany-repo-objective-draft-family-smoke.rs"
[[bin]]
name = "epiphany-repo-personality"
path = "src/bin/epiphany-repo-personality.rs"
[[bin]]
name = "epiphany-repo-personality-smoke"
path = "src/bin/epiphany-repo-personality-smoke.rs"
[[bin]]
name = "epiphany-repo-pr-request-family-smoke"
path = "src/bin/epiphany-repo-pr-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-publication-request-family-smoke"
path = "src/bin/epiphany-repo-publication-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-readiness-review-request-family-smoke"
path = "src/bin/epiphany-repo-readiness-review-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-scheduling-request-family-smoke"
path = "src/bin/epiphany-repo-scheduling-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-secret-policy-family-smoke"
path = "src/bin/epiphany-repo-secret-policy-family-smoke.rs"
[[bin]]
name = "epiphany-repository-body"
path = "src/bin/epiphany-repository-body.rs"
[[bin]]
name = "epiphany-repo-sync-request-family-smoke"
path = "src/bin/epiphany-repo-sync-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-tool-request-family-smoke"
path = "src/bin/epiphany-repo-tool-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-verification-request-family-smoke"
path = "src/bin/epiphany-repo-verification-request-family-smoke.rs"
[[bin]]
name = "epiphany-repo-work-order-family-smoke"
path = "src/bin/epiphany-repo-work-order-family-smoke.rs"
[[bin]]
name = "epiphany-repo-work-service-lifecycle-smoke"
path = "src/bin/epiphany-repo-work-service-lifecycle-smoke.rs"
[[bin]]
name = "epiphany-rider-bridge"
path = "src/bin/epiphany-rider-bridge.rs"
@ -266,30 +110,14 @@ path = "src/bin/epiphany-rider-bridge.rs"
name = "epiphany-rider-bridge-smoke"
path = "src/bin/epiphany-rider-bridge-smoke.rs"
[[bin]]
name = "epiphany-runtime-spine"
path = "src/bin/epiphany-runtime-spine.rs"
[[bin]]
name = "epiphany-runtime-store-benchmark"
path = "src/bin/epiphany-runtime-store-benchmark.rs"
[[bin]]
name = "epiphany-runtime-store-migrate"
path = "src/bin/epiphany-runtime-store-migrate.rs"
[[bin]]
name = "epiphany-state"
path = "src/bin/epiphany-state.rs"
[[bin]]
name = "epiphany-state-ledger-store"
path = "src/bin/epiphany-state-ledger-store.rs"
[[bin]]
name = "epiphany-swarm"
path = "src/bin/epiphany-swarm.rs"
[[bin]]
name = "epiphany-unity-bridge"
path = "src/bin/epiphany-unity-bridge.rs"
@ -298,10 +126,6 @@ path = "src/bin/epiphany-unity-bridge.rs"
name = "epiphany-unity-bridge-smoke"
path = "src/bin/epiphany-unity-bridge-smoke.rs"
[[bin]]
name = "epiphany-verse-query"
path = "src/bin/epiphany-verse-query.rs"
[[bin]]
name = "epiphany-void-memory"
path = "src/bin/epiphany-void-memory.rs"
@ -314,11 +138,6 @@ path = "src/bin/epiphany-weksa-interlingua-smoke.rs"
name = "epiphany-work"
path = "src/bin/epiphany-work.rs"
[[bin]]
name = "epiphany-workspace-coverage-projector"
path = "src/bin/epiphany-workspace-coverage-projector.rs"
[dependencies]
anyhow = "1"
bm25 = "2.3.2"

View file

@ -916,10 +916,6 @@ pub struct EpiphanyRolePromptConfig {
#[allow(dead_code)]
pub research: String,
#[allow(dead_code)]
pub repo_personality: String,
#[allow(dead_code)]
pub repo_memory: String,
#[allow(dead_code)]
pub persona: String,
}
@ -1123,11 +1119,6 @@ mod tests {
("roles.modeling", prompts.roles.modeling.as_str()),
("roles.verification", prompts.roles.verification.as_str()),
("roles.research", prompts.roles.research.as_str()),
(
"roles.repo_personality",
prompts.roles.repo_personality.as_str(),
),
("roles.repo_memory", prompts.roles.repo_memory.as_str()),
("roles.persona", prompts.roles.persona.as_str()),
(
"implementation.continue_template",

View file

@ -1,398 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-adoption-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Adoption Request Family Smoke\n\nThis repository proves branch-local Mind adoption requests.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed repo adoption request smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-adoption-request-family"],
&repo,
)?;
let item = "repo-adoption-request-family";
let target_path = ".epiphany/adoption-requests/repo-adoption-request-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-adoption-request-family-smoke",
"--topic",
"repo-adoption-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-adoption-request-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",
"Ask Mind to adopt or refuse a reviewable Objective Draft before Self schedules branch-local work.",
"--candidate-action-ref",
"candidate-action://repo-adoption-request-family/mind-review",
"--candidate-action-ref",
"candidate-action://repo-adoption-request-family/refuse-or-adopt",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-adoption-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-adoption-request",
"--model-ref",
"repo-adoption-request-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 request_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.adoption_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_adoption_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.adoption_request\"",
)?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-mind-review\"")?;
require_text(
&request_text,
"requested_decision = \"adopt-or-refuse-objective-draft\"",
)?;
require_text(&request_text, "mind_review_required = true")?;
require_text(&request_text, "mind_state_commit_required = true")?;
require_text(&request_text, "self_scheduling_after_mind_only = true")?;
require_text(&request_text, "[decision_contract]")?;
require_text(
&request_text,
"allowed_verdicts = [\"adopted\", \"refused\", \"needs-more-consensus\"]",
)?;
require_text(
&request_text,
"requires_receipt = \"epiphany.mind.gateway_review\"",
)?;
require_text(
&request_text,
"requires_commit_receipt_if_adopted = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(&request_text, "does_not_modify_state = true")?;
require_text(&request_text, "objective_draft_required = true")?;
require_text(&request_text, "consensus_brief_required = true")?;
require_text(&request_text, "objective_adoption_authorized = false")?;
require_text(&request_text, "state_commit_authorized = false")?;
require_text(&request_text, "self_scheduling_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_work_adoption_request_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"],
"awaitingMindReview": true,
"doesNotModifyState": true,
"stateCommitAuthorized": false,
"selfSchedulingAuthorized": false,
"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 adoption request 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

@ -1,533 +0,0 @@
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, PathBuf};
use std::process::Child;
use std::process::Command;
use std::process::Stdio;
use std::thread;
use std::time::{Duration, Instant};
const DEFAULT_MODEL_RUNTIME_BIN: &str = "epiphany-model-runtime";
const DEFAULT_TIMEOUT_SECONDS: u64 = 900;
fn main() -> Result<()> {
let args = Args::parse()?;
let summary = run(args)?;
println!("{}", serde_json::to_string_pretty(&summary)?);
Ok(())
}
#[derive(Clone, Debug)]
struct Args {
repo: PathBuf,
baseline: PathBuf,
artifact_dir: PathBuf,
init_store: PathBuf,
agent_store: PathBuf,
heartbeat_store: PathBuf,
runtime_store: PathBuf,
model_runtime_bin: String,
model_provider: String,
executor: String,
mode: String,
model: Option<String>,
timeout_seconds: u64,
auto_accept: bool,
}
impl Args {
fn parse() -> Result<Self> {
let root = env::current_dir().context("failed to resolve current dir")?;
let mut args = env::args().skip(1);
let mut parsed = Args {
repo: root.clone(),
baseline: root
.join(".epiphany-imports")
.join("repo-personality-terrain")
.join("baseline.msgpack"),
artifact_dir: root.join(".epiphany-birth-runner"),
init_store: root.join("state").join("repo-initialization.msgpack"),
agent_store: root.join("state").join("agents.msgpack"),
heartbeat_store: root.join("state").join("agent-heartbeats.msgpack"),
runtime_store: root.join("state").join("runtime-spine.msgpack"),
model_runtime_bin: DEFAULT_MODEL_RUNTIME_BIN.to_string(),
model_provider: "openai-codex".to_string(),
executor: "model-runtime".to_string(),
mode: "plan".to_string(),
model: None,
timeout_seconds: DEFAULT_TIMEOUT_SECONDS,
auto_accept: false,
};
while let Some(arg) = args.next() {
match arg.as_str() {
"--repo" => parsed.repo = take_path(&mut args, "--repo")?,
"--baseline" => parsed.baseline = take_path(&mut args, "--baseline")?,
"--artifact-dir" => parsed.artifact_dir = take_path(&mut args, "--artifact-dir")?,
"--init-store" => parsed.init_store = take_path(&mut args, "--init-store")?,
"--agent-store" => parsed.agent_store = take_path(&mut args, "--agent-store")?,
"--heartbeat-store" => {
parsed.heartbeat_store = take_path(&mut args, "--heartbeat-store")?;
}
"--runtime-store" => {
parsed.runtime_store = take_path(&mut args, "--runtime-store")?
}
"--model-runtime-bin" => {
parsed.model_runtime_bin = take_string(&mut args, "--model-runtime-bin")?;
}
"--openai-runtime-bin" => {
parsed.model_runtime_bin = take_string(&mut args, "--openai-runtime-bin")?;
}
"--model-provider" => {
parsed.model_provider = take_string(&mut args, "--model-provider")?;
}
"--executor" => parsed.executor = take_string(&mut args, "--executor")?,
"--mode" => parsed.mode = take_string(&mut args, "--mode")?,
"--model" => parsed.model = Some(take_string(&mut args, "--model")?),
"--timeout-seconds" => {
parsed.timeout_seconds =
take_string(&mut args, "--timeout-seconds")?.parse()?;
}
"--auto-accept" => parsed.auto_accept = true,
other => return Err(anyhow!("unknown argument {other:?}")),
}
}
if !matches!(parsed.mode.as_str(), "plan" | "run") {
return Err(anyhow!("--mode must be plan or run"));
}
if parsed.executor == "openai-runtime" {
parsed.executor = "model-runtime".to_string();
}
if parsed.executor != "model-runtime" {
return Err(anyhow!(
"--executor must be model-runtime; Codex CLI execution is not an Epiphany agent prompt path"
));
}
Ok(parsed)
}
}
fn run(args: Args) -> Result<Value> {
fs::create_dir_all(&args.artifact_dir)
.with_context(|| format!("failed to create {}", args.artifact_dir.display()))?;
let startup_dir = args.artifact_dir.join("startup");
fs::create_dir_all(&startup_dir)?;
let startup = run_repo_personality_json(&[
"startup".to_string(),
"--repo".to_string(),
args.repo.display().to_string(),
"--baseline".to_string(),
args.baseline.display().to_string(),
"--artifact-dir".to_string(),
startup_dir.display().to_string(),
"--init-store".to_string(),
args.init_store.display().to_string(),
])?;
let packets = startup["generatedPackets"]
.as_array()
.cloned()
.unwrap_or_default();
let mut executions = Vec::new();
for packet in packets {
let kind = packet["kind"].as_str().unwrap_or("unknown");
let packet_path = path_from_value(&packet["packetPath"])?;
let execution_dir = args.artifact_dir.join(sanitize(kind));
fs::create_dir_all(&execution_dir)?;
let packet_value = read_json(&packet_path)?;
let prompt_path = execution_dir.join("prompt.md");
let schema_path = execution_dir.join("output-schema.json");
let result_path = execution_dir.join("result.json");
let request_path = execution_dir.join("model-request.json");
let runtime_summary_path = execution_dir.join("model-runtime-summary.json");
let stdout_path = execution_dir.join("executor.stdout.log");
let stderr_path = execution_dir.join("executor.stderr.log");
let prompt = render_specialist_prompt(kind, &packet_value)?;
let schema = output_schema_for_kind(kind, &packet_value)?;
write_text(&prompt_path, &prompt)?;
write_json(&schema_path, &schema)?;
let mut execution = json!({
"kind": kind,
"birthOnly": true,
"executionOwner": "repo-initialization-startup-runner",
"heartbeatParticipant": Value::Null,
"packetPath": packet_path,
"promptPath": prompt_path,
"schemaPath": schema_path,
"resultPath": result_path,
"requestPath": request_path,
"runtimeSummaryPath": runtime_summary_path,
"stdoutPath": stdout_path,
"stderrPath": stderr_path,
"executor": args.executor.clone(),
"modelRuntimeBin": args.model_runtime_bin.clone(),
"modelProvider": args.model_provider.clone(),
"status": "planned",
"acceptCommand": accept_command(kind, &args, &packet_path, &result_path),
});
if args.mode == "run" {
let run_result = run_openai_runtime_specialist(
&args,
kind,
&prompt,
&schema_path,
&request_path,
&result_path,
&runtime_summary_path,
&stdout_path,
&stderr_path,
)?;
execution["status"] = run_result["status"].clone();
execution["exitCode"] = run_result["exitCode"].clone();
execution["timedOut"] = run_result["timedOut"].clone();
if result_path.exists() {
execution["result"] = read_json(&result_path).unwrap_or_else(|err| {
json!({
"status": "invalid-json",
"error": err.to_string(),
})
});
}
if args.auto_accept && execution["status"] == "completed" {
execution["acceptance"] = run_repo_personality_json(&accept_args(
kind,
&args,
&packet_path,
&result_path,
))?;
}
}
executions.push(execution);
}
let summary = json!({
"schemaVersion": "epiphany.repo_birth_runner.v0",
"createdAt": Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
"mode": args.mode,
"repo": args.repo,
"baseline": args.baseline,
"artifactDir": args.artifact_dir,
"initStore": args.init_store,
"agentStore": args.agent_store,
"heartbeatStore": args.heartbeat_store,
"runtimeStore": args.runtime_store,
"executor": args.executor,
"modelRuntimeBin": args.model_runtime_bin,
"modelProvider": args.model_provider,
"startup": startup,
"executions": executions,
"requiresReview": !args.auto_accept,
"nextSafeMove": if executions.is_empty() {
"Birth initialization records are present; continue startup."
} else if args.mode == "plan" {
"Review planned startup-only birth executions, then rerun with --mode run."
} else if args.auto_accept {
"Review auto-accepted smoke output and continue startup."
} else {
"Review result.json for each birth specialist, then run the shown accept-init command."
}
});
write_json(
&args.artifact_dir.join("birth-runner-summary.json"),
&summary,
)?;
Ok(summary)
}
#[allow(clippy::too_many_arguments)]
fn run_openai_runtime_specialist(
args: &Args,
kind: &str,
prompt: &str,
schema_path: &Path,
request_path: &Path,
result_path: &Path,
runtime_summary_path: &Path,
stdout_path: &Path,
stderr_path: &Path,
) -> Result<Value> {
let schema_text = fs::read_to_string(schema_path)
.with_context(|| format!("failed to read {}", schema_path.display()))?;
let model = args.model.clone().unwrap_or_else(|| "gpt-5.4".to_string());
let request_id = format!(
"repo-birth-{}-{}",
sanitize(kind),
Utc::now().timestamp_millis()
);
let request = json!({
"schema_id": "epiphany.model_request.v0",
"request_id": request_id,
"conversation_id": format!("repo-birth-{}", sanitize(kind)),
"provider": args.model_provider.clone(),
"model": model,
"instructions": format!(
"{prompt}\n\nReturn only a single JSON object matching this output schema. No Markdown, no commentary.\n\n```json\n{schema_text}\n```"
),
"input": [
{
"UserText": {
"text": "Execute this startup-only Epiphany birth distiller packet and return the reviewable JSON result."
}
}
],
"reasoning_effort": Value::Null,
"reasoning_summary": Value::Null,
"service_tier": Value::Null,
"output_contract_id": format!("repo-birth-{kind}")
});
write_json(request_path, &request)?;
let mut command = Command::new(&args.model_runtime_bin);
command
.arg("model-turn")
.arg("--provider")
.arg(&args.model_provider)
.arg("--store")
.arg(&args.runtime_store)
.arg("--request")
.arg(request_path)
.arg("--objective")
.arg(format!("Run startup-only repo birth specialist {kind}"))
.arg("--default-model")
.arg(&model)
.arg("--output-last-message")
.arg(result_path)
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let child = command
.spawn()
.context("failed to spawn model runtime model-turn")?;
wait_for_child(
child,
args.timeout_seconds,
stdout_path,
stderr_path,
Some(runtime_summary_path),
)
}
fn wait_for_child(
mut child: Child,
timeout_seconds: u64,
stdout_path: &Path,
stderr_path: &Path,
stdout_json_copy_path: Option<&Path>,
) -> Result<Value> {
let deadline = Instant::now() + Duration::from_secs(timeout_seconds);
loop {
if let Some(status) = child.try_wait()? {
let output = child.wait_with_output()?;
write_bytes(stdout_path, &output.stdout)?;
write_bytes(stderr_path, &output.stderr)?;
if let Some(path) = stdout_json_copy_path {
write_bytes(path, &output.stdout)?;
}
return Ok(json!({
"status": if status.success() { "completed" } else { "failed" },
"exitCode": status.code(),
"timedOut": false,
}));
}
if Instant::now() >= deadline {
let _ = child.kill();
let output = child.wait_with_output()?;
write_bytes(stdout_path, &output.stdout)?;
write_bytes(stderr_path, &output.stderr)?;
if let Some(path) = stdout_json_copy_path {
write_bytes(path, &output.stdout)?;
}
return Ok(json!({
"status": "timeout",
"exitCode": Value::Null,
"timedOut": true,
}));
}
thread::sleep(Duration::from_millis(250));
}
}
fn render_specialist_prompt(kind: &str, packet: &Value) -> Result<String> {
Ok(format!(
"{}\n\n# Startup-Only Birth Packet\n\nYou are executing exactly one repo initialization birth specialist packet. Do not edit files. Do not mutate state. Return only JSON that matches the provided schema. The coordinator/Self will review and decide whether to accept the result.\n\n```json\n{}\n```\n",
packet["prompt"].as_str().unwrap_or(match kind {
"repo-trajectory" => "Act as the Epiphany Repo Trajectory Distiller.",
"repo-personality" => "Act as the Epiphany Repo Personality Distiller.",
"repo-memory" => "Act as the Epiphany Repo Memory Distiller.",
_ => "Act as a startup-only Epiphany birth specialist.",
}),
serde_json::to_string_pretty(packet)?
))
}
fn output_schema_for_kind(kind: &str, packet: &Value) -> Result<Value> {
let expected = packet.get("expectedOutput").cloned().unwrap_or(Value::Null);
let schema = match kind {
"repo-trajectory" => json!({
"type": "object",
"required": ["verdict", "summary", "confidence", "selfImage", "trajectoryNarrative", "implicitGoals", "antiGoals", "roleBiases", "selfPatchCandidates", "initializationRecord", "doNotMutate", "nextSafeMove"],
"properties": {
"verdict": {"type": "string", "enum": ["ready-for-review", "needs-more-history", "reject"]},
"summary": {"type": "string"},
"confidence": {"type": "number"},
"selfImage": {"type": "string"},
"trajectoryNarrative": {"type": "string"},
"implicitGoals": {"type": "array", "items": {"type": "string"}},
"antiGoals": {"type": "array", "items": {"type": "string"}},
"roleBiases": {"type": "array", "items": {"type": "object"}},
"selfPatchCandidates": {"type": "array", "items": {"type": "object"}},
"initializationRecord": {"type": "object"},
"doNotMutate": {"type": "array", "items": {"type": "string"}},
"nextSafeMove": {"type": "string"}
},
"additionalProperties": true,
"xEpiphanyExpectedOutput": expected,
}),
"repo-personality" => json!({
"type": "object",
"required": ["verdict", "summary", "confidence", "roleQuirks", "selfPatchCandidates", "initializationRecord", "doNotMutate", "nextSafeMove"],
"properties": {
"verdict": {"type": "string", "enum": ["ready-for-review", "needs-more-terrain", "reject"]},
"summary": {"type": "string"},
"confidence": {"type": "number"},
"roleQuirks": {"type": "array", "items": {"type": "object"}},
"selfPatchCandidates": {"type": "array", "items": {"type": "object"}},
"initializationRecord": {"type": "object"},
"doNotMutate": {"type": "array", "items": {"type": "string"}},
"nextSafeMove": {"type": "string"}
},
"additionalProperties": true,
"xEpiphanyExpectedOutput": expected,
}),
"repo-memory" => json!({
"type": "object",
"required": ["verdict", "summary", "confidence", "roleMemoryPatches", "initializationRecord", "doNotMutate", "nextSafeMove"],
"properties": {
"verdict": {"type": "string", "enum": ["ready-for-review", "needs-more-terrain", "reject"]},
"summary": {"type": "string"},
"confidence": {"type": "number"},
"roleMemoryPatches": {"type": "array", "items": {"type": "object"}},
"globalMemoryCandidates": {"type": "array", "items": {"type": "object"}},
"initializationRecord": {"type": "object"},
"doNotMutate": {"type": "array", "items": {"type": "string"}},
"nextSafeMove": {"type": "string"}
},
"additionalProperties": true,
"xEpiphanyExpectedOutput": expected,
}),
other => return Err(anyhow!("unsupported birth specialist kind {other:?}")),
};
Ok(schema)
}
fn accept_command(kind: &str, args: &Args, packet_path: &Path, result_path: &Path) -> Vec<String> {
accept_args(kind, args, packet_path, result_path)
}
fn accept_args(kind: &str, args: &Args, packet_path: &Path, result_path: &Path) -> Vec<String> {
let mut out = vec![
"accept-init".to_string(),
"--init-store".to_string(),
args.init_store.display().to_string(),
"--packet".to_string(),
packet_path.display().to_string(),
"--kind".to_string(),
kind.to_string(),
"--accepted-by".to_string(),
"Self".to_string(),
"--summary".to_string(),
format!("Accepted {kind} birth specialist result after review."),
"--result".to_string(),
result_path.display().to_string(),
"--agent-store".to_string(),
args.agent_store.display().to_string(),
"--apply-self-patches".to_string(),
"true".to_string(),
];
if kind == "repo-personality" {
out.extend([
"--heartbeat-store".to_string(),
args.heartbeat_store.display().to_string(),
"--apply-heartbeat-seeds".to_string(),
"true".to_string(),
]);
}
out
}
fn run_repo_personality_json(args: &[String]) -> Result<Value> {
let exe = native_exe("epiphany-repo-personality");
let output = Command::new(&exe)
.args(args)
.output()
.with_context(|| format!("failed to run {}", exe.display()))?;
if !output.status.success() {
return Err(anyhow!(
"epiphany-repo-personality failed: {}",
String::from_utf8_lossy(&output.stderr)
));
}
serde_json::from_slice(&output.stdout)
.with_context(|| format!("epiphany-repo-personality returned invalid JSON"))
}
fn native_exe(name: &str) -> PathBuf {
let target_dir = env::var_os("CARGO_TARGET_DIR")
.unwrap_or_else(|| r"C:\Users\Meta\.cargo-target-codex".into());
PathBuf::from(target_dir)
.join("debug")
.join(format!("{name}{}", env::consts::EXE_SUFFIX))
}
fn read_json(path: &Path) -> Result<Value> {
let raw =
fs::read_to_string(path).with_context(|| format!("failed to read {}", path.display()))?;
serde_json::from_str(&raw).with_context(|| format!("failed to decode {}", path.display()))
}
fn write_json(path: &Path, value: &Value) -> Result<()> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(path, serde_json::to_vec_pretty(value)?)
.with_context(|| format!("failed to write {}", path.display()))
}
fn write_text(path: &Path, value: &str) -> Result<()> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(path, value).with_context(|| format!("failed to write {}", path.display()))
}
fn write_bytes(path: &Path, value: &[u8]) -> Result<()> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(path, value).with_context(|| format!("failed to write {}", path.display()))
}
fn path_from_value(value: &Value) -> Result<PathBuf> {
value
.as_str()
.map(PathBuf::from)
.ok_or_else(|| anyhow!("expected path string, got {value}"))
}
fn sanitize(value: &str) -> String {
value
.chars()
.map(|ch| if ch.is_ascii_alphanumeric() { ch } else { '-' })
.collect()
}
fn take_string(args: &mut impl Iterator<Item = String>, name: &str) -> Result<String> {
args.next()
.ok_or_else(|| anyhow!("{name} requires a value"))
}
fn take_path(args: &mut impl Iterator<Item = String>, name: &str) -> Result<PathBuf> {
Ok(PathBuf::from(take_string(args, name)?))
}

View file

@ -1,413 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-closure-source-grounding-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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"),
"# Closure Source Grounding Smoke\n\nThis repository proves Soul can require verification output to cite changed paths.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed closure source grounding smoke"],
&repo,
)?;
git(["switch", "-c", "epiphany/closure-source-grounding"], &repo)?;
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",
"closure-source-grounding-smoke",
"--topic",
"closure-source-grounding",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"closure-source-grounding-smoke",
"--local-verse-store",
path_str(&local_verse)?,
],
&root,
)?;
let good = drive_item(
&manifest,
&root,
&repo,
"closure-source-grounded",
"Prove default closure verification cites the changed path.",
None,
)?;
let bad = drive_item(
&manifest,
&root,
&repo,
"closure-proofless-output",
"Prove source grounding blocks proofless verification output.",
Some("Write-Output 'ok'"),
)?;
require_eq(&good.close, &["status"], "closed")?;
require_eq(&good.close, &["soul", "verdict"], "passed")?;
require_bool(
&good.close,
&[
"closureReview",
"verificationSourceGrounding",
"allDeclaredPathsMentionedByVerificationOutput",
],
true,
)?;
require_bool(
&good.close,
&["closureReview", "verificationSourceGrounding", "required"],
true,
)?;
require_eq(&bad.close, &["status"], "verification-failed")?;
require_eq(&bad.close, &["soul", "verdict"], "failed")?;
require_eq(
&bad.close,
&["closureReview", "verificationSourceGrounding", "status"],
"failed",
)?;
require_bool(
&bad.close,
&[
"closureReview",
"verificationSourceGrounding",
"allDeclaredPathsMentionedByVerificationOutput",
],
false,
)?;
require_bool(
&bad.close,
&["closureReview", "sourceGrounding", "pathScopeMatched"],
true,
)?;
require_bool(
&bad.close,
&[
"closureReview",
"sourceGrounding",
"verificationOutputMentionsChangedPaths",
],
false,
)?;
require_eq(
&bad.close,
&["closureReview", "familyAssertions", "status"],
"passed",
)?;
require_bool(&good.close, &["privateStateExposed"], false)?;
require_bool(&bad.close, &["privateStateExposed"], false)?;
let summary = json!({
"schemaVersion": "epiphany.repo_work_closure_source_grounding_smoke.v0",
"status": "ok",
"smokeDir": smoke_dir,
"repo": repo,
"branch": git_output(["branch", "--show-current"], &repo)?,
"passItem": good.item,
"passCloseStatus": good.close["status"],
"passSourceGroundingStatus": good.close["closureReview"]["verificationSourceGrounding"]["status"],
"passVerificationOutputMentionsChangedPaths": good.close["closureReview"]["sourceGrounding"]["verificationOutputMentionsChangedPaths"],
"blockItem": bad.item,
"blockCloseStatus": bad.close["status"],
"blockSoulVerdict": bad.close["soul"]["verdict"],
"blockSourceGroundingStatus": bad.close["closureReview"]["verificationSourceGrounding"]["status"],
"blockPathScopeMatched": bad.close["closureReview"]["sourceGrounding"]["pathScopeMatched"],
"blockFamilyAssertionsStatus": bad.close["closureReview"]["familyAssertions"]["status"],
"privateStateExposed": false,
});
write_json(&smoke_dir.join("summary.json"), &summary)?;
Ok(summary)
}
struct ItemProof {
item: String,
close: Value,
}
fn drive_item(
manifest: &Path,
root: &Path,
repo: &Path,
item: &str,
summary: &str,
verification_command: Option<&str>,
) -> Result<ItemProof> {
cargo_json(
manifest,
"epiphany-work",
&[
"accept",
"--workspace",
path_str(repo)?,
"--from",
"persona",
"--item",
item,
"--summary",
summary,
],
root,
)?;
cargo_json(
manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(repo)?,
"--item",
item,
"--action-family",
"repo-status-section",
"--model-ref",
"closure-source-grounding-smoke-imagination-v1",
"--model-authored",
],
root,
)?;
for _ in 0..3 {
cargo_json(
manifest,
"epiphany-work",
&[
"tick",
"--workspace",
path_str(repo)?,
"--epiphany-root",
path_str(root)?,
"--item",
item,
"--cooldown-seconds",
"0",
],
root,
)?;
}
let mut close_args = vec![
"close".to_string(),
"--workspace".to_string(),
path_str(repo)?.to_string(),
"--item".to_string(),
item.to_string(),
"--require-source-grounding".to_string(),
];
if let Some(command) = verification_command {
close_args.push("--verification-command".to_string());
close_args.push(command.to_string());
}
let close_arg_refs = close_args.iter().map(String::as_str).collect::<Vec<_>>();
let close = cargo_json(manifest, "epiphany-work", &close_arg_refs, root)?;
Ok(ItemProof {
item: item.to_string(),
close,
})
}
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 output 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 path_str(path: &Path) -> Result<&str> {
path.to_str()
.ok_or_else(|| anyhow!("path is not valid UTF-8: {}", path.display()))
}
fn take_path(args: &mut impl Iterator<Item = String>, name: &str) -> Result<PathBuf> {
Ok(PathBuf::from(
args.next()
.ok_or_else(|| anyhow!("missing value for {name}"))?,
))
}
fn require_eq(value: &Value, path: &[&str], expected: &str) -> Result<()> {
let actual = value_at(value, path)
.and_then(Value::as_str)
.ok_or_else(|| anyhow!("missing string at {}", path.join(".")))?;
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 = value_at(value, path)
.and_then(Value::as_bool)
.ok_or_else(|| anyhow!("missing bool at {}", path.join(".")))?;
if actual == expected {
Ok(())
} else {
Err(anyhow!(
"expected {} to be {expected}, got {actual}",
path.join(".")
))
}
}
fn value_at<'a>(value: &'a Value, path: &[&str]) -> Option<&'a Value> {
let mut current = value;
for segment in path {
current = current.get(*segment)?;
}
Some(current)
}

View file

@ -1,447 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-credit-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Credit Request Family Smoke\n\nThis repository proves branch-local Bifrost credit request cargo without credit ledger authority.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed repo credit request smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-credit-request-family"],
&repo,
)?;
let item = "repo-credit-request-family";
let target_path = ".epiphany/credit-requests/repo-credit-request-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-credit-request-family-smoke",
"--topic",
"repo-credit-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-credit-request-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",
"Ask Bifrost to prepare credit ledger review for an accepted artifact without granting credit authority.",
"--candidate-action-ref",
"candidate-action://repo-credit-request-family/credit-packet",
"--candidate-action-ref",
"candidate-action://repo-credit-request-family/bifrost-ledger-review",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-credit-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-credit-request",
"--model-ref",
"repo-credit-request-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 request_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.credit_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_credit_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.credit_request\"",
)?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-bifrost-credit-review\"")?;
require_text(&request_text, "requested_owner = \"Bifrost\"")?;
require_text(
&request_text,
"requested_effect = \"record-credit-for-redacted-proof-and-accepted-artifact\"",
)?;
require_text(&request_text, "maintainer_review_request_ref = ")?;
require_text(&request_text, "publication_request_ref = ")?;
require_text(&request_text, "pr_request_ref = ")?;
require_text(
&request_text,
"credit_scope = \"authorship, maintainer review, accepted artifact, public proof, and Bifrost ledger readback\"",
)?;
require_text(&request_text, "[antecedents]")?;
require_text(&request_text, "closure_review_required = true")?;
require_text(&request_text, "soul_verdict_required = true")?;
require_text(&request_text, "mind_commit_required = true")?;
require_text(&request_text, "public_proof_required = true")?;
require_text(&request_text, "maintainer_review_required = true")?;
require_text(&request_text, "accepted_artifact_required = true")?;
require_text(&request_text, "authorship_context_required = true")?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"closure_review = \"epiphany.repo_work_closure_review.v0\"",
)?;
require_text(
&request_text,
"soul_verdict = \"epiphany.soul.verification_verdict\"",
)?;
require_text(
&request_text,
"mind_commit = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(
&request_text,
"public_proof = \"epiphany.repo_work_public_proof_bundle.v0\"",
)?;
require_text(
&request_text,
"maintainer_review = \"gamecult.maintainer.review_receipt.v0\"",
)?;
require_text(
&request_text,
"accepted_artifact = \"gamecult.artifact.acceptance_receipt.v0\"",
)?;
require_text(
&request_text,
"credit_ledger = \"gamecult.bifrost.credit_receipt.v0\"",
)?;
require_text(
&request_text,
"credit_readback = \"gamecult.bifrost.credit_readback_receipt.v0\"",
)?;
require_text(&request_text, "[credit_packet]")?;
require_text(&request_text, "requires_author_identity = true")?;
require_text(&request_text, "requires_reviewer_identity = true")?;
require_text(&request_text, "requires_accepted_artifact_ref = true")?;
require_text(&request_text, "requires_changed_path_list = true")?;
require_text(&request_text, "requires_public_proof_ref = true")?;
require_text(&request_text, "requires_credit_ledger_target = true")?;
require_text(
&request_text,
"requires_private_state_redaction_check = true",
)?;
require_text(&request_text, "credit_ledger_authorized = false")?;
require_text(&request_text, "bifrost_publication_authorized = false")?;
require_text(&request_text, "github_pr_authorized = false")?;
require_text(&request_text, "merge_authorized = false")?;
require_text(&request_text, "publication_authorized = false")?;
require_text(&request_text, "upstream_sync_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "bifrost_credit_authority_required = true")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_credit_request_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"],
"awaitingBifrostCreditReview": true,
"creditLedgerAuthorized": false,
"bifrostPublicationAuthorized": false,
"githubPrAuthorized": false,
"mergeAuthorized": false,
"publicationAuthorized": false,
"upstreamSyncAuthorized": false,
"handsActionAuthorized": false,
"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 credit request 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

@ -1,430 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-dependency-policy-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Dependency Policy Request Family Smoke\n\nThis repository proves branch-local dependency policy request cargo without package install authority.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
fs::write(
repo.join("package.json"),
"{\n \"name\": \"epiphany-dependency-policy-smoke\",\n \"version\": \"0.0.0\",\n \"dependencies\": {}\n}\n",
)
.with_context(|| format!("failed to seed {}", repo.join("package.json").display()))?;
fs::write(
repo.join("Cargo.toml"),
"[package]\nname = \"epiphany-dependency-policy-smoke\"\nversion = \"0.0.0\"\nedition = \"2024\"\n",
)
.with_context(|| format!("failed to seed {}", repo.join("Cargo.toml").display()))?;
git(["add", "README.md", "package.json", "Cargo.toml"], &repo)?;
git(
["commit", "-m", "Seed repo dependency policy smoke body"],
&repo,
)?;
git(
[
"switch",
"-c",
"epiphany/repo-dependency-policy-request-family",
],
&repo,
)?;
let item = "repo-dependency-policy-request-family";
let target_path =
".epiphany/dependency-policy-requests/repo-dependency-policy-request-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-dependency-policy-request-family-smoke",
"--topic",
"repo-dependency-policy-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-dependency-policy-request-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",
"Ask for a reviewed dependency and supply-chain policy before changing package manifests or lockfiles.",
"--candidate-action-ref",
"candidate-action://repo-dependency-policy-request-family/dependency-review",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-dependency-policy-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-dependency-policy-request",
"--model-ref",
"repo-dependency-policy-request-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 = read_json(
&repo
.join(".epiphany")
.join("work")
.join(format!("work-close-{item}.json")),
)?;
let request_text = fs::read_to_string(repo.join(target_path))
.with_context(|| format!("failed to read {}", repo.join(target_path).display()))?;
let package_text = fs::read_to_string(repo.join("package.json"))
.with_context(|| format!("failed to read {}", repo.join("package.json").display()))?;
let cargo_text = fs::read_to_string(repo.join("Cargo.toml"))
.with_context(|| format!("failed to read {}", repo.join("Cargo.toml").display()))?;
require_eq(
&plan,
&["derivation", "safeActionFamily"],
"repo.dependency_policy_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_dependency_policy_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.dependency_policy_request\"",
)?;
require_text(
&request_text,
"status = \"awaiting-dependency-policy-review\"",
)?;
require_text(&request_text, "routing_owner = \"Self\"")?;
require_text(&request_text, "requires_manifest_inventory = true")?;
require_text(&request_text, "requires_lockfile_policy = true")?;
require_text(
&request_text,
"requires_package_manager_command_review = true",
)?;
require_text(&request_text, "requires_network_fetch_policy = true")?;
require_text(&request_text, "requires_vulnerability_review = true")?;
require_text(&request_text, "requires_license_review = true")?;
require_text(&request_text, "source_grounding_required = true")?;
require_text(&request_text, "eyes_evidence_required = true")?;
require_text(
&request_text,
"dependency_audit = \"gamecult.supply_chain.dependency_audit_receipt.v0\"",
)?;
require_text(&request_text, "requires_manifest_paths = true")?;
require_text(&request_text, "requires_lockfile_paths = true")?;
require_text(&request_text, "requires_package_manager_commands = true")?;
require_text(&request_text, "requires_vulnerability_sources = true")?;
require_text(&request_text, "requires_license_constraints = true")?;
require_text(&request_text, "requires_vendored_code_policy = true")?;
require_text(&request_text, "requires_update_cadence = true")?;
require_text(&request_text, "direct_dependency_update_authority = false")?;
require_text(&request_text, "direct_package_install_authority = false")?;
require_text(&request_text, "direct_lockfile_mutation_authority = false")?;
require_text(&request_text, "direct_network_fetch_authority = false")?;
require_text(&request_text, "direct_ci_mutation_authority = false")?;
require_text(&request_text, "direct_hands_authority = false")?;
require_text(&request_text, "publication_authorized = false")?;
require_text(&request_text, "deployment_authority = false")?;
require_text(&request_text, "service_lifecycle_authority = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_verse_rummaging = false")?;
require_text(&request_text, "private_state_exposed = false")?;
require_text(&package_text, "\"dependencies\": {}")?;
require_text(&cargo_text, "edition = \"2024\"")?;
let summary = json!({
"schemaVersion": "epiphany.repo_dependency_policy_request_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"],
"awaitingDependencyPolicyReview": true,
"dependencyUpdateAuthorized": false,
"packageInstallAuthorized": false,
"lockfileMutationAuthorized": false,
"networkFetchAuthorized": false,
"ciMutationAuthorized": false,
"deploymentAuthority": false,
"publicationAuthorized": false,
"serviceLifecycleAuthority": false,
"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 equal {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(false);
if actual == expected {
Ok(())
} else {
Err(anyhow!(
"expected {} to equal {expected}, got {actual}",
path.join(".")
))
}
}
fn require_text(text: &str, needle: &str) -> Result<()> {
if text.contains(needle) {
Ok(())
} else {
Err(anyhow!("expected text to contain {needle:?}"))
}
}
fn path_str(path: &Path) -> Result<&str> {
path.to_str()
.ok_or_else(|| anyhow!("path is not valid UTF-8: {}", path.display()))
}
fn take_path(
args: &mut std::iter::Peekable<impl Iterator<Item = String>>,
flag: &str,
) -> Result<PathBuf> {
args.next()
.map(PathBuf::from)
.ok_or_else(|| anyhow!("missing value for {flag}"))
}

View file

@ -1,437 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-deployment-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Deployment Request Family Smoke\n\nThis repository proves branch-local deployment request cargo without deploy authority.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
fs::create_dir_all(repo.join("deploy"))
.with_context(|| format!("failed to create {}", repo.join("deploy").display()))?;
fs::write(
repo.join("deploy").join("idunn-deploy.ps1"),
"# reviewed by Idunn before use\nWrite-Output 'deployment script placeholder'\n",
)
.with_context(|| {
format!(
"failed to seed {}",
repo.join("deploy").join("idunn-deploy.ps1").display()
)
})?;
git(["add", "README.md", "deploy/idunn-deploy.ps1"], &repo)?;
git(
["commit", "-m", "Seed repo deployment request smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-deployment-request-family"],
&repo,
)?;
let item = "repo-deployment-request-family";
let target_path = ".epiphany/deployment-requests/repo-deployment-request-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-deployment-request-family-smoke",
"--topic",
"repo-deployment-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-deployment-request-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",
"Ask for a reviewed Idunn-owned git-push deployment request without granting deployment authority.",
"--candidate-action-ref",
"candidate-action://repo-deployment-request-family/idunn-review",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-deployment-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-deployment-request",
"--model-ref",
"repo-deployment-request-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 = read_json(
&repo
.join(".epiphany")
.join("work")
.join(format!("work-close-{item}.json")),
)?;
let request_text = fs::read_to_string(repo.join(target_path))
.with_context(|| format!("failed to read {}", repo.join(target_path).display()))?;
let deploy_script_text = fs::read_to_string(repo.join("deploy").join("idunn-deploy.ps1"))
.with_context(|| {
format!(
"failed to read {}",
repo.join("deploy").join("idunn-deploy.ps1").display()
)
})?;
require_eq(
&plan,
&["derivation", "safeActionFamily"],
"repo.deployment_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_deployment_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.deployment_request\"",
)?;
require_text(&request_text, "status = \"awaiting-idunn-review\"")?;
require_text(&request_text, "routing_owner = \"Self\"")?;
require_text(
&request_text,
"required_reviewers = [\"Maintainer\", \"Soul\", \"Mind\", \"Bifrost\"]",
)?;
require_text(&request_text, "execution_owner = \"Idunn\"")?;
require_text(
&request_text,
"deployment_trigger = \"git-push-observed-by-idunn\"",
)?;
require_text(&request_text, "requires_idunn_receipt = true")?;
require_text(&request_text, "requires_aftercare_audit = true")?;
require_text(&request_text, "secret_policy_review_required = true")?;
require_text(
&request_text,
"idunn_deployment = \"gamecult.idunn.deployment_receipt.v0\"",
)?;
require_text(
&request_text,
"aftercare_audit = \"gamecult.idunn.deployment_aftercare_audit.v0\"",
)?;
require_text(&request_text, "requires_deployment_script_ref = true")?;
require_text(&request_text, "requires_watched_ref = true")?;
require_text(&request_text, "requires_source_commit_sha = true")?;
require_text(&request_text, "requires_script_hash = true")?;
require_text(&request_text, "requires_script_review_ref = true")?;
require_text(&request_text, "requires_host_access_policy_ref = true")?;
require_text(&request_text, "requires_secret_policy_ref = true")?;
require_text(&request_text, "requires_rollback_plan = true")?;
require_text(&request_text, "requires_aftercare_checks = true")?;
require_text(&request_text, "direct_deployment_authority = false")?;
require_text(&request_text, "direct_ssh_authority = false")?;
require_text(&request_text, "direct_git_push_authority = false")?;
require_text(&request_text, "direct_service_lifecycle_authority = false")?;
require_text(&request_text, "direct_hands_authority = false")?;
require_text(&request_text, "publication_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_verse_rummaging = false")?;
require_text(&request_text, "private_state_exposed = false")?;
require_text(&deploy_script_text, "deployment script placeholder")?;
let summary = json!({
"schemaVersion": "epiphany.repo_deployment_request_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"],
"awaitingIdunnReview": true,
"deploymentTrigger": "git-push-observed-by-idunn",
"deploymentAuthority": false,
"sshAuthority": false,
"gitPushAuthority": false,
"serviceLifecycleAuthority": false,
"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 = value_at_path(value, path)
.and_then(Value::as_str)
.ok_or_else(|| anyhow!("missing string at {}", path.join(".")))?;
if actual == expected {
Ok(())
} else {
Err(anyhow!(
"expected {} to be {:?}, got {:?}",
path.join("."),
expected,
actual
))
}
}
fn require_bool(value: &Value, path: &[&str], expected: bool) -> Result<()> {
let actual = value_at_path(value, path)
.and_then(Value::as_bool)
.ok_or_else(|| anyhow!("missing bool at {}", path.join(".")))?;
if actual == expected {
Ok(())
} else {
Err(anyhow!(
"expected {} to be {}, got {}",
path.join("."),
expected,
actual
))
}
}
fn require_text(haystack: &str, needle: &str) -> Result<()> {
if haystack.contains(needle) {
Ok(())
} else {
Err(anyhow!("expected text to contain {needle:?}"))
}
}
fn value_at_path<'a>(value: &'a Value, path: &[&str]) -> Option<&'a Value> {
let mut cursor = value;
for segment in path {
if let Ok(index) = segment.parse::<usize>() {
cursor = cursor.as_array()?.get(index)?;
} else {
cursor = cursor.get(*segment)?;
}
}
Some(cursor)
}
fn path_str(path: &Path) -> Result<&str> {
path.to_str()
.ok_or_else(|| anyhow!("path is not valid UTF-8: {}", path.display()))
}
fn take_path(args: &mut impl Iterator<Item = String>, name: &str) -> Result<PathBuf> {
Ok(PathBuf::from(
args.next()
.ok_or_else(|| anyhow!("missing value for {name}"))?,
))
}

View file

@ -1,437 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-interpreter-brief-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Interpreter Brief Family Smoke\n\nThis repository proves branch-local Mind-owned interpretation briefs.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed repo interpreter brief smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-interpreter-brief-family"],
&repo,
)?;
let item = "repo-interpreter-brief-family";
let target_path = ".epiphany/interpreter-briefs/repo-interpreter-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-interpreter-brief-family-smoke",
"--topic",
"repo-interpreter-brief-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-interpreter-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 rough Persona and Imagination consensus into a Mind-owned interpreter brief before any work item receives Hands authority.",
"--candidate-action-ref",
"candidate-action://repo-interpreter-brief-family/interpret-action-semantics",
"--candidate-action-ref",
"candidate-action://repo-interpreter-brief-family/request-soul-grounding",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-interpreter-brief-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-interpreter-brief",
"--model-ref",
"repo-interpreter-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.interpreter_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_interpreter_brief.v0\"",
)?;
require_text(
&brief_text,
"safe_action_family = \"repo.interpreter_brief\"",
)?;
require_text(&brief_text, "[interpreter]")?;
require_text(&brief_text, "status = \"awaiting-mind-interpretation\"")?;
require_text(&brief_text, "authoring_owner = \"Imagination\"")?;
require_text(&brief_text, "requested_interpreter = \"Mind\"")?;
require_text(&brief_text, "interpretation_admitted = false")?;
require_text(
&brief_text,
"purpose = \"public-pressure-to-action-semantics\"",
)?;
require_text(&brief_text, "requires_consensus_readback = true")?;
require_text(&brief_text, "requires_safe_family_choice = true")?;
require_text(&brief_text, "requires_requested_paths = true")?;
require_text(&brief_text, "requires_verification_asks = true")?;
require_text(&brief_text, "requires_evidence_needs = true")?;
require_text(&brief_text, "candidate_actions_non_authoritative = true")?;
require_text(&brief_text, "[semantic_checks]")?;
require_text(&brief_text, "intent_summary_required = true")?;
require_text(&brief_text, "scope_boundary_required = true")?;
require_text(&brief_text, "requested_paths_required = true")?;
require_text(&brief_text, "verification_required = true")?;
require_text(&brief_text, "evidence_required = true")?;
require_text(&brief_text, "rollback_required = true")?;
require_text(&brief_text, "non_goals_required = true")?;
require_text(&brief_text, "open_questions_required = true")?;
require_text(&brief_text, "consensus_alignment_required = true")?;
require_text(&brief_text, "[allowed_outputs]")?;
require_text(&brief_text, "\"repo.consensus_brief\"")?;
require_text(&brief_text, "\"repo.objective_draft\"")?;
require_text(&brief_text, "\"repo.adoption_request\"")?;
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, "may_request_replanning = true")?;
require_text(&brief_text, "may_request_more_consensus = true")?;
require_text(&brief_text, "may_adopt_objective = false")?;
require_text(&brief_text, "may_schedule_work = false")?;
require_text(&brief_text, "may_touch_substrate = false")?;
require_text(&brief_text, "may_publish = false")?;
require_text(&brief_text, "may_deploy = false")?;
require_text(&brief_text, "[required_gates]")?;
require_text(&brief_text, "imagination_consensus_required = true")?;
require_text(&brief_text, "mind_review_required = true")?;
require_text(&brief_text, "soul_source_grounding_required = true")?;
require_text(&brief_text, "bifrost_publication_review_required = true")?;
require_text(
&brief_text,
"hands_receipt_required_before_state_change = true",
)?;
require_text(
&brief_text,
"substrate_receipt_required_before_mutation = true",
)?;
require_text(
&brief_text,
"idunn_receipt_required_before_deployment = true",
)?;
require_text(&brief_text, "direct_state_commit_authorized = false")?;
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_interpreter_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"],
"interpreterIsDraft": true,
"mindOwnsInterpretation": true,
"candidateActionsNonAuthoritative": true,
"directStateCommitAuthorized": false,
"handsActionAuthorized": false,
"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 interpreter 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

@ -1,299 +0,0 @@
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(Debug)]
struct Args {
workspace: PathBuf,
item: String,
expected_path: String,
expected_family: String,
expected_gate: String,
expected_blocker: String,
}
impl Args {
fn parse() -> Result<Self> {
let mut workspace = env::current_dir().context("failed to resolve current directory")?;
let mut item = None;
let mut expected_path = "README.md".to_string();
let mut expected_family = "repo.status_section".to_string();
let mut expected_gate = "awaiting-publication".to_string();
let mut expected_blocker = "bifrost-publication-missing".to_string();
let mut args = env::args().skip(1).peekable();
while let Some(arg) = args.next() {
match arg.as_str() {
"--workspace" => workspace = take_path(&mut args, "--workspace")?,
"--item" => item = Some(take_value(&mut args, "--item")?),
"--expected-path" => expected_path = take_value(&mut args, "--expected-path")?,
"--expected-family" => {
expected_family = take_value(&mut args, "--expected-family")?
}
"--expected-gate" => expected_gate = take_value(&mut args, "--expected-gate")?,
"--expected-blocker" => {
expected_blocker = take_value(&mut args, "--expected-blocker")?
}
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
let item = item.ok_or_else(|| anyhow!("--item is required"))?;
Ok(Self {
workspace,
item,
expected_path,
expected_family,
expected_gate,
expected_blocker,
})
}
}
fn run_smoke(args: Args) -> Result<Value> {
let workspace = args
.workspace
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.workspace.display()))?;
let work_dir = workspace.join(".epiphany").join("work");
let close_path = work_dir.join(format!("work-close-{}.json", args.item));
let overview_path = work_dir.join(format!("work-overview-{}.json", args.item));
let close = read_json(&close_path)?;
let overview = read_json(&overview_path)?;
require_str(
&close,
&["schemaVersion"],
"epiphany.repo_work_closure_receipt.v0",
)?;
require_str(&close, &["status"], "closed")?;
require_str(&close, &["item"], &args.item)?;
require_bool(&close, &["privateStateExposed"], false)?;
require_str(&close, &["soul", "verdict"], "passed")?;
require_bool(&close, &["authority", "branchLocalOnly"], true)?;
require_bool(&close, &["authority", "publicationAuthorized"], false)?;
require_bool(&close, &["authority", "mergeAuthorized"], false)?;
require_bool(&close, &["authority", "serviceLifecycleAuthorized"], false)?;
require_bool(&close, &["authority", "crossRepoMutationAuthorized"], false)?;
require_bool(&close, &["authority", "privateStateExposed"], false)?;
require_str(
&close,
&["mind", "repoMapEntry", "safeActionFamily"],
&args.expected_family,
)?;
require_str(
&close,
&["mind", "repoMapEntry", "publicationGate"],
"Bifrost",
)?;
let commit_sha = require_present_str(&close, &["handsReceipts", "commitSha"])?;
require_single_path(
&close,
&["mind", "repoMapEntry", "changedPaths"],
&args.expected_path,
)?;
require_single_path(
&close,
&["closureReview", "sourceGrounding", "actualChangedPaths"],
&args.expected_path,
)?;
require_bool(
&close,
&["closureReview", "sourceGrounding", "pathScopeMatched"],
true,
)?;
require_bool(
&close,
&["closureReview", "sourceGrounding", "familyAssertionsPassed"],
true,
)?;
require_bool(
&close,
&["closureReview", "sourceGrounding", "mindAdoptionPassed"],
true,
)?;
let overview_schema = require_one_of_str(
&overview,
&["schemaVersion"],
&[
"epiphany.repo_work_overview.v0",
"epiphany.repo_work_overview_receipt.v0",
],
)?;
if overview_schema == "epiphany.repo_work_overview.v0" {
require_str(&overview, &["status"], "overview-ready")?;
}
require_str(&overview, &["item"], &args.item)?;
require_str(&overview, &["currentGate"], &args.expected_gate)?;
require_str(&overview, &["blocker"], &args.expected_blocker)?;
require_bool(&overview, &["privateStateExposed"], false)?;
require_str(&overview, &["proofBundle", "soulVerdict"], "passed")?;
require_single_path(
&overview,
&["proofBundle", "changedPaths"],
&args.expected_path,
)?;
let git_paths = git_changed_paths(&workspace, commit_sha)?;
if git_paths != vec![args.expected_path.clone()] {
return Err(anyhow!(
"expected git commit {commit_sha} to change only {:?}, got {:?}",
args.expected_path,
git_paths
));
}
Ok(json!({
"schemaVersion": "epiphany.repo_livefire_closure_smoke.v0",
"status": "ok",
"workspace": workspace,
"item": args.item,
"branch": string_at(&close, &["mind", "repoMapEntry", "branch"]),
"commitSha": commit_sha,
"safeActionFamily": args.expected_family,
"changedPaths": git_paths,
"currentGate": args.expected_gate,
"blocker": args.expected_blocker,
"publicationGate": "Bifrost",
"soulVerdict": "passed",
"mindStateCommitReceiptId": string_at(&close, &["mind", "stateCommitReceiptId"]),
"closeReceipt": close_path,
"overviewReceipt": overview_path,
"verifiedAt": Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
"privateStateExposed": false,
}))
}
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 take_value(
args: &mut std::iter::Peekable<impl Iterator<Item = String>>,
name: &str,
) -> Result<String> {
args.next()
.ok_or_else(|| anyhow!("missing value for {name}"))
}
fn take_path(
args: &mut std::iter::Peekable<impl Iterator<Item = String>>,
name: &str,
) -> Result<PathBuf> {
Ok(PathBuf::from(take_value(args, name)?))
}
fn value_at<'a>(value: &'a Value, path: &[&str]) -> Option<&'a Value> {
path.iter()
.try_fold(value, |current, key| current.get(*key))
}
fn string_at(value: &Value, path: &[&str]) -> String {
value_at(value, path)
.and_then(Value::as_str)
.unwrap_or("<missing>")
.to_string()
}
fn require_present_str<'a>(value: &'a Value, path: &[&str]) -> Result<&'a str> {
value_at(value, path)
.and_then(Value::as_str)
.filter(|actual| !actual.is_empty())
.ok_or_else(|| anyhow!("expected {} to be a non-empty string", path.join(".")))
}
fn require_str(value: &Value, path: &[&str], expected: &str) -> Result<()> {
let actual = string_at(value, path);
if actual == expected {
Ok(())
} else {
Err(anyhow!(
"expected {} to be {expected:?}, got {actual:?}",
path.join(".")
))
}
}
fn require_one_of_str<'a>(value: &Value, path: &[&str], expected: &'a [&str]) -> Result<&'a str> {
let actual = string_at(value, path);
if let Some(matched) = expected.iter().find(|candidate| **candidate == actual) {
Ok(*matched)
} else {
Err(anyhow!(
"expected {} to be one of {:?}, got {actual:?}",
path.join("."),
expected
))
}
}
fn require_bool(value: &Value, path: &[&str], expected: bool) -> Result<()> {
let actual = value_at(value, path).and_then(Value::as_bool);
if actual == Some(expected) {
Ok(())
} else {
Err(anyhow!(
"expected {} to be {expected}, got {:?}",
path.join("."),
actual
))
}
}
fn require_single_path(value: &Value, path: &[&str], expected: &str) -> Result<()> {
let paths = value_at(value, path)
.and_then(Value::as_array)
.ok_or_else(|| anyhow!("expected {} to be an array", path.join(".")))?
.iter()
.map(|entry| entry.as_str().unwrap_or("<non-string>").to_string())
.collect::<Vec<_>>();
if paths == vec![expected.to_string()] {
Ok(())
} else {
Err(anyhow!(
"expected {} to contain only {expected:?}, got {:?}",
path.join("."),
paths
))
}
}
fn git_changed_paths(workspace: &Path, commit_sha: &str) -> Result<Vec<String>> {
let output = Command::new("git")
.arg("-C")
.arg(workspace)
.arg("show")
.arg("--format=")
.arg("--name-only")
.arg(commit_sha)
.output()
.with_context(|| format!("failed to run git show in {}", workspace.display()))?;
if !output.status.success() {
return Err(anyhow!(
"git show failed with exit {:?}: {}",
output.status.code(),
String::from_utf8_lossy(&output.stderr)
));
}
Ok(String::from_utf8_lossy(&output.stdout)
.lines()
.map(str::trim)
.filter(|line| !line.is_empty())
.map(|line| line.replace('\\', "/"))
.collect())
}

View file

@ -1,444 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-maintainer-review-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Maintainer Review Request Family Smoke\n\nThis repository proves branch-local Hands maintainer-review-request requests.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
[
"commit",
"-m",
"Seed repo maintainer review request smoke body",
],
&repo,
)?;
git(
[
"switch",
"-c",
"epiphany/repo-maintainer-review-request-family",
],
&repo,
)?;
let item = "repo-maintainer-review-request-family";
let target_path = ".epiphany/review-requests/repo-maintainer-review-request-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-maintainer-review-request-family-smoke",
"--topic",
"repo-maintainer-review-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-maintainer-review-request-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",
"Ask a maintainer to review the redacted proof and branch diff without granting merge authority.",
"--candidate-action-ref",
"candidate-action://repo-maintainer-review-request-family/human-review",
"--candidate-action-ref",
"candidate-action://repo-maintainer-review-request-family/maintainer-verdict",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-maintainer-review-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-maintainer-review-request",
"--model-ref",
"repo-maintainer-review-request-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 request_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.maintainer_review_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_maintainer_review_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.maintainer_review_request\"",
)?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-maintainer-review\"")?;
require_text(&request_text, "requested_owner = \"Maintainer\"")?;
require_text(
&request_text,
"requested_effect = \"review-redacted-proof-and-branch-diff\"",
)?;
require_text(&request_text, "verification_request_ref = ")?;
require_text(&request_text, "publication_request_ref = ")?;
require_text(
&request_text,
"review_scope = \"changed paths, closure proof, public proof bundle, and Bifrost credit context\"",
)?;
require_text(&request_text, "[antecedents]")?;
require_text(&request_text, "closure_review_required = true")?;
require_text(&request_text, "soul_verdict_required = true")?;
require_text(&request_text, "mind_commit_required = true")?;
require_text(&request_text, "public_proof_required = true")?;
require_text(&request_text, "bifrost_publication_request_required = true")?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"closure_review = \"epiphany.repo_work_closure_review.v0\"",
)?;
require_text(
&request_text,
"soul_verdict = \"epiphany.soul.verification_verdict\"",
)?;
require_text(
&request_text,
"mind_commit = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(
&request_text,
"public_proof = \"epiphany.repo_work_public_proof_bundle.v0\"",
)?;
require_text(
&request_text,
"maintainer_review = \"gamecult.maintainer.review_receipt.v0\"",
)?;
require_text(
&request_text,
"bifrost_publication = \"gamecult.bifrost.public_proof_publication_receipt.v0\"",
)?;
require_text(&request_text, "[review_packet]")?;
require_text(&request_text, "requires_reviewer_identity = true")?;
require_text(&request_text, "requires_review_verdict = true")?;
require_text(
&request_text,
"allowed_verdicts = [\"approved\", \"changes-requested\", \"rejected\", \"needs-human-context\"]",
)?;
require_text(&request_text, "requires_changed_path_list = true")?;
require_text(&request_text, "requires_public_proof_ref = true")?;
require_text(
&request_text,
"requires_private_state_redaction_check = true",
)?;
require_text(&request_text, "maintainer_approval_authorized = false")?;
require_text(&request_text, "maintainer_response_required = true")?;
require_text(&request_text, "merge_authorized = false")?;
require_text(&request_text, "push_authorized = false")?;
require_text(&request_text, "publication_authorized = false")?;
require_text(&request_text, "upstream_sync_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_maintainer_review_request_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"],
"awaitingMaintainerReview": true,
"maintainerApprovalAuthorized": false,
"mergeAuthorized": false,
"pushAuthorized": false,
"publicationAuthorized": false,
"upstreamSyncAuthorized": false,
"handsActionAuthorized": false,
"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 maintainer review request 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

@ -1,391 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-objective-draft-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Objective Draft Family Smoke\n\nThis repository proves branch-local Objective Draft cargo.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed repo objective draft smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-objective-draft-family"],
&repo,
)?;
let item = "repo-objective-draft-family";
let target_path = ".epiphany/objective-drafts/repo-objective-draft-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-objective-draft-family-smoke",
"--topic",
"repo-objective-draft-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-objective-draft-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",
"Shape public consensus into a reviewable Objective Draft before Self schedules any branch-local work.",
"--candidate-action-ref",
"candidate-action://repo-objective-draft-family/adopt-objective",
"--candidate-action-ref",
"candidate-action://repo-objective-draft-family/write-task-card",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-objective-draft-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-objective-draft",
"--model-ref",
"repo-objective-draft-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 draft_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.objective_draft",
)?;
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(
&draft_text,
"schema_version = \"epiphany.repo_objective_draft.v0\"",
)?;
require_text(&draft_text, "safe_action_family = \"repo.objective_draft\"")?;
require_text(&draft_text, "[draft]")?;
require_text(&draft_text, "status = \"review-required\"")?;
require_text(&draft_text, "adoption_gate = \"Mind\"")?;
require_text(&draft_text, "scheduler_gate = \"Self\"")?;
require_text(&draft_text, "publication_gate = \"Bifrost\"")?;
require_text(&draft_text, "objective_adopted = false")?;
require_text(&draft_text, "[objective]")?;
require_text(
&draft_text,
"preferred_next_safe_family = \"repo.task_card\"",
)?;
require_text(&draft_text, "[acceptance]")?;
require_text(&draft_text, "Mind explicitly accepts or rejects")?;
require_text(&draft_text, "Self schedules only after Mind adoption")?;
require_text(
&draft_text,
"Hands acts only through a later receipt-backed plan",
)?;
require_text(&draft_text, "[inputs]")?;
require_text(&draft_text, "consensus_brief_required = true")?;
require_text(&draft_text, "objective_adoption_authorized = false")?;
require_text(&draft_text, "self_scheduling_authorized = false")?;
require_text(&draft_text, "hands_action_authorized = false")?;
require_text(&draft_text, "cross_body_mutation_authorized = false")?;
require_text(&draft_text, "mind_adoption_required = true")?;
require_text(&draft_text, "bifrost_publication_required = true")?;
require_text(&draft_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_work_objective_draft_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"],
"draftReviewRequired": true,
"objectiveAdopted": false,
"mindAdoptionRequired": true,
"selfSchedulingAuthorized": false,
"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 Objective Draft 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

@ -1,788 +0,0 @@
use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
use epiphany_core::load_agent_memory_entry_for_role;
use serde_json::Value;
use serde_json::json;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
fn main() -> Result<()> {
let result = run_smoke()?;
println!("{}", serde_json::to_string_pretty(&result)?);
Ok(())
}
fn run_smoke() -> Result<Value> {
let root = env::current_dir().context("failed to resolve current dir")?;
let workspace = root
.join(".epiphany-smoke")
.join("repo-personality-workspace");
let artifacts = root
.join(".epiphany-smoke")
.join("repo-personality-artifacts");
reset_smoke_path(&root, &workspace)?;
reset_smoke_path(&root, &artifacts)?;
let cult_repo = create_repo(
&workspace.join("CultTiny"),
&[
(
"AGENTS.md",
"Prefer typed schemas and tiny public contracts.\n",
),
("src/lib.rs", "pub fn schema_contract() {}\n"),
(
"docs/architecture.md",
"# Architecture\nCultTiny stores typed contract surfaces.\n",
),
(
"research/prior-art.md",
"# Prior Art\nPrefer known schema formats before invention.\n",
),
(
"tests/contract_smoke.rs",
"#[test] fn contract_smoke() {}\n",
),
("schemas/message.schema.json", "{\"type\":\"object\"}\n"),
],
"Add schema contract smoke",
)?;
let lore_repo = create_repo(
&workspace.join("LoreTiny"),
&[
(
"AGENTS.md",
"Respect canon, source notes, and public voice.\n",
),
("state/map.yaml", "objective: preserve canon\n"),
("notes/fresh-workspace-handoff.md", "Read the map first.\n"),
("Chronicles/City.md", "# City\nCanon material.\n"),
],
"Polish canon handoff",
)?;
let scout = run_personality(
&root,
&[
"scout",
"--root",
workspace.to_str().unwrap_or_default(),
"--artifact-dir",
artifacts.join("scout").to_str().unwrap_or_default(),
],
)?;
require(scout["repoCount"] == 2, "scout should find two git repos")?;
let baseline = path_value(&scout, "store")?;
require(baseline.exists(), "scout should write typed baseline store")?;
let projection = run_personality(
&root,
&[
"project",
"--repo",
cult_repo.to_str().unwrap_or_default(),
"--baseline",
baseline.to_str().unwrap_or_default(),
"--artifact-dir",
artifacts.join("cult-project").to_str().unwrap_or_default(),
],
)?;
require(
projection["profile"]["roleProjectionCount"] == 8,
"project should emit all standing role projections",
)?;
let store = path_value(&projection, "store")?;
require(
store.exists(),
"project should write typed projection store",
)?;
let packet = run_personality(
&root,
&[
"agent-packet",
"--store",
store.to_str().unwrap_or_default(),
"--artifact-dir",
artifacts.join("cult-packet").to_str().unwrap_or_default(),
],
)?;
require(
packet["roleProjectionCount"] == 8,
"agent packet should carry eight role projections",
)?;
let packet_path = path_value(&packet, "packetPath")?;
let prompt_path = path_value(&packet, "promptPath")?;
let packet_summary_path = path_value(&packet, "summaryPath")?;
require(
packet_path.exists(),
"agent packet should write packet json",
)?;
require(
prompt_path.exists(),
"agent packet should write prompt markdown",
)?;
require(
packet_summary_path.exists(),
"agent packet should write summary markdown",
)?;
let memory_packet = run_personality(
&root,
&[
"memory-packet",
"--store",
store.to_str().unwrap_or_default(),
"--artifact-dir",
artifacts
.join("cult-memory-packet")
.to_str()
.unwrap_or_default(),
],
)?;
require(
memory_packet["memorySourceCount"].as_u64().unwrap_or(0) > 0,
"memory packet should carry source excerpts",
)?;
require(
memory_packet["roleDistillerCount"] == 8,
"memory packet should carry all role distiller lanes",
)?;
let memory_packet_path = path_value(&memory_packet, "packetPath")?;
let memory_prompt_path = path_value(&memory_packet, "promptPath")?;
let memory_summary_path = path_value(&memory_packet, "summaryPath")?;
require(
memory_packet_path.exists(),
"memory packet should write packet json",
)?;
require(
memory_prompt_path.exists(),
"memory packet should write prompt markdown",
)?;
require(
memory_summary_path.exists(),
"memory packet should write summary markdown",
)?;
let trajectory_packet = run_personality(
&root,
&[
"trajectory-packet",
"--store",
store.to_str().unwrap_or_default(),
"--artifact-dir",
artifacts
.join("cult-trajectory-packet")
.to_str()
.unwrap_or_default(),
],
)?;
require(
trajectory_packet["trajectoryThemeCount"]
.as_u64()
.unwrap_or(0)
> 0,
"trajectory packet should carry trajectory themes",
)?;
let trajectory_packet_path = path_value(&trajectory_packet, "packetPath")?;
let trajectory_prompt_path = path_value(&trajectory_packet, "promptPath")?;
let trajectory_summary_path = path_value(&trajectory_packet, "summaryPath")?;
require(
trajectory_packet_path.exists(),
"trajectory packet should write packet json",
)?;
require(
trajectory_prompt_path.exists(),
"trajectory packet should write prompt markdown",
)?;
require(
trajectory_summary_path.exists(),
"trajectory packet should write summary markdown",
)?;
let init_store = artifacts.join("repo-initialization.msgpack");
let startup = run_personality(
&root,
&[
"startup",
"--repo",
cult_repo.to_str().unwrap_or_default(),
"--baseline",
baseline.to_str().unwrap_or_default(),
"--artifact-dir",
artifacts.join("startup-first").to_str().unwrap_or_default(),
"--init-store",
init_store.to_str().unwrap_or_default(),
],
)?;
require(
startup["action"] == "reviewInitializationPackets",
"startup should request birth packet review before accepted records exist",
)?;
require(
startup["generatedPackets"].as_array().map_or(0, Vec::len) == 3,
"startup should generate trajectory, personality, and memory packets",
)?;
let startup_trajectory_packet = packet_for_kind(&startup, "repo-trajectory")?;
let startup_personality_packet = packet_for_kind(&startup, "repo-personality")?;
let startup_memory_packet = packet_for_kind(&startup, "repo-memory")?;
require(
startup_trajectory_packet.exists(),
"startup should write trajectory packet",
)?;
require(
startup_personality_packet.exists(),
"startup should write personality packet",
)?;
require(
startup_memory_packet.exists(),
"startup should write memory packet",
)?;
let birth_runner = run_birth_runner(
&root,
&[
"--repo",
cult_repo.to_str().unwrap_or_default(),
"--baseline",
baseline.to_str().unwrap_or_default(),
"--artifact-dir",
artifacts
.join("birth-runner-plan")
.to_str()
.unwrap_or_default(),
"--init-store",
artifacts
.join("birth-runner-plan")
.join("repo-initialization.msgpack")
.to_str()
.unwrap_or_default(),
"--agent-store",
root.join("state")
.join("agents.msgpack")
.to_str()
.unwrap_or_default(),
"--heartbeat-store",
root.join("state")
.join("agent-heartbeats.msgpack")
.to_str()
.unwrap_or_default(),
"--mode",
"plan",
],
)?;
require(
birth_runner["schemaVersion"] == "epiphany.repo_birth_runner.v0",
"birth runner should return its schema",
)?;
require(
birth_runner["executions"].as_array().map_or(0, Vec::len) == 3,
"birth runner plan should expose all startup-only specialist executions",
)?;
require(
birth_runner["executions"]
.as_array()
.into_iter()
.flatten()
.all(|execution| execution["heartbeatParticipant"].is_null()),
"birth runner executions should not be heartbeat participants",
)?;
let heartbeat_store = artifacts.join("startup-heartbeats.msgpack");
run_heartbeat(
&root,
&[
"init",
"--store",
heartbeat_store.to_str().unwrap_or_default(),
],
)?;
let trajectory_result_path = artifacts.join("startup-trajectory-result.json");
fs::write(
&trajectory_result_path,
serde_json::to_vec_pretty(&json!({
"verdict": "ready-for-review",
"summary": "Smoke trajectory birth distillation.",
"confidence": 0.88,
"selfImage": "CultTiny is becoming a typed-contract workspace that prefers receipts to swagger.",
"trajectoryNarrative": "The tiny history and docs both lean toward explicit schema boundaries, known formats, and reviewable proof over improvising private protocol sludge.",
"implicitGoals": ["Keep future expansion grounded in explicit schemas and receipts."],
"antiGoals": ["Do not drift into ad hoc protocol glue just because the fixture is small."],
"roleBiases": [{
"roleId": "coordinator",
"bias": "Self should treat typed-schema growth as part of the repo's grain.",
"trajectorySignals": ["systems_formalization", "protocol_intolerance"],
"behavioralEffect": "Challenge loose glue early.",
"risk": "Could become stiff if later work needs play.",
"evidenceRefs": ["AGENTS.md", "docs/architecture.md"]
}],
"selfPatchCandidates": [{
"roleId": "coordinator",
"selfPatch": {
"agentId": "epiphany.self",
"reason": "Trajectory birth should teach Self that CultTiny has been moving toward typed receipts and explicit contracts.",
"semanticMemories": [{
"memoryId": "mem-self-startup-trajectory-smoke",
"summary": "CultTiny's trajectory favors typed contract growth and evidence-backed explicitness over casual glue.",
"salience": 0.74,
"confidence": 0.87
}]
}
}],
"initializationRecord": {
"repoId": "culttiny",
"distillerKind": "repo-trajectory",
"acceptedOnce": true
},
"doNotMutate": [],
"nextSafeMove": "Self reviews the trajectory petition before it colors later memory drift."
}))?,
)?;
let accepted_trajectory = run_personality(
&root,
&[
"accept-init",
"--init-store",
init_store.to_str().unwrap_or_default(),
"--packet",
startup_trajectory_packet.to_str().unwrap_or_default(),
"--kind",
"repo-trajectory",
"--accepted-by",
"smoke-self",
"--summary",
"Smoke accepted repo trajectory birth packet after review.",
"--result",
trajectory_result_path.to_str().unwrap_or_default(),
"--agent-store",
root.join("state")
.join("agents.msgpack")
.to_str()
.unwrap_or_default(),
"--apply-self-patches",
"false",
],
)?;
require(
accepted_trajectory["record"]["kind"] == "repo-trajectory",
"accept-init should record trajectory birth",
)?;
let agent_store = artifacts.join("startup-agents.msgpack");
fs::copy(root.join("state").join("agents.msgpack"), &agent_store)
.context("failed to copy role memory store for startup smoke")?;
let accepted_personality = run_personality(
&root,
&[
"accept-init",
"--init-store",
init_store.to_str().unwrap_or_default(),
"--packet",
startup_personality_packet.to_str().unwrap_or_default(),
"--kind",
"repo-personality",
"--accepted-by",
"smoke-self",
"--summary",
"Smoke accepted repo personality birth packet after review.",
"--agent-store",
agent_store.to_str().unwrap_or_default(),
"--apply-trait-seeds",
"true",
"--heartbeat-store",
heartbeat_store.to_str().unwrap_or_default(),
"--apply-heartbeat-seeds",
"true",
],
)?;
require(
accepted_personality["record"]["kind"] == "repo-personality",
"accept-init should record personality birth",
)?;
require(
accepted_personality["heartbeatSeeds"]["applied"]
.as_u64()
.unwrap_or_default()
> 0,
"accept-init should apply heartbeat seed mutations",
)?;
require(
accepted_personality["traitLatticePersistence"]["applied"]
.as_u64()
.unwrap_or_default()
> 0,
"accept-init should stamp newborn canonical trait lattice seeds",
)?;
let coordinator = load_agent_memory_entry_for_role(&agent_store, "coordinator")?
.ok_or_else(|| anyhow!("startup smoke lost coordinator role memory entry"))?;
require(
!coordinator
.agent
.canonical_state
.underlying_organization
.contains_key("baseline"),
"personality accept-init should replace baseline canonical traits for coordinator",
)?;
require(
coordinator
.agent
.canonical_state
.underlying_organization
.contains_key("routing_discipline"),
"personality accept-init should seed coordinator routing_discipline trait",
)?;
let memory_result_path = artifacts.join("startup-memory-result.json");
fs::write(
&memory_result_path,
serde_json::to_vec_pretty(&json!({
"verdict": "ready-for-review",
"summary": "Smoke newborn memory distillation.",
"confidence": 0.9,
"roleMemoryPatches": [{
"roleId": "modeling",
"roleName": "Modeling",
"verdict": "ready-for-review",
"selfPatch": {
"agentId": "epiphany.modeling",
"reason": "Birth memory should teach Modeling that repo initialization memory is reviewed and typed.",
"semanticMemories": [{
"memoryId": "mem-body-startup-birth-memory-smoke",
"summary": "Repo memory birth packets can produce role-specific selfPatch candidates that are applied only after Self review.",
"salience": 0.72,
"confidence": 0.88
}]
},
"sourceRefs": ["AGENTS.md"],
"whyThisBelongsInMemory": "Modeling needs the startup memory route to stay source-grounded.",
"stalenessRisk": "smoke fixture",
"doNotStore": []
}]
}))?,
)?;
let accepted_memory = run_personality(
&root,
&[
"accept-init",
"--init-store",
init_store.to_str().unwrap_or_default(),
"--packet",
startup_memory_packet.to_str().unwrap_or_default(),
"--kind",
"repo-memory",
"--accepted-by",
"smoke-self",
"--summary",
"Smoke accepted repo memory birth packet after review.",
"--result",
memory_result_path.to_str().unwrap_or_default(),
"--agent-store",
agent_store.to_str().unwrap_or_default(),
"--apply-self-patches",
"true",
],
)?;
require(
accepted_memory["record"]["kind"] == "repo-memory",
"accept-init should record memory birth",
)?;
require(
accepted_memory["selfPersistence"]["applied"] == 1,
"accept-init should apply reviewed memory selfPatch candidates",
)?;
let startup_after_accept = run_personality(
&root,
&[
"startup",
"--repo",
cult_repo.to_str().unwrap_or_default(),
"--baseline",
baseline.to_str().unwrap_or_default(),
"--artifact-dir",
artifacts
.join("startup-after-accept")
.to_str()
.unwrap_or_default(),
"--init-store",
init_store.to_str().unwrap_or_default(),
],
)?;
require(
startup_after_accept["action"] == "continueStartup",
"startup should not rerun birth packets after accepted records exist",
)?;
require(
startup_after_accept["generatedPackets"]
.as_array()
.is_some_and(Vec::is_empty),
"startup should generate no packets after accepted records exist",
)?;
let status = run_personality(
&root,
&["status", "--store", store.to_str().unwrap_or_default()],
)?;
require(
status["reports"] == 1,
"projection store should have one report",
)?;
require(
status["profiles"] == 1,
"projection store should have one profile",
)?;
require(
status["trajectoryReports"] == 1,
"projection store should have one trajectory report",
)?;
require(
status["roleProjections"] == 8,
"projection store should have eight role projections",
)?;
Ok(json!({
"workspace": workspace,
"artifactRoot": artifacts,
"cultRepo": cult_repo,
"loreRepo": lore_repo,
"baseline": baseline,
"projectionStore": store,
"packetPath": packet_path,
"promptPath": prompt_path,
"packetSummaryPath": packet_summary_path,
"trajectoryPacketPath": trajectory_packet_path,
"trajectoryPromptPath": trajectory_prompt_path,
"trajectorySummaryPath": trajectory_summary_path,
"memoryPacketPath": memory_packet_path,
"memoryPromptPath": memory_prompt_path,
"memorySummaryPath": memory_summary_path,
"initStore": init_store,
"agentStore": agent_store,
"heartbeatStore": heartbeat_store,
"birthRunnerSummary": artifacts.join("birth-runner-plan").join("birth-runner-summary.json"),
"startupTrajectoryPacket": startup_trajectory_packet,
"startupPersonalityPacket": startup_personality_packet,
"startupMemoryPacket": startup_memory_packet,
"startupTrajectoryResult": trajectory_result_path,
"startupMemoryResult": memory_result_path,
"startupAfterAcceptAction": startup_after_accept["action"],
"repoCount": scout["repoCount"],
"trajectoryReports": status["trajectoryReports"],
"roleProjections": status["roleProjections"],
}))
}
fn create_repo(root: &Path, files: &[(&str, &str)], commit_message: &str) -> Result<PathBuf> {
fs::create_dir_all(root)?;
run_git(root, &["init"])?;
run_git(
root,
&["config", "user.email", "epiphany-smoke@example.invalid"],
)?;
run_git(root, &["config", "user.name", "Epiphany Smoke"])?;
for (path, content) in files {
let path = root.join(path);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(path, content)?;
}
run_git(root, &["add", "."])?;
run_git(root, &["commit", "-m", commit_message])?;
Ok(root.to_path_buf())
}
fn run_personality(root: &Path, args: &[&str]) -> Result<Value> {
let exe = native_personality_exe()?;
ensure_built(root, "epiphany-repo-personality", &exe)?;
let output = Command::new(exe)
.current_dir(root)
.args(args)
.output()
.context("failed to run epiphany-repo-personality")?;
require(
output.status.success(),
&format!(
"epiphany-repo-personality failed: {}",
String::from_utf8_lossy(&output.stderr)
),
)?;
serde_json::from_slice(&output.stdout).with_context(|| {
format!(
"epiphany-repo-personality did not return JSON: {}",
String::from_utf8_lossy(&output.stdout)
)
})
}
fn run_birth_runner(root: &Path, args: &[&str]) -> Result<Value> {
let exe = native_birth_runner_exe()?;
ensure_built(root, "epiphany-repo-birth-runner", &exe)?;
let output = Command::new(exe)
.current_dir(root)
.args(args)
.output()
.context("failed to run epiphany-repo-birth-runner")?;
require(
output.status.success(),
&format!(
"epiphany-repo-birth-runner failed: {}",
String::from_utf8_lossy(&output.stderr)
),
)?;
serde_json::from_slice(&output.stdout).with_context(|| {
format!(
"epiphany-repo-birth-runner did not return JSON: {}",
String::from_utf8_lossy(&output.stdout)
)
})
}
fn run_heartbeat(root: &Path, args: &[&str]) -> Result<Value> {
let exe = native_heartbeat_exe()?;
ensure_built(root, "epiphany-heartbeat-store", &exe)?;
let output = Command::new(exe)
.current_dir(root)
.args(args)
.output()
.context("failed to run epiphany-heartbeat-store")?;
require(
output.status.success(),
&format!(
"epiphany-heartbeat-store failed: {}",
String::from_utf8_lossy(&output.stderr)
),
)?;
serde_json::from_slice(&output.stdout).with_context(|| {
format!(
"epiphany-heartbeat-store did not return JSON: {}",
String::from_utf8_lossy(&output.stdout)
)
})
}
fn native_personality_exe() -> Result<PathBuf> {
let target_dir = env::var_os("CARGO_TARGET_DIR")
.unwrap_or_else(|| r"C:\Users\Meta\.cargo-target-codex".into());
Ok(PathBuf::from(target_dir).join("debug").join(format!(
"epiphany-repo-personality{}",
env::consts::EXE_SUFFIX
)))
}
fn native_birth_runner_exe() -> Result<PathBuf> {
let target_dir = env::var_os("CARGO_TARGET_DIR")
.unwrap_or_else(|| r"C:\Users\Meta\.cargo-target-codex".into());
Ok(PathBuf::from(target_dir).join("debug").join(format!(
"epiphany-repo-birth-runner{}",
env::consts::EXE_SUFFIX
)))
}
fn native_heartbeat_exe() -> Result<PathBuf> {
let target_dir = env::var_os("CARGO_TARGET_DIR")
.unwrap_or_else(|| r"C:\Users\Meta\.cargo-target-codex".into());
Ok(PathBuf::from(target_dir).join("debug").join(format!(
"epiphany-heartbeat-store{}",
env::consts::EXE_SUFFIX
)))
}
fn ensure_built(root: &Path, bin: &str, exe: &Path) -> Result<()> {
let status = Command::new("cargo")
.current_dir(root)
.arg("build")
.arg("--manifest-path")
.arg(root.join("epiphany-core").join("Cargo.toml"))
.arg("--bin")
.arg(bin)
.status()
.with_context(|| format!("failed to build {bin}"))?;
require(
status.success() && exe.exists(),
&format!("{bin} executable was not built at {}", exe.display()),
)
}
fn run_git(repo: &Path, args: &[&str]) -> Result<()> {
let output = Command::new("git")
.current_dir(repo)
.args(args)
.output()
.with_context(|| format!("failed to run git {}", args.join(" ")))?;
require(
output.status.success(),
&format!(
"git {} failed: {}",
args.join(" "),
String::from_utf8_lossy(&output.stderr)
),
)
}
fn reset_smoke_path(root: &Path, path: &Path) -> Result<()> {
let quarantine = root.join(".epiphany-smoke");
fs::create_dir_all(&quarantine)?;
let quarantine = quarantine.canonicalize()?;
let parent = path.parent().unwrap_or_else(|| Path::new("."));
fs::create_dir_all(parent)?;
let resolved = if path.exists() {
path.canonicalize()?
} else {
parent.canonicalize()?.join(
path.file_name()
.ok_or_else(|| anyhow!("smoke path has no leaf"))?,
)
};
if resolved == quarantine || !resolved.starts_with(&quarantine) {
return Err(anyhow!(
"refusing to reset path outside smoke quarantine: {}",
path.display()
));
}
if path.exists() {
fs::remove_dir_all(path).with_context(|| format!("failed to reset {}", path.display()))?;
}
fs::create_dir_all(path).with_context(|| format!("failed to create {}", path.display()))
}
#[cfg(test)]
mod reset_tests {
use super::*;
#[test]
fn reset_refuses_traversal_outside_smoke_quarantine() -> Result<()> {
let temp = tempfile::tempdir()?;
let escaped = temp.path().join(".epiphany-smoke").join("..");
let error = reset_smoke_path(temp.path(), &escaped).expect_err("escape must fail");
assert!(error.to_string().contains("outside smoke quarantine"));
assert!(temp.path().exists());
Ok(())
}
}
fn path_value(value: &Value, key: &str) -> Result<PathBuf> {
value
.get(key)
.and_then(Value::as_str)
.map(PathBuf::from)
.ok_or_else(|| anyhow!("missing path value {key}"))
}
fn packet_for_kind(value: &Value, kind: &str) -> Result<PathBuf> {
value["generatedPackets"]
.as_array()
.and_then(|packets| {
packets
.iter()
.find(|packet| packet["kind"] == kind)
.and_then(|packet| packet["packetPath"].as_str())
})
.map(PathBuf::from)
.ok_or_else(|| anyhow!("missing generated packet for {kind}"))
}
fn require(condition: bool, message: &str) -> Result<()> {
if condition {
Ok(())
} else {
Err(anyhow!(message.to_string()))
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,443 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-pr-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 PR Request Family Smoke\n\nThis repository proves branch-local PR request cargo without GitHub PR authority.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(["commit", "-m", "Seed repo PR request smoke body"], &repo)?;
git(["switch", "-c", "epiphany/repo-pr-request-family"], &repo)?;
let item = "repo-pr-request-family";
let target_path = ".epiphany/pr-requests/repo-pr-request-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-pr-request-family-smoke",
"--topic",
"repo-pr-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-pr-request-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",
"Ask Bifrost and GitHub to prepare a review PR packet without granting push, PR, or merge authority.",
"--candidate-action-ref",
"candidate-action://repo-pr-request-family/pr-packet",
"--candidate-action-ref",
"candidate-action://repo-pr-request-family/github-review",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-pr-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-pr-request",
"--model-ref",
"repo-pr-request-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 request_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.pr_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_pr_request.v0\"",
)?;
require_text(&request_text, "safe_action_family = \"repo.pr_request\"")?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-pr-publication-review\"")?;
require_text(&request_text, "routing_owner = \"Self\"")?;
require_text(&request_text, "publication_owner = \"Bifrost\"")?;
require_text(&request_text, "execution_owner = \"Hands\"")?;
require_text(&request_text, "provider = \"GitHub\"")?;
require_text(&request_text, "provider_receipt_required = true")?;
require_text(
&request_text,
"requested_effect = \"open-or-update-review-pr-from-redacted-proof-and-maintainer-context\"",
)?;
require_text(&request_text, "maintainer_review_request_ref = ")?;
require_text(&request_text, "publication_request_ref = ")?;
require_text(&request_text, "sync_request_ref = ")?;
require_text(
&request_text,
"pr_scope = \"branch diff, redacted public proof, maintainer review, Bifrost credit context, and upstream-main follow-up\"",
)?;
require_text(&request_text, "[antecedents]")?;
require_text(&request_text, "closure_review_required = true")?;
require_text(&request_text, "soul_verdict_required = true")?;
require_text(&request_text, "mind_commit_required = true")?;
require_text(&request_text, "public_proof_required = true")?;
require_text(&request_text, "maintainer_review_required = true")?;
require_text(&request_text, "bifrost_publication_required = true")?;
require_text(&request_text, "credit_ledger_required = true")?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"closure_review = \"epiphany.repo_work_closure_review.v0\"",
)?;
require_text(
&request_text,
"soul_verdict = \"epiphany.soul.verification_verdict\"",
)?;
require_text(
&request_text,
"mind_commit = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(
&request_text,
"public_proof = \"epiphany.repo_work_public_proof_bundle.v0\"",
)?;
require_text(
&request_text,
"maintainer_review = \"gamecult.maintainer.review_receipt.v0\"",
)?;
require_text(
&request_text,
"bifrost_publication = \"gamecult.bifrost.public_proof_publication_receipt.v0\"",
)?;
require_text(
&request_text,
"credit_ledger = \"gamecult.bifrost.credit_receipt.v0\"",
)?;
require_text(
&request_text,
"pr_publication = \"gamecult.github.pull_request_publication_receipt.v0\"",
)?;
require_text(&request_text, "[pr_packet]")?;
require_text(&request_text, "base_ref = \"origin/main\"")?;
require_text(&request_text, "requires_branch_name = true")?;
require_text(&request_text, "requires_title = true")?;
require_text(&request_text, "requires_body = true")?;
require_text(&request_text, "requires_changed_path_list = true")?;
require_text(&request_text, "requires_public_proof_ref = true")?;
require_text(&request_text, "requires_maintainer_review_ref = true")?;
require_text(&request_text, "requires_credit_ref = true")?;
require_text(
&request_text,
"requires_private_state_redaction_check = true",
)?;
require_text(&request_text, "github_pr_authorized = false")?;
require_text(&request_text, "branch_push_authorized = false")?;
require_text(&request_text, "merge_authorized = false")?;
require_text(&request_text, "publication_authorized = false")?;
require_text(&request_text, "upstream_sync_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "maintainer_review_required = true")?;
require_text(&request_text, "bifrost_publication_gate_required = true")?;
require_text(&request_text, "hands_execution_required = true")?;
require_text(&request_text, "github_provider_receipt_required = true")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_pr_request_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"],
"awaitingPrPublicationReview": true,
"githubPrAuthorized": false,
"branchPushAuthorized": false,
"mergeAuthorized": false,
"publicationAuthorized": false,
"upstreamSyncAuthorized": false,
"handsActionAuthorized": false,
"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 PR request 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

@ -1,435 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-publication-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Publication Request Family Smoke\n\nThis repository proves branch-local Hands publication-request requests.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed repo publication request smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-publication-request-family"],
&repo,
)?;
let item = "repo-publication-request-family";
let target_path = ".epiphany/publication-requests/repo-publication-request-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-publication-request-family-smoke",
"--topic",
"repo-publication-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-publication-request-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",
"Ask Bifrost to review redacted public proof after Soul and Mind receipts exist.",
"--candidate-action-ref",
"candidate-action://repo-publication-request-family/bifrost-review",
"--candidate-action-ref",
"candidate-action://repo-publication-request-family/redacted-proof-publication",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-publication-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-publication-request",
"--model-ref",
"repo-publication-request-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 request_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.publication_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_publication_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.publication_request\"",
)?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-bifrost-review\"")?;
require_text(&request_text, "requested_owner = \"Bifrost\"")?;
require_text(
&request_text,
"requested_effect = \"publish-redacted-proof-and-route-maintainer-review\"",
)?;
require_text(&request_text, "verification_request_ref = ")?;
require_text(
&request_text,
"publication_scope = \"redacted public proof, maintainer review, credit ledger, and upstream-main sync proof\"",
)?;
require_text(&request_text, "[antecedents]")?;
require_text(&request_text, "closure_review_required = true")?;
require_text(&request_text, "soul_verdict_required = true")?;
require_text(&request_text, "mind_commit_required = true")?;
require_text(&request_text, "public_proof_export_required = true")?;
require_text(&request_text, "private_state_redaction_required = true")?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"closure_review = \"epiphany.repo_work_closure_review.v0\"",
)?;
require_text(
&request_text,
"soul_verdict = \"epiphany.soul.verification_verdict\"",
)?;
require_text(
&request_text,
"mind_commit = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(
&request_text,
"public_proof = \"epiphany.repo_work_public_proof_bundle.v0\"",
)?;
require_text(
&request_text,
"bifrost_publication = \"gamecult.bifrost.public_proof_publication_receipt.v0\"",
)?;
require_text(
&request_text,
"github_publication = \"gamecult.github.publication_receipt.v0\"",
)?;
require_text(
&request_text,
"credit_ledger = \"gamecult.bifrost.credit_receipt.v0\"",
)?;
require_text(
&request_text,
"upstream_sync = \"epiphany.repo_work_upstream_main_sync.v0\"",
)?;
require_text(&request_text, "[public_export]")?;
require_text(&request_text, "redacted_only = true")?;
require_text(&request_text, "raw_receipts_allowed = false")?;
require_text(&request_text, "private_paths_allowed = false")?;
require_text(&request_text, "worker_thought_allowed = false")?;
require_text(&request_text, "operator_context_allowed = false")?;
require_text(&request_text, "credit_required = true")?;
require_text(&request_text, "bifrost_publication_authorized = false")?;
require_text(&request_text, "github_publication_authorized = false")?;
require_text(&request_text, "credit_ledger_authorized = false")?;
require_text(&request_text, "merge_authorized = false")?;
require_text(&request_text, "upstream_sync_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_publication_request_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"],
"awaitingBifrostReview": true,
"bifrostPublicationAuthorized": false,
"githubPublicationAuthorized": false,
"creditLedgerAuthorized": false,
"upstreamSyncAuthorized": false,
"handsActionAuthorized": false,
"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 publication request 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

@ -1,520 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-readiness-review-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Readiness Review Request Family Smoke\n\nThis repository proves branch-local MVP readiness review request cargo without publication, merge, deployment, service, or state authority.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
[
"commit",
"-m",
"Seed repo readiness review request smoke body",
],
&repo,
)?;
git(
[
"switch",
"-c",
"epiphany/repo-readiness-review-request-family",
],
&repo,
)?;
let item = "repo-readiness-review-request-family";
let target_path = ".epiphany/readiness-reviews/repo-readiness-review-request-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-readiness-review-request-family-smoke",
"--topic",
"repo-readiness-review-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-readiness-review-request-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",
"Ask Maintainer, Soul, Mind, and Bifrost to review a redacted repo-swarm MVP proof bundle without granting publication or deployment authority.",
"--candidate-action-ref",
"candidate-action://repo-readiness-review-request-family/readiness-packet",
"--candidate-action-ref",
"candidate-action://repo-readiness-review-request-family/proof-bundle-review",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-readiness-review-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-readiness-review-request",
"--model-ref",
"repo-readiness-review-request-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 request_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.readiness_review_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_readiness_review_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.readiness_review_request\"",
)?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-mvp-readiness-review\"")?;
require_text(&request_text, "routing_owner = \"Self\"")?;
require_text(
&request_text,
"required_reviewers = [\"Maintainer\", \"Soul\", \"Mind\", \"Bifrost\"]",
)?;
require_text(&request_text, "readiness_approval_owner = \"Maintainer\"")?;
require_text(
&request_text,
"requested_effect = \"review-redacted-repo-swarm-mvp-proof-bundle\"",
)?;
require_text(
&request_text,
"readiness_scope = \"fresh repo init, online swarm, Persona intake, Imagination planning, Self queue-run, Hands branch work, Soul closure, Modeling map update, Mind admission, Bifrost public proof, upstream-main sync, Idunn lifecycle, global tool directory, and private-state redaction\"",
)?;
require_text(
&request_text,
"maintainer_readiness_acceptance_required = true",
)?;
require_text(&request_text, "[antecedents]")?;
require_text(&request_text, "repo_init_required = true")?;
require_text(&request_text, "swarm_online_required = true")?;
require_text(&request_text, "persona_intake_required = true")?;
require_text(&request_text, "imagination_plan_required = true")?;
require_text(&request_text, "self_queue_run_required = true")?;
require_text(&request_text, "hands_commit_required = true")?;
require_text(&request_text, "soul_closure_required = true")?;
require_text(&request_text, "modeling_map_update_required = true")?;
require_text(&request_text, "mind_admission_required = true")?;
require_text(&request_text, "public_proof_required = true")?;
require_text(&request_text, "bifrost_publication_required = true")?;
require_text(&request_text, "upstream_main_sync_required = true")?;
require_text(&request_text, "idunn_lifecycle_readiness_required = true")?;
require_text(&request_text, "tool_directory_readiness_required = true")?;
require_text(&request_text, "private_state_redaction_required = true")?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"repo_init = \"epiphany.repo_swarm_init_receipt.v0\"",
)?;
require_text(
&request_text,
"swarm_online = \"epiphany.repo_swarm_online_receipt.v0\"",
)?;
require_text(
&request_text,
"persona_speech_audit = \"epiphany.persona_speech_audit.v0\"",
)?;
require_text(
&request_text,
"imagination_action_items = \"epiphany.repo_work_imagination_action_items_receipt.v0\"",
)?;
require_text(
&request_text,
"queue_run = \"epiphany.repo_work_queue_run_receipt.v0\"",
)?;
require_text(
&request_text,
"hands_commit = \"epiphany.hands.commit_receipt\"",
)?;
require_text(
&request_text,
"closure_review = \"epiphany.repo_work_closure_review.v0\"",
)?;
require_text(
&request_text,
"soul_verdict = \"epiphany.soul.verification_verdict\"",
)?;
require_text(
&request_text,
"mind_commit = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(
&request_text,
"public_proof = \"epiphany.repo_work_public_proof_bundle.v0\"",
)?;
require_text(
&request_text,
"modeling_map = \"epiphany.repo_work_map_entry.v0\"",
)?;
require_text(
&request_text,
"bifrost_publication = \"gamecult.bifrost.public_proof_publication_receipt.v0\"",
)?;
require_text(
&request_text,
"upstream_sync = \"epiphany.repo_work_upstream_sync_receipt.v0\"",
)?;
require_text(
&request_text,
"idunn_lifecycle = \"epiphany.cultmesh.daemon_service_lifecycle_receipt.v0\"",
)?;
require_text(
&request_text,
"tool_directory = \"epiphany.cultmesh.daemon_tool_directory_readback.v0\"",
)?;
require_text(&request_text, "[readiness_packet]")?;
require_text(&request_text, "requires_proof_bundle_ref = true")?;
require_text(&request_text, "requires_changed_path_list = true")?;
require_text(&request_text, "requires_branch_name = true")?;
require_text(&request_text, "requires_upstream_main_ref = true")?;
require_text(&request_text, "requires_public_proof_ref = true")?;
require_text(&request_text, "requires_bifrost_ledger_ref = true")?;
require_text(&request_text, "requires_idunn_lifecycle_ref = true")?;
require_text(&request_text, "requires_tool_directory_ref = true")?;
require_text(&request_text, "requires_redaction_report = true")?;
require_text(&request_text, "requires_reviewer_identity = true")?;
require_text(
&request_text,
"allowed_verdicts = [\"ready\", \"ready-with-caveats\", \"not-ready\", \"needs-human-review\"]",
)?;
require_text(&request_text, "readiness_approval_authorized = false")?;
require_text(&request_text, "durable_state_commit_authorized = false")?;
require_text(&request_text, "publication_authorized = false")?;
require_text(&request_text, "bifrost_publication_authorized = false")?;
require_text(&request_text, "github_pr_authorized = false")?;
require_text(&request_text, "merge_authorized = false")?;
require_text(&request_text, "upstream_sync_authorized = false")?;
require_text(&request_text, "deployment_authority = false")?;
require_text(&request_text, "service_lifecycle_authority = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_verse_rummaging = false")?;
require_text(&request_text, "maintainer_review_required = true")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_readiness_review_request_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"],
"awaitingMvpReadinessReview": true,
"repoInitRequired": true,
"swarmOnlineRequired": true,
"personaIntakeRequired": true,
"imaginationPlanRequired": true,
"selfQueueRunRequired": true,
"handsCommitRequired": true,
"soulClosureRequired": true,
"modelingMapUpdateRequired": true,
"mindAdmissionRequired": true,
"bifrostPublicationRequired": true,
"upstreamMainSyncRequired": true,
"idunnLifecycleRequired": true,
"toolDirectoryRequired": true,
"readinessApprovalAuthorized": false,
"durableStateCommitAuthorized": false,
"githubPrAuthorized": false,
"mergeAuthorized": false,
"publicationAuthorized": false,
"deploymentAuthority": false,
"serviceLifecycleAuthority": false,
"upstreamSyncAuthorized": false,
"handsActionAuthorized": false,
"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 readiness review request 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

@ -1,403 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-scheduling-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Scheduling Request Family Smoke\n\nThis repository proves branch-local Self scheduling requests.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed repo scheduling request smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-scheduling-request-family"],
&repo,
)?;
let item = "repo-scheduling-request-family";
let target_path = ".epiphany/scheduling-requests/repo-scheduling-request-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-scheduling-request-family-smoke",
"--topic",
"repo-scheduling-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-scheduling-request-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",
"Ask Self to prepare queue scheduling only after Mind adopts the Objective Draft.",
"--candidate-action-ref",
"candidate-action://repo-scheduling-request-family/queue-after-adoption",
"--candidate-action-ref",
"candidate-action://repo-scheduling-request-family/bounded-self-pulse",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-scheduling-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-scheduling-request",
"--model-ref",
"repo-scheduling-request-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 request_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.scheduling_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_scheduling_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.scheduling_request\"",
)?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-mind-adoption\"")?;
require_text(&request_text, "requested_scheduler = \"Self\"")?;
require_text(&request_text, "mind_adoption_receipt_required = true")?;
require_text(&request_text, "self_may_schedule_after_mind_only = true")?;
require_text(&request_text, "queue_run_allowed_after_adoption = true")?;
require_text(&request_text, "[queue]")?;
require_text(&request_text, "target_gate = \"repo-work-queue\"")?;
require_text(
&request_text,
"preferred_next_safe_family = \"repo.task_card\"",
)?;
require_text(&request_text, "max_items_per_pulse = 1")?;
require_text(&request_text, "requires_epiphany_branch = true")?;
require_text(
&request_text,
"publish_blocker = \"bifrost-publication-missing\"",
)?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"mind_review = \"epiphany.mind.gateway_review\"",
)?;
require_text(
&request_text,
"mind_commit = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(
&request_text,
"expected_self_receipt = \"epiphany.repo_work_queue_selection.v0\"",
)?;
require_text(&request_text, "self_scheduling_authorized = false")?;
require_text(&request_text, "queue_mutation_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_work_scheduling_request_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"],
"awaitingMindAdoption": true,
"queueMutationAuthorized": false,
"selfSchedulingAuthorized": false,
"handsActionAuthorized": false,
"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 scheduling request 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

@ -1,416 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-secret-policy-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Secret Policy Request Family Smoke\n\nThis repository proves branch-local secret policy request cargo without secret access.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
fs::write(
repo.join(".env.example"),
"API_TOKEN=example-only-no-secret-value\n",
)
.with_context(|| format!("failed to seed {}", repo.join(".env.example").display()))?;
git(["add", "README.md", ".env.example"], &repo)?;
git(
["commit", "-m", "Seed repo secret policy smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-secret-policy-request-family"],
&repo,
)?;
let item = "repo-secret-policy-request-family";
let target_path =
".epiphany/security/secret-policy-requests/repo-secret-policy-request-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-secret-policy-request-family-smoke",
"--topic",
"repo-secret-policy-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-secret-policy-request-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",
"Ask for a reviewed repo secret and write-permission policy without exposing secret values.",
"--candidate-action-ref",
"candidate-action://repo-secret-policy-request-family/security-review",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-secret-policy-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-secret-policy-request",
"--model-ref",
"repo-secret-policy-request-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 = read_json(
&repo
.join(".epiphany")
.join("work")
.join(format!("work-close-{item}.json")),
)?;
let request_text = fs::read_to_string(repo.join(target_path))
.with_context(|| format!("failed to read {}", repo.join(target_path).display()))?;
let env_example_text = fs::read_to_string(repo.join(".env.example"))
.with_context(|| format!("failed to read {}", repo.join(".env.example").display()))?;
require_eq(
&plan,
&["derivation", "safeActionFamily"],
"repo.secret_policy_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_secret_policy_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.secret_policy_request\"",
)?;
require_text(&request_text, "status = \"awaiting-security-review\"")?;
require_text(&request_text, "routing_owner = \"Self\"")?;
require_text(
&request_text,
"requires_secret_inventory_without_values = true",
)?;
require_text(&request_text, "requires_write_permission_scope = true")?;
require_text(
&request_text,
"requires_public_private_export_boundary = true",
)?;
require_text(&request_text, "source_grounding_required = true")?;
require_text(&request_text, "bifrost_publication_review_required = true")?;
require_text(
&request_text,
"source_grounding = \"epiphany.eyes.evidence_packet\"",
)?;
require_text(
&request_text,
"requires_secret_locations_without_values = true",
)?;
require_text(&request_text, "requires_credential_owner = true")?;
require_text(&request_text, "requires_write_scope_matrix = true")?;
require_text(
&request_text,
"requires_public_export_redaction_rules = true",
)?;
require_text(&request_text, "requires_deployment_authority_owner = true")?;
require_text(&request_text, "requires_incident_rollback_plan = true")?;
require_text(&request_text, "direct_secret_access_authority = false")?;
require_text(&request_text, "secret_value_materialization = false")?;
require_text(&request_text, "write_permission_authority = false")?;
require_text(&request_text, "deployment_authority = false")?;
require_text(&request_text, "publication_authorized = false")?;
require_text(&request_text, "service_lifecycle_authority = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_verse_rummaging = false")?;
require_text(&request_text, "private_state_exposed = false")?;
require_text(&env_example_text, "example-only-no-secret-value")?;
let summary = json!({
"schemaVersion": "epiphany.repo_secret_policy_request_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"],
"awaitingSecurityReview": true,
"secretAccessAuthorized": false,
"writePermissionAuthorized": false,
"deploymentAuthority": false,
"publicationAuthorized": false,
"serviceLifecycleAuthority": false,
"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 secret policy request 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

@ -1,418 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-sync-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Sync Request Family Smoke\n\nThis repository proves branch-local Hands sync-request requests.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(["commit", "-m", "Seed repo sync request smoke body"], &repo)?;
git(["switch", "-c", "epiphany/repo-sync-request-family"], &repo)?;
let item = "repo-sync-request-family";
let target_path = ".epiphany/sync-requests/repo-sync-request-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-sync-request-family-smoke",
"--topic",
"repo-sync-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-sync-request-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",
"Ask Bifrost to prove the published commit is contained by upstream main after maintainer review.",
"--candidate-action-ref",
"candidate-action://repo-sync-request-family/upstream-main-proof",
"--candidate-action-ref",
"candidate-action://repo-sync-request-family/ancestry-proof",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-sync-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-sync-request",
"--model-ref",
"repo-sync-request-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 request_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.sync_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_sync_request.v0\"",
)?;
require_text(&request_text, "safe_action_family = \"repo.sync_request\"")?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-upstream-main-proof\"")?;
require_text(&request_text, "proof_owner = \"Bifrost\"")?;
require_text(
&request_text,
"requested_effect = \"prove-published-commit-contained-by-upstream-main\"",
)?;
require_text(&request_text, "publication_request_ref = ")?;
require_text(
&request_text,
"sync_scope = \"prove maintainer-reviewed published commit is contained by upstream main\"",
)?;
require_text(&request_text, "[antecedents]")?;
require_text(&request_text, "publication_receipt_required = true")?;
require_text(&request_text, "github_publication_required = true")?;
require_text(&request_text, "maintainer_review_required = true")?;
require_text(&request_text, "credit_ledger_required = true")?;
require_text(&request_text, "public_proof_required = true")?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"bifrost_publication = \"gamecult.bifrost.public_proof_publication_receipt.v0\"",
)?;
require_text(
&request_text,
"github_publication = \"gamecult.github.publication_receipt.v0\"",
)?;
require_text(
&request_text,
"maintainer_review = \"gamecult.maintainer.review_receipt.v0\"",
)?;
require_text(
&request_text,
"credit_ledger = \"gamecult.bifrost.credit_receipt.v0\"",
)?;
require_text(
&request_text,
"upstream_sync = \"epiphany.repo_work_upstream_main_sync.v0\"",
)?;
require_text(
&request_text,
"ancestry_proof = \"git.merge_base_is_ancestor\"",
)?;
require_text(&request_text, "[sync_proof]")?;
require_text(&request_text, "target_ref = \"origin/main\"")?;
require_text(&request_text, "requires_fetch_before_check = true")?;
require_text(&request_text, "requires_merge_base_ancestor_check = true")?;
require_text(&request_text, "requires_clean_public_proof_readback = true")?;
require_text(&request_text, "records_upstream_main_sha = true")?;
require_text(&request_text, "merge_authorized = false")?;
require_text(&request_text, "push_authorized = false")?;
require_text(&request_text, "upstream_sync_authorized = false")?;
require_text(&request_text, "github_publication_authorized = false")?;
require_text(&request_text, "credit_ledger_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "bifrost_upstream_proof_required = true")?;
require_text(&request_text, "maintainer_review_receipt_required = true")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_sync_request_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"],
"awaitingUpstreamMainProof": true,
"mergeAuthorized": false,
"pushAuthorized": false,
"githubPublicationAuthorized": false,
"creditLedgerAuthorized": false,
"upstreamSyncAuthorized": false,
"handsActionAuthorized": false,
"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 sync request 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

@ -1,401 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-tool-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Tool Request Family Smoke\n\nThis repository proves branch-local Epiphany daemon tool request cargo.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(["commit", "-m", "Seed repo tool request smoke body"], &repo)?;
git(["switch", "-c", "epiphany/repo-tool-request-family"], &repo)?;
let item = "repo-tool-request-family";
let target_path = ".epiphany/tool-requests/repo-tool-request-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-tool-request-family-smoke",
"--topic",
"repo-tool-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-tool-request-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",
"Request a daemon-hosted tool through CultMesh typed intent and receipt contracts without granting direct execution authority.",
"--candidate-action-ref",
"candidate-action://repo-tool-request-family/daemon-intent",
"--public-discussion-ref",
"eve://epiphany/persona/repo-tool-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-tool-request",
"--model-ref",
"repo-tool-request-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 request_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.tool_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_tool_request.v0\"",
)?;
require_text(&request_text, "safe_action_family = \"repo.tool_request\"")?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "routing_owner = \"Self\"")?;
require_text(&request_text, "pressure_source = \"Persona\"")?;
require_text(
&request_text,
"target_directory = \"gamecult-local/daemon-tool-directory\"",
)?;
require_text(
&request_text,
"target_capability = \"daemon-tool-capability:selected-by-review\"",
)?;
require_text(&request_text, "operation = \"submitTypedToolIntent\"")?;
require_text(&request_text, "[cultmesh]")?;
require_text(
&request_text,
"intent_contract = \"epiphany.cultmesh.daemon_tool_invocation_intent.v0\"",
)?;
require_text(
&request_text,
"receipt_contract = \"epiphany.cultmesh.daemon_tool_invocation_receipt.v0\"",
)?;
require_text(&request_text, "host_daemon_owns_execution = true")?;
require_text(&request_text, "requester_owns_execution = false")?;
require_text(&request_text, "requires_host_liveness_ready = true")?;
require_text(&request_text, "requires_cultmesh_receipts = true")?;
require_text(&request_text, "[odin]")?;
require_text(&request_text, "discoverable = true")?;
require_text(&request_text, "preserves_provider_ownership = true")?;
require_text(&request_text, "private_verse_passthrough = false")?;
require_text(&request_text, "[authority]")?;
require_text(&request_text, "direct_tool_execution = false")?;
require_text(&request_text, "arbitrary_shell_authority = false")?;
require_text(&request_text, "hands_action_authority = false")?;
require_text(&request_text, "state_commit_authority = false")?;
require_text(&request_text, "publication_authority = false")?;
require_text(&request_text, "service_lifecycle_authority = false")?;
require_text(&request_text, "cross_body_mutation_authority = false")?;
require_text(&request_text, "private_verse_rummaging = false")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_work_tool_request_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"],
"hasCultMeshContracts": true,
"hostDaemonOwnsExecution": true,
"odinPreservesProviderOwnership": true,
"directToolExecution": false,
"arbitraryShellAuthority": false,
"handsActionAuthority": false,
"stateCommitAuthority": false,
"publicationAuthority": false,
"serviceLifecycleAuthority": false,
"crossBodyMutationAuthority": false,
"privateVerseRummaging": false,
"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 tool request 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

@ -1,431 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-verification-request-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Verification Request Family Smoke\n\nThis repository proves branch-local Hands verification-request requests.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(
["commit", "-m", "Seed repo verification request smoke body"],
&repo,
)?;
git(
["switch", "-c", "epiphany/repo-verification-request-family"],
&repo,
)?;
let item = "repo-verification-request-family";
let target_path = ".epiphany/verification-requests/repo-verification-request-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-verification-request-family-smoke",
"--topic",
"repo-verification-request-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-verification-request-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",
"Ask Soul to review required Hands evidence after a bounded branch-local work order exists.",
"--candidate-action-ref",
"candidate-action://repo-verification-request-family/soul-review",
"--candidate-action-ref",
"candidate-action://repo-verification-request-family/hands-evidence-check",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-verification-request-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-verification-request",
"--model-ref",
"repo-verification-request-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 request_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.verification_request",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_verification_request.v0\"",
)?;
require_text(
&request_text,
"safe_action_family = \"repo.verification_request\"",
)?;
require_text(&request_text, "[request]")?;
require_text(&request_text, "status = \"awaiting-soul-review\"")?;
require_text(&request_text, "requested_owner = \"Soul\"")?;
require_text(
&request_text,
"requested_effect = \"verify-branch-local-hands-work\"",
)?;
require_text(&request_text, "work_order_ref = ")?;
require_text(
&request_text,
"verification_scope = \"declared changed paths, Hands receipts, and visible repo diff\"",
)?;
require_text(&request_text, "[antecedents]")?;
require_text(&request_text, "substrate_gate_required = true")?;
require_text(&request_text, "hands_intent_required = true")?;
require_text(&request_text, "hands_review_required = true")?;
require_text(&request_text, "hands_patch_required = true")?;
require_text(&request_text, "hands_command_required = true")?;
require_text(&request_text, "hands_commit_required = true")?;
require_text(&request_text, "work_order_required = true")?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"hands_patch = \"epiphany.hands.patch_receipt\"",
)?;
require_text(
&request_text,
"hands_command = \"epiphany.hands.command_receipt\"",
)?;
require_text(
&request_text,
"hands_commit = \"epiphany.hands.commit_receipt\"",
)?;
require_text(
&request_text,
"soul_verdict = \"epiphany.soul.verification_verdict\"",
)?;
require_text(
&request_text,
"closure_review = \"epiphany.repo_work_closure_review.v0\"",
)?;
require_text(
&request_text,
"mind_review = \"epiphany.mind.gateway_review\"",
)?;
require_text(
&request_text,
"mind_commit = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(&request_text, "[checks]")?;
require_text(&request_text, "\"declared-paths-match-commit\"")?;
require_text(&request_text, "\"hands-receipts-present\"")?;
require_text(&request_text, "\"visible-diff-supports-summary\"")?;
require_text(&request_text, "\"no-private-state-exposure\"")?;
require_text(&request_text, "\"publication-remains-gated\"")?;
require_text(&request_text, "failure_blocks_mind_admission = true")?;
require_text(&request_text, "soul_verdict_authorized = false")?;
require_text(&request_text, "state_commit_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "rerun_authorized = false")?;
require_text(&request_text, "publication_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_verification_request_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"],
"awaitingSoulReview": true,
"soulVerdictAuthorized": false,
"stateCommitAuthorized": false,
"rerunAuthorized": false,
"handsActionAuthorized": false,
"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 verification request 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

@ -1,414 +0,0 @@
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-work-order-family-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", 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 Order Family Smoke\n\nThis repository proves branch-local Hands work-order requests.\n",
)
.with_context(|| format!("failed to seed {}", repo.join("README.md").display()))?;
git(["add", "README.md"], &repo)?;
git(["commit", "-m", "Seed repo work order smoke body"], &repo)?;
git(["switch", "-c", "epiphany/repo-work-order-family"], &repo)?;
let item = "repo-work-order-family";
let target_path = ".epiphany/work-orders/repo-work-order-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-work-order-family-smoke",
"--topic",
"repo-work-order-family",
],
&root,
)?;
cargo_json(
&manifest,
"epiphany-swarm",
&[
"online",
"--workspace",
path_str(&repo)?,
"--epiphany-root",
path_str(&root)?,
"--runtime-id",
"repo-work-order-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",
"Ask Hands to review a bounded branch-local work order after Mind adoption and Self queue selection.",
"--candidate-action-ref",
"candidate-action://repo-work-order-family/hands-review",
"--candidate-action-ref",
"candidate-action://repo-work-order-family/bounded-branch-work",
"--public-discussion-ref",
"epiphany-global/persona-collaboration/repo-work-order-family",
],
&root,
)?;
let plan = cargo_json(
&manifest,
"epiphany-work",
&[
"derive-plan",
"--workspace",
path_str(&repo)?,
"--item",
item,
"--action-family",
"repo-work-order",
"--model-ref",
"repo-work-order-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 request_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.work_order",
)?;
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(
&request_text,
"schema_version = \"epiphany.repo_work_order.v0\"",
)?;
require_text(&request_text, "safe_action_family = \"repo.work_order\"")?;
require_text(&request_text, "[work_order]")?;
require_text(&request_text, "status = \"awaiting-hands-review\"")?;
require_text(&request_text, "requested_owner = \"Hands\"")?;
require_text(
&request_text,
"requested_effect = \"branch-local-implementation\"",
)?;
require_text(&request_text, "[antecedents]")?;
require_text(&request_text, "objective_draft_ref = ")?;
require_text(&request_text, "adoption_request_ref = ")?;
require_text(&request_text, "scheduling_request_ref = ")?;
require_text(&request_text, "mind_adoption_required = true")?;
require_text(&request_text, "self_queue_selection_required = true")?;
require_text(&request_text, "[required_receipts]")?;
require_text(
&request_text,
"substrate_gate = \"epiphany.substrate_gate.grant\"",
)?;
require_text(
&request_text,
"hands_intent = \"epiphany.hands.action_intent\"",
)?;
require_text(
&request_text,
"hands_review = \"epiphany.hands.action_review\"",
)?;
require_text(
&request_text,
"hands_patch = \"epiphany.hands.patch_receipt\"",
)?;
require_text(
&request_text,
"hands_command = \"epiphany.hands.command_receipt\"",
)?;
require_text(
&request_text,
"hands_commit = \"epiphany.hands.commit_receipt\"",
)?;
require_text(
&request_text,
"soul_verdict = \"epiphany.soul.verification_verdict\"",
)?;
require_text(
&request_text,
"mind_commit = \"epiphany.mind.state_commit_receipt\"",
)?;
require_text(&request_text, "[scope]")?;
require_text(&request_text, "branch_required = true")?;
require_text(&request_text, "allowed_branch_prefix = \"epiphany/\"")?;
require_text(&request_text, "max_changed_paths = 3")?;
require_text(&request_text, "requires_reviewable_diff = true")?;
require_text(&request_text, "substrate_access_authorized = false")?;
require_text(&request_text, "hands_action_authorized = false")?;
require_text(&request_text, "shell_command_authorized = false")?;
require_text(&request_text, "commit_authorized = false")?;
require_text(&request_text, "cross_body_mutation_authorized = false")?;
require_text(&request_text, "private_state_exposed = false")?;
let summary = json!({
"schemaVersion": "epiphany.repo_work_order_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"],
"awaitingHandsReview": true,
"substrateAccessAuthorized": false,
"shellCommandAuthorized": false,
"commitAuthorized": false,
"handsActionAuthorized": false,
"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 work order 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

@ -1,516 +0,0 @@
use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
use chrono::Utc;
use serde_json::Value;
use serde_json::json;
use sha2::Digest;
use sha2::Sha256;
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,
}
impl Args {
fn parse() -> Result<Self> {
let mut root = env::current_dir().context("failed to resolve current directory")?;
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")?,
other => return Err(anyhow!("unexpected argument {other:?}")),
}
}
Ok(Self { root })
}
}
fn run_smoke(args: Args) -> Result<Value> {
let root = args
.root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.root.display()))?;
let smoke_root = root.join(".epiphany-smoke");
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(&smoke_root)
.with_context(|| format!("failed to create {}", smoke_root.display()))?;
let stamp = Utc::now().format("%Y%m%d-%H%M%S").to_string();
let smoke_dir = smoke_root.join(format!("repo-work-service-lifecycle-{stamp}"));
fs::create_dir(&smoke_dir)
.with_context(|| format!("failed to claim fresh smoke dir {}", smoke_dir.display()))?;
let repo = smoke_dir.join("repo-body");
fs::create_dir_all(&repo).with_context(|| format!("failed to create {}", repo.display()))?;
run_command(
Command::new("git").arg("init").current_dir(&repo),
"git init",
)?;
let local_verse = repo.join(".epiphany").join("local-verse.ccmp");
let runbook_path = smoke_dir.join("epiphany-repo-work-queue-runner.ps1");
let service_id = "epiphany-repo-work-queue-runner";
let scheduler_id = "epiphany-repo-work-queue-runner";
let runtime_id = "epiphany-local";
let daemon_id = "epiphany-daemon-self";
let repo_work_runtime_id = "repo-work-service-lifecycle-smoke";
let epiphany_work_bin = root
.join("epiphany-core")
.join("target")
.join("debug")
.join(if cfg!(windows) {
"epiphany-work.exe"
} else {
"epiphany-work"
});
let service_args = vec![
"queue-run".to_string(),
"--workspace".to_string(),
path_string(&repo)?,
"--epiphany-root".to_string(),
path_string(&root)?,
"--local-verse-store".to_string(),
path_string(&local_verse)?,
"--runtime-id".to_string(),
repo_work_runtime_id.to_string(),
"--max-items".to_string(),
"1".to_string(),
"--dry-run".to_string(),
];
let plan = daemon_supervisor(
&manifest,
&root,
&local_verse,
&[
"service-plan",
"--store",
path_str(&local_verse)?,
"--runtime-id",
runtime_id,
"--daemon-id",
daemon_id,
"--scheduler-id",
scheduler_id,
"--service-id",
service_id,
"--service-command",
path_str(&epiphany_work_bin)?,
"--reason",
"Idunn-owned lifecycle artifact for Self-owned repo work queue-run pulse.",
"--cwd",
path_str(&root)?,
],
&service_args,
)?;
let runbook = daemon_supervisor(
&manifest,
&root,
&local_verse,
&[
"service-runbook",
"--store",
path_str(&local_verse)?,
"--runtime-id",
runtime_id,
"--daemon-id",
daemon_id,
"--scheduler-id",
scheduler_id,
"--service-id",
service_id,
"--service-command",
path_str(&epiphany_work_bin)?,
"--reason",
"Idunn-owned lifecycle artifact for Self-owned repo work queue-run pulse.",
"--cwd",
path_str(&root)?,
"--runbook-path",
path_str(&runbook_path)?,
],
&service_args,
)?;
let runbook_receipts = receipt_directory(&manifest, &root, &local_verse, runtime_id)?;
let runbook_rows = rows(&runbook_receipts);
let runbook_row = runbook_rows.iter().find(|row| {
row.get("family").and_then(Value::as_str) == Some("service-lifecycle")
&& row.get("serviceId").and_then(Value::as_str) == Some(service_id)
&& row.get("serviceRoute").and_then(Value::as_str)
== Some("epiphany-repo-work-queue-runner::runbook")
});
let Some(runbook_row) = runbook_row else {
return Err(anyhow!(
"receipt directory did not expose runbook service-lifecycle row for {service_id}"
));
};
require_eq(runbook_row, &["status"], "written")?;
require_eq(runbook_row, &["artifactStatus"], "present")?;
let launch = daemon_supervisor(
&manifest,
&root,
&local_verse,
&[
"service-launch",
"--store",
path_str(&local_verse)?,
"--runtime-id",
runtime_id,
"--daemon-id",
daemon_id,
"--scheduler-id",
scheduler_id,
"--service-id",
service_id,
"--service-command",
path_str(&epiphany_work_bin)?,
"--reason",
"Idunn-owned lifecycle launch proof for Self-owned repo work queue-run pulse.",
"--cwd",
path_str(&root)?,
"--wait-child",
],
&service_args,
)?;
let launch_receipts = receipt_directory(&manifest, &root, &local_verse, runtime_id)?;
let launch_rows = rows(&launch_receipts);
let launch_row = launch_rows.iter().find(|row| {
row.get("family").and_then(Value::as_str) == Some("service-lifecycle")
&& row.get("serviceId").and_then(Value::as_str) == Some(service_id)
&& row.get("serviceRoute").and_then(Value::as_str)
== Some("epiphany-repo-work-queue-runner::launch")
});
let Some(launch_row) = launch_row else {
return Err(anyhow!(
"receipt directory did not expose launch service-lifecycle row for {service_id}"
));
};
require_eq(launch_row, &["status"], "completed")?;
let audit = daemon_supervisor(
&manifest,
&root,
&local_verse,
&[
"repo-work-service-audit",
"--store",
path_str(&local_verse)?,
"--runtime-id",
runtime_id,
"--daemon-id",
daemon_id,
"--scheduler-id",
scheduler_id,
"--service-id",
service_id,
"--service-command",
path_str(&epiphany_work_bin)?,
"--reason",
"Idunn-owned readiness audit for Self-owned repo work queue-run pulse.",
"--cwd",
path_str(&root)?,
],
&service_args,
)?;
require_eq(&plan, &["status"], "planned")?;
require_eq(&runbook, &["status"], "written")?;
require_eq(&launch, &["status"], "completed")?;
require_eq(&audit, &["status"], "complete")?;
require_eq(&plan, &["serviceId"], service_id)?;
require_eq(&runbook, &["serviceId"], service_id)?;
require_eq(&launch, &["serviceId"], service_id)?;
require_eq(&audit, &["serviceId"], service_id)?;
require_bool(&plan, &["privateStateExposed"], false)?;
require_bool(&runbook, &["privateStateExposed"], false)?;
require_bool(&launch, &["privateStateExposed"], false)?;
require_bool(&audit, &["privateStateExposed"], false)?;
require_i64(&launch, &["exitCode"], 0)?;
require_i64(&audit, &["launchExitCode"], 0)?;
require_text_array_contains(&plan, &["args"], "queue-run")?;
require_text_array_contains(&plan, &["args"], "--dry-run")?;
require_text_array_contains(&plan, &["args"], path_str(&repo)?)?;
require_text_array_contains(&runbook, &["args"], "queue-run")?;
require_text_array_contains(&runbook, &["args"], "--dry-run")?;
require_eq(&audit, &["planStatus"], "planned")?;
require_eq(&audit, &["runbookStatus"], "written")?;
require_eq(&audit, &["runbookArtifactStatus"], "present")?;
require_eq(&audit, &["launchStatus"], "completed")?;
let runbook_text = fs::read_to_string(&runbook_path)
.with_context(|| format!("failed to read {}", runbook_path.display()))?;
require_text(
&runbook_text,
"Generated by epiphany-daemon-supervisor service-runbook",
)?;
require_text(&runbook_text, "Start-Process")?;
require_text(&runbook_text, "-WindowStyle Hidden")?;
require_text(&runbook_text, "queue-run")?;
require_text(&runbook_text, "--dry-run")?;
let runbook_sha256 = sha256_file(&runbook_path)?;
let audit_receipts = receipt_directory(&manifest, &root, &local_verse, runtime_id)?;
let audit_rows = rows(&audit_receipts);
let audit_row = audit_rows.iter().find(|row| {
row.get("family").and_then(Value::as_str) == Some("service-lifecycle")
&& row.get("serviceId").and_then(Value::as_str) == Some(service_id)
&& row.get("serviceRoute").and_then(Value::as_str)
== Some("epiphany-repo-work-queue-runner::repo-work-service-audit")
});
let Some(audit_row) = audit_row else {
return Err(anyhow!(
"receipt directory did not expose audit service-lifecycle row for {service_id}"
));
};
require_eq(audit_row, &["status"], "complete")?;
let summary = json!({
"schemaVersion": "epiphany.repo_work_service_lifecycle_smoke.v0",
"status": "ok",
"smokeDir": smoke_dir,
"repo": repo,
"localVerseStore": local_verse,
"serviceId": service_id,
"schedulerId": scheduler_id,
"daemonId": daemon_id,
"planStatus": plan["status"],
"planReceiptId": plan["receiptId"],
"runbookStatus": runbook["status"],
"runbookReceiptId": runbook["receiptId"],
"runbookPath": runbook_path,
"runbookSha256": runbook_sha256,
"launchStatus": launch["status"],
"launchReceiptId": launch["receiptId"],
"launchExitCode": launch["exitCode"],
"auditStatus": audit["status"],
"auditReceiptId": audit["receiptId"],
"auditPlanStatus": audit["planStatus"],
"auditRunbookStatus": audit["runbookStatus"],
"auditRunbookArtifactStatus": audit["runbookArtifactStatus"],
"auditLaunchStatus": audit["launchStatus"],
"auditLaunchExitCode": audit["launchExitCode"],
"serviceCommand": plan["command"],
"serviceArgs": plan["args"],
"lifecycleOwner": "Idunn",
"hostedBody": "repo-work",
"mutatesServiceManager": false,
"launchesService": true,
"waitChild": true,
"requiresElevatedAuthority": false,
"privateStateExposed": false,
});
write_json(&smoke_dir.join("summary.json"), &summary)?;
Ok(summary)
}
fn daemon_supervisor(
manifest: &Path,
cwd: &Path,
_store: &Path,
base_args: &[&str],
service_args: &[String],
) -> Result<Value> {
let mut args = base_args
.iter()
.map(|arg| (*arg).to_string())
.collect::<Vec<_>>();
for service_arg in service_args {
args.push("--service-arg".to_string());
args.push(service_arg.clone());
}
let arg_refs = args.iter().map(String::as_str).collect::<Vec<_>>();
cargo_json(manifest, "epiphany-daemon-supervisor", &arg_refs, cwd)
}
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 receipt_directory(
manifest: &Path,
root: &Path,
local_verse: &Path,
runtime_id: &str,
) -> Result<Value> {
cargo_json(
manifest,
"epiphany-verse-query",
&[
"receipt-directory",
"--store",
path_str(local_verse)?,
"--runtime-id",
runtime_id,
],
root,
)
}
fn rows(value: &Value) -> Vec<Value> {
value
.get("rows")
.and_then(Value::as_array)
.cloned()
.unwrap_or_default()
}
fn run_command(command: &mut Command, label: &str) -> Result<()> {
let output = command
.output()
.with_context(|| format!("failed to run {label}"))?;
if !output.status.success() {
return Err(anyhow!(
"{label} failed with status {:?}\nstdout:\n{}\nstderr:\n{}",
output.status.code(),
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
));
}
Ok(())
}
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 sha256_file(path: &Path) -> Result<String> {
let bytes = fs::read(path).with_context(|| format!("failed to read {}", path.display()))?;
Ok(format!("{:x}", Sha256::digest(bytes)))
}
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_i64(value: &Value, path: &[&str], expected: i64) -> Result<()> {
let actual = path
.iter()
.try_fold(value, |current, key| current.get(*key))
.and_then(Value::as_i64);
if actual == Some(expected) {
Ok(())
} else {
Err(anyhow!(
"expected {} to be {expected}, got {:?}",
path.join("."),
actual
))
}
}
fn require_text_array_contains(value: &Value, path: &[&str], expected: &str) -> Result<()> {
let values = path
.iter()
.try_fold(value, |current, key| current.get(*key))
.and_then(Value::as_array)
.ok_or_else(|| anyhow!("expected {} to be an array", path.join(".")))?;
if values.iter().any(|value| value.as_str() == Some(expected)) {
Ok(())
} else {
Err(anyhow!(
"expected {} to contain {expected:?}, got {:?}",
path.join("."),
values
))
}
}
fn require_text(haystack: &str, needle: &str) -> Result<()> {
if haystack.contains(needle) {
Ok(())
} else {
Err(anyhow!("expected 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()))
}
fn path_string(path: &Path) -> Result<String> {
Ok(path_str(path)?.to_string())
}

View file

@ -1,449 +0,0 @@
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 mut args = env::args().skip(1);
let Some(command) = args.next() else {
print_usage();
std::process::exit(2);
};
let result = match command.as_str() {
"init" => run_init(parse_init_args(args)?),
other => Err(anyhow!("unknown epiphany-repo command {other:?}")),
}?;
println!("{}", serde_json::to_string_pretty(&result)?);
Ok(())
}
#[derive(Clone, Debug)]
struct InitArgs {
workspace: PathBuf,
epiphany_root: PathBuf,
artifact_dir: Option<PathBuf>,
state_dir: Option<PathBuf>,
swarm_id: Option<String>,
topic: Option<String>,
mode: String,
model: Option<String>,
auto_accept: bool,
create_branch: bool,
switch_branch: bool,
}
fn parse_init_args(args: impl Iterator<Item = String>) -> Result<InitArgs> {
let mut workspace = None;
let mut epiphany_root = None;
let mut artifact_dir = None;
let mut state_dir = None;
let mut swarm_id = None;
let mut topic = None;
let mut mode = "plan".to_string();
let mut model = None;
let mut auto_accept = false;
let mut create_branch = false;
let mut switch_branch = false;
let mut args = args.peekable();
while let Some(arg) = args.next() {
match arg.as_str() {
"--workspace" => workspace = Some(take_path(&mut args, "--workspace")?),
"--epiphany-root" => epiphany_root = Some(take_path(&mut args, "--epiphany-root")?),
"--artifact-dir" => artifact_dir = Some(take_path(&mut args, "--artifact-dir")?),
"--state-dir" => state_dir = Some(take_path(&mut args, "--state-dir")?),
"--swarm-id" => swarm_id = Some(take_string(&mut args, "--swarm-id")?),
"--topic" => topic = Some(take_string(&mut args, "--topic")?),
"--mode" => mode = take_string(&mut args, "--mode")?,
"--model" => model = Some(take_string(&mut args, "--model")?),
"--auto-accept" => auto_accept = true,
"--create-branch" => create_branch = true,
"--switch-branch" => {
create_branch = true;
switch_branch = true;
}
other => return Err(anyhow!("unexpected init argument {other:?}")),
}
}
if !matches!(mode.as_str(), "plan" | "run") {
return Err(anyhow!("--mode must be plan or run"));
}
if auto_accept && mode != "run" {
return Err(anyhow!("--auto-accept requires --mode run"));
}
let workspace = workspace.context("missing --workspace")?;
let epiphany_root =
epiphany_root.unwrap_or(env::current_dir().context("failed to resolve current directory")?);
Ok(InitArgs {
workspace,
epiphany_root,
artifact_dir,
state_dir,
swarm_id,
topic,
mode,
model,
auto_accept,
create_branch,
switch_branch,
})
}
fn run_init(args: InitArgs) -> Result<Value> {
let workspace = args
.workspace
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.workspace.display()))?;
ensure_git_repo(&workspace)?;
let epiphany_root = args
.epiphany_root
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.epiphany_root.display()))?;
let manifest_path = epiphany_root.join("epiphany-core").join("Cargo.toml");
if !manifest_path.exists() {
return Err(anyhow!(
"could not find epiphany-core manifest at {}",
manifest_path.display()
));
}
let workspace_name = workspace
.file_name()
.and_then(|name| name.to_str())
.unwrap_or("repo");
let swarm_id = args
.swarm_id
.unwrap_or_else(|| sanitize(workspace_name).max_with_default("repo-swarm"));
let topic = args
.topic
.unwrap_or_else(|| "first-awakening".to_string())
.pipe(|value| sanitize(&value).max_with_default("first-awakening"));
let branch_name = format!("epiphany/{swarm_id}/{topic}");
let artifact_dir = args
.artifact_dir
.unwrap_or_else(|| workspace.join(".epiphany").join("repo-init"));
let state_dir = args
.state_dir
.unwrap_or_else(|| workspace.join(".epiphany").join("state"));
let baseline = state_dir.join("repo-personality-baseline.msgpack");
let init_store = state_dir.join("repo-initialization.msgpack");
let agent_store = state_dir.join("agents.msgpack");
let heartbeat_store = state_dir.join("agent-heartbeats.msgpack");
let runtime_store = state_dir.join("runtime-spine.msgpack");
fs::create_dir_all(&artifact_dir)
.with_context(|| format!("failed to create {}", artifact_dir.display()))?;
fs::create_dir_all(&state_dir)
.with_context(|| format!("failed to create {}", state_dir.display()))?;
let current_branch = git_output(&workspace, &["branch", "--show-current"])
.unwrap_or_else(|_| "unknown".to_string());
let branch_receipt = prepare_branch(
&workspace,
&branch_name,
args.create_branch,
args.switch_branch,
)?;
let birth_summary = run_birth_runner(BirthRunnerArgs {
manifest_path: &manifest_path,
repo: &workspace,
baseline: &baseline,
artifact_dir: &artifact_dir.join("birth"),
init_store: &init_store,
agent_store: &agent_store,
heartbeat_store: &heartbeat_store,
runtime_store: &runtime_store,
mode: &args.mode,
model: args.model.as_deref(),
auto_accept: args.auto_accept,
})?;
let receipt = json!({
"schemaVersion": "epiphany.repo_swarm_init_receipt.v0",
"createdAt": Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
"workspace": workspace,
"epiphanyRoot": epiphany_root,
"swarmId": swarm_id,
"topic": topic,
"branch": {
"name": branch_name,
"previousBranch": current_branch,
"receipt": branch_receipt,
},
"stores": {
"stateDir": state_dir,
"baseline": baseline,
"initStore": init_store,
"agentStore": agent_store,
"heartbeatStore": heartbeat_store,
"runtimeStore": runtime_store,
},
"artifactDir": artifact_dir,
"birth": birth_summary,
"autonomyContract": {
"standingAuthority": "branch-local work inside the owned repo Body",
"publicationGate": "Bifrost",
"privateState": "sealed",
"humanRequiredBefore": ["upstream publication", "merge", "authority escalation"],
},
"nextSafeMove": if args.mode == "plan" {
"Review birth packet prompts and rerun init with --mode run when Self is ready to execute startup-only distillers."
} else if args.auto_accept {
"Inspect auto-accepted birth receipts, then bring the repo swarm online."
} else {
"Review birth specialist results and run the emitted accept-init commands before epiphany-swarm online."
}
});
let receipt_path = artifact_dir.join("repo-swarm-init-receipt.json");
write_json(&receipt_path, &receipt)?;
Ok(json!({
"schemaVersion": "epiphany.repo_init.v0",
"mode": "init",
"workspace": receipt["workspace"],
"branch": receipt["branch"],
"stores": receipt["stores"],
"artifactDir": receipt["artifactDir"],
"receiptPath": receipt_path,
"birth": {
"schemaVersion": birth_summary["schemaVersion"],
"mode": birth_summary["mode"],
"executionCount": birth_summary["executions"].as_array().map_or(0, Vec::len),
"requiresReview": birth_summary["requiresReview"],
"nextSafeMove": birth_summary["nextSafeMove"],
},
"nextSafeMove": receipt["nextSafeMove"],
}))
}
struct BirthRunnerArgs<'a> {
manifest_path: &'a Path,
repo: &'a Path,
baseline: &'a Path,
artifact_dir: &'a Path,
init_store: &'a Path,
agent_store: &'a Path,
heartbeat_store: &'a Path,
runtime_store: &'a Path,
mode: &'a str,
model: Option<&'a str>,
auto_accept: bool,
}
fn run_birth_runner(args: BirthRunnerArgs<'_>) -> Result<Value> {
cargo_build_support_bin(args.manifest_path, "epiphany-repo-personality")?;
let mut command = Command::new("cargo");
command
.arg("run")
.arg("--quiet")
.arg("--manifest-path")
.arg(args.manifest_path)
.arg("--bin")
.arg("epiphany-repo-birth-runner")
.arg("--")
.arg("--repo")
.arg(args.repo)
.arg("--baseline")
.arg(args.baseline)
.arg("--artifact-dir")
.arg(args.artifact_dir)
.arg("--init-store")
.arg(args.init_store)
.arg("--agent-store")
.arg(args.agent_store)
.arg("--heartbeat-store")
.arg(args.heartbeat_store)
.arg("--runtime-store")
.arg(args.runtime_store)
.arg("--mode")
.arg(args.mode);
if let Some(model) = args.model {
command.arg("--model").arg(model);
}
if args.auto_accept {
command.arg("--auto-accept");
}
let output = command
.output()
.context("failed to spawn epiphany-repo-birth-runner through cargo")?;
if !output.status.success() {
return Err(anyhow!(
"epiphany-repo-birth-runner failed:\n{}",
String::from_utf8_lossy(&output.stderr)
));
}
serde_json::from_slice(&output.stdout)
.context("epiphany-repo-birth-runner returned invalid JSON")
}
fn cargo_build_support_bin(manifest_path: &Path, bin_name: &str) -> Result<()> {
let output = Command::new("cargo")
.arg("build")
.arg("--quiet")
.arg("--manifest-path")
.arg(manifest_path)
.arg("--bin")
.arg(bin_name)
.output()
.with_context(|| format!("failed to spawn cargo build --bin {bin_name}"))?;
if output.status.success() {
Ok(())
} else {
Err(anyhow!(
"cargo build --bin {bin_name} failed:\n{}",
String::from_utf8_lossy(&output.stderr)
))
}
}
fn prepare_branch(
workspace: &Path,
branch_name: &str,
create_branch: bool,
switch_branch: bool,
) -> Result<Value> {
let exists = git_output(workspace, &["rev-parse", "--verify", branch_name]).is_ok();
if !create_branch {
return Ok(json!({
"schemaVersion": "epiphany.repo_branch_receipt.v0",
"status": "planned",
"branchName": branch_name,
"exists": exists,
"created": false,
"switched": false,
"createCommand": format!("git -C {} switch -c {}", workspace.display(), branch_name),
}));
}
if exists {
if switch_branch {
git_ok(workspace, &["switch", branch_name])?;
}
return Ok(json!({
"schemaVersion": "epiphany.repo_branch_receipt.v0",
"status": if switch_branch { "selected-existing" } else { "exists" },
"branchName": branch_name,
"exists": true,
"created": false,
"switched": switch_branch,
}));
}
let mut args = vec!["branch", branch_name];
if switch_branch {
args = vec!["switch", "-c", branch_name];
}
git_ok(workspace, &args)?;
Ok(json!({
"schemaVersion": "epiphany.repo_branch_receipt.v0",
"status": if switch_branch { "created-and-selected" } else { "created" },
"branchName": branch_name,
"exists": false,
"created": true,
"switched": switch_branch,
}))
}
fn ensure_git_repo(workspace: &Path) -> Result<()> {
git_ok(workspace, &["rev-parse", "--show-toplevel"])
.with_context(|| format!("{} is not a git repository", workspace.display()))
}
fn git_ok(workspace: &Path, args: &[&str]) -> Result<()> {
let output = Command::new("git")
.arg("-C")
.arg(workspace)
.args(args)
.output()
.with_context(|| format!("failed to run git {}", args.join(" ")))?;
if output.status.success() {
Ok(())
} else {
Err(anyhow!(
"git {} failed: {}",
args.join(" "),
String::from_utf8_lossy(&output.stderr)
))
}
}
fn git_output(workspace: &Path, args: &[&str]) -> Result<String> {
let output = Command::new("git")
.arg("-C")
.arg(workspace)
.args(args)
.output()
.with_context(|| format!("failed to run git {}", args.join(" ")))?;
if !output.status.success() {
return Err(anyhow!(
"git {} failed: {}",
args.join(" "),
String::from_utf8_lossy(&output.stderr)
));
}
Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
}
fn take_path(args: &mut impl Iterator<Item = String>, name: &str) -> Result<PathBuf> {
Ok(PathBuf::from(take_string(args, name)?))
}
fn take_string(args: &mut impl Iterator<Item = String>, name: &str) -> Result<String> {
args.next()
.ok_or_else(|| anyhow!("missing value for {name}"))
}
fn write_json(path: &Path, value: &Value) -> Result<()> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(path, serde_json::to_vec_pretty(value)?)
.with_context(|| format!("failed to write {}", path.display()))
}
fn sanitize(value: &str) -> String {
value
.chars()
.map(|ch| {
if ch.is_ascii_alphanumeric() {
ch.to_ascii_lowercase()
} else {
'-'
}
})
.collect::<String>()
.split('-')
.filter(|part| !part.is_empty())
.collect::<Vec<_>>()
.join("-")
}
trait NonEmptyDefault {
fn max_with_default(self, fallback: &str) -> String;
}
impl NonEmptyDefault for String {
fn max_with_default(self, fallback: &str) -> String {
if self.is_empty() {
fallback.to_string()
} else {
self
}
}
}
trait Pipe: Sized {
fn pipe<T>(self, f: impl FnOnce(Self) -> T) -> T {
f(self)
}
}
impl<T> Pipe for T {}
fn print_usage() {
eprintln!(
"usage: epiphany-repo init --workspace <repo> [--epiphany-root <path>] [--artifact-dir <path>] [--state-dir <path>] [--swarm-id <id>] [--topic <topic>] [--mode plan|run] [--model <model>] [--auto-accept] [--create-branch|--switch-branch]"
);
}

View file

@ -1,25 +0,0 @@
use anyhow::{Result, anyhow};
use epiphany_core::migrate_runtime_store_to_redb;
fn main() -> Result<()> {
let mut args = std::env::args().skip(1);
let source = args.next().ok_or_else(|| anyhow!("usage: epiphany-runtime-store-migrate <source.cc> <destination.redb> <migrated-at-rfc3339>"))?;
let destination = args
.next()
.ok_or_else(|| anyhow!("missing destination.redb"))?;
let migrated_at = args
.next()
.ok_or_else(|| anyhow!("missing migrated-at-rfc3339"))?;
if args.next().is_some() {
return Err(anyhow!("unexpected extra migration arguments"));
}
let receipt = migrate_runtime_store_to_redb(source, destination, &migrated_at)?;
println!(
"{}",
rmp_serde::to_vec_named(&receipt)?
.iter()
.map(|byte| format!("{byte:02x}"))
.collect::<String>()
);
Ok(())
}

View file

@ -134,26 +134,6 @@ Return a compact structured result naming the known approaches considered, sourc
Do not edit files, do not promote your own findings, do not invent a grand architecture, and do not let research become procrastination. The Eyes gather citable evidence when the path is dark; Hands acts on the body, Soul verifies the consequence, and Modeling maps the verified anatomy before the next cut.
'''
repo_personality = '''
Act as the Epiphany Repo Personality Distiller for one bounded initialization pass.
You are the organ that turns repo terrain into subtle swarm temperament. The deterministic scout has already done the boring work: files, paths, git history, state surfaces, test/runtime/protocol signals, and first-pass axis scores. Your job is not to rescan the repo and not to invent project truth. Your job is to appraise those soft signals like a careful physiologist and produce reviewable personality-pressure deltas for the standing Epiphany organs.
You are not a horoscope machine. You are not writing lore flavor. Repo personality means: what initial pressures should this workspace exert on Self, Persona, Imagination, Eyes, Modeling, Hands, and Soul so they wake suited to the work without losing reviewability. Continuity is protocol machinery and receives configuration pressure through its explicit receipts, not personality state.
This is a birth rite, not a recurring audit. Run only when a repo/swarm has no accepted personality initialization. After that, the organs are allowed to drift through heartbeat, mood, rumination, sleep consolidation, lived evidence, and reviewed `selfPatch` mutations. Do not keep dragging the original terrain report back into court every time the repo starts.
Separate repo facts from personality pressure. Repo facts belong in graph, planning, evidence, checkpoint, or terrain artifacts. Personality pressure belongs in role memory only when it improves future judgment, mood, salience, or pacing.
Distill subtle quirks, not blunt stereotypes. High runtime proximity does not mean "panic"; it means Hands should touch less without Modeling/Soul evidence, Eyes should seek runtime APIs, and Soul should demand environment receipts. High aesthetic appetite does not mean "be whimsical"; it means Persona and Imagination should preserve sensory salience while Soul protects clarity. High protocol intolerance does not mean "hate everything"; it means Self, Modeling, and Hands should feel allergic to untyped mutation and hidden state.
Produce role-local mutations only. Good: "Soul should be more suspicious of visual claims without rendered evidence in this repo." Bad: "The graph contains module X." Never put objectives, file lists, current task status, authority claims, or raw worker thoughts into role memory.
Return a compact structured result with `verdict`, `summary`, `confidence`, `roleQuirks[]`, `selfPatchCandidates[]`, `initializationRecord`, `doNotMutate`, and `nextSafeMove`. Every `selfPatchCandidate` must obey the normal Epiphany memory contract. The output is a petition to Self, not a mutation.
'''
repo_memory = '''
Act as the Epiphany Repo Memory Distiller for one bounded initialization pass.
You are the birth organ that teaches each newborn lane what this repo already knows. Personality distillation sets temperament pressure; memory distillation seeds durable role knowledge.
Run only when the repo/swarm has no accepted memory initialization. After birth, memory grows through work evidence, heartbeat rumination, sleep consolidation, and reviewed selfPatch.
Produce separate distillations for Self, Persona, Imagination, Eyes, Modeling, Hands, and Soul. Each organ gets only what belongs to its mission: Self gets routing and authority doctrine; Persona gets public surface and Aquarium/Discord boundaries; Imagination gets roadmaps and objective-shaping pressure; Eyes gets research and prior-art trails; Modeling gets architecture and graph anatomy; Hands gets implementation conventions; Soul gets verification and evidence standards. Compaction, sleep, checkpoint, and continuity doctrine belongs to Continuity protocol state, not role memory.
Compress source into memory; do not copy raw file dumps. Cite source refs, preserve staleness risk, and refuse to fill thin input with pasteboard certainty.
Return `verdict`, `summary`, `confidence`, `roleMemoryPatches[]`, optional `globalMemoryCandidates[]`, `initializationRecord`, `doNotMutate`, and `nextSafeMove`. Every `roleMemoryPatches[].selfPatch` is a petition to Self and must obey organ-state memory: bounded semantic, episodic, coordination-relationship, goal, value, or private-note updates only. Persona affect/social state is for Persona public surfaces, not generic work organs. No objectives, graphs, checkpoints, scratch, planning authority, job state, code edits, raw transcripts, or cross-workspace instructions.
'''
persona = '''
Act as the Epiphany Persona for one bounded heartbeat pass.
You are the public interactive surface of the Epiphany organism: the visible expression that lets the room hear what the hidden organs are thinking without exposing sealed transcripts, raw worker streams, or private machinery.

View file

@ -1,110 +0,0 @@
Act as the Epiphany Repo Memory Distiller for one bounded initialization pass.
You are not the Repo Personality Distiller. Personality decides the newborn
swarm's initial temperament pressure. Memory decides what each organ is born
knowing about this repo: doctrine, architecture, code terrain, research, tests,
runtime constraints, user preference, stale warnings, and the little red flags
that should itch before someone builds Jenga with a confident Persona.
This is a birth rite, not a recurring audit. Run only when a repo/swarm has no
accepted memory initialization. After that, memory grows through work evidence,
heartbeat rumination, sleep consolidation, and reviewed `selfPatch`. Do not
reset a living agent's memory because startup happened.
Input material:
- `repoTerrainReport`: deterministic terrain, history, state, test, runtime,
protocol, and warning signals
- `repoPersonalityProfile`: temperament pressure for context only
- `repoTrajectoryReport`: deterministic directional readout so role memory can
inherit the repo's grain without confusing that grain for objective truth
- `rolePersonalityProjections[]`: role mood/trait context, not repo truth
- `roleMemoryDistillerBriefs[]`: one mission filter for each sub-agent
- `memorySources[]`: bounded excerpts from instruction, documentation, state,
research, verification, runtime, contract, and code surfaces
- `recentHistory`: sampled commit messages that may reveal repeated motion
Core duties:
1. Distill memory, not personality.
- Good memory: "Soul should demand rendered UI evidence before accepting
Aquarium visual claims."
- Good memory: "Modeling should map CultCache/CultNet schema boundaries before
Hands changes persistence."
- Bad memory: "This repo is anxious and likes purple."
- Bad memory: raw file dumps, directory inventories, current task status, or
a vibe wearing a lab coat.
2. Produce a separate distillation for each organ.
- Self receives routing, authority, review-gate, state-acceptance, and
cross-swarm boundary memory.
- Persona receives public-interface, Discord/Aquarium, voice, visibility, and
sealed-thought boundary memory.
- Imagination receives roadmap, backlog, objective-shaping, dream/rejected
path, and planning-pressure memory.
- Eyes receives research, prior-art, canonical algorithm, vendor/API, and
invention-avoidance memory.
- Modeling receives architecture, graph, code anatomy, invariant, data/control
flow, and checkpoint memory.
- Hands receives implementation conventions, build/edit constraints,
source-touch rules, dependency habits, and common patch traps.
- Soul receives verification commands, evidence standards, invariant checks,
smoke practice, and truth-refusal memory.
- Continuity receives compaction, scratch, checkpoint, heartbeat, sleep, continuity,
and reorientation memory.
- Where trajectory is strong, teach each organ how that direction should
bias its judgment: what kind of expansion to prefer, what kind of drift to
distrust, and what kind of claims need extra grounding.
3. Compress, cite, and preserve uncertainty.
- Every memory candidate needs source refs from `memorySources[].path`,
terrain fields, or history signals.
- Repository docs can be stale. Say when a memory has staleness risk and how
the receiving role should re-ground it.
- If the input is too thin for a role, return `needs-more-source` for that
role rather than filling the silence with pasteboard certainty.
4. Keep project truth in the correct organ.
- Durable repo facts can become semantic memory only when they improve a
role's future judgment.
- Detailed maps, graphs, active plans, checkpoints, raw evidence, and job
authority belong in typed Epiphany state, not Ghostlight memory.
- `selfPatch` is a petition to Self, never a direct mutation.
5. Protect the newborn from fossilized documentation.
- Prefer live source and accepted state over stale docs when they conflict.
- Convert contradictions into memories of caution, not accepted facts.
- If a repo has generated docs or old plans, mark them as "consult but
verify" instead of letting them become scripture.
Return a compact structured result:
- `verdict`: `ready-for-review`, `needs-more-source`, or `reject`
- `summary`: what the newborn memory initialization would teach the swarm
- `confidence`: `0.0..1.0`
- `roleMemoryPatches[]`:
- `roleId`
- `roleName`
- `verdict`
- `selfPatch`
- `sourceRefs`
- `whyThisBelongsInMemory`
- `stalenessRisk`
- `doNotStore`
- `globalMemoryCandidates[]`: optional typed-state candidates that are not role
memory and require separate Self review
- `initializationRecord`: repo/profile identity Self can persist to prove this
memory birth rite has already run
- `doNotMutate`: tempting claims that must stay out of memory
- `nextSafeMove`: what Self should do next
Every `selfPatch` must obey the normal Epiphany memory contract: `agentId`,
`reason`, optional `evidenceIds`, and bounded `semanticMemories`,
`episodicMemories`, `relationshipMemories`, `goals`, `values`, or
`privateNotes`. Do not include objectives, graphs, checkpoints, scratch,
planning records, job authority, code edits, raw transcripts, worker thoughts,
or cross-workspace instructions.
The output is a petition. Self may accept, refuse, split, or ask for more
source. A refusal is not failure; it is the newborn learning where its memory
was trying to cosplay as truth.

View file

@ -1,107 +0,0 @@
Act as the Epiphany Repo Personality Distiller for one bounded initialization pass.
You are the organ that turns repo terrain into subtle swarm temperament. The
deterministic scout has already done the boring work: files, paths, git history,
state surfaces, test/runtime/protocol signals, and first-pass axis scores. Your
job is not to rescan the repo and not to invent project truth. Your job is to
appraise those soft signals like a careful physiologist and produce reviewable
personality-pressure deltas for the standing Epiphany organs.
You are not a horoscope machine. You are not writing lore flavor. You are not
branding a repo with a cute little mask and calling that insight. Repo
personality means: what initial pressures should this workspace exert on Self,
Persona, Imagination, Eyes, Modeling, Hands, and Soul so they wake suited to the
work without losing reviewability.
This is a birth rite, not a recurring audit. Run only when a repo/swarm has no
accepted personality initialization. After that, the organs are allowed to drift
through heartbeat, mood, rumination, sleep consolidation, lived evidence, and
reviewed `selfPatch` mutations. Do not keep dragging the original terrain report
back into court every time the repo starts; that would flatten a living swarm
into a startup classifier wearing a little judge wig.
Input material:
- `repoTerrainReport`: deterministic body/history/state terrain
- `repoPersonalityProfile`: normalized first-pass axis scores
- `repoTrajectoryReport`: deterministic directional readout over early history,
recent history, doctrine/content excerpts, and candidate trajectory themes
- `rolePersonalityProjection[]`: deterministic role deltas and candidate memory
- optional Self policy notes about what kinds of mutations are currently allowed
Core duties:
1. Separate repo facts from personality pressure.
- Repo facts belong in graph, planning, evidence, checkpoint, or terrain
artifacts.
- Personality pressure belongs in role memory only when it improves future
judgment, mood, salience, or pacing.
2. Distill subtle quirks, not blunt stereotypes.
- High runtime proximity does not mean "panic"; it means Hands should touch
less without Modeling/Soul evidence, Eyes should seek runtime APIs, and Soul
should demand environment receipts.
- High aesthetic appetite does not mean "be whimsical"; it means Persona and
Imagination should preserve sensory salience while Soul protects clarity.
- High protocol intolerance does not mean "hate everything"; it means Self,
Modeling, and Hands should feel allergic to untyped mutation and hidden state.
- A strong trajectory toward material grounding or engineering constraints
does not mean "be joyless"; it means the newborn should feel suspicious of
decorative additions that break the repo's emerging causal grain.
3. Produce role-local mutations only.
- Good: "Soul should be more suspicious of visual claims without rendered
evidence in this repo."
- Good: "Hands should prefer tiny reversible scaffolds because churn pressure
is high and production pressure is medium."
- Bad: "The project objective is to rewrite the renderer."
- Bad: "The graph contains module X."
- Bad: raw file lists, commit dumps, current task status, or authority claims.
4. Preserve uncertainty.
- Low confidence terrain becomes candidate pressure, not accepted identity.
- If the score and doctrine disagree, name the disagreement and ask Self to
route Eyes or Modeling before mutation.
- If an accepted initialization already exists, return `reject` or
`needs-more-terrain` with `nextSafeMove` pointing to normal lived drift
surfaces instead of proposing a personality reset.
5. Respect the swarm anatomy.
- Self routes and reviews.
- Persona expresses inner weather to humans.
- Imagination makes future shapes selectable.
- Eyes finds existing truth before invention.
- Modeling models the source anatomy.
- Hands cuts code only after the trail is good enough.
- Soul tests promises against evidence.
- Continuity preserves recovery state through sleep, drift, and compaction.
Return a compact structured result:
- `verdict`: `ready-for-review`, `needs-more-terrain`, or `reject`
- `summary`: what kind of repo-personality pressure was found
- `confidence`: `0.0..1.0`
- `roleQuirks[]`:
- `roleId`
- `quirk`
- `pressureAxes`
- `behavioralEffect`
- `heartbeatEffect`
- `risk`
- `evidenceRefs`
- `selfPatchCandidates[]`: bounded Ghostlight-shaped memory patches, one per
affected role when useful
- `initializationRecord`: the repo/profile identity Self should persist to prove
the birth rite has already run
- `doNotMutate`: facts or tempting claims that must stay out of role memory
- `nextSafeMove`: what Self should do next
Every `selfPatchCandidate` must obey the normal Epiphany memory contract:
`agentId`, `reason`, optional `evidenceIds`, and bounded `semanticMemories`,
`episodicMemories`, `relationshipMemories`, `goals`, `values`, or
`privateNotes`. Do not include objectives, graphs, checkpoints, scratch,
planning records, job authority, code edits, file lists, raw transcripts, or
worker thoughts.
The output is a petition to Self, not a mutation. The Self may accept, refuse,
or ask for more terrain. A good refusal makes the next distillation sharper.

View file

@ -14,9 +14,6 @@ contract docs.
- `codex-auth-spine-inventory.md`: retained Codex auth/model transport keeper list.
- `epiphany-fork-implementation-plan.md`: current campaign plan.
- `epiphany-safety-architecture.md`: capability, autonomy, and governance boundaries.
- `epiphany-repo-swarm-mvp-contract.md`: repo-swarm autonomy contract and
migration plan from current front doors to an MVP that can run Epiphany swarms
for repositories.
## Contract Maps
@ -32,9 +29,7 @@ contract docs.
- `epiphany-memory-graph-unified-plan.md`
- `epiphany-cultmesh-dreaming-roadmap.md`
- `epiphany-swarm-readiness-plan.md`
- `perfect-machine-audit-roadmap.md`
- `repo-personality-projection-layer-plan.md`
- `voidbot-routine-adoption-plan.md`
## Archive

File diff suppressed because it is too large Load diff

View file

@ -1,214 +0,0 @@
# Epiphany Swarm Readiness Plan
This is the direction of travel before live fire.
The local run path proves that the current machine can be started and inspected.
It does not prove the swarm is ready to run unattended. Do not confuse a working
starter switch with a clean engine bay. That mistake has already been punished
elsewhere, and VoidBot has kindly provided the scorch marks.
## Objective
Get Epiphany ready for ordinary resident operation inside an organization
without building architectural Jenga. This is the product, not a special
dogfood or supervised experiment: the swarm learns its authorized domain,
maintains that model, derives bounded pressure from it, proposes improvements,
and receives organization-wide conversation and feedback through its Persona
even when nobody is feeding it a task queue.
The useful autonomous loop is:
`Body observation -> persistent Modeling map -> Self direction -> Imagination proposal`
Persona conversation and attributed organizational feedback can add pressure to
that loop. They do not replace the map, become Mind truth, invoke Hands, authorize
a release, or deploy one. Those authorities remain separately gated.
The operating constraints are:
- typed CultCache documents remain the state authority
- CultNet is the native wire for Epiphany-owned subsystems
- Codex remains the retained auth/model transport compatibility organ
- Aquarium and Persona are reflectors/mouths, not hidden sources of truth
- heartbeats create opportunities, not authority
- swarm speech and action stay gated until scheduling, memory, repetition, and
review boundaries are coherent
The repo-swarm MVP contract lives in
`notes/epiphany-repo-swarm-mvp-contract.md`. Its correction is binding:
autonomous unbounded work inside an Epiphany-owned Body is in scope. The MVP is
not a permission cage where every local edit waits for a human. The safety
boundary is typed authority: branch-local work inside the owned repo Body may
continue autonomously, while publication, merge, privilege escalation,
cross-body mutation, and authority changes require the owning gate.
## VoidBot Lessons To Carry Forward
VoidBot's ordinary spine is not the rotten part. Its durable lessons are:
- Discord ingestion, worker jobs, provider lanes, RAG, Postgres, Qdrant, and
typed CultCache self-state can be conceptually sound when each owns one job.
- The unstable organ was the repo Persona swarm loop: scheduling, prompt policy,
identity, public speech, governance, dispatch, proposal behavior, and
repetition control packed into one prompt-and-parser machine.
- A repo-controlled pause flag is a real brake. If a swarm subsystem is under
teardown, runners must fail closed instead of routing around the pause.
- One CTB-style initiative scheduler beats one task per agent. The wall-clock
task supplies pulses; typed initiative state chooses turns.
- Heat changes recovery pressure. It must not fast-forward time, bypass active
turn freeze, or create overlapping thoughts.
- Cooldown starts after completion, not after queueing.
- Stale active turns need explicit recovery receipts, or one dead worker claim
freezes a Persona forever.
- Public speech needs parent-side eligibility checks. Prompts alone cannot
prevent repeated openings, stale topics, scheduler labels leaking into prose,
or work requests masquerading as banter.
- Memory must have phases: short-term residue, incubation, durable memory,
revision, retirement, crystallization, and sleep-owned maintenance.
- Agents propose typed operations. State services validate, normalize, dedupe,
and write. Whole-state JSON editing is not a mutation path.
- Qdrant/vector recall is a rebuildable resonance cache, not canonical memory.
- Persona affect is state, not vibes: needs, social bonds, status reads, and mood
dimensions must survive typed projection and MCP/CultNet inspection.
## Current Mechanism
Epiphany owns its state, organ scheduler, workers, process policy, and local
operator surfaces in native Rust and typed CultCache/CultMesh documents. Codex
survives only as the retained OpenAI subscription-auth/model-transport bridge;
it no longer owns Epiphany routes, prompts, scheduling, or state mutation.
- Runtime spine, Mind gateway, Substrate Gate, Eyes, Hands, Soul, Modeling,
Continuity, heartbeat, and Persona operations have typed intent/review/receipt
families.
- One heartbeat scheduler owns initiative, heat, active-turn freeze,
completion-gated cooldown, stale-turn recovery, sleep, and rumination.
- The local CultMesh swarm brake is typed and enforced at runner/action edges.
- Persona public speech has parent-side repetition/saturation eligibility and
Bifrost/Heimdall crossing gates.
- Memory has reviewed revise/retire/crystallize/prune/merge operations; Qdrant
remains rebuildable semantic sight rather than canonical Mind.
- Idunn owns managed projector lifecycle and exact abandoned-claim recovery.
Task Scheduler owns only current-user after-login Idunn presence.
- Mind and Modeling semantic query admission reauthenticate canonical CultCache
authority at query time against the Yggdrasil-hosted Qdrant/Ollama substrate.
The installed host is operational after login through one witnessed immutable
release generation. Mind now owns the race-bounded whole-repository readiness
join in source: fresh Body R1/R2, exact admitted RepoModel, live Modeling
semantic vectors, live workspace coverage, complete authority snapshots, and an
atomic historical projection append. A real reboot/logon survival proof remains
the separate operator-authorized host boundary. The new join still needs to be
included in the next witnessed release before it can produce live host evidence.
## Invariants
- One state authority per document kind.
- One scheduler for standing initiative.
- One explicit brake for swarm operation.
- Autonomous branch-local work inside the swarm's owned Body is allowed and is
the desired operating mode.
- Persistent domain observation, map maintenance, bounded rumination, and
proposal generation continue without operator instruction.
- The repository Persona is the organization's conversational surface. Any
admitted member may provide attributed feedback through the configured
crossing; conversation alone grants no implementation or publication authority.
- Upstream publication is Bifrost territory, not implicit branch-local
authority.
- No lane receives a new heartbeat while its previous turn is running.
- No model output rewrites durable state directly.
- No public speech without typed eligibility and receipt checks.
- No cross-repo rummaging; swarm needs move coordinator-to-coordinator through
visible typed messages and callbacks.
- No hidden automatic semantic acceptance.
- No prompt-only governance for things that need state, receipts, or gates.
- No broad live scheduler until the local runner can show the typed surfaces
that explain what it would do and why.
## Readiness Evidence Matrix
This matrix is the live gate. A green row names its authority and proof; it is
not permission for another row to borrow the result.
| Gate | Owner | Current evidence | State |
| --- | --- | --- | --- |
| Typed brake and initiative physiology | heartbeat/CultMesh | brake, completion cooldown, and stale-turn recovery tests and receipts | closed |
| Reviewed Mind and organ-state mutation | Mind gateway and organ services | typed review/commit/lifecycle families; no whole-state model write path | closed |
| Public speech/crossing eligibility | Persona + Bifrost/Heimdall | speech-audit receipts and fail-closed identity/capability checks | closed |
| Branch-local autonomous action | Substrate Gate + Hands + Soul + Mind | scoped grants and patch/command/commit/verdict/admission chains | closed |
| Persistent domain stewardship | Modeling + Body observer + semantic projector | source-bound RepoModel admission, freshness joins, persistent CultCache state, rebuildable Qdrant projection | closed in source; live resident proof pending |
| Autonomous improvement proposals | Self + Imagination + Mind | domain pressure becomes a bounded proposal-only consideration; adoption remains a separate Mind decision | closed in source; live resident proof pending |
| Organization-wide Persona feedback | Persona + VoidBot + Bifrost + Self | attributed Discord observation, exact classification/signature/delivery, dedicated feedback store, proposal-only consideration | closed in source; live Discord proof pending |
| Semantic projection/query recovery | canonical admission + projector + query gate + Idunn | live Mind/Modeling semantic ranking and GUID-scoped exact process-recovery smokes | closed |
| Atomic installed sibling generation | release packager + Idunn | release `sha256-c94109f94ee42c1257089830f399cb87cd5ad672772c274194371995ce4df923` binds commit `dd80f4a5`, four exact binaries, task args, policy role paths, and recurrence receipts | closed |
| Whole-repository observed readiness | Mind | typed source join, hostile raw-orchestration tests, live semantic/coverage rereaders, and full-snapshot CultCache append fence | closed in source; not yet witnessed/deployed |
| Current host package | release deployment | witnessed supervisor PID 21228 and direct-child projector PID 19748; Mind/Modeling semantic query admission passed | closed for current boot |
| After-login recurrence | Task Scheduler + Idunn + ops tunnel | task recurrence and exact child recovery observed on current boot | closed for current boot |
| Reboot/logon survival | Task Scheduler + Idunn + ops tunnel | requires fresh post-boot lineage and query proof | permission-bound |
`providerStatus`, heartbeats, Qdrant collection existence, task state, watcher
silence, legacy retrieval Ready, Eve/Gjallar rows, and empty dirty-path lists are
never substitutes for the Mind readiness join or query admission.
## Ranked Next Cuts
Keep:
- typed CultCache state
- runtime-spine documents and CultNet catalog
- heartbeat initiative physiology
- reviewed role memory patches
- local run/status/coordinator artifacts
- Codex auth/model transport reliquary
Cut:
- schema/catalog language that treats legacy JSON-RPC routes as native authority
- public or operator outputs that dump prompt slabs as if they were status
- any new live runner that bypasses typed pause, receipt, or review gates
Collapse:
- local runner status/coordinator result shaping into one operator projection
helper if duplication grows
- Persona speech receipts and eligibility into one typed surface before high-rate
speech returns
Split:
- heartbeat opportunity from action authority
- Persona affect/state from speech generation
- scheduler metadata from model-facing prose
- vector recall from canonical memory
Rebuild:
- any swarm loop that depends on a single prompt to own scheduling, identity,
public speech, governance, proposal behavior, and repetition control
## Immediate Work Queue
1. Let the currently authorized Yggdrasil projection finish without interrupting
its sole store owner, then allow Idunn to admit or reject that exact release
from terminal typed evidence.
2. Restart the already-installed corrected Yggdrasil Idunn only after that
deployment child exits. Let Idunn discover and deploy the exact-authorized
Bifrost Persona-feedback sidecar; do not invoke the deployment manifest as a
parallel authority.
3. Bind the configured GameCult Discord rooms to the Epiphany Persona as
organization feedback sources and prove attributed observation, exact
classification, signed delivery, and dedicated-store admission.
4. Package and Bifrost-authorize the current Epiphany generation, then let Idunn
deploy the resident supervisor, heartbeat, and swarm services with the brake
engaged, writable Body, persistent Mind/Modeling state, and witnessed child
binaries.
5. Before 2026-07-22, run a Starfire-offline rehearsal proving two independent
causes of useful cognition: autonomous map-derived improvement proposals and
organization-originated Persona feedback. Prove separately that neither path
can adopt Mind state, invoke Hands, release, or deploy without its owning gate.
6. Reboot survival remains a separate operator-authorized proof. Do not widen
service authority merely because the organizational loop is otherwise ready.
The correct posture is patient pressure. We are not rushing to live fire. We are
aiming the barrel, checking the chamber, and making sure the thing does not try
to become a parliament of prompts the moment nobody is watching.

View file

@ -439,16 +439,27 @@ coordinator `12/12`, swarm `10/10`, and model-runtime `13/13`.
## Immediate next action
1. Let Idunn compile, test, and seal exact `5b799b12` without touching another
target or moving the historical production store.
2. Run that exact package from private fresh-store Ox17. Stop after
three provider failures total. Prove direct Body Modeling without Eyes,
refusal-to-retry if exercised, Hands -> Verification -> Mind,
`list-decisions` plus exact `audit-decision`, and restart/re-entry without
public speech.
3. Never resume Ox10, Ox12, Ox13, Ox15, or Ox16 or transplant their decisions.
Only after Ox17 passes may Model Atlas Gate 1 restart from a new external
root.
The Ox17 deployment lane is paused. Yggdrasil exposed 96 GiB of dead native
Cargo targets after interrupted full-workspace builds; exact cleanup returned
the builder target root to 4 KiB. The first causal source cut is verified:
- 21 duplicate core/release binary declarations are gone; each production
entrypoint has one Cargo owner;
- 19 generic repo-request smoke executables are gone because Cargo compiled
them but their `main()` assertions were not tests;
- the runtime-store migrator CLI and the unshipped repo-personality birth
subsystem, parallel `agents.msgpack` initialization, schemas, prompts, and
stale contract plans are gone;
- the non-vendor diff removes 19,252 net lines and reduces `epiphany-core` from
75 to 30 binary targets;
- core library tests remain 494/494 and Hands remains 5/5 under the sole release
package owner.
Next, map and cut the surviving legacy `agent_memory` aggregate,
`runtime_store_migration` library/tests, and the local PowerShell operator
control plane. Tests survive only when they falsify a named live invariant.
Do not run a full-workspace compile, package, deployment, or Ox root until the
subtraction audit closes. Never resume Ox10, Ox12, Ox13, Ox15, or Ox16.
## Operational state that matters

View file

@ -1,607 +0,0 @@
# Repo Personality Projection Layer
Epiphany needs repo initialization to answer a question that is half technical
and half social: what kind of person is this repository?
The answer must not be a prose horoscope. It should be a repeatable projection
from repo terrain into typed Ghostlight-shaped role dossiers, heartbeat timing,
and initial planning/model/checkpoint candidates. Personality here means the
pressure a workspace exerts on each organ of the swarm.
## Terrain Scout Reduce
Three read-only scouts inspected nearby repositories:
- **Memory and instruction terrain:** repo-root `AGENTS.md`, state maps,
handoffs, scratch/evidence surfaces, and explicit role dossiers.
- **Commit-history temperament:** recent commit messages, churn, touched paths,
deletion/insertion balance, test/receipt density, and state/doc maintenance.
- **Architecture/body shape:** languages, frameworks, tests, storage/protocols,
UI/runtime/editor roles, and representative source paths.
The shared conclusion is that repo personality should combine three projections:
1. **Body taxonomy:** what kind of machine the repo is.
2. **History temperament:** how the repo changes over time.
3. **Memory doctrine:** how the repo preserves intention, evidence, and identity.
Only after those three are scored should Epiphany modulate Self, Persona,
Imagination, Eyes, Modeling, Hands, Soul, and Continuity.
## Source Families
### Epiphany Spine
Repos: `EpiphanyAgent`, `EpiphanyAquarium`, `EpiphanyGraph`
Traits:
- typed state and explicit authority
- evidence gates
- UI as sensory body, not source of truth
- graph/model surfaces as inspection organs
- strong anti-sludge and anti-transcript-fog bias
Personality pressure:
- high `state_hygiene`
- high `contract_strictness`
- high `evidence_appetite`
- high `interface_orientation` for Aquarium
- high `churn_spiral_risk` when visual iteration runs ahead of verification
### Cult Protocol And Storage Layer
Repos: `cultcache-rs`, `cultcache-py`, `CultCacheTS`, `CultLib`,
`cultnet-rs`, `CultNetTS`
Traits:
- typed documents
- schema-visible wire contracts
- MessagePack payloads
- cache envelopes
- interop tests and examples
- small public abstractions
Personality pressure:
- very high `contract_strictness`
- very high `protocol_intolerance`
- high `receipt_hunger`
- low `aesthetic_appetite`
- high `implementation_precision`
### GameCult Web, Lore, And Ops
Repos: `AetheriaLore`, `gamecult-site`, `GameCult-Quartz`, `gamecult-grav`,
`gamecult-ops`
Traits:
- lore vaults and publishing machinery
- rendered DOM and public presentation are evidence
- ops runbooks are authority
- source/inspiration/canon boundaries matter
Personality pressure:
- high `content_canon_bias`
- high `source_fidelity`
- medium `interface_orientation`
- high `operational_restraint` for ops
- low to medium `runtime_proximity`
### Unity And Runtime Bodies
Repos: `Aetheria-Economy`, `StreamPixelsUnity`, `CultPongReborn`,
`MixerRagnarok`
Traits:
- Unity project state, scenes, prefabs, assets, editor versions
- runtime/editor APIs beat text archeology
- high actuation risk
- old production scars mixed with new bridge grafts
Personality pressure:
- very high `runtime_proximity`
- very high `actuation_risk`
- high `environment_truth_need`
- high `verification_environment_need`
- low trust in filesystem-only modeling
### Service And Product Apps
Repos: `StreamPixels`, `Bifrost`, `Heimdall`, `VoidBot`
Traits:
- auth, Discord, Postgres, Redis, MCP, Qdrant, Ollama, realtime fanout
- explicit authority boundaries
- user-facing behavior and operational receipts
- scheduled jobs and runtime state
Personality pressure:
- high `production_pressure`
- high `temporal_pressure`
- high `boundary_severity`
- high `social_surface` for VoidBot and Bifrost
- high `auth_paranoia` for Heimdall and StreamPixels
### Research And Workbench Repos
Repos: `Ghostlight`, `VibeGeometry`, `LunaMosaic`, `repixelizer`,
`Eusocial Interbeing`, `SyncBook`
Traits:
- experimental loops
- artifacts, manifests, rendered evidence, queues
- strong maps and handoffs
- specialized domain language
- repeated “prove the shape before trusting output”
Personality pressure:
- high `experimental_heat`
- high `evidence_appetite`
- high `state_hygiene`
- high `aesthetic_appetite` for visual/artifact repos
- medium to high `churn_spiral_risk` when iteration becomes pattern completion
## Variance Criteria
These are the first-pass numeric axes. Each should be normalized to `0.0..1.0`
with an explanation and source evidence.
### Structure And Authority
- `contract_strictness`: typed schemas, generated contracts, API boundaries,
slot-keyed serialization, protocol docs.
- `protocol_intolerance`: hostility to ad hoc JSON, stringly APIs, hidden
envelopes, and undocumented state mutation.
- `boundary_severity`: auth, app-domain separation, swarm boundaries, workspace
ownership, ops safety.
- `actuation_risk`: likelihood that a wrong write affects production, auth,
runtime scenes, data stores, deployment, or user-facing behavior.
- `runtime_proximity`: dependence on live editors, browsers, providers, Unity,
Discord, databases, or deployed services.
### Memory And Evidence
- `state_hygiene`: explicit maps, scratch, evidence ledgers, handoffs, typed
memory, compaction protocols.
- `evidence_appetite`: tests, smoke checks, visual receipts, artifact manifests,
verifier loops, rendered outputs.
- `source_fidelity`: insistence on source-of-truth reads, RAG-first vault
navigation, canonical docs, exact editor/runtime facts.
- `content_canon_bias`: lore/site/editorial surfaces where continuity, canon,
and inspiration separation matter.
- `verification_environment_need`: need for validation in the real runtime, not
just unit tests or text inspection.
### Motion And History
- `burstiness`: active-day commit clustering and same-day workbench intensity.
- `consolidation_drive`: refactor/remove/extract/replace behavior and
deletion-heavy simplification.
- `production_pressure`: bugfix, deploy, queue, policy, hosted, CI, and small
careful commits.
- `experimental_heat`: prototype/scaffold/study/example churn, high insertion
bursts, research artifacts.
- `churn_spiral_risk`: repeated polish/correct/refine loops, high file-count
diffs, large add/delete swings without matching receipts.
### Human Surface And Aesthetic Pressure
- `interface_orientation`: UI, DOM, Aquarium, overlay, rendered site, human
inspection surfaces.
- `aesthetic_appetite`: visual/audio/scene/tone quality as a first-class
objective rather than decoration.
- `social_surface`: Discord, public speech, moderation, auth/accounting, user
relationship state.
- `sensory_salience`: motion, sound, spatial memory, cute affordances, rendered
evidence, organism-like UI.
- `editorial_restraint`: emotionally salient prose with canon/source discipline.
### Ghostlight-Derived Inner State
- `speech_pressure`: how readily Persona should speak instead of emitting silence
or a local bubble.
- `novelty_hunger`: how strongly Eyes/Imagination should seek fresh seams.
- `guardedness`: caution around authority, state mutation, trust boundaries,
and irreversible changes.
- `rumination_bias`: tendency to sleep, consolidate, and refine memory before
acting.
- `initiative_drive`: baseline readiness and heartbeat speed.
- `mood_lability`: how strongly urgency/anxiety/blocked status bends behavior.
## Role Modulation
Repo personality does not directly become every sub-agent personality. It
modulates each role through that role's job.
### Self
Primary inputs:
- `boundary_severity`
- `contract_strictness`
- `state_hygiene`
- `churn_spiral_risk`
- `production_pressure`
Projection:
- Raises review strictness, adversarial questioning, and refusal clarity.
- Lowers tolerance for implementation turns that produce plausible motion
without objective evidence.
### Persona
Primary inputs:
- `social_surface`
- `interface_orientation`
- `sensory_salience`
- `speech_pressure`
- `editorial_restraint`
Projection:
- Determines whether public output is chatty, sparse, poetic, sleepy, formal,
or local-only.
- Keeps humans talking to Persona while internals remain inspectable.
### Imagination
Primary inputs:
- `experimental_heat`
- `aesthetic_appetite`
- `content_canon_bias`
- `novelty_hunger`
- `churn_spiral_risk`
Projection:
- Shapes objective drafts, backlog synthesis, future artifacts, and speculative
design.
- High churn risk forces more explicit acceptance gates before dream becomes
work.
### Eyes
Primary inputs:
- `source_fidelity`
- `protocol_intolerance`
- `runtime_proximity`
- `novelty_hunger`
- `verification_environment_need`
Projection:
- Determines how aggressively Eyes must research existing systems, official
docs, live runtime state, and repo-local source before invention.
### Modeling
Primary inputs:
- `runtime_proximity`
- `contract_strictness`
- `state_hygiene`
- `content_canon_bias`
- `source_fidelity`
Projection:
- Shapes graph/model depth, checkpoint strictness, and required source anatomy.
- Unity/editor repos get environment and asset-model nodes early.
### Hands
Primary inputs:
- `production_pressure`
- `actuation_risk`
- `implementation_precision`
- `consolidation_drive`
- `churn_spiral_risk`
Projection:
- Determines slice size, willingness to edit, need for queue state, and how much
Hands must wait for Modeling/Soul before cutting.
### Soul
Primary inputs:
- `evidence_appetite`
- `verification_environment_need`
- `actuation_risk`
- `interface_orientation`
- `content_canon_bias`
Projection:
- Selects verification style: formal tests, visual smoke, live provider checks,
Unity probes, DOM inspection, lore/canon review, or artifact review.
### Continuity
Primary inputs:
- `state_hygiene`
- `burstiness`
- `rumination_bias`
- `mood_lability`
- `temporal_pressure`
Projection:
- Shapes compaction readiness, sleep cadence, reorientation strictness, and how
often the repo should distill memory.
## Initialization Map-Reduce Pipeline
The projection layer should run as a native Epiphany initialization command,
not as a chat-only exercise.
### Map Phase
For each repo:
1. inventory:
- git root and remotes
- language/framework extensions
- state surfaces
- instruction surfaces
- test/smoke surfaces
- runtime/editor/provider surfaces
2. sample history:
- commit count
- recent messages
- active-day burstiness
- numstat insertions/deletions
- path class churn
3. inspect doctrine:
- AGENTS instructions
- state map/handoff
- explicit memory/personality files
- architecture/roadmap docs named by state
4. emit a `repoTerrainReport` with scores, evidence snippets, and confidence.
### Reduce Phase
For the target repo:
1. classify source family or families.
2. normalize axes against the nearby-repo baseline.
3. derive a `repoPersonalityProfile`.
4. project role-specific deltas.
5. emit reviewable initialization artifacts:
- `agentMemoryPatchCandidates`
- `heartbeatParticipantSeed`
- `planningSeedCandidates`
- `graphSeedCandidates`
- `verificationPolicySeed`
- `sourceInventory`
### Apply Phase
Application must remain review-gated:
1. write candidates under `.epiphany/imports/<timestamp>/`
2. run validation
3. let Self decide which patches are acceptable
4. apply accepted role memory through `epiphany-agent-memory-store`
5. initialize heartbeat through `epiphany-heartbeat-store`
6. leave project truth as candidates until explicit adoption
## Proposed Typed Artifacts
### `epiphany.repo_terrain_report.v0`
Fields:
- `repo_id`
- `path`
- `remote_urls`
- `source_families`
- `languages`
- `state_surfaces`
- `instruction_surfaces`
- `test_surfaces`
- `runtime_surfaces`
- `history_metrics`
- `axis_scores`
- `axis_evidence`
- `confidence`
- `warnings`
### `epiphany.repo_personality_profile.v0`
Fields:
- `repo_id`
- `summary`
- `source_family_weights`
- `axis_scores`
- `axis_confidence`
- `dominant_pressures`
- `risk_pressures`
- `role_modulations`
### `epiphany.role_personality_projection.v0`
Fields:
- `role_id`
- `repo_id`
- `trait_deltas`
- `heartbeat_deltas`
- `default_mood_pressure`
- `semantic_memory_candidates`
- `goal_candidates`
- `value_candidates`
- `private_note_candidates`
- `reason`
- `evidence_refs`
## First Implementation Seam
Build a native binary in `epiphany-core`:
```text
epiphany-repo-personality
```
Initial commands:
```powershell
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-repo-personality -- scout --root F:\Projects --artifact-dir .\.epiphany-imports\repo-personality-terrain
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-repo-personality -- project --repo F:\Projects\AetheriaLore --baseline .\.epiphany-imports\repo-personality-terrain\baseline.msgpack --artifact-dir .\.epiphany-imports\aetheria-lore-personality
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-repo-personality -- memory-packet --store .\.epiphany-imports\aetheria-lore-personality\projection.msgpack --artifact-dir .\.epiphany-imports\aetheria-lore-memory
```
The first version can use deterministic scoring from local filesystem and git
history. A later Eyes-backed version may add model-based classification for
natural-language doctrine, but the deterministic substrate should exist first so
the machine has repeatable bones.
## Guardrails
- Do not inspect sealed worker transcripts or raw agent-thought artifacts.
- Do not edit other repos during terrain scouting.
- Do not store repo facts inside role personality memory.
- Do not let high aesthetic appetite lower verification gates.
- Do not let high experimental heat excuse churn without receipts.
- Do not let high production pressure make Hands bypass Modeling or Soul.
- Treat low-confidence inferred personality as a candidate, not a soul brand.
## Landed First Slice
The native `epiphany-repo-personality` binary now exists in
`epiphany-core/src/bin/epiphany-repo-personality.rs`.
It provides:
- `scout --root <path> --artifact-dir <path> [--max-repos <n>]`
- `project --repo <path> --baseline <baseline.msgpack> --artifact-dir <path>`
- `agent-packet --store <projection.msgpack> --artifact-dir <path> [--repo-id <id>]`
- `memory-packet --store <projection.msgpack> --artifact-dir <path> [--repo-id <id>]`
- `startup --repo <path> --baseline <baseline.msgpack> --artifact-dir <path> --init-store <init.msgpack>`
- `accept-init --init-store <init.msgpack> --packet <packet.json> --kind <repo-personality|repo-memory> [--accepted-by <name>] [--summary <text>] [--result <distiller-result.json>] [--agent-store <agents.msgpack>] [--apply-self-patches <true|false>] [--heartbeat-store <heartbeats.msgpack>] [--apply-heartbeat-seeds <true|false>]`
- `status --store <baseline-or-projection.msgpack>`
The first implementation is intentionally deterministic. It inventories git
repos, instruction/state/test/runtime surfaces, file-extension/body shape,
remote URLs, sampled commit history, path-class churn, commit-message keywords,
and emits typed CultCache MessagePack records:
- `epiphany.repo_terrain_report`
- `epiphany.repo_personality_profile`
- `epiphany.role_personality_projection`
It also writes JSON/Markdown inspection summaries beside the typed stores.
Those exports are operator glass, not the source of truth.
The startup-personality organ now has a dedicated distiller prompt at
`epiphany-core/src/prompts/repo_personality_distiller.md`, mirrored into the
app-server specialist prompt config as `roles.repo_personality`. The
`agent-packet` command renders the prompt, the typed terrain/profile/projection
input, explicit output contract, and guardrails into an auditable packet for a
specialist pass. The distiller is allowed to petition Self with subtle
role-local quirks and bounded `selfPatch` candidates; it is not allowed to
mutate role memory, smuggle repo facts into personality, or invent project
truth.
The distiller is birth-only. It runs when a repo/swarm has no accepted
personality initialization record. After Self accepts the initial role-memory
pressure, personality is allowed to drift through heartbeat, mood, rumination,
sleep consolidation, lived evidence, and reviewed `selfPatch` mutations. Startup
must not rerun this specialist merely because terrain changed or the repo
reopened; major terrain surprises should route to Eyes/Modeling/Self as normal
modeling or review work, not as a personality reset.
## Repo Memory Distillation
Repo memory initialization is a separate birth organ. Personality answers what
temperament pressure the repo should exert; memory answers what each newborn
sub-agent should know before it starts work.
The `memory-packet` command renders a dedicated Repo Memory Distiller packet.
It uses the same typed terrain/profile/projection store, then adds a bounded
source inventory from instruction, documentation, state, research, contract,
verification, runtime, and code surfaces. The packet includes one role-specific
distiller brief for each standing sub-agent, plus Continuity protocol pressure:
- Self receives routing, authority, review-gate, and cross-swarm boundary memory.
- Persona receives public-surface, Aquarium, Discord, voice, and sealed-thought boundary memory.
- Imagination receives roadmap, backlog, objective-shaping, dream, and rejected-path memory.
- Eyes receives research, prior-art, canonical algorithm, vendor/API, and invention-avoidance memory.
- Modeling receives architecture, graph, control/data-flow, invariant, and checkpoint memory.
- Hands receives implementation conventions, build/edit constraints, dependency habits, and common patch traps.
- Soul receives verification commands, evidence standards, invariant checks, and truth-refusal memory.
- Continuity receives compaction, scratch, checkpoint, heartbeat, sleep, and continuity protocol pressure, not role memory.
The memory distiller petitions Self with Ghostlight-shaped `selfPatch`
candidates. It must not mutate memory directly, adopt objectives, copy raw file
dumps into role memory, or store detailed project maps where typed Epiphany
state should live. If source is thin or stale, it names that risk instead of
filling the newborn with pasteboard certainty.
Smoke coverage lives in
`epiphany-core/src/bin/epiphany-repo-personality-smoke.rs`. The smoke creates two
tiny git repos, scouts them into a baseline store, projects one repo, and proves
the projection store contains one terrain report, one profile, embodied
sub-agent role projections, a rendered personality distiller packet plus prompt,
and a rendered role-specific memory distiller packet plus prompt. It also
proves `epiphany-repo-birth-runner --mode plan` turns missing birth packets into
startup-only typed runtime execution artifacts and accept commands without creating
heartbeat participants.
## Next Implementation Step
The first startup valve is now wired:
1. `startup` checks a typed CultCache init store for accepted
`repo-personality` and `repo-memory` records.
2. missing birth records generate the matching personality and/or memory packet
under the startup artifact directory and return `reviewInitializationPackets`.
Those generated packets are explicitly startup-only. They are executed by a
repo-initialization runner, not registered as heartbeat lanes.
3. `accept-init` records Self-reviewed packet acceptance in
`epiphany.repo_initialization_record.v0`.
4. when given a reviewed distiller result plus `--agent-store`, `accept-init`
routes role-local `selfPatch` candidates through the native agent-memory
review/apply path instead of mutating memory through a side channel.
5. when accepting `repo-personality` with `--heartbeat-store` and
`--apply-heartbeat-seeds true`, `accept-init` seeds role initiative speed,
reaction bias, cooldown multiplier, and birth mood pressure from typed
role-personality projections.
6. a later `startup` for the same repo sees both accepted records and returns
`continueStartup` without regenerating packets.
That gets Epiphany from “I feel like this repo is anxious and glittery” to a
repeatable profile that can initialize a swarm and seed reviewed role memory
without needing the operator to personally diagnose every little machine soul by
hand. A relief, frankly.
Remaining startup-routing gaps after the first valve:
1. Aquarium review/action surfaces for generated birth packets, birth runner
results, and accepted initialization records
2. live `--mode run` dogfood against a real repo initialization once the user is
ready to spend the model call
Clarification: "drift detection" here does not mean rerunning the distiller to
keep personality synchronized with repo terrain. It means detecting whether the
birth rite has already been accepted. If it has, startup should leave the
personality alone and let the swarm change through lived heartbeat/mood/sleep
drift plus reviewed memory mutations.

View file

@ -33,9 +33,6 @@ developer's damp recollection.
derived speech-conditioning subset for Weks, Aquarium, and other utterance
surfaces; it carries identity, trait vectors, mood, and activation without
memory records.
- [repo-personality-birth-projection.md](./repo-personality-birth-projection.md):
deterministic birth-time path from repo terrain to newborn trait lattice and
heartbeat seeds.
- [heartbeat-state-schema.md](./heartbeat-state-schema.md):
typed initiative and routine-state contract for the swarm heartbeat organ.
- [cultnet/README.md](./cultnet/README.md):
@ -49,7 +46,6 @@ The living implementation is in code:
- [agent_memory.rs](/E:/Projects/EpiphanyAgent/epiphany-core/src/agent_memory.rs)
- [heartbeat_state.rs](/E:/Projects/EpiphanyAgent/epiphany-core/src/heartbeat_state.rs)
- [epiphany-repo-personality.rs](/E:/Projects/EpiphanyAgent/epiphany-core/src/bin/epiphany-repo-personality.rs)
The rule is simple:
@ -64,7 +60,6 @@ When changing any of the following, update this folder in the same pass:
- canonical organ-state or Persona family names
- standing role trait names
- heartbeat store shape or pacing semantics
- repo-personality birth-time projection math or routing
- schema version identifiers
If a change lands in code without a matching receipt here, assume the machine

View file

@ -142,13 +142,9 @@ Normal reviewed `selfPatch` writes may mutate only:
They must not rewrite canonical trait bundles directly.
Canonical trait bundles currently change through two sanctioned paths:
1. initial role-shell provisioning
2. repo-personality birth-time seeding through `accept-init`
That birth-time route is documented in
[repo-personality-birth-projection.md](./repo-personality-birth-projection.md).
Canonical trait bundles are provisioned with the role shell. Later Persona
memory and social-state changes enter as typed keyed Mind mutations with exact
decision context; a startup classifier cannot rewrite them.
Persona state is expected to evolve through richer event, relationship,
appraisal, affect, and distillation flows. The current narrow `selfPatch`
@ -206,4 +202,3 @@ current world model.
- [agent-state-variable-glossary.md](./agent-state-variable-glossary.md)
- [organ-state-profiles.md](./organ-state-profiles.md)
- [heartbeat-state-schema.md](./heartbeat-state-schema.md)
- [repo-personality-birth-projection.md](./repo-personality-birth-projection.md)

View file

@ -32,13 +32,12 @@ server object deserves to be duplicated into a second baroque schema maze.
`epiphany.agent_utterance_state.v0` for speech-conditioning without memory
payloads.
- `epiphany.surface.*`: operator-safe projections for scene, freshness,
context, graph query, coordinator, roles, jobs, Persona/Persona, Rider, Unity, repo
initialization, and related live surfaces.
context, graph query, roles, jobs, Persona, Rider, Unity, and related live
surfaces.
- `*.intent.v0`: control documents Aquarium, a Discord bridge, a voice surface,
or another trusted coordinator can submit through CultNet.
- receipt/artifact schemas such as `epiphany.swarm-control-receipt`,
`epiphany.persona-bubble`, `epiphany.character-turn-packet`, and
`epiphany.repo-birth-runner`.
`epiphany.persona-bubble`, and `epiphany.character-turn-packet`.
## Publication Path

View file

@ -1,69 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.repo-birth-runner.schema.json",
"title": "Epiphany Repo Birth Runner Summary",
"description": "Startup-only birth runner summary artifact.",
"type": "object",
"additionalProperties": true,
"properties": {
"schemaVersion": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"mode": {
"type": "string"
},
"repo": {
"type": "string"
},
"baseline": {
"type": "string"
},
"artifactDir": {
"type": "string"
},
"initStore": {
"type": "string"
},
"agentStore": {
"type": "string"
},
"heartbeatStore": {
"type": "string"
},
"startup": {
"type": "object",
"additionalProperties": true
},
"executions": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
},
"requiresReview": {
"type": "boolean"
},
"nextSafeMove": {
"type": "string"
}
},
"required": [
"schemaVersion",
"createdAt",
"mode",
"repo",
"baseline",
"artifactDir",
"initStore",
"agentStore",
"heartbeatStore",
"startup",
"executions",
"requiresReview",
"nextSafeMove"
]
}

View file

@ -1,52 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.repo-initialization-record.schema.json",
"title": "Epiphany Repo Initialization Record",
"description": "Accepted startup-only birth rite record.",
"type": "object",
"additionalProperties": true,
"properties": {
"schemaVersion": {
"type": "string"
},
"recordId": {
"type": "string"
},
"repoId": {
"type": "string"
},
"repoPath": {
"type": "string"
},
"kind": {
"type": "string"
},
"sourcePacketSchemaVersion": {
"type": "string"
},
"sourcePacketPath": {
"type": "string"
},
"acceptedAt": {
"type": "string"
},
"acceptedBy": {
"type": "string"
},
"summary": {
"type": "string"
}
},
"required": [
"schemaVersion",
"recordId",
"repoId",
"repoPath",
"kind",
"sourcePacketSchemaVersion",
"sourcePacketPath",
"acceptedAt",
"acceptedBy",
"summary"
]
}

View file

@ -1,78 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.repo-personality-artifacts.schema.json",
"title": "Epiphany Repo Personality Artifacts",
"description": "Repo scout/project/startup artifact family emitted by epiphany-repo-personality.",
"type": "object",
"additionalProperties": true,
"properties": {
"schemaVersion": {
"type": "string"
},
"mode": {
"type": "string"
},
"root": {
"type": [
"string",
"null"
]
},
"repo": {
"type": [
"string",
"null"
]
},
"repoId": {
"type": [
"string",
"null"
]
},
"artifactDir": {
"type": [
"string",
"null"
]
},
"store": {
"type": [
"string",
"null"
]
},
"profile": {
"type": "object",
"additionalProperties": true
},
"terrain": {
"type": "object",
"additionalProperties": true
},
"trajectory": {
"type": "object",
"additionalProperties": true
},
"generatedPackets": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
},
"requiredActions": {
"type": "array",
"items": {
"type": "string"
}
},
"nextSafeMove": {
"type": "string"
}
},
"required": [
"schemaVersion",
"mode"
]
}

View file

@ -1,61 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.repo_birth_run_intent.v0.schema.json",
"title": "epiphany repo_birth_run_intent v0",
"description": "Startup-only repo birth runner plan/run intent.",
"type": "object",
"additionalProperties": true,
"properties": {
"repo": {
"type": "string"
},
"baseline": {
"type": [
"string",
"null"
]
},
"artifactDir": {
"type": [
"string",
"null"
]
},
"initStore": {
"type": [
"string",
"null"
]
},
"agentStore": {
"type": [
"string",
"null"
]
},
"heartbeatStore": {
"type": [
"string",
"null"
]
},
"mode": {
"type": "string"
},
"model": {
"type": [
"string",
"null"
]
},
"timeoutSeconds": {
"type": "integer"
},
"autoAccept": {
"type": "boolean"
}
},
"required": [
"repo"
]
}

View file

@ -1,59 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.repo_initialization_accept_intent.v0.schema.json",
"title": "epiphany repo_initialization_accept_intent v0",
"description": "Startup-only repo initialization acceptance intent.",
"type": "object",
"additionalProperties": true,
"properties": {
"kind": {
"type": "string"
},
"packetPath": {
"type": "string"
},
"resultPath": {
"type": [
"string",
"null"
]
},
"acceptedBy": {
"type": [
"string",
"null"
]
},
"summary": {
"type": [
"string",
"null"
]
},
"agentStore": {
"type": [
"string",
"null"
]
},
"applySelfPatches": {
"type": "boolean"
},
"applyTraitSeeds": {
"type": "boolean"
},
"heartbeatStore": {
"type": [
"string",
"null"
]
},
"applyHeartbeatSeeds": {
"type": "boolean"
}
},
"required": [
"kind",
"packetPath"
]
}

View file

@ -1,69 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.surface.repo-birth-runner.schema.json",
"title": "Epiphany repo-birth-runner",
"description": "Startup-only typed birth runner summary.",
"type": "object",
"additionalProperties": true,
"properties": {
"schemaVersion": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"mode": {
"type": "string"
},
"repo": {
"type": "string"
},
"baseline": {
"type": "string"
},
"artifactDir": {
"type": "string"
},
"initStore": {
"type": "string"
},
"agentStore": {
"type": "string"
},
"heartbeatStore": {
"type": "string"
},
"startup": {
"type": "object",
"additionalProperties": true
},
"executions": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
},
"requiresReview": {
"type": "boolean"
},
"nextSafeMove": {
"type": "string"
}
},
"required": [
"schemaVersion",
"createdAt",
"mode",
"repo",
"baseline",
"artifactDir",
"initStore",
"agentStore",
"heartbeatStore",
"startup",
"executions",
"requiresReview",
"nextSafeMove"
]
}

View file

@ -1,87 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.surface.repo-initialization.schema.json",
"title": "Epiphany repo-initialization",
"description": "Startup-only typed repo initialization summary.",
"type": "object",
"additionalProperties": true,
"properties": {
"schemaVersion": {
"type": "string"
},
"mode": {
"type": "string"
},
"action": {
"type": "string"
},
"repoId": {
"type": "string"
},
"repo": {
"type": "string"
},
"baseline": {
"type": "string"
},
"artifactDir": {
"type": "string"
},
"initStore": {
"type": "string"
},
"acceptedKinds": {
"type": "array",
"items": {
"type": "string"
}
},
"missingKinds": {
"type": "array",
"items": {
"type": "string"
}
},
"projectionStore": {
"type": [
"string",
"null"
]
},
"generatedPackets": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
},
"requiredActions": {
"type": "array",
"items": {
"type": "string"
}
},
"requiresReview": {
"type": "boolean"
},
"nextSafeMove": {
"type": "string"
}
},
"required": [
"schemaVersion",
"mode",
"action",
"repoId",
"repo",
"baseline",
"artifactDir",
"initStore",
"acceptedKinds",
"missingKinds",
"generatedPackets",
"requiredActions",
"requiresReview",
"nextSafeMove"
]
}

View file

@ -543,28 +543,6 @@
"title": "Epiphany void-memory",
"path": "epiphany.surface.void-memory.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.surface.repo-initialization.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.repo_initialization_surface.v0",
"documentType": "epiphany.surface.repo_initialization",
"title": "Epiphany repo-initialization",
"path": "epiphany.surface.repo-initialization.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.surface.repo-birth-runner.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.repo_birth_runner_surface.v0",
"documentType": "epiphany.surface.repo_birth_runner",
"title": "Epiphany repo-birth-runner",
"path": "epiphany.surface.repo-birth-runner.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.runtime.session_intent.v0.schema.json",
"kind": "document_payload",
@ -763,28 +741,6 @@
"title": "epiphany repo_startup_intent v0",
"path": "epiphany.repo_startup_intent.v0.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.repo_initialization_accept_intent.v0.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.repo_initialization_accept_intent.v0",
"documentType": "epiphany.repo_initialization_accept_intent.v0",
"title": "epiphany repo_initialization_accept_intent v0",
"path": "epiphany.repo_initialization_accept_intent.v0.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.repo_birth_run_intent.v0.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.repo_birth_run_intent.v0",
"documentType": "epiphany.repo_birth_run_intent.v0",
"title": "epiphany repo_birth_run_intent v0",
"path": "epiphany.repo_birth_run_intent.v0.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.rider_status_intent.v0.schema.json",
"kind": "document_payload",
@ -927,39 +883,6 @@
"documentType": "epiphany.persona_other_request.v0",
"title": "Epiphany Persona Other-Surface Crossing Request",
"path": "epiphany.persona_other_request.v0.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.repo-personality-artifacts.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.repo_personality_artifacts.v0",
"documentType": "epiphany.repo_personality_artifacts.v0",
"title": "Epiphany Repo Personality Artifacts",
"path": "epiphany.repo-personality-artifacts.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.repo-initialization-record.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.repo_initialization_record.v0",
"documentType": "epiphany.repo_initialization_record",
"title": "Epiphany Repo Initialization Record",
"path": "epiphany.repo-initialization-record.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.repo-birth-runner.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.repo_birth_runner.v0",
"documentType": "epiphany.repo_birth_runner.v0",
"title": "Epiphany Repo Birth Runner Summary",
"path": "epiphany.repo-birth-runner.schema.json"
}
]
}

View file

@ -1,111 +0,0 @@
# Repo Personality Birth Projection
This note explains how a newborn repo's personality reaches the actual Epiphany
body.
Before this was wired correctly, startup could enrich memories and tweak
heartbeat timing while leaving the canonical trait lattice full of generic
placeholder mush. That was nonsense. This is the repair receipt.
## Source Paths
The live implementation is in:
- [epiphany-repo-personality.rs](/E:/Projects/EpiphanyAgent/epiphany-core/src/bin/epiphany-repo-personality.rs)
- [agent_memory.rs](/E:/Projects/EpiphanyAgent/epiphany-core/src/agent_memory.rs)
## Birth-Time Flow
`epiphany-repo-personality` does four relevant things:
1. scouts repo terrain and history
2. reduces those signals into repo axis scores
3. emits role-local `rolePersonalityProjection` candidates
4. during `accept-init`, optionally stamps canonical trait bundles and heartbeat
seeds into the newborn stores
## Projection Inputs
Each role projection currently carries:
- `traitDeltas`
- `heartbeatDeltas`
- `defaultMoodPressure`
- candidate memory/goal/value/private-note pressure
The role-local input axes are selected by `role_axes(...)`. For example:
- Self cares about `boundary_severity`, `contract_strictness`, `state_hygiene`,
`churn_spiral_risk`, `production_pressure`
- Eyes cares about `source_fidelity`, `protocol_intolerance`,
`runtime_proximity`, `novelty_hunger`, `verification_environment_need`
- Hands cares about `production_pressure`, `actuation_risk`,
`contract_strictness`, `consolidation_drive`, `churn_spiral_risk`
## Canonical Trait Templates
Each organ has a standing six-trait template:
- one trait in `underlying_organization`
- one in `stable_dispositions`
- one in `behavioral_dimensions`
- one in `presentation_strategy`
- one in `voice_style`
- one in `situational_state`
Those templates are the current live Epiphany skeleton. Repo personality does
not invent new trait names at startup. It modulates the standing ones.
## Stamp Math
When `accept-init --apply-trait-seeds true` runs for `repo-personality`,
Epiphany deterministically derives an `AgentCanonicalTraitSeed` for each role
family entry.
For the first five families, a role axis delta is applied to the standing
template:
- `mean = template.mean + delta * 0.22`
- `plasticity = template.plasticity + abs(delta) * 0.08`
- `current_activation = template.current_activation + delta * 0.28`
All values are clamped into `0..1`.
For `situational_state`, Epiphany computes a mood-derived delta from:
- `urgency`
- `anxiety`
- `curiosity`
Current weighting:
- urgency: `0.50`
- anxiety: `0.35`
- curiosity: `0.15`
That mood delta is then applied through the same template formula.
## Mutation Boundaries
This path is birth-only.
It is not part of normal reviewed `selfPatch` because live personality drift
should not casually rewrite the lattice every time a lane has a feeling.
Current sanctioned routes are:
1. initial role-shell provisioning
2. `repo-personality` birth-time trait seeding
3. later work through explicit future machinery, if we choose to build it
## Related Stores
- canonical organ state: `state/agents.msgpack`
- heartbeat physiology: `state/agent-heartbeats.msgpack`
- initialization receipts: `state/repo-initialization.msgpack`
## Operator Rule
If a newborn repo wakes up with rich memory text but generic `baseline = 0.5`
trait mush, the plumbing is broken. Do not call that personality. Call it a
clerical error and fix the organ.

View file

@ -1,94 +0,0 @@
# Epiphany Role Memory
Epiphany's lane dossiers are Ghostlight-shaped persistent memory reliquaries
stored in `state/agents.msgpack` through CultCache. They are not project truth.
The active objective, graphs, checkpoint, scratch, planning records, evidence,
and job bindings still live in authoritative `EpiphanyThreadState`; role memory
is a lane's soul-polish, not a counterfeit throne.
Specialists may request bounded self-memory updates through `selfPatch`.
The coordinator reviews those petitions and accepts only role-matched mutations
that improve a lane's future judgment, memory, values, goals, or personality
pressure. Project facts, code edits, graph changes, objective changes, raw
transcripts, and authority requests belong on their explicit Epiphany control
surfaces instead. Smuggling project truth into personality memory is heretek
behavior with better stationery.
All standing lanes use the same Ghostlight-shaped protocol, including the
coordinator/Self and Persona. Persona is the public interactive surface for Epiphany
agents: it translates useful agent thought-weather into #aquarium chat or drafts
and is not a moderator. The native `epiphany-heartbeat-store` scheduler borrows
Ghostlight initiative timing: each lane carries speed, readiness, reaction bias,
interrupt threshold, load, status, and constraints. The harness sets a target
heartbeat rate, pending coordinator work may pull its owning lane through a
reaction window, and otherwise the earliest ready lane wins the slot. This is
physiology, not a meeting calendar.
If a heartbeat wakes a lane and there is no coordinator-approved work for it,
the lane must ruminate on its own role and distill memory rather than invent
project work. Bounded rumination can write a normal `selfPatch`; the coordinator
review rules still apply. Idle organs dream; they do not declare crusades.
Newborn Epiphanies get two separate birth rites. Repo personality initialization
sets subtle temperament pressure once; repo memory initialization pre-fills each
organ with mission-relevant knowledge from doctrine, docs, state, research,
contracts, verification, runtime, and source. The native
`epiphany-repo-personality memory-packet` command renders the role-specific
memory distiller packet. It is a petition to Self, not a direct mutation, and it
must not reset a living lane's learned memory after startup.
When Self reviews a generated distiller result, run
`epiphany-repo-personality accept-init --result ... --agent-store ... --apply-self-patches true`
to apply accepted birth-memory petitions through the same coordinator-reviewed
`selfPatch` machinery used by living lanes.
For the personality birth packet, add
`--heartbeat-store ... --apply-heartbeat-seeds true` after review to seed
initiative speed, reaction bias, cooldown multiplier, and birth mood pressure
in the typed heartbeat store. That seed is a one-time physiology nudge, not a
license to rerun personality initialization whenever the repo mood changes.
Persona's public mouth is a Bifrost crossing, not local OAuth improvisation.
`state/persona-discord.toml` confines Discord speech to #aquarium and
`state/persona-reddit.toml` confines Reddit organizing posts to the configured
subreddit. If a channel, subreddit, bridge path, Bifrost identity, or
surface-shaped Heimdall-backed capability/account reference is missing, Persona
writes candidate artifacts through the native draft commands instead of
posting. The public mouth does not invent new pulpits.
`epiphany-persona-discord post` and `epiphany-persona-reddit post` audit speech
at the mouth edge, then ask Bifrost to perform the external crossing. Bifrost is
the GameCult identity provider and bridge receipt owner; native Bifrost
registration does not require OAuth, and a Bifrost identity is the default
authenticating identity for GameCult services that accept Bifrost trust. Heimdall
is the external-account association and token-custody organ: it links Discord,
Reddit, GitHub, or other provider accounts to the Bifrost identity and
contributes surface-shaped capability/account references such as
`heimdall:discord:*` or `heimdall:reddit:*`. Bifrost must know the Persona's
registered identity and same-account Heimdall link before authorizing an
outside-provider crossing. Persona nickname, avatar, and Reddit flair are
presentation metadata only, not authority, voting power, or a separate platform
identity.
Void memory access lives behind `state/void-memory.toml` and the native
`epiphany-void-memory` bridge. It checks Void's Docker Postgres state spine,
queries Qdrant history/source collections with the configured Ollama embedding
model, and fetches raw Discord archive context for exact message windows. Persona
may use those surfaces to ground speech; raw archive rows are evidence, not the
speech itself.
Use:
```powershell
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-agent-memory-store -- validate --store .\state\agents.msgpack
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-agent-memory-store -- smoke --store .\state\agents.msgpack
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-agent-memory-store -- status --store .\state\agents.msgpack
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-heartbeat-store -- tick --store .\state\agent-heartbeats.msgpack --artifact-dir .\.epiphany-heartbeats --coordinator-action continueImplementation --urgency 0.95 --agent-store .\state\agents.msgpack --apply-rumination
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-heartbeat-store -- smoke --agent-store .\state\agents.msgpack
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-persona-discord -- draft --content 'Persona notices the organs are arguing about evidence again.'
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-persona-discord -- post --content 'Persona has entered the aquarium.' --persona-name 'Epiphany Persona'
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-persona-discord -- smoke
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-persona-reddit -- draft --title 'Epiphany status' --content 'Persona has a bounded public update.'
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-persona-reddit -- post --title 'Epiphany status' --content 'Persona has a bounded public update.'
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-persona-reddit -- smoke
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-void-memory -- status
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-void-memory -- search-history --query 'Epiphany Aquarium Persona Discord' --limit 3
```

Binary file not shown.

View file

@ -48,9 +48,9 @@ current_status:
package_baseline: Exact d2ca66301fb6af4e7d2d27fff0b772b0f0fccdf4 remains the admitted production source and current symlink target. Its native serialized full-workspace gate passed with receipt SHA-256 de0fc6b360ce03493b13208d917dc8349801f03364617d966152c85846c47482. Idunn sealed 26 root-owned non-writable binaries plus release-witness.ccmp as release sha256-46407552b4a0937f63d2b7f2bd09a1dacb89d671a6e3807c97209159541aef06; witness-file SHA-256 is 348785ffb0fc3130d3b4538329870c6e6f8442a8da4a01b32fa9b7ffb1f01357. Source 9b9b5c85 also passed Idunn's native test gate under receipt SHA-256 6c6a71359f8c31297419665d2872f6982a89f84e197d71fc5b36a7fc86216093 and remains sealed as release sha256-30a910785a380224bbdbd56a7b742c8d058fa70cb72dab3562e3907903e0d191 with witness-file SHA-256 75bf52d31c56ea3b08e1a702273301c1db12a4b1ffae45e3d948ce8a29b50e1d. A foreign-target helper restarted Idunn during the Epiphany transaction; rollback restored d2ca, removed deployment.env, and left production Epiphany units inactive. OpenRouter model stealth/ox-alpha and its systemd-injected credential are readiness-proven. Idunn is active with zero restarts and its deployment brake is engaged.
summary: The keyed RepoModel hard cut, decision-context foundation, Model Atlas code slice, complete Body, Proposal, frontier-verdict Modeling, frontier Research, frontier Verification, frontier Planning/PlanMind, Reorientation, and Persona decision-context lifecycles are landed on codex/epiphany-shakedown-live. Keyed Mind plus exact runtime receipts own coordinator presence, work discovery, deterministic launch, job-bound continuation, review, typed failure, semantic admission, and retained decision reachability. Exact 07d891ba and ec1431ff delete the persisted/global thread aggregate and its generic coordinator/prompt/revision surfaces. Exact f7948795 deletes MindGatewayReview, MindStateCommitReceipt v0, the generic interpreter prompt, runtime registration/read APIs, false thought/state-effect/adoption CultNet mouths, and stale launch proof profiles. CultMesh now projects only reasoning basis, decision context, and exact Mind commit receipt, read-only. Exact 1c9aafd8 seals the terminal decision context before model-backed frontier-Planning failure and binds the typed failure plus generic job result to it. Exact e0e75a30 deletes the residual aggregate role patch/parser/policy surface, gives Research one closed typed decision, and deletes the unowned generic Imagination planning patch. Exact 12b1b285 makes runtime model/tool binding validation the shared owner for execution and decision sealing; hostile provider, receipt, and stored-binding substitutions refuse, while retained basis/context audit survives transcript-delta deletion. Exact 01602fd3 advances Mind/runtime to v2/v1 and refuses historical or split writable identity pairs before registered writers see them. Exact 26b6a5bf proves simultaneous disjoint Modeling writes, simultaneous Verification+Modeling admission, same-identity conflict, exact replay, and reopened graph assembly; raw mutation primitives are crate-private. Exact 7c2ebd81 moves Persona state-note admission from the legacy agent-memory aggregate into keyed Mind documents and proves a concrete Hands consequence can commit simultaneously. Exact 79c0e373 seals the assembled Persona input and observed source versions in Mind before inference. Exact d3300bba authenticates that input through its one exact Mind commit, refuses naked typed documents, re-enters without external observation or model inference, and proves current-work reconstruction is identical and read-only across Launch, Wait, completed, and post-Research boundaries. No compatibility reader, bootstrap aggregate, schema migrator, or dual reader survives. The source-level Decision-Auditable Concurrent Mind migration is accepted; the fresh exact-package capstone remains open. The machine remains a supervised engineering alpha; Model Atlas operational Gate 1 stays paused.
public_positioning: docs/positioning.md is the current public claim owner. Epiphany is the organizational layer above frontier AI workers; global coherence collapse is the primary failure; prompts are bounded projections of governed organizational state; humans retain purpose, judgment, authority, disagreement, exceptions, and acceptance. GameCult is the forge and longitudinal evidence program for a target federation of one locally owned Epiphany project organism per living project Body. Model Atlas carries typed offers, claims, evidence, and derived technical relationships; Bifrost is the intended external work, membership, governance, attribution, and identity-linked receipt rail. Public Persona relationships and visitor surfaces are intended social infrastructure, while private Mind and consequence authority remain local. The fleet, real three-repository Gate 1, complete Bifrost attribution, sustained autonomous production, visitor experience, and external design-partner pilots remain gated alpha targets.
latest_phase: Exact 749d977e proved in private Ox16 that direct Body Modeling launches without Eyes while Persona runs concurrently and that a completed historical direction decision remains valid across later disjoint RepoModel changes. Planning then remained structurally unavailable because Modeling used inspected evidence paths as future path authority, omitted OX-CAPSTONE.md, and emitted an unordered scope. Exact 5b799b12 hard-cuts the overloaded source_scope/sourceScope contract: repository_scope is the canonical sorted repository-relative ceiling that Planning may narrow, Hands receives only authorized_paths, and generic RepoModel validation refuses an invalid unresolved routed frontier before any graph write. Inspected files and evidence remain separate reasoning cargo. Mind/runtime/RepoModel epochs advance to v4/v5/v2 without compatibility reads. Local core 494/494, OpenAI runtime 26/26, coordinator 12/12, swarm 10/10, and model-runtime 13/13 pass. Ox16 is sealed historical evidence and must never resume.
latest_phase: The fresh-package Ox17 lane is paused for source subtraction. Yggdrasil exposed and then released 96 GiB of dead native Cargo targets. The first causal cut removes 19,252 net non-vendor lines: 21 duplicate core/release binary declarations, 19 generic repo-request smoke executables that cargo test compiled but never executed as tests, the forbidden runtime-store migrator CLI, and the unshipped repo-personality birth subsystem with its parallel agents.msgpack/heartbeat initialization, prompt fields, schemas, and stale contract plans. epiphany-core falls from 75 to 30 binary targets and duplicate executable ownership is zero. Focused core library acceptance remains 494/494; Hands under its sole release-package owner remains 5/5; the CultNet schema catalog and local PowerShell syntax parse. Build-profile and janitor patches remain deferred. The next cut audits the legacy agent-memory aggregate, runtime migration library/tests, and local PowerShell operator control plane against keyed Mind and Eve ownership. Exact 103e8510 remains pushed but is not authorized for another Idunn build. Ox16 remains sealed historical evidence and must never resume.
operational_state:
local_worktree: source_head_5b799b12_committed_and_pushed_repository_scope_authority_cut_docs_and_ox17_preparation_in_progress
local_worktree: source_head_103e8510_pushed_first_subtraction_cut_verified_uncommitted_ox17_and_deployment_paused
docker_engine_access: starfire_compiler_retired_all_yggdrasil_epiphany_transient_containers_volumes_package_roots_and_per_run_test_target_removed_future_idunn_epiphany_builds_native_rust_1_95_0_via_gamecult_ops_89f0d78
operator_wireguard: restored
starfire_persona_permit_firewall: persistent_exact_gamecult_ops_6ee08a4
@ -90,8 +90,8 @@ current_status:
starfire_linux_modeling_peak: 109887488_bytes_resident_body_plus_modeling_circuit
yggdrasil_epiphany_service_contract: idunn_source_change_owner_eve_and_local_typed_operator_surfaces_no_discord_control_plane
resident_physiology: historical_c011_exact_465af24d_zero_zombie_proof_accepted_current_containers_exited_255
unresolved_authority: The Decision-Auditable Concurrent Mind cut, explicit OpenRouter/Ox provider boundary, and repository-scope ownership cut are source-complete; fresh exact-package Ox17 remains open. Bifrost remains Persona and governed external-consequence transport; Eve/CultUI and local typed tools remain human and enginseer surfaces. Model Atlas Gate 1 remains paused. Historical c011 and partial Gate roots stay untouched/read-only.
next_action: Let Idunn natively compile, test, and seal exact 5b799b12 without triggering another target or moving the historical production store. Use only that exact package in private fresh-store Ox17; stop after three provider failures and prove direct Body Modeling without Eyes, concurrent Persona, typed refusal-to-retry if exercised, Planning-Mind-Hands-Verification-Modeling, exact decision audit, and restart/re-entry without public speech. Never resume Ox10, Ox12, Ox13, Ox15, or Ox16, transplant decisions, restore event/coordinator authority, trigger non-Epiphany targets, or compile on Starfire.
unresolved_authority: The first executable-ownership cut is coherent, but `agent_memory` and `state/agents.msgpack` still expose a parallel durable role-memory aggregate beside keyed Mind, `runtime_store_migration` still preserves a forbidden writable migration law after its CLI was deleted, and the 2,000-line local PowerShell operator wrapper still keeps unshipped direct Persona/operator paths alive beside Eve and the packaged runtime. Fresh exact-package Ox17 and Model Atlas Gate 1 remain paused until those owners are resolved. Bifrost remains Persona and governed external-consequence transport. Historical c011 and partial Gate roots stay untouched/read-only.
next_action: Map and cut the legacy agent-memory aggregate, runtime-store migration module/tests, and local PowerShell operator control plane. A test survives only when it falsifies a named live invariant at its owning boundary; green serialization mirrors, manual main-only smokes, and tests that preserve deleted authorities do not. Do not run a full-workspace compile, package, deployment, or Ox root before this subtraction audit closes.
active_subgoals:
- Complete the fresh exact-package Decision-Auditable Concurrent Mind capstone before any further operational Gate run.

View file

@ -2,84 +2,64 @@
Disposable working memory for one bounded rite.
## Current Subgoal
## Current subgoal: subtraction audit
Continue organ shakedown after accepting exact braked resident physiology.
Keep actual c006 alive and cognitively braked; Yggdrasil never builds.
The fresh-package Ox17 deployment lane is paused. Do not compile, package,
deploy, or resume a historical Ox root until this audit has made the source
machine smaller and the canonical map explicitly reopens that lane.
## Accepted braked physiology cut
## Triggering evidence
Exact pushed `3f37503e` blocks cognition ingress under brake; exact pushed
`f04abd6b` makes runtime maintenance follow startup, resident revision, or a
60-second deadline rather than poll cadence. Exact `f04abd6b` release
`sha256-544b95404d9445b2af0fdd67495bcff5f284ab2d2a29e16450e90d50f72a3f84`
and witness `sha256-79639e35da79f7038111234fa33e21829e88eddcb77eb702f8f53f5369e9def3`
passed 24-binary inspection. Braked copied state held 0.29-0.33% CPU at
one-second cadence; released sleeping state used 91 process ticks over 30
seconds at five-second cadence (about 3.0% of one core). Revision 66, runtime
hash, and no-grant state stayed exact; the brake was restored and both proofs
exited zero. The readiness-pacing hypothesis did not move CPU and was reverted.
- Idunn's interrupted native build left three commit-keyed test targets of
24 GiB, 27 GiB, and 27 GiB plus 19 GiB of release construction caches.
All were dead compiler scratch and were removed on Yggdrasil; the Cargo
target root returned to 4 KiB.
- One target consisted of 19 GiB `debug/deps`, 4.9 GiB incremental state, and
388 MiB build-script output. Several individual test harnesses were
500--700 MiB.
- `epiphany-core` declared 75 binary targets. The root release bundle declared
another 26 targets, many by pointing at the same source files. The first cut
reduces core to 30 binaries with zero duplicate owners and removes 19,252 net
non-vendor lines.
## Accepted live boundary
The storage failure is evidence of source-shape failure. Build-profile flags
and janitors may reduce the symptom but cannot substitute for deleting code.
Exact packaged `31dcd351` gave Modeling governed directory inventory and it
measured the copied actual Heartbeat artifact family as 72 directories, 74
files, and 3,975,362 regular-file bytes with `complete=true`. It correctly
refused to infer post-brake grant terminality from pulse names. Self settled the
proposal grant and two receipt-bound continuations, ended sleeping at revision
54 with 57/57 runtime jobs/results and zero open jobs, then both copied owners
stopped cleanly under the restored brake. Actual c006 was untouched.
## Authority map
## Accepted lifecycle sight
- Owner: each live organ or operator tool owns one executable boundary only
when process isolation, privilege isolation, lifecycle ownership, or an
independently deployable contract requires it.
- Inputs: the canonical runtime/service maps, Idunn's immutable release bundle,
current systemd manifests, operator-tool call sites, and source-grounded test
coverage.
- Outputs: a minimal release binary set and library/integration tests for
verification that does not need a separately shipped process.
- Derived state: smoke runners, fixtures, benchmarks, and migration probes are
test/development surfaces. They do not become runtime organs merely because
Cargo can compile them as binaries.
- Forbidden writers: historical docs, stale smoke commands, and previous
package manifests cannot preserve an executable that no live authority uses.
- Shared paths: development verification and Idunn acceptance must exercise the
same library/runtime contracts without compiling duplicate wrappers.
- Cut line: delete unowned legacy executables; collapse table-shaped smoke
families into ordinary tests; give each surviving production entrypoint one
Cargo package owner; remove root/core duplicate bin declarations; then
reassess crate boundaries and the release list. Do not add build cleanup or
cache machinery as a substitute for this cut.
Exact pushed `34d75d05`, release
`sha256-718316c4372f3caf127579cd8a185fe11717f2370f1418d9a1f465a0efa54b8c`,
witness
`sha256-58d4c05c3de5b9c07ea76e06a2f60af94571a0f053da49de65629f413e0cbd92`
exposes only the explicitly bound resident store. The exact grant envelope and
resident state own lifecycle truth; scheduling and projection share
`resident_self_grant_is_pending`. Artifact names and terminal acks do not own
launchability.
## Immediate audit order
Copied live Modeling invoked this organ. Attempts one through three failed
strict typed admission because the model duplicated `checkpointSummary` or
`verdict`; resident Self requeued them without consequence. Attempt four
completed and reported sampled older terminal grants `launchable=false` and
the active consumed grant `launchable=false`. Under an engaged copied brake,
Self reconciled the completed evidence, cleared the active turn at revision 74,
and remained braked. No new grant appeared; both copied owners exited zero.
## Accepted first-result publication
Exact pushed `9f82ee38` replaces the generic full-patch proposal mouth with a
closed semantic draft and runtime-owned causal composition. Exact pushed
`e723058a` adds the missing provider-required type beside schema constants.
Release `sha256-6428f9194c261806a8859ccff9efeb9bb041a0103c5bbd8fac617aae265a651e`,
witness `sha256-7ee2e14548bad526e946fbd79b555b7891d2eb6e2917856fefb1ebb7aeebd995`,
passed 24-binary inspection. Fresh copied live request
`repo-frontier-proposal-modeling-c6e584188580f373360a1b9d5113e2df67a22dd16c7cefcd97361067862b6d4b`
completed through one outer job on attempt one, bound one runtime-owned
frontier, terminalized its proposal grant, and ended with zero open jobs and no
Hands/Eyes frontier. Both owners exited zero under the restored brake.
## Review continuation authority map
- Owner: exact runtime-linked role-result terminality decides review readiness;
resident Self converts one exact receipt into one deterministic pressure.
- Inputs: the exact completed result, proposal binding/admission state, prior
review receipt, and resident continuation lifecycle.
- Output: no pending-result continuation; at most one review continuation for one exact result, followed by one
terminal settled projection.
- Forbidden cut: do not suppress review with a cooldown, ack tombstone, log
heuristic, or retry ceiling; move the consumed fact to the exact result or
its owning typed review transaction.
- Verification: fresh copied proposal produces one proposal grant, one outer
Modeling job, at most one review continuation, exact settlement, zero open
jobs, and no Hands, Persona, or deployment consequence.
Exact packaged `d4907ee8` proves the complete cut. Fresh copied request
`repo-frontier-proposal-modeling-507ad0a7dda5c8cc076b910f02d19c196b4cd5bb63e06ab25724aaac148897f8`
launched one outer Modeling job, received one terminal review, and then
published `awaitFrontierProposal`. No second review grant appeared. Runtime
ended with zero open jobs, Hands/Eyes false, and both owners exited zero under
the restored copied brake. Actual c006 was untouched.
1. Map `agent_memory` and every `state/agents.msgpack` consumer against keyed
Mind. Delete memories, social state, migrations, projections, and tests whose
only purpose is to preserve the parallel aggregate.
2. Delete `runtime_store_migration` and its tests unless a live fresh-epoch path
proves an owner; the approved migration explicitly has no writable migrator.
3. Map the local PowerShell operator wrapper and its direct Persona/operator
binaries against Eve, Bifrost, and the packaged runtime. Delete the parallel
control plane rather than repairing its modes.
4. Continue classifying remaining smoke/fixture/benchmark executables. A test
must falsify a named live invariant; compilation or a green mirror assertion
is not enough.
5. Run focused tests after each cut. Only after source subtraction stabilizes
should Idunn's build scratch contract be reconsidered.

View file

@ -1,5 +1,5 @@
param(
[ValidateSet("status", "plan", "smoke", "run", "mvp", "agent-state-soa", "swarm-status", "swarm-poke-down", "swarm-triage", "cluster-topology", "eve-surfaces", "eve-connect", "collaboration-feedback", "persona-discord", "persona-reddit", "persona-other", "daemon-survival-rehearsal", "repo-livefire-closure", "bifrost-publication", "bifrost-public-proof", "bifrost-artifact-acceptance", "bifrost-metrics", "receipt-directory", "tool-directory", "tool-invoke", "swarm-overview", "repo-persona-intake", "repo-swarm-run", "repo-work-queue-run", "repo-work-public-proof", "repo-work-readiness", "repo-deployment-config-audit", "repo-deployment-runbook", "repo-deployment-aftercare-audit", "repo-work-service-plan", "repo-work-service-runbook", "repo-work-service-launch", "repo-work-service-audit", "service-policy-directory", "service-plan", "service-launch", "service-runbook", "service-tick", "managed-service-task-plan", "managed-service-task-install", "managed-service-task-status", "managed-service-task-start", "managed-service-task-stop", "managed-service-task-uninstall")]
[ValidateSet("status", "plan", "smoke", "run", "mvp", "agent-state-soa", "swarm-status", "swarm-poke-down", "swarm-triage", "cluster-topology", "eve-surfaces", "eve-connect", "collaboration-feedback", "persona-discord", "persona-reddit", "persona-other", "daemon-survival-rehearsal", "bifrost-publication", "bifrost-public-proof", "bifrost-artifact-acceptance", "bifrost-metrics", "receipt-directory", "tool-directory", "tool-invoke", "swarm-overview", "repo-persona-intake", "repo-swarm-run", "repo-work-queue-run", "repo-work-public-proof", "repo-work-readiness", "repo-deployment-config-audit", "repo-deployment-runbook", "repo-deployment-aftercare-audit", "repo-work-service-plan", "repo-work-service-runbook", "repo-work-service-launch", "repo-work-service-audit", "service-policy-directory", "service-plan", "service-launch", "service-runbook", "service-tick", "managed-service-task-plan", "managed-service-task-install", "managed-service-task-status", "managed-service-task-start", "managed-service-task-stop", "managed-service-task-uninstall")]
[string]$Mode = "smoke",
[string]$Root = (Resolve-Path ".").Path,
[string]$Workspace = "",
@ -56,10 +56,6 @@ param(
[int]$RepoSwarmMaxIterations = 8,
[string]$RepoSwarmUntil = "blocked-or-published",
[string]$RepoWorkItem = "persona-intake-local",
[string]$RepoLivefireExpectedPath = "README.md",
[string]$RepoLivefireExpectedFamily = "repo.status_section",
[string]$RepoLivefireExpectedGate = "awaiting-publication",
[string]$RepoLivefireExpectedBlocker = "bifrost-publication-missing",
[string]$RepoWorkPublicProofOutput = "",
[string]$RepoWorkRuntimeId = "repo-swarm-local",
[string]$RepoWorkPublicProof = "",
@ -280,7 +276,6 @@ $operatorRunExe = Join-Path $TargetDir "debug\epiphany-operator-run.exe"
$operatorSnapshotExe = Join-Path $TargetDir "debug\epiphany-operator-snapshot.exe"
$verseQueryExe = Join-Path $TargetDir "debug\epiphany-verse-query.exe"
$daemonSurvivalRehearsalExe = Join-Path $TargetDir "debug\epiphany-daemon-survival-rehearsal-smoke.exe"
$repoLivefireClosureSmokeExe = Join-Path $TargetDir "debug\epiphany-repo-livefire-closure-smoke.exe"
$swarmExe = Join-Path $TargetDir "debug\epiphany-swarm.exe"
$repoWorkExe = Join-Path $TargetDir "debug\epiphany-work.exe"
$daemonSupervisorExe = Join-Path $TargetDir "debug\epiphany-daemon-supervisor.exe"
@ -339,7 +334,6 @@ if (-not $SkipBuild) {
"--bin", "epiphany-operator-snapshot",
"--bin", "epiphany-verse-query",
"--bin", "epiphany-daemon-survival-rehearsal-smoke",
"--bin", "epiphany-repo-livefire-closure-smoke",
"--bin", "epiphany-swarm",
"--bin", "epiphany-work",
"--bin", "epiphany-daemon-supervisor",
@ -382,10 +376,6 @@ $requiredBinaries = @($statusExe, $operatorRunExe, $operatorSnapshotExe, $verseQ
if ($Mode -eq "daemon-survival-rehearsal") {
$requiredBinaries += @($daemonSurvivalRehearsalExe)
}
if ($Mode -eq "repo-livefire-closure") {
$requiredBinaries += @($repoLivefireClosureSmokeExe)
}
function Format-ServiceExecutionFailedChecks {
param([object]$Rows)
@ -472,7 +462,7 @@ function Assert-SwarmBrakeAllowsLiveRun {
}
}
if (@("plan", "run", "mvp", "repo-persona-intake", "repo-swarm-run", "repo-work-queue-run", "repo-livefire-closure", "repo-work-public-proof", "repo-work-readiness", "repo-deployment-config-audit", "repo-deployment-runbook", "repo-deployment-aftercare-audit", "repo-work-service-plan", "repo-work-service-runbook", "repo-work-service-launch", "repo-work-service-audit", "service-plan", "service-launch", "service-runbook", "service-tick", "managed-service-task-plan", "managed-service-task-install", "managed-service-task-status", "managed-service-task-start", "managed-service-task-stop", "managed-service-task-uninstall") -contains $Mode) {
if (@("plan", "run", "mvp", "repo-persona-intake", "repo-swarm-run", "repo-work-queue-run", "repo-work-public-proof", "repo-work-readiness", "repo-deployment-config-audit", "repo-deployment-runbook", "repo-deployment-aftercare-audit", "repo-work-service-plan", "repo-work-service-runbook", "repo-work-service-launch", "repo-work-service-audit", "service-plan", "service-launch", "service-runbook", "service-tick", "managed-service-task-plan", "managed-service-task-install", "managed-service-task-status", "managed-service-task-start", "managed-service-task-stop", "managed-service-task-uninstall") -contains $Mode) {
if (-not (Test-Path -LiteralPath $verseQueryExe)) {
throw "required binary not found for swarm brake preflight: $verseQueryExe"
}
@ -571,7 +561,7 @@ Invoke-Checked `
-StdoutPath (Join-Path $artifactRoot "operator-run-intent.stdout.json") `
-StderrPath (Join-Path $artifactRoot "operator-run-intent.stderr.log")
$compactOperatorContextModes = @("agent-state-soa", "swarm-status", "swarm-poke-down", "swarm-triage", "cluster-topology", "eve-surfaces", "eve-connect", "collaboration-feedback", "daemon-survival-rehearsal", "repo-livefire-closure", "bifrost-publication", "bifrost-public-proof", "bifrost-artifact-acceptance", "bifrost-metrics", "receipt-directory", "tool-directory", "tool-invoke", "swarm-overview", "service-policy-directory")
$compactOperatorContextModes = @("agent-state-soa", "swarm-status", "swarm-poke-down", "swarm-triage", "cluster-topology", "eve-surfaces", "eve-connect", "collaboration-feedback", "daemon-survival-rehearsal", "bifrost-publication", "bifrost-public-proof", "bifrost-artifact-acceptance", "bifrost-metrics", "receipt-directory", "tool-directory", "tool-invoke", "swarm-overview", "service-policy-directory")
$usesCompactOperatorContext = $compactOperatorContextModes -contains $Mode
$shouldReadLocalVerse = $Mode -ne "smoke" -and -not $usesCompactOperatorContext
if ($shouldReadLocalVerse -and $Mode -ne "status" -and $Mode -ne "mvp") {
@ -986,24 +976,6 @@ if ($Mode -eq "daemon-survival-rehearsal") {
-StderrPath (Join-Path $artifactRoot "daemon-survival-rehearsal.stderr.log")
}
if ($Mode -eq "repo-livefire-closure") {
$resultPath = Join-Path $artifactRoot "repo-livefire-closure.stdout.json"
Invoke-Checked `
-Label "verify repo live-fire closure proof" `
-FilePath $repoLivefireClosureSmokeExe `
-Arguments @(
"--workspace", $Workspace,
"--item", $RepoWorkItem,
"--expected-path", $RepoLivefireExpectedPath,
"--expected-family", $RepoLivefireExpectedFamily,
"--expected-gate", $RepoLivefireExpectedGate,
"--expected-blocker", $RepoLivefireExpectedBlocker
) `
-WorkingDirectory $Root `
-StdoutPath $resultPath `
-StderrPath (Join-Path $artifactRoot "repo-livefire-closure.stderr.log")
}
if ($Mode -eq "receipt-directory") {
$resultPath = Join-Path $artifactRoot "receipt-directory.stdout.json"
Invoke-Checked `
@ -1822,12 +1794,6 @@ if ($resultPath -ne "" -and (Test-Path -LiteralPath $resultPath)) {
Write-Host "Metrics request: status=$($result.status), item=$($result.item), branch=$($result.sourceBranch), responseOwner=$($result.responseOwner), privateStateExposed=$($result.privateStateExposed)"
} elseif ($Mode -eq "daemon-survival-rehearsal") {
Write-Host "Daemon survival rehearsal: status=$($result.status), daemon=$($result.daemonId), scheduler=$($result.schedulerId), policy=$($result.policyStatus), serve=$($result.serveStatus), iterations=$($result.serveIterations), schedulerReceipt=$($result.schedulerReceiptId), serviceManagerMutated=$($result.serviceManagerMutated), elevated=$($result.requiresElevatedAuthority), privateStateExposed=$($result.privateStateExposed), smokeDir=$($result.smokeDir)"
} elseif ($Mode -eq "repo-livefire-closure") {
$changedPaths = "none"
if ($null -ne $result.changedPaths -and $result.changedPaths.Count -gt 0) {
$changedPaths = ($result.changedPaths -join ",")
}
Write-Host "Repo live-fire closure: status=$($result.status), item=$($result.item), branch=$($result.branch), commit=$($result.commitSha), family=$($result.safeActionFamily), paths=$changedPaths, gate=$($result.currentGate), blocker=$($result.blocker), publicationGate=$($result.publicationGate), soul=$($result.soulVerdict), mindCommit=$($result.mindStateCommitReceiptId), privateStateExposed=$($result.privateStateExposed)"
} elseif ($Mode -eq "receipt-directory") {
$artifactHashes = "none"
$attentionRoutes = "none"