diff --git a/epiphany-core/src/bin/epiphany-repo-tool-request-family-smoke.rs b/epiphany-core/src/bin/epiphany-repo-tool-request-family-smoke.rs index 53c9b51a..1bf364ad 100644 --- a/epiphany-core/src/bin/epiphany-repo-tool-request-family-smoke.rs +++ b/epiphany-core/src/bin/epiphany-repo-tool-request-family-smoke.rs @@ -196,6 +196,8 @@ fn run_smoke(args: Args) -> Result { )?; 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\"", @@ -215,7 +217,7 @@ fn run_smoke(args: Args) -> Result { "receipt_contract = \"epiphany.cultmesh.daemon_tool_invocation_receipt.v0\"", )?; require_text(&request_text, "host_daemon_owns_execution = true")?; - require_text(&request_text, "requester_owns_request = false")?; + 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]")?; diff --git a/epiphany-core/src/bin/epiphany-work.rs b/epiphany-core/src/bin/epiphany-work.rs index 5817f7de..d67f945d 100644 --- a/epiphany-core/src/bin/epiphany-work.rs +++ b/epiphany-core/src/bin/epiphany-work.rs @@ -2721,7 +2721,8 @@ fn derive_repo_tool_request_plan( "[request]".to_string(), format!("id = {}", toml_basic_string(&request_id)), format!("requester_body = {}", toml_basic_string(&requester_body)), - "requesting_agent = \"repo Persona/Self\"".to_string(), + "routing_owner = \"Self\"".to_string(), + "pressure_source = \"Persona\"".to_string(), "target_directory = \"gamecult-local/daemon-tool-directory\"".to_string(), "target_capability = \"daemon-tool-capability:selected-by-review\"".to_string(), "operation = \"submitTypedToolIntent\"".to_string(), @@ -2736,7 +2737,7 @@ fn derive_repo_tool_request_plan( toml_basic_string(receipt_contract) ), "host_daemon_owns_execution = true".to_string(), - "requester_owns_request = false".to_string(), + "requester_owns_execution = false".to_string(), "requires_host_liveness_ready = true".to_string(), "requires_cultmesh_receipts = true".to_string(), String::new(), diff --git a/epiphany-core/src/bin/epiphany_work/closure_contracts/external_governance.rs b/epiphany-core/src/bin/epiphany_work/closure_contracts/external_governance.rs index d69d599a..bec88f39 100644 --- a/epiphany-core/src/bin/epiphany_work/closure_contracts/external_governance.rs +++ b/epiphany-core/src/bin/epiphany_work/closure_contracts/external_governance.rs @@ -20,7 +20,10 @@ impl RepoToolRequest { } pub(super) fn has_request_contract(&self) -> bool { - self.request.target_directory == "gamecult-local/daemon-tool-directory" + !self.request.requester_body.is_empty() + && self.request.routing_owner == "Self" + && self.request.pressure_source == "Persona" + && self.request.target_directory == "gamecult-local/daemon-tool-directory" && self.request.target_capability == "daemon-tool-capability:selected-by-review" && self.request.operation == "submitTypedToolIntent" } @@ -30,7 +33,7 @@ impl RepoToolRequest { && self.cultmesh.receipt_contract == "epiphany.cultmesh.daemon_tool_invocation_receipt.v0" && self.cultmesh.host_daemon_owns_execution - && !self.cultmesh.requester_owns_request + && !self.cultmesh.requester_owns_execution && self.cultmesh.requires_host_liveness_ready && self.cultmesh.requires_cultmesh_receipts } @@ -55,6 +58,9 @@ impl RepoToolRequest { #[derive(Debug, Deserialize)] pub(super) struct RepoToolRequestBody { + requester_body: String, + routing_owner: String, + pressure_source: String, target_directory: String, target_capability: String, operation: String, @@ -65,7 +71,7 @@ pub(super) struct RepoToolRequestCultMesh { intent_contract: String, receipt_contract: String, host_daemon_owns_execution: bool, - requester_owns_request: bool, + requester_owns_execution: bool, requires_host_liveness_ready: bool, requires_cultmesh_receipts: bool, } diff --git a/epiphany-core/src/bin/epiphany_work/closure_contracts/external_governance_tests.rs b/epiphany-core/src/bin/epiphany_work/closure_contracts/external_governance_tests.rs index 61584534..32b11945 100644 --- a/epiphany-core/src/bin/epiphany_work/closure_contracts/external_governance_tests.rs +++ b/epiphany-core/src/bin/epiphany_work/closure_contracts/external_governance_tests.rs @@ -47,6 +47,9 @@ safe_action_family = "repo.tool_request" summary = "summary" private_state_exposed = false [request] +requester_body = "repo:test" +routing_owner = "Self" +pressure_source = "Persona" target_directory = "gamecult-local/daemon-tool-directory" target_capability = "daemon-tool-capability:selected-by-review" operation = "submitTypedToolIntent" @@ -54,7 +57,7 @@ operation = "submitTypedToolIntent" intent_contract = "epiphany.cultmesh.daemon_tool_invocation_intent.v0" receipt_contract = "epiphany.cultmesh.daemon_tool_invocation_receipt.v0" host_daemon_owns_execution = true -requester_owns_request = false +requester_owns_execution = false requires_host_liveness_ready = true requires_cultmesh_receipts = true [odin] diff --git a/notes/conceptual-substitution-audit-2026-07-12.md b/notes/conceptual-substitution-audit-2026-07-12.md index 9e092892..314408ff 100644 --- a/notes/conceptual-substitution-audit-2026-07-12.md +++ b/notes/conceptual-substitution-audit-2026-07-12.md @@ -1389,3 +1389,16 @@ ledger rows name the actual source Persona id as owner and retain the requested Imagination consensus route. Bifrost owns collaboration-consensus accounting; the Persona-to-Imagination chain is what Bifrost observes, not who Bifrost is. Production source now contains no arrow-shaped owner value. + +## Request ownership is not execution ownership + +The repo tool request encoded `requesting_agent="repo Persona/Self"`, while its +typed closure ignored requester identity entirely and declared +`requester_owns_request=false`. This merged Persona pressure, Self routing, and +host execution, then denied ownership of the request because the requester did +not own execution. + +The request now carries a concrete requester body, `routing_owner=Self`, and +`pressure_source=Persona`. CultMesh separately states that the target host +daemon owns execution and the requester does not. The typed closure validates +all of these fields. Persona supplies pressure; Self routes; the provider acts. diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 798498b0..1c37242f 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -509,3 +509,11 @@ publishes the Persona-to-Imagination handoff separately; feedback ledger rows use their source Persona id; Bifrost owns consensus accounting. Continue the conceptual-substitution scan beyond owner strings: look for status, route, receipt, or cache fields that borrow consequence authority from another organ. + +The first non-owner substitution is cut in `repo.tool_request`. The old +`requesting_agent="repo Persona/Self"` and `requester_owns_request=false` shape +is replaced by requester body identity, Self routing, Persona pressure +provenance, target-host execution ownership, and requester execution denial. +The typed closure now validates the identity and authority split. Continue +looking for fields where observation, request, admission, and effect ownership +are collapsed under innocent-sounding status or cache names. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 1b0c475a..32547135 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index 52728d97..8d02017a 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -660,4 +660,4 @@ current_status: - 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. last_completed_repo_swarm_cut: Huginn live-fire has crossed the first real repo Body from Persona pressure to branch-local Hands commit and Soul/Mind closure, and now has repeatable closure and redacted-public-proof mouths. On `E:\Projects\Huginn` branch `epiphany/huginn/first-awakening`, `tools/epiphany_local_run.ps1 -Mode repo-persona-intake` accepted item `huginn-inspection-readback-livefire`, Weksa/Persona intake remained sealed, and `epiphany-work derive-plan` lowered it to model-authored safe family `repo.status_section` for `README.md` only. `tools/epiphany_local_run.ps1 -Mode repo-swarm-run` advanced four bounded pulses: run-from-plan, adopt-from-plan, execute-from-plan, and close-from-execute. Huginn commit `e9b07c38fceabbdc89ea35c2156326c80c0393a2` updated only `README.md`; closure receipt `.epiphany\work\work-close-huginn-inspection-readback-livefire.json` records status `closed`, Soul verdict `passed`, Mind state commit `repo-work-close-huginn-inspection-readback-livefire-mind-commit`, safe family `repo.status_section`, path scope `README.md`, Bifrost publication gate, and `privateStateExposed=false`. Verification also ran Huginn's TypeScript compiler through concrete Node path: `C:\Program Files\nodejs\node.exe E:\Projects\Huginn\node_modules\typescript\bin\tsc -p tsconfig.json` passed. Native verifier `epiphany-repo-livefire-closure-smoke --workspace E:\Projects\Huginn --item huginn-inspection-readback-livefire --expected-path README.md --expected-family repo.status_section --expected-gate awaiting-publication --expected-blocker bifrost-publication-missing` checks closure receipt, Mind map entry, overview gate/blocker, authority seals, and `git show` changed paths, returning `status=ok`, `soulVerdict=passed`, `publicationGate=Bifrost`, and `privateStateExposed=false`. Wrapper `tools/epiphany_local_run.ps1 -Mode repo-livefire-closure -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exposes the same read-only proof through the local operator mouth; artifact `local-20260621-190156-803-2f85ba15` printed commit, path, gate, blocker, Soul verdict, Mind commit receipt, and `privateStateExposed=False` without push, merge, publication, or target mutation. New wrapper `tools/epiphany_local_run.ps1 -Mode repo-work-public-proof -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exports the redacted proof bundle and repo-local Verse index without publishing; artifact `local-20260621-190645-345-4555b1dc` wrote `.epiphany\public\proof-bundles\repo-work-public-proof-huginn-inspection-readback-livefire.json`, proof id `repo-work-public-proof-huginn-inspection-readback-livefire`, SHA-256 `857545b199f3e37eb06c2e757e5cfc201958e46667bb1f8403fd333a22620f63`, nine artifact rows, zero publication rows, and `privateStateExposed=False`. swarm overview readback `local-20260621-190701-140-b9519ec6` sees the `REPO-WORK-PUBLIC-PROOF` row and action row from Huginn's repo-local Verse with the same SHA-256 while Bifrost publication remains missing. Launcher compact modes are now named compact operator-context modes instead of read-only modes, and `bifrost-public-proof` summaries print item, target public Verse, room, proof SHA-256, review receipts, and credit receipts so publication receipts are auditable without claiming upstream sync. - next_action: Continue the conceptual-substitution audit beyond owner strings. Arrow-shaped handoffs are no longer owners: Self owns intake readback, source Personas own feedback, Bifrost owns consensus accounting, and routes carry the Persona-to-Imagination handoff. Next inspect status, route, receipt, scheduler, and cache projections for borrowed consequence authority; keep closure's zero-substring invariant. + next_action: Continue the conceptual-substitution audit beyond owner strings. Tool requests now separate requester body, Self routing, Persona pressure provenance, and target-host execution; the typed closure validates the split. Next inspect status, receipt, scheduler, and cache projections for fields that collapse observation/request/admission/effect authority. Keep closure's zero-substring invariant.