Clarify CultNet receipt authority

This commit is contained in:
Meta Vens 2026-05-22 23:15:07 +01:00
commit dd5530ecb5
3 changed files with 74 additions and 1 deletions

View file

@ -1387,6 +1387,7 @@ fn epiphany_mutation_contracts() -> Vec<CultNetDocumentMutationContract> {
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.",
],
),
mutation_contract(
@ -1597,6 +1598,7 @@ fn epiphany_mutation_contracts() -> Vec<CultNetDocumentMutationContract> {
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.",
],
),
read_only_surface_contract(
@ -1618,6 +1620,7 @@ fn epiphany_mutation_contracts() -> Vec<CultNetDocumentMutationContract> {
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.",
],
),
coordinator_surface_contract(
@ -2282,6 +2285,25 @@ mod tests {
schema.document_type.as_deref() == Some("epiphany.swarm_control_receipt.v0")
&& schema.schema_version.as_deref() == Some("epiphany.swarm_control_receipt.v0")
}));
let receipt_schema_path =
epiphany_schema_root().join("epiphany.swarm-control-receipt.schema.json");
let receipt_schema: serde_json::Value =
serde_json::from_str(&fs::read_to_string(receipt_schema_path)?)?;
let required = receipt_schema["required"]
.as_array()
.expect("receipt schema should list required fields");
assert!(required.iter().any(|field| field == "decisionOwner"));
assert!(required.iter().any(|field| field == "bridgeRole"));
assert!(
receipt_schema["properties"]["decisionOwner"]["description"]
.as_str()
.is_some_and(|description| description.contains("epiphany-core"))
);
assert!(
receipt_schema["properties"]["bridgeRole"]["description"]
.as_str()
.is_some_and(|description| description.contains("transport"))
);
assert!(schemas.iter().any(|schema| {
schema.document_type.as_deref() == Some(OPENAI_MODEL_REQUEST_TYPE)
&& schema.schema_version.as_deref() == Some(OPENAI_MODEL_REQUEST_SCHEMA_VERSION)

View file

@ -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.",
"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.",
"type": "object",
"additionalProperties": true,
"properties": {
@ -18,6 +18,41 @@
"authority": {
"type": "string"
},
"decisionOwner": {
"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": {
"type": "string",
"description": "What the bridge did for this action. Expected values are transport, translate, gatherHostFacts, executeSideEffects, and reportReceipt, alone or joined with '+'."
},
"intentDocumentType": {
"type": [
"string",
"null"
]
},
"decision": {
"type": "object",
"additionalProperties": true,
"properties": {
"verdict": {
"type": "string"
},
"reason": {
"type": "string"
},
"sourceDocumentType": {
"type": "string"
},
"sourceRevision": {
"type": [
"integer",
"null"
]
}
}
},
"targetDocumentType": {
"type": "string"
},
@ -51,6 +86,20 @@
"type": "string"
}
},
"hostFacts": {
"type": "array",
"description": "Host/runtime facts gathered by the bridge 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.",
"items": {
"type": "string"
}
},
"note": {
"type": "string"
}
@ -60,6 +109,8 @@
"ok",
"action",
"authority",
"decisionOwner",
"bridgeRole",
"targetDocumentType",
"status",
"summary"

Binary file not shown.