chio_workflow_preflight/
lib.rs1mod scope;
4mod types;
5mod validation;
6
7pub use types::{
8 WorkflowApprovalPreflight, WorkflowBudgetPool, WorkflowPlanningArtifact,
9 WorkflowPreflightCheck, WorkflowPreflightChildTask, WorkflowPreflightError,
10 WorkflowPreflightParentTask, WorkflowPreflightPlan, WorkflowPreflightReport,
11 WorkflowPreflightScope, WorkflowPreflightVerdict, WorkflowRegistrySupport,
12 WorkflowRevocationPreflight, WorkflowRoutePlanPreflight, WORKFLOW_PREFLIGHT_PLAN_SCHEMA,
13 WORKFLOW_PREFLIGHT_REPORT_SCHEMA,
14};
15
16use scope::collect_child_scope_checks;
17use validation::{collect_plan_gate_checks, validate_plan_shape};
18
19const CLAIM_PREFLIGHT_CHILD_SCOPE_BOUNDED: &str = "claim.workflow.preflight_child_scope_bounded";
20const CLAIM_PREFLIGHT_PLANNING_ONLY: &str = "claim.workflow.preflight_planning_only";
21
22pub fn evaluate_workflow_preflight(
23 plan: &WorkflowPreflightPlan,
24) -> Result<WorkflowPreflightReport, WorkflowPreflightError> {
25 validate_plan_shape(plan)?;
26
27 let mut rejected_checks = Vec::new();
28 collect_child_scope_checks(plan, &mut rejected_checks);
29 collect_plan_gate_checks(plan, &mut rejected_checks);
30
31 let verdict = if rejected_checks.is_empty() {
32 WorkflowPreflightVerdict::Accepted
33 } else {
34 WorkflowPreflightVerdict::Rejected
35 };
36 let verified_claims = if verdict == WorkflowPreflightVerdict::Accepted {
37 vec![
38 CLAIM_PREFLIGHT_CHILD_SCOPE_BOUNDED.to_string(),
39 CLAIM_PREFLIGHT_PLANNING_ONLY.to_string(),
40 ]
41 } else {
42 Vec::new()
43 };
44
45 Ok(WorkflowPreflightReport {
46 schema: WORKFLOW_PREFLIGHT_REPORT_SCHEMA.to_string(),
47 id: format!("workflow-preflight-report-{}", plan.id),
48 issued_at: plan.issued_at.clone(),
49 plan_id: plan.id.clone(),
50 verdict,
51 evidence_class: "planning".to_string(),
52 verified_claims,
53 rejected_checks,
54 live_authority_claims: Vec::new(),
55 })
56}