Seal complete repository Body into Modeling basis
This commit is contained in:
parent
785213ec29
commit
33ae22dea2
2 changed files with 147 additions and 15 deletions
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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()?;
|
||||
|
|
|
|||
Reference in a new issue