diff --git a/epiphany-core/src/runtime_spine.rs b/epiphany-core/src/runtime_spine.rs index b9c40652..35e98064 100644 --- a/epiphany-core/src/runtime_spine.rs +++ b/epiphany-core/src/runtime_spine.rs @@ -1387,7 +1387,8 @@ fn epiphany_mutation_contracts() -> Vec { vec![RUNTIME_JOB_TYPE], vec![ "Worker launch requests are typed task-intent documents; runtime jobs are lifecycle receipts, not the source of work intent.", - "Core/coordinator policy owns the launch yes/no; transport bridges translate, gather host facts, execute side effects, and return receipts.", + "Core/coordinator policy owns the launch yes/no; transport bridges translate and carry orders/receipts only.", + "Host executors gather host facts and perform side effects after the verdict, with readable receipts.", ], ), mutation_contract( @@ -1598,7 +1599,7 @@ fn epiphany_mutation_contracts() -> Vec { vec![ "Reorientation policy is the typed resume/regather verdict surface.", "Launch and acceptance stay review-gated through explicit typed intents.", - "The bridge may carry a reorient launch intent and report receipts, but the resume/regather verdict belongs to core.", + "The transport may carry a reorient launch intent and receipt, but the resume/regather verdict belongs to core.", ], ), read_only_surface_contract( @@ -1620,7 +1621,7 @@ fn epiphany_mutation_contracts() -> Vec { vec![ "Job reflection over typed job bindings and runtime-spine lifecycle receipts.", "Heartbeat/runtime-spine owns activation; callers submit typed intents and watch receipts.", - "Launch receipts must name decisionOwner and bridgeRole so transport never grows an unreadable second opinion.", + "Launch receipts must name decisionOwner, transportRole, and any hostExecutorRole so transport never grows an unreadable second opinion.", ], ), coordinator_surface_contract( @@ -2293,16 +2294,21 @@ mod tests { .as_array() .expect("receipt schema should list required fields"); assert!(required.iter().any(|field| field == "decisionOwner")); - assert!(required.iter().any(|field| field == "bridgeRole")); + assert!(required.iter().any(|field| field == "transportRole")); assert!( receipt_schema["properties"]["decisionOwner"]["description"] .as_str() .is_some_and(|description| description.contains("epiphany-core")) ); assert!( - receipt_schema["properties"]["bridgeRole"]["description"] + receipt_schema["properties"]["transportRole"]["description"] .as_str() - .is_some_and(|description| description.contains("transport")) + .is_some_and(|description| description.contains("must not make")) + ); + assert!( + receipt_schema["properties"]["hostExecutorRole"]["description"] + .as_str() + .is_some_and(|description| description.contains("gathered facts")) ); assert!(schemas.iter().any(|schema| { schema.document_type.as_deref() == Some(OPENAI_MODEL_REQUEST_TYPE) diff --git a/schemas/cultnet/epiphany.swarm-control-receipt.schema.json b/schemas/cultnet/epiphany.swarm-control-receipt.schema.json index cb341de0..f1cefd98 100644 --- a/schemas/cultnet/epiphany.swarm-control-receipt.schema.json +++ b/schemas/cultnet/epiphany.swarm-control-receipt.schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://gamecult.dev/epiphany/cultnet/epiphany.swarm-control-receipt.schema.json", "title": "Epiphany Swarm Control Receipt", - "description": "Generic receipt emitted after a coordinator-owned Epiphany control action. The receipt names the authority that made the final yes/no decision and the transport role that carried it out.", + "description": "Generic receipt emitted after a coordinator-owned Epiphany control action. The receipt names the authority that made the final yes/no decision, the transport that carried the order, and any host executor that gathered facts or performed side effects.", "type": "object", "additionalProperties": true, "properties": { @@ -22,9 +22,16 @@ "type": "string", "description": "Authority that made the final yes/no verdict. For Epiphany-owned launch and reorientation flows this is epiphany-core, not the transport bridge." }, - "bridgeRole": { + "transportRole": { "type": "string", - "description": "What the bridge did for this action. Expected values are transport, translate, gatherHostFacts, executeSideEffects, and reportReceipt, alone or joined with '+'." + "description": "What the transport bridge did for this action. Expected values are translate, carryOrder, carryReceipt, or a '+' joined combination. It must not make the launch/reorient verdict, gather host facts, or execute side effects." + }, + "hostExecutorRole": { + "type": [ + "string", + "null" + ], + "description": "Host-side executor role that gathered facts or performed side effects after the core/coordinator verdict, when such an executor exists." }, "intentDocumentType": { "type": [ @@ -88,14 +95,14 @@ }, "hostFacts": { "type": "array", - "description": "Host/runtime facts gathered by the bridge before execution, expressed as readable labels or artifact refs rather than private context.", + "description": "Host/runtime facts gathered by the host executor before execution, expressed as readable labels or artifact refs rather than private context.", "items": { "type": "string" } }, "sideEffects": { "type": "array", - "description": "Side effects the bridge performed after the core/coordinator verdict.", + "description": "Side effects the host executor performed after the core/coordinator verdict.", "items": { "type": "string" } @@ -110,7 +117,7 @@ "action", "authority", "decisionOwner", - "bridgeRole", + "transportRole", "targetDocumentType", "status", "summary" diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 220f5006..55334a5d 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ