diff --git a/epiphany-core/src/bin/epiphany-verse-query.rs b/epiphany-core/src/bin/epiphany-verse-query.rs index 94f6c752..41f63300 100644 --- a/epiphany-core/src/bin/epiphany-verse-query.rs +++ b/epiphany-core/src/bin/epiphany-verse-query.rs @@ -1893,6 +1893,58 @@ fn run_cli() -> Result<()> { "local Verse query smoke lost daemon status readback for globally invokable status tools" ); } + let persona_eve_connect = context + .daemon_tool_capabilities + .iter() + .find(|capability| { + capability.capability_id == "epiphany.cluster.persona.tool.eve-connect" + }) + .context("missing Persona eve-connect daemon tool capability")?; + let persona_surface_directory = + load_epiphany_cultmesh_eve_surface_directory(&args.store, args.runtime_id.clone())?; + let (persona_cluster, persona_advertisement, persona_surface) = + persona_surface_directory + .iter() + .find(|(cluster, _advertisement, _surface)| { + cluster.cluster_id == persona_eve_connect.host_cluster_id + }) + .context("missing Persona Eve surface for eve-connect readback")?; + let (eve_connection_readback, eve_connection_private_state_exposed) = + eve_connection_readback_from_host( + persona_cluster, + persona_advertisement, + persona_surface, + persona_eve_connect, + ); + let supported_actions = eve_connection_readback["supportedActions"] + .as_array() + .context("eve-connect readback lost supported actions")?; + if eve_connection_readback["targetClusterId"].as_str() + != Some("epiphany.cluster.persona") + || eve_connection_readback["targetDisplayName"].as_str() != Some("Persona") + || eve_connection_readback["targetEveSurfaceId"].as_str() + != Some("eve://epiphany/persona") + || eve_connection_readback["targetPrivateVerseId"].as_str() + != Some("epiphany.cluster.persona.private") + || eve_connection_readback["connectionCommand"].as_str() + != Some( + "epiphany-verse-query connect-eve --target-cluster-id epiphany.cluster.persona", + ) + || eve_connection_readback["wrapperConnectionCommand"].as_str() + != Some( + "tools/epiphany_local_run.ps1 -Mode eve-connect -EveTargetClusterId epiphany.cluster.persona", + ) + || eve_connection_readback["publicPersonaDiscussionAllowed"].as_bool() != Some(true) + || !supported_actions + .iter() + .any(|action| action.as_str() == Some("submitEveConnectionIntent")) + || eve_connection_private_state_exposed + || eve_connection_readback["privateStateExposed"].as_bool() != Some(false) + { + anyhow::bail!( + "local Verse query smoke lost Eve surface readback for globally invokable eve-connect tools" + ); + } let no_op_pokes = write_poke_receipts_for_non_ready_daemons(&args, &context)?; if !no_op_pokes.is_empty() { anyhow::bail!("local Verse query smoke poked ready daemons during no-op sweep"); @@ -6156,9 +6208,29 @@ fn run_invoke_tool_command(args: &Args) -> Result<()> { } else { (serde_json::Value::Null, false) }; + let (eve_connection_readback, eve_connection_readback_private_state_exposed) = + if is_eve_connect_capability(capability) { + let surface_directory = + load_epiphany_cultmesh_eve_surface_directory(&args.store, args.runtime_id.clone())?; + let (target_cluster, target_advertisement, target_surface) = surface_directory + .iter() + .find(|(cluster, _advertisement, _surface)| { + cluster.cluster_id == capability.host_cluster_id + }) + .context("local Verse lost Eve surface for eve-connect capability host")?; + eve_connection_readback_from_host( + target_cluster, + target_advertisement, + target_surface, + capability, + ) + } else { + (serde_json::Value::Null, false) + }; let private_state_exposed = written_receipt.private_state_exposed || service_health_readback_private_state_exposed - || daemon_status_readback_private_state_exposed; + || daemon_status_readback_private_state_exposed + || eve_connection_readback_private_state_exposed; let invocation_tui_row = daemon_tool_invocation_tui_row(DaemonToolInvocationTuiFields { requester: &requesting_cluster.display_name, requesting_agent_id: &written_intent.requesting_agent_id, @@ -6214,6 +6286,8 @@ fn run_invoke_tool_command(args: &Args) -> Result<()> { "privateStateRequested": written_intent.private_state_requested, "daemonStatusReadback": daemon_status_readback, "daemonStatusReadbackPrivateStateExposed": daemon_status_readback_private_state_exposed, + "eveConnectionReadback": eve_connection_readback, + "eveConnectionReadbackPrivateStateExposed": eve_connection_readback_private_state_exposed, "serviceHealthReadback": service_health_readback, "serviceHealthReadbackPrivateStateExposed": service_health_readback_private_state_exposed, "privateStateExposed": private_state_exposed, @@ -6231,6 +6305,8 @@ fn default_daemon_tool_receipt_status( "accepted-for-service-lifecycle-readback".to_string() } else if is_daemon_status_capability(capability) { "accepted-for-daemon-status-readback".to_string() + } else if is_eve_connect_capability(capability) { + "accepted-for-eve-surface-readback".to_string() } else { "accepted-for-daemon-routing".to_string() } @@ -6274,6 +6350,46 @@ fn daemon_status_readback_from_host( ) } +fn eve_connection_readback_from_host( + target_cluster: &EpiphanyCultMeshClusterTopologyEntry, + target_advertisement: &EpiphanyCultMeshOdinAdvertisementEntry, + target_surface: &EpiphanyCultMeshEveSurfaceStateEntry, + capability: &EpiphanyCultMeshDaemonToolCapabilityEntry, +) -> (serde_json::Value, bool) { + let private_state_exposed = target_advertisement.private_state_exposed + || target_surface.private_state_exposed + || capability.private_state_exposed; + ( + json!({ + "targetAdvertisementId": target_advertisement.advertisement_id, + "targetClusterId": target_cluster.cluster_id, + "targetDisplayName": target_cluster.display_name, + "targetBodyDomain": target_cluster.body_domain, + "targetPrivateVerseId": target_cluster.private_verse_id, + "targetDaemonId": target_cluster.daemon_id, + "targetEveSurfaceId": target_surface.surface_id, + "targetTuiTitle": target_surface.tui_title, + "publicPersonaDiscussionAllowed": target_cluster.public_persona_discussion_allowed, + "supportedActions": target_surface.supported_actions, + "exposedDocumentTypes": target_surface.exposed_document_types, + "connectionCommand": format!( + "epiphany-verse-query connect-eve --target-cluster-id {}", + target_cluster.cluster_id + ), + "wrapperConnectionCommand": format!( + "tools/epiphany_local_run.ps1 -Mode eve-connect -EveTargetClusterId {}", + target_cluster.cluster_id + ), + "feedbackRoute": format!( + "cultmesh://epiphany-local/eve/{}/feedback", + target_cluster.cluster_id + ), + "privateStateExposed": private_state_exposed, + }), + private_state_exposed, + ) +} + fn service_health_readback_from_idunn(args: &Args) -> Result<(serde_json::Value, bool)> { let overview = load_swarm_overview_report(args)?; let service_action_rows = overview @@ -6330,6 +6446,11 @@ fn default_daemon_tool_result_ref( "cultmesh://epiphany-local/daemon-status/{}", capability.host_daemon_id ) + } else if is_eve_connect_capability(capability) { + format!( + "cultmesh://epiphany-local/eve-surface/{}", + capability.host_cluster_id + ) } else { format!("cultmesh://epiphany-local/tool-receipt/{receipt_id}") } @@ -6349,6 +6470,11 @@ fn default_daemon_tool_result_summary( "{requesting_agent_id} requested daemon status; {} returned compact topology/liveness/tool readback through the daemon tool bus.", capability.host_daemon_id ) + } else if is_eve_connect_capability(capability) { + format!( + "{requesting_agent_id} requested Eve surface connection readback; {} returned compact CultMesh surface routing for {}.", + capability.host_daemon_id, capability.host_cluster_id + ) } else { format!( "{} accepted typed invocation routing for {}.", @@ -6371,6 +6497,13 @@ fn is_daemon_status_capability(capability: &EpiphanyCultMeshDaemonToolCapability && capability.receipt_contract_type == "epiphany.cultmesh.tool_status_receipt" } +fn is_eve_connect_capability(capability: &EpiphanyCultMeshDaemonToolCapabilityEntry) -> bool { + capability.tool_name == "eve-connect" + && capability.operation == "submitEveConnectionIntent" + && capability.input_contract_type == "epiphany.cultmesh.eve_connection_intent" + && capability.receipt_contract_type == "epiphany.cultmesh.eve_connection_receipt" +} + fn poke_result_tui_row(row: &serde_json::Value) -> String { let target_display_name = row["targetDisplayName"].as_str().unwrap_or("unknown"); let target_daemon_id = row["targetDaemonId"].as_str().unwrap_or("unknown"); diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 07896619..41b14db1 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -41,7 +41,7 @@ remembers doctrine; the branch remembers the blade. - This Codex operator's own roadmap/todo posture has been retuned for this scale target, with the Epiphany Imagination specialist as an optional sub-agent rail rather than the whole point. `notes/epiphany-investor-readiness-roadmap.md` now says: make the local Mom MVP a repeatable proof bundle; build the Bifrost-first external-work bridge; add compute/review/accepted-artifact accounting; prove fresh-repo operation without supervisor contamination; keep public/operator-safe exports sealed; and treat angel capital as fuel for capacity, not command authority. The Imagination specialist prompt was also updated so investor-scale Objective Drafts must name Bifrost provenance, bounded Epiphany proof, maintainer review, receipts/ledger evidence, compute/output metrics, public/private export safety, consent, and legal/security gates. - Local operator status runs now write typed CultMesh operator witnesses into `.epiphany-run/cultmesh/local-verse.ccmp`: `epiphany-operator-run` records the run intent before acting, `epiphany-operator-snapshot` distills the operator-safe MVP status artifact, and `epiphany-operator-run` records the completion receipt after success. The final `local-verse-context.json` is queried after those witnesses exist, so the operator read path sees latest run intent, snapshot, and receipt from the same local Verse vessel instead of treating separate JSON artifacts or side stores as truth. - `epiphany-operator-snapshot from-status` also mirrors the latest native status `tools.invocations[]` row into the same local Verse as `epiphany.cultmesh.daemon_tool_invocation_intent.v0`, plus `epiphany.cultmesh.daemon_tool_invocation_receipt.v0` when runtime-spine has a receipt id. Runtime-spine remains the tool lifecycle owner and raw MCP JSON stays quarantined behind `epiphany.tool_invocation_intent.v0` / `epiphany.tool_invocation_receipt.v0`; the local Verse mirror is operator-safe routing/readback. -- `epiphany-verse-query invoke-tool --capability-id ` now exercises the same global daemon tool directory directly: it records a typed daemon tool invocation intent plus receipt from an advertised capability and reports requesting/host display names, body domains, private Verse ids, and Eve surfaces from cluster topology, while the target daemon remains the execution owner and private Verse payloads stay sealed. `tools/epiphany_local_run.ps1 -Mode tool-invoke` wraps that same receipt path with explicit capability/requester/intent/receipt parameters, so operator use follows the same daemon-owned contract instead of a wrapper-owned shortcut. Tool routing reads the target daemon's typed liveness status and refuses when the host daemon is not `ready` or does not advertise `submitTypedToolIntent`. `epiphany-verse-query daemon-status --daemon-id --daemon-status ready|down|degraded` updates one daemon's status without repainting the whole status table, and local Verse seeding preserves existing daemon statuses and swarm-brake state instead of overwriting live telemetry. The CLI proof used Persona requesting Hands `repo-action` through `epiphany.cluster.hands.tool.repo-action`, returned Persona/Hands topology metadata, and refused the same invocation when Hands was degraded; the wrapper proof used stable ids `daemon-tool-intent-wrapper-persona-hands` / `daemon-tool-receipt-wrapper-persona-hands` and returned `availableToAllAgents=true`, `requiresReceipt=true`, and `privateStateExposed=false`. The invocation command body is now extracted out of the monolithic CLI `main` so compact row work does not tip the Windows debug stack; live wrapper artifact `local-20260618-181426-520-e3b051b8` routed Persona to Hands `repo-action` and printed one compact `INVOKE` row with requester/host private Verses, Eve surfaces, host daemon id, operation, capability, intent, receipt/status, authority, all-agents, receipt-required, and `private=false`. Status tools now embed `daemonStatusReadback` in the invocation JSON, carrying compact topology/liveness/tool-count fields and private-state seals; live wrapper proof `local-20260619-015644-193-d31ca95c` routed Persona to Hands `status` and printed `daemonStatus=status=ready:cluster=epiphany.cluster.hands:daemon=epiphany-daemon-hands:surface=eve://epiphany/hands:tools=3:private=False`. The Self-hosted `service-health` tool embeds `serviceHealthReadback`, carrying Idunn service lifecycle attention rows, service action rows, failed-check rows, and private-state seals from the same local Verse; production and smoke share `service_health_readback_from_idunn`, and source smoke rejects any payload that loses Idunn owner/hosted-body fields, service lifecycle/action rows, failed-check anatomy, or the private-state seal. Live wrapper proof `local-20260619-015010-170-38e1c830` printed `serviceHealth=status=attention:attentionRows=2:actionRows=4:failedChecks=11:missingChecks=0:private=False`. +- `epiphany-verse-query invoke-tool --capability-id ` now exercises the same global daemon tool directory directly: it records a typed daemon tool invocation intent plus receipt from an advertised capability and reports requesting/host display names, body domains, private Verse ids, and Eve surfaces from cluster topology, while the target daemon remains the execution owner and private Verse payloads stay sealed. `tools/epiphany_local_run.ps1 -Mode tool-invoke` wraps that same receipt path with explicit capability/requester/intent/receipt parameters, so operator use follows the same daemon-owned contract instead of a wrapper-owned shortcut. Tool routing reads the target daemon's typed liveness status and refuses when the host daemon is not `ready` or does not advertise `submitTypedToolIntent`. `epiphany-verse-query daemon-status --daemon-id --daemon-status ready|down|degraded` updates one daemon's status without repainting the whole status table, and local Verse seeding preserves existing daemon statuses and swarm-brake state instead of overwriting live telemetry. The CLI proof used Persona requesting Hands `repo-action` through `epiphany.cluster.hands.tool.repo-action`, returned Persona/Hands topology metadata, and refused the same invocation when Hands was degraded; the wrapper proof used stable ids `daemon-tool-intent-wrapper-persona-hands` / `daemon-tool-receipt-wrapper-persona-hands` and returned `availableToAllAgents=true`, `requiresReceipt=true`, and `privateStateExposed=false`. The invocation command body is now extracted out of the monolithic CLI `main` so compact row work does not tip the Windows debug stack; live wrapper artifact `local-20260618-181426-520-e3b051b8` routed Persona to Hands `repo-action` and printed one compact `INVOKE` row with requester/host private Verses, Eve surfaces, host daemon id, operation, capability, intent, receipt/status, authority, all-agents, receipt-required, and `private=false`. Status tools embed `daemonStatusReadback`, carrying compact topology/liveness/tool-count fields and private-state seals; live wrapper proof `local-20260619-015644-193-d31ca95c` routed Persona to Hands `status` and printed `daemonStatus=status=ready:cluster=epiphany.cluster.hands:daemon=epiphany-daemon-hands:surface=eve://epiphany/hands:tools=3:private=False`. Eve connection tools embed `eveConnectionReadback`, carrying target surface routing, public discussion eligibility, supported actions, connection commands, feedback route, and private-state seals while the dedicated `connect-eve` path remains the receipt writer; live wrapper proof `local-20260619-020458-304-b180a17c` routed Persona to Persona `eve-connect` and printed `eveConnection=target=epiphany.cluster.persona:surface=eve://epiphany/persona:publicDiscussion=True:actions=3:private=False`. The Self-hosted `service-health` tool embeds `serviceHealthReadback`, carrying Idunn service lifecycle attention rows, service action rows, failed-check rows, and private-state seals from the same local Verse; production and smoke share `service_health_readback_from_idunn`, and source smoke rejects any payload that loses Idunn owner/hosted-body fields, service lifecycle/action rows, failed-check anatomy, or the private-state seal. Live wrapper proof `local-20260619-015010-170-38e1c830` printed `serviceHealth=status=attention:attentionRows=2:actionRows=4:failedChecks=11:missingChecks=0:private=False`. - `epiphany-verse-query swarm-overview` and `epiphany-verse-query swarm-triage` now publish direct and wrapper command hints for the compact operator paths: topology, liveness, surfaces, tool directory, receipt directory, poke-down, Eve connection, Bifrost ledger readback, and `wrapperInvokeTool=tools/epiphany_local_run.ps1 -Mode tool-invoke -ToolCapabilityId -ToolRequestingAgentId -ToolRequestingClusterId `. The hints are display/ergonomics only; daemon-hosted tool invocation still routes through the typed intent/receipt path and host-daemon liveness gate, Bifrost ledger readback still reads Bifrost/Imagination-owned receipts, and receipt directory readback only indexes latest sealed local Verse witnesses. - `epiphany-daemon-supervisor policy --daemon-id --restart-command [--restart-arg ...]` writes durable local Verse restart policy as `epiphany.cultmesh.daemon_restart_policy.v0` with command/args/cwd/cooldown/backoff/attempt state, reconcile cadence, stale-heartbeat threshold, and last scheduled pulse. `epiphany-daemon-supervisor reconcile --daemon-id ` loads that policy when no override command is supplied, refuses under a matching `daemon.lifecycle_poke` brake before launching anything, refuses during cooldown/backoff, writes daemon poke intent/receipt documents, updates daemon status to `ready` or `down` from the command exit, and updates policy attempt state. `epiphany-daemon-supervisor tick [--daemon-id ]` is an explicit scheduler pulse: it scans durable policies, records ready/noop pulses, skips before the configured interval, marks stale heartbeat status degraded, routes restarts through the same brake/cooldown/poke receipt path, and writes latest `epiphany.cultmesh.daemon_scheduler_receipt.v0`. `epiphany-daemon-supervisor serve` runs that same pulse on `--loop-interval-seconds`, with bounded `--max-iterations` proof mode or unbounded service mode. `epiphany-daemon-supervisor service-plan`/`install-service` writes a planned local Verse `epiphany.cultmesh.daemon_service_lifecycle_receipt.v0` for the `serve` command; `service-launch`/`start-service` spawns that 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` writes a PowerShell operator runbook artifact for the same `serve` command and records it as a lifecycle receipt without spawning; `windows-service-install`/`service-install-plan` writes a Windows `sc.exe create` install script for that same `serve` command and records a lifecycle receipt, with optional `--execute-install` reserved for explicit elevated authority; `windows-service-status`, `windows-service-reconcile`, `windows-service-execution-readiness`, `windows-service-execution-audit`, `windows-service-execution-runbook`, `windows-service-start`, and `windows-service-stop` query/request/audit/document the Windows service manager path and record lifecycle receipts for missing/running/stopped/query-failed, in-sync/drift/missing/query-failed, elevated-ready/not-elevated, complete/incomplete, runbook written, start/stop planned, execution-refused-not-elevated, or start/stop requested/failed outcomes. `tools/epiphany_local_run.ps1 -Mode service-runbook`, `-Mode service-install-plan`, `-Mode service-install-execute`, `-Mode service-status`, `-Mode service-reconcile`, `-Mode service-execution-readiness`, `-Mode service-execution-runbook`, `-Mode service-execution-audit`, `-Mode service-start-plan`, `-Mode service-stop-plan`, `-Mode service-start-execute`, and `-Mode service-stop-execute` wrap the artifact/status/reconcile/readiness/runbook/audit/control-plan/execution paths with operator run intent/receipt and final local Verse context. Service lifecycle actions check the local Verse swarm brake before spawning, writing runbook/install artifacts, querying service-manager state, reconciling service policy, checking execution readiness, auditing execution receipts, planning control, or requesting start/stop. The local wrapper builds/checks this binary with the other Epiphany operator tools. Installed-service status reconciliation has now been proved read-only against the real Windows `EventLog` service: `service-status` wrote `daemon-service-lifecycle-receipt-windows-eventlog-proof-windows-service-status` with status `running`, exit code `0`, and `privateStateExposed=false`. The new read-only policy reconciliation path was also proved: direct missing-service reconcile wrote `missing`, direct real-service reconcile wrote `drift`, brake engagement refused before query with exit `1`, and wrapper `service-reconcile` wrote `daemon-service-lifecycle-receipt-windows-eventlog-reconcile-proof-windows-service-reconcile` with status `drift`, exit code `0`, artifact ref `service-manager://windows/EventLog/reconcile`, and `privateStateExposed=false`. Start/stop now plan by default unless `--execute-control`/`--execute-service-control` is passed: direct start/stop wrote `start-planned`/`stop-planned` with `executed=false`, wrapper `service-start-plan` and `service-stop-plan` wrote local Verse receipts against `EventLog`, and brake engagement refused the plan path before any control action. Explicit execution is also elevation-gated before mutation: non-elevated `--execute-control` and `--execute-install` wrote `execution-refused-not-elevated` lifecycle receipts with `executed=false`, and a matching brake still refuses before the elevation check. Execution readiness is queryable without mutation: direct and wrapper `windows-service-execution-readiness` wrote `not-elevated` receipts for `EventLog`, with `privateStateExposed=false`, and brake engagement refused readiness as lifecycle activity. The explicit wrapper execution modes have also been proved in this non-elevated shell: `service-install-execute`, `service-start-execute`, and `service-stop-execute` reached the elevation gate, wrote `execution-refused-not-elevated` receipts, and did not mutate Windows services. Execution audit is now the post-run proof target: it scans service lifecycle receipts through CultMesh typed enumeration, writes its own audit receipt, and returns `complete` only when the sealed `windows-service-execution-runbook` witness plus elevated-ready/install/start/status/reconcile/stop effect receipts are present, successful, and sealed. Audit check rows carry `operatorArtifactRef`, and wrapper audit summaries print OK runbook witnesses with local SHA-256 before failed checks. Focused test `service_execution_audit_checks_expose_operator_artifact_refs` proves the typed field; live cluster wrapper proof `local-20260618-170322-330-e6cb2117` printed the cluster runbook witness hash while still reporting the five expected failed checks. This is a durable policy-backed process-owner seam; the remaining scar is an actual elevated install/start/stop execution proof under operator authority followed by a `complete` audit receipt. - `tools/epiphany_local_run.ps1 -Mode service-execution-runbook` writes a non-mutating `#Requires -RunAsAdministrator` PowerShell artifact that sequences `service-execution-readiness`, `service-install-execute`, `service-start-execute`, `service-status`, `service-reconcile`, `service-stop-execute`, final `service-status`, and `service-execution-audit` through the existing typed wrapper modes, then asks `epiphany-daemon-supervisor windows-service-execution-runbook` to seal the artifact as a `written` lifecycle receipt. The artifact now uses `Invoke-EpiphanyRunbookStep` so each step resets `$LASTEXITCODE`, catches thrown/nonzero failures, keeps running to gather more lifecycle receipts, runs `service-execution-audit` in `finally`, and exits nonzero only after the audit if any step failed. Latest proof `local-20260618-160641-685-331af57c` generated and parsed the artifact with `privateStateExposed=false`; the next elevated scar is to run it under explicit operator authority and preserve its effect receipts. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index c2ff7e24..b735ab6c 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index 8e3d1b29..99b62b90 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -123,7 +123,7 @@ active_subgoals: accepted_design: - Distributed Epiphany dreaming is a CultMesh typed-document problem, not prompt folklore. CultCache owns local typed documents, Epiphany owns export/import/adoption policy, CultNet owns wire/provenance/shard delivery, and CultMesh owns Verses, peer exchange, leases, shard logs, replicas, and watchable runtime surfaces. Start with local dream document types and a local store before public Verse wiring. - - The local CultMesh daemon tool directory now has both discovery and invocation receipts at the operator edge. `epiphany-verse-query tools` lists globally available, receipt-gated daemon capabilities; `epiphany-verse-query invoke-tool --capability-id ` records `epiphany.cultmesh.daemon_tool_invocation_intent.v0` plus `epiphany.cultmesh.daemon_tool_invocation_receipt.v0` from the advertised capability, reports requesting/host display names, body domains, private Verse ids, and Eve surfaces from cluster topology, and refuses when the host daemon is not ready. `tools/epiphany_local_run.ps1 -Mode tool-invoke` wraps the same path with explicit requester/capability/intent/receipt parameters; wrapper proof routed Persona to Hands `repo-action` and returned `availableToAllAgents=true`, `requiresReceipt=true`, and `privateStateExposed=false`. Tool availability is global across local agents, but execution and authority remain with the hosting daemon and its typed receipt contract. Status tools now embed `daemonStatusReadback` with host cluster id, daemon status, body domain/kind, private Verse id, Eve surface, hosted tool capability ids, and private-state seal; live wrapper proof `local-20260619-015644-193-d31ca95c` routed Persona to Hands `status` and printed `daemonStatus=status=ready:cluster=epiphany.cluster.hands:daemon=epiphany-daemon-hands:surface=eve://epiphany/hands:tools=3:private=False`. The Self-hosted `service-health` tool now embeds `serviceHealthReadback` in the invocation result instead of only pointing at receipt-directory: live wrapper proof `local-20260619-013750-366-f5ad69b0` returned status `attention`, two service lifecycle attention rows, four service action rows, eleven failed checks, zero missing checks, and no private-state exposure. Production invocation and source smoke now share `service_health_readback_from_idunn`, and the smoke rejects payloads that lose Idunn ownership, service lifecycle/action rows, failed-check anatomy, or the private-state seal. + - The local CultMesh daemon tool directory now has both discovery and invocation receipts at the operator edge. `epiphany-verse-query tools` lists globally available, receipt-gated daemon capabilities; `epiphany-verse-query invoke-tool --capability-id ` records `epiphany.cultmesh.daemon_tool_invocation_intent.v0` plus `epiphany.cultmesh.daemon_tool_invocation_receipt.v0` from the advertised capability, reports requesting/host display names, body domains, private Verse ids, and Eve surfaces from cluster topology, and refuses when the host daemon is not ready. `tools/epiphany_local_run.ps1 -Mode tool-invoke` wraps the same path with explicit requester/capability/intent/receipt parameters; wrapper proof routed Persona to Hands `repo-action` and returned `availableToAllAgents=true`, `requiresReceipt=true`, and `privateStateExposed=false`. Tool availability is global across local agents, but execution and authority remain with the hosting daemon and its typed receipt contract. Status tools now embed `daemonStatusReadback` with host cluster id, daemon status, body domain/kind, private Verse id, Eve surface, hosted tool capability ids, and private-state seal; live wrapper proof `local-20260619-015644-193-d31ca95c` routed Persona to Hands `status` and printed `daemonStatus=status=ready:cluster=epiphany.cluster.hands:daemon=epiphany-daemon-hands:surface=eve://epiphany/hands:tools=3:private=False`. Eve connection tools now embed `eveConnectionReadback` with target cluster/surface, public discussion eligibility, supported actions, connection command, wrapper connection command, feedback route, and private-state seal while leaving actual connection receipt creation to `connect-eve`; live wrapper proof `local-20260619-020458-304-b180a17c` routed Persona to Persona `eve-connect` and printed `eveConnection=target=epiphany.cluster.persona:surface=eve://epiphany/persona:publicDiscussion=True:actions=3:private=False`. The Self-hosted `service-health` tool now embeds `serviceHealthReadback` in the invocation result instead of only pointing at receipt-directory: live wrapper proof `local-20260619-013750-366-f5ad69b0` returned status `attention`, two service lifecycle attention rows, four service action rows, eleven failed checks, zero missing checks, and no private-state exposure. Production invocation and source smoke now share `service_health_readback_from_idunn`, and the smoke rejects payloads that lose Idunn ownership, service lifecycle/action rows, failed-check anatomy, or the private-state seal. - The local Verse swarm brake is now operator-writable from the same CLI surface and enforced at the main local wrapper plus direct coordinator/heartbeat runner edges. `epiphany-verse-query swarm-brake --brake-status engaged|released` writes the typed `epiphany.cultmesh.swarm_brake.v0` document with scope, reason, operator id, affected clusters, protected surfaces, expiry, and private-state seal. `tools/epiphany_local_run.ps1` queries that document before live `plan`, `run`, or `mvp` work and fails closed when engaged; `status` remains readable. `epiphany-mvp-coordinator --local-verse-store ` refuses before app-server startup when the brake is engaged, and `epiphany-heartbeat-store tick|pump|heat|queue-mention|routine --local-verse-store ` refuses heartbeat-driving work while leaving init/status/complete/repair-stale outside that live-run brake. - The first Rust CultMesh integration slice is landed and repaired to compile from repo-contained vendored crates. `vendor/cultmesh-rs` is a small Rust node/database facade over vendored CultCache and CultNet with document-set registration and durable typed put/get/delete. `vendor/cultcache-rs` now reads and writes the `cultcache.store.v1` snapshot format used by `state/ledgers.msgpack`, so `epiphany-state status` is a working re-entry rite again. `epiphany-core` depends on `vendor/cultcache-rs`, `vendor/cultnet-rs`, and `vendor/cultmesh-rs`, exposes an `EpiphanyCultMeshStatusEntry`, records typed `EpiphanyCultMeshVersePolicyEntry` documents for the internal/local-area/global Verse tiers, and records typed `EpiphanyCultMeshGlobalRoomPolicyEntry` documents for threaded public global rooms such as dreams, architecture, research, Personas, GameCult, and governance. Native operator status is now a typed `EpiphanyCultMeshOperatorStatusEntry` in the internal Verse; it names Codex as bridge transport, Epiphany as authority owner, prompt-authority separation, and the quarantined Rider/Unity optional surfaces. Native operator snapshots are typed `EpiphanyCultMeshOperatorSnapshotEntry` documents distilled from operator-safe status artifacts; local status runs write operator run intent, operator snapshot, and run receipt into `.epiphany-run/cultmesh/local-verse.ccmp`, leaving JSON artifacts as display/evidence rather than the local-run read authority. - Mind's CultNet contract surface is native enough for the next Aquarium/CultMesh cut: `epiphany-core::mind_gateway` defines thought, state-effect proposal, gateway-review, commit-receipt, rejection-receipt, and Verse-adoption document contracts; runtime-spine advertises those mutation/read contracts; CultMesh persists matching `EpiphanyCultMeshMindContractEntry` policy documents so the private state guardian boundary is inspectable as typed state. @@ -618,7 +618,7 @@ current_status: - `epiphany-verse-query restart-policy-directory` and `tools/epiphany_local_run.ps1 -Mode service-policy-directory` provide the compact scheduler coverage sight organ. It reads daemon topology/status plus durable `epiphany.cultmesh.daemon_restart_policy.v0` rows through a narrow CultMesh restart-policy directory loader, reports each daemon as `ENABLED`, `DISABLED`, or `MISSING`, treats disabled and missing policies as recovery attention, returns covered/enabled/disabled/missing/attention counts, and publishes explicit policy-write plus scheduler-tick follow-up commands without creating or mutating policies. Compact TUI rows now expose `owner=Idunn`, `hostedBody=Epiphany`, cooldown, reconcile interval, heartbeat stale threshold, failure count, last result, `followUp=`, and `private=false`; wrapper proof `local-20260619-003720-135-799146f3` prints the Rust-owned `tuiRows` directly for all seven faculties as `ENABLED` with `owner=Idunn`, `hostedBody=Epiphany`, `last=ready`, `cooldown=30s`, `reconcile=60s`, `stale=300s`, `followUp=tools/epiphany_local_run.ps1 -Mode service-tick`, and `private=false`, instead of rebuilding policy text in PowerShell. Direct and wrapper proof now report seven daemons, seven covered policies, seven enabled policies, zero disabled, zero missing, zero attention, `status=ok`, `lifecycleOwner=Idunn`, `hostedBody=Epiphany`, and `privateStateExposed=false`. This is a real Idunn-owned daemon heartbeat body with non-mutating per-organ launch and install artifacts, but not yet executed installed per-organ OS services. - `https://gamecult.org/Blog/purge-the-heretek-from-our-daemonic-swarm` is a public doctrine receipt for the Perfect Machine audit pressure: organs must not borrow each other's crowns, witnesses need owning mouths, surfaces reflect rather than rule, and cross-repo purification needs Bifrost-shaped ledger evidence instead of relying on recoverable transcripts or commit trails alone. - `tools/epiphany_local_run.ps1` now uses collision-resistant local run ids (`local-YYYYMMDD-HHMMSS-fff-`) for artifact roots and operator run receipts. Same-second parallel compact wrapper proofs for `collaboration-feedback` and `bifrost-publication` produce separate artifact drawers and both complete, so operator rites no longer collide on second-resolution run ids. - - `epiphany-verse-query tool-directory` and `tools/epiphany_local_run.ps1 -Mode tool-directory` provide the compact daemon tool sight organ over the same local Verse capability records used by `invoke-tool`. It returns seventeen globally available daemon-hosted capabilities, host readiness counts, direct `invocationCommand`, wrapper `wrapperInvocationCommand=tools/epiphany_local_run.ps1 -Mode tool-invoke -ToolCapabilityId -ToolRequestingAgentId -ToolRequestingClusterId `, and the invariants `availableToAllAgents=true`, `requiresReceipt=true`, `privateStateExposed=false`. Agent-friendly TUI rows now carry the same contract bits, authority gate, and advertised payload/review contract types, e.g. `READY | Hands | repo-action | submitHandsActionIntent | epiphany.cluster.hands.tool.repo-action | eve://epiphany/hands | authority=hands | input=epiphany.hands.action_intent | receiptType=epiphany.hands.action_review | allAgents=true | receipt=true | private=false`; wrapper proof `local-20260618-233719-320-e38a5549` prints all seventeen rows in the one-line `toolRows` summary, including Self `service-health` as `readServiceLifecycleStatus` with `authority=daemon.service_lifecycle`, `input=epiphany.cultmesh.daemon_service_lifecycle_query`, and `receiptType=epiphany.cultmesh.daemon_service_lifecycle_receipt`, plus Eve connection tools, Hands `repo-action`, and Soul `verify`. `invoke-tool` runs through a smaller extracted command handler and emits compact invocation rows with requester/host display names, requesting/host private Verses and Eve surfaces, host daemon id, tool operation, capability id, intent id, receipt id/status, authority gate, `allAgents=true`, `receiptRequired=true`, and `private=false`; status invocation additionally embeds `daemonStatusReadback` with compact topology/liveness/tool-count fields, while service-health invocation embeds `serviceHealthReadback` with Idunn lifecycle attention/action/failed-check rows, so agents get useful readback through the advertised daemon tool without opening full local Verse state. + - `epiphany-verse-query tool-directory` and `tools/epiphany_local_run.ps1 -Mode tool-directory` provide the compact daemon tool sight organ over the same local Verse capability records used by `invoke-tool`. It returns seventeen globally available daemon-hosted capabilities, host readiness counts, direct `invocationCommand`, wrapper `wrapperInvocationCommand=tools/epiphany_local_run.ps1 -Mode tool-invoke -ToolCapabilityId -ToolRequestingAgentId -ToolRequestingClusterId `, and the invariants `availableToAllAgents=true`, `requiresReceipt=true`, `privateStateExposed=false`. Agent-friendly TUI rows now carry the same contract bits, authority gate, and advertised payload/review contract types, e.g. `READY | Hands | repo-action | submitHandsActionIntent | epiphany.cluster.hands.tool.repo-action | eve://epiphany/hands | authority=hands | input=epiphany.hands.action_intent | receiptType=epiphany.hands.action_review | allAgents=true | receipt=true | private=false`; wrapper proof `local-20260618-233719-320-e38a5549` prints all seventeen rows in the one-line `toolRows` summary, including Self `service-health` as `readServiceLifecycleStatus` with `authority=daemon.service_lifecycle`, `input=epiphany.cultmesh.daemon_service_lifecycle_query`, and `receiptType=epiphany.cultmesh.daemon_service_lifecycle_receipt`, plus Eve connection tools, Hands `repo-action`, and Soul `verify`. `invoke-tool` runs through a smaller extracted command handler and emits compact invocation rows with requester/host display names, requesting/host private Verses and Eve surfaces, host daemon id, tool operation, capability id, intent id, receipt id/status, authority gate, `allAgents=true`, `receiptRequired=true`, and `private=false`; status invocation embeds `daemonStatusReadback` with compact topology/liveness/tool-count fields, Eve connection invocation embeds `eveConnectionReadback` with compact CultMesh surface routing and collaboration commands, and service-health invocation embeds `serviceHealthReadback` with Idunn lifecycle attention/action/failed-check rows, so agents get useful readback through the advertised daemon tool without opening full local Verse state. - `epiphany-verse-query cluster-topology` and `tools/epiphany_local_run.ps1 -Mode cluster-topology` provide the compact cluster/body/private-Verse/daemon sight organ over local Verse topology rows through a narrow CultMesh loader. The report returns seven clusters, seven private Verse ids, seven daemon ids, one public Persona discussion cluster, agent-friendly TUI rows such as `PUBLIC | Persona | cluster=epiphany.cluster.persona | role=Persona | privateVerse=epiphany.cluster.persona.private | body=repo:E:/Projects/EpiphanyAgent | bodyKind=repository | daemon=epiphany-daemon-persona | surface=eve://epiphany/persona`, and `privateStateExposed=false`; `epiphany-verse-query smoke` source-proves the compact topology invariants, and wrapper proof `local-20260618-225347-337-cea74491` prints all seven standing-faculty rows in the one-line `topologyRows` summary. - `epiphany-verse-query swarm-overview` and `tools/epiphany_local_run.ps1 -Mode swarm-overview` provide the one-command compact global-agent sight rite. It composes narrow cluster topology, liveness, Odin/Eve surface, daemon tool, restart-policy coverage, receipt-directory service-lifecycle attention, and the shared core service-execution audit report without full local Verse serialization, returning seven agents/daemons, seven clusters, seven private Verse ids, seven Eve surfaces, one public Persona discussion surface, sixteen globally invokable receipt-gated tools, command hints for topology/liveness/surfaces/tools/receipts/poke/connect/invoke/Bifrost-ledger/restart-policy coverage, wrapper command hints for overview/swarm-online-runbook/receipts/poke/connect/tool-invoke/Bifrost-ledger/service-policy-directory/service-execution-audit, sealed `toolHostAttentionRows`/TUI rows for blocked daemon-hosted capabilities, sealed `serviceLifecycleAttentionRows`/TUI rows copied from the receipt directory, `serviceExecutionFailedCheckRows`/TUI rows naming failed sealed execution checks, explicit `serviceLifecycleRecommended*` fields so service-manager follow-up remains visible even when global `recommendedWrapperMode` is occupied by liveness or policy, and ordered `swarmActionRows`/TUI rows with authority gates, effect class, wrapper command, mutation flag, elevation flag, sealed `operatorArtifactRef`, `operatorArtifactStatus`, `operatorArtifactSha256`, `operatorArtifactExecutionCommand`, `operatorAftercareCommand`, and `completionAuditWrapper*` for operator-runbook rows. Compact action TUI rows now also render `aftercare=`, so the Rust-owned row itself names the post-run audit command instead of relying on wrapper compatibility summaries. Current live overview `local-20260619-001128-955-195f4e65` returns `status=attention`, `livenessStatus=ready`, `recoveryStatus=attention`, `recommendedWrapperMode=swarm-online-runbook`, `recommendedWrapperCommand=tools/epiphany_local_run.ps1 -Mode swarm-online-runbook`, `serviceLifecycleRecommendedWrapperMode=cluster-service-execution-audit`, `toolHostAttentionCount=0`, `serviceLifecycleAttentionCount=2`, `swarmActionCount=4`, non-mutating service lifecycle readback rows with `aftercare=none`, and elevated service authority rows with `aftercare=tools/epiphany_local_run.ps1 -Mode cluster-service-execution-audit` / `aftercare=tools/epiphany_local_run.ps1 -Mode service-execution-audit`, present runbook artifacts, SHA-256 provenance, failed/missing check counts, and `privateStateExposed=false`. `tools/epiphany_local_run.ps1 -Mode swarm-online-runbook` now prints and stores the swarm-level elevated command for its generated Idunn-owned artifact, and the generated parent runbook verifies each child runbook artifact exists and matches its advertised SHA-256 before launching it elevated, then runs aftercare audits through the known wrapper `ScriptPath` plus explicit argument arrays instead of string evaluation. The operator sees the exact `Start-Process PowerShell -Verb RunAs -Wait ...` command, parent artifact hash, child hash guard, aftercare, owner, hosted body, and private-state seal before granting service mutation authority; the wrapper JSON also carries structured `childRunbookRows` and `aftercareRows` with service ids, routes, SHA-256s, audit modes, authority gates, failed-check counts, and private-state seals. Live proof `local-20260619-013021-159-c93088be` generated the parent artifact with two child rows, two aftercare rows, `usesExplicitAftercareArguments=true`, no `Invoke-Expression`, child hash guards, and wrapper-path aftercare calls. If a local runbook artifact is missing, source smoke proves the same row is demoted to `status=runbook-artifact-missing`, `wrapperMode=cluster-service-execution-runbook`, `effectClass=service-lifecycle-runbook-regeneration`, `operatorArtifactSha256=none`, `operatorArtifactExecutionCommand=none`, `operatorAftercareCommand=none`, `mutatesState=false`, and `requiresElevatedAuthority=false` instead of pretending elevated service authority is actionable. Degraded daemon overview still routes global recommendation to `swarm-poke-down` first while independent action rows preserve the liveness/tool-host duties; liveness action rows are explicitly mutating typed lifecycle pokes but do not require elevation, while service execution authority rows make the operator grant boundary visible. `epiphany-verse-query` defaults to the shared `.epiphany-run\cultmesh\local-verse.ccmp` store for live query/readback, while bare `epiphany-verse-query smoke` now uses a disposable `.epiphany-smoke\verse-query-default\local-verse.ccmp` fixture unless an explicit `--store` is provided. - `epiphany-verse-query swarm-triage` and `tools/epiphany_local_run.ps1 -Mode swarm-triage` compose the compact swarm overview with the existing brake-aware daemon poke receipt writer. Triage pokes only daemon liveness attention; service-manager lifecycle wounds are reflected from overview as sealed `serviceLifecycleAttentionRows`/TUI rows, `serviceExecutionFailedCheckRows`/TUI rows, explicit `serviceLifecycleRecommended*` fields, and ordered `swarmActionRows`, but do not cause daemon poke receipts, while blocked daemon-hosted tools ride as sealed `toolHostAttentionRows`/TUI rows so agents can see which advertised capabilities are unavailable because their host body is sick. Current live triage `local-20260618-150015-844-aba20563` returns `status=noop`, `overviewStatus=attention`, `livenessStatus=ready`, `recoveryStatus=attention`, `clusterCount=7`, `privateVerseCount=7`, `pokedDaemonCount=0`, `recommendedWrapperMode=cluster-service-execution-audit`, `serviceLifecycleRecommendedWrapperMode=cluster-service-execution-audit`, `swarmActionCount=2`, the same sealed service readback plus operator-elevated runbook rows, including `operatorArtifactStatus=present`, `operatorArtifactRef=E:\Projects\EpiphanyAgent\.epiphany-run\local-20260618-132257-139-26213a29\epiphany-cluster-daemon-services-execution-runbook.ps1`, and `completionAuditWrapperCommand=tools/epiphany_local_run.ps1 -Mode cluster-service-execution-audit` on the elevated row, empty daemon/tool-host attention arrays, `serviceLifecycleAttentionCount=2`, routes `epiphany-cluster-daemon-services::cluster-windows-service-execution-audit` and `epiphany-daemon-supervisor-service::windows-service-execution-audit`, direct and wrapper command hints including `wrapperInvokeTool` and `wrapperBifrostLedger=tools/epiphany_local_run.ps1 -Mode bifrost-ledger`, and `privateStateExposed=false`; degraded Hands proof returns `status=ok`, `overviewStatus=attention`, topology and daemon TUI rows, blocked Hands-hosted tool rows, one sealed topology-aware poke receipt for `epiphany-daemon-hands` with `bodyDomain=repo:E:/Projects/EpiphanyAgent`, `privateVerseId=epiphany.cluster.hands.private`, `eveSurfaceId=eve://epiphany/hands`, `observedStatus=degraded`, `attentionDaemonIds=[epiphany-daemon-hands]`, `attentionToolHostDaemonIds=[epiphany-daemon-hands]`, and liveness/tool-host action rows with no private-state exposure. Source smoke `verse-query-service-execution-failed-checks-clean` proves a physical synthetic written runbook plus incomplete service audit receipts expose both service lifecycle readback and failed-check anatomy with no Windows service mutation. diff --git a/tools/epiphany_local_run.ps1 b/tools/epiphany_local_run.ps1 index c5c3b5ff..dd4199be 100644 --- a/tools/epiphany_local_run.ps1 +++ b/tools/epiphany_local_run.ps1 @@ -2074,7 +2074,11 @@ if ($resultPath -ne "" -and (Test-Path -LiteralPath $resultPath)) { if ($null -ne $result.daemonStatusReadback -and $null -ne $result.daemonStatusReadback.status) { $daemonStatus = "status=$($result.daemonStatusReadback.status):cluster=$($result.daemonStatusReadback.clusterId):daemon=$($result.daemonStatusReadback.daemonId):surface=$($result.daemonStatusReadback.eveSurfaceId):tools=$($result.daemonStatusReadback.hostedToolCount):private=$($result.daemonStatusReadback.privateStateExposed)" } - Write-Host "Tool invoke: status=$($result.status), requester=$($result.requestingDisplayName), host=$($result.hostDisplayName), tool=$($result.toolName), receipt=$($result.receiptId), daemonStatus=$daemonStatus, serviceHealth=$serviceHealth, invocationRows=$invocationRows, privateStateExposed=$($result.privateStateExposed)" + $eveConnection = "none" + if ($null -ne $result.eveConnectionReadback -and $null -ne $result.eveConnectionReadback.targetClusterId) { + $eveConnection = "target=$($result.eveConnectionReadback.targetClusterId):surface=$($result.eveConnectionReadback.targetEveSurfaceId):publicDiscussion=$($result.eveConnectionReadback.publicPersonaDiscussionAllowed):actions=$(@($result.eveConnectionReadback.supportedActions).Count):private=$($result.eveConnectionReadback.privateStateExposed)" + } + Write-Host "Tool invoke: status=$($result.status), requester=$($result.requestingDisplayName), host=$($result.hostDisplayName), tool=$($result.toolName), receipt=$($result.receiptId), daemonStatus=$daemonStatus, eveConnection=$eveConnection, serviceHealth=$serviceHealth, invocationRows=$invocationRows, privateStateExposed=$($result.privateStateExposed)" } elseif ($Mode -eq "swarm-overview" -or $Mode -eq "gjallar") { $attention = "none" if ($null -ne $result.attentionDaemonIds -and $result.attentionDaemonIds.Count -gt 0) {