Move coordinator role mutation native
This commit is contained in:
parent
cd7ed532dd
commit
b381a5f9e5
5 changed files with 138 additions and 18 deletions
|
|
@ -450,10 +450,11 @@ fn run_coordinator(args: &Args) -> Result<Value> {
|
|||
steps.push(step);
|
||||
break;
|
||||
}
|
||||
let accepted = client.send(
|
||||
"thread/epiphany/roleAccept",
|
||||
Some(json!({"threadId": thread_id, "roleId": role_id, "expectedRevision": revision})),
|
||||
true,
|
||||
let accepted = accept_role(
|
||||
&runtime_store,
|
||||
&thread_id,
|
||||
role_id,
|
||||
revision.and_then(|value| u64::try_from(value).ok()),
|
||||
)?;
|
||||
if let Some(memory) = maybe_apply_role_self_patch(&accepted, &agent_memory_dir)? {
|
||||
let mut accepted_with_memory = accepted.clone();
|
||||
|
|
@ -513,7 +514,7 @@ fn run_coordinator(args: &Args) -> Result<Value> {
|
|||
let role_id = role_id_for_coordinator_action(&action)
|
||||
.ok_or_else(|| anyhow!("unsupported launch action {action}"))?;
|
||||
let launch = launch_role(
|
||||
&mut client,
|
||||
&runtime_store,
|
||||
&thread_id,
|
||||
role_id,
|
||||
revision,
|
||||
|
|
@ -983,18 +984,106 @@ fn push_requested_path(paths: &mut Vec<String>, path: &str) {
|
|||
}
|
||||
|
||||
fn launch_role(
|
||||
client: &mut status_cli::AppServerClient,
|
||||
runtime_store: &Path,
|
||||
thread_id: &str,
|
||||
role_id: &str,
|
||||
expected_revision: Option<i64>,
|
||||
max_runtime_seconds: u64,
|
||||
) -> Result<Value> {
|
||||
let mut payload =
|
||||
json!({"threadId": thread_id, "roleId": role_id, "maxRuntimeSeconds": max_runtime_seconds});
|
||||
if let Some(revision) = expected_revision {
|
||||
payload["expectedRevision"] = json!(revision);
|
||||
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store, runtime_store);
|
||||
let state = service
|
||||
.state()?
|
||||
.ok_or_else(|| anyhow!("cannot launch role without native coordinator state"))?;
|
||||
let role = parse_role_id(role_id)?;
|
||||
let expected_revision = expected_revision.and_then(|value| u64::try_from(value).ok());
|
||||
let mut context = epiphany_core::render_launch_dynamic_prompt_context(
|
||||
runtime_store,
|
||||
&state,
|
||||
epiphany_core::role_launch_context_focus(&state, epiphany_core::epiphany_role_label(role)),
|
||||
)
|
||||
.map_err(anyhow::Error::msg)?;
|
||||
if role == epiphany_core::EpiphanyRoleResultRoleId::Verification {
|
||||
context = epiphany_core::append_verification_hands_receipt_context(
|
||||
context,
|
||||
runtime_store,
|
||||
&state,
|
||||
)
|
||||
.map_err(anyhow::Error::msg)?;
|
||||
} else if role == epiphany_core::EpiphanyRoleResultRoleId::Modeling {
|
||||
context = epiphany_core::append_modeling_work_loop_telemetry_context(
|
||||
context,
|
||||
runtime_store,
|
||||
&state,
|
||||
)
|
||||
.map_err(anyhow::Error::msg)?;
|
||||
}
|
||||
let request = epiphany_core::build_epiphany_role_launch_request_with_dynamic_context(
|
||||
thread_id,
|
||||
role,
|
||||
expected_revision,
|
||||
Some(max_runtime_seconds),
|
||||
&state,
|
||||
Some(context),
|
||||
)
|
||||
.map_err(anyhow::Error::msg)?;
|
||||
let launched = service.launch_job(
|
||||
thread_id,
|
||||
&state,
|
||||
&request,
|
||||
format!("epiphany-heartbeat-launch-{}", Uuid::new_v4()),
|
||||
Uuid::new_v4().to_string(),
|
||||
now(),
|
||||
)?;
|
||||
Ok(json!({
|
||||
"bindingId": launched.binding_id,
|
||||
"launcherJobId": launched.launcher_job_id,
|
||||
"backendJobId": launched.backend_job_id,
|
||||
"revision": launched.epiphany_state.revision,
|
||||
"epiphanyState": launched.epiphany_state,
|
||||
}))
|
||||
}
|
||||
|
||||
fn accept_role(
|
||||
runtime_store: &Path,
|
||||
thread_id: &str,
|
||||
role_id: &str,
|
||||
expected_revision: Option<u64>,
|
||||
) -> Result<Value> {
|
||||
let service = epiphany_core::EpiphanyCoordinatorService::new(runtime_store, runtime_store);
|
||||
let state = service
|
||||
.state()?
|
||||
.ok_or_else(|| anyhow!("cannot accept role without native coordinator state"))?;
|
||||
let role = parse_role_id(role_id)?;
|
||||
let accepted = service.accept_role(
|
||||
thread_id,
|
||||
&state,
|
||||
role,
|
||||
&default_binding_id_for_role(role_id),
|
||||
expected_revision,
|
||||
None,
|
||||
now(),
|
||||
&Uuid::new_v4().to_string(),
|
||||
)?;
|
||||
Ok(json!({
|
||||
"roleId": role,
|
||||
"revision": accepted.state.revision,
|
||||
"epiphanyState": accepted.state,
|
||||
"acceptedReceiptId": accepted.update.accepted_receipt_id,
|
||||
"acceptedObservationId": accepted.update.accepted_observation_id,
|
||||
"acceptedEvidenceId": accepted.update.accepted_evidence_id,
|
||||
"appliedPatch": accepted.update.applied_patch,
|
||||
"finding": accepted.finding,
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_role_id(role_id: &str) -> Result<epiphany_core::EpiphanyRoleResultRoleId> {
|
||||
match role_id {
|
||||
"imagination" => Ok(epiphany_core::EpiphanyRoleResultRoleId::Imagination),
|
||||
"research" => Ok(epiphany_core::EpiphanyRoleResultRoleId::Research),
|
||||
"modeling" => Ok(epiphany_core::EpiphanyRoleResultRoleId::Modeling),
|
||||
"verification" => Ok(epiphany_core::EpiphanyRoleResultRoleId::Verification),
|
||||
_ => Err(anyhow!("unsupported coordinator role {role_id:?}")),
|
||||
}
|
||||
client.send("thread/epiphany/roleLaunch", Some(payload), true)
|
||||
}
|
||||
|
||||
fn role_id_for_coordinator_action(action: &str) -> Option<&'static str> {
|
||||
|
|
@ -1702,6 +1791,28 @@ mod tests {
|
|||
assert!(!reads.contains("thread/epiphany/"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn coordinator_role_launch_and_acceptance_are_native() {
|
||||
let source = include_str!("epiphany-mvp-coordinator.rs");
|
||||
let start = source.find("fn launch_role").unwrap();
|
||||
let end = source.find("fn role_id_for_coordinator_action").unwrap();
|
||||
let native_roles = &source[start..end];
|
||||
for required in [
|
||||
"render_launch_dynamic_prompt_context",
|
||||
"append_verification_hands_receipt_context",
|
||||
"append_modeling_work_loop_telemetry_context",
|
||||
".launch_job(",
|
||||
".accept_role(",
|
||||
] {
|
||||
assert!(
|
||||
native_roles.contains(required),
|
||||
"missing native role seam {required:?}"
|
||||
);
|
||||
}
|
||||
assert!(!native_roles.contains("AppServerClient"));
|
||||
assert!(!native_roles.contains("thread/epiphany/"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn continue_implementation_is_not_a_passive_stop_action() {
|
||||
assert!(!is_stop_action("continueImplementation"));
|
||||
|
|
|
|||
|
|
@ -1857,9 +1857,13 @@ imports are deleted. Begin `epiphany-mvp-coordinator` AppServerClient removal.
|
|||
Coordinator read authority is now native. Status plus role/reorientation result
|
||||
reads invoke `epiphany-mvp-status --native` over the shared CultCache store; six
|
||||
Codex view/result calls were deleted and a source test rejects AppServerClient or
|
||||
`thread/epiphany/*` inside those functions. Seven production mutation route
|
||||
strings remain: bootstrap update/freshness, role acceptance, role/reorient
|
||||
launch, and supersession update. Cut those next, then delete app-server startup.
|
||||
`thread/epiphany/*` inside those functions. Role mutation is native too: `launch_role` loads native state, renders the same
|
||||
Verse/memory context, appends Verification Hands evidence or Modeling work-loop
|
||||
telemetry, builds the typed request, and calls the atomic service launch.
|
||||
`accept_role` calls the service acceptance actuator directly. A source test
|
||||
guards every required context seam and rejects AppServerClient/routes. Five
|
||||
production routes remain: bootstrap update/freshness, supersession update, and
|
||||
reorientation launch.
|
||||
|
||||
## Immediate Re-entry Instruction
|
||||
|
||||
|
|
|
|||
|
|
@ -238,6 +238,11 @@ unable to decide the result.
|
|||
Coordinator sight has crossed the boundary. `collect_coordinator_status`, role
|
||||
result readback, and reorientation result readback now use the native status
|
||||
projection over the shared thread/runtime CultCache store. The coordinator no
|
||||
longer calls Codex for `view`, `roleResult`, or `reorientResult`. Bootstrap,
|
||||
launch, acceptance dispatch, and supersession mutations still use app-server
|
||||
routes and remain the live cut line.
|
||||
longer calls Codex for `view`, `roleResult`, or `reorientResult`.
|
||||
|
||||
Role mutation has now crossed too. `epiphany-mvp-coordinator` builds role launch
|
||||
requests from native state plus the full native Verse/memory/work-loop context,
|
||||
publishes them through `EpiphanyCoordinatorService::launch_job`, and dispatches
|
||||
auto-review through `accept_role`. The role launch and role acceptance routes
|
||||
are gone. Bootstrap/freshness, supersession update, and reorientation launch are
|
||||
the five remaining production route strings.
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -659,4 +659,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`. Gjallar 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: Replace `epiphany-mvp-coordinator` mutation routes—bootstrap update/freshness, role acceptance dispatch, role/reorient launch, and failure supersession—with `EpiphanyCoordinatorService` and native launch context. Status and all result reads are already native; remove AppServerClient after the remaining seven production `thread/epiphany/*` strings are cut.
|
||||
next_action: Replace the five remaining `epiphany-mvp-coordinator` mutation routes: bootstrap update/freshness, failure supersession update, and reorientation launch. Status/results plus role launch/acceptance are native and preserve full Verse/memory/work-loop context. Remove AppServerClient startup after these final routes are cut.
|
||||
|
|
|
|||
Reference in a new issue