From a01c684262e19fe0712c81d786d44b2901e09eaa Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 24 Aug 2026 23:21:26 +0200 Subject: [PATCH] Delete counterfeit Hands review authority --- .../src/bin/epiphany-mvp-coordinator.rs | 60 +--- epiphany-core/src/current_work.rs | 59 +--- epiphany-core/src/hands_gateway.rs | 128 ++------ epiphany-core/src/lib.rs | 1 - epiphany-core/src/repo_model_gateway.rs | 16 +- epiphany-core/src/runtime_spine.rs | 279 +++--------------- epiphany-core/src/soul_gateway.rs | 10 +- epiphany-core/src/surfaces/worker_launch.rs | 5 +- notes/hands-cultnet-contracts.md | 35 ++- 9 files changed, 106 insertions(+), 487 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-mvp-coordinator.rs b/epiphany-core/src/bin/epiphany-mvp-coordinator.rs index 0acca96c..3f4a8b70 100644 --- a/epiphany-core/src/bin/epiphany-mvp-coordinator.rs +++ b/epiphany-core/src/bin/epiphany-mvp-coordinator.rs @@ -4,7 +4,6 @@ use anyhow::anyhow; use chrono::SecondsFormat; use epiphany_core::COORDINATOR_RUN_RECEIPT_TYPE; use epiphany_core::EpiphanyCoordinatorRunReceipt; -use epiphany_core::HANDS_ACTION_INTENT_SCHEMA_VERSION; use epiphany_core::HANDS_COMMAND_RECEIPT_TYPE; use epiphany_core::HANDS_COMMIT_RECEIPT_TYPE; use epiphany_core::HANDS_PATCH_RECEIPT_TYPE; @@ -13,12 +12,10 @@ use epiphany_core::RepoFrontierHandsAuthority; use epiphany_core::RuntimeSpineInitOptions; use epiphany_core::coordinator_status as status_projection; use epiphany_core::finalize_coordinator_run; -use epiphany_core::hands_action_review_for_intent; use epiphany_core::initialize_runtime_spine; use epiphany_core::load_epiphany_cultmesh_swarm_brake; use epiphany_core::open_coordinator_run; use epiphany_core::put_hands_action_intent; -use epiphany_core::put_hands_action_review; use epiphany_core::put_repo_frontier_hands_authority; use epiphany_core::put_substrate_gate_repo_access_grant_receipt; use epiphany_core::select_and_commit_repo_frontier_route; @@ -1533,71 +1530,17 @@ fn record_hands_implementation_gate( put_substrate_gate_repo_access_grant_receipt(runtime_store, &substrate_grant)?; let intent = HandsActionIntent { - schema_version: HANDS_ACTION_INTENT_SCHEMA_VERSION.to_string(), intent_id: format!("hands-intent-{suffix}"), runtime_job_id: runtime_job_id.clone(), - binding_id: "implementation-worker".to_string(), - role: "epiphany-hands".to_string(), - authority_scope: "epiphany.role.implementation".to_string(), - requested_action: "continueImplementation".to_string(), requested_paths: requested_paths.clone(), substrate_gate_grant_receipt_id: grant_id.clone(), - requested_at: requested_at.clone(), - contract: "Coordinator continuation becomes a typed Hands action intent before any file edit, command, or commit may count as implementation evidence." - .to_string(), - frontier_route_id: route - .adopted_plan - .as_ref() - .map(|_| route.route_id.clone()) - .unwrap_or_default(), - plan_candidate_sha256: route - .adopted_plan - .as_ref() - .map(|plan| plan.candidate_sha256.clone()) - .unwrap_or_default(), - plan_action: route - .adopted_plan - .as_ref() - .map(|plan| plan.effective_action().to_string()) - .unwrap_or_default(), }; put_hands_action_intent(runtime_store, &intent)?; - - let mut review = hands_action_review_for_intent( - format!("hands-review-{suffix}"), - &intent, - "approved".to_string(), - vec![ - "patch".to_string(), - "command".to_string(), - "commit".to_string(), - ], - vec![ - "Coordinator selected continueImplementation for the current thread state." - .to_string(), - "Hands remains the action owner; Mind and Soul still own state admission and verification." - .to_string(), - ], - requested_at, - ); - review.required_receipts = vec![ - HANDS_PATCH_RECEIPT_TYPE.to_string(), - HANDS_COMMAND_RECEIPT_TYPE.to_string(), - HANDS_COMMIT_RECEIPT_TYPE.to_string(), - ]; - put_hands_action_review(runtime_store, &review)?; let authority = RepoFrontierHandsAuthority { authority_id: format!("repo-frontier-hands-authority-{}", intent.intent_id), route_id: route.route_id.clone(), - model_projection_digest: route.model_projection_digest.clone(), - model_source_documents: route.model_source_documents.clone(), - frontier_item_id: route.frontier_item_id.clone(), - frontier_item_hash: route.frontier_item_hash.clone(), hands_intent_id: intent.intent_id.clone(), - hands_review_id: review.review_id.clone(), substrate_grant_receipt_id: grant_id.clone(), - requested_paths: requested_paths.clone(), - granted_at: review.reviewed_at.clone(), }; put_repo_frontier_hands_authority(runtime_store, &authority)?; @@ -1606,13 +1549,12 @@ fn record_hands_implementation_gate( "runtimeJobId": runtime_job_id, "substrateGateGrantReceiptId": grant_id, "intentId": intent.intent_id, - "reviewId": review.review_id, "routeId": route.route_id, "modelProjectionDigest": route.model_projection_digest, "modelSourceDocuments": route.model_source_documents, "frontierItemId": route.frontier_item_id, "requestedPaths": requested_paths, - "requiredReceipts": review.required_receipts, + "requiredReceipts": [HANDS_PATCH_RECEIPT_TYPE, HANDS_COMMAND_RECEIPT_TYPE, HANDS_COMMIT_RECEIPT_TYPE], "plannedAction": route.adopted_plan.as_ref().map(|plan| plan.effective_action()), "plannedCommand": route.adopted_plan.as_ref().map(|plan| plan.effective_command()), "originalPlannedAction": route.adopted_plan.as_ref().map(|plan| plan.action.as_str()), diff --git a/epiphany-core/src/current_work.rs b/epiphany-core/src/current_work.rs index d1520c22..182e4a5a 100644 --- a/epiphany-core/src/current_work.rs +++ b/epiphany-core/src/current_work.rs @@ -1523,10 +1523,6 @@ pub fn launch_current_frontier_verification_work( crate::HandsActionIntent::TYPE, request.hands_intent_id.as_str(), ), - ( - crate::HandsActionReview::TYPE, - request.hands_review_id.as_str(), - ), ( crate::HandsPatchReceipt::TYPE, request.hands_patch_receipt_id.as_str(), @@ -2026,10 +2022,6 @@ pub fn accept_frontier_verification_result( crate::HandsActionIntent::TYPE, request.hands_intent_id.as_str(), ), - ( - crate::HandsActionReview::TYPE, - request.hands_review_id.as_str(), - ), ( crate::HandsPatchReceipt::TYPE, request.hands_patch_receipt_id.as_str(), @@ -4377,63 +4369,30 @@ mod tests { ); crate::put_substrate_gate_repo_access_grant_receipt(&store, &grant)?; let intent = crate::HandsActionIntent { - schema_version: crate::HANDS_ACTION_INTENT_SCHEMA_VERSION.into(), intent_id: "hands-intent-verification-fixture".into(), runtime_job_id: hands_job_id.into(), - binding_id: "implementation-worker".into(), - role: "epiphany-hands".into(), - authority_scope: "epiphany.role.implementation".into(), - requested_action: "continueImplementation".into(), requested_paths: route.authorized_paths.clone(), substrate_gate_grant_receipt_id: grant.receipt_id.clone(), - requested_at: "2026-08-17T00:00:14.200Z".into(), - contract: "The exact Hands consequence under Verification.".into(), - frontier_route_id: String::new(), - plan_candidate_sha256: String::new(), - plan_action: String::new(), }; crate::put_hands_action_intent(&store, &intent)?; - let mut hands_review = crate::hands_action_review_for_intent( - "hands-review-verification-fixture".into(), - &intent, - "approved".into(), - vec!["patch".into(), "command".into(), "commit".into()], - vec!["Bounded fixture consequence is authorized.".into()], - "2026-08-17T00:00:14.300Z".into(), - ); - hands_review.required_receipts = vec![ - crate::HANDS_PATCH_RECEIPT_TYPE.into(), - crate::HANDS_COMMAND_RECEIPT_TYPE.into(), - crate::HANDS_COMMIT_RECEIPT_TYPE.into(), - ]; - crate::put_hands_action_review(&store, &hands_review)?; let hands_authority = crate::RepoFrontierHandsAuthority { authority_id: "repo-frontier-hands-authority-verification-fixture".into(), route_id: route.route_id.clone(), - model_projection_digest: route.model_projection_digest.clone(), - model_source_documents: route.model_source_documents.clone(), - frontier_item_id: route.frontier_item_id.clone(), - frontier_item_hash: route.frontier_item_hash.clone(), hands_intent_id: intent.intent_id.clone(), - hands_review_id: hands_review.review_id.clone(), substrate_grant_receipt_id: grant.receipt_id.clone(), - requested_paths: route.authorized_paths.clone(), - granted_at: hands_review.reviewed_at.clone(), }; crate::put_repo_frontier_hands_authority(&store, &hands_authority)?; - let hands_patch = crate::hands_patch_receipt_for_review( + let hands_patch = crate::hands_patch_receipt_for_intent( "hands-patch-verification-fixture".into(), &intent, - &hands_review, route.authorized_paths.clone(), "Applied the exact bounded change.".into(), "2026-08-17T00:00:14.400Z".into(), ); crate::put_hands_patch_receipt(&store, &hands_patch)?; - let hands_command = crate::hands_command_receipt_for_review( + let hands_command = crate::hands_command_receipt_for_intent( "hands-command-verification-fixture".into(), &intent, - &hands_review, "cargo test exact-verification-fixture".into(), "0".into(), "verification.stdout".into(), @@ -4442,16 +4401,26 @@ mod tests { "2026-08-17T00:00:14.500Z".into(), ); crate::put_hands_command_receipt(&store, &hands_command)?; - let hands_commit = crate::hands_commit_receipt_for_review( + let hands_commit = crate::hands_commit_receipt_for_intent( "hands-commit-verification-fixture".into(), &intent, - &hands_review, "0123456789abcdef0123456789abcdef01234567".into(), "codex/verification-fixture".into(), route.authorized_paths.clone(), "Committed the exact bounded consequence.".into(), "2026-08-17T00:00:14.600Z".into(), ); + let ambiguous_hands_store = temp.path().join("ambiguous-hands.cc"); + std::fs::copy(&store, &ambiguous_hands_store)?; + let mut duplicate_patch = hands_patch.clone(); + duplicate_patch.receipt_id = "hands-patch-verification-fixture-duplicate".into(); + crate::put_hands_patch_receipt(&ambiguous_hands_store, &duplicate_patch)?; + assert!( + crate::put_hands_commit_receipt(&ambiguous_hands_store, &hands_commit) + .unwrap_err() + .to_string() + .contains("one exact patch receipt") + ); let persona_cultmesh = temp.path().join("persona-concurrency-cultmesh.cc"); crate::write_epiphany_cultmesh_swarm_brake( &persona_cultmesh, diff --git a/epiphany-core/src/hands_gateway.rs b/epiphany-core/src/hands_gateway.rs index eea8c087..d4bf0e12 100644 --- a/epiphany-core/src/hands_gateway.rs +++ b/epiphany-core/src/hands_gateway.rs @@ -3,63 +3,17 @@ use cultcache_rs::DatabaseEntry; pub const HANDS_COMMAND_RECEIPT_TYPE: &str = "epiphany.hands.command_receipt"; pub const HANDS_PATCH_RECEIPT_TYPE: &str = "epiphany.hands.patch_receipt"; pub const HANDS_COMMIT_RECEIPT_TYPE: &str = "epiphany.hands.commit_receipt"; -pub const HANDS_ACTION_INTENT_SCHEMA_VERSION: &str = "epiphany.hands.action_intent.v1"; -pub const HANDS_ACTION_REVIEW_SCHEMA_VERSION: &str = "epiphany.hands.action_review.v0"; - #[derive(Debug, Clone, PartialEq, Eq, DatabaseEntry)] #[cultcache(type = "epiphany.hands.action_intent", schema = "HandsActionIntent")] pub struct HandsActionIntent { #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] pub intent_id: String, - #[cultcache(key = 2)] + #[cultcache(key = 1)] pub runtime_job_id: String, - #[cultcache(key = 3)] - pub binding_id: String, - #[cultcache(key = 4)] - pub role: String, - #[cultcache(key = 5)] - pub authority_scope: String, - #[cultcache(key = 6)] - pub requested_action: String, - #[cultcache(key = 7)] - pub requested_paths: Vec, - #[cultcache(key = 8)] - pub substrate_gate_grant_receipt_id: String, - #[cultcache(key = 9)] - pub requested_at: String, - #[cultcache(key = 10)] - pub contract: String, - #[cultcache(key = 11, default)] - pub frontier_route_id: String, - #[cultcache(key = 12, default)] - pub plan_candidate_sha256: String, - #[cultcache(key = 13, default)] - pub plan_action: String, -} - -#[derive(Debug, Clone, PartialEq, Eq, DatabaseEntry)] -#[cultcache(type = "epiphany.hands.action_review", schema = "HandsActionReview")] -pub struct HandsActionReview { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub review_id: String, #[cultcache(key = 2)] - pub intent_id: String, + pub requested_paths: Vec, #[cultcache(key = 3)] - pub decision: String, - #[cultcache(key = 4)] - pub allowed_operations: Vec, - #[cultcache(key = 5)] - pub required_receipts: Vec, - #[cultcache(key = 6)] - pub reasons: Vec, - #[cultcache(key = 7)] - pub reviewed_at: String, - #[cultcache(key = 8)] - pub contract: String, + pub substrate_gate_grant_receipt_id: String, } #[derive(Debug, Clone, PartialEq, Eq, DatabaseEntry)] @@ -70,16 +24,10 @@ pub struct HandsPatchReceipt { #[cultcache(key = 1)] pub intent_id: String, #[cultcache(key = 2)] - pub review_id: String, - #[cultcache(key = 3)] - pub substrate_gate_grant_receipt_id: String, - #[cultcache(key = 4)] - pub runtime_job_id: String, - #[cultcache(key = 5)] pub changed_paths: Vec, - #[cultcache(key = 6)] + #[cultcache(key = 3)] pub summary: String, - #[cultcache(key = 7)] + #[cultcache(key = 4)] pub emitted_at: String, } @@ -94,22 +42,16 @@ pub struct HandsCommandReceipt { #[cultcache(key = 1)] pub intent_id: String, #[cultcache(key = 2)] - pub review_id: String, - #[cultcache(key = 3)] - pub substrate_gate_grant_receipt_id: String, - #[cultcache(key = 4)] - pub runtime_job_id: String, - #[cultcache(key = 5)] pub command: String, - #[cultcache(key = 6)] + #[cultcache(key = 3)] pub exit_code: String, - #[cultcache(key = 7)] + #[cultcache(key = 4)] pub stdout_artifact: String, - #[cultcache(key = 8)] + #[cultcache(key = 5)] pub stderr_artifact: String, - #[cultcache(key = 9)] + #[cultcache(key = 6)] pub summary: String, - #[cultcache(key = 10)] + #[cultcache(key = 7)] pub emitted_at: String, } @@ -121,46 +63,20 @@ pub struct HandsCommitReceipt { #[cultcache(key = 1)] pub intent_id: String, #[cultcache(key = 2)] - pub review_id: String, - #[cultcache(key = 3)] - pub runtime_job_id: String, - #[cultcache(key = 4)] pub commit_sha: String, - #[cultcache(key = 5)] + #[cultcache(key = 3)] pub branch: String, - #[cultcache(key = 6)] + #[cultcache(key = 4)] pub changed_paths: Vec, - #[cultcache(key = 7)] + #[cultcache(key = 5)] pub summary: String, - #[cultcache(key = 8)] + #[cultcache(key = 6)] pub emitted_at: String, } -pub fn hands_action_review_for_intent( - review_id: String, - intent: &HandsActionIntent, - decision: String, - allowed_operations: Vec, - reasons: Vec, - reviewed_at: String, -) -> HandsActionReview { - HandsActionReview { - schema_version: HANDS_ACTION_REVIEW_SCHEMA_VERSION.to_string(), - review_id, - intent_id: intent.intent_id.clone(), - decision, - allowed_operations, - required_receipts: vec![HANDS_PATCH_RECEIPT_TYPE.to_string()], - reasons, - reviewed_at, - contract: "Hands review is the execution decision for a bounded action intent; it depends on Substrate Gate access and does not admit durable Mind state.".to_string(), - } -} - -pub fn hands_patch_receipt_for_review( +pub fn hands_patch_receipt_for_intent( receipt_id: String, intent: &HandsActionIntent, - review: &HandsActionReview, changed_paths: Vec, summary: String, emitted_at: String, @@ -168,9 +84,6 @@ pub fn hands_patch_receipt_for_review( HandsPatchReceipt { receipt_id, intent_id: intent.intent_id.clone(), - review_id: review.review_id.clone(), - substrate_gate_grant_receipt_id: intent.substrate_gate_grant_receipt_id.clone(), - runtime_job_id: intent.runtime_job_id.clone(), changed_paths, summary, emitted_at, @@ -178,10 +91,9 @@ pub fn hands_patch_receipt_for_review( } #[allow(clippy::too_many_arguments)] -pub fn hands_command_receipt_for_review( +pub fn hands_command_receipt_for_intent( receipt_id: String, intent: &HandsActionIntent, - review: &HandsActionReview, command: String, exit_code: String, stdout_artifact: String, @@ -192,9 +104,6 @@ pub fn hands_command_receipt_for_review( HandsCommandReceipt { receipt_id, intent_id: intent.intent_id.clone(), - review_id: review.review_id.clone(), - substrate_gate_grant_receipt_id: intent.substrate_gate_grant_receipt_id.clone(), - runtime_job_id: intent.runtime_job_id.clone(), command, exit_code, stdout_artifact, @@ -204,10 +113,9 @@ pub fn hands_command_receipt_for_review( } } -pub fn hands_commit_receipt_for_review( +pub fn hands_commit_receipt_for_intent( receipt_id: String, intent: &HandsActionIntent, - review: &HandsActionReview, commit_sha: String, branch: String, changed_paths: Vec, @@ -217,8 +125,6 @@ pub fn hands_commit_receipt_for_review( HandsCommitReceipt { receipt_id, intent_id: intent.intent_id.clone(), - review_id: review.review_id.clone(), - runtime_job_id: intent.runtime_job_id.clone(), commit_sha, branch, changed_paths, diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index 449ed15a..2762108a 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -247,7 +247,6 @@ pub use runtime_spine::open_runtime_model_execution; pub use runtime_spine::prepare_runtime_spine_heartbeat_job; pub(crate) use runtime_spine::promote_autonomous_direction_options_for_modeling; pub use runtime_spine::put_hands_action_intent; -pub use runtime_spine::put_hands_action_review; pub use runtime_spine::put_hands_command_receipt; pub use runtime_spine::put_hands_commit_receipt; pub use runtime_spine::put_hands_patch_receipt; diff --git a/epiphany-core/src/repo_model_gateway.rs b/epiphany-core/src/repo_model_gateway.rs index 9193d843..35f77608 100644 --- a/epiphany-core/src/repo_model_gateway.rs +++ b/epiphany-core/src/repo_model_gateway.rs @@ -434,21 +434,7 @@ pub struct RepoFrontierHandsAuthority { #[cultcache(key = 2)] pub route_id: String, #[cultcache(key = 3)] - pub model_projection_digest: String, - #[cultcache(key = 4)] - pub model_source_documents: Vec, - #[cultcache(key = 5)] - pub frontier_item_id: String, - #[cultcache(key = 6)] - pub frontier_item_hash: String, - #[cultcache(key = 7)] pub hands_intent_id: String, - #[cultcache(key = 8)] - pub hands_review_id: String, - #[cultcache(key = 9)] + #[cultcache(key = 4)] pub substrate_grant_receipt_id: String, - #[cultcache(key = 10)] - pub requested_paths: Vec, - #[cultcache(key = 11)] - pub granted_at: String, } diff --git a/epiphany-core/src/runtime_spine.rs b/epiphany-core/src/runtime_spine.rs index f054e495..023a21ff 100644 --- a/epiphany-core/src/runtime_spine.rs +++ b/epiphany-core/src/runtime_spine.rs @@ -55,7 +55,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.v45"; +pub const RUNTIME_SPINE_SCHEMA_VERSION: &str = "epiphany.runtime_spine.v46"; pub const EPIPHANY_RUNTIME_ROOT_SESSION_ID: &str = "epiphany-main"; #[derive(Clone, Debug, PartialEq, DatabaseEntry)] #[cultcache(type = "epiphany.runtime.identity", schema = "EpiphanyRuntimeIdentity")] @@ -696,7 +696,6 @@ fn runtime_spine_schema_cache() -> Result { cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; - cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; @@ -2610,9 +2609,7 @@ pub(crate) fn frontier_verification_request_for_launch( || carried.route.route_id != request.route_id || carried.hands_authority.route_id != request.route_id || carried.hands_authority.hands_intent_id != request.hands_intent_id - || carried.hands_authority.hands_review_id != request.hands_review_id || carried.hands_intent.intent_id != request.hands_intent_id - || carried.hands_review.review_id != request.hands_review_id || carried.patch_receipt.receipt_id != request.hands_patch_receipt_id || carried.command_receipt.receipt_id != request.hands_command_receipt_id || carried.commit_receipt.receipt_id != request.hands_commit_receipt_id @@ -6810,24 +6807,13 @@ pub fn put_hands_action_intent( ) -> Result<()> { validate_non_empty(&intent.intent_id, "Hands action intent id")?; validate_non_empty(&intent.runtime_job_id, "Hands action runtime job")?; - validate_non_empty(&intent.binding_id, "Hands action binding")?; - validate_non_empty(&intent.role, "Hands action role")?; - validate_non_empty(&intent.authority_scope, "Hands action authority scope")?; - validate_non_empty(&intent.requested_action, "Hands requested action")?; validate_non_empty( &intent.substrate_gate_grant_receipt_id, "Hands Substrate Gate grant receipt", )?; - validate_non_empty(&intent.requested_at, "Hands action requested timestamp")?; if intent.requested_paths.is_empty() { return Err(anyhow!("Hands action intent must name requested paths")); } - if intent.schema_version != HANDS_ACTION_INTENT_SCHEMA_VERSION - || chrono::DateTime::parse_from_rfc3339(&intent.requested_at).is_err() - || intent.contract.trim().is_empty() - { - return Err(anyhow!("invalid Hands action intent contract")); - } let store_path = store_path.as_ref(); let mut cache = runtime_spine_cache(store_path)?; cache.pull_all_backing_stores()?; @@ -6838,9 +6824,6 @@ pub fn put_hands_action_intent( anyhow!("Hands action intent requires its persisted Substrate Gate grant") })?; if grant.runtime_job_id != intent.runtime_job_id - || grant.binding_id != intent.binding_id - || grant.role != intent.role - || grant.authority_scope != intent.authority_scope || !grant .granted_operations .iter() @@ -6870,40 +6853,6 @@ pub fn put_hands_action_intent( } } -pub fn put_hands_action_review( - store_path: impl AsRef, - review: &HandsActionReview, -) -> Result<()> { - validate_non_empty(&review.review_id, "Hands action review id")?; - validate_non_empty(&review.intent_id, "Hands action review intent")?; - validate_non_empty(&review.decision, "Hands action review decision")?; - validate_non_empty(&review.reviewed_at, "Hands action review timestamp")?; - if review.allowed_operations.is_empty() { - return Err(anyhow!("Hands action review must name allowed operations")); - } - if review.schema_version != HANDS_ACTION_REVIEW_SCHEMA_VERSION - || chrono::DateTime::parse_from_rfc3339(&review.reviewed_at).is_err() - || review.contract.trim().is_empty() - { - return Err(anyhow!("invalid Hands action review contract")); - } - let store_path = store_path.as_ref(); - let mut cache = runtime_spine_cache(store_path)?; - cache.pull_all_backing_stores()?; - require_identity(&cache)?; - let (envelope, _) = cache.prepare_entry(&review.review_id, review)?; - let backing = SingleFileMessagePackBackingStore::new(store_path); - if backing.compare_and_swap_batch(&[], vec![envelope])? { - return Ok(()); - } - let mut reloaded = runtime_spine_cache(store_path)?; - reloaded.pull_all_backing_stores()?; - match reloaded.get::(&review.review_id)? { - Some(existing) if existing == *review => Ok(()), - _ => Err(anyhow!("Hands action review ids are immutable")), - } -} - fn validate_repo_frontier_hands_authority_chain( cache: &CultCache, authority: &RepoFrontierHandsAuthority, @@ -6937,80 +6886,28 @@ fn validate_repo_frontier_hands_authority_chain( let intent = cache .get::(&authority.hands_intent_id)? .ok_or_else(|| anyhow!("Hands authority requires its persisted intent"))?; - let review = cache - .get::(&authority.hands_review_id)? - .ok_or_else(|| anyhow!("Hands authority requires its persisted review"))?; let grant = cache .get::(&authority.substrate_grant_receipt_id)? .ok_or_else(|| anyhow!("Hands authority requires its persisted Substrate grant"))?; - let within_scope = authority.requested_paths.iter().all(|path| { - route.authorized_paths.iter().any(|scope| { - path == scope || path.starts_with(&format!("{}/", scope.trim_end_matches(['/', '\\']))) - }) - }); - let requested_operations: &[&str] = match intent.requested_action.as_str() { - "patch" => &["patch"], - "continueImplementation" => &["patch", "command", "commit"], - _ => { - return Err(anyhow!( - "Hands authority names an unsupported requested action" - )); - } - }; - let adopted_plan_binding_is_exact = match route.adopted_plan.as_ref() { - Some(plan) => { - intent.frontier_route_id == route.route_id - && intent.plan_candidate_sha256 == plan.candidate_sha256 - && intent.plan_action == plan.effective_action() - } - None => { - intent.frontier_route_id.is_empty() - && intent.plan_candidate_sha256.is_empty() - && intent.plan_action.is_empty() - } - }; - if intent.schema_version != HANDS_ACTION_INTENT_SCHEMA_VERSION - || review.schema_version != HANDS_ACTION_REVIEW_SCHEMA_VERSION - || grant.schema_version != SUBSTRATE_GATE_REPO_ACCESS_GRANT_RECEIPT_SCHEMA_VERSION - || intent.contract.trim().is_empty() - || review.contract.trim().is_empty() + if grant.schema_version != SUBSTRATE_GATE_REPO_ACCESS_GRANT_RECEIPT_SCHEMA_VERSION || grant.contract.trim().is_empty() - || chrono::DateTime::parse_from_rfc3339(&intent.requested_at).is_err() - || chrono::DateTime::parse_from_rfc3339(&review.reviewed_at).is_err() || chrono::DateTime::parse_from_rfc3339(&grant.granted_at).is_err() || route.next_organ != RepoFrontierNextOrgan::Hands - || authority.model_projection_digest != route.model_projection_digest - || authority.model_source_documents != route.model_source_documents - || authority.frontier_item_id != route.frontier_item_id - || authority.frontier_item_hash != route.frontier_item_hash || current_item.adopted_plan != route.adopted_plan || route .adopted_plan .as_ref() .is_some_and(|plan| route.authorized_paths != plan.safe_paths) - || !adopted_plan_binding_is_exact - || review.intent_id != intent.intent_id - || review.decision != "approved" - || !requested_operations.iter().all(|required| { - review - .allowed_operations - .iter() - .any(|operation| operation == required) - }) || intent.substrate_gate_grant_receipt_id != grant.receipt_id || grant.runtime_job_id != intent.runtime_job_id - || grant.binding_id != intent.binding_id - || grant.role != intent.role - || grant.authority_scope != intent.authority_scope - || !requested_operations.iter().all(|required| { + || !["patch", "command", "commit"].iter().all(|required| { grant .granted_operations .iter() .any(|operation| operation == required) }) - || authority.requested_paths != intent.requested_paths - || authority.requested_paths != grant.granted_paths - || !within_scope + || intent.requested_paths != grant.granted_paths + || intent.requested_paths != route.authorized_paths { return Err(anyhow!( "repo frontier Hands authority chain violates its full authority contract" @@ -7024,9 +6921,14 @@ pub fn put_repo_frontier_hands_authority( authority: &RepoFrontierHandsAuthority, ) -> Result<()> { let store_path = store_path.as_ref(); - if chrono::DateTime::parse_from_rfc3339(&authority.granted_at).is_err() - || !crate::memory_graph::repo_paths_are_canonical_and_safe(&authority.requested_paths) - || authority.requested_paths.is_empty() + if [ + authority.authority_id.as_str(), + authority.route_id.as_str(), + authority.hands_intent_id.as_str(), + authority.substrate_grant_receipt_id.as_str(), + ] + .into_iter() + .any(str::is_empty) { return Err(anyhow!("invalid repo frontier Hands authority contract")); } @@ -7040,40 +6942,11 @@ pub fn put_repo_frontier_hands_authority( let intent = cache .get::(&authority.hands_intent_id)? .ok_or_else(|| anyhow!("repo frontier Hands authority requires its persisted intent"))?; - let review = cache - .get::(&authority.hands_review_id)? - .ok_or_else(|| anyhow!("repo frontier Hands authority requires its persisted review"))?; let grant = cache .get::(&authority.substrate_grant_receipt_id)? .ok_or_else(|| { anyhow!("repo frontier Hands authority requires its persisted Substrate grant") })?; - let within_scope = authority.requested_paths.iter().all(|path| { - route.authorized_paths.iter().any(|scope| { - path == scope || path.starts_with(&format!("{}/", scope.trim_end_matches(['/', '\\']))) - }) - }); - if route.next_organ != RepoFrontierNextOrgan::Hands - || authority.route_id != route.route_id - || authority.model_projection_digest != route.model_projection_digest - || authority.model_source_documents != route.model_source_documents - || authority.frontier_item_id != route.frontier_item_id - || authority.frontier_item_hash != route.frontier_item_hash - || review.intent_id != intent.intent_id - || review.decision != "approved" - || intent.substrate_gate_grant_receipt_id != grant.receipt_id - || grant.runtime_job_id != intent.runtime_job_id - || grant.binding_id != intent.binding_id - || grant.role != intent.role - || grant.authority_scope != intent.authority_scope - || authority.requested_paths != intent.requested_paths - || authority.requested_paths != grant.granted_paths - || !within_scope - { - return Err(anyhow!( - "repo frontier Hands authority does not exactly bind route, model, intent, review, grant, and scope" - )); - } let (envelope, _) = cache.prepare_entry(&authority.authority_id, authority)?; let backing = SingleFileMessagePackBackingStore::new(store_path); let expected = vec![ @@ -7083,14 +6956,11 @@ pub fn put_repo_frontier_hands_authority( cache .get_envelope::(&intent.intent_id)? .ok_or_else(|| anyhow!("repo frontier Hands authority lost its intent envelope"))?, - cache - .get_envelope::(&review.review_id)? - .ok_or_else(|| anyhow!("repo frontier Hands authority lost its review envelope"))?, cache .get_envelope::(&grant.receipt_id)? .ok_or_else(|| anyhow!("repo frontier Hands authority lost its grant envelope"))?, cache - .get_envelope::(&authority.frontier_item_id)? + .get_envelope::(&route.frontier_item_id)? .ok_or_else(|| anyhow!("repo frontier Hands authority lost its frontier envelope"))?, ]; let mut writes = expected.clone(); @@ -7157,7 +7027,6 @@ pub(crate) fn validate_repo_frontier_verification_request_intrinsic( request.frontier_item_id.as_str(), request.frontier_item_hash.as_str(), request.hands_intent_id.as_str(), - request.hands_review_id.as_str(), request.hands_patch_receipt_id.as_str(), request.hands_command_receipt_id.as_str(), request.hands_commit_receipt_id.as_str(), @@ -7244,7 +7113,6 @@ fn repo_frontier_verification_context_with_commit( .filter(|authority| { authority.route_id == request.route_id && authority.hands_intent_id == request.hands_intent_id - && authority.hands_review_id == request.hands_review_id }) .collect::>(); let [hands_authority] = authorities.as_slice() else { @@ -7256,9 +7124,6 @@ fn repo_frontier_verification_context_with_commit( let hands_intent = cache .get::(&request.hands_intent_id)? .ok_or_else(|| anyhow!("Verification context lost its Hands intent"))?; - let hands_review = cache - .get::(&request.hands_review_id)? - .ok_or_else(|| anyhow!("Verification context lost its Hands review"))?; let patch_receipt = cache .get::(&request.hands_patch_receipt_id)? .ok_or_else(|| anyhow!("Verification context lost its patch receipt"))?; @@ -7268,8 +7133,7 @@ fn repo_frontier_verification_context_with_commit( let commit_receipt = match prospective_commit { Some(receipt) if receipt.receipt_id == request.hands_commit_receipt_id - && receipt.intent_id == request.hands_intent_id - && receipt.review_id == request.hands_review_id => + && receipt.intent_id == request.hands_intent_id => { receipt.clone() } @@ -7288,7 +7152,6 @@ fn repo_frontier_verification_context_with_commit( route, hands_authority: hands_authority.clone(), hands_intent, - hands_review, patch_receipt, command_receipt, commit_receipt, @@ -7415,9 +7278,7 @@ fn derive_repo_frontier_verification_request_for_chain( let authorities = cache .get_all::()? .into_iter() - .filter(|value| { - value.hands_intent_id == commit.intent_id && value.hands_review_id == commit.review_id - }) + .filter(|value| value.hands_intent_id == commit.intent_id) .collect::>(); if authorities.len() != 1 { return Err(anyhow!( @@ -7425,8 +7286,11 @@ fn derive_repo_frontier_verification_request_for_chain( )); } let authority = &authorities[0]; + let route = cache + .get::(&authority.route_id)? + .ok_or_else(|| anyhow!("Hands authority lost its exact route"))?; let frontier_envelope = cache - .get_envelope::(&authority.frontier_item_id)? + .get_envelope::(&route.frontier_item_id)? .ok_or_else(|| anyhow!("Hands authority lost its exact frontier document"))?; let frontier_authority_documents = vec![crate::EpiphanyMindDocumentVersion::from_envelope( "epiphany-mind", @@ -7443,12 +7307,11 @@ fn derive_repo_frontier_verification_request_for_chain( let request = RepoFrontierVerificationRequest { request_id, route_id: authority.route_id.clone(), - model_projection_digest: authority.model_projection_digest.clone(), - model_source_documents: authority.model_source_documents.clone(), - frontier_item_id: authority.frontier_item_id.clone(), - frontier_item_hash: authority.frontier_item_hash.clone(), + model_projection_digest: route.model_projection_digest.clone(), + model_source_documents: route.model_source_documents.clone(), + frontier_item_id: route.frontier_item_id.clone(), + frontier_item_hash: route.frontier_item_hash.clone(), hands_intent_id: commit.intent_id.clone(), - hands_review_id: commit.review_id.clone(), hands_patch_receipt_id: patch.receipt_id.clone(), hands_command_receipt_id: command.receipt_id.clone(), hands_commit_receipt_id: commit.receipt_id.clone(), @@ -7461,11 +7324,8 @@ fn derive_repo_frontier_verification_request_for_chain( fn validate_hands_consequence_grant( store_path: &Path, intent_id: &str, - review_id: &str, - runtime_job_id: &str, operation: &str, changed_paths: &[String], - stated_grant_id: Option<&str>, stated_command: Option<&str>, ) -> Result<()> { let mut cache = runtime_spine_cache(store_path)?; @@ -7474,9 +7334,6 @@ fn validate_hands_consequence_grant( let intent = cache .get::(intent_id)? .ok_or_else(|| anyhow!("Hands consequence requires its persisted intent"))?; - let review = cache - .get::(review_id)? - .ok_or_else(|| anyhow!("Hands consequence requires its persisted review"))?; let grant = cache .get::(&intent.substrate_gate_grant_receipt_id)? .ok_or_else(|| anyhow!("Hands consequence requires its persisted Substrate Gate grant"))?; @@ -7496,8 +7353,8 @@ fn validate_hands_consequence_grant( .ok_or_else(|| anyhow!("Hands consequence requires its persisted repo frontier route"))?; require_keyed_repo_model_basis( &cache, - &authority.model_projection_digest, - &authority.model_source_documents, + &route.model_projection_digest, + &route.model_source_documents, )?; let paths_covered = changed_paths.iter().all(|path| { grant.granted_paths.iter().any(|granted| { @@ -7506,22 +7363,11 @@ fn validate_hands_consequence_grant( || path.starts_with(&format!("{}/", granted.trim_end_matches(['/', '\\']))) }) }); - if intent.runtime_job_id != runtime_job_id - || review.intent_id != intent.intent_id - || review.decision != "approved" - || !review - .allowed_operations - .iter() - .any(|allowed| allowed == operation) - || grant.runtime_job_id != intent.runtime_job_id - || grant.binding_id != intent.binding_id - || grant.role != intent.role - || grant.authority_scope != intent.authority_scope + if grant.runtime_job_id != intent.runtime_job_id || !grant .granted_operations .iter() .any(|allowed| allowed == operation) - || stated_grant_id.is_some_and(|id| id != grant.receipt_id) || stated_command.is_some_and(|command| { route .adopted_plan @@ -7529,23 +7375,19 @@ fn validate_hands_consequence_grant( .is_some_and(|plan| command != plan.effective_command()) }) || !paths_covered - || authority.hands_review_id != review.review_id || authority.substrate_grant_receipt_id != grant.receipt_id - || authority.requested_paths != intent.requested_paths || authority.route_id != route.route_id - || authority.model_projection_digest != route.model_projection_digest - || authority.model_source_documents != route.model_source_documents - || authority.frontier_item_id != route.frontier_item_id - || authority.frontier_item_hash != route.frontier_item_hash + || authority.hands_intent_id != intent.intent_id + || intent.requested_paths != route.authorized_paths || !changed_paths.iter().all(|path| { - authority.requested_paths.iter().any(|scope| { + intent.requested_paths.iter().any(|scope| { path == scope || path.starts_with(&format!("{}/", scope.trim_end_matches(['/', '\\']))) }) }) { return Err(anyhow!( - "Hands consequence does not match its approved review and Substrate Gate grant" + "Hands consequence does not match its route, intent, and Substrate Gate grant" )); } Ok(()) @@ -7558,12 +7400,6 @@ pub fn put_hands_patch_receipt( let store_path = store_path.as_ref(); validate_non_empty(&receipt.receipt_id, "Hands patch receipt id")?; validate_non_empty(&receipt.intent_id, "Hands patch intent")?; - validate_non_empty(&receipt.review_id, "Hands patch review")?; - validate_non_empty( - &receipt.substrate_gate_grant_receipt_id, - "Hands patch Substrate Gate grant receipt", - )?; - validate_non_empty(&receipt.runtime_job_id, "Hands patch runtime job")?; validate_non_empty(&receipt.summary, "Hands patch summary")?; validate_non_empty(&receipt.emitted_at, "Hands patch timestamp")?; if receipt.changed_paths.is_empty() { @@ -7572,11 +7408,8 @@ pub fn put_hands_patch_receipt( validate_hands_consequence_grant( store_path.as_ref(), &receipt.intent_id, - &receipt.review_id, - &receipt.runtime_job_id, "patch", &receipt.changed_paths, - Some(&receipt.substrate_gate_grant_receipt_id), None, )?; let mut cache = runtime_spine_cache(store_path)?; @@ -7603,23 +7436,14 @@ pub fn put_hands_command_receipt( let store_path = store_path.as_ref(); validate_non_empty(&receipt.receipt_id, "Hands command receipt id")?; validate_non_empty(&receipt.intent_id, "Hands command intent")?; - validate_non_empty(&receipt.review_id, "Hands command review")?; - validate_non_empty( - &receipt.substrate_gate_grant_receipt_id, - "Hands command Substrate Gate grant receipt", - )?; - validate_non_empty(&receipt.runtime_job_id, "Hands command runtime job")?; validate_non_empty(&receipt.command, "Hands command")?; validate_non_empty(&receipt.exit_code, "Hands command exit code")?; validate_non_empty(&receipt.emitted_at, "Hands command timestamp")?; validate_hands_consequence_grant( store_path.as_ref(), &receipt.intent_id, - &receipt.review_id, - &receipt.runtime_job_id, "command", &[], - Some(&receipt.substrate_gate_grant_receipt_id), Some(&receipt.command), )?; let mut cache = runtime_spine_cache(store_path)?; @@ -7646,8 +7470,6 @@ pub fn put_hands_commit_receipt( let store_path = store_path.as_ref(); validate_non_empty(&receipt.receipt_id, "Hands commit receipt id")?; validate_non_empty(&receipt.intent_id, "Hands commit intent")?; - validate_non_empty(&receipt.review_id, "Hands commit review")?; - validate_non_empty(&receipt.runtime_job_id, "Hands commit runtime job")?; validate_non_empty(&receipt.commit_sha, "Hands commit sha")?; validate_non_empty(&receipt.branch, "Hands commit branch")?; validate_non_empty(&receipt.summary, "Hands commit summary")?; @@ -7658,41 +7480,33 @@ pub fn put_hands_commit_receipt( validate_hands_consequence_grant( store_path.as_ref(), &receipt.intent_id, - &receipt.review_id, - &receipt.runtime_job_id, "commit", &receipt.changed_paths, None, - None, )?; let mut cache = runtime_spine_cache(store_path)?; cache.pull_all_backing_stores()?; require_identity(&cache)?; - let patch = cache + let patches = cache .get_all::()? .into_iter() - .filter(|patch| { - patch.intent_id == receipt.intent_id - && patch.review_id == receipt.review_id - && patch.runtime_job_id == receipt.runtime_job_id - && patch.emitted_at <= receipt.emitted_at - }) - .max_by(|left, right| left.emitted_at.cmp(&right.emitted_at)) - .ok_or_else(|| anyhow!("Hands commit requires its exact patch receipt"))?; - let command = cache + .filter(|patch| patch.intent_id == receipt.intent_id) + .collect::>(); + let [patch] = patches.as_slice() else { + return Err(anyhow!("Hands commit requires one exact patch receipt")); + }; + let commands = cache .get_all::()? .into_iter() - .filter(|command| { - command.intent_id == receipt.intent_id - && command.review_id == receipt.review_id - && command.runtime_job_id == receipt.runtime_job_id - && command.exit_code == "0" - && command.emitted_at <= receipt.emitted_at - }) - .max_by(|left, right| left.emitted_at.cmp(&right.emitted_at)) - .ok_or_else(|| anyhow!("Hands commit requires its successful command receipt"))?; + .filter(|command| command.intent_id == receipt.intent_id && command.exit_code == "0") + .collect::>(); + let [command] = commands.as_slice() else { + return Err(anyhow!( + "Hands commit requires one exact successful command receipt" + )); + }; let request = - derive_repo_frontier_verification_request_for_chain(&cache, &patch, &command, receipt)?; + derive_repo_frontier_verification_request_for_chain(&cache, patch, command, receipt)?; let context = repo_frontier_verification_context_with_commit(&cache, &request, Some(receipt))?; let snapshot = cache.snapshot_envelopes(); let mut expected = Vec::new(); @@ -7703,7 +7517,6 @@ pub fn put_hands_commit_receipt( context.hands_authority.authority_id.as_str(), ), (HandsActionIntent::TYPE, request.hands_intent_id.as_str()), - (HandsActionReview::TYPE, request.hands_review_id.as_str()), ( HandsPatchReceipt::TYPE, request.hands_patch_receipt_id.as_str(), diff --git a/epiphany-core/src/soul_gateway.rs b/epiphany-core/src/soul_gateway.rs index 09a093cf..93613a37 100644 --- a/epiphany-core/src/soul_gateway.rs +++ b/epiphany-core/src/soul_gateway.rs @@ -46,15 +46,13 @@ pub struct RepoFrontierVerificationRequest { #[cultcache(key = 7)] pub hands_intent_id: String, #[cultcache(key = 8)] - pub hands_review_id: String, - #[cultcache(key = 9)] pub hands_patch_receipt_id: String, - #[cultcache(key = 10)] + #[cultcache(key = 9)] pub hands_command_receipt_id: String, - #[cultcache(key = 11)] + #[cultcache(key = 10)] pub hands_commit_receipt_id: String, - #[cultcache(key = 12)] + #[cultcache(key = 11)] pub requested_at: String, - #[cultcache(key = 14)] + #[cultcache(key = 12)] pub frontier_authority_documents: Vec, } diff --git a/epiphany-core/src/surfaces/worker_launch.rs b/epiphany-core/src/surfaces/worker_launch.rs index af709e3b..e8a8adce 100644 --- a/epiphany-core/src/surfaces/worker_launch.rs +++ b/epiphany-core/src/surfaces/worker_launch.rs @@ -16,9 +16,9 @@ pub const REPO_FRONTIER_RESEARCH_CONTEXT_SCHEMA_VERSION: &str = pub const REPO_FRONTIER_RESEARCH_CONTEXT_CONTRACT: &str = "epiphany.repo_frontier_research_context.v3"; pub const REPO_FRONTIER_VERIFICATION_CONTEXT_SCHEMA_VERSION: &str = - "epiphany.worker.repo_frontier_verification_context.v1"; + "epiphany.worker.repo_frontier_verification_context.v2"; pub const REPO_FRONTIER_VERIFICATION_CONTEXT_CONTRACT: &str = - "epiphany.repo_frontier_verification_context.v1"; + "epiphany.repo_frontier_verification_context.v2"; pub const REPO_FRONTIER_PLAN_MIND_CONTEXT_SCHEMA_VERSION: &str = "epiphany.worker.repo_frontier_plan_mind_context.v0"; pub const REPO_FRONTIER_PLAN_MIND_CONTEXT_CONTRACT: &str = @@ -241,7 +241,6 @@ pub struct RepoFrontierVerificationContextProjection { pub route: crate::RepoFrontierRoute, pub hands_authority: crate::RepoFrontierHandsAuthority, pub hands_intent: crate::HandsActionIntent, - pub hands_review: crate::HandsActionReview, pub patch_receipt: crate::HandsPatchReceipt, pub command_receipt: crate::HandsCommandReceipt, pub commit_receipt: crate::HandsCommitReceipt, diff --git a/notes/hands-cultnet-contracts.md b/notes/hands-cultnet-contracts.md index 2eb01938..e0ad3f6b 100644 --- a/notes/hands-cultnet-contracts.md +++ b/notes/hands-cultnet-contracts.md @@ -10,27 +10,27 @@ receipts that can be verified or admitted into Mind state. - Inputs: typed action intents, Substrate Gate access grants, requested commands or patches, current repo policy, Soul verification requirements, and coordinator authority. -- Outputs: Hands action reviews, command receipts, patch receipts, commit - receipts, and action refusal receipts. +- Outputs: observed patch, command, and commit receipts. - Derived state: diffs, command logs, and commits are action receipts. They are not durable Mind state until Mind admits them. - Forbidden writers: raw workers, Persona, Eyes, Imagination, Self, compatibility JSON-RPC routes, and bridge tools must not execute repo-affecting commands, edit files, commit, or publish without the Hands path after Body access. -- Shared path: file edits, shell commands, and commits share Hands action - intent/review/receipt semantics. +- Shared path: file edits, shell commands, and commits share the exact adopted + route, action intent, Substrate Gate grant, frontier authority, and receipt + admission path. - Deletion line: Substrate Gate grants access; it does not execute. Soul verifies; it does not execute. Mind records durable state; it does not execute. ## Contract Families - `epiphany.hands.action_intent`: request for bounded action. -- `epiphany.hands.action_review`: Hands decision and execution plan. +- `epiphany.hands.repo_frontier_authority`: exact binding among the adopted + route, action intent, and Substrate Gate grant. - `epiphany.hands.command_receipt`: proof of command execution. - `epiphany.hands.patch_receipt`: proof of file mutation. - `epiphany.hands.commit_receipt`: proof of commit creation. -- `epiphany.hands.action_refusal_receipt`: proof that Hands refused to act. ## Neighboring Gates @@ -52,21 +52,28 @@ Epiphany may consume that provider-owned receipt after the local commit exists. The first runtime-spine proof chain now exists: ```text -HandsActionIntent --> HandsActionReview +RepoFrontierRoute + SubstrateGateRepoAccessGrantReceipt +-> HandsActionIntent + RepoFrontierHandsAuthority -> HandsPatchReceipt -> HandsCommandReceipt -> HandsCommitReceipt +-> RepoFrontierVerificationRequest ``` `epiphany-core::hands_gateway` owns the typed document bodies and constructors. -`epiphany-core::runtime_spine` can persist and reread the intent, review, patch, -command, and commit receipts from the runtime-spine CultCache store. -The launch organ contract's repo-action proof profile now requires the full -Hands chain, not only the final patch receipt. +`epiphany-core::runtime_spine` admits the intent and consequence receipts into +the runtime-spine CultCache store and atomically creates Verification work with +the commit. The typed CultCache documents are the process boundary; public Rust +helper functions are not a substitute ABI. `epiphany-mvp-coordinator` turns `continueImplementation` into a persisted -Substrate Gate grant plus Hands intent/review gate and exposes the exact receipt -identities required by downstream Verification. +Substrate Gate grant, Hands intent, and frontier authority, then exposes the +exact receipt families required by downstream Verification. + +There is no separate Hands review document. The coordinator formerly authored +the grant, intent, review, and authority in one function, and the review could +only repeat `approved` plus the grant operations. It was a paper authority, not +an independent decision. Consequences now validate directly against the route, +intent, grant, and authority. Epiphany currently has no admitted repository actuator. The former `epiphany-hands-action` executable only accepted operator-authored descriptions