Skip to main content

forge_pilot/
targets.rs

1//! Verification target types for the orient phase.
2//!
3//! Each `TargetKind` variant represents a distinct class of verification
4//! work the pilot can select, from active syndromes to stale scopes.
5
6use crate::types::{BudgetClass, CanonicalCaseClass, LawfulStepKind};
7use serde::{Deserialize, Serialize};
8use stack_ids::ClaimVersionId;
9use verification_control::VerificationCaseClass;
10
11/// Scheduling priority of a verification target, lowest numeric value wins.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum TargetPriority {
15    ActiveSyndrome = 0,
16    FragileNode = 1,
17    ThinExport = 2,
18    UnverifiedClaimVersion = 3,
19    RefutationGap = 4,
20    SupersessionVerification = 5,
21    ComparabilityDrift = 6,
22    CalibrationCaveat = 7,
23    ScopeStale = 8,
24}
25
26/// A specific class of verification work identified during orientation.
27///
28/// Each variant carries the data the act phase needs to execute the
29/// corresponding oracle or advisory plan.
30#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
31#[serde(rename_all = "snake_case")]
32pub enum TargetKind {
33    FragileNode {
34        node_id: String,
35        belief_micros: u64,
36    },
37    ActiveSyndrome {
38        signature: String,
39    },
40    ThinExport {
41        marker: String,
42    },
43    UnverifiedClaimVersion {
44        claim_version_id: ClaimVersionId,
45    },
46    RefutationGap {
47        target_node_id: String,
48        claim_version_id: Option<ClaimVersionId>,
49    },
50    SupersessionVerification {
51        claim_version_id: ClaimVersionId,
52        supersedes_claim_version_id: ClaimVersionId,
53    },
54    ComparabilityDrift {
55        detail: String,
56    },
57    CalibrationCaveat {
58        marker: String,
59    },
60    ScopeStale {
61        last_import_at: Option<String>,
62    },
63}
64
65impl TargetKind {
66    /// Returns the canonical case class associated with this target kind.
67    pub fn canonical_case_class(&self) -> CanonicalCaseClass {
68        match self {
69            Self::ActiveSyndrome { .. } => CanonicalCaseClass::ContradictionInvestigation,
70            Self::FragileNode { .. } => CanonicalCaseClass::PromotionCandidate,
71            Self::ThinExport { .. } => CanonicalCaseClass::ThinExportGap,
72            Self::UnverifiedClaimVersion { .. } => CanonicalCaseClass::PromotionCandidate,
73            Self::RefutationGap { .. } => CanonicalCaseClass::PromotionCandidate,
74            Self::SupersessionVerification { .. } => CanonicalCaseClass::SupersessionVerification,
75            Self::ComparabilityDrift { .. } => CanonicalCaseClass::ComparabilityDrift,
76            Self::CalibrationCaveat { .. } => CanonicalCaseClass::CalibrationCaveat,
77            Self::ScopeStale { .. } => CanonicalCaseClass::ScopeFreshness,
78        }
79    }
80
81    /// Returns the verification case class associated with this target kind.
82    pub fn case_class(&self) -> VerificationCaseClass {
83        match self {
84            Self::FragileNode { .. } => VerificationCaseClass::FragileNode,
85            Self::ActiveSyndrome { .. } => VerificationCaseClass::ActiveSyndrome,
86            Self::ThinExport { .. } => VerificationCaseClass::ThinExport,
87            Self::UnverifiedClaimVersion { .. } => VerificationCaseClass::UnverifiedClaimVersion,
88            Self::RefutationGap { .. } => VerificationCaseClass::RefutationGap,
89            Self::SupersessionVerification { .. } => {
90                VerificationCaseClass::SupersessionVerification
91            }
92            Self::ComparabilityDrift { .. } => VerificationCaseClass::ComparabilityDrift,
93            Self::CalibrationCaveat { .. } => VerificationCaseClass::CalibrationCaveat,
94            Self::ScopeStale { .. } => VerificationCaseClass::ScopeStale,
95        }
96    }
97
98    /// Returns the primary claim version carried by this target, if any.
99    pub fn primary_claim_version_id(&self) -> Option<ClaimVersionId> {
100        match self {
101            Self::UnverifiedClaimVersion { claim_version_id }
102            | Self::RefutationGap {
103                claim_version_id: Some(claim_version_id),
104                ..
105            }
106            | Self::SupersessionVerification {
107                claim_version_id, ..
108            } => Some(claim_version_id.clone()),
109            _ => None,
110        }
111    }
112
113    /// Returns the stable key used for history tracking and receipts.
114    pub fn stable_key(&self) -> String {
115        match self {
116            Self::FragileNode { node_id, .. } => format!("fragile:{node_id}"),
117            Self::ActiveSyndrome { signature } => format!("syndrome:{signature}"),
118            Self::ThinExport { marker } => format!("thin_export:{marker}"),
119            Self::UnverifiedClaimVersion { claim_version_id } => {
120                format!("unverified:{}", claim_version_id.as_str())
121            }
122            Self::RefutationGap {
123                target_node_id,
124                claim_version_id,
125            } => format!(
126                "refutation_gap:{target_node_id}:{}",
127                claim_version_id
128                    .as_ref()
129                    .map(|id| id.as_str())
130                    .unwrap_or("none")
131            ),
132            Self::SupersessionVerification {
133                claim_version_id,
134                supersedes_claim_version_id,
135            } => format!(
136                "supersession:{}:{}",
137                claim_version_id.as_str(),
138                supersedes_claim_version_id.as_str()
139            ),
140            Self::ComparabilityDrift { detail } => format!("comparability:{detail}"),
141            Self::CalibrationCaveat { marker } => format!("calibration:{marker}"),
142            Self::ScopeStale { last_import_at } => {
143                format!(
144                    "scope_stale:{}",
145                    last_import_at.as_deref().unwrap_or("none")
146                )
147            }
148        }
149    }
150
151    /// Returns the scheduling priority implied by this target.
152    pub fn priority(&self) -> TargetPriority {
153        match self {
154            Self::ActiveSyndrome { .. } => TargetPriority::ActiveSyndrome,
155            Self::FragileNode { .. } => TargetPriority::FragileNode,
156            Self::ThinExport { .. } => TargetPriority::ThinExport,
157            Self::UnverifiedClaimVersion { .. } => TargetPriority::UnverifiedClaimVersion,
158            Self::RefutationGap { .. } => TargetPriority::RefutationGap,
159            Self::SupersessionVerification { .. } => TargetPriority::SupersessionVerification,
160            Self::ComparabilityDrift { .. } => TargetPriority::ComparabilityDrift,
161            Self::CalibrationCaveat { .. } => TargetPriority::CalibrationCaveat,
162            Self::ScopeStale { .. } => TargetPriority::ScopeStale,
163        }
164    }
165
166    /// Returns the budget class implied by this target.
167    pub fn budget_class(&self) -> BudgetClass {
168        match self {
169            Self::ThinExport { .. } | Self::ScopeStale { .. } => BudgetClass::Micro,
170            Self::ActiveSyndrome { .. }
171            | Self::FragileNode { .. }
172            | Self::UnverifiedClaimVersion { .. }
173            | Self::RefutationGap { .. }
174            | Self::SupersessionVerification { .. }
175            | Self::ComparabilityDrift { .. }
176            | Self::CalibrationCaveat { .. } => BudgetClass::Standard,
177        }
178    }
179
180    /// Returns the artifact families required to execute this target lawfully.
181    pub fn required_artifact_families(&self) -> Vec<String> {
182        let mut families = vec![
183            "ExecutionContextV1".into(),
184            "RuntimeQueryProvenanceV1".into(),
185        ];
186        match self {
187            Self::ThinExport { .. } => {}
188            Self::ComparabilityDrift { .. } => families.push("ComparableWitnessSet".into()),
189            Self::SupersessionVerification { .. } => families.push("ReplayArtifact".into()),
190            Self::RefutationGap { .. } => families.push("FalsifierWitness".into()),
191            _ => families.push("VerificationPlanV1".into()),
192        }
193        families
194    }
195
196    /// Returns the lawful step ladder implied by this target.
197    pub fn lawful_step_ladder(&self) -> Vec<LawfulStepKind> {
198        match self {
199            Self::ActiveSyndrome { .. } => vec![
200                LawfulStepKind::ExactOracleSlice,
201                LawfulStepKind::ExactReplay,
202                LawfulStepKind::MinimalPerturbationRefuter,
203                LawfulStepKind::HumanReviewRequest,
204            ],
205            Self::FragileNode { .. } => vec![
206                LawfulStepKind::ContractSchemaCheck,
207                LawfulStepKind::ProvenanceReceiptAudit,
208                LawfulStepKind::MinimalPerturbationRefuter,
209                LawfulStepKind::HumanReviewRequest,
210            ],
211            Self::ThinExport { .. } => vec![
212                LawfulStepKind::ContractSchemaCheck,
213                LawfulStepKind::ProvenanceReceiptAudit,
214                LawfulStepKind::HumanReviewRequest,
215            ],
216            Self::UnverifiedClaimVersion { .. } => vec![
217                LawfulStepKind::ContractSchemaCheck,
218                LawfulStepKind::ProvenanceReceiptAudit,
219                LawfulStepKind::TemporalConsistencyCheck,
220                LawfulStepKind::ExactOracleSlice,
221                LawfulStepKind::ConservativeOracleSlice,
222                LawfulStepKind::HumanReviewRequest,
223            ],
224            Self::RefutationGap { .. } => vec![
225                LawfulStepKind::MinimalPerturbationRefuter,
226                LawfulStepKind::ExactOracleSlice,
227                LawfulStepKind::HumanReviewRequest,
228            ],
229            Self::SupersessionVerification { .. } => vec![
230                LawfulStepKind::TemporalConsistencyCheck,
231                LawfulStepKind::ExactReplay,
232                LawfulStepKind::HumanReviewRequest,
233            ],
234            Self::ComparabilityDrift { .. } => vec![
235                LawfulStepKind::NuisanceComparabilityAudit,
236                LawfulStepKind::PairedComparativeCheck,
237                LawfulStepKind::HumanReviewRequest,
238            ],
239            Self::CalibrationCaveat { .. } => vec![
240                LawfulStepKind::ProvenanceReceiptAudit,
241                LawfulStepKind::ConservativeOracleSlice,
242                LawfulStepKind::HumanReviewRequest,
243            ],
244            Self::ScopeStale { .. } => vec![
245                LawfulStepKind::TemporalConsistencyCheck,
246                LawfulStepKind::CanonicalExportRequest,
247                LawfulStepKind::CanonicalImportRequest,
248                LawfulStepKind::HumanReviewRequest,
249            ],
250        }
251    }
252}