Seal role passes from keyed Mind
This commit is contained in:
parent
4ad62ac49d
commit
7934652381
6 changed files with 760 additions and 77 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Reference in a new issue