Delete test-only Eyes claim challenge authority

This commit is contained in:
Meta Vens 2026-08-23 21:59:34 +02:00
commit 2dfd8c728c
6 changed files with 42 additions and 507 deletions

View file

@ -5571,82 +5571,6 @@ mod tests {
.all(|envelope| envelope.r#type != "epiphany.thread_state")
);
let challenged_plan_store = temp.path().join("challenged-plan.cc");
std::fs::copy(&store, &challenged_plan_store)?;
let mut challenged_cache = crate::runtime_spine_cache(&challenged_plan_store)?;
challenged_cache.pull_all_backing_stores()?;
let challenged_model = crate::assemble_repo_model_view(&challenged_plan_store)?;
let challenged_claim = challenged_model
.nodes
.iter()
.find(|node| node.id == "body-node")
.expect("planning claim");
let packet = crate::EyesEvidencePacket {
schema_version: crate::EYES_EVIDENCE_PACKET_SCHEMA_VERSION.into(),
packet_id: "planning-challenge-packet".into(),
source_result_id: "planning-challenge-result".into(),
source_job_id: "planning-challenge-job".into(),
source_role_id: "research".into(),
evidence_ids: vec!["planning-challenge-evidence".into()],
observation_ids: vec!["planning-challenge-observation".into()],
source_refs: vec![
"github://GameCult/Epiphany@0000000000000000000000000000000000000000/README.md"
.into(),
],
summary: "External evidence challenges the planning claim.".into(),
uncertainty: "Bounded fixture uncertainty.".into(),
emitted_at: "2026-08-17T00:00:21.300Z".into(),
contract: "epiphany.eyes.evidence_packet.fixture".into(),
source_lookup_receipt_ids: Vec::new(),
research_request_id: "planning-challenge-research-request".into(),
decision_context_id: "planning-challenge-decision-context".into(),
};
crate::runtime_spine::put_eyes_evidence_packet(&challenged_plan_store, &packet)?;
let challenge = crate::RepoModelClaimChallenge {
schema_version: crate::REPO_MODEL_CLAIM_CHALLENGE_SCHEMA_VERSION.into(),
challenge_id: "planning-claim-challenge".into(),
eyes_evidence_packet_id: packet.packet_id.clone(),
eyes_evidence_packet_sha256: format!(
"{:x}",
Sha256::digest(rmp_serde::to_vec_named(&packet)?)
),
source_result_id: packet.source_result_id.clone(),
source_job_id: packet.source_job_id.clone(),
model_projection_digest: planning_request.model_projection_digest.clone(),
model_source_documents: planning_request.model_source_documents.clone(),
target_claim_id: challenged_claim.id.clone(),
target_claim_sha256: format!(
"{:x}",
Sha256::digest(rmp_serde::to_vec_named(challenged_claim)?)
),
disposition: crate::RepoModelClaimChallengeDisposition::EvidenceInsufficient,
finding: "The exact target claim requires external correction.".into(),
uncertainty: "The plan must be regenerated after evidence admission.".into(),
source_refs: packet.source_refs.clone(),
evidence_ids: packet.evidence_ids.clone(),
challenged_at: "2026-08-17T00:00:21.400Z".into(),
contract: crate::REPO_MODEL_CLAIM_CHALLENGE_CONTRACT.into(),
};
crate::commit_repo_model_claim_challenge(&challenged_plan_store, &challenge)?;
challenged_cache.pull_all_backing_stores()?;
let challenged_snapshot = challenged_cache.snapshot_envelopes();
assert!(
crate::runtime_spine::validate_actionable_repo_frontier_planning_request(
&challenged_cache,
&planning_request,
)
.is_err()
);
assert!(
launch_current_frontier_planning_work(
&challenged_plan_store,
"2026-08-17T00:00:21.500Z",
)
.is_err()
);
challenged_cache.pull_all_backing_stores()?;
assert_eq!(challenged_cache.snapshot_envelopes(), challenged_snapshot);
let mut disjoint_planning_node = final_model
.nodes
.iter()

View file

@ -296,7 +296,6 @@ pub use runtime_spine::close_runtime_session;
pub use runtime_spine::commit_repo_frontier_modeling_request;
pub use runtime_spine::commit_repo_frontier_plan_decision;
pub use runtime_spine::commit_repo_frontier_plan_mind_request;
pub use runtime_spine::commit_repo_model_claim_challenge;
pub use runtime_spine::complete_runtime_job;
pub use runtime_spine::coordinator_run_receipts;
pub use runtime_spine::coordinator_run_session_id;

View file

@ -13,7 +13,7 @@ use sha2::{Digest, Sha256};
use crate::{EpiphanyMindDocumentVersion, runtime_spine_cache};
pub const MIND_SCHEMA_EPOCH: &str = "epiphany.mind.epoch.v7";
pub const MIND_SCHEMA_EPOCH: &str = "epiphany.mind.epoch.v8";
pub const MIND_OBJECTIVE_KEY: &str = "objective";
pub const MIND_FOCUS_KEY: &str = "focus";
pub const MIND_MODE_KEY: &str = "mode";

View file

@ -4,8 +4,8 @@ use std::path::Path;
use anyhow::{Result, anyhow};
use cultcache_rs::{CultCache, CultCacheEnvelope, DatabaseEntry};
use epiphany_state_model::{
EpiphanyMemoryDomain, EpiphanyMemoryEdge, EpiphanyMemoryGraphSnapshot,
EpiphanyMemoryNode, RepoFrontierItem,
EpiphanyMemoryDomain, EpiphanyMemoryEdge, EpiphanyMemoryGraphSnapshot, EpiphanyMemoryNode,
RepoFrontierItem,
};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
@ -87,7 +87,7 @@ repo_document!(
);
#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
#[cultcache(
type = "epiphany.mind.repo_model.claim_obligations.v2",
type = "epiphany.mind.repo_model.claim_obligations.v3",
schema = "EpiphanyRepoModelClaimObligationsDocument"
)]
pub struct EpiphanyRepoModelClaimObligationsDocument {
@ -95,8 +95,6 @@ pub struct EpiphanyRepoModelClaimObligationsDocument {
pub node_id: String,
#[cultcache(key = 1)]
pub unresolved_frontier_ids: Vec<String>,
#[cultcache(key = 2)]
pub active_challenge_ids: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@ -798,7 +796,6 @@ pub fn plan_repo_model_mutation(
EpiphanyRepoModelClaimObligationsDocument {
node_id: node.id.clone(),
unresolved_frontier_ids: Vec::new(),
active_challenge_ids: Vec::new(),
}
});
if let Some(existing) =
@ -806,7 +803,6 @@ pub fn plan_repo_model_mutation(
{
insert_strong_envelope(&mut strong, existing)?;
}
obligation.active_challenge_ids.clear();
let envelope = cache
.prepare_entry(&node.id, &EpiphanyRepoModelNodeDocument::new(node)?)?
.0;
@ -827,12 +823,9 @@ pub fn plan_repo_model_mutation(
EpiphanyRepoModelClaimObligationsDocument {
node_id: node_id.clone(),
unresolved_frontier_ids: Vec::new(),
active_challenge_ids: Vec::new(),
}
});
if !obligation.unresolved_frontier_ids.is_empty()
|| !obligation.active_challenge_ids.is_empty()
{
if !obligation.unresolved_frontier_ids.is_empty() {
return Err(anyhow!(
"RepoModel node retirement is blocked by unresolved claim obligations"
));
@ -937,7 +930,6 @@ pub fn plan_repo_model_mutation(
EpiphanyRepoModelClaimObligationsDocument {
node_id: node_id.clone(),
unresolved_frontier_ids: Vec::new(),
active_challenge_ids: Vec::new(),
}
});
if let Some(existing) =
@ -1355,7 +1347,6 @@ fn claim_obligations_for_frontier(
|(node_id, unresolved_frontier_ids)| EpiphanyRepoModelClaimObligationsDocument {
node_id,
unresolved_frontier_ids: unresolved_frontier_ids.into_iter().collect(),
active_challenge_ids: Vec::new(),
},
)
.collect()
@ -1423,38 +1414,6 @@ pub(crate) fn assemble_repo_model_view_from_cache(
frontier.clone(),
claim_obligations.clone(),
)?;
let challenges = cache.get_all::<crate::RepoModelClaimChallenge>()?;
for obligation in &claim_obligations {
for challenge_id in &obligation.active_challenge_ids {
let challenge = challenges
.iter()
.find(|challenge| challenge.challenge_id == *challenge_id)
.ok_or_else(|| anyhow!("claim obligation names a missing challenge"))?;
if challenge.target_claim_id != obligation.node_id {
return Err(anyhow!("claim obligation challenge targets another node"));
}
}
}
for challenge in &challenges {
let Some(node) = nodes
.iter()
.find(|node| node.id == challenge.target_claim_id)
else {
continue;
};
let node_sha256 = format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(node)?));
if node_sha256 == challenge.target_claim_sha256
&& !claim_obligations.iter().any(|obligation| {
obligation.node_id == challenge.target_claim_id
&& obligation
.active_challenge_ids
.contains(&challenge.challenge_id)
})
{
return Err(anyhow!("current claim challenge lost its claim obligation"));
}
}
let mut source_documents = cache
.snapshot_envelopes()
.into_iter()
@ -1539,14 +1498,6 @@ fn validate_claim_obligations(
.unresolved_frontier_ids
.windows(2)
.all(|pair| pair[0] < pair[1])
|| !obligation
.active_challenge_ids
.windows(2)
.all(|pair| pair[0] < pair[1])
|| obligation
.active_challenge_ids
.iter()
.any(|id| id.trim().is_empty())
{
return Err(anyhow!("RepoModel claim obligation is not canonical"));
}
@ -1592,8 +1543,7 @@ mod tests {
use super::*;
use crate::{RuntimeSpineInitOptions, initialize_runtime_spine};
use epiphany_state_model::{
EpiphanyMemoryEdgeKind, EpiphanyMemoryLifecycle, EpiphanyMemoryNodeKind,
RepoFrontierStatus,
EpiphanyMemoryEdgeKind, EpiphanyMemoryLifecycle, EpiphanyMemoryNodeKind, RepoFrontierStatus,
};
fn bind_test_body(
@ -1816,7 +1766,6 @@ mod tests {
&EpiphanyRepoModelClaimObligationsDocument {
node_id: "node-1".into(),
unresolved_frontier_ids: Vec::new(),
active_challenge_ids: Vec::new(),
},
)?;
let first = assemble_repo_model_view(&store)?;

View file

@ -77,9 +77,6 @@ pub const REPO_FRONTIER_PROPOSAL_MODELING_LAUNCH_BINDING_SCHEMA_VERSION: &str =
"epiphany.coordinator.repo_frontier_proposal_modeling_launch_binding.v1";
pub const REPO_FRONTIER_PROPOSAL_MODELING_LAUNCH_BINDING_CONTRACT: &str =
"epiphany.repo_frontier_proposal_modeling_launch_binding.v1";
pub const REPO_MODEL_CLAIM_CHALLENGE_SCHEMA_VERSION: &str =
"epiphany.eyes.repo_model_claim_challenge.v0";
pub const REPO_MODEL_CLAIM_CHALLENGE_CONTRACT: &str = "epiphany.repo_model_claim_challenge.v0";
pub const REPO_FRONTIER_PLANNING_LAUNCH_BINDING_SCHEMA_VERSION: &str =
"epiphany.coordinator.repo_frontier_planning_launch_binding.v0";
pub const REPO_FRONTIER_PLANNING_LAUNCH_BINDING_CONTRACT: &str =
@ -93,56 +90,6 @@ pub const REPO_FRONTIER_PLAN_MIND_LAUNCH_BINDING_SCHEMA_VERSION: &str =
pub const REPO_FRONTIER_PLAN_MIND_LAUNCH_BINDING_CONTRACT: &str =
"epiphany.repo_frontier_plan_mind_launch_binding.v0";
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RepoModelClaimChallengeDisposition {
Contradicted,
Stale,
EvidenceInsufficient,
}
#[derive(Debug, Clone, PartialEq, Eq, DatabaseEntry)]
#[cultcache(
type = "epiphany.eyes.repo_model_claim_challenge",
schema = "RepoModelClaimChallenge"
)]
pub struct RepoModelClaimChallenge {
#[cultcache(key = 0)]
pub schema_version: String,
#[cultcache(key = 1)]
pub challenge_id: String,
#[cultcache(key = 2)]
pub eyes_evidence_packet_id: String,
#[cultcache(key = 3)]
pub eyes_evidence_packet_sha256: String,
#[cultcache(key = 4)]
pub source_result_id: String,
#[cultcache(key = 5)]
pub source_job_id: String,
#[cultcache(key = 6)]
pub model_projection_digest: String,
#[cultcache(key = 7)]
pub model_source_documents: Vec<crate::EpiphanyMindDocumentVersion>,
#[cultcache(key = 8)]
pub target_claim_id: String,
#[cultcache(key = 9)]
pub target_claim_sha256: String,
#[cultcache(key = 10)]
pub disposition: RepoModelClaimChallengeDisposition,
#[cultcache(key = 11)]
pub finding: String,
#[cultcache(key = 12)]
pub uncertainty: String,
#[cultcache(key = 13)]
pub source_refs: Vec<String>,
#[cultcache(key = 14)]
pub evidence_ids: Vec<String>,
#[cultcache(key = 15)]
pub challenged_at: String,
#[cultcache(key = 16)]
pub contract: String,
}
#[derive(Debug, Clone, PartialEq, Eq, DatabaseEntry)]
#[cultcache(
type = "epiphany.evidence.repo_frontier_work_proposal",

View file

@ -6,8 +6,6 @@ use crate::agent_launch::{
EPIPHANY_MODELING_ROLE_BINDING_ID,
};
use crate::continuity_gateway::ContinuityRecoveryReceipt;
use crate::eyes_gateway::EYES_EVIDENCE_PACKET_SCHEMA_VERSION;
use crate::eyes_gateway::EYES_EVIDENCE_PACKET_TYPE;
use crate::eyes_gateway::EyesEvidencePacket;
use crate::eyes_gateway::EyesSourceLookupReceipt;
use crate::hands_gateway::*;
@ -32,7 +30,6 @@ use crate::repo_model_gateway::{
REPO_FRONTIER_RESEARCH_REQUEST_CONTRACT, REPO_FRONTIER_RESEARCH_REQUEST_SCHEMA_VERSION,
REPO_FRONTIER_ROUTE_CONTRACT, REPO_FRONTIER_ROUTE_SCHEMA_VERSION,
REPO_FRONTIER_WORK_PROPOSAL_CONTRACT, REPO_FRONTIER_WORK_PROPOSAL_SCHEMA_VERSION,
REPO_MODEL_CLAIM_CHALLENGE_CONTRACT, REPO_MODEL_CLAIM_CHALLENGE_SCHEMA_VERSION,
RUNTIME_REPOSITORY_DOMAIN_BINDING_CONTRACT, RUNTIME_REPOSITORY_DOMAIN_BINDING_KEY,
RUNTIME_REPOSITORY_DOMAIN_BINDING_SCHEMA_VERSION, RepoFrontierAutonomousProposalBinding,
RepoFrontierHandsAuthority, RepoFrontierModelingRequest, RepoFrontierNextOrgan,
@ -42,8 +39,7 @@ use crate::repo_model_gateway::{
RepoFrontierPlanningLifecycle, RepoFrontierPlanningLifecycleStage, RepoFrontierPlanningRequest,
RepoFrontierProposalModelingLaunchBinding, RepoFrontierProposalModelingRequest,
RepoFrontierResearchRequest, RepoFrontierRoute, RepoFrontierVerdictDisposition,
RepoFrontierWorkProposal, RepoModelClaimChallenge,
RuntimeRepositoryDomainBinding,
RepoFrontierWorkProposal, RuntimeRepositoryDomainBinding,
};
use crate::runtime_store_backend::{
RuntimeSpineBackingStore as SingleFileMessagePackBackingStore, runtime_spine_backing_store,
@ -102,7 +98,7 @@ pub const COORDINATOR_RUN_RECEIPT_TYPE: &str = "epiphany.coordinator_run_receipt
pub const RUNTIME_IDENTITY_KEY: &str = "self";
pub const RUNTIME_SWARM_BINDING_KEY: &str = "runtime-swarm-binding";
pub const RUNTIME_SWARM_BINDING_SCHEMA_VERSION: &str = "epiphany.runtime.swarm_binding.v1";
pub const RUNTIME_SPINE_SCHEMA_VERSION: &str = "epiphany.runtime_spine.v10";
pub const RUNTIME_SPINE_SCHEMA_VERSION: &str = "epiphany.runtime_spine.v11";
pub const EPIPHANY_RUNTIME_ROOT_SESSION_ID: &str = "epiphany-main";
pub const RUNTIME_MODEL_EXECUTION_BINDING_SCHEMA_VERSION: &str =
"epiphany.runtime.model_execution_binding.v0";
@ -916,7 +912,6 @@ fn runtime_spine_schema_cache() -> Result<CultCache> {
cache.register_entry_type::<EpiphanyArchivedRuntimeWorkerAttempt>()?;
cache.register_entry_type::<EpiphanyRuntimeRoleWorkerResult>()?;
cache.register_entry_type::<crate::RuntimeRepositoryBodyStoreBinding>()?;
cache.register_entry_type::<RepoModelClaimChallenge>()?;
cache.register_entry_type::<RepoFrontierRoute>()?;
cache.register_entry_type::<RepoFrontierHandsAuthority>()?;
cache.register_entry_type::<RepoFrontierModelingRequest>()?;
@ -1137,7 +1132,6 @@ pub fn bind_runtime_to_swarm(
}
}
pub fn create_runtime_session(
store_path: impl AsRef<Path>,
options: RuntimeSpineSessionOptions,
@ -2639,7 +2633,9 @@ pub fn prepare_runtime_spine_heartbeat_job(
.get_envelope::<EpiphanyRuntimeIdentity>(RUNTIME_IDENTITY_KEY)?
.ok_or_else(|| anyhow!("runtime job preparation lost runtime identity envelope"))?;
if identity.runtime_id != options.runtime_id {
return Err(anyhow!("runtime job preparation cannot substitute runtime identity"));
return Err(anyhow!(
"runtime job preparation cannot substitute runtime identity"
));
}
let session = match cache.get::<EpiphanyRuntimeSession>(&options.session_id)? {
Some(existing)
@ -2713,10 +2709,11 @@ pub fn prepare_runtime_spine_heartbeat_job(
repo_frontier_research_request_id: options.repo_frontier_research_request_id,
repo_frontier_verification_request_id: options.repo_frontier_verification_request_id,
};
let session_envelope = match cache.get_envelope::<EpiphanyRuntimeSession>(&session.session_id)? {
Some(existing) => existing,
None => cache.prepare_entry(&session.session_id, &session)?.0,
};
let session_envelope =
match cache.get_envelope::<EpiphanyRuntimeSession>(&session.session_id)? {
Some(existing) => existing,
None => cache.prepare_entry(&session.session_id, &session)?.0,
};
let envelopes = vec![
identity_envelope,
session_envelope,
@ -3013,7 +3010,6 @@ pub fn runtime_worker_launch_request(
cache.get::<EpiphanyRuntimeWorkerLaunchRequest>(job_id)
}
pub fn runtime_worker_process_claim(
store_path: impl AsRef<Path>,
job_id: &str,
@ -5792,7 +5788,6 @@ pub fn promote_autonomous_direction_options_for_modeling(
Ok(promoted)
}
fn current_keyed_repo_model(
cache: &CultCache,
) -> Result<(crate::EpiphanyRepoModelView, crate::EpiphanyRepoModelBasis)> {
@ -5835,7 +5830,6 @@ fn keyed_repo_model_basis_envelopes(
.collect()
}
pub fn select_and_commit_repo_frontier_planning_request(
runtime_store: impl AsRef<Path>,
at: &str,
@ -5849,8 +5843,7 @@ pub fn select_and_commit_repo_frontier_planning_request(
let backing = SingleFileMessagePackBackingStore::new(runtime_store);
let (view, basis) = current_keyed_repo_model(&cache)?;
let model = view.memory_context_projection();
let challenges = current_repo_model_claim_challenges(&cache, &model, &basis)?;
let item = actionable_imagination_frontier_item(&model, &challenges)
let item = actionable_imagination_frontier_item(&model)
.ok_or_else(|| anyhow!("planning requires an actionable Imagination frontier"))?;
let item_hash = repo_frontier_item_hash(item)?;
let frontier_authority_documents = frontier_authority_documents(&cache, item)?;
@ -6036,9 +6029,7 @@ pub(crate) fn validate_actionable_repo_frontier_planning_request(
}
let view = crate::repo_model_documents::assemble_repo_model_view_from_cache(cache)?;
let model = view.memory_context_projection();
let basis = view.reasoning_basis();
let challenges = current_repo_model_claim_challenges(cache, &model, &basis)?;
if !imagination_frontier_item_is_actionable(&model, &challenges, &current_item) {
if !imagination_frontier_item_is_actionable(&model, &current_item) {
return Err(anyhow!("planning request frontier is no longer actionable"));
}
Ok(())
@ -6180,14 +6171,13 @@ fn validate_repo_frontier_plan_mind_request_identity(
Ok((planning, candidate))
}
fn actionable_imagination_frontier_item<'a>(
model: &'a crate::EpiphanyMemoryGraphSnapshot,
challenges: &[RepoModelClaimChallenge],
) -> Option<&'a crate::RepoFrontierItem> {
fn actionable_imagination_frontier_item(
model: &crate::EpiphanyMemoryGraphSnapshot,
) -> Option<&crate::RepoFrontierItem> {
let mut eligible = model
.frontier
.iter()
.filter(|item| imagination_frontier_item_is_actionable(model, challenges, item))
.filter(|item| imagination_frontier_item_is_actionable(model, item))
.collect::<Vec<_>>();
eligible.sort_by(|a, b| a.id.cmp(&b.id));
eligible.into_iter().next()
@ -6195,7 +6185,6 @@ fn actionable_imagination_frontier_item<'a>(
fn imagination_frontier_item_is_actionable(
model: &crate::EpiphanyMemoryGraphSnapshot,
challenges: &[RepoModelClaimChallenge],
item: &crate::RepoFrontierItem,
) -> bool {
let terminal = |id: &str| {
@ -6215,214 +6204,9 @@ fn imagination_frontier_item_is_actionable(
item.status == crate::RepoFrontierStatus::Active
&& item.recommended_next_organ == "Imagination"
&& crate::memory_graph::frontier_item_has_routeable_repository_scope(item)
&& frontier_target_claims_unchallenged(item, challenges)
&& item.dependency_item_ids.iter().all(|id| terminal(id))
}
fn frontier_target_claims_unchallenged(
item: &crate::RepoFrontierItem,
challenges: &[RepoModelClaimChallenge],
) -> bool {
!challenges
.iter()
.any(|challenge| item.target_claim_ids.contains(&challenge.target_claim_id))
}
fn current_repo_model_claim_challenges(
cache: &CultCache,
model: &crate::EpiphanyMemoryGraphSnapshot,
basis: &crate::EpiphanyRepoModelBasis,
) -> Result<Vec<RepoModelClaimChallenge>> {
let mut current = Vec::new();
for challenge in cache.get_all::<RepoModelClaimChallenge>()? {
let Some(claim) = model
.nodes
.iter()
.find(|node| node.id == challenge.target_claim_id)
else {
continue;
};
if format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(claim)?))
== challenge.target_claim_sha256
{
validate_repo_model_claim_challenge_chain(cache, model, basis, &challenge, true)?;
current.push(challenge);
}
}
Ok(current)
}
fn validate_repo_model_claim_challenge_chain(
cache: &CultCache,
model: &crate::EpiphanyMemoryGraphSnapshot,
_current_basis: &crate::EpiphanyRepoModelBasis,
challenge: &RepoModelClaimChallenge,
require_current_model: bool,
) -> Result<()> {
if challenge.schema_version != REPO_MODEL_CLAIM_CHALLENGE_SCHEMA_VERSION
|| challenge.contract != REPO_MODEL_CLAIM_CHALLENGE_CONTRACT
|| challenge.challenge_id.trim().is_empty()
|| challenge.finding.trim().is_empty()
|| challenge.uncertainty.trim().is_empty()
|| challenge.source_refs.is_empty()
|| challenge.evidence_ids.is_empty()
|| chrono::DateTime::parse_from_rfc3339(&challenge.challenged_at).is_err()
{
return Err(anyhow!("invalid repo model claim challenge"));
}
let packet = cache
.get::<EyesEvidencePacket>(&challenge.eyes_evidence_packet_id)?
.ok_or_else(|| anyhow!("claim challenge requires exact Eyes evidence packet"))?;
if packet.schema_version != EYES_EVIDENCE_PACKET_SCHEMA_VERSION
|| packet.contract.trim().is_empty()
|| chrono::DateTime::parse_from_rfc3339(&packet.emitted_at).is_err()
|| packet.source_result_id != challenge.source_result_id
|| packet.source_job_id != challenge.source_job_id
|| packet.source_refs != challenge.source_refs
|| packet.evidence_ids != challenge.evidence_ids
|| format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(&packet)?))
!= challenge.eyes_evidence_packet_sha256
{
return Err(anyhow!("claim challenge substituted Eyes evidence"));
}
let audit_basis = crate::EpiphanyRepoModelBasis {
projection_digest: challenge.model_projection_digest.clone(),
source_documents: challenge.model_source_documents.clone(),
};
audit_basis.validate()?;
let claim = model
.nodes
.iter()
.find(|node| node.id == challenge.target_claim_id)
.ok_or_else(|| anyhow!("claim challenge target claim is missing"))?;
if format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(claim)?))
!= challenge.target_claim_sha256
{
return Err(anyhow!("claim challenge target claim identity mismatch"));
}
let claim_envelope = cache
.get_envelope::<crate::EpiphanyRepoModelNodeDocument>(&claim.id)?
.ok_or_else(|| anyhow!("claim challenge target claim envelope is missing"))?;
let claim_version =
crate::EpiphanyMindDocumentVersion::from_envelope("epiphany-mind", &claim_envelope)?;
if !audit_basis.source_documents.contains(&claim_version) {
return Err(anyhow!(
"claim challenge audit basis omitted its exact target claim"
));
}
if require_current_model {
let obligation = cache
.get::<crate::EpiphanyRepoModelClaimObligationsDocument>(&claim.id)?
.ok_or_else(|| anyhow!("claim challenge target lost its obligation owner"))?;
if obligation.node_id != claim.id {
return Err(anyhow!("claim challenge obligation owner is corrupt"));
}
}
Ok(())
}
pub fn commit_repo_model_claim_challenge(
store_path: impl AsRef<Path>,
challenge: &RepoModelClaimChallenge,
) -> Result<()> {
if challenge.schema_version != REPO_MODEL_CLAIM_CHALLENGE_SCHEMA_VERSION
|| challenge.contract != REPO_MODEL_CLAIM_CHALLENGE_CONTRACT
|| challenge.challenge_id.trim().is_empty()
|| challenge.finding.trim().is_empty()
|| challenge.uncertainty.trim().is_empty()
|| challenge.source_refs.is_empty()
|| challenge.evidence_ids.is_empty()
|| chrono::DateTime::parse_from_rfc3339(&challenge.challenged_at).is_err()
{
return Err(anyhow!("invalid repo model claim challenge"));
}
let store_path = store_path.as_ref();
let mut cache = runtime_spine_cache(store_path)?;
cache.pull_all_backing_stores()?;
let backing = SingleFileMessagePackBackingStore::new(store_path);
let envelopes = backing.pull_all()?;
let (view, basis) = current_keyed_repo_model(&cache)?;
let model = view.memory_context_projection();
validate_repo_model_claim_challenge_chain(&cache, &model, &basis, challenge, true)?;
if let Some(existing) = cache.get::<RepoModelClaimChallenge>(&challenge.challenge_id)? {
if existing != *challenge {
return Err(anyhow!("claim challenge ids are immutable"));
}
let obligation = cache
.get::<crate::EpiphanyRepoModelClaimObligationsDocument>(&challenge.target_claim_id)?
.ok_or_else(|| anyhow!("replayed claim challenge lost its obligation"))?;
return if obligation
.active_challenge_ids
.contains(&challenge.challenge_id)
{
Ok(())
} else {
Err(anyhow!("replayed claim challenge lost active authority"))
};
}
let packet_envelope = envelopes
.iter()
.find(|entry| {
entry.r#type == EYES_EVIDENCE_PACKET_TYPE
&& entry.key == challenge.eyes_evidence_packet_id
})
.cloned()
.ok_or_else(|| anyhow!("claim challenge packet envelope is missing"))?;
let (challenge_envelope, _) = cache.prepare_entry(&challenge.challenge_id, challenge)?;
let claim_envelope = cache
.get_envelope::<crate::EpiphanyRepoModelNodeDocument>(&challenge.target_claim_id)?
.ok_or_else(|| anyhow!("claim challenge target envelope is missing"))?;
let mut obligation = cache
.get::<crate::EpiphanyRepoModelClaimObligationsDocument>(&challenge.target_claim_id)?
.ok_or_else(|| anyhow!("claim challenge target obligation is missing"))?;
let obligation_envelope = cache
.get_envelope::<crate::EpiphanyRepoModelClaimObligationsDocument>(
&challenge.target_claim_id,
)?
.ok_or_else(|| anyhow!("claim challenge target obligation envelope is missing"))?;
obligation
.active_challenge_ids
.push(challenge.challenge_id.clone());
obligation.active_challenge_ids.sort();
obligation.active_challenge_ids.dedup();
let expected = vec![claim_envelope, obligation_envelope.clone(), packet_envelope];
let mut writes = expected
.iter()
.filter(|envelope| {
envelope.r#type != obligation_envelope.r#type || envelope.key != obligation_envelope.key
})
.cloned()
.collect::<Vec<_>>();
writes.push(challenge_envelope);
writes.push(
cache
.prepare_entry(&challenge.target_claim_id, &obligation)?
.0,
);
if !backing.compare_and_swap_batch(&expected, writes)? {
let mut reloaded = runtime_spine_cache(store_path)?;
reloaded.pull_all_backing_stores()?;
return match (
reloaded.get::<RepoModelClaimChallenge>(&challenge.challenge_id)?,
reloaded.get::<crate::EpiphanyRepoModelClaimObligationsDocument>(
&challenge.target_claim_id,
)?,
) {
(Some(existing), Some(obligation))
if existing == *challenge
&& obligation
.active_challenge_ids
.contains(&challenge.challenge_id) =>
{
Ok(())
}
(Some(_), _) => Err(anyhow!("claim challenge immutable collision")),
_ => Err(anyhow!("claim challenge lost exact claim/packet CAS")),
};
}
Ok(())
}
fn validate_repo_frontier_plan_candidate_against_request(
cache: &CultCache,
candidate: &RepoFrontierPlanCandidate,
@ -6710,8 +6494,7 @@ pub fn select_and_commit_repo_frontier_route(
let backing = SingleFileMessagePackBackingStore::new(runtime_store);
let (view, basis) = current_keyed_repo_model(&cache)?;
let current = view.memory_context_projection();
let challenges = current_repo_model_claim_challenges(&cache, &current, &basis)?;
let item = actionable_hands_frontier_item(&current, &challenges)
let item = actionable_hands_frontier_item(&current)
.ok_or_else(|| anyhow!("current repo model has no eligible Hands frontier route"))?;
if !crate::memory_graph::frontier_item_has_routeable_repository_scope(item) {
return Err(anyhow!(
@ -6768,36 +6551,26 @@ pub fn select_and_commit_repo_frontier_route(
Ok(route)
}
fn actionable_hands_frontier_item<'a>(
model: &'a crate::EpiphanyMemoryGraphSnapshot,
challenges: &[RepoModelClaimChallenge],
) -> Option<&'a crate::RepoFrontierItem> {
actionable_frontier_item_for_organ(model, challenges, "Hands", true)
fn actionable_hands_frontier_item(
model: &crate::EpiphanyMemoryGraphSnapshot,
) -> Option<&crate::RepoFrontierItem> {
actionable_frontier_item_for_organ(model, "Hands")
}
fn actionable_frontier_item_for_organ<'a>(
model: &'a crate::EpiphanyMemoryGraphSnapshot,
challenges: &[RepoModelClaimChallenge],
organ: &str,
require_unchallenged_targets: bool,
) -> Option<&'a crate::RepoFrontierItem> {
model.frontier.iter().find(|item| {
frontier_item_is_actionable_for_organ(
model,
challenges,
item,
organ,
require_unchallenged_targets,
)
})
model
.frontier
.iter()
.find(|item| frontier_item_is_actionable_for_organ(model, item, organ))
}
fn frontier_item_is_actionable_for_organ(
model: &crate::EpiphanyMemoryGraphSnapshot,
challenges: &[RepoModelClaimChallenge],
item: &crate::RepoFrontierItem,
organ: &str,
require_unchallenged_targets: bool,
) -> bool {
let terminal = |status: crate::RepoFrontierStatus| {
matches!(
@ -6810,7 +6583,6 @@ fn frontier_item_is_actionable_for_organ(
item.status == crate::RepoFrontierStatus::Active
&& item.recommended_next_organ == organ
&& crate::memory_graph::frontier_item_has_routeable_repository_scope(item)
&& (!require_unchallenged_targets || frontier_target_claims_unchallenged(item, challenges))
&& item.dependency_item_ids.iter().all(|dependency_id| {
model
.frontier
@ -6825,10 +6597,9 @@ fn frontier_item_is_actionable_for_organ(
/// Hands. Status projection must use this instead of assuming that a clear
/// CRRC lane implies implementation authority.
pub fn runtime_has_actionable_hands_frontier(runtime_store: impl AsRef<Path>) -> Result<bool> {
runtime_has_actionable_frontier_for_organ(runtime_store, "Hands", true)
runtime_has_actionable_frontier_for_organ(runtime_store, "Hands")
}
fn frontier_authority_documents(
cache: &CultCache,
item: &crate::RepoFrontierItem,
@ -6937,11 +6708,6 @@ fn planning_claim_obligation_envelopes(
{
return Err(anyhow!("planning claim obligation changed"));
}
let obligation: crate::EpiphanyRepoModelClaimObligationsDocument =
rmp_serde::from_slice(&envelope.payload)?;
if !obligation.active_challenge_ids.is_empty() {
return Err(anyhow!("planning claim is challenged"));
}
Ok(envelope.clone())
})
.collect()
@ -7084,7 +6850,7 @@ pub fn select_and_commit_repo_frontier_research_request(
let model = view.memory_context_projection();
let launches = cache.get_all::<EpiphanyRuntimeWorkerLaunchRequest>()?;
let packets = cache.get_all::<EyesEvidencePacket>()?;
let item = match next_repo_frontier_research_work(&cache, &model, &[], &launches, &packets)? {
let item = match next_repo_frontier_research_work(&cache, &model, &launches, &packets)? {
Some(NextRepoFrontierResearchWork::Existing(request)) => return Ok(request),
Some(NextRepoFrontierResearchWork::Unrequested(item)) => item,
None => {
@ -7176,7 +6942,6 @@ fn repo_frontier_research_request_for_admitted_item(
})
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum RepoFrontierResearchLifecycleStage {
@ -7245,7 +7010,7 @@ pub fn runtime_repo_frontier_research_lifecycle(
let (view, _basis) = current_keyed_repo_model(&cache)?;
let model = view.memory_context_projection();
let work = next_repo_frontier_research_work(&cache, &model, &[], &launches, &packets)?;
let work = next_repo_frontier_research_work(&cache, &model, &launches, &packets)?;
let request = match work {
Some(NextRepoFrontierResearchWork::Unrequested(item)) => {
return Ok(RepoFrontierResearchLifecycle {
@ -7352,7 +7117,6 @@ enum NextRepoFrontierResearchWork {
fn next_repo_frontier_research_work(
cache: &CultCache,
model: &crate::EpiphanyMemoryGraphSnapshot,
challenges: &[RepoModelClaimChallenge],
launches: &[EpiphanyRuntimeWorkerLaunchRequest],
packets: &[EyesEvidencePacket],
) -> Result<Option<NextRepoFrontierResearchWork>> {
@ -7372,9 +7136,11 @@ fn next_repo_frontier_research_work(
if let Some(request) = existing_uncovered.into_iter().next() {
return Ok(Some(NextRepoFrontierResearchWork::Existing(request)));
}
for item in model.frontier.iter().filter(|item| {
frontier_item_is_actionable_for_organ(model, challenges, item, "Eyes", false)
}) {
for item in model
.frontier
.iter()
.filter(|item| frontier_item_is_actionable_for_organ(model, item, "Eyes"))
{
let item_hash = repo_frontier_item_hash(item)?;
if !existing_actionable.iter().any(|request| {
request.frontier_item_id == item.id && request.frontier_item_hash == item_hash
@ -7647,7 +7413,7 @@ pub fn runtime_repo_frontier_planning_lifecycle(
..empty(RepoFrontierPlanningLifecycleStage::Terminal)
});
}
if runtime_has_actionable_frontier_for_organ(runtime_store, "Imagination", true)? {
if runtime_has_actionable_frontier_for_organ(runtime_store, "Imagination")? {
return Ok(empty(RepoFrontierPlanningLifecycleStage::Ready));
}
let latest_terminal = decisions.iter().max_by(|a, b| {
@ -7818,28 +7584,16 @@ pub fn runtime_repo_frontier_planning_lifecycle(
fn runtime_has_actionable_frontier_for_organ(
runtime_store: impl AsRef<Path>,
organ: &str,
require_unchallenged_targets: bool,
) -> Result<bool> {
let runtime_store = runtime_store.as_ref();
let mut cache = runtime_spine_cache(runtime_store)?;
cache.pull_all_backing_stores()?;
require_identity(&cache)?;
let Ok((view, basis)) = current_keyed_repo_model(&cache) else {
let Ok((view, _basis)) = current_keyed_repo_model(&cache) else {
return Ok(false);
};
let model = view.memory_context_projection();
let challenges = if require_unchallenged_targets {
current_repo_model_claim_challenges(&cache, &model, &basis)?
} else {
Vec::new()
};
Ok(actionable_frontier_item_for_organ(
&model,
&challenges,
organ,
require_unchallenged_targets,
)
.is_some())
Ok(actionable_frontier_item_for_organ(&model, organ).is_some())
}
pub fn put_runtime_reorient_worker_result(
@ -7890,32 +7644,6 @@ pub fn runtime_reorient_worker_result(
cache.get::<EpiphanyRuntimeReorientWorkerResult>(job_id)
}
// Eyes packets are accepted-research prerequisites and publish atomically with
// the coordinator state transition. Direct insertion is fixture-only.
#[cfg(test)]
pub(crate) fn put_eyes_evidence_packet(
store_path: impl AsRef<Path>,
packet: &EyesEvidencePacket,
) -> Result<()> {
validate_non_empty(&packet.packet_id, "Eyes evidence packet id")?;
validate_non_empty(
&packet.source_result_id,
"Eyes evidence packet source result",
)?;
validate_non_empty(&packet.source_job_id, "Eyes evidence packet source job")?;
validate_non_empty(&packet.source_role_id, "Eyes evidence packet source role")?;
validate_non_empty(&packet.emitted_at, "Eyes evidence packet timestamp")?;
if packet.evidence_ids.is_empty() {
return Err(anyhow!("Eyes evidence packet must reference evidence ids"));
}
let mut cache = runtime_spine_cache(store_path)?;
cache.pull_all_backing_stores()?;
require_identity(&cache)?;
cache.put(&packet.packet_id, packet)?;
Ok(())
}
pub fn put_substrate_gate_repo_access_grant_receipt(
store_path: impl AsRef<Path>,
receipt: &SubstrateGateRepoAccessGrantReceipt,
@ -7963,7 +7691,6 @@ pub fn put_substrate_gate_repo_access_grant_receipt(
}
}
pub fn put_hands_action_intent(
store_path: impl AsRef<Path>,
intent: &HandsActionIntent,
@ -8030,7 +7757,6 @@ pub fn put_hands_action_intent(
}
}
pub fn put_hands_action_review(
store_path: impl AsRef<Path>,
review: &HandsActionReview,
@ -8065,7 +7791,6 @@ pub fn put_hands_action_review(
}
}
fn validate_repo_frontier_hands_authority_chain(
cache: &CultCache,
authority: &RepoFrontierHandsAuthority,
@ -8274,7 +7999,6 @@ pub fn put_repo_frontier_hands_authority(
}
}
fn worker_result_has_keyed_mind_commit(
cache: &CultCache,
result: &EpiphanyRuntimeRoleWorkerResult,
@ -8387,8 +8111,6 @@ pub(crate) fn verification_frontier_is_current(
.unwrap_or(false))
}
pub(crate) fn repo_frontier_verification_context(
cache: &CultCache,
request: &RepoFrontierVerificationRequest,
@ -8468,7 +8190,6 @@ fn repo_frontier_verification_context_with_commit(
})
}
pub(crate) fn derive_repo_frontier_modeling_request(
cache: &CultCache,
verdict: &SoulVerdictReceipt,
@ -8620,7 +8341,6 @@ pub fn commit_repo_frontier_modeling_request(
}
}
fn derive_repo_frontier_verification_request_for_chain(
cache: &CultCache,
chain: &RuntimeHandsReceiptChainSummary,
@ -8674,7 +8394,6 @@ fn derive_repo_frontier_verification_request_for_chain(
Ok(request)
}
fn validate_hands_consequence_grant(
store_path: &Path,
intent_id: &str,
@ -8770,7 +8489,6 @@ fn validate_hands_consequence_grant(
Ok(())
}
pub fn put_hands_patch_receipt(
store_path: impl AsRef<Path>,
receipt: &HandsPatchReceipt,
@ -9019,7 +8737,6 @@ pub fn runtime_hands_commit_receipt(
cache.get::<HandsCommitReceipt>(receipt_id)
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct RuntimeHandsReceiptChainSummary {
pub patch_schema_version: String,
@ -10279,7 +9996,6 @@ pub fn runtime_spine_status(store_path: impl AsRef<Path>) -> Result<EpiphanyRunt
})
}
pub fn runtime_registered_document_types() -> Result<Vec<String>> {
Ok(runtime_spine_schema_cache()?.registered_entry_types())
}