Separate worker launch from bootstrap
This commit is contained in:
parent
74407daf8a
commit
f17a6d4585
7 changed files with 90 additions and 11 deletions
|
|
@ -20,15 +20,17 @@ use epiphany_core::query_epiphany_local_verse_context;
|
|||
use epiphany_core::render_epiphany_prompt_context;
|
||||
use epiphany_core::seed_epiphany_local_verse_context;
|
||||
use serde_json::json;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let store = env::args().nth(1).map(PathBuf::from).unwrap_or_else(|| {
|
||||
PathBuf::from(".epiphany-smoke")
|
||||
.join("cultmesh")
|
||||
.join("epiphany-prompt-context.ccmp")
|
||||
});
|
||||
if std::env::args().nth(1).is_some() {
|
||||
anyhow::bail!(
|
||||
"prompt-context smoke accepts no arguments and writes only beneath .epiphany-smoke"
|
||||
);
|
||||
}
|
||||
let store = PathBuf::from(".epiphany-smoke")
|
||||
.join("cultmesh")
|
||||
.join("epiphany-prompt-context.ccmp");
|
||||
if let Some(parent) = store.parent() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use crate::EpiphanyMemoryContextQuery;
|
|||
use crate::EpiphanyMemoryProfile;
|
||||
use crate::EpiphanyPromptContextInput;
|
||||
use crate::RuntimeHandsReceiptChainSummary;
|
||||
use crate::load_epiphany_cultmesh_cluster_topology;
|
||||
use crate::load_epiphany_cultmesh_status;
|
||||
use crate::load_latest_epiphany_cultmesh_work_loop_telemetry;
|
||||
use crate::load_memory_graph_snapshot;
|
||||
use crate::memory_graph_from_epiphany_graphs;
|
||||
|
|
@ -16,7 +18,6 @@ use crate::runtime_hands_command_receipt;
|
|||
use crate::runtime_hands_commit_receipt;
|
||||
use crate::runtime_hands_patch_receipt;
|
||||
use crate::runtime_latest_hands_receipt_chain_after;
|
||||
use crate::seed_epiphany_local_verse_context;
|
||||
use crate::write_epiphany_cultmesh_work_loop_telemetry;
|
||||
use crate::write_memory_graph_snapshot;
|
||||
use chrono::SecondsFormat;
|
||||
|
|
@ -72,17 +73,35 @@ pub fn render_launch_dynamic_prompt_context(
|
|||
focus: String,
|
||||
) -> Result<String, String> {
|
||||
let local_verse_store = local_verse_store_path(runtime_store_path);
|
||||
seed_epiphany_local_verse_context(
|
||||
load_epiphany_cultmesh_status(&local_verse_store, EPIPHANY_LOCAL_VERSE_RUNTIME_ID)
|
||||
.map_err(|error| {
|
||||
format!(
|
||||
"failed to inspect local Verse context store {}: {error}",
|
||||
local_verse_store.display()
|
||||
)
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"local Verse is not bootstrapped at {}; initialize it before building worker launch context",
|
||||
local_verse_store.display()
|
||||
)
|
||||
})?;
|
||||
let topology = load_epiphany_cultmesh_cluster_topology(
|
||||
&local_verse_store,
|
||||
EPIPHANY_LOCAL_VERSE_RUNTIME_ID,
|
||||
Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true),
|
||||
)
|
||||
.map_err(|error| {
|
||||
format!(
|
||||
"failed to seed local Verse context store {}: {error}",
|
||||
"failed to inspect local Verse topology store {}: {error}",
|
||||
local_verse_store.display()
|
||||
)
|
||||
})?;
|
||||
if topology.is_empty() {
|
||||
return Err(format!(
|
||||
"local Verse has no persisted cluster topology at {}; initialize it before building worker launch context",
|
||||
local_verse_store.display()
|
||||
));
|
||||
}
|
||||
let local_verse =
|
||||
query_epiphany_local_verse_context(&local_verse_store, EPIPHANY_LOCAL_VERSE_RUNTIME_ID)
|
||||
.map_err(|error| {
|
||||
|
|
@ -681,6 +700,7 @@ mod tests {
|
|||
use crate::put_hands_commit_receipt;
|
||||
use crate::put_hands_patch_receipt;
|
||||
use crate::runtime_worker_launch_request;
|
||||
use crate::seed_epiphany_local_verse_context;
|
||||
use epiphany_state_model::EpiphanyAcceptanceReceipt;
|
||||
use std::fs;
|
||||
use uuid::Uuid;
|
||||
|
|
@ -713,6 +733,11 @@ mod tests {
|
|||
objective: Some("Test launch context.".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
seed_epiphany_local_verse_context(
|
||||
local_verse_store_path(&runtime_store),
|
||||
EPIPHANY_LOCAL_VERSE_RUNTIME_ID,
|
||||
"2026-07-12T00:00:00Z",
|
||||
)?;
|
||||
|
||||
let rendered = render_launch_dynamic_prompt_context(
|
||||
&runtime_store,
|
||||
|
|
@ -771,6 +796,33 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_context_refuses_to_bootstrap_shared_state() -> anyhow::Result<()> {
|
||||
let temp = std::env::temp_dir().join(format!(
|
||||
"epiphany-launch-context-unbootstrapped-{}",
|
||||
Uuid::new_v4()
|
||||
));
|
||||
fs::create_dir_all(&temp)?;
|
||||
let runtime_store = temp.join("runtime-spine.msgpack");
|
||||
let local_verse_store = local_verse_store_path(&runtime_store);
|
||||
let state = EpiphanyThreadState {
|
||||
revision: 1,
|
||||
objective: Some("Prove launch assembly cannot initialize shared state.".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let error = render_launch_dynamic_prompt_context(
|
||||
&runtime_store,
|
||||
&state,
|
||||
role_launch_context_focus(&state, "modeling"),
|
||||
)
|
||||
.expect_err("unbootstrapped launch context must fail closed");
|
||||
|
||||
assert!(error.contains("local Verse is not bootstrapped"));
|
||||
assert!(!local_verse_store.exists());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verification_launch_context_includes_hands_receipt_chain() -> anyhow::Result<()> {
|
||||
let temp = std::env::temp_dir().join(format!("epiphany-hands-context-{}", Uuid::new_v4()));
|
||||
|
|
|
|||
|
|
@ -169,3 +169,21 @@ paths may initialize the local Verse. Every other mutating query command passes
|
|||
and refuses before store creation when either is absent. Requesters now write
|
||||
into an existing body; they cannot manufacture the body as a side effect of
|
||||
asking it for work.
|
||||
|
||||
## Launch-context/bootstrap split
|
||||
|
||||
The final implicit production caller was
|
||||
`render_launch_dynamic_prompt_context`. Building a worker launch packet seeded
|
||||
the sibling local Verse before reading it, so launch preparation owned shared
|
||||
policy, topology, contracts, brake initialization, and operator status.
|
||||
|
||||
Launch-context assembly now requires persisted Epiphany status and topology and
|
||||
fails before creating the Verse store when they are absent. Tests and the
|
||||
prompt-context smoke initialize their fixtures explicitly. The smoke no longer
|
||||
accepts an arbitrary output path; it writes only
|
||||
`.epiphany-smoke/cultmesh/epiphany-prompt-context.ccmp`.
|
||||
|
||||
The remaining non-test seed callers are now limited to the explicit Verse seed
|
||||
commands and two named, path-confined smoke fixture initializers. No production
|
||||
provider, supervisor, requester, diagnostic, or launch path bootstraps shared
|
||||
state as a convenience side effect.
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@
|
|||
quarantined smoke initialize local Verse state. Every operator/requester
|
||||
mutation requires persisted status and topology before writing its bounded
|
||||
brake, poke, tool, Eve, Bifrost, metrics, artifact, or feedback document.
|
||||
- Coordinator launch-context assembly also requires persisted status and
|
||||
topology. Rendering a worker prompt cannot initialize shared state. Its
|
||||
standalone smoke accepts no path arguments and writes only beneath
|
||||
`.epiphany-smoke`.
|
||||
- Store/runtime overrides fail before fixture seeding or receipt construction.
|
||||
- Negative proof: targeting `state/local-verse.ccmp` was rejected and its SHA-256 did not change.
|
||||
- Positive proof: the built-in quarantined smoke completes successfully and reports its quarantine coordinates.
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ The confirmed conceptual substitutions have been cut:
|
|||
- query-CLI requester/operator mutations also require persisted bootstrap.
|
||||
Only explicit seed commands and the fixed aggregate smoke may initialize the
|
||||
shared local Verse.
|
||||
- worker launch-context rendering requires the existing Verse and cannot seed
|
||||
it. The prompt-context smoke accepts no destination and is fixed beneath
|
||||
`.epiphany-smoke`.
|
||||
|
||||
The presentation boundary is now plain: `swarm overview` is a generic compact read-only projection. Gjallar is a downstream TUI application on Nightwing and is not an Epiphany organ, provider, owner, runtime, or architectural dependency. Eve/CultUI graphs may be lowered or composited downstream without Epiphany caring which presentation client does it.
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -70,7 +70,7 @@ data_flow:
|
|||
- move historical proof to git, commits, smoke artifacts, or distilled evidence rather than plan prose
|
||||
|
||||
active_subgoals:
|
||||
- Use `notes/conceptual-substitution-audit-2026-07-12.md` plus `notes/receipt-writer-provenance-audit-2026-07-12.md` as the current authority-corrosion maps. Snapshot promotion, synthetic smoke escape, unbound operator completion, hidden service execution flags, generic-bootstrap publication of provider advertisements/Eve surfaces/hosted tools, the central topology-derived Odin publisher, all-provider state writers, cluster-daemon bootstrap, daemon-supervisor production bootstrap, and requester/operator query-side bootstrap are cut. Provider absence survives bootstrap; only explicit seed/fixture paths initialize; each cluster daemon writes its own presence and pulse; Idunn and requester paths require the shared body rather than repainting it; synthetic seeding is quarantined. Next remove or test-gate dead public receipt constructors where provider binaries are absent and audit remaining projections, caches, schedulers, adapters, and non-receipt smokes for borrowed authority or path escape.
|
||||
- Use `notes/conceptual-substitution-audit-2026-07-12.md` plus `notes/receipt-writer-provenance-audit-2026-07-12.md` as the current authority-corrosion maps. Snapshot promotion, synthetic smoke escape, unbound operator completion, hidden service execution flags, provider/bootstrap collapse, the central topology-derived Odin publisher, all-provider writers, cluster-daemon bootstrap, daemon-supervisor production bootstrap, requester/operator query bootstrap, and launch-context bootstrap are cut. Only explicit seed commands and named path-confined fixtures initialize; providers, Idunn, requesters, diagnostics, and worker-launch assembly require the existing shared body. Next remove or test-gate dead public receipt constructors where provider binaries are absent and audit remaining projections, caches, schedulers, adapters, and non-receipt smokes for borrowed authority or path escape.
|
||||
- `swarm-overview` is an Epiphany-local, renderer-neutral diagnostic projection over provider-owned typed state. It owns no lifecycle, discovery, composition, or mutation authority. Epiphany publishes clean provider-owned Eve surfaces; Odin may discover them; downstream lowerers and compositors remain outside Epiphany's concern.
|
||||
- Idunn owns daemon survival and service lifecycle physiology. Codex/operator sessions may inspect, generate runbooks, and route explicit operator authority, but keeping daemons alive belongs to Idunn-owned service lifecycle receipts, scheduler policy, audits, and aftercare. Do not let Self, diagnostic projections, or ad hoc wrapper summaries become a second daemon-keeper. Global tool readbacks for Self `service-health`, `service-policy-directory`, and `swarm-online-runbook` state `lifecycleOwner=Idunn` and `hostedBody=Epiphany` without service mutation or private-state exposure.
|
||||
- Use `notes/epiphany-cultmesh-dreaming-roadmap.md` as the design authority for distributed Epiphany dreaming. Public dreams are separately authored typed documents distributed through CultMesh/CultNet; private state remains local and cannot be shared by flipping a visibility flag. Foreign dreams are external thought weather until a reviewed local adoption receipt digests them into memory, planning, doctrine, or governance.
|
||||
|
|
|
|||
Reference in a new issue