Delete counterfeit Hands review authority
This commit is contained in:
parent
08588a6d3f
commit
a01c684262
9 changed files with 106 additions and 487 deletions
|
|
@ -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()),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<String>,
|
||||
#[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<String>,
|
||||
#[cultcache(key = 3)]
|
||||
pub decision: String,
|
||||
#[cultcache(key = 4)]
|
||||
pub allowed_operations: Vec<String>,
|
||||
#[cultcache(key = 5)]
|
||||
pub required_receipts: Vec<String>,
|
||||
#[cultcache(key = 6)]
|
||||
pub reasons: Vec<String>,
|
||||
#[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<String>,
|
||||
#[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<String>,
|
||||
#[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<String>,
|
||||
reasons: Vec<String>,
|
||||
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<String>,
|
||||
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<String>,
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<crate::EpiphanyMindDocumentVersion>,
|
||||
#[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<String>,
|
||||
#[cultcache(key = 11)]
|
||||
pub granted_at: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<CultCache> {
|
|||
cache.register_entry_type::<EpiphanyCoordinatorDeathRecovery>()?;
|
||||
cache.register_entry_type::<SubstrateGateRepoAccessGrantReceipt>()?;
|
||||
cache.register_entry_type::<HandsActionIntent>()?;
|
||||
cache.register_entry_type::<HandsActionReview>()?;
|
||||
cache.register_entry_type::<HandsPatchReceipt>()?;
|
||||
cache.register_entry_type::<HandsCommandReceipt>()?;
|
||||
cache.register_entry_type::<HandsCommitReceipt>()?;
|
||||
|
|
@ -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<Path>,
|
||||
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::<HandsActionReview>(&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::<HandsActionIntent>(&authority.hands_intent_id)?
|
||||
.ok_or_else(|| anyhow!("Hands authority requires its persisted intent"))?;
|
||||
let review = cache
|
||||
.get::<HandsActionReview>(&authority.hands_review_id)?
|
||||
.ok_or_else(|| anyhow!("Hands authority requires its persisted review"))?;
|
||||
let grant = cache
|
||||
.get::<SubstrateGateRepoAccessGrantReceipt>(&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::<HandsActionIntent>(&authority.hands_intent_id)?
|
||||
.ok_or_else(|| anyhow!("repo frontier Hands authority requires its persisted intent"))?;
|
||||
let review = cache
|
||||
.get::<HandsActionReview>(&authority.hands_review_id)?
|
||||
.ok_or_else(|| anyhow!("repo frontier Hands authority requires its persisted review"))?;
|
||||
let grant = cache
|
||||
.get::<SubstrateGateRepoAccessGrantReceipt>(&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::<HandsActionIntent>(&intent.intent_id)?
|
||||
.ok_or_else(|| anyhow!("repo frontier Hands authority lost its intent envelope"))?,
|
||||
cache
|
||||
.get_envelope::<HandsActionReview>(&review.review_id)?
|
||||
.ok_or_else(|| anyhow!("repo frontier Hands authority lost its review envelope"))?,
|
||||
cache
|
||||
.get_envelope::<SubstrateGateRepoAccessGrantReceipt>(&grant.receipt_id)?
|
||||
.ok_or_else(|| anyhow!("repo frontier Hands authority lost its grant envelope"))?,
|
||||
cache
|
||||
.get_envelope::<crate::EpiphanyRepoModelFrontierDocument>(&authority.frontier_item_id)?
|
||||
.get_envelope::<crate::EpiphanyRepoModelFrontierDocument>(&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::<Vec<_>>();
|
||||
let [hands_authority] = authorities.as_slice() else {
|
||||
|
|
@ -7256,9 +7124,6 @@ fn repo_frontier_verification_context_with_commit(
|
|||
let hands_intent = cache
|
||||
.get::<HandsActionIntent>(&request.hands_intent_id)?
|
||||
.ok_or_else(|| anyhow!("Verification context lost its Hands intent"))?;
|
||||
let hands_review = cache
|
||||
.get::<HandsActionReview>(&request.hands_review_id)?
|
||||
.ok_or_else(|| anyhow!("Verification context lost its Hands review"))?;
|
||||
let patch_receipt = cache
|
||||
.get::<HandsPatchReceipt>(&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::<RepoFrontierHandsAuthority>()?
|
||||
.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::<Vec<_>>();
|
||||
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::<RepoFrontierRoute>(&authority.route_id)?
|
||||
.ok_or_else(|| anyhow!("Hands authority lost its exact route"))?;
|
||||
let frontier_envelope = cache
|
||||
.get_envelope::<crate::EpiphanyRepoModelFrontierDocument>(&authority.frontier_item_id)?
|
||||
.get_envelope::<crate::EpiphanyRepoModelFrontierDocument>(&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::<HandsActionIntent>(intent_id)?
|
||||
.ok_or_else(|| anyhow!("Hands consequence requires its persisted intent"))?;
|
||||
let review = cache
|
||||
.get::<HandsActionReview>(review_id)?
|
||||
.ok_or_else(|| anyhow!("Hands consequence requires its persisted review"))?;
|
||||
let grant = cache
|
||||
.get::<SubstrateGateRepoAccessGrantReceipt>(&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::<HandsPatchReceipt>()?
|
||||
.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::<Vec<_>>();
|
||||
let [patch] = patches.as_slice() else {
|
||||
return Err(anyhow!("Hands commit requires one exact patch receipt"));
|
||||
};
|
||||
let commands = cache
|
||||
.get_all::<HandsCommandReceipt>()?
|
||||
.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::<Vec<_>>();
|
||||
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(),
|
||||
|
|
|
|||
|
|
@ -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<crate::EpiphanyMindDocumentVersion>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Reference in a new issue