Add repo work derived plan gate

This commit is contained in:
Meta Vens 2026-06-20 00:39:44 +01:00
commit a2ba319ec4
5 changed files with 313 additions and 47 deletions

View file

@ -55,6 +55,9 @@ fn main() -> Result<()> {
};
let result = match command.as_str() {
"accept" => run_accept(parse_accept_args(args)?),
"derive-plan" | "imagine" | "plan-from-pressure" => {
run_derive_plan(parse_derive_plan_args(args)?)
}
"plan" => run_plan(parse_plan_args(args)?),
"run" => run_work(parse_run_args(args)?),
"adopt" | "promote" => run_adopt(parse_adopt_args(args)?),
@ -115,6 +118,30 @@ struct PlanArgs {
rollback_hints: Vec<String>,
}
#[derive(Clone, Debug)]
struct DerivePlanArgs {
workspace: PathBuf,
item: Option<String>,
accept_receipt: Option<PathBuf>,
artifact_dir: Option<PathBuf>,
target_path: String,
model_ref: Option<String>,
}
#[derive(Clone, Debug)]
struct PlanReceiptInputs {
objective: String,
plan_summary: String,
command: String,
changed_paths: Vec<String>,
commit_message: String,
adoption_evidence_refs: Vec<String>,
verification_asks: Vec<String>,
stop_conditions: Vec<String>,
rollback_hints: Vec<String>,
derivation: Option<Value>,
}
#[derive(Clone, Debug)]
struct AdoptArgs {
workspace: PathBuf,
@ -402,6 +429,40 @@ fn parse_plan_args(args: impl Iterator<Item = String>) -> Result<PlanArgs> {
})
}
fn parse_derive_plan_args(args: impl Iterator<Item = String>) -> Result<DerivePlanArgs> {
let mut workspace = None;
let mut item = None;
let mut accept_receipt = None;
let mut artifact_dir = None;
let mut target_path = "EPIPHANY_WORKLOG.md".to_string();
let mut model_ref = None;
let mut args = args.peekable();
while let Some(arg) = args.next() {
match arg.as_str() {
"--workspace" => workspace = Some(take_path(&mut args, "--workspace")?),
"--item" => item = Some(take_string(&mut args, "--item")?),
"--accept-receipt" => accept_receipt = Some(take_path(&mut args, "--accept-receipt")?),
"--artifact-dir" => artifact_dir = Some(take_path(&mut args, "--artifact-dir")?),
"--target-path" | "--changed-path" | "--path" => {
target_path = take_string(&mut args, "--target-path")?;
}
"--model-ref" | "--imagination-ref" => {
model_ref = Some(take_string(&mut args, "--model-ref")?);
}
other => return Err(anyhow!("unexpected derive-plan argument {other:?}")),
}
}
Ok(DerivePlanArgs {
workspace: workspace.context("missing --workspace")?,
item,
accept_receipt,
artifact_dir,
target_path,
model_ref,
})
}
fn parse_adopt_args(args: impl Iterator<Item = String>) -> Result<AdoptArgs> {
let mut workspace = None;
let mut epiphany_root = None;
@ -1184,17 +1245,145 @@ fn run_plan(args: PlanArgs) -> Result<Value> {
fs::create_dir_all(&artifact_dir)
.with_context(|| format!("failed to create {}", artifact_dir.display()))?;
write_plan_receipt(
workspace,
accept_receipt_path,
&accept_receipt,
artifact_dir,
PlanReceiptInputs {
objective: args.objective,
plan_summary: args.plan_summary,
command: args.command,
changed_paths: args.changed_paths,
commit_message: args.commit_message,
adoption_evidence_refs: args.adoption_evidence_refs,
verification_asks: args.verification_asks,
stop_conditions: args.stop_conditions,
rollback_hints: args.rollback_hints,
derivation: None,
},
)
}
fn run_derive_plan(args: DerivePlanArgs) -> Result<Value> {
let workspace = args
.workspace
.canonicalize()
.with_context(|| format!("failed to resolve {}", args.workspace.display()))?;
ensure_git_repo(&workspace)?;
let accept_receipt_path =
resolve_accept_receipt(&workspace, args.item.as_deref(), args.accept_receipt)?;
let accept_receipt = read_json(&accept_receipt_path)?;
let artifact_dir = args
.artifact_dir
.unwrap_or_else(|| workspace.join(".epiphany").join("work"));
fs::create_dir_all(&artifact_dir)
.with_context(|| format!("failed to create {}", artifact_dir.display()))?;
let item = accept_receipt
.get("item")
.and_then(Value::as_str)
.unwrap_or("work-item")
.to_string();
let summary = accept_receipt
.get("summary")
.and_then(Value::as_str)
.unwrap_or("Accepted repo work item.");
let source = accept_receipt
.get("source")
.and_then(Value::as_str)
.unwrap_or("persona");
let target_path = validate_plan_target_path(&args.target_path)?;
let objective = format!(
"Respond to {source} work item {item}: {}",
compact_line(summary)
);
let plan_summary = format!(
"Imagination derived a safe append-only worklog update from accepted {} pressure.",
source
);
let worklog_line = format!(
"- {} [{}]: {}",
Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
item,
compact_line(summary)
);
let command = format!(
"Add-Content -LiteralPath {} -Value {}",
powershell_single_quoted(&target_path),
powershell_single_quoted(&worklog_line)
);
let mut evidence_refs = vec![format!("accept-receipt:{}", accept_receipt_path.display())];
if let Some(consensus_id) =
string_from_json(&accept_receipt, &["feedback", "consensusReceiptId"])
{
evidence_refs.push(format!("imagination-consensus:{consensus_id}"));
}
if let Some(model_ref) = args.model_ref {
evidence_refs.push(format!("imagination-model:{model_ref}"));
} else {
evidence_refs.push("imagination-derivation:deterministic-append-worklog.v0".to_string());
}
write_plan_receipt(
workspace,
accept_receipt_path,
&accept_receipt,
artifact_dir,
PlanReceiptInputs {
objective,
plan_summary,
command,
changed_paths: vec![target_path],
commit_message: format!("Record repo work item {}", item),
adoption_evidence_refs: evidence_refs,
verification_asks: vec![
"Soul verifies the worklog path changed and the appended line matches the accepted pressure.".to_string(),
],
stop_conditions: vec![
"Stop if the command exits nonzero or changes paths outside the derived plan.".to_string(),
],
rollback_hints: vec![
"Remove the appended worklog line if the pressure was misinterpreted.".to_string(),
],
derivation: Some(json!({
"schemaVersion": "epiphany.repo_work_plan_derivation.v0",
"mode": "append-worklog",
"owner": "Imagination",
"router": "Self",
"inputPressure": {
"source": source,
"summary": summary,
"candidateActionRefs": accept_receipt["feedback"]["candidateActionRefs"],
"publicDiscussionRefs": accept_receipt["feedback"]["publicDiscussionRefs"],
},
"operatorAuthoredShellDetails": false,
"modelAuthored": false,
"deterministicQuarantine": true,
"nextUpgrade": "replace this deterministic derivation with model-authored Imagination planning over the same receipt contract"
})),
},
)
}
fn write_plan_receipt(
workspace: PathBuf,
accept_receipt_path: PathBuf,
accept_receipt: &Value,
artifact_dir: PathBuf,
inputs: PlanReceiptInputs,
) -> Result<Value> {
let item = accept_receipt
.get("item")
.and_then(Value::as_str)
.unwrap_or("work-item")
.to_string();
let item_slug = sanitize(&item);
let normalized_paths = normalize_paths(args.changed_paths.clone());
let normalized_paths = normalize_paths(inputs.changed_paths.clone());
let now = Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
let plan_id = format!("repo-work-plan-{item_slug}");
let action_id = format!("{plan_id}-action-1");
let plan_receipt = json!({
let mut plan_receipt = json!({
"schemaVersion": "epiphany.repo_work_action_plan_receipt.v0",
"createdAt": now,
"workspace": workspace,
@ -1207,18 +1396,18 @@ fn run_plan(args: PlanArgs) -> Result<Value> {
"router": "Self",
"stateGate": "Mind"
},
"objective": args.objective,
"planSummary": args.plan_summary,
"adoptionEvidenceRefs": args.adoption_evidence_refs,
"objective": inputs.objective,
"planSummary": inputs.plan_summary,
"adoptionEvidenceRefs": inputs.adoption_evidence_refs,
"actions": [{
"actionId": action_id,
"kind": "repo.branch_local_command",
"command": args.command,
"command": inputs.command,
"changedPaths": normalized_paths,
"commitMessage": args.commit_message,
"verificationAsks": args.verification_asks,
"stopConditions": args.stop_conditions,
"rollbackHints": args.rollback_hints
"commitMessage": inputs.commit_message,
"verificationAsks": inputs.verification_asks,
"stopConditions": inputs.stop_conditions,
"rollbackHints": inputs.rollback_hints
}],
"authority": {
"handsAuthorityGranted": false,
@ -1229,6 +1418,9 @@ fn run_plan(args: PlanArgs) -> Result<Value> {
"privateStateExposed": false,
"nextSafeMove": "Run epiphany-work adopt --from-plan <receipt> after Self/Mind accept this Imagination action plan."
});
if let Some(derivation) = inputs.derivation {
plan_receipt["derivation"] = derivation;
}
let receipt_path = artifact_dir.join(format!("work-plan-{item_slug}.json"));
write_json(&receipt_path, &plan_receipt)?;
Ok(json!({
@ -1240,6 +1432,7 @@ fn run_plan(args: PlanArgs) -> Result<Value> {
"planId": plan_receipt["planId"],
"objective": plan_receipt["objective"],
"action": plan_receipt["actions"][0],
"derivation": plan_receipt.get("derivation").cloned().unwrap_or(Value::Null),
"authority": plan_receipt["authority"],
"privateStateExposed": false,
"nextSafeMove": plan_receipt["nextSafeMove"],
@ -3240,6 +3433,44 @@ fn normalize_path(path: &str) -> String {
}
}
fn validate_plan_target_path(path: &str) -> Result<String> {
let normalized = normalize_path(path);
if normalized == "." || normalized.is_empty() {
return Err(anyhow!("derived plan target path cannot be empty"));
}
if normalized.starts_with('/')
|| normalized.contains(':')
|| normalized
.split('/')
.any(|part| part == ".." || part.is_empty())
{
return Err(anyhow!(
"derived plan target path {normalized:?} must be a clean repo-relative path"
));
}
Ok(normalized)
}
fn compact_line(text: &str) -> String {
let compact = text
.split_whitespace()
.collect::<Vec<_>>()
.join(" ")
.trim()
.to_string();
let mut chars = compact.chars();
let truncated = chars.by_ref().take(240).collect::<String>();
if chars.next().is_some() {
format!("{truncated}...")
} else {
compact
}
}
fn powershell_single_quoted(value: &str) -> String {
format!("'{}'", value.replace('\'', "''"))
}
fn normalize_path_for_receipt(path: &Path) -> String {
path.display().to_string().replace('\\', "/")
}
@ -3497,12 +3728,14 @@ fn sanitize(value: &str) -> String {
fn print_usage() {
eprintln!(
"usage: epiphany-work <accept|plan|run|adopt|execute|publish|sync|tick> ...\n\
"usage: epiphany-work <accept|derive-plan|plan|run|adopt|execute|close|publish|sync|tick|serve> ...\n\
accept --workspace <repo> --from <persona|bifrost|persona-or-bifrost> --item <id> [--summary <text>] [--topic <topic>] [--store <local-verse.ccmp>] [--runtime-id <id>] [--online-receipt <path>] [--public-discussion-ref <ref>] [--candidate-action-ref <ref>]\n\
derive-plan --workspace <repo> [--item <id>] [--accept-receipt <path>] [--target-path EPIPHANY_WORKLOG.md] [--model-ref <ref>]\n\
plan --workspace <repo> [--item <id>] --objective <text> --plan-summary <text> --command <command> --changed-path <path> --commit-message <text> [--adoption-evidence-ref <ref>]\n\
run --workspace <repo> [--item <id>] [--accept-receipt <path>] [--runtime-store <path>] [--requested-path <path>]\n\
adopt --workspace <repo> [--item <id>] [--run-receipt <path>] [--from-plan <path>] [--plan-summary <text>] [--adoption-evidence-ref <ref>]\n\
execute --workspace <repo> [--item <id>] [--from-plan <path>] [--command <command>] [--changed-path <path>] [--commit-message <text>]\n\
close --workspace <repo> [--item <id>] [--execute-receipt <path>] [--verification-command <command>]\n\
publish --workspace <repo> [--item <id>] --change-summary <text> --justification <text> --verification-receipt <ref> --review-receipt <ref> --ledger-entry-id <id> --pull-request-url <url> --pull-request-title <text>\n\
sync --workspace <repo> [--item <id>] [--publish-receipt <path>] [--upstream-ref origin/main] --merge-receipt <ref>\n\
tick --workspace <repo> [--item <id>] [--local-verse-store <path>] [--runtime-store <path>] [--dry-run]"

View file

@ -130,6 +130,7 @@ The first MVP is done when a fresh repository can run:
epiphany-repo init --workspace <repo>
epiphany-swarm online --workspace <repo>
epiphany-work accept --workspace <repo> --from persona-or-bifrost --item <id>
epiphany-work derive-plan --workspace <repo> --item <id>
epiphany-work plan --workspace <repo> --item <id> --objective <text> --plan-summary <text> --command <command> --changed-path <path> --commit-message <text>
epiphany-work run --workspace <repo>
epiphany-work adopt --workspace <repo> --item <id> --from-plan <plan-receipt>
@ -226,23 +227,35 @@ ref, public discussion ref, and `privateStateExposed=false`.
### Landed Work Plan Gate
The fourth front door exists as native Rust:
The fourth and fifth front doors exist as native Rust:
```powershell
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-work -- derive-plan --workspace <repo> --item <id>
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-work -- plan --workspace <repo> --item <id> --objective <text> --plan-summary <text> --command <command> --changed-path <path> --commit-message <text>
```
It reads the named or latest work-accept receipt and writes
Both commands read the named or latest work-accept receipt and write
`.epiphany/work/work-plan-<item>.json` as a typed
`epiphany.repo_work_action_plan_receipt.v0`. The receipt names Imagination as
planner, Self as router, Mind as state gate, the objective, plan summary,
adoption evidence refs, and one branch-local command action with changed paths,
commit message, verification asks, stop conditions, and rollback hints.
This is still not Hands authority. It is the first less-manual bridge between
Imagination/Self planning and Hands execution: `adopt --from-plan <receipt>`
can approve the plan, and `execute --from-plan <receipt>` can consume the
planned command/paths/commit message without the operator retyping them.
`epiphany-work plan` is the manual compatibility reliquary: the operator supplies
objective, summary, shell command, paths, and commit message. `epiphany-work
derive-plan` is the first Persona/Bifrost-to-plan automation: it consumes the
accepted pressure summary, candidate action refs, and consensus receipt, then
derives a safe append-only `EPIPHANY_WORKLOG.md` plan with
`operatorAuthoredShellDetails=false`. Its receipt includes
`epiphany.repo_work_plan_derivation.v0`, mode `append-worklog`, and explicitly
marks the path as deterministic quarantine rather than final model-authored
Imagination.
This is still not Hands authority. It is the first non-operator-shell bridge
between Imagination/Self planning and Hands execution: `adopt --from-plan
<receipt>` can approve the plan, and `execute --from-plan <receipt>` can
consume the planned command/paths/commit message without the operator retyping
them.
The first smoke proved:
@ -258,9 +271,26 @@ The execute receipt produced a real branch-local commit from the typed plan
packet, with Hands patch/command/commit receipts and
`privateStateExposed=false`.
A later smoke proved the derived route:
```powershell
epiphany-work accept --workspace <repo> --from persona --item derive-request --summary '...'
epiphany-work derive-plan --workspace <repo> --item derive-request
epiphany-work run --workspace <repo> --item derive-request
epiphany-work adopt --workspace <repo> --item derive-request --from-plan <work-plan-derive-request.json>
epiphany-work execute --workspace <repo> --item derive-request --from-plan <work-plan-derive-request.json>
epiphany-work close --workspace <repo> --item derive-request
```
The derived plan used mode `append-worklog`,
`operatorAuthoredShellDetails=false`, changed only `EPIPHANY_WORKLOG.md`,
executed into `branch-local-commit-recorded`, closed as `closed:passed`, and
reported `privateStateExposed=false` across accept, plan, run, adopt, execute,
and close.
### Landed Work Run Gate
The fifth front door exists as native Rust:
The seventh front door exists as native Rust:
```powershell
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-work -- run --workspace <repo>
@ -323,7 +353,7 @@ still refuses queued or mismatched gates.
### Landed Work Execution Gate
The seventh front door exists as native Rust:
The eighth front door exists as native Rust:
```powershell
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-work -- execute --workspace <repo> --item <id> --command <command> --changed-path <path> --commit-message <text>
@ -360,7 +390,7 @@ The execute receipt produced a real branch-local commit on
### Landed Work Publication Gate
The eighth front door exists as native Rust:
The ninth front door exists as native Rust:
```powershell
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-work -- publish --workspace <repo> --item <id> --change-summary <text> --justification <text> --verification-receipt <ref> --review-receipt <ref> --ledger-entry-id <id> --pull-request-url <url> --pull-request-title <text>
@ -392,14 +422,11 @@ epiphany-work publish --workspace <repo> --item first-request --change-summary '
The publish receipt produced a Hands PR receipt, Bifrost publication receipt,
GitHub publication receipt, `privateStateExposed=false`, and an explicit
`upstreamMainSynced=false` guard. The next cut is a merge/sync gate that can
prove upstream main actually matches the accepted publication, plus a less
manual planner/executor bridge that supplies executable commands from
Imagination/Self rather than operator CLI arguments.
`upstreamMainSynced=false` guard.
### Landed Upstream Sync Proof Gate
The ninth front door exists as native Rust:
The tenth front door exists as native Rust:
```powershell
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-work -- sync --workspace <repo> --item <id> --upstream-ref origin/main --merge-receipt <ref>
@ -431,7 +458,7 @@ The synced receipt produced `publicationAuthorized=true`,
### Landed Work Scheduler Pulse
The tenth front door exists as native Rust:
The eleventh front door exists as native Rust:
```powershell
cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-work -- tick --workspace <repo> --item <id>
@ -588,18 +615,19 @@ That is the machine we are building.
## Full Migration Plan To Repo Swarm MVP
This plan starts from the current state: eleven native front doors exist, but
the work loop is not yet a full physiology. `init`, `online`, `accept`, `plan`,
`run`, `adopt`, `execute`, `close`, `tick`, `publish`, and `sync` prove the typed path
from repo birth to branch-local scheduler pulse, Bifrost/GitHub publication
receipts, and upstream-main sync proof. `tick` now also proves brake refusal,
active-turn refusal, completion-anchored cooldown refusal, and stale active-turn
recovery through typed scheduler receipts; `serve` now proves bounded cadence
around that same tick artery; `close` now proves first deterministic
Soul/Modeling/Mind closure over Hands commit receipts. The chain does not yet
prove a repo Persona that can turn conversation into autonomous action without
the operator feeding plan details by hand, and deeper model-authored
Soul/Modeling closure remains future work.
This plan starts from the current state: twelve native front doors exist, but
the work loop is not yet a full physiology. `init`, `online`, `accept`,
`derive-plan`, `plan`, `run`, `adopt`, `execute`, `close`, `tick`, `publish`,
and `sync` prove the typed path from repo birth to branch-local scheduler
pulse, Bifrost/GitHub publication receipts, and upstream-main sync proof.
`tick` now also proves brake refusal, active-turn refusal,
completion-anchored cooldown refusal, and stale active-turn recovery through
typed scheduler receipts; `serve` now proves bounded cadence around that same
tick artery; `close` now proves first deterministic Soul/Modeling/Mind closure
over Hands commit receipts; `derive-plan` now proves a deterministic
Persona/Bifrost pressure-to-plan bridge with no operator-authored shell
details. The chain does not yet prove fully model-authored Imagination planning
or deeper model-authored Soul/Modeling closure.
The MVP target is narrower than the full Perfect Machine and wider than a demo:
a fresh repository can host an Epiphany swarm that initializes its Body,
@ -617,7 +645,7 @@ The repo swarm can already prove the following chain on a fresh repo Body:
repo birth
-> local Verse online
-> Persona/Bifrost work intake
-> Imagination/Self action plan receipt
-> derived or manual Imagination/Self action plan receipt
-> Substrate Gate + Hands queued run packet
-> plan-backed branch-local Hands adoption
-> plan-backed branch-local execution and commit
@ -634,9 +662,13 @@ The chain is typed and sealed enough to be useful:
topology, liveness, daemon tool directory, and private-state seals.
- `epiphany-work accept` records Persona/Bifrost pressure without granting
Hands, durable-state, publication, or merge authority.
- `epiphany-work plan` records the first typed Imagination/Self action plan:
- `epiphany-work derive-plan` records the first deterministic
Persona/Bifrost-to-plan bridge: accepted pressure becomes a safe append-only
action plan with `operatorAuthoredShellDetails=false`.
- `epiphany-work plan` records a manual typed Imagination/Self action plan:
objective, command, changed paths, commit message, verification asks, stop
conditions, and rollback hints.
conditions, and rollback hints. It remains a compatibility reliquary until
model-authored Imagination can cover richer action classes.
- `epiphany-work run` opens the Substrate Gate and queues a Hands packet, but
leaves mutation blocked until adoption.
- `epiphany-work adopt --from-plan` converts the queued packet into
@ -682,9 +714,10 @@ Required organs before MVP:
Remaining work is optional handoff from branch-local execution into the close
gate and any later Idunn service lifecycle integration under explicit
operator authority.
- Persona-to-plan automation: repo Persona input becomes candidate action
pressure, Mind/Interpreter extracts work-shaped intent, and Imagination
writes the plan packet without the operator hand-authoring shell details.
- Persona-to-plan depth: deterministic append-worklog derivation exists for
accepted Persona/Bifrost pressure; remaining work is model-authored
Imagination planning for richer action classes without operator shell
details.
- Closure depth: deterministic Soul/Modeling/Mind closure exists for Hands
commits; richer model-authored Soul/Modeling review remains to replace the
current local verification rite where appropriate.

View file

@ -102,7 +102,7 @@ remembers doctrine; the branch remembers the blade.
- Edge JSON is allowed for schema description, hostile ingress before immediate typed parsing, sealed forensic artifacts, or named quarantine experiments. When both subsystems are ours, runtime data must remain typed CultCache documents and move over CultNet typed contracts. Generic `serde_json::Value` in worker launch/result/selfPatch/runtime flow is contamination until classified and replaced.
- Hands now has a first executable action receipt spine. `epiphany-core::hands_gateway` owns `HandsActionIntent`, `HandsActionReview`, `HandsPatchReceipt`, `HandsCommandReceipt`, and `HandsCommitReceipt`; runtime-spine can persist/reread them; `runtime_spine_persists_mind_gateway_review_receipts` includes the Hands chain beside Mind/Eyes/Substrate/Soul/Continuity proofs and proves the post-timestamp Hands receipt-chain detector; `epiphany-hands-action-smoke` emits intent/review/patch/command/commit receipt ids from `.epiphany-smoke\runtime-spine\hands-action-smoke.msgpack`; and the repo-action launch proof profile now requires action intent, action review, and patch receipt together. `epiphany-mvp-coordinator` now turns `continueImplementation` into a persisted Substrate Gate grant plus Hands intent/review gate and includes the receipt ids in the operator step. `epiphany-hands-action` is the native consequence recorder for that gate: `record-patch`, `record-command`, `record-commit`, and turn-level `record-pass` load the stored intent/review or `finalAction.handsActionGate` from `coordinator-summary.json`, require an approved matching review, enforce allowed operations, and keep patch/commit changed paths inside the requested scope. `epiphany-mvp-coordinator-smoke` includes the deterministic Hands pass proof. The coordinator now treats a complete Hands receipt chain after an accepted Soul result as new implementation evidence, launches Soul again, and routes a passing accepted Soul result to Modeling/modeling before another Hands turn. Work-loop telemetry is now typed internal CultMesh state: Verification role launches write `epiphany.cultmesh.work_loop_telemetry.v0` beside runtime-spine, render that packet for Soul with resolved receipt bodies, commit diff preview, source proof notes, verification assertions, and stdout/stderr previews, and Modeling launches read/enrich the latest packet with Soul acceptance receipt ids before Modeling updates the map. Local Verse prompt context now exposes only a sealed `latest_work_loop_summary` digest with telemetry id, Hands receipt ids, path/source/assertion counts, and Soul receipt ids; receipt payload previews, artifact previews, and commit diff previews remain internal telemetry and are leak-guarded by tests plus `epiphany-verse-query -- smoke`.
- `notes/epiphany-swarm-readiness-plan.md` is the current live-fire direction gate. The local runner proves startup/status/coordinator wiring; it does not authorize unattended swarm operation. Carry VoidBot's lessons forward: one CTB-style initiative scheduler, typed pause/brake, active-turn freeze, cooldown after completion, stale active-turn recovery receipts, parent-side speech eligibility, memory lifecycle phases, and typed operation proposals instead of prompt-owned governance. `epiphany-verse-query swarm-brake --brake-status engaged|released` can now write the local Verse brake document, and `tools/epiphany_local_run.ps1` refuses live `plan`/`run`/`mvp` modes when that brake is engaged while keeping `status` readable. `epiphany-mvp-coordinator` also checks `--local-verse-store` before app-server startup, and `epiphany-heartbeat-store` guards tick/pump/heat/queue-mention/routine when passed `--local-verse-store`. Daemon tool invocation, daemon lifecycle poke, and `epiphany-daemon-supervisor` restart/tick/serve/service-plan/service-launch/service-runbook/windows-service-install/windows-service-status/windows-service-reconcile/windows-service-execution-readiness/start/stop attempts now fail closed under a matching engaged brake; supervisor restart now has durable per-daemon policy with cooldown/backoff, explicit scheduled tick pulses, latest scheduler receipts, typed service lifecycle plan/launch/runbook/install/status/reconcile/readiness/start/stop receipts, and local operator wrapper modes that write runbook/install/status/reconcile/readiness/control-plan/execution artifacts plus operator run receipts. The installed-service read path, read-only service-policy reconciliation path, execution-readiness path, non-mutating start/stop control-plan path, and non-elevated execution refusal path have been proved against real Windows `EventLog` service-manager state or safe missing-service targets through local Verse receipts, including explicit wrapper install/start/stop execution modes. The next cut is actual elevated install/start/stop execution proof under operator authority.
- `notes/epiphany-repo-swarm-mvp-contract.md` is the repo-swarm MVP authority map and migration plan. It states the live eleven-front-door chain from `epiphany-repo init` through `epiphany-work close`, `tick`, `publish`, and `sync`, documents the operator-safe proof receipts already proved with `privateStateExposed=false`, and names the remaining MVP organs: Persona-to-plan automation, repo work overview, proof bundles, optional execute-to-close handoff, and richer model-authored closure. Autonomous branch-local work inside the owned repo Body is in scope and desired; Bifrost gates publication/merge/escalation, Idunn owns daemon lifecycle, and `epiphany-work tick` may only advance one safe receipt-backed branch-local step per pulse before stopping at closure or publication gates. The tick pulse now reads the repo-local CultMesh swarm brake and writes `refused-by-swarm-brake` without creating run/adopt/execute receipts when the brake is engaged. It also writes active-turn and last-completed scheduler receipts, refuses live duplicate pulses as `refused-active-turn`, refuses explicit completion-anchored cooldown as `refused-by-cooldown`, clears stale active markers after `--active-timeout-seconds`, and records `physiology.recoveredActiveTurn.recovered=true` when recovery proceeds. `epiphany-work serve` now wraps that tick artery in Self-owned cadence: bounded `--max-iterations` proof mode writes `work-scheduler-serve-<item>.json`, unbounded service mode relies on per-pulse tick receipts, and unbounded zero-second polling is refused. `epiphany-work close` now consumes branch-local execute receipts, verifies the Hands commit, writes Soul verdict plus Modeling summary plus Mind gateway/state-commit receipts, and seals `work-close-<item>.json` without granting publication, merge, service lifecycle, cross-repo mutation, or private-state exposure. `epiphany-work publish --closure-receipt` can consume the closure's Soul/Mind ids, while tick no-ops once closure exists before Bifrost publication authority. Disposable fresh-repo smokes proved active refusal, `advanced:run-from-plan`, cooldown refusal without adoption, stale recovery into `advanced:adopt-from-plan`, active marker cleanup, last-completed anchor creation, serve cadence iteration one `advanced:run-from-plan`, iteration two `refused-by-cooldown:none`, no adoption during cooldown, unbounded zero-interval refusal, close `closed:passed`, publish consumption of the close receipt's Soul/Mind refs, post-publication tick `noop:none`, and `privateStateExposed=false`.
- `notes/epiphany-repo-swarm-mvp-contract.md` is the repo-swarm MVP authority map and migration plan. It states the live twelve-front-door chain from `epiphany-repo init` through `epiphany-work derive-plan`, `close`, `tick`, `publish`, and `sync`, documents the operator-safe proof receipts already proved with `privateStateExposed=false`, and names the remaining MVP organs: model-authored Persona-to-plan depth, repo work overview, proof bundles, optional execute-to-close handoff, and richer model-authored closure. Autonomous branch-local work inside the owned repo Body is in scope and desired; Bifrost gates publication/merge/escalation, Idunn owns daemon lifecycle, and `epiphany-work tick` may only advance one safe receipt-backed branch-local step per pulse before stopping at closure or publication gates. `epiphany-work derive-plan` now consumes accepted Persona/Bifrost pressure and writes an Imagination/Self action plan in deterministic `append-worklog` quarantine mode with `operatorAuthoredShellDetails=false`; disposable smoke proved accept -> derive-plan -> run -> adopt -> execute -> close, changed only `EPIPHANY_WORKLOG.md`, ended `closed:passed`, and reported no private-state exposure. The tick pulse reads the repo-local CultMesh swarm brake and writes `refused-by-swarm-brake` without creating run/adopt/execute receipts when the brake is engaged. It also writes active-turn and last-completed scheduler receipts, refuses live duplicate pulses as `refused-active-turn`, refuses explicit completion-anchored cooldown as `refused-by-cooldown`, clears stale active markers after `--active-timeout-seconds`, and records `physiology.recoveredActiveTurn.recovered=true` when recovery proceeds. `epiphany-work serve` wraps that tick artery in Self-owned cadence: bounded `--max-iterations` proof mode writes `work-scheduler-serve-<item>.json`, unbounded service mode relies on per-pulse tick receipts, and unbounded zero-second polling is refused. `epiphany-work close` consumes branch-local execute receipts, verifies the Hands commit, writes Soul verdict plus Modeling summary plus Mind gateway/state-commit receipts, and seals `work-close-<item>.json` without granting publication, merge, service lifecycle, cross-repo mutation, or private-state exposure. `epiphany-work publish --closure-receipt` can consume the closure's Soul/Mind ids, while tick no-ops once closure exists before Bifrost publication authority.
- `service-execution-runbook` makes that next cut repeatable: it generates the exact elevated wrapper command sequence without mutating the service manager, continues after per-step failure to preserve more receipts, runs `service-execution-audit` in `finally`, exits nonzero if any step failed, and seals a typed runbook lifecycle receipt. Run the generated artifact only with explicit operator authority.
- `service-execution-audit` is the non-mutating acceptance proof after the elevated rite: it reports `complete` only when typed lifecycle receipts prove the runbook witness plus expected elevated chain, and otherwise reports the missing/failed sealed checks.
- `service-tick` is the non-elevated scheduler pulse proof: it writes the latest daemon scheduler receipt through durable policy ownership and local wrapper receipts.

Binary file not shown.

View file

@ -88,7 +88,7 @@ active_subgoals:
- Keep the landed Phase 6 coordinator, limited safe-boundary CRRC automation, and pre-compaction checkpoint intervention ready for the next bridge-equipped dogfood run.
- Preserve the Ghostlight-derived heartbeat initiative seam: every lane, including coordinator/Self and Persona, has a organ-state record and competes for heartbeat slots through readiness/reaction timing; initiative heat can raise or cool global, group, arena, role, and agent tempo through typed heartbeat policy; active thinking freezes initiative until completion, so heat never queues a lane already mid-turn; idle winners ruminate instead of inventing project work, and sleep windows distill the accumulated thought pressure into reviewed self-memory or doctrine.
- Use `notes/epiphany-swarm-readiness-plan.md` as the live-fire direction gate. The local run path is a compass, not launch clearance: before unattended swarm operation, Epiphany needs typed pause/brake enforcement, one initiative scheduler, completion-gated cooldown, stale active-turn recovery receipts, parent-side Persona speech eligibility, memory lifecycle operations, and CultNet-first operator snapshots/intents/receipts. The local Verse brake document exists, `epiphany-verse-query swarm-brake` can engage/release it, `tools/epiphany_local_run.ps1` refuses live `plan`/`run`/`mvp` modes when the brake is engaged while leaving `status` readable, `epiphany-mvp-coordinator` checks the local Verse brake before app-server startup, and `epiphany-heartbeat-store` guards tick/pump/heat/queue-mention/routine when given `--local-verse-store`. Daemon liveness is now a typed local Verse authority: `epiphany-verse-query daemon-status` writes one daemon status without repainting the table, local Verse seeding preserves existing daemon statuses and swarm brakes, `invoke-tool` refuses when the host daemon is not ready or lacks `submitTypedToolIntent`, and both daemon tool invocation and lifecycle poke fail closed under an engaged matching brake. `epiphany-daemon-supervisor policy` writes durable per-daemon restart policy with command/args/cwd/cooldown/backoff/attempt state plus reconcile cadence and stale-heartbeat threshold; `epiphany-daemon-supervisor reconcile` loads that policy when no override command is supplied, refuses under a matching lifecycle brake, refuses during cooldown/backoff, writes daemon poke intent/receipt, updates daemon status, and updates policy attempt state; `epiphany-daemon-supervisor tick` is an explicit scheduler pulse that scans durable policies, records ready/noop pulses, skips before the configured reconcile interval, marks stale heartbeat status degraded, routes restarts through the same brake/cooldown/poke receipt path, and writes a latest `epiphany.cultmesh.daemon_scheduler_receipt.v0`; `epiphany-daemon-supervisor serve` runs that same pulse on a configurable cadence with bounded `--max-iterations` proof mode or unbounded service mode. `epiphany-daemon-supervisor service-plan`/`install-service` now writes a planned `epiphany.cultmesh.daemon_service_lifecycle_receipt.v0` for the `serve` command, while `service-launch`/`start-service` spawns that `serve` loop through the current executable or `--service-command`, can `--wait-child` for bounded proof, and records command/args/cwd, scheduler id, daemon selector, pid/exit/status, artifact ref, and private-state guard. `service-runbook`, `windows-service-install`/`service-install-plan`, `windows-service-status`, `windows-service-reconcile`, `windows-service-execution-readiness`, and `windows-service-start`/`stop` now record service lifecycle receipts through the same local Verse; the read-only status path has been proved against the real Windows `EventLog` service with receipt `daemon-service-lifecycle-receipt-windows-eventlog-proof-windows-service-status`, status `running`, exit code `0`, and `privateStateExposed=false`; the read-only service-policy reconciliation path has been proved for missing service, real-service drift against `EventLog`, lifecycle-brake refusal, and wrapper/local-Verse receipt `daemon-service-lifecycle-receipt-windows-eventlog-reconcile-proof-windows-service-reconcile`; execution readiness has been proved as a non-mutating `not-elevated` receipt through direct and wrapper paths; start/stop now produce non-mutating `start-planned`/`stop-planned` receipts unless `--execute-control`/`--execute-service-control` is passed, and wrapper `service-start-plan`/`service-stop-plan` proves those receipts against `EventLog`; explicit install/control execution now refuses as `execution-refused-not-elevated` with `executed=false` when the shell lacks Windows administrator authority, and wrapper `service-install-execute`, `service-start-execute`, and `service-stop-execute` prove those refusal receipts without mutation. Service lifecycle actions check the local Verse swarm brake before process launch, artifact writes, service-manager queries, service-policy reconciliation, execution-readiness checks, control planning, elevation-gated execution, or start/stop execution. The local wrapper builds/checks this binary.
- Use `notes/epiphany-repo-swarm-mvp-contract.md` as the authority correction and migration plan for repo-swarm autonomy. Autonomous branch-local work inside an Epiphany-owned repo Body is in scope and desired; the safety boundary is typed authority, branch containment, interruptibility, receipts, private-state sealing, and Bifrost-gated publication/merge/escalation, not asking a human before every local edit. Eleven native repo-swarm front doors are live and documented there: `epiphany-repo init`, `epiphany-swarm online`, `epiphany-work accept`, `epiphany-work plan`, `epiphany-work run`, `epiphany-work adopt --from-plan`, `epiphany-work execute --from-plan`, `epiphany-work close`, `epiphany-work tick`, `epiphany-work publish`, and `epiphany-work sync`. Fresh-repo smokes proved the chain with `privateStateExposed=false`, including plan-backed branch-local commit creation, a Self-owned tick pulse that advances `run-from-plan -> adopt-from-plan -> execute-from-plan` then no-ops before closure/publication gates, local CultMesh swarm-brake refusal that writes `refused-by-swarm-brake` without creating a run/adopt/execute receipt, active-turn refusal through `work-tick-active-<item>.json`, explicit completion-anchored cooldown refusal through `work-tick-last-<item>.json`, stale active-turn recovery that records `physiology.recoveredActiveTurn.recovered=true`, Self-owned `epiphany-work serve` cadence that writes `work-scheduler-serve-<item>.json`, bounded serve proof `advanced:run-from-plan -> refused-by-cooldown:none` without adoption, unbounded zero-interval refusal, deterministic `epiphany-work close` proof that consumes execute receipts, verifies the Hands commit, writes Soul verdict plus Modeling summary plus Mind gateway/state-commit receipts, `publish --closure-receipt` consumption of the close receipt's Soul/Mind refs, post-publication tick `noop:none`, and upstream-main ancestry proof after explicit merge receipt. Remaining MVP organs are Persona-to-plan automation, compact repo work overview, operator-safe proof bundles, optional execute-to-close scheduler handoff, and richer model-authored closure; the scheduler may advance only one safe receipt-backed branch-local step per pulse and must not publish, merge, mutate services, cross repo boundaries, expose private state, or impersonate Idunn.
- Use `notes/epiphany-repo-swarm-mvp-contract.md` as the authority correction and migration plan for repo-swarm autonomy. Autonomous branch-local work inside an Epiphany-owned repo Body is in scope and desired; the safety boundary is typed authority, branch containment, interruptibility, receipts, private-state sealing, and Bifrost-gated publication/merge/escalation, not asking a human before every local edit. Twelve native repo-swarm front doors are live and documented there: `epiphany-repo init`, `epiphany-swarm online`, `epiphany-work accept`, `epiphany-work derive-plan`, `epiphany-work plan`, `epiphany-work run`, `epiphany-work adopt --from-plan`, `epiphany-work execute --from-plan`, `epiphany-work close`, `epiphany-work tick`, `epiphany-work publish`, and `epiphany-work sync`. Fresh-repo smokes proved the chain with `privateStateExposed=false`, including deterministic Persona/Bifrost pressure-to-plan derivation (`append-worklog`, `operatorAuthoredShellDetails=false`) into `EPIPHANY_WORKLOG.md`, plan-backed branch-local commit creation, a Self-owned tick pulse that advances `run-from-plan -> adopt-from-plan -> execute-from-plan` then no-ops before closure/publication gates, local CultMesh swarm-brake refusal that writes `refused-by-swarm-brake` without creating a run/adopt/execute receipt, active-turn refusal through `work-tick-active-<item>.json`, explicit completion-anchored cooldown refusal through `work-tick-last-<item>.json`, stale active-turn recovery that records `physiology.recoveredActiveTurn.recovered=true`, Self-owned `epiphany-work serve` cadence that writes `work-scheduler-serve-<item>.json`, bounded serve proof `advanced:run-from-plan -> refused-by-cooldown:none` without adoption, unbounded zero-interval refusal, deterministic `epiphany-work close` proof that consumes execute receipts, verifies the Hands commit, writes Soul verdict plus Modeling summary plus Mind gateway/state-commit receipts, `publish --closure-receipt` consumption of the close receipt's Soul/Mind refs, post-publication tick `noop:none`, and upstream-main ancestry proof after explicit merge receipt. Remaining MVP organs are model-authored Persona-to-plan depth for richer actions, compact repo work overview, operator-safe proof bundles, optional execute-to-close scheduler handoff, and richer model-authored closure; the scheduler may advance only one safe receipt-backed branch-local step per pulse and must not publish, merge, mutate services, cross repo boundaries, expose private state, or impersonate Idunn.
- Agent memory lifecycle now has a first typed v0 operation surface in `epiphany-core::agent_memory`: `AgentMemoryLifecycleOperation` can revise, retire, crystallize, prune, and merge bounded memory records after role/agent review, and `epiphany-agent-memory-store review-lifecycle|apply-lifecycle` exposes the path at the operator edge. This closes the first explicit lifecycle-operation slice from the swarm-readiness gate; it does not yet make sleep silently mutate identity or project truth.
- Persona public speech now has a parent-side eligibility receipt at the Discord/Aquarium mouth edge. `epiphany.persona_speech_audit.v0` records action kind, content fingerprint, opening/topic keys, recent-window counts, repeated opening/topic counts, channel saturation, and allow/block reasons. `epiphany-persona-discord post` blocks repeated public openings before token/webhook work; draft and bubble still emit audit receipts for operator inspection. The compatibility JSON artifact remains for display, but the durable witness is now `epiphany.cultmesh.persona_speech_audit.v0` in CultMesh with latest-key projection through local Verse context. Local MVP Persona bubbles now write that durable witness to `.epiphany-run/cultmesh/local-verse.ccmp`, not a separate mouth-side store. This is posting-edge policy, not a Persona prompt wish.
- Grow the VoidBot repo-Persona pattern into Epiphany's product direction: each Epiphany owns one or more repos, has one or more Personas, and exposes project-native conversation through Aquarium, Discord, voice/WebRTC, stream surfaces, CLI, and CultNet clients so humans can talk to projects instead of pre-authoring complete implementation briefs. Persona is special because Imagination acts as Projector, turning typed state into narrative context before the Persona thinks, and Mind acts as Interpreter, turning natural Persona output into reviewed state/side-effect intents after the Persona thinks.
@ -633,4 +633,4 @@ current_status:
- `tools/epiphany_local_run.ps1 -Mode swarm-online-runbook` now emits an explicit Idunn preflight summary before the operator elevation boundary. Its JSON and one-line summary report `preflightStatus`, child artifact present/hash-verified/mismatch/missing counts, aggregate service execution failed/missing check counts, child preflight rows with expected/actual SHA-256s, and private-state exposure. Live proof `local-20260619-025627-410-9724e2f6` generated the non-mutating parent artifact with `preflightStatus=ready-for-elevated-operator`, two child runbooks present, two hashes verified, zero mismatches, zero missing artifacts, eleven failed sealed service checks, zero missing checks, explicit aftercare audits, and `privateStateExposed=false`. The remaining scar is still explicit elevated operator execution followed by complete Idunn audits, not missing parent/child artifact readiness.
- Service lifecycle receipt history is now event-only: `load_epiphany_cultmesh_daemon_service_lifecycle_receipts` filters out the `epiphany-local/daemon-service-lifecycle-receipt/latest` mirror, while `load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt` remains the latest-state reader. Focused unit test `service_lifecycle_receipt_history_excludes_latest_mirror` proves two per-receipt writes return exactly two history records and latest points at the second. Fresh smoke `verse-query-lifecycle-history-filter-smoke` and live overview/triage `local-20260618-145632-497-efac6f0d` / `local-20260618-145632-321-867947af` prove compact swarm sights still expose service lifecycle attention plus the present elevated runbook artifact without daemon pokes or service mutation. Do not use a broad unscoped cargo test filter for this check on Windows; it fans out across bin harnesses and hit a broken pipe during this pass.
- `epiphany-verse-query seed-compact` is the compact seed receipt for wrappers and read-only rites. The older `seed` command still prints the full local Verse context for explicit debugging, but compact wrapper modes now avoid full `seed`/final `query` readback after the combined overview proof exposed Windows debug stack overflow from full-context serialization pressure.
next_action: Continue repo-swarm MVP work from the documented eleven-front-door chain. Next build Persona-to-plan automation so Persona/Bifrost candidate action pressure becomes model/Imagination-authored plan packets rather than operator-authored shell details. Preserve Idunn service lifecycle surfaces and existing CultMesh/Odin/Eve tool directories; service install/start execution still requires explicit elevated operator authority.
next_action: Continue repo-swarm MVP work from the documented twelve-front-door chain. Next build compact repo work overview/proof-bundle surfaces so operators and repo Personas can see current item, branch, receipt chain, blocker, next safe action, closure/publication/sync state, and private-state seal without opening raw worker thought. Preserve Idunn service lifecycle surfaces and existing CultMesh/Odin/Eve tool directories; service install/start execution still requires explicit elevated operator authority.