Skip to main content

omena_testkit/
snapshot.rs

1use serde::Serialize;
2
3/// Snapshot-governance policy locked by the M4 testkit substrate.
4#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
5#[serde(rename_all = "camelCase")]
6pub struct OmenaTestkitSnapshotGovernancePolicyV0 {
7    /// Fixture grammar that owns snapshot identity.
8    pub fixture_grammar: &'static str,
9    /// Manifest schema that binds snapshots back to fixture ids.
10    pub snapshot_manifest_schema: &'static str,
11    /// Known-failure schema that requires per-fixture rationale and review.
12    pub known_failure_schema: &'static str,
13    /// Whether a single global snapshot disable switch is accepted.
14    pub allow_global_disable: bool,
15    /// Whether snapshot updates require explicit human review.
16    pub update_requires_review: bool,
17    /// Action for snapshots not referenced by any fixture.
18    pub unreferenced_action: &'static str,
19    /// Maximum age before a hot snapshot requires review.
20    pub hot_snapshot_max_age_days: u32,
21    /// Maximum age before a known failure requires review.
22    pub known_failure_review_period_days: u32,
23}
24
25/// One known-failure record attached to a fixture-scoped snapshot.
26#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
27#[serde(rename_all = "camelCase")]
28pub struct OmenaTestkitKnownFailureRecordV0 {
29    /// Human-readable rationale for carrying the failure.
30    pub rationale: &'static str,
31    /// Owner or lane responsible for review.
32    pub owner: &'static str,
33    /// Age of the known-failure record.
34    pub age_days: u32,
35    /// Whether the entry has an explicit expiry or review policy.
36    pub has_expiry_or_review_policy: bool,
37}
38
39/// Seed snapshot entry used to prove the governance decision table.
40#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
41#[serde(rename_all = "camelCase")]
42pub struct OmenaTestkitSnapshotGovernanceSeedV0 {
43    /// Stable snapshot id.
44    pub snapshot_id: &'static str,
45    /// Fixture id that should own the snapshot.
46    pub fixture_id: &'static str,
47    /// Snapshot path relative to the corpus root.
48    pub snapshot_path: &'static str,
49    /// Whether this snapshot is referenced by a fixture manifest.
50    pub referenced_by_fixture: bool,
51    /// Whether this snapshot belongs to a frequently edited product path.
52    pub hot_snapshot: bool,
53    /// Snapshot age in days.
54    pub age_days: u32,
55    /// Optional known-failure metadata.
56    pub known_failure: Option<OmenaTestkitKnownFailureRecordV0>,
57}
58
59/// Per-seed governance verdict.
60#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
61#[serde(rename_all = "camelCase")]
62pub struct OmenaTestkitSnapshotGovernanceVerdictV0 {
63    /// Stable snapshot id.
64    pub snapshot_id: &'static str,
65    /// Fixture id that should own the snapshot.
66    pub fixture_id: &'static str,
67    /// Whether the seed is rejected as unreferenced.
68    pub rejected_unreferenced: bool,
69    /// Whether a hot snapshot requires age review.
70    pub hot_snapshot_review_required: bool,
71    /// Whether known-failure metadata requires review.
72    pub known_failure_review_required: bool,
73    /// Whether the known failure includes rationale plus expiry or review policy.
74    pub known_failure_policy_complete: bool,
75    /// Final machine action for the governance seed.
76    pub action: &'static str,
77}
78
79/// Snapshot-governance foundation report for Axis A.
80#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
81#[serde(rename_all = "camelCase")]
82pub struct OmenaTestkitSnapshotGovernanceReportV0 {
83    /// Schema version.
84    pub schema_version: &'static str,
85    /// Product surface.
86    pub product: &'static str,
87    /// Fixture grammar that owns snapshot identity.
88    pub fixture_grammar: &'static str,
89    /// Policy applied by the report.
90    pub policy: OmenaTestkitSnapshotGovernancePolicyV0,
91    /// Governance seed count.
92    pub seed_count: usize,
93    /// Whether global snapshot-disable behavior is rejected by policy.
94    pub global_disable_rejected: bool,
95    /// Whether unreferenced snapshots are rejected.
96    pub unreferenced_reject_ready: bool,
97    /// Whether hot snapshots are age-audited.
98    pub hot_snapshot_age_audit_ready: bool,
99    /// Whether known failures require rationale and expiry or review policy.
100    pub known_failure_policy_ready: bool,
101    /// Rejected unreferenced snapshot count.
102    pub rejected_unreferenced_count: usize,
103    /// Hot snapshot review-required count.
104    pub hot_snapshot_review_required_count: usize,
105    /// Known-failure count.
106    pub known_failure_count: usize,
107    /// Known-failure review-required count.
108    pub known_failure_review_required_count: usize,
109    /// Per-seed verdicts.
110    pub verdicts: Vec<OmenaTestkitSnapshotGovernanceVerdictV0>,
111}
112
113const SNAPSHOT_POLICY: OmenaTestkitSnapshotGovernancePolicyV0 =
114    OmenaTestkitSnapshotGovernancePolicyV0 {
115        fixture_grammar: "omena-fixture-v0",
116        snapshot_manifest_schema: "omena-testkit-snapshot-manifest-v0",
117        known_failure_schema: "omena-testkit-known-failures-v0",
118        allow_global_disable: false,
119        update_requires_review: true,
120        unreferenced_action: "reject",
121        hot_snapshot_max_age_days: 14,
122        known_failure_review_period_days: 30,
123    };
124
125const SNAPSHOT_GOVERNANCE_SEEDS: &[OmenaTestkitSnapshotGovernanceSeedV0] = &[
126    OmenaTestkitSnapshotGovernanceSeedV0 {
127        snapshot_id: "style-facts-current",
128        fixture_id: "shared-style-fixture",
129        snapshot_path: "snapshots/shared-style-fixture/style-facts.snap.json",
130        referenced_by_fixture: true,
131        hot_snapshot: false,
132        age_days: 3,
133        known_failure: None,
134    },
135    OmenaTestkitSnapshotGovernanceSeedV0 {
136        snapshot_id: "orphan-style-facts",
137        fixture_id: "removed-fixture",
138        snapshot_path: "snapshots/removed-fixture/style-facts.snap.json",
139        referenced_by_fixture: false,
140        hot_snapshot: false,
141        age_days: 2,
142        known_failure: None,
143    },
144    OmenaTestkitSnapshotGovernanceSeedV0 {
145        snapshot_id: "hot-lsp-hover",
146        fixture_id: "lsp-hover-scenario",
147        snapshot_path: "snapshots/lsp-hover-scenario/hover.snap.json",
148        referenced_by_fixture: true,
149        hot_snapshot: true,
150        age_days: 21,
151        known_failure: None,
152    },
153    OmenaTestkitSnapshotGovernanceSeedV0 {
154        snapshot_id: "known-failure-source-rename",
155        fixture_id: "dynamic-source-rename-scenario",
156        snapshot_path: "snapshots/dynamic-source-rename-scenario/rename.snap.json",
157        referenced_by_fixture: true,
158        hot_snapshot: true,
159        age_days: 5,
160        known_failure: Some(OmenaTestkitKnownFailureRecordV0 {
161            rationale: "issue-38 dynamic identifier rename path is tracked as an M4 gate",
162            owner: "m4-axis-a-testkit",
163            age_days: 31,
164            has_expiry_or_review_policy: true,
165        }),
166    },
167];
168
169/// Summarize the M4 snapshot-governance foundation.
170pub fn summarize_omena_testkit_snapshot_governance_report() -> OmenaTestkitSnapshotGovernanceReportV0
171{
172    let verdicts = SNAPSHOT_GOVERNANCE_SEEDS
173        .iter()
174        .map(snapshot_governance_verdict)
175        .collect::<Vec<_>>();
176    let rejected_unreferenced_count = verdicts
177        .iter()
178        .filter(|verdict| verdict.rejected_unreferenced)
179        .count();
180    let hot_snapshot_review_required_count = verdicts
181        .iter()
182        .filter(|verdict| verdict.hot_snapshot_review_required)
183        .count();
184    let known_failure_count = SNAPSHOT_GOVERNANCE_SEEDS
185        .iter()
186        .filter(|seed| seed.known_failure.is_some())
187        .count();
188    let known_failure_review_required_count = verdicts
189        .iter()
190        .filter(|verdict| verdict.known_failure_review_required)
191        .count();
192    let known_failure_policy_ready = SNAPSHOT_GOVERNANCE_SEEDS
193        .iter()
194        .filter_map(|seed| seed.known_failure.as_ref())
195        .all(|known_failure| {
196            !known_failure.rationale.trim().is_empty()
197                && !known_failure.owner.trim().is_empty()
198                && known_failure.has_expiry_or_review_policy
199        });
200
201    OmenaTestkitSnapshotGovernanceReportV0 {
202        schema_version: "0",
203        product: "omena-testkit.snapshot-governance",
204        fixture_grammar: SNAPSHOT_POLICY.fixture_grammar,
205        policy: SNAPSHOT_POLICY,
206        seed_count: SNAPSHOT_GOVERNANCE_SEEDS.len(),
207        global_disable_rejected: !SNAPSHOT_POLICY.allow_global_disable,
208        unreferenced_reject_ready: rejected_unreferenced_count > 0
209            && SNAPSHOT_POLICY.unreferenced_action == "reject",
210        hot_snapshot_age_audit_ready: hot_snapshot_review_required_count > 0,
211        known_failure_policy_ready,
212        rejected_unreferenced_count,
213        hot_snapshot_review_required_count,
214        known_failure_count,
215        known_failure_review_required_count,
216        verdicts,
217    }
218}
219
220fn snapshot_governance_verdict(
221    seed: &OmenaTestkitSnapshotGovernanceSeedV0,
222) -> OmenaTestkitSnapshotGovernanceVerdictV0 {
223    let rejected_unreferenced =
224        !seed.referenced_by_fixture && SNAPSHOT_POLICY.unreferenced_action == "reject";
225    let hot_snapshot_review_required =
226        seed.hot_snapshot && seed.age_days > SNAPSHOT_POLICY.hot_snapshot_max_age_days;
227    let known_failure_review_required = seed.known_failure.as_ref().is_some_and(|known_failure| {
228        known_failure.age_days > SNAPSHOT_POLICY.known_failure_review_period_days
229    });
230    let known_failure_policy_complete = seed.known_failure.as_ref().is_none_or(|known_failure| {
231        !known_failure.rationale.trim().is_empty()
232            && !known_failure.owner.trim().is_empty()
233            && known_failure.has_expiry_or_review_policy
234    });
235    let action = if rejected_unreferenced {
236        "reject"
237    } else if hot_snapshot_review_required || known_failure_review_required {
238        "review"
239    } else {
240        "accept"
241    };
242
243    OmenaTestkitSnapshotGovernanceVerdictV0 {
244        snapshot_id: seed.snapshot_id,
245        fixture_id: seed.fixture_id,
246        rejected_unreferenced,
247        hot_snapshot_review_required,
248        known_failure_review_required,
249        known_failure_policy_complete,
250        action,
251    }
252}
253
254#[cfg(test)]
255mod tests {
256    use super::*;
257
258    #[test]
259    fn snapshot_governance_rejects_unreferenced_snapshots() {
260        let report = summarize_omena_testkit_snapshot_governance_report();
261
262        assert_eq!(report.product, "omena-testkit.snapshot-governance");
263        assert_eq!(report.fixture_grammar, "omena-fixture-v0");
264        assert!(report.global_disable_rejected);
265        assert!(report.policy.update_requires_review);
266        assert!(report.unreferenced_reject_ready);
267        assert_eq!(report.rejected_unreferenced_count, 1);
268        assert!(
269            report
270                .verdicts
271                .iter()
272                .any(|verdict| verdict.snapshot_id == "orphan-style-facts"
273                    && verdict.rejected_unreferenced
274                    && verdict.action == "reject")
275        );
276    }
277
278    #[test]
279    fn snapshot_governance_audits_hot_snapshots_and_known_failures() {
280        let report = summarize_omena_testkit_snapshot_governance_report();
281
282        assert!(report.hot_snapshot_age_audit_ready);
283        assert_eq!(report.hot_snapshot_review_required_count, 1);
284        assert!(report.known_failure_policy_ready);
285        assert_eq!(report.known_failure_count, 1);
286        assert_eq!(report.known_failure_review_required_count, 1);
287        assert!(report.verdicts.iter().any(|verdict| verdict.snapshot_id
288            == "known-failure-source-rename"
289            && verdict.known_failure_review_required
290            && verdict.known_failure_policy_complete
291            && verdict.action == "review"));
292    }
293}