Seal complete repository Body into Modeling basis

This commit is contained in:
Meta Vens 2026-08-22 13:35:47 +02:00
commit 33ae22dea2
2 changed files with 147 additions and 15 deletions

View file

@ -28,7 +28,7 @@ pub const MIND_COMMIT_RECEIPT_TYPE: &str = "epiphany.mind_commit_receipt.v1";
pub const DECISION_AUDIT_PROJECTION_SCHEMA_VERSION: &str = "epiphany.decision_audit_projection.v1";
pub const DECISION_AUDIT_INDEX_SCHEMA_VERSION: &str = "epiphany.decision_audit_index.v1";
pub const WORKER_REASONING_PROJECTION_POLICY: &str =
"epiphany.reasoning_projection.worker_launch.v2";
"epiphany.reasoning_projection.worker_launch.v3";
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct EpiphanyRolePassAuthorityProjection {
@ -154,6 +154,7 @@ impl From<crate::EpiphanyMindView> for EpiphanyMindPromptProjection {
pub struct EpiphanyRoleReasoningProjection {
pub authority: EpiphanyRolePassAuthorityProjection,
pub mind: EpiphanyMindPromptProjection,
pub modeling_body: Option<crate::RepositoryBodyReasoningProjection>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -996,9 +997,7 @@ fn validate_decision_terminal_records(
fn role_terminal_semantic_role(basis: &EpiphanyReasoningBasis) -> Result<Option<String>> {
Ok(match basis.projection()? {
EpiphanyReasoningProjection::RolePass(projection) => {
Some(projection.authority.role_id)
}
EpiphanyReasoningProjection::RolePass(projection) => Some(projection.authority.role_id),
_ => None,
})
}
@ -1017,11 +1016,26 @@ pub fn worker_reasoning_basis(
EpiphanyWorkerLaunchDocument::Role(document) => {
let mind = crate::assemble_mind_view(store_path)?;
let source_documents = mind.source_documents.clone();
let authority: EpiphanyRolePassAuthorityProjection = document.into();
let modeling_body = if authority.role_id.eq_ignore_ascii_case("modeling") {
Some(crate::load_repository_body_reasoning_projection(
store_path,
authority
.repository_body_observation_basis
.as_ref()
.ok_or_else(|| {
anyhow!("Modeling reasoning launch has no repository Body basis")
})?,
)?)
} else {
None
};
(
source_documents,
EpiphanyReasoningProjection::RolePass(EpiphanyRoleReasoningProjection {
authority: document.into(),
authority,
mind: mind.into(),
modeling_body,
}),
)
}
@ -1109,6 +1123,22 @@ pub fn put_reasoning_basis(
return Err(anyhow!("role reasoning basis cites a non-role launch"));
};
let current_mind = crate::assemble_mind_view(store_path)?;
let current_modeling_body = if projection
.authority
.role_id
.eq_ignore_ascii_case("modeling")
{
Some(crate::load_repository_body_reasoning_projection(
store_path,
projection
.authority
.repository_body_observation_basis
.as_ref()
.ok_or_else(|| anyhow!("Modeling reasoning basis has no Body basis"))?,
)?)
} else {
None
};
let modeling_body_mismatch = projection
.authority
.role_id
@ -1117,6 +1147,7 @@ pub fn put_reasoning_basis(
!= current_mind.repository_body_observation;
if projection.authority != document.into()
|| projection.mind != current_mind.clone().into()
|| projection.modeling_body != current_modeling_body
|| basis.source_documents != current_mind.source_documents
|| modeling_body_mismatch
{
@ -1846,8 +1877,8 @@ mod tests {
fn role_document() -> EpiphanyRoleWorkerLaunchDocument {
EpiphanyRoleWorkerLaunchDocument {
thread_id: "creation-thread".into(),
role_id: "Modeling".into(),
objective: Some("Map the Body".into()),
role_id: "Imagination".into(),
objective: Some("Propose one future".into()),
dynamic_prompt_context: Some("typed projection".into()),
repository_body_observation_basis: None,
proposal_modeling_context: None,
@ -1879,16 +1910,16 @@ mod tests {
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(),
binding_id: crate::EPIPHANY_IMAGINATION_ROLE_BINDING_ID.into(),
role: "Imagination".into(),
authority_scope: "epiphany.role.imagination".into(),
instruction: "Propose one future".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",
"epiphany.role.imagination",
"role",
crate::ROLE_WORKER_OUTPUT_CONTRACT_ID,
),
@ -1904,7 +1935,10 @@ mod tests {
}
fn basis() -> Result<EpiphanyReasoningBasis> {
let authority = EpiphanyRolePassAuthorityProjection::from(role_document());
let mut document = role_document();
document.role_id = "Modeling".into();
document.objective = Some("Map the Body".into());
let authority = EpiphanyRolePassAuthorityProjection::from(document);
let payload_msgpack = rmp_serde::to_vec_named(&crate::EpiphanyMindIdentity {
schema_epoch: crate::MIND_SCHEMA_EPOCH.into(),
runtime_id: "test-runtime".into(),
@ -1938,6 +1972,7 @@ mod tests {
repository_body_observation: None,
repo_model: None,
},
modeling_body: None,
});
EpiphanyReasoningBasis::new(
"pass-1",
@ -2581,9 +2616,9 @@ mod tests {
result_id: "worker-result-1".into(),
job_id: "pass-1".into(),
session_id: "session-1".into(),
role: "Modeling".into(),
role: "Imagination".into(),
verdict: "completed".into(),
summary: "Structured Modeling decision".into(),
summary: "Structured Imagination decision".into(),
completed_at: "2026-08-14T00:00:03Z".into(),
next_safe_move: "Inspect the durable decision context".into(),
evidence_refs: Vec::new(),

View file

@ -109,6 +109,27 @@ pub struct RepositoryBodyObservationBasis {
pub scan_finished_at: String,
}
/// Exact authenticated Repository Body state sealed into Modeling reasoning.
///
/// The compact basis identifies the admitted generation. Modeling additionally
/// needs the actual Git identity and complete manifest so it can reason from
/// its Body without laundering internal inspection through Eyes.
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RepositoryBodyReasoningProjection {
pub basis: RepositoryBodyObservationBasis,
pub source_identity_type: String,
pub source_identity_key: String,
pub source_identity_sha256: String,
pub git_top_level: String,
pub object_format: String,
pub head_oid: Option<String>,
pub tree_oid: String,
pub two_scan_outcome: String,
pub manifest_entry_count: u64,
pub manifest_entries: Vec<RepositoryBodyManifestEntry>,
}
#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
#[cultcache(
type = "epiphany.repository_body.observation",
@ -487,6 +508,41 @@ pub fn load_current_runtime_repository_body_basis(
})
}
pub fn load_repository_body_reasoning_projection(
runtime_store: &Path,
basis: &RepositoryBodyObservationBasis,
) -> Result<RepositoryBodyReasoningProjection> {
validate_repository_body_observation_basis(runtime_store, basis)?;
let route = runtime_repository_body_store_binding(runtime_store)?
.ok_or_else(|| anyhow!("runtime has no repository Body-store binding"))?;
let entries = load_body_envelopes(Path::new(&route.body_store_path))?;
let binding: RepositoryBodyBinding = decode(
find(&entries, BODY_BINDING_TYPE, BODY_BINDING_KEY)
.ok_or_else(|| anyhow!("runtime repository Body store has no Body binding"))?,
)?;
let historical_head = RepositoryBodyHead {
schema_version: BODY_SCHEMA_VERSION.into(),
workspace_id: basis.workspace_id.clone(),
generation: basis.generation,
observation_id: basis.observation_id.clone(),
manifest_root_sha256: basis.manifest_root_sha256.clone(),
};
let (observation, manifest) = validate_body_chain(&entries, &binding, &historical_head)?;
Ok(RepositoryBodyReasoningProjection {
basis: basis.clone(),
source_identity_type: binding.source_identity_type,
source_identity_key: binding.source_identity_key,
source_identity_sha256: binding.source_identity_sha256,
git_top_level: binding.git_top_level,
object_format: binding.object_format,
head_oid: observation.head_oid,
tree_oid: observation.tree_oid,
two_scan_outcome: observation.two_scan_outcome,
manifest_entry_count: observation.manifest_entry_count,
manifest_entries: manifest.entries,
})
}
pub fn validate_repository_body_observation_basis(
runtime_store: &Path,
basis: &RepositoryBodyObservationBasis,
@ -1688,6 +1744,47 @@ mod tests {
assert_ne!(b.tree_oid, c.tree_oid);
Ok(())
}
#[test]
fn reasoning_projection_carries_the_exact_authenticated_body_manifest() -> Result<()> {
let d = repo()?;
let state = tempfile::tempdir()?;
let (store, runtime) = bound(d.path(), state.path(), "workspace", "runtime", "swarm")?;
write(&d.path().join("tracked.txt"), "one")?;
run(d.path(), &["add", "."])?;
run(d.path(), &["commit", "-m", "seed"])?;
let basis = observe_runtime_repository_body_basis(&runtime)?;
let projection = load_repository_body_reasoning_projection(&runtime, &basis)?;
let (binding, _) = load_repository_body_status(&store)?.expect("Body status");
assert_eq!(projection.basis, basis);
assert_eq!(
projection.source_identity_type,
binding.source_identity_type
);
assert_eq!(projection.source_identity_key, binding.source_identity_key);
assert_eq!(
projection.source_identity_sha256,
binding.source_identity_sha256
);
assert_eq!(projection.git_top_level, binding.git_top_level);
assert_eq!(projection.object_format, binding.object_format);
assert!(projection.head_oid.is_some());
assert!(!projection.tree_oid.is_empty());
assert_eq!(projection.two_scan_outcome, "stable_equal");
assert_eq!(
projection.manifest_entry_count as usize,
projection.manifest_entries.len()
);
assert!(
projection
.manifest_entries
.iter()
.any(|entry| entry.path == "tracked.txt")
);
Ok(())
}
#[test]
fn equality_scans_share_one_private_index_session_and_remove_it() -> Result<()> {
let d = repo()?;