Seal role passes from keyed Mind

This commit is contained in:
Meta Vens 2026-08-17 19:29:43 +02:00
commit 7934652381
6 changed files with 760 additions and 77 deletions

View file

@ -316,13 +316,52 @@ pub fn accept_coordinator_role_finding(
anyhow::anyhow!("Modeling result has no Repository Body observation basis")
})?;
validate_repository_body_observation_basis(store, &repository_body_observation_basis)?;
if let Some(proposal) = result.repo_model_mutation_proposal()? {
let proposal = result.repo_model_mutation_proposal()?;
let is_body_modeling = result.proposal_modeling_request_id.is_none()
&& result.claim_repair_request_id.is_none()
&& result.repo_frontier_modeling_request_id.is_none();
if proposal.is_none()
&& !finding.verdict.as_deref().is_some_and(|verdict| {
verdict.eq_ignore_ascii_case("checkpoint-ready")
|| verdict.eq_ignore_ascii_case("regather-needed")
})
{
return Err(anyhow::anyhow!(
"Modeling result requiring RepoModel change has no semantic mutation proposal"
));
}
let mut strong_reads = Vec::new();
let mut writes = Vec::new();
if let Some(proposal) = proposal.as_ref() {
if proposal.proposal_id != format!("repo-model-mutation-proposal-{job_id}") {
return Err(anyhow::anyhow!(
"Modeling RepoModel mutation proposal identity is not runtime-owned"
));
}
let plan = plan_repo_model_mutation(store, &proposal)?;
strong_reads = plan.strong_reads;
writes = plan.writes;
}
if is_body_modeling {
let disposition = if proposal.is_some() {
"modeled"
} else if finding
.verdict
.as_deref()
.is_some_and(|verdict| verdict.eq_ignore_ascii_case("checkpoint-ready"))
{
"checkpoint-ready"
} else {
"regather-needed"
};
writes.push(crate::body_modeling_decision_envelope(
store,
&result,
disposition,
&accepted_at,
)?);
}
if !writes.is_empty() {
let invariant_owner = if result.proposal_modeling_request_id.is_some() {
"Modeling.proposal_frontier"
} else if result.claim_repair_request_id.is_some() {
@ -330,14 +369,14 @@ pub fn accept_coordinator_role_finding(
} else if result.repo_frontier_modeling_request_id.is_some() {
"Modeling.frontier_verdict"
} else {
"Modeling.repo_model"
"Modeling.body_projection"
};
match commit_mind_mutation(
store,
&result.decision_context_id,
invariant_owner,
plan.strong_reads,
plan.writes,
strong_reads,
writes,
&accepted_at,
)? {
EpiphanyMindCommitOutcome::Committed(_) => {}
@ -349,13 +388,6 @@ pub fn accept_coordinator_role_finding(
));
}
}
} else if !finding.verdict.as_deref().is_some_and(|verdict| {
verdict.eq_ignore_ascii_case("checkpoint-ready")
|| verdict.eq_ignore_ascii_case("regather-needed")
}) {
return Err(anyhow::anyhow!(
"Modeling result requiring RepoModel change has no semantic mutation proposal"
));
}
}
let commit = mind_state_commit_receipt(

View file

@ -1,5 +1,5 @@
use anyhow::{Result, anyhow};
use cultcache_rs::{CultCache, DatabaseEntry};
use cultcache_rs::{CultCache, CultCacheEnvelope, DatabaseEntry};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::path::Path;
@ -108,7 +108,7 @@ impl EpiphanyBodyModelingDecisionReceipt {
.any(str::is_empty)
|| !matches!(
self.disposition.as_str(),
"checkpoint-ready" | "regather-needed"
"modeled" | "checkpoint-ready" | "regather-needed"
)
|| chrono::DateTime::parse_from_rfc3339(&self.decided_at).is_err()
{
@ -125,6 +125,65 @@ pub(crate) fn register_current_work_types(cache: &mut CultCache) -> Result<()> {
Ok(())
}
pub(crate) fn body_modeling_decision_envelope(
store_path: &Path,
result: &crate::EpiphanyRuntimeRoleWorkerResult,
disposition: &str,
decided_at: &str,
) -> Result<CultCacheEnvelope> {
let body_basis = result
.repository_body_observation_basis
.clone()
.ok_or_else(|| anyhow!("Body Modeling result has no Body observation basis"))?;
let mut cache = crate::runtime_spine_cache(store_path)?;
cache.pull_all_backing_stores()?;
let context = cache
.get::<crate::EpiphanyDecisionContext>(&result.decision_context_id)?
.ok_or_else(|| anyhow!("Body Modeling result has no decision context"))?;
let reasoning_basis = cache
.get::<crate::EpiphanyReasoningBasis>(&context.basis_id)?
.ok_or_else(|| anyhow!("Body Modeling decision context lost its reasoning basis"))?;
context.validate(&reasoning_basis)?;
let crate::EpiphanyReasoningProjection::RolePass(role_projection) =
reasoning_basis.projection()?
else {
return Err(anyhow!(
"Body Modeling decision has no sealed role projection"
));
};
if role_projection.authority.role_id.to_ascii_lowercase() != "modeling"
|| role_projection
.authority
.repository_body_observation_basis
.as_ref()
!= Some(&body_basis)
{
return Err(anyhow!(
"Body Modeling decision does not bind its projected organ and Body basis"
));
}
let work = EpiphanyBodyModelingWorkProjection::derive(
body_basis.runtime_id.clone(),
body_basis.clone(),
crate::reasoning_repo_model_basis(&reasoning_basis)?,
)?;
let receipt = EpiphanyBodyModelingDecisionReceipt {
schema_version: BODY_MODELING_DECISION_RECEIPT_SCHEMA_VERSION.to_string(),
work_id: work.work_id.clone(),
runtime_id: work.runtime_id.clone(),
body_basis,
repo_model_projection_digest: work.repo_model_basis.projection_digest.clone(),
repo_model_source_documents: work.repo_model_basis.source_documents.clone(),
decision_context_id: result.decision_context_id.clone(),
result_id: result.result_id.clone(),
job_id: result.job_id.clone(),
disposition: disposition.to_string(),
decided_at: decided_at.to_string(),
};
receipt.validate(&work)?;
Ok(cache.prepare_entry(&receipt.work_id, &receipt)?.0)
}
pub fn current_body_modeling_work(
store_path: impl AsRef<Path>,
) -> Result<EpiphanyBodyModelingWorkProjection> {
@ -175,6 +234,10 @@ fn resolve_body_modeling_work(
#[cfg(test)]
mod tests {
use super::*;
use epiphany_state_model::{
EpiphanyMemoryDomain, EpiphanyMemoryLifecycle, EpiphanyMemoryNode, EpiphanyMemoryNodeKind,
EpiphanyMemoryProfile,
};
fn basis(observation_id: &str, generation: u64) -> RepositoryBodyObservationBasis {
RepositoryBodyObservationBasis {
@ -267,4 +330,185 @@ mod tests {
assert!(resolve_body_modeling_work(current_work, Some(receipt))?.is_none());
Ok(())
}
#[test]
fn body_decision_is_derived_from_the_sealed_role_projection() -> Result<()> {
let temp = tempfile::tempdir()?;
let store = temp.path().join("body-decision.cc");
crate::initialize_runtime_spine(
&store,
crate::RuntimeSpineInitOptions {
runtime_id: "runtime".into(),
display_name: "Body decision".into(),
created_at: "2026-08-17T00:00:00Z".into(),
},
)?;
crate::runtime_spine::tests::bind_test_runtime_swarm(&store, "swarm")?;
crate::runtime_spine::tests::bind_test_repository_body(&store, "workspace")?;
let body = crate::observe_runtime_repository_body_basis(&store)?;
let domain = EpiphanyMemoryDomain {
id: "body-domain".into(),
profile: EpiphanyMemoryProfile::RepoArchitecture,
title: "Body".into(),
lifecycle: EpiphanyMemoryLifecycle::Accepted,
..Default::default()
};
let node = EpiphanyMemoryNode {
id: "body-node".into(),
domain_id: domain.id.clone(),
profile: EpiphanyMemoryProfile::RepoArchitecture,
kind: EpiphanyMemoryNodeKind::Module,
title: "Body node".into(),
claim: "The Body is typed".into(),
question: "What does the Body contain?".into(),
action_implication: "Model it".into(),
source_hashes: vec!["anchor:missing".into()],
lifecycle: EpiphanyMemoryLifecycle::Accepted,
..Default::default()
};
crate::initialize_keyed_repo_model(
&store,
&crate::EpiphanyRepoModelSeed::new(
"body-seed",
"body-graph",
"swarm",
"workspace",
body.body_binding_sha256.clone(),
crate::EpiphanyRepoModelSeedDocuments {
domains: vec![domain],
nodes: vec![node],
edges: Vec::new(),
summaries: Vec::new(),
frontier: Vec::new(),
lifecycle_receipts: Vec::new(),
},
)?,
"2026-08-17T00:00:01Z",
)?;
let document =
crate::EpiphanyWorkerLaunchDocument::Role(crate::EpiphanyRoleWorkerLaunchDocument {
thread_id: "creation-thread".into(),
role_id: "modeling".into(),
state_revision: 99,
objective: Some("obsolete aggregate objective".into()),
dynamic_prompt_context: None,
repository_body_observation_basis: Some(body.clone()),
proposal_modeling_context: None,
claim_repair_context: None,
frontier_planning_context: None,
frontier_research_context: None,
frontier_plan_mind_context: None,
imagination_consideration_context: None,
admitted_model_direction_consideration_context: None,
active_subgoal_id: None,
active_subgoals: Vec::new(),
active_graph_node_ids: Vec::new(),
investigation_checkpoint: None,
scratch: None,
invariants: Vec::new(),
graphs: None,
recent_evidence: Vec::new(),
recent_observations: Vec::new(),
graph_frontier: None,
graph_checkpoint: None,
planning: None,
churn: None,
});
let launch = crate::EpiphanyRuntimeWorkerLaunchRequest {
schema_version: crate::RUNTIME_WORKER_LAUNCH_REQUEST_SCHEMA_VERSION.into(),
job_id: "body-job".into(),
binding_id: crate::EPIPHANY_MODELING_ROLE_BINDING_ID.into(),
role: crate::EPIPHANY_MODELING_OWNER_ROLE.into(),
authority_scope: "epiphany.role.modeling".into(),
instruction: "Model the Body".into(),
output_contract_id: crate::ROLE_WORKER_OUTPUT_CONTRACT_ID.into(),
document_kind: "role".into(),
launch_document_msgpack: rmp_serde::to_vec_named(&document)?,
metadata: Default::default(),
organ_launch_contract: crate::default_launch_organ_contract(
"epiphany.role.modeling",
"role",
crate::ROLE_WORKER_OUTPUT_CONTRACT_ID,
),
proposal_modeling_request_id: None,
claim_repair_request_id: None,
frontier_planning_request_id: None,
frontier_plan_mind_request_id: None,
imagination_consideration_request_id: None,
admitted_model_direction_consideration_request_id: None,
repo_frontier_modeling_request_id: None,
repo_frontier_research_request_id: None,
repo_frontier_verdict_modeling_authority_msgpack: None,
};
let mut cache = crate::runtime_spine_cache(&store)?;
cache.put(&launch.job_id, &launch)?;
let reasoning_basis = crate::worker_reasoning_basis(&store, &launch)?;
crate::put_reasoning_basis(&store, &reasoning_basis)?;
let mut native = epiphany_model_adapter::EpiphanyModelRequest::new(
"body-request",
"body-conversation",
"openai-codex",
"gpt-test",
"model",
);
native.reasoning_basis_id = Some(reasoning_basis.basis_id.clone());
native.source_worker_job_id = Some(launch.job_id.clone());
let provider = epiphany_openai_adapter::request_from_native(&native);
let context =
crate::EpiphanyDecisionContext::new(&reasoning_basis, native, provider, Vec::new())?;
cache.put(&context.context_id, &context)?;
let result = crate::EpiphanyRuntimeRoleWorkerResult {
schema_version: crate::RUNTIME_ROLE_WORKER_RESULT_SCHEMA_VERSION.into(),
result_id: "body-result".into(),
job_id: launch.job_id.clone(),
role_id: "modeling".into(),
verdict: "checkpoint-ready".into(),
summary: "modeled".into(),
next_safe_move: "admit".into(),
checkpoint_summary: None,
scratch_summary: None,
files_inspected: Vec::new(),
frontier_node_ids: Vec::new(),
evidence_ids: Vec::new(),
artifact_refs: Vec::new(),
open_questions: Vec::new(),
evidence_gaps: Vec::new(),
risks: Vec::new(),
state_patch_msgpack: None,
self_patch_msgpack: None,
item_error: None,
metadata: Default::default(),
repo_model_mutation_proposal_msgpack: None,
verification_request_id: None,
frontier_route_id: None,
repo_frontier_modeling_request_id: None,
proposal_modeling_request_id: None,
claim_repair_request_id: None,
frontier_planning_request_id: None,
frontier_plan_candidate_msgpack: None,
frontier_plan_mind_request_id: None,
frontier_plan_mind_decision_msgpack: None,
repository_body_observation_basis: Some(body.clone()),
imagination_consideration_request_id: None,
imagination_consideration_candidate_msgpack: None,
admitted_model_direction_consideration_request_id: None,
admitted_model_direction_consideration_result_msgpack: None,
decision_context_id: context.context_id,
};
let envelope = body_modeling_decision_envelope(
&store,
&result,
"checkpoint-ready",
"2026-08-17T00:00:02Z",
)?;
crate::mind_documents::validate_mind_write_envelope(&envelope)?;
let receipt: EpiphanyBodyModelingDecisionReceipt =
rmp_serde::from_slice(&envelope.payload)?;
assert_eq!(receipt.body_basis, body);
assert_eq!(
receipt.repo_model_projection_digest,
crate::assemble_repo_model_view(&store)?.projection_digest
);
Ok(())
}
}

View file

@ -145,6 +145,8 @@ pub struct EpiphanyMindObjectiveDraftDocument {
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct EpiphanyMindView {
pub schema_epoch: String,
pub runtime_id: String,
pub projection_digest: String,
pub source_documents: Vec<EpiphanyMindDocumentVersion>,
pub objective: Option<String>,
@ -363,11 +365,22 @@ pub fn assemble_mind_view(store_path: impl AsRef<Path>) -> Result<EpiphanyMindVi
None => None,
};
let mut source_documents = canonical_mind_versions(&cache.snapshot_envelopes())?;
if let Some(repo_model) = &repo_model {
source_documents.extend(repo_model.source_documents.clone());
}
source_documents.sort_by(|left, right| {
(&left.document_type, &left.document_key).cmp(&(&right.document_type, &right.document_key))
});
let projection_digest = digest_versions(&source_documents)?;
if source_documents
.windows(2)
.any(|pair| pair[0].identity() == pair[1].identity())
{
return Err(anyhow!("Mind view repeats a canonical source document"));
}
let projection_digest = mind_view_digest(&source_documents)?;
Ok(EpiphanyMindView {
schema_epoch: identity.schema_epoch,
runtime_id: identity.runtime_id,
projection_digest,
source_documents,
objective,
@ -401,18 +414,39 @@ fn canonical_mind_versions(
) -> Result<Vec<EpiphanyMindDocumentVersion>> {
envelopes
.iter()
.filter(|envelope| envelope.r#type.starts_with("epiphany.mind."))
.filter(|envelope| {
matches!(
envelope.r#type.as_str(),
EpiphanyMindIdentity::TYPE
| EpiphanyMindObjectiveDocument::TYPE
| EpiphanyMindFocusDocument::TYPE
| EpiphanyMindModeDocument::TYPE
| EpiphanyMindSubgoalDocument::TYPE
| EpiphanyMindInvariantDocument::TYPE
| EpiphanyMindObservationDocument::TYPE
| EpiphanyMindEvidenceDocument::TYPE
| EpiphanyMindInvestigationCheckpointDocument::TYPE
| EpiphanyMindPlanningCaptureDocument::TYPE
| EpiphanyMindBacklogItemDocument::TYPE
| EpiphanyMindRoadmapStreamDocument::TYPE
| EpiphanyMindObjectiveDraftDocument::TYPE
)
})
.map(|envelope| EpiphanyMindDocumentVersion::from_envelope("epiphany-mind", envelope))
.collect()
}
fn digest_versions(versions: &[EpiphanyMindDocumentVersion]) -> Result<String> {
pub(crate) fn mind_view_digest(versions: &[EpiphanyMindDocumentVersion]) -> Result<String> {
let mut digest = Sha256::new();
digest.update(b"epiphany.mind_view.v1\0");
digest.update(rmp_serde::to_vec_named(versions)?);
Ok(format!("sha256:{:x}", digest.finalize()))
}
pub fn epiphany_mind_projection_digest(versions: &[EpiphanyMindDocumentVersion]) -> Result<String> {
mind_view_digest(versions)
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -21,7 +21,122 @@ pub const REASONING_BASIS_SCHEMA_VERSION: &str = "epiphany.reasoning_basis.v1";
pub const DECISION_CONTEXT_SCHEMA_VERSION: &str = "epiphany.decision_context.v1";
pub const MIND_COMMIT_RECEIPT_SCHEMA_VERSION: &str = "epiphany.mind_commit_receipt.v1";
pub const WORKER_REASONING_PROJECTION_POLICY: &str =
"epiphany.reasoning_projection.worker_launch.v1";
"epiphany.reasoning_projection.worker_launch.v2";
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct EpiphanyRolePassAuthorityProjection {
pub creation_thread_id: String,
pub role_id: String,
pub dynamic_prompt_context: Option<String>,
pub repository_body_observation_basis: Option<crate::RepositoryBodyObservationBasis>,
pub proposal_modeling_context: Option<crate::RepoFrontierProposalModelingContextProjection>,
pub claim_repair_context: Option<crate::RepoModelClaimRepairContextProjection>,
pub frontier_planning_context: Option<crate::RepoFrontierPlanningContextProjection>,
pub frontier_research_context: Option<crate::RepoFrontierResearchContextProjection>,
pub frontier_plan_mind_context: Option<crate::RepoFrontierPlanMindContextProjection>,
pub imagination_consideration_context: Option<crate::ImaginationConsiderationContextProjection>,
pub admitted_model_direction_consideration_context:
Option<crate::AdmittedModelDirectionConsiderationContextProjection>,
}
impl From<EpiphanyRoleWorkerLaunchDocument> for EpiphanyRolePassAuthorityProjection {
fn from(value: EpiphanyRoleWorkerLaunchDocument) -> Self {
Self {
creation_thread_id: value.thread_id,
role_id: value.role_id,
dynamic_prompt_context: value.dynamic_prompt_context,
repository_body_observation_basis: value.repository_body_observation_basis,
proposal_modeling_context: value.proposal_modeling_context,
claim_repair_context: value.claim_repair_context,
frontier_planning_context: value.frontier_planning_context,
frontier_research_context: value.frontier_research_context,
frontier_plan_mind_context: value.frontier_plan_mind_context,
imagination_consideration_context: value.imagination_consideration_context,
admitted_model_direction_consideration_context: value
.admitted_model_direction_consideration_context,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct EpiphanyRepoModelPromptProjection {
pub identity: crate::EpiphanyRepoModelIdentityDocument,
pub projection_digest: String,
pub domains: Vec<epiphany_state_model::EpiphanyMemoryDomain>,
pub nodes: Vec<epiphany_state_model::EpiphanyMemoryNode>,
pub edges: Vec<epiphany_state_model::EpiphanyMemoryEdge>,
pub summaries: Vec<epiphany_state_model::EpiphanyMemorySummary>,
pub frontier: Vec<epiphany_state_model::RepoFrontierItem>,
pub lifecycle_receipts: Vec<epiphany_state_model::EpiphanyMemoryLifecycleReceipt>,
pub claim_obligations: Vec<crate::EpiphanyRepoModelClaimObligationsDocument>,
pub surface_offers: Vec<crate::AtlasSurfaceOffer>,
pub dependency_claims: Vec<crate::AtlasDependencyClaim>,
pub dependency_verifications: Vec<crate::AtlasDependencyVerification>,
pub dependency_impacts: Vec<crate::AtlasDependencyImpact>,
}
impl From<crate::EpiphanyRepoModelView> for EpiphanyRepoModelPromptProjection {
fn from(value: crate::EpiphanyRepoModelView) -> Self {
Self {
identity: value.identity,
projection_digest: value.projection_digest,
domains: value.domains,
nodes: value.nodes,
edges: value.edges,
summaries: value.summaries,
frontier: value.frontier,
lifecycle_receipts: value.lifecycle_receipts,
claim_obligations: value.claim_obligations,
surface_offers: value.surface_offers,
dependency_claims: value.dependency_claims,
dependency_verifications: value.dependency_verifications,
dependency_impacts: value.dependency_impacts,
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct EpiphanyMindPromptProjection {
pub schema_epoch: String,
pub runtime_id: String,
pub projection_digest: String,
pub objective: Option<String>,
pub active_subgoal_id: Option<String>,
pub subgoals: Vec<epiphany_state_model::EpiphanySubgoal>,
pub invariants: Vec<epiphany_state_model::EpiphanyInvariant>,
pub observations: Vec<epiphany_state_model::EpiphanyObservation>,
pub evidence: Vec<epiphany_state_model::EpiphanyEvidenceRecord>,
pub investigation_checkpoint: Option<epiphany_state_model::EpiphanyInvestigationCheckpoint>,
pub mode: Option<epiphany_state_model::EpiphanyModeState>,
pub planning: epiphany_state_model::EpiphanyPlanningState,
pub repo_model: Option<EpiphanyRepoModelPromptProjection>,
}
impl From<crate::EpiphanyMindView> for EpiphanyMindPromptProjection {
fn from(value: crate::EpiphanyMindView) -> Self {
Self {
schema_epoch: value.schema_epoch,
runtime_id: value.runtime_id,
projection_digest: value.projection_digest,
objective: value.objective,
active_subgoal_id: value.active_subgoal_id,
subgoals: value.subgoals,
invariants: value.invariants,
observations: value.observations,
evidence: value.evidence,
investigation_checkpoint: value.investigation_checkpoint,
mode: value.mode,
planning: value.planning,
repo_model: value.repo_model.map(Into::into),
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct EpiphanyRoleReasoningProjection {
pub authority: EpiphanyRolePassAuthorityProjection,
pub mind: EpiphanyMindPromptProjection,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct EpiphanyMindDocumentVersion {
@ -71,22 +186,13 @@ impl EpiphanyMindDocumentVersion {
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum EpiphanyReasoningProjection {
RoleLaunch(EpiphanyRoleWorkerLaunchDocument),
RolePass(EpiphanyRoleReasoningProjection),
ReorientLaunch(crate::EpiphanyReorientWorkerLaunchDocument),
PersonaProjector(PersonaProjectorInput),
PersonaTurn(PersonaTurnInput),
PersonaInterpreter(PersonaInterpreterInput),
}
impl From<EpiphanyWorkerLaunchDocument> for EpiphanyReasoningProjection {
fn from(value: EpiphanyWorkerLaunchDocument) -> Self {
match value {
EpiphanyWorkerLaunchDocument::Role(document) => Self::RoleLaunch(document),
EpiphanyWorkerLaunchDocument::Reorient(document) => Self::ReorientLaunch(document),
}
}
}
#[derive(Clone, Debug, PartialEq, DatabaseEntry)]
#[cultcache(
type = "epiphany.reasoning_basis.v1",
@ -157,8 +263,21 @@ impl EpiphanyReasoningBasis {
"reasoning basis source documents are not canonical"
));
}
let _: EpiphanyReasoningProjection = rmp_serde::from_slice(&self.projection_msgpack)
.map_err(|error| anyhow!("reasoning projection is invalid: {error}"))?;
let projection: EpiphanyReasoningProjection =
rmp_serde::from_slice(&self.projection_msgpack)
.map_err(|error| anyhow!("reasoning projection is invalid: {error}"))?;
if let EpiphanyReasoningProjection::RolePass(role) = &projection {
if role.authority.creation_thread_id.trim().is_empty()
|| role.authority.role_id.trim().is_empty()
|| self.source_documents.is_empty()
|| role.mind.projection_digest
!= crate::mind_documents::mind_view_digest(&self.source_documents)?
{
return Err(anyhow!(
"role reasoning projection does not bind its exact keyed Mind sources"
));
}
}
if self
.predecessor_decision_context_ids
.iter()
@ -339,19 +458,79 @@ pub fn worker_reasoning_basis(
let launch_envelope = cache
.get_envelope::<EpiphanyRuntimeWorkerLaunchRequest>(&launch.job_id)?
.ok_or_else(|| anyhow!("worker reasoning basis lost its launch envelope"))?;
let source_documents = vec![EpiphanyMindDocumentVersion::from_envelope(
"epiphany-mind",
&launch_envelope,
)?];
let launch_document = launch.launch_document()?;
let (source_documents, projection) = match launch_document {
EpiphanyWorkerLaunchDocument::Role(document) => {
let mind = crate::assemble_mind_view(store_path)?;
let source_documents = mind.source_documents.clone();
(
source_documents,
EpiphanyReasoningProjection::RolePass(EpiphanyRoleReasoningProjection {
authority: document.into(),
mind: mind.into(),
}),
)
}
EpiphanyWorkerLaunchDocument::Reorient(document) => (
vec![EpiphanyMindDocumentVersion::from_envelope(
"epiphany-mind",
&launch_envelope,
)?],
EpiphanyReasoningProjection::ReorientLaunch(document),
),
};
EpiphanyReasoningBasis::new(
&launch.job_id,
&launch.role,
WORKER_REASONING_PROJECTION_POLICY,
source_documents,
launch.launch_document()?.into(),
projection,
)
}
pub fn reasoning_repo_model_basis(
basis: &EpiphanyReasoningBasis,
) -> Result<crate::EpiphanyRepoModelBasis> {
basis.validate()?;
let source_documents = basis
.source_documents
.iter()
.filter(|source| {
source
.document_type
.starts_with("epiphany.mind.repo_model.")
|| matches!(
source.document_type.as_str(),
crate::AtlasSurfaceOffer::TYPE
| crate::AtlasDependencyClaim::TYPE
| crate::AtlasDependencyVerification::TYPE
| crate::AtlasDependencyImpact::TYPE
)
})
.cloned()
.collect::<Vec<_>>();
let repo_model_basis = crate::EpiphanyRepoModelBasis {
projection_digest: sha256(&rmp_serde::to_vec_named(&source_documents)?),
source_documents,
};
repo_model_basis.validate()?;
let EpiphanyReasoningProjection::RolePass(role) = basis.projection()? else {
return Err(anyhow!("RepoModel reasoning basis is not a role pass"));
};
if role
.mind
.repo_model
.as_ref()
.map(|model| model.projection_digest.as_str())
!= Some(repo_model_basis.projection_digest.as_str())
{
return Err(anyhow!(
"role reasoning projection RepoModel diverges from its exact sources"
));
}
Ok(repo_model_basis)
}
pub fn put_reasoning_basis(
store_path: &Path,
basis: &EpiphanyReasoningBasis,
@ -359,6 +538,23 @@ pub fn put_reasoning_basis(
basis.validate()?;
let mut cache = runtime_spine_cache(store_path)?;
cache.pull_all_backing_stores()?;
if let EpiphanyReasoningProjection::RolePass(projection) = basis.projection()? {
let launch = cache
.get::<EpiphanyRuntimeWorkerLaunchRequest>(&basis.pass_id)?
.ok_or_else(|| anyhow!("role reasoning basis lost its worker launch"))?;
let EpiphanyWorkerLaunchDocument::Role(document) = launch.launch_document()? else {
return Err(anyhow!("role reasoning basis cites a non-role launch"));
};
let current_mind = crate::assemble_mind_view(store_path)?;
if projection.authority != document.into()
|| projection.mind != current_mind.clone().into()
|| basis.source_documents != current_mind.source_documents
{
return Err(anyhow!(
"role reasoning projection diverges from its exact launch or keyed Mind sources"
));
}
}
for source in &basis.source_documents {
if source.store_id != "epiphany-mind" {
return Err(anyhow!(
@ -979,41 +1175,104 @@ mod tests {
use epiphany_model_adapter::EpiphanyModelInputItem;
use tempfile::tempdir;
fn role_document() -> EpiphanyRoleWorkerLaunchDocument {
EpiphanyRoleWorkerLaunchDocument {
thread_id: "creation-thread".into(),
role_id: "Modeling".into(),
state_revision: 7,
objective: Some("Map the Body".into()),
dynamic_prompt_context: Some("typed projection".into()),
repository_body_observation_basis: None,
proposal_modeling_context: None,
claim_repair_context: None,
frontier_planning_context: None,
frontier_research_context: None,
frontier_plan_mind_context: None,
imagination_consideration_context: None,
admitted_model_direction_consideration_context: None,
active_subgoal_id: None,
active_subgoals: Vec::new(),
active_graph_node_ids: Vec::new(),
investigation_checkpoint: None,
scratch: None,
invariants: Vec::new(),
graphs: None,
recent_evidence: Vec::new(),
recent_observations: Vec::new(),
graph_frontier: None,
graph_checkpoint: None,
planning: None,
churn: None,
}
}
fn role_launch() -> Result<EpiphanyRuntimeWorkerLaunchRequest> {
let document = EpiphanyWorkerLaunchDocument::Role(role_document());
Ok(EpiphanyRuntimeWorkerLaunchRequest {
schema_version: crate::RUNTIME_WORKER_LAUNCH_REQUEST_SCHEMA_VERSION.into(),
job_id: "pass-1".into(),
binding_id: crate::EPIPHANY_MODELING_ROLE_BINDING_ID.into(),
role: "Modeling".into(),
authority_scope: "epiphany.role.modeling".into(),
instruction: "Map the Body".into(),
output_contract_id: crate::ROLE_WORKER_OUTPUT_CONTRACT_ID.into(),
document_kind: "role".into(),
launch_document_msgpack: rmp_serde::to_vec_named(&document)?,
metadata: Default::default(),
organ_launch_contract: crate::default_launch_organ_contract(
"epiphany.role.modeling",
"role",
crate::ROLE_WORKER_OUTPUT_CONTRACT_ID,
),
proposal_modeling_request_id: None,
claim_repair_request_id: None,
frontier_planning_request_id: None,
frontier_plan_mind_request_id: None,
imagination_consideration_request_id: None,
admitted_model_direction_consideration_request_id: None,
repo_frontier_modeling_request_id: None,
repo_frontier_research_request_id: None,
repo_frontier_verdict_modeling_authority_msgpack: None,
})
}
fn basis() -> Result<EpiphanyReasoningBasis> {
let projection =
EpiphanyReasoningProjection::RoleLaunch(EpiphanyRoleWorkerLaunchDocument {
thread_id: "creation-thread".into(),
role_id: "Modeling".into(),
state_revision: 7,
objective: Some("Map the Body".into()),
dynamic_prompt_context: Some("typed projection".into()),
repository_body_observation_basis: None,
proposal_modeling_context: None,
claim_repair_context: None,
frontier_planning_context: None,
frontier_research_context: None,
frontier_plan_mind_context: None,
imagination_consideration_context: None,
admitted_model_direction_consideration_context: None,
let authority = EpiphanyRolePassAuthorityProjection::from(role_document());
let payload_msgpack = rmp_serde::to_vec_named(&crate::EpiphanyMindIdentity {
schema_epoch: crate::MIND_SCHEMA_EPOCH.into(),
runtime_id: "test-runtime".into(),
})?;
let source_documents = vec![EpiphanyMindDocumentVersion {
store_id: "epiphany-mind".into(),
document_type: "epiphany.mind.identity.v1".into(),
document_key: crate::MIND_SCHEMA_EPOCH.into(),
schema_id: None,
payload_sha256: sha256(&payload_msgpack),
payload_msgpack,
}];
let projection = EpiphanyReasoningProjection::RolePass(EpiphanyRoleReasoningProjection {
authority,
mind: EpiphanyMindPromptProjection {
schema_epoch: crate::MIND_SCHEMA_EPOCH.into(),
runtime_id: "test-runtime".into(),
projection_digest: crate::epiphany_mind_projection_digest(&source_documents)?,
objective: None,
active_subgoal_id: None,
active_subgoals: Vec::new(),
active_graph_node_ids: Vec::new(),
investigation_checkpoint: None,
scratch: None,
subgoals: Vec::new(),
invariants: Vec::new(),
graphs: None,
recent_evidence: Vec::new(),
recent_observations: Vec::new(),
graph_frontier: None,
graph_checkpoint: None,
planning: None,
churn: None,
});
observations: Vec::new(),
evidence: Vec::new(),
investigation_checkpoint: None,
mode: None,
planning: Default::default(),
repo_model: None,
},
});
EpiphanyReasoningBasis::new(
"pass-1",
"Modeling",
WORKER_REASONING_PROJECTION_POLICY,
Vec::new(),
source_documents,
projection,
)
}
@ -1066,6 +1325,44 @@ mod tests {
Ok(())
}
#[test]
fn role_basis_refuses_projection_not_derived_from_its_mind_sources() -> Result<()> {
let temp = tempdir()?;
let store = temp.path().join("mind.cc");
initialize_runtime_spine(
&store,
RuntimeSpineInitOptions {
runtime_id: "mind-projection-test".into(),
display_name: "Mind projection test".into(),
created_at: "2026-08-17T00:00:00Z".into(),
},
)?;
let launch = role_launch()?;
let mut cache = runtime_spine_cache(&store)?;
cache.put(&launch.job_id, &launch)?;
let canonical = worker_reasoning_basis(&store, &launch)?;
let EpiphanyReasoningProjection::RolePass(mut forged_projection) =
canonical.projection()?
else {
unreachable!();
};
forged_projection.mind.objective = Some("invented aggregate objective".into());
let forged = EpiphanyReasoningBasis::new(
&canonical.pass_id,
&canonical.organ_id,
&canonical.projection_policy_id,
canonical.source_documents.clone(),
EpiphanyReasoningProjection::RolePass(forged_projection),
)?;
let before = SingleFileMessagePackBackingStore::new(&store).pull_all()?;
assert!(put_reasoning_basis(&store, &forged).is_err());
assert_eq!(
SingleFileMessagePackBackingStore::new(&store).pull_all()?,
before
);
Ok(())
}
#[test]
fn disjoint_mind_mutations_merge_and_same_identity_conflicts() -> Result<()> {
let temp = tempdir()?;
@ -1078,7 +1375,11 @@ mod tests {
created_at: "2026-08-14T00:00:00Z".into(),
},
)?;
let basis = put_reasoning_basis(&store, &basis()?)?;
let launch = role_launch()?;
let mut cache = runtime_spine_cache(&store)?;
cache.put(&launch.job_id, &launch)?;
let basis = worker_reasoning_basis(&store, &launch)?;
let basis = put_reasoning_basis(&store, &basis)?;
let (native, provider) = requests(&basis);
crate::open_runtime_model_execution(
&store,

View file

@ -943,7 +943,7 @@ async fn run_worker_launch_with_tool_continuation(
&launch_request,
&options.provider,
&options.model,
&basis.basis_id,
&basis,
)?;
let requested_public_source_intents =
if launch_request.repo_frontier_research_request_id.is_some() {

View file

@ -348,7 +348,7 @@ where
&launch_request,
&options.provider,
&options.model,
&basis.basis_id,
&basis,
)?;
let openai_options = EpiphanyOpenAiRuntimeOptions {
store_path: options.store_path.clone(),
@ -615,20 +615,40 @@ pub fn build_worker_model_request(
launch_request: &EpiphanyRuntimeWorkerLaunchRequest,
provider: &str,
model: &str,
reasoning_basis_id: &str,
reasoning_basis: &epiphany_core::EpiphanyReasoningBasis,
) -> Result<EpiphanyModelRequest> {
if reasoning_basis_id.trim().is_empty() {
return Err(anyhow!("worker model request requires a reasoning basis"));
reasoning_basis.validate()?;
if reasoning_basis.pass_id != launch_request.job_id {
return Err(anyhow!(
"worker model request reasoning basis belongs to another pass"
));
}
let launch_document = launch_request.launch_document()?;
let reasoning_projection = reasoning_basis.projection()?;
match (&launch_document, &reasoning_projection) {
(
EpiphanyWorkerLaunchDocument::Role(document),
epiphany_core::EpiphanyReasoningProjection::RolePass(projection),
) if projection.authority
== epiphany_core::EpiphanyRolePassAuthorityProjection::from(document.clone()) => {}
(
EpiphanyWorkerLaunchDocument::Reorient(document),
epiphany_core::EpiphanyReasoningProjection::ReorientLaunch(projection),
) if projection == document => {}
_ => {
return Err(anyhow!(
"worker model request reasoning projection does not match its launch authority"
));
}
}
let output_schema_json = worker_output_schema_json(launch_request, &launch_document)?;
let request_id = format!(
"worker-{}-{}",
sanitize_request_id(&launch_request.job_id),
chrono::Utc::now().timestamp_millis()
);
let launch_document_text = serde_json::to_string_pretty(&launch_document)
.context("failed to render worker launch document for model input")?;
let reasoning_projection_text = serde_json::to_string_pretty(&reasoning_projection)
.context("failed to render sealed worker reasoning projection for model input")?;
let mut instructions = worker_instructions(launch_request, &launch_document);
if launch_request.binding_id == epiphany_core::EPIPHANY_VERIFICATION_ROLE_BINDING_ID {
instructions.push_str("\n\nTool mandate: before returning `needs-evidence` because source files, artifact directories, command artifacts, commit diffs, Hands receipt bodies, or resident grant lifecycle are not inspectable, call the governed read-only tools available on this request. Use `mcp__epiphany_source__read_file` for cited source/artifact files, `mcp__epiphany_source__directory_inventory` for bounded workspace directory counts and bytes, `mcp__epiphany_source__git_show` for commit diffs, `mcp__epiphany_source__read_hands_receipt` for Hands patch/command/commit receipts, and `mcp__epiphany_state__resident_grant_lifecycle` for exact or bounded recent grant-owned lifecycle state. Directory totals are authoritative only when the tool reports `complete=true`. Grant launchability is authoritative only from the typed state projection, never artifact names or acknowledgement presence. If a tool fails, cite that failed tool result and the exact remaining blocker.");
@ -646,7 +666,7 @@ pub fn build_worker_model_request(
);
request.input.push(EpiphanyModelInputItem::UserText {
text: format!(
"Execute this Epiphany worker launch document.\n\n```json\n{launch_document_text}\n```"
"Execute this sealed Epiphany reasoning projection.\n\n```json\n{reasoning_projection_text}\n```"
),
});
request.reasoning_effort = Some("low".to_string());
@ -654,7 +674,7 @@ pub fn build_worker_model_request(
request.output_contract_id = Some(launch_request.output_contract_id.clone());
request.output_schema_json = Some(output_schema_json);
request.source_worker_job_id = Some(launch_request.job_id.clone());
request.reasoning_basis_id = Some(reasoning_basis_id.to_string());
request.reasoning_basis_id = Some(reasoning_basis.basis_id.clone());
if matches!(
launch_request.binding_id.as_str(),
epiphany_core::EPIPHANY_RESEARCH_ROLE_BINDING_ID
@ -2509,8 +2529,56 @@ mod tests {
use epiphany_core::open_runtime_spine_heartbeat_job;
use epiphany_core::runtime_job_snapshot;
use epiphany_openai_adapter::EpiphanyOpenAiModelReceipt;
use sha2::{Digest, Sha256};
use tempfile::tempdir;
fn test_reasoning_basis(
launch: &EpiphanyRuntimeWorkerLaunchRequest,
) -> Result<epiphany_core::EpiphanyReasoningBasis> {
let EpiphanyWorkerLaunchDocument::Role(document) = launch.launch_document()? else {
return Err(anyhow!("test fixture requires a role launch"));
};
let payload_msgpack = rmp_serde::to_vec_named(&epiphany_core::EpiphanyMindIdentity {
schema_epoch: epiphany_core::MIND_SCHEMA_EPOCH.into(),
runtime_id: "test-runtime".into(),
})?;
let source_documents = vec![epiphany_core::EpiphanyMindDocumentVersion {
store_id: "epiphany-mind".into(),
document_type: "epiphany.mind.identity.v1".into(),
document_key: epiphany_core::MIND_SCHEMA_EPOCH.into(),
schema_id: None,
payload_sha256: format!("sha256:{:x}", Sha256::digest(&payload_msgpack)),
payload_msgpack,
}];
let mind = epiphany_core::EpiphanyMindPromptProjection {
schema_epoch: epiphany_core::MIND_SCHEMA_EPOCH.into(),
runtime_id: "test-runtime".into(),
projection_digest: epiphany_core::epiphany_mind_projection_digest(&source_documents)?,
objective: None,
active_subgoal_id: None,
subgoals: Vec::new(),
invariants: Vec::new(),
observations: Vec::new(),
evidence: Vec::new(),
investigation_checkpoint: None,
mode: None,
planning: Default::default(),
repo_model: None,
};
epiphany_core::EpiphanyReasoningBasis::new(
&launch.job_id,
&launch.role,
epiphany_core::WORKER_REASONING_PROJECTION_POLICY,
source_documents,
epiphany_core::EpiphanyReasoningProjection::RolePass(
epiphany_core::EpiphanyRoleReasoningProjection {
authority: document.into(),
mind,
},
),
)
}
#[test]
fn model_authored_body_basis_has_no_ingress_authority() -> Result<()> {
let parsed = parse_assistant_json::<RoleWorkerResultIngress>(
@ -2937,7 +3005,7 @@ mod tests {
thread_id: "thread-1".into(),
role_id: "modeling".into(),
state_revision: 1,
objective: None,
objective: Some("obsolete aggregate objective must not cross inference".into()),
dynamic_prompt_context: None,
repository_body_observation_basis: None,
proposal_modeling_context: Some(context),
@ -2992,7 +3060,7 @@ mod tests {
&launch,
DEFAULT_MODEL_PROVIDER,
"gpt-5.4",
"reasoning-basis-test",
&test_reasoning_basis(&launch)?,
)?;
let schema: serde_json::Value = serde_json::from_str(
request
@ -3009,6 +3077,10 @@ mod tests {
.instructions
.contains("Emit only the semantic frontier draft")
);
let rendered_input = serde_json::to_string(&request.input)?;
assert!(rendered_input.contains("sealed Epiphany reasoning projection"));
assert!(!rendered_input.contains("obsolete aggregate objective"));
assert!(!rendered_input.contains("stateRevision"));
Ok(())
}
@ -3808,7 +3880,7 @@ mod tests {
&launch_request,
DEFAULT_MODEL_PROVIDER,
"gpt-5.4",
&reasoning_basis.basis_id,
&reasoning_basis,
)?;
let provider_request = openai_request_from_model_request(&model_request);
epiphany_core::open_runtime_model_execution(
@ -4037,7 +4109,7 @@ mod tests {
&launch_request,
DEFAULT_MODEL_PROVIDER,
"gpt-5.4",
"reasoning-basis-test",
&test_reasoning_basis(&launch_request)?,
)?;
let tool_names = model_request
.tools
@ -4075,7 +4147,7 @@ mod tests {
&research_launch,
DEFAULT_MODEL_PROVIDER,
"gpt-5.4",
"reasoning-basis-test",
&test_reasoning_basis(&research_launch)?,
)?;
assert!(
!research_request