Build Eyes claim challenge circulation

This commit is contained in:
Meta Vens 2026-07-14 01:27:45 +01:00
commit 24c761e953
7 changed files with 447 additions and 15 deletions

View file

@ -409,7 +409,7 @@ mod tests {
},
)?;
let state = EpiphanyThreadState::default();
let cache = coordinator_acceptance_cache(&store)?;
let mut cache = coordinator_acceptance_cache(&store)?;
cache.put(
THREAD_STATE_KEY,
&EpiphanyThreadStateEntry::from_state(&thread_id, &state)?,
@ -700,7 +700,7 @@ mod tests {
projection.proposal_payload_sha256,
selection.proposal_payload_sha256
);
let mut cache = coordinator_acceptance_cache(&store)?;
let cache = coordinator_acceptance_cache(&store)?;
let binding = cache
.get::<RepoFrontierProposalModelingLaunchBinding>(
"repo-frontier-proposal-modeling-launch-backend-first",

View file

@ -780,6 +780,7 @@ pub use runtime_spine::clear_epiphany_job_binding_backend;
pub use runtime_spine::commit_repo_frontier_modeling_request;
pub use runtime_spine::commit_repo_frontier_verification_request_for_chain;
pub use runtime_spine::commit_repo_model_admission;
pub use runtime_spine::commit_repo_model_claim_challenge;
pub use runtime_spine::complete_runtime_job;
pub use runtime_spine::create_runtime_job;
pub use runtime_spine::create_runtime_session;

View file

@ -46,6 +46,61 @@ 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";
#[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_revision: u64,
#[cultcache(key = 7)]
pub model_hash: String,
#[cultcache(key = 8)]
pub admission_receipt_id: String,
#[cultcache(key = 9)]
pub target_claim_id: String,
#[cultcache(key = 10)]
pub target_claim_sha256: String,
#[cultcache(key = 11)]
pub disposition: RepoModelClaimChallengeDisposition,
#[cultcache(key = 12)]
pub finding: String,
#[cultcache(key = 13)]
pub uncertainty: String,
#[cultcache(key = 14)]
pub source_refs: Vec<String>,
#[cultcache(key = 15)]
pub evidence_ids: Vec<String>,
#[cultcache(key = 16)]
pub challenged_at: String,
#[cultcache(key = 17)]
pub contract: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]

View file

@ -54,13 +54,15 @@ use crate::repo_model_gateway::{
REPO_FRONTIER_WORK_PROPOSAL_SCHEMA_VERSION, REPO_MODEL_ADMISSION_CONTRACT,
REPO_MODEL_ADMISSION_RECEIPT_SCHEMA_VERSION, REPO_MODEL_ADMISSION_RECEIPT_TYPE,
REPO_MODEL_ADMISSION_REVIEW_SCHEMA_VERSION, REPO_MODEL_ADMISSION_REVIEW_TYPE,
REPO_MODEL_CLAIM_CHALLENGE_CONTRACT, REPO_MODEL_CLAIM_CHALLENGE_SCHEMA_VERSION,
REPO_MODEL_MIGRATION_CONTRACT, REPO_MODEL_MIGRATION_RECEIPT_SCHEMA_VERSION,
REPO_MODEL_MIGRATION_RECEIPT_TYPE, RepoFrontierHandsAuthority, RepoFrontierModelingRequest,
RepoFrontierNextOrgan, RepoFrontierPlanAdoption, RepoFrontierPlanCandidate,
RepoFrontierPlanDecision, RepoFrontierPlanningRequest,
RepoFrontierProposalModelingLaunchBinding, RepoFrontierProposalModelingRequest,
RepoFrontierRoute, RepoFrontierVerdictDisposition, RepoFrontierWorkProposal,
RepoModelAdmissionReceipt, RepoModelAdmissionReview, RepoModelMigrationReceipt,
RepoModelAdmissionReceipt, RepoModelAdmissionReview, RepoModelClaimChallenge,
RepoModelMigrationReceipt,
};
use crate::soul_gateway::SoulVerdictReceipt;
use crate::soul_gateway::*;
@ -766,6 +768,7 @@ pub fn runtime_spine_cache(store_path: impl AsRef<Path>) -> Result<CultCache> {
cache.register_entry_type::<RepoModelAdmissionReview>()?;
cache.register_entry_type::<RepoModelAdmissionReceipt>()?;
cache.register_entry_type::<RepoModelMigrationReceipt>()?;
cache.register_entry_type::<RepoModelClaimChallenge>()?;
cache.register_entry_type::<RepoFrontierRoute>()?;
cache.register_entry_type::<RepoFrontierHandsAuthority>()?;
cache.register_entry_type::<RepoFrontierModelingRequest>()?;
@ -2466,7 +2469,8 @@ pub fn select_and_commit_repo_frontier_planning_request(
"planning requires exactly one current admission receipt"
));
}
let item = actionable_imagination_frontier_item(&model)
let challenges = current_repo_model_claim_challenges(&cache, &model, &model_hash)?;
let item = actionable_imagination_frontier_item(&model, &challenges)
.ok_or_else(|| anyhow!("planning requires an actionable Imagination frontier"))?;
let item_hash = format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(item)?));
if cache
@ -2525,9 +2529,10 @@ pub fn select_and_commit_repo_frontier_planning_request(
Ok(request)
}
fn actionable_imagination_frontier_item(
model: &crate::EpiphanyMemoryGraphSnapshot,
) -> Option<&crate::RepoFrontierItem> {
fn actionable_imagination_frontier_item<'a>(
model: &'a crate::EpiphanyMemoryGraphSnapshot,
challenges: &[RepoModelClaimChallenge],
) -> Option<&'a crate::RepoFrontierItem> {
let terminal = |id: &str| {
model
.frontier
@ -2550,6 +2555,7 @@ fn actionable_imagination_frontier_item(
&& item.recommended_next_organ == "Imagination"
&& !item.source_scope.is_empty()
&& safe_sorted_unique_paths(&item.source_scope)
&& frontier_target_claims_unchallenged(item, challenges)
&& item.dependency_item_ids.iter().all(|id| terminal(id))
})
.collect::<Vec<_>>();
@ -2557,6 +2563,176 @@ fn actionable_imagination_frontier_item(
eligible.into_iter().next()
}
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,
model_hash: &str,
) -> Result<Vec<RepoModelClaimChallenge>> {
let mut current = Vec::new();
for challenge in cache.get_all::<RepoModelClaimChallenge>()? {
if challenge.model_revision == model.model_revision && challenge.model_hash == model_hash {
validate_repo_model_claim_challenge_chain(cache, model, model_hash, &challenge)?;
current.push(challenge);
}
}
Ok(current)
}
fn validate_repo_model_claim_challenge_chain(
cache: &CultCache,
model: &crate::EpiphanyMemoryGraphSnapshot,
model_hash: &str,
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 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"));
}
if challenge.model_revision != model.model_revision || challenge.model_hash != model_hash {
return Err(anyhow!("claim challenge model revision is stale"));
}
let receipts = cache
.get_all::<RepoModelAdmissionReceipt>()?
.into_iter()
.filter(|receipt| {
receipt.schema_version == REPO_MODEL_ADMISSION_RECEIPT_SCHEMA_VERSION
&& receipt.contract == REPO_MODEL_ADMISSION_CONTRACT
&& receipt.admitted_revision == model.model_revision
&& receipt.admitted_hash == model_hash
})
.collect::<Vec<_>>();
if receipts.len() != 1 || receipts[0].receipt_id != challenge.admission_receipt_id {
return Err(anyhow!(
"claim challenge requires the unique current admission receipt"
));
}
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"));
}
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 model_envelope = envelopes
.iter()
.find(|entry| {
entry.r#type == crate::MEMORY_GRAPH_TYPE && entry.key == crate::MEMORY_GRAPH_KEY
})
.cloned()
.ok_or_else(|| anyhow!("claim challenge requires canonical model"))?;
let entry: crate::EpiphanyMemoryGraphEntry = rmp_serde::from_slice(&model_envelope.payload)?;
crate::validate_memory_graph_entry(&entry)?;
let model = entry.snapshot()?;
let model_hash = crate::memory_graph_model_hash(&model)?;
if challenge.model_revision != model.model_revision || challenge.model_hash != model_hash {
return Err(anyhow!("claim challenge model revision is stale"));
}
validate_repo_model_claim_challenge_chain(&cache, &model, &model_hash, challenge)?;
if let Some(existing) = cache.get::<RepoModelClaimChallenge>(&challenge.challenge_id)? {
return if existing == *challenge {
Ok(())
} else {
Err(anyhow!("claim challenge ids are immutable"))
};
}
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 admission_envelope = envelopes
.iter()
.find(|entry| {
entry.r#type == REPO_MODEL_ADMISSION_RECEIPT_TYPE
&& entry.key == challenge.admission_receipt_id
})
.cloned()
.ok_or_else(|| anyhow!("claim challenge admission envelope is missing"))?;
let (challenge_envelope, _) = cache.prepare_entry(&challenge.challenge_id, challenge)?;
if !backing.compare_and_swap_batch(
&[
model_envelope.clone(),
packet_envelope.clone(),
admission_envelope.clone(),
],
vec![
model_envelope,
packet_envelope,
admission_envelope,
challenge_envelope,
],
)? {
let mut reloaded = runtime_spine_cache(store_path)?;
reloaded.pull_all_backing_stores()?;
return match reloaded.get::<RepoModelClaimChallenge>(&challenge.challenge_id)? {
Some(existing) if existing == *challenge => Ok(()),
Some(_) => Err(anyhow!("claim challenge immutable collision")),
None => Err(anyhow!("claim challenge lost exact model/packet CAS")),
};
}
Ok(())
}
pub fn put_repo_frontier_plan_candidate(
store_path: impl AsRef<Path>,
candidate: &RepoFrontierPlanCandidate,
@ -2775,7 +2951,8 @@ pub fn select_and_commit_repo_frontier_route(
));
}
let receipt = &receipts[0];
let item = actionable_hands_frontier_item(&current)
let challenges = current_repo_model_claim_challenges(&cache, &current, &current_hash)?;
let item = actionable_hands_frontier_item(&current, &challenges)
.ok_or_else(|| anyhow!("current repo model has no eligible Hands frontier route"))?;
if !safe_sorted_unique_paths(&item.source_scope) || item.source_scope.is_empty() {
return Err(anyhow!(
@ -2828,9 +3005,10 @@ pub fn select_and_commit_repo_frontier_route(
Ok(route)
}
fn actionable_hands_frontier_item(
model: &crate::EpiphanyMemoryGraphSnapshot,
) -> Option<&crate::RepoFrontierItem> {
fn actionable_hands_frontier_item<'a>(
model: &'a crate::EpiphanyMemoryGraphSnapshot,
challenges: &[RepoModelClaimChallenge],
) -> Option<&'a crate::RepoFrontierItem> {
let terminal = |status: crate::RepoFrontierStatus| {
matches!(
status,
@ -2844,6 +3022,7 @@ fn actionable_hands_frontier_item(
&& item.recommended_next_organ == "Hands"
&& !item.source_scope.is_empty()
&& safe_sorted_unique_paths(&item.source_scope)
&& frontier_target_claims_unchallenged(item, challenges)
&& item.dependency_item_ids.iter().all(|dependency_id| {
model
.frontier
@ -2879,7 +3058,8 @@ pub fn runtime_has_actionable_hands_frontier(runtime_store: impl AsRef<Path>) ->
&& receipt.admitted_hash == model_hash
})
.count();
Ok(admission_count == 1 && actionable_hands_frontier_item(&model).is_some())
let challenges = current_repo_model_claim_challenges(&cache, &model, &model_hash)?;
Ok(admission_count == 1 && actionable_hands_frontier_item(&model, &challenges).is_some())
}
pub fn put_runtime_reorient_worker_result(
@ -6711,16 +6891,185 @@ mod tests {
item("b-ready", vec![]),
];
assert_eq!(
actionable_imagination_frontier_item(&model).unwrap().id,
actionable_imagination_frontier_item(&model, &[])
.unwrap()
.id,
"b-ready"
);
model.frontier[2].status = crate::RepoFrontierStatus::Resolved;
assert_eq!(
actionable_imagination_frontier_item(&model).unwrap().id,
actionable_imagination_frontier_item(&model, &[])
.unwrap()
.id,
"a-blocked"
);
}
fn claim_challenge_fixture(
root: &Path,
suffix: &str,
next_organ: &str,
) -> Result<(PathBuf, RepoModelClaimChallenge)> {
let (store, result, review) = proposal_admission_fixture(root, suffix)?;
let mut result = result;
if next_organ != "Hands" {
let mut patch: crate::RepoModelPatch =
rmp_serde::from_slice(result.repo_model_patch_msgpack.as_deref().unwrap())?;
let crate::RepoModelPatchOperation::UpsertFrontier { item } = &mut patch.operations[0]
else {
unreachable!()
};
item.recommended_next_organ = next_organ.into();
let bytes = rmp_serde::to_vec_named(&patch)?;
result.repo_model_patch_msgpack = Some(bytes.clone());
let mut amended = review;
amended.patch_sha256 = format!("{:x}", Sha256::digest(&bytes));
put_runtime_role_worker_result(&store, &result)?;
commit_repo_model_admission(&store, &result.result_id, &amended)?;
} else {
put_runtime_role_worker_result(&store, &result)?;
commit_repo_model_admission(&store, &result.result_id, &review)?;
}
let model = runtime_current_repo_model(&store)?.unwrap();
let model_hash = crate::memory_graph_model_hash(&model)?;
let mut cache = runtime_spine_cache(&store)?;
cache.pull_all_backing_stores()?;
let admission = cache
.get_all::<RepoModelAdmissionReceipt>()?
.into_iter()
.find(|receipt| {
receipt.admitted_revision == model.model_revision
&& receipt.admitted_hash == model_hash
})
.unwrap();
let packet = EyesEvidencePacket {
schema_version: EYES_EVIDENCE_PACKET_SCHEMA_VERSION.into(),
packet_id: format!("eyes-packet-{suffix}"),
source_result_id: format!("eyes-result-{suffix}"),
source_job_id: format!("eyes-job-{suffix}"),
source_role_id: "research".into(),
evidence_ids: vec![format!("evidence-{suffix}")],
observation_ids: vec![format!("observation-{suffix}")],
source_refs: vec!["epiphany-core/src/runtime_spine.rs:1".into()],
summary: "The exact claim is challenged by inspected source.".into(),
uncertainty: "Bounded to the cited source.".into(),
emitted_at: "2026-07-13T04:01:00Z".into(),
contract: "Eyes packet emitted from a reviewed Research lane finding; it makes the source-gathering evidence claim citable before Mind admission.".into(),
};
put_eyes_evidence_packet(&store, &packet)?;
let claim = model
.nodes
.iter()
.find(|node| node.id == "claim-runtime-model")
.unwrap();
let challenge = RepoModelClaimChallenge {
schema_version: REPO_MODEL_CLAIM_CHALLENGE_SCHEMA_VERSION.into(),
challenge_id: format!("claim-challenge-{suffix}"),
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,
source_job_id: packet.source_job_id,
model_revision: model.model_revision,
model_hash,
admission_receipt_id: admission.receipt_id,
target_claim_id: claim.id.clone(),
target_claim_sha256: format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(claim)?)),
disposition: crate::RepoModelClaimChallengeDisposition::Contradicted,
finding: "The exact admitted claim is contradicted.".into(),
uncertainty: packet.uncertainty,
source_refs: packet.source_refs,
evidence_ids: packet.evidence_ids,
challenged_at: "2026-07-13T04:01:01Z".into(),
contract: REPO_MODEL_CLAIM_CHALLENGE_CONTRACT.into(),
};
Ok((store, challenge))
}
#[test]
fn claim_challenge_is_exact_immutable_and_rejects_substitution() -> Result<()> {
let root = tempdir()?;
let (store, challenge) = claim_challenge_fixture(root.path(), "exact", "Hands")?;
commit_repo_model_claim_challenge(&store, &challenge)?;
commit_repo_model_claim_challenge(&store, &challenge)?;
let mut collision = challenge.clone();
collision.finding = "substituted finding".into();
assert!(commit_repo_model_claim_challenge(&store, &collision).is_err());
for (suffix, mutate) in [
"packet-id",
"packet-hash",
"provenance",
"admission",
"claim",
"claim-hash",
"revision",
]
.into_iter()
.enumerate()
{
let (hostile_store, mut hostile) =
claim_challenge_fixture(root.path(), &format!("hostile-{suffix}"), "Hands")?;
match mutate {
"packet-id" => hostile.eyes_evidence_packet_id = "swapped-packet".into(),
"packet-hash" => hostile.eyes_evidence_packet_sha256 = "00".repeat(32),
"provenance" => hostile.source_job_id = "swapped-job".into(),
"admission" => hostile.admission_receipt_id = "swapped-admission".into(),
"claim" => hostile.target_claim_id = "swapped-claim".into(),
"claim-hash" => hostile.target_claim_sha256 = "11".repeat(32),
"revision" => hostile.model_revision += 1,
_ => unreachable!(),
}
let before = std::fs::read(&hostile_store)?;
assert!(commit_repo_model_claim_challenge(&hostile_store, &hostile).is_err());
assert_eq!(std::fs::read(&hostile_store)?, before);
}
Ok(())
}
#[test]
fn current_claim_challenge_withholds_planning_and_hands_but_not_unrelated_frontier()
-> Result<()> {
let root = tempdir()?;
let (hands_store, hands_challenge) =
claim_challenge_fixture(root.path(), "hands-gate", "Hands")?;
commit_repo_model_claim_challenge(&hands_store, &hands_challenge)?;
assert!(!runtime_has_actionable_hands_frontier(&hands_store)?);
assert!(
select_and_commit_repo_frontier_route(&hands_store, "2026-07-13T04:02:00Z").is_err()
);
let (planning_store, planning_challenge) =
claim_challenge_fixture(root.path(), "planning-gate", "Imagination")?;
commit_repo_model_claim_challenge(&planning_store, &planning_challenge)?;
assert!(
select_and_commit_repo_frontier_planning_request(
&planning_store,
"2026-07-13T04:02:00Z"
)
.is_err()
);
let mut unrelated = repo_model_bootstrap();
unrelated.frontier = vec![crate::RepoFrontierItem {
id: "unrelated".into(),
target_claim_ids: vec!["another-claim".into()],
source_scope: vec!["epiphany-core/src".into()],
recommended_next_organ: "Hands".into(),
status: crate::RepoFrontierStatus::Active,
..Default::default()
}];
assert_eq!(
actionable_hands_frontier_item(&unrelated, &[hands_challenge])
.unwrap()
.id,
"unrelated"
);
Ok(())
}
fn admit_route_and_authorize_hands(
store: &Path,
intent: &HandsActionIntent,

View file

@ -27,6 +27,18 @@ roadmap mythology, and Self preserved dependency order without flattening those
different judgments into one running narrative. This is positive evidence for
durable organ-to-organ cognition, not merely for role-flavored prompting.
That lesson now has a concrete corrective nerve. Eyes can persist an immutable
`RepoModelClaimChallenge` against one serialized claim at one exact admitted
model revision. Runtime-spine admission replays the canonical Eyes packet,
unique current Mind receipt, model identity, and claim hash in one absent-only
CAS. Self uses the same validated challenge predicate for Imagination planning,
Hands route selection, and actionable-Hands status; only frontier targeting the
challenged claim is withheld. Eyes never writes RepoModel, and no challenge ids
were stuffed into the graph. Core proof is 304 passed/1 ignored and independent
Soul review passes. Next build a typed Modeling challenge-repair request and
Mind admission path so evidence can reshape the shared map, then let Self and
Imagination revise the campaign from that repaired substrate.
Do not substitute the first linear frontier identity proof for that larger
lesson. `Modeling -> Mind -> Self -> Hands -> Soul -> Modeling` proves that one
wound can retain causal identity. The awakened anatomy also needs typed backward

Binary file not shown.

View file

@ -377,6 +377,21 @@ current_status:
replay -> one proposal-citing frontier contribution. Verification: core
302 passed/1 ignored, OpenAI runtime 8 passed, hostile no-write proofs, and
independent Soul PASS.
eyes_claim_challenge_authority: >
Eyes may persist one immutable challenge against one serialized RepoModel
claim at one exact admitted model revision. Runtime-spine admission replays
the canonical Eyes packet hash and provenance, the unique current Mind
admission receipt, the model revision/hash, and the target claim hash; the
model, packet, and admission envelopes participate in the absent-only CAS.
Eyes does not write RepoModel. Self derives pressure from fully revalidated
current challenges through one shared target-overlap predicate: challenged
frontier is withheld from Imagination planning, Hands routing, and
actionable-Hands status while unrelated frontier remains eligible. Prompt
prose, UI state, direct CultCache challenge rows, latest-challenge helpers,
challenge metadata inside RepoModel, and generic evidence routers are
forbidden authorities. Verification: core 304 passed/1 ignored, hostile
immutable/substitution/no-write proofs, identical planning/Hands gates, and
independent Soul PASS.
latest_cut: >
The bridge host seam has been cut down: target-specific Hands prompt scar
tissue was purged, bridge manifests carry the retained Codex websocket fork
@ -678,4 +693,4 @@ current_status:
- Service lifecycle receipt history is now event-only: `load_epiphany_cultmesh_daemon_service_lifecycle_receipts` filters out the `epiphany-local/daemon-service-lifecycle-receipt/latest` mirror, while `load_latest_epiphany_cultmesh_daemon_service_lifecycle_receipt` remains the latest-state reader. Focused unit test `service_lifecycle_receipt_history_excludes_latest_mirror` proves two per-receipt writes return exactly two history records and latest points at the second. Fresh smoke `verse-query-lifecycle-history-filter-smoke` and live overview/triage `local-20260618-145632-497-efac6f0d` / `local-20260618-145632-321-867947af` prove compact swarm sights still expose service lifecycle attention plus the present elevated runbook artifact without daemon pokes or service mutation. Do not use a broad unscoped cargo test filter for this check on Windows; it fans out across bin harnesses and hit a broken pipe during this pass.
- `epiphany-verse-query seed-compact` is the compact seed receipt for wrappers and read-only rites. The older `seed` command still prints the full local Verse context for explicit debugging, but compact wrapper modes now avoid full `seed`/final `query` readback after the combined overview proof exposed Windows debug stack overflow from full-context serialization pressure.
last_completed_repo_swarm_cut: Huginn live-fire has crossed the first real repo Body from Persona pressure to branch-local Hands commit and Soul/Mind closure, and now has repeatable closure and redacted-public-proof mouths. On `E:\Projects\Huginn` branch `epiphany/huginn/first-awakening`, `tools/epiphany_local_run.ps1 -Mode repo-persona-intake` accepted item `huginn-inspection-readback-livefire`, Weksa/Persona intake remained sealed, and `epiphany-work derive-plan` lowered it to model-authored safe family `repo.status_section` for `README.md` only. `tools/epiphany_local_run.ps1 -Mode repo-swarm-run` advanced four bounded pulses: run-from-plan, adopt-from-plan, execute-from-plan, and close-from-execute. Huginn commit `e9b07c38fceabbdc89ea35c2156326c80c0393a2` updated only `README.md`; closure receipt `.epiphany\work\work-close-huginn-inspection-readback-livefire.json` records status `closed`, Soul verdict `passed`, Mind state commit `repo-work-close-huginn-inspection-readback-livefire-mind-commit`, safe family `repo.status_section`, path scope `README.md`, Bifrost publication gate, and `privateStateExposed=false`. Verification also ran Huginn's TypeScript compiler through concrete Node path: `C:\Program Files\nodejs\node.exe E:\Projects\Huginn\node_modules\typescript\bin\tsc -p tsconfig.json` passed. Native verifier `epiphany-repo-livefire-closure-smoke --workspace E:\Projects\Huginn --item huginn-inspection-readback-livefire --expected-path README.md --expected-family repo.status_section --expected-gate awaiting-publication --expected-blocker bifrost-publication-missing` checks closure receipt, Mind map entry, overview gate/blocker, authority seals, and `git show` changed paths, returning `status=ok`, `soulVerdict=passed`, `publicationGate=Bifrost`, and `privateStateExposed=false`. Wrapper `tools/epiphany_local_run.ps1 -Mode repo-livefire-closure -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exposes the same read-only proof through the local operator mouth; artifact `local-20260621-190156-803-2f85ba15` printed commit, path, gate, blocker, Soul verdict, Mind commit receipt, and `privateStateExposed=False` without push, merge, publication, or target mutation. New wrapper `tools/epiphany_local_run.ps1 -Mode repo-work-public-proof -Workspace E:\Projects\Huginn -RepoWorkItem huginn-inspection-readback-livefire -SkipBuild` exports the redacted proof bundle and repo-local Verse index without publishing; artifact `local-20260621-190645-345-4555b1dc` wrote `.epiphany\public\proof-bundles\repo-work-public-proof-huginn-inspection-readback-livefire.json`, proof id `repo-work-public-proof-huginn-inspection-readback-livefire`, SHA-256 `857545b199f3e37eb06c2e757e5cfc201958e46667bb1f8403fd333a22620f63`, nine artifact rows, zero publication rows, and `privateStateExposed=False`. swarm overview readback `local-20260621-190701-140-b9519ec6` sees the `REPO-WORK-PUBLIC-PROOF` row and action row from Huginn's repo-local Verse with the same SHA-256 while Bifrost publication remains missing. Launcher compact modes are now named compact operator-context modes instead of read-only modes, and `bifrost-public-proof` summaries print item, target public Verse, room, proof SHA-256, review receipts, and credit receipts so publication receipts are auditable without claiming upstream sync.
next_action: Extend the Aetheria-shaped correction ecology from the now-landed selected-proposal ingress. User proposal intake, exact coordinator selection, coordinator-owned typed Modeling launch projection, immutable job/request/proposal binding, and proposal-bound Mind admission are Soul-approved; core proof is 302 passed/1 ignored and OpenAI runtime proof is 8 passed. The proposal remains contestable evidence and creates only one admitted frontier contribution—never a plan, route, Hands grant, or lifecycle decision. Next add typed Eyes challenge artifacts that can invalidate or stale model claims and create evidence pressure without direct RepoModel write authority; Self must route that pressure from admitted artifacts. Then bind the existing Self planning request to a real Imagination worker result and Mind Adopt/Refuse/Hold path before inventing any execution route. Add the production semantic index over typed graph claims so organs retrieve the living migration map instead of rediscovering files. Do not infer identities from prose/evidence intersection, revive epiphany-work, add metadata adapters, or let a prompt projection become authority. The intentionally absent Other-world action still requires a typed intent and real owner. Keep closure's zero-substring invariant.
next_action: Continue the Aetheria-shaped correction ecology from the landed selected-proposal ingress and Eyes claim-challenge pressure. Eyes can now challenge one exact admitted claim without RepoModel write authority, and Self withholds only frontier targeting that challenged claim from planning and Hands. Next create the typed Modeling challenge-repair request/result/admission path so Modeling can revise the exact claim and affected frontier through Mind, after which the old challenge naturally loses current-revision pressure. Then bind the existing Self planning request to a real Imagination worker result and Mind Adopt/Refuse/Hold path before inventing any execution route. Add the production semantic index over typed graph claims so organs retrieve the living migration map instead of rediscovering files. Do not infer identities from prose/evidence intersection, revive epiphany-work, add metadata adapters, store challenge ids inside RepoModel, or let prompt projections become authority. The intentionally absent Other-world action still requires a typed intent and real owner. Keep closure's zero-substring invariant.