1use omena_abstract_value::{AbstractCssValueV0, FactPrecision};
10use omena_cascade::{
11 CascadeDeclaration, CascadeLevel, CascadeOriginV0, CascadeOutcome, CascadeProof,
12 ElementSignature, SupportsTargetCapabilityV0,
13};
14use omena_cascade_proof::{
15 CanonicalSmtInputV0, DischargeLedgerLookupStatusV0, DischargeLedgerLookupV0,
16 DischargeLedgerVerdictV0,
17};
18use omena_evidence_graph::{
19 EvidenceDemandEdgeV0, EvidenceGraphBuildErrorV0, EvidenceGraphV0, EvidenceNodeKeyV0,
20 EvidenceNodeSeedV0, GuaranteeFamilyV0, GuaranteeKindV0, build_evidence_graph_from_edges_v0,
21};
22use omena_incremental::{IncrementalComputationPlanV0, IncrementalSnapshotV0};
23use omena_parser::ModuleInstanceKeyV0;
24use omena_transform_cst::{
25 StableNodeKeyV0, TransformBuildProfileV0, TransformDagEdgeV0, TransformPassContractV0,
26 TransformPassDescriptorV0, TransformPassKind, TransformStrictPolicyDescriptorV0,
27 strict_policy_descriptor_for_profile,
28};
29use serde::{Deserialize, Serialize};
30use serde_json::Value;
31
32const TRANSFORM_PASS_OUTCOME_EVIDENCE_QUERY_V0: &str =
33 "omena-transform-passes.transform-pass-execution-outcome";
34const TRANSFORM_PROVENANCE_NODE_EVIDENCE_QUERY_V0: &str =
35 "omena-transform-passes.provenance-derivation-node";
36const TRANSFORM_EVIDENCE_EDGE_KIND_V0: &str = "transform-evidence";
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
39#[serde(rename_all = "camelCase")]
40pub enum TransformPassExecutionStatus {
41 RegistryAndPlannerReady,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
45#[serde(rename_all = "camelCase")]
46pub enum TransformPassDispatchKindV0 {
47 TextLocalSliceRewrite,
48 StructuralIrTransaction,
49 ModuleEvaluationHandler,
50 EmissionBoundary,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
54#[serde(rename_all = "camelCase")]
55pub struct TransformPassRegistryEntryV0 {
56 pub contract: TransformPassContractV0,
57 pub descriptor: TransformPassDescriptorV0,
58 pub module_family: &'static str,
59 pub query_family: &'static str,
60 pub dispatch_kind: TransformPassDispatchKindV0,
61 pub execution_status: TransformPassExecutionStatus,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
65#[serde(rename_all = "camelCase")]
66pub struct TransformPassRegistryV0 {
67 pub schema_version: &'static str,
68 pub product: &'static str,
69 pub entries: Vec<TransformPassRegistryEntryV0>,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
73#[serde(rename_all = "camelCase")]
74pub struct TransformPassesBoundarySummaryV0 {
75 pub schema_version: &'static str,
76 pub product: &'static str,
77 pub registry_entries: Vec<TransformPassRegistryEntryV0>,
78 pub dag_edges: Vec<TransformDagEdgeV0>,
79 pub pass_count: usize,
80 pub full_catalog_registered: bool,
81 pub semantic_aware_pass_count: usize,
82 pub cascade_aware_pass_count: usize,
83 pub structural_pass_count: usize,
84 pub text_local_pass_count: usize,
85 pub module_evaluation_pass_count: usize,
86 pub planner_enforces_dag_edges: bool,
87 pub planner_uses_pass_descriptors: bool,
88 pub ordinal_has_execution_semantics: bool,
89 pub execution_runtime_ready: bool,
90 pub incremental_execution_runtime_ready: bool,
91 pub module_evaluation_native_output_marker: &'static str,
92 pub module_evaluation_requires_native_product_output: bool,
93 pub module_evaluation_requires_oracle_readiness: bool,
94 pub module_evaluation_legacy_output_is_oracle_only: bool,
95 pub module_evaluation_preserves_source_without_native_output: bool,
96 pub implemented_mutation_pass_ids: Vec<&'static str>,
97 pub next_surfaces: Vec<&'static str>,
98}
99
100#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
101#[serde(rename_all = "camelCase")]
102pub struct TransformPassPlanV0 {
103 pub schema_version: &'static str,
104 pub product: &'static str,
105 pub build_profile: TransformBuildProfileV0,
106 pub requested_pass_ids: Vec<&'static str>,
107 pub ordered_pass_ids: Vec<&'static str>,
108 pub satisfied_dag_edge_count: usize,
109 pub violated_dag_edge_count: usize,
110 pub all_requested_registered: bool,
111 pub conflicting_unordered_pass_pairs: Vec<TransformPlanPassConflictV0>,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
115#[serde(rename_all = "camelCase")]
116pub struct TransformPlanPassConflictV0 {
117 pub pass_a: &'static str,
118 pub pass_b: &'static str,
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
122#[serde(rename_all = "camelCase")]
123pub struct TransformStructuralIrShadowFieldReportV0 {
124 pub field: &'static str,
125 pub string_path_values: Vec<String>,
126 pub ir_path_values: Vec<String>,
127 pub typed_path_values: Vec<String>,
128 pub matches: bool,
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
132#[serde(rename_all = "camelCase")]
133pub struct TransformStructuralIrShadowFixtureReportV0 {
134 pub schema_version: &'static str,
135 pub product: &'static str,
136 pub fixture: String,
137 pub pass_id: &'static str,
138 pub dialect: &'static str,
139 pub string_path_mutation_count: Option<usize>,
140 pub ir_path_mutation_count: Option<usize>,
141 pub typed_path_mutation_count: Option<usize>,
142 pub ir_path_transaction_commit_count: Option<u64>,
143 pub typed_payload_projections_consumed: usize,
144 pub typed_payload_memo_hits: usize,
145 pub fields: Vec<TransformStructuralIrShadowFieldReportV0>,
146 pub all_fields_match: bool,
147 pub all_typed_path_fields_match: bool,
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
151#[serde(rename_all = "camelCase")]
152pub struct TransformStructuralIrShadowEquivalenceReportV0 {
153 pub schema_version: &'static str,
154 pub product: &'static str,
155 pub fixture_count: usize,
156 pub compared_pass_ids: Vec<&'static str>,
157 pub compared_fields: Vec<&'static str>,
158 pub reports: Vec<TransformStructuralIrShadowFixtureReportV0>,
159 pub all_fields_match: bool,
160 pub all_typed_path_fields_match: bool,
161 pub typed_payload_projections_consumed: usize,
162 pub typed_payload_memo_hits: usize,
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
166#[serde(rename_all = "camelCase")]
167pub enum TransformPassRuntimeStatus {
168 Applied,
169 NoChange,
170 PlannedOnly,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
174#[serde(rename_all = "camelCase")]
175pub struct TransformPassExecutionOutcomeV0 {
176 pub pass_id: &'static str,
177 pub status: TransformPassRuntimeStatus,
178 pub input_byte_len: usize,
179 pub output_byte_len: usize,
180 pub mutation_count: usize,
181 pub provenance_preserved: bool,
182 pub detail: &'static str,
183}
184
185impl TransformPassExecutionOutcomeV0 {
186 pub fn evidence_node_key(&self) -> EvidenceNodeKeyV0 {
187 EvidenceNodeKeyV0::new(TRANSFORM_PASS_OUTCOME_EVIDENCE_QUERY_V0, self.pass_id)
188 }
189
190 pub fn evidence_node_seed(&self) -> EvidenceNodeSeedV0 {
191 EvidenceNodeSeedV0::new(
192 self.evidence_node_key(),
193 vec![
194 ["pass:", self.pass_id].concat(),
195 ["detail:", self.detail].concat(),
196 ["mutationCount:", self.mutation_count.to_string().as_str()].concat(),
197 [
198 "provenancePreserved:",
199 self.provenance_preserved.to_string().as_str(),
200 ]
201 .concat(),
202 ],
203 GuaranteeKindV0::for_label_less_family(),
204 )
205 }
206
207 pub fn evidence_demand_edge(&self) -> EvidenceDemandEdgeV0 {
208 EvidenceDemandEdgeV0::new(
209 TRANSFORM_PASS_OUTCOME_EVIDENCE_QUERY_V0,
210 self.evidence_node_key(),
211 TRANSFORM_EVIDENCE_EDGE_KIND_V0,
212 )
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
217#[serde(rename_all = "camelCase")]
218pub enum TransformEvaluationProfileV0 {
219 Scss,
220 Less,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
224#[serde(tag = "kind", rename_all = "camelCase")]
225pub enum TransformPreconditionV0 {
226 EvaluatorOutput {
227 profile: TransformEvaluationProfileV0,
228 },
229 ResolvedImportReplacements,
230 CssModulesComposesResolution,
231 DesignTokenRoutes,
232 SelectorIdentity,
233 ClosedStyleWorldBundle,
234 ClosedWorldBundle,
235}
236
237#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
238#[serde(tag = "kind", rename_all = "camelCase")]
239pub enum TransformNoChangeReasonV0 {
240 NoMutation,
241 EmissionBoundary,
242 ProfileNotApplicable {
243 profile: TransformEvaluationProfileV0,
244 },
245 NoMatchingSelectorRewrite,
246 DialectNotApplicable,
247}
248
249#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
250#[serde(
251 tag = "kind",
252 rename_all = "camelCase",
253 rename_all_fields = "camelCase"
254)]
255pub enum TransformBlockedReasonV0 {
256 MissingPrecondition {
257 precondition: TransformPreconditionV0,
258 },
259 PrecisionBelowFloor {
260 required: FactPrecision,
261 observed: FactPrecision,
262 },
263 DischargeMissing {
264 lookup_status: Option<DischargeLedgerLookupStatusV0>,
265 verdict: Option<DischargeLedgerVerdictV0>,
266 },
267 StrictVerification {
268 reasons: Vec<TransformStrictPolicyReasonV0>,
269 },
270 PassImplementation,
271}
272
273#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
274#[serde(tag = "kind", rename_all = "camelCase")]
275pub enum TransformRejectionReasonV0 {
276 IrTransaction {
277 pass: TransformPassKind,
278 },
279 SemanticPreservation,
280 StrictVerification {
281 reasons: Vec<TransformStrictPolicyReasonV0>,
282 },
283}
284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
286#[serde(
287 tag = "kind",
288 rename_all = "camelCase",
289 rename_all_fields = "camelCase"
290)]
291pub enum TransformStructuralDecisionClassV0 {
292 FactConsuming { required_precision: FactPrecision },
293 StaticExact,
294 ObligationDischarge,
295 NonRemovalRewrite,
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
299#[serde(rename_all = "camelCase")]
300pub struct TransformStructuralDecisionPolicyV0 {
301 pub pass: TransformPassKind,
302 pub class: TransformStructuralDecisionClassV0,
303 pub reason: &'static str,
304}
305
306impl TransformStructuralDecisionPolicyV0 {
307 pub const fn new(
308 pass: TransformPassKind,
309 class: TransformStructuralDecisionClassV0,
310 reason: &'static str,
311 ) -> Self {
312 Self {
313 pass,
314 class,
315 reason,
316 }
317 }
318
319 pub const fn required_precision(self) -> Option<FactPrecision> {
320 match self.class {
321 TransformStructuralDecisionClassV0::FactConsuming { required_precision } => {
322 Some(required_precision)
323 }
324 TransformStructuralDecisionClassV0::StaticExact
325 | TransformStructuralDecisionClassV0::ObligationDischarge
326 | TransformStructuralDecisionClassV0::NonRemovalRewrite => None,
327 }
328 }
329}
330
331pub const TRANSFORM_STRUCTURAL_DECISION_POLICIES_V0: &[TransformStructuralDecisionPolicyV0] = &[
332 TransformStructuralDecisionPolicyV0::new(
333 TransformPassKind::ImportInline,
334 TransformStructuralDecisionClassV0::NonRemovalRewrite,
335 "materializes explicitly resolved imports without reachability pruning",
336 ),
337 TransformStructuralDecisionPolicyV0::new(
338 TransformPassKind::ResolveCssModulesComposes,
339 TransformStructuralDecisionClassV0::NonRemovalRewrite,
340 "materializes explicit CSS Modules composition resolution",
341 ),
342 TransformStructuralDecisionPolicyV0::new(
343 TransformPassKind::DesignTokenRouting,
344 TransformStructuralDecisionClassV0::NonRemovalRewrite,
345 "rewrites values through explicit design-token routes",
346 ),
347 TransformStructuralDecisionPolicyV0::new(
348 TransformPassKind::HashCssModuleClassNames,
349 TransformStructuralDecisionClassV0::NonRemovalRewrite,
350 "rewrites selectors through an explicit identity map",
351 ),
352 TransformStructuralDecisionPolicyV0::new(
353 TransformPassKind::RuleDeduplication,
354 TransformStructuralDecisionClassV0::StaticExact,
355 "removes only statically equivalent duplicate rules",
356 ),
357 TransformStructuralDecisionPolicyV0::new(
358 TransformPassKind::RuleMerging,
359 TransformStructuralDecisionClassV0::NonRemovalRewrite,
360 "combines adjacent declarations without reachability pruning",
361 ),
362 TransformStructuralDecisionPolicyV0::new(
363 TransformPassKind::SelectorMerging,
364 TransformStructuralDecisionClassV0::NonRemovalRewrite,
365 "combines equivalent selector blocks without reachability pruning",
366 ),
367 TransformStructuralDecisionPolicyV0::new(
368 TransformPassKind::NestingUnwrap,
369 TransformStructuralDecisionClassV0::NonRemovalRewrite,
370 "expands nested selectors without reachability pruning",
371 ),
372 TransformStructuralDecisionPolicyV0::new(
373 TransformPassKind::ScopeFlatten,
374 TransformStructuralDecisionClassV0::ObligationDischarge,
375 "requires accepted scope-flatten obligations",
376 ),
377 TransformStructuralDecisionPolicyV0::new(
378 TransformPassKind::LayerFlatten,
379 TransformStructuralDecisionClassV0::ObligationDischarge,
380 "requires accepted layer-flatten obligations",
381 ),
382 TransformStructuralDecisionPolicyV0::new(
383 TransformPassKind::SupportsStaticEval,
384 TransformStructuralDecisionClassV0::StaticExact,
385 "removes only statically decided supports branches",
386 ),
387 TransformStructuralDecisionPolicyV0::new(
388 TransformPassKind::MediaStaticEval,
389 TransformStructuralDecisionClassV0::StaticExact,
390 "removes only statically unsatisfiable media branches",
391 ),
392 TransformStructuralDecisionPolicyV0::new(
393 TransformPassKind::ContainerStaticEval,
394 TransformStructuralDecisionClassV0::StaticExact,
395 "removes only statically unsatisfiable container branches",
396 ),
397 TransformStructuralDecisionPolicyV0::new(
398 TransformPassKind::NativeCssStaticEval,
399 TransformStructuralDecisionClassV0::StaticExact,
400 "folds only statically evaluable native CSS expressions",
401 ),
402 TransformStructuralDecisionPolicyV0::new(
403 TransformPassKind::DeadMediaBranchRemoval,
404 TransformStructuralDecisionClassV0::StaticExact,
405 "removes only media branches selected by explicit static policy",
406 ),
407 TransformStructuralDecisionPolicyV0::new(
408 TransformPassKind::DeadSupportsBranchRemoval,
409 TransformStructuralDecisionClassV0::StaticExact,
410 "removes only statically decided supports branches",
411 ),
412 TransformStructuralDecisionPolicyV0::new(
413 TransformPassKind::TreeShakeClass,
414 TransformStructuralDecisionClassV0::FactConsuming {
415 required_precision: FactPrecision::Conservative,
416 },
417 "removes class rules only from a closed-world reachability over-approximation",
418 ),
419 TransformStructuralDecisionPolicyV0::new(
420 TransformPassKind::TreeShakeKeyframes,
421 TransformStructuralDecisionClassV0::FactConsuming {
422 required_precision: FactPrecision::Conservative,
423 },
424 "removes keyframes only from a closed-world reachability over-approximation",
425 ),
426 TransformStructuralDecisionPolicyV0::new(
427 TransformPassKind::TreeShakeValue,
428 TransformStructuralDecisionClassV0::FactConsuming {
429 required_precision: FactPrecision::Conservative,
430 },
431 "removes CSS Modules values only from a closed-world reachability over-approximation",
432 ),
433 TransformStructuralDecisionPolicyV0::new(
434 TransformPassKind::TreeShakeCustomProperty,
435 TransformStructuralDecisionClassV0::FactConsuming {
436 required_precision: FactPrecision::Conservative,
437 },
438 "removes custom properties only from a closed-world reachability over-approximation",
439 ),
440 TransformStructuralDecisionPolicyV0::new(
441 TransformPassKind::EmptyRuleRemoval,
442 TransformStructuralDecisionClassV0::StaticExact,
443 "removes only structurally empty rules",
444 ),
445];
446
447pub fn transform_structural_decision_policy(
448 pass: TransformPassKind,
449) -> Option<&'static TransformStructuralDecisionPolicyV0> {
450 TRANSFORM_STRUCTURAL_DECISION_POLICIES_V0
451 .iter()
452 .find(|policy| policy.pass == pass)
453}
454
455#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
456#[serde(tag = "kind", rename_all = "camelCase")]
457pub enum RollbackScopeV0 {
458 RejectPreservedInput,
459 InversePatch,
460 CommittedIrrecoverable,
461}
462
463#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
464#[serde(rename_all = "camelCase")]
465pub struct RollbackReceiptV0 {
466 pub pass_id: String,
467 pub attempted_mutation_count: Option<usize>,
468 pub input_content_signature: String,
469 #[serde(skip_serializing_if = "Option::is_none")]
470 pub output_preserved_content_signature: Option<String>,
471 pub restorable: RollbackScopeV0,
472}
473
474#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
475#[serde(rename_all = "camelCase")]
476pub struct TransformDischargeEvidenceV0 {
477 pub evidence_node_key: EvidenceNodeKeyV0,
478 pub guarantee_family: GuaranteeFamilyV0,
479 pub ledger_cell_key: String,
480 pub boundedness_kind: String,
481}
482
483#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
488#[serde(rename_all = "camelCase")]
489pub enum TransformWinnerEqualityAxisV0 {
490 CascadeLevel,
491 LayerRank,
492 ScopeProximity,
493 Specificity,
494 SourceOrder,
495}
496
497#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
499#[serde(
500 tag = "kind",
501 rename_all = "camelCase",
502 rename_all_fields = "camelCase"
503)]
504pub enum TransformWinnerEqualityAbsenceReasonV0 {
505 DriverUnavailable { level: Option<CascadeLevel> },
506 AffectedPairUnavailable,
507 SpecificityInexact,
508 WinnerNotDefinite,
509 WinnerChanged,
510}
511
512#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
514#[serde(rename_all = "camelCase")]
515pub struct TransformWinnerEqualityAbsenceV0 {
516 pub axis: TransformWinnerEqualityAxisV0,
517 pub reason: TransformWinnerEqualityAbsenceReasonV0,
518}
519
520#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
522#[serde(rename_all = "camelCase")]
523pub struct TransformWinnerEqualityAffectedPairV0 {
524 pub element_signature: ElementSignature,
525 pub property: String,
526}
527
528#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
533#[serde(rename_all = "camelCase")]
534pub struct TransformWinnerEqualityWitnessV0 {
535 pub winner: CascadeDeclaration,
536 pub proof: CascadeProof,
537}
538
539impl TransformWinnerEqualityWitnessV0 {
540 pub fn from_cascade_outcome(outcome: &CascadeOutcome) -> Option<Self> {
541 match outcome {
542 CascadeOutcome::Definite { winner, proof, .. } => Some(Self {
543 winner: winner.clone(),
544 proof: proof.as_ref().clone(),
545 }),
546 CascadeOutcome::RankedSet(_) | CascadeOutcome::Inherit | CascadeOutcome::Top => None,
547 }
548 }
549}
550
551#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
553#[serde(
554 tag = "kind",
555 rename_all = "camelCase",
556 rename_all_fields = "camelCase"
557)]
558pub enum TransformWinnerEqualityObservationV0 {
559 ObservedEqual {
560 axes: Vec<TransformWinnerEqualityAxisV0>,
561 input: TransformWinnerEqualityWitnessV0,
562 output: TransformWinnerEqualityWitnessV0,
563 },
564 ObservedDifferent {
565 axes: Vec<TransformWinnerEqualityAxisV0>,
566 input: TransformWinnerEqualityWitnessV0,
567 output: TransformWinnerEqualityWitnessV0,
568 },
569 Absent {
570 reasons: Vec<TransformWinnerEqualityAbsenceV0>,
571 },
572}
573
574#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
576#[serde(rename_all = "camelCase")]
577pub struct TransformWinnerEqualityObligationV0 {
578 pub pass_id: &'static str,
579 pub affected_pair: TransformWinnerEqualityAffectedPairV0,
580 pub observation: TransformWinnerEqualityObservationV0,
581}
582
583#[derive(Debug, Clone, Default, PartialEq, Eq)]
584pub struct TransformExecutionPolicyV0 {
585 pub strict_policy: Option<TransformStrictPolicyDescriptorV0>,
586}
587
588impl TransformExecutionPolicyV0 {
589 pub fn for_profile(profile_id: &str) -> Option<Self> {
590 strict_policy_descriptor_for_profile(profile_id).map(|strict_policy| Self {
591 strict_policy: Some(strict_policy),
592 })
593 }
594}
595
596#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
597#[serde(
598 tag = "kind",
599 rename_all = "camelCase",
600 rename_all_fields = "camelCase"
601)]
602pub enum TransformStrictPolicyReasonV0 {
603 RequiredAxisUnavailable {
604 axis: TransformWinnerEqualityAxisV0,
605 },
606 CascadeEnvironmentUnavailable,
607 WinnerChanged {
608 axes: Vec<TransformWinnerEqualityAxisV0>,
609 },
610 ObservationUnavailable {
611 reasons: Vec<TransformWinnerEqualityAbsenceV0>,
612 },
613 UnknownPass,
614 ClosedWorldEvidenceUnavailable,
615 DecisionCoverageIncomplete,
616}
617
618#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
619#[serde(rename_all = "camelCase")]
620pub struct TransformStrictPolicyEventV0 {
621 pub pass_id: String,
622 pub reasons: Vec<TransformStrictPolicyReasonV0>,
623}
624
625#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
626#[serde(rename_all = "camelCase")]
627pub struct TransformStrictPolicySummaryV0 {
628 pub profile_id: Option<String>,
629 pub refused_count: usize,
630 pub rolled_back_count: usize,
631 pub refusal_reasons: Vec<TransformStrictPolicyEventV0>,
632 pub rollback_reasons: Vec<TransformStrictPolicyEventV0>,
633}
634
635impl TransformStrictPolicySummaryV0 {
636 pub fn for_profile(profile_id: &str) -> Self {
637 Self {
638 profile_id: Some(profile_id.to_string()),
639 ..Self::default()
640 }
641 }
642
643 pub fn record_refusal(
644 &mut self,
645 pass_id: impl Into<String>,
646 reasons: Vec<TransformStrictPolicyReasonV0>,
647 ) {
648 self.refusal_reasons.push(TransformStrictPolicyEventV0 {
649 pass_id: pass_id.into(),
650 reasons,
651 });
652 self.refused_count = self.refusal_reasons.len();
653 }
654
655 pub fn record_rollback(
656 &mut self,
657 pass_id: impl Into<String>,
658 reasons: Vec<TransformStrictPolicyReasonV0>,
659 ) {
660 self.rollback_reasons.push(TransformStrictPolicyEventV0 {
661 pass_id: pass_id.into(),
662 reasons,
663 });
664 self.rolled_back_count = self.rollback_reasons.len();
665 }
666}
667
668#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
675#[serde(
676 tag = "kind",
677 rename_all = "camelCase",
678 rename_all_fields = "camelCase"
679)]
680pub enum TransformSemanticGuaranteeTierV0 {
681 L0Observed,
682 WinnerEqualityObserved {
683 axes: Vec<TransformWinnerEqualityAxisV0>,
684 },
685 Absent {
686 reasons: Vec<TransformWinnerEqualityAbsenceV0>,
687 },
688}
689
690impl RollbackReceiptV0 {
691 pub fn preserves_rejected_input(&self) -> bool {
692 self.restorable == RollbackScopeV0::RejectPreservedInput
693 && self.output_preserved_content_signature.as_deref()
694 == Some(self.input_content_signature.as_str())
695 }
696
697 pub fn covers_inverse_patch(
698 &self,
699 inverse_patch_count: usize,
700 input_content_signature: &str,
701 ) -> bool {
702 self.restorable == RollbackScopeV0::InversePatch
703 && self.attempted_mutation_count == Some(inverse_patch_count)
704 && self.input_content_signature == input_content_signature
705 && self.output_preserved_content_signature.is_none()
706 }
707}
708
709#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
710#[serde(
711 tag = "kind",
712 rename_all = "camelCase",
713 rename_all_fields = "camelCase"
714)]
715pub enum TransformDecision {
716 Applied {
717 outcome: TransformPassExecutionOutcomeV0,
718 rollback_receipt: RollbackReceiptV0,
719 #[serde(skip_serializing_if = "Option::is_none")]
720 semantic_guarantee_tier: Option<TransformSemanticGuaranteeTierV0>,
721 #[serde(skip_serializing_if = "Vec::is_empty")]
722 discharge_evidence: Vec<TransformDischargeEvidenceV0>,
723 },
724 NoChange {
725 reason: TransformNoChangeReasonV0,
726 outcome: TransformPassExecutionOutcomeV0,
727 },
728 Blocked {
729 reason: TransformBlockedReasonV0,
730 outcome: TransformPassExecutionOutcomeV0,
731 },
732 Rejected {
733 reason: TransformRejectionReasonV0,
734 outcome: TransformPassExecutionOutcomeV0,
735 rollback_receipt: RollbackReceiptV0,
736 },
737}
738
739impl TransformDecision {
740 pub fn compatibility_outcome(&self) -> &TransformPassExecutionOutcomeV0 {
741 match self {
742 Self::Applied { outcome, .. }
743 | Self::NoChange { outcome, .. }
744 | Self::Blocked { outcome, .. }
745 | Self::Rejected { outcome, .. } => outcome,
746 }
747 }
748
749 pub fn into_compatibility_outcome(self) -> TransformPassExecutionOutcomeV0 {
750 match self {
751 Self::Applied { outcome, .. }
752 | Self::NoChange { outcome, .. }
753 | Self::Blocked { outcome, .. }
754 | Self::Rejected { outcome, .. } => outcome,
755 }
756 }
757
758 pub fn rollback_receipt(&self) -> Option<&RollbackReceiptV0> {
759 match self {
760 Self::Applied {
761 rollback_receipt, ..
762 }
763 | Self::Rejected {
764 rollback_receipt, ..
765 } => Some(rollback_receipt),
766 Self::NoChange { .. } | Self::Blocked { .. } => None,
767 }
768 }
769
770 pub fn semantic_guarantee_tier(&self) -> Option<&TransformSemanticGuaranteeTierV0> {
771 match self {
772 Self::Applied {
773 semantic_guarantee_tier,
774 ..
775 } => semantic_guarantee_tier.as_ref(),
776 Self::NoChange { .. } | Self::Blocked { .. } | Self::Rejected { .. } => None,
777 }
778 }
779}
780
781#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
782#[serde(rename_all = "camelCase")]
783pub struct TransformProvenanceDerivationForestV0 {
784 pub schema_version: &'static str,
785 pub product: &'static str,
786 pub root_count: usize,
787 pub node_count: usize,
788 pub nodes: Vec<TransformProvenanceDerivationNodeV0>,
789}
790
791impl TransformProvenanceDerivationForestV0 {
792 pub fn evidence_graph(&self) -> Result<EvidenceGraphV0, EvidenceGraphBuildErrorV0> {
793 build_evidence_graph_from_edges_v0(
794 self.nodes
795 .iter()
796 .map(TransformProvenanceDerivationNodeV0::evidence_node_seed),
797 self.nodes
798 .iter()
799 .map(TransformProvenanceDerivationNodeV0::evidence_demand_edge),
800 )
801 }
802}
803
804#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
805#[serde(rename_all = "camelCase")]
806pub struct TransformProvenanceDerivationNodeV0 {
807 pub node_index: usize,
808 pub parent_index: Option<usize>,
809 pub pass_id: &'static str,
810 pub status: TransformPassRuntimeStatus,
811 pub input_byte_len: usize,
812 pub output_byte_len: usize,
813 pub source_span_start: usize,
814 pub source_span_end: usize,
815 pub generated_span_start: usize,
816 pub generated_span_end: usize,
817 pub mutation_spans: Vec<TransformProvenanceMutationSpanV0>,
818 pub mutation_count: usize,
819 pub provenance_preserved: bool,
820 pub detail: &'static str,
821}
822
823impl TransformProvenanceDerivationNodeV0 {
824 pub fn evidence_node_key(&self) -> EvidenceNodeKeyV0 {
825 EvidenceNodeKeyV0::new(
826 TRANSFORM_PROVENANCE_NODE_EVIDENCE_QUERY_V0,
827 format!("{}#{}", self.pass_id, self.node_index),
828 )
829 }
830
831 pub fn evidence_node_seed(&self) -> EvidenceNodeSeedV0 {
832 EvidenceNodeSeedV0::new(
833 self.evidence_node_key(),
834 vec![
835 ["pass:", self.pass_id].concat(),
836 ["detail:", self.detail].concat(),
837 ["mutationCount:", self.mutation_count.to_string().as_str()].concat(),
838 [
839 "provenancePreserved:",
840 self.provenance_preserved.to_string().as_str(),
841 ]
842 .concat(),
843 ],
844 GuaranteeKindV0::for_label_less_family(),
845 )
846 }
847
848 pub fn evidence_demand_edge(&self) -> EvidenceDemandEdgeV0 {
849 EvidenceDemandEdgeV0::new(
850 TRANSFORM_PROVENANCE_NODE_EVIDENCE_QUERY_V0,
851 self.evidence_node_key(),
852 TRANSFORM_EVIDENCE_EDGE_KIND_V0,
853 )
854 }
855}
856
857#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
858#[serde(rename_all = "camelCase")]
859pub struct TransformProvenanceMutationSpanV0 {
860 pub source_span_start: usize,
861 pub source_span_end: usize,
862 pub generated_span_start: usize,
863 pub generated_span_end: usize,
864 #[serde(skip_serializing_if = "Option::is_none")]
865 pub node_key: Option<StableNodeKeyV0>,
866}
867
868#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize)]
873#[serde(rename_all = "camelCase")]
874pub struct TransformLexCacheSpliceTelemetryV0 {
875 pub splice_hit_count: u64,
877 pub full_relex_fallback_count: u64,
879 pub window_derivation_fallback_count: u64,
881 pub full_output_window_fallback_count: u64,
883 pub token_offset_fallback_count: u64,
885}
886
887#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize)]
890#[serde(rename_all = "camelCase")]
891pub struct TransformStructuralIrTransactionTelemetryV0 {
892 pub transaction_commit_count: u64,
893}
894
895#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
896#[serde(rename_all = "camelCase")]
897pub enum TransformSemanticObservationKeyAxisV0 {
898 Selector,
899 Property,
900 Context,
901}
902
903#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
904#[serde(rename_all = "camelCase")]
905pub enum TransformSemanticObservationValueAxisV0 {
906 Value,
907 Important,
908}
909
910#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
911#[serde(rename_all = "camelCase")]
912pub enum TransformSemanticObservationOrderingRuleV0 {
913 SourceOrder,
914 ImportantPrecedence,
915}
916
917#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
918#[serde(rename_all = "camelCase")]
919pub enum TransformSemanticUnobservedAxisV0 {
920 InterSelectorSpecificityCompetition,
921 CascadeLayerOrder,
922 Origin,
923 ScopeProximity,
924 DomDependentMatching,
925 Inheritance,
926 CustomPropertyEnvironment,
927 AnimationAndTransition,
928}
929
930#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
931#[serde(rename_all = "camelCase")]
932pub enum TransformSemanticPreservationClaimScopeV0 {
933 ObservedSurfaceOnly,
934}
935
936#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
937#[serde(rename_all = "camelCase")]
938pub enum TransformSemanticPreservationVocabularyReviewV0 {
939 DeferredUntilFullCascadeObservation,
940}
941
942#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
944#[serde(rename_all = "camelCase")]
945pub struct TransformSemanticObservationSurfaceV0 {
946 pub key_axes: Vec<TransformSemanticObservationKeyAxisV0>,
947 pub value_axes: Vec<TransformSemanticObservationValueAxisV0>,
948 pub ordering_rules: Vec<TransformSemanticObservationOrderingRuleV0>,
949 pub unobserved_axes: Vec<TransformSemanticUnobservedAxisV0>,
950 pub claim_scope: TransformSemanticPreservationClaimScopeV0,
951 pub vocabulary_review: TransformSemanticPreservationVocabularyReviewV0,
952}
953
954#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
955#[serde(rename_all = "camelCase")]
956pub struct TransformSemanticPreservationTelemetryV0 {
957 pub observed_pass_count: u64,
958 pub preserved_pass_count: u64,
959 pub blocked_pass_count: u64,
960 pub observed_surface: TransformSemanticObservationSurfaceV0,
961}
962
963#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
964#[serde(rename_all = "camelCase")]
965pub struct TransformDischargeLedgerTelemetryV0 {
966 pub lookup_count: u64,
967 pub matched_lookup_count: u64,
968 pub accepted_stamp_count: u64,
969 pub blocked_lookup_count: u64,
970}
971
972#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
973#[serde(rename_all = "camelCase")]
974pub struct TransformExecutionSummaryV0 {
975 pub schema_version: &'static str,
976 pub product: &'static str,
977 pub input_byte_len: usize,
978 pub output_byte_len: usize,
979 pub requested_pass_ids: Vec<&'static str>,
980 pub ordered_pass_ids: Vec<&'static str>,
981 pub executed_pass_ids: Vec<&'static str>,
982 pub planned_only_pass_ids: Vec<&'static str>,
983 pub mutation_count: usize,
984 pub provenance_preserved: bool,
985 pub output_css: String,
986 pub css_module_evaluation: Option<TransformModuleEvaluationV0>,
987 pub css_import_inlines: Vec<TransformImportInlineV0>,
988 pub css_module_composes_exports: Vec<TransformCssModuleComposesResolutionV0>,
989 pub design_token_routes: Vec<TransformDesignTokenRouteV0>,
990 pub semantic_removals: Vec<TransformSemanticRemovalV0>,
991 #[serde(skip_serializing_if = "Option::is_none")]
992 pub module_qualified_shake: Option<TransformModuleQualifiedShakeSummaryV0>,
993 pub cascade_proof_obligations: TransformCascadeProofObligationReportV0,
994 #[serde(skip_serializing_if = "Vec::is_empty")]
995 pub winner_equality_obligations: Vec<TransformWinnerEqualityObligationV0>,
996 pub provenance_derivation_forest: TransformProvenanceDerivationForestV0,
997 pub structural_ir_transaction_telemetry: TransformStructuralIrTransactionTelemetryV0,
998 pub semantic_preservation_telemetry: TransformSemanticPreservationTelemetryV0,
999 pub discharge_ledger_telemetry: TransformDischargeLedgerTelemetryV0,
1000 pub strict_policy: TransformStrictPolicySummaryV0,
1001 pub decisions: Vec<TransformDecision>,
1002 pub outcomes: Vec<TransformPassExecutionOutcomeV0>,
1003 pub pass_plan: TransformPassPlanV0,
1004}
1005
1006#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1007#[serde(rename_all = "camelCase")]
1008pub struct TransformModuleQualifiedShakeSummaryV0 {
1009 pub module_instance: ModuleInstanceKeyV0,
1010 pub removed_count: usize,
1011}
1012
1013#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1014#[serde(
1015 tag = "kind",
1016 rename_all = "camelCase",
1017 rename_all_fields = "camelCase"
1018)]
1019pub enum TransformModuleQualifiedExecutionErrorV0 {
1020 UnknownModuleInstance {
1021 module_instance: ModuleInstanceKeyV0,
1022 },
1023}
1024
1025#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1026#[serde(rename_all = "camelCase")]
1027pub struct TransformCascadeProofObligationReportV0 {
1028 pub schema_version: &'static str,
1029 pub product: &'static str,
1030 pub obligation_count: usize,
1031 pub accepted_count: usize,
1032 pub blocked_count: usize,
1033 pub checked_pass_ids: Vec<&'static str>,
1034 pub obligations: Vec<TransformCascadeProofObligationV0>,
1035}
1036
1037#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1038#[serde(rename_all = "camelCase")]
1039pub struct TransformCascadeProofObligationV0 {
1040 pub pass_id: &'static str,
1041 pub proof_product: &'static str,
1042 pub accepted: bool,
1043 pub blocked_reason: Option<String>,
1044 pub provenance_preserved: bool,
1045 pub cascade_safe_witness: String,
1046 pub source_span_start: Option<usize>,
1047 pub source_span_end: Option<usize>,
1048 pub checked_obligations: Vec<&'static str>,
1049 #[serde(skip_serializing_if = "Option::is_none")]
1050 pub canonical_smt_input: Option<CanonicalSmtInputV0>,
1051 #[serde(skip_serializing_if = "Option::is_none")]
1052 pub discharge_ledger_lookup: Option<DischargeLedgerLookupV0>,
1053 #[serde(skip_serializing_if = "Option::is_none")]
1054 pub discharge_evidence: Option<TransformDischargeEvidenceV0>,
1055 pub proof_payload: Value,
1056}
1057
1058#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1059#[serde(rename_all = "camelCase")]
1060pub struct TransformSemanticRemovalV0 {
1061 pub pass_id: &'static str,
1062 pub symbol_kind: &'static str,
1063 pub name: String,
1064 pub source_span_start: usize,
1065 pub source_span_end: usize,
1066 pub reason: &'static str,
1067 pub certainty: &'static str,
1068 pub derivation_steps: Vec<&'static str>,
1069}
1070
1071#[derive(Debug, Clone, PartialEq, Eq)]
1072pub(crate) struct TransformSemanticRemovalCandidate {
1073 pub(crate) symbol_kind: &'static str,
1074 pub(crate) name: String,
1075 pub(crate) source_span_start: usize,
1076 pub(crate) source_span_end: usize,
1077 pub(crate) reason: &'static str,
1078}
1079
1080impl TransformSemanticRemovalCandidate {
1081 pub(crate) fn into_public(self, pass_id: &'static str) -> TransformSemanticRemovalV0 {
1082 TransformSemanticRemovalV0 {
1083 pass_id,
1084 symbol_kind: self.symbol_kind,
1085 name: self.name,
1086 source_span_start: self.source_span_start,
1087 source_span_end: self.source_span_end,
1088 reason: self.reason,
1089 certainty: "high",
1090 derivation_steps: vec![
1091 "closedStyleWorld",
1092 "reachableRootSetComputed",
1093 "symbolNotMarkedReachable",
1094 "sourceRangeRemoved",
1095 ],
1096 }
1097 }
1098}
1099
1100#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1101#[serde(rename_all = "camelCase")]
1102pub struct TransformIncrementalExecutionSummaryV0 {
1103 pub schema_version: &'static str,
1104 pub product: &'static str,
1105 pub incremental_engine: &'static str,
1106 pub query_model: &'static str,
1107 pub reuse_policy: &'static str,
1108 pub reused_previous_execution: bool,
1109 pub incremental_plan: IncrementalComputationPlanV0,
1110 pub next_snapshot: IncrementalSnapshotV0,
1111 pub execution: TransformExecutionSummaryV0,
1112 pub ready_surfaces: Vec<&'static str>,
1113}
1114
1115#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1116#[serde(rename_all = "camelCase")]
1117pub struct TransformCascadeSafetyFuzzCaseV0 {
1118 pub seed: u64,
1119 pub pass_count: usize,
1120}
1121
1122#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1123#[serde(rename_all = "camelCase")]
1124pub struct TransformCascadeSafetyFuzzResultV0 {
1125 pub seed: u64,
1126 pub pass_count: usize,
1127 pub requested_pass_ids: Vec<&'static str>,
1128 pub executed_pass_ids: Vec<&'static str>,
1129 pub output_byte_len: usize,
1130 pub output_token_count: usize,
1131 pub output_error_count: usize,
1132 pub provenance_node_count: usize,
1133 pub passed: bool,
1134}
1135
1136#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1137#[serde(rename_all = "camelCase")]
1138pub struct TransformFuzzSeedReportV0 {
1139 pub schema_version: &'static str,
1140 pub product: &'static str,
1141 pub case_count: usize,
1142 pub passed_count: usize,
1143 pub failed_count: usize,
1144 pub results: Vec<TransformCascadeSafetyFuzzResultV0>,
1145}
1146
1147#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
1148#[serde(default, rename_all = "camelCase")]
1149pub struct TransformExecutionContextV0 {
1150 pub drop_dark_mode_media_queries: bool,
1151 pub supports_target_capability: Option<SupportsTargetCapabilityV0>,
1152 pub vendor_prefix_policy: Option<TransformVendorPrefixPolicyV0>,
1153 pub reachable_class_names: Vec<String>,
1154 pub reachable_keyframe_names: Vec<String>,
1155 pub reachable_value_names: Vec<String>,
1156 pub reachable_custom_property_names: Vec<String>,
1157 pub scss_module_evaluation: Option<TransformModuleEvaluationV0>,
1158 pub less_module_evaluation: Option<TransformModuleEvaluationV0>,
1159 pub import_inlines: Vec<TransformImportInlineV0>,
1160 pub class_name_rewrites: Vec<TransformClassNameRewriteV0>,
1161 pub css_module_composes_resolutions: Vec<TransformCssModuleComposesResolutionV0>,
1162 pub css_module_value_resolutions: Vec<TransformCssModuleValueResolutionV0>,
1163 pub design_token_routes: Vec<TransformDesignTokenRouteV0>,
1164 #[serde(default, skip_serializing_if = "Option::is_none")]
1167 pub cascade_environment: Option<TransformCascadeEnvironmentV0>,
1168}
1169
1170#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
1171#[serde(default, rename_all = "camelCase")]
1172pub struct TransformCascadeEnvironmentV0 {
1173 pub stylesheet_source_order_base: u32,
1176 pub declarations: Vec<TransformCascadeEnvironmentDeclarationV0>,
1177}
1178
1179#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1180#[serde(rename_all = "camelCase")]
1181pub struct TransformCascadeEnvironmentDeclarationV0 {
1182 pub declaration_id: String,
1183 pub selector: String,
1184 pub property: String,
1185 pub value: String,
1186 pub origin: CascadeOriginV0,
1187 pub important: bool,
1188 #[serde(default, skip_serializing_if = "Option::is_none")]
1189 pub layer_rank: Option<i32>,
1190 #[serde(default, skip_serializing_if = "Option::is_none")]
1191 pub scope_proximity: Option<u32>,
1192 pub source_order: u32,
1193}
1194
1195#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
1196#[serde(rename_all = "camelCase")]
1197pub struct TransformVendorPrefixPolicyV0 {
1198 pub webkit: bool,
1199 pub moz: bool,
1200 pub ms: bool,
1201}
1202
1203impl TransformVendorPrefixPolicyV0 {
1204 pub const fn none() -> Self {
1205 Self {
1206 webkit: false,
1207 moz: false,
1208 ms: false,
1209 }
1210 }
1211
1212 pub const fn conservative() -> Self {
1213 Self {
1214 webkit: true,
1215 moz: true,
1216 ms: true,
1217 }
1218 }
1219
1220 pub const fn is_empty(self) -> bool {
1221 !(self.webkit || self.moz || self.ms)
1222 }
1223
1224 pub fn allows_prefix(self, prefixed_name: &str) -> bool {
1225 if prefixed_name.starts_with("-webkit-") {
1226 return self.webkit;
1227 }
1228 if prefixed_name.starts_with("-moz-") {
1229 return self.moz;
1230 }
1231 if prefixed_name.starts_with("-ms-") {
1232 return self.ms;
1233 }
1234 true
1235 }
1236}
1237
1238#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1239#[serde(rename_all = "camelCase")]
1240pub struct TransformModuleEvaluationV0 {
1241 pub evaluator: String,
1242 #[serde(default, skip_serializing_if = "Option::is_none")]
1243 pub product_output_source: Option<String>,
1244 pub evaluated_css: String,
1245 #[serde(default, skip_serializing_if = "Option::is_none")]
1246 pub native_edit_output: Option<String>,
1247 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1248 pub native_replacements: Vec<TransformModuleEvaluationNativeReplacementV0>,
1249 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1250 pub native_edits: Vec<TransformModuleEvaluationNativeEditV0>,
1251 #[serde(default, skip_serializing_if = "Option::is_none")]
1252 pub oracle: Option<TransformModuleEvaluationOracleV0>,
1253}
1254
1255impl TransformModuleEvaluationV0 {
1256 pub fn declares_native_product_output(&self) -> bool {
1257 self.product_output_source
1258 .as_deref()
1259 .is_some_and(|source| source == "nativeEditOutput")
1260 }
1261
1262 pub fn oracle_allows_native_product_output(&self) -> bool {
1271 self.oracle.as_ref().is_some_and(|oracle| {
1272 oracle.mode == "oracleOnly"
1273 && oracle.divergence_count == 0
1274 && oracle.all_legacy_declaration_values_preserved
1275 })
1276 }
1277
1278 pub fn may_consume_native_product_output(&self) -> bool {
1279 self.declares_native_product_output() && self.oracle_allows_native_product_output()
1280 }
1281
1282 pub fn native_output_matches_retained_oracle(&self, native_output: &str) -> bool {
1287 self.oracle
1288 .as_ref()
1289 .is_some_and(|_| native_output == self.evaluated_css)
1290 }
1291}
1292
1293#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1294#[serde(rename_all = "camelCase")]
1295pub struct TransformModuleEvaluationNativeReplacementV0 {
1296 pub name: String,
1297 pub start: usize,
1298 pub end: usize,
1299 pub text: String,
1300 #[serde(default, skip_serializing_if = "Option::is_none")]
1301 pub rendered_value: Option<String>,
1302 pub abstract_value: AbstractCssValueV0,
1303 pub abstract_value_kind: String,
1304}
1305
1306#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1307#[serde(rename_all = "camelCase")]
1308pub struct TransformModuleEvaluationNativeEditV0 {
1309 pub start: usize,
1310 pub end: usize,
1311 pub replacement: String,
1312 pub edit_kind: String,
1313 #[serde(default, skip_serializing_if = "Option::is_none")]
1314 pub abstract_value: Option<AbstractCssValueV0>,
1315 #[serde(default, skip_serializing_if = "Option::is_none")]
1316 pub abstract_value_kind: Option<String>,
1317}
1318
1319#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
1320#[serde(default, rename_all = "camelCase")]
1321pub struct TransformModuleEvaluationOracleV0 {
1322 pub mode: String,
1323 pub product_output_source: String,
1324 pub legacy_declaration_value_count: usize,
1325 pub abstract_value_count: usize,
1326 pub exact_value_count: usize,
1327 pub raw_value_count: usize,
1328 pub bottom_value_count: usize,
1329 pub top_value_count: usize,
1330 pub divergence_count: usize,
1331 pub all_legacy_declaration_values_preserved: bool,
1332 pub native_replacement_count: usize,
1333 pub native_replacement_legacy_reflection_count: usize,
1334 pub native_replacement_legacy_unreflected_count: usize,
1335 pub native_value_reference_count: usize,
1336 pub native_resolved_value_count: usize,
1337 pub native_raw_value_count: usize,
1338 pub native_top_value_count: usize,
1339 pub native_cycle_count: usize,
1340 pub native_fuel_exhausted_count: usize,
1341 pub native_unresolved_reference_count: usize,
1342 pub native_unsupported_dynamic_count: usize,
1343}
1344
1345#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1346#[serde(rename_all = "camelCase")]
1347pub struct TransformImportInlineV0 {
1348 pub import_source: String,
1349 pub replacement_css: String,
1350}
1351
1352#[derive(Debug, Clone, PartialEq, Eq)]
1353pub struct TransformLessInlineLiteralPlaceholderV0 {
1354 pub placeholder: String,
1355 pub literal_css: String,
1356}
1357
1358#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1359#[serde(rename_all = "camelCase")]
1360pub struct TransformClassNameRewriteV0 {
1361 pub original_name: String,
1362 pub rewritten_name: String,
1363}
1364
1365#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1366#[serde(rename_all = "camelCase")]
1367pub struct TransformCssModuleComposesResolutionV0 {
1368 pub local_class_name: String,
1369 pub exported_class_names: Vec<String>,
1370}
1371
1372#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1373#[serde(rename_all = "camelCase")]
1374pub struct TransformCssModuleValueResolutionV0 {
1375 pub local_name: String,
1376 pub resolved_value: String,
1377}
1378
1379#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1380#[serde(rename_all = "camelCase")]
1381pub struct TransformDesignTokenRouteV0 {
1382 pub token_name: String,
1383 pub routed_value: String,
1384}
1385
1386#[cfg(test)]
1387mod evidence_graph_tests {
1388 use super::*;
1389 use omena_cascade::{
1390 CascadeKey, CascadeValue, LayerRank, ModuleRank, Specificity, cascade_property,
1391 };
1392
1393 fn winner_equality_test_declaration(
1394 id: &str,
1395 value: &str,
1396 source_order: u32,
1397 ) -> CascadeDeclaration {
1398 CascadeDeclaration {
1399 id: id.to_string(),
1400 property: "color".to_string(),
1401 value: CascadeValue::Literal(value.to_string()),
1402 key: CascadeKey::new(
1403 CascadeLevel::AuthorNormal,
1404 LayerRank(0),
1405 0,
1406 Specificity::new(0, 1, 0),
1407 ModuleRank::ZERO,
1408 source_order,
1409 ),
1410 specificity_exactness: omena_cascade::SpecificityExactnessV0::Exact,
1411 }
1412 }
1413
1414 #[test]
1415 fn winner_equality_witness_consumes_the_cascade_authority_outcome() -> Result<(), String> {
1416 let outcome = cascade_property(
1417 [
1418 winner_equality_test_declaration("earlier", "red", 0),
1419 winner_equality_test_declaration("later", "blue", 1),
1420 ],
1421 "color",
1422 );
1423 let witness = TransformWinnerEqualityWitnessV0::from_cascade_outcome(&outcome)
1424 .ok_or_else(|| "the closed cascade should have a definite winner".to_string())?;
1425
1426 assert_eq!(witness.winner.id, "later");
1427 assert_eq!(
1428 witness.proof,
1429 CascadeProof::from_declaration(&witness.winner)
1430 );
1431 Ok(())
1432 }
1433
1434 #[test]
1435 fn winner_equality_witness_stays_absent_for_non_definite_outcomes() {
1436 assert!(
1437 TransformWinnerEqualityWitnessV0::from_cascade_outcome(&CascadeOutcome::Top).is_none()
1438 );
1439 assert!(
1440 TransformWinnerEqualityWitnessV0::from_cascade_outcome(&CascadeOutcome::Inherit)
1441 .is_none()
1442 );
1443 }
1444
1445 #[test]
1446 fn winner_equality_trust_records_name_covered_axes() -> Result<(), serde_json::Error> {
1447 let tier = TransformSemanticGuaranteeTierV0::WinnerEqualityObserved {
1448 axes: vec![
1449 TransformWinnerEqualityAxisV0::CascadeLevel,
1450 TransformWinnerEqualityAxisV0::LayerRank,
1451 ],
1452 };
1453
1454 assert_eq!(
1455 serde_json::to_value(tier)?,
1456 serde_json::json!({
1457 "kind": "winnerEqualityObserved",
1458 "axes": ["cascadeLevel", "layerRank"]
1459 })
1460 );
1461 Ok(())
1462 }
1463
1464 #[test]
1465 fn winner_equality_absence_names_the_undriven_level() -> Result<(), serde_json::Error> {
1466 let tier = TransformSemanticGuaranteeTierV0::Absent {
1467 reasons: vec![TransformWinnerEqualityAbsenceV0 {
1468 axis: TransformWinnerEqualityAxisV0::CascadeLevel,
1469 reason: TransformWinnerEqualityAbsenceReasonV0::DriverUnavailable {
1470 level: Some(CascadeLevel::Animation),
1471 },
1472 }],
1473 };
1474
1475 assert_eq!(
1476 serde_json::to_value(tier)?,
1477 serde_json::json!({
1478 "kind": "absent",
1479 "reasons": [{
1480 "axis": "cascadeLevel",
1481 "reason": {
1482 "kind": "driverUnavailable",
1483 "level": "animation"
1484 }
1485 }]
1486 })
1487 );
1488 Ok(())
1489 }
1490
1491 #[test]
1492 fn transform_outcome_evidence_graph_preserves_public_shape() -> Result<(), serde_json::Error> {
1493 let outcome = TransformPassExecutionOutcomeV0 {
1494 pass_id: "number-compression",
1495 status: TransformPassRuntimeStatus::Applied,
1496 input_byte_len: 32,
1497 output_byte_len: 28,
1498 mutation_count: 1,
1499 provenance_preserved: true,
1500 detail: "fixture pass",
1501 };
1502
1503 let before = serde_json::to_value(&outcome)?;
1504 let node = outcome.evidence_node_seed();
1505 let graph = build_evidence_graph_from_edges_v0([node], [outcome.evidence_demand_edge()])
1506 .map_err(|_| serde::ser::Error::custom("outcome edge must target its node"))?;
1507 let after = serde_json::to_value(&outcome)?;
1508
1509 assert_eq!(before, after);
1510 assert_eq!(graph.nodes.len(), 1);
1511 assert_eq!(graph.nodes[0].key.input_identity, "number-compression");
1512 assert_eq!(graph.nodes[0].guarantee, GuaranteeKindV0::Floor);
1513 assert!(
1514 graph.nodes[0]
1515 .provenance
1516 .iter()
1517 .any(|item| item == "mutationCount:1")
1518 );
1519 Ok(())
1520 }
1521
1522 #[test]
1523 fn transform_derivation_forest_evidence_graph_preserves_public_shape()
1524 -> Result<(), serde_json::Error> {
1525 let forest = TransformProvenanceDerivationForestV0 {
1526 schema_version: "0",
1527 product: "omena-transform-passes.provenance-derivation-forest",
1528 root_count: 1,
1529 node_count: 1,
1530 nodes: vec![TransformProvenanceDerivationNodeV0 {
1531 node_index: 0,
1532 parent_index: None,
1533 pass_id: "comment-strip",
1534 status: TransformPassRuntimeStatus::Applied,
1535 input_byte_len: 48,
1536 output_byte_len: 36,
1537 source_span_start: 0,
1538 source_span_end: 12,
1539 generated_span_start: 0,
1540 generated_span_end: 0,
1541 mutation_spans: Vec::new(),
1542 mutation_count: 1,
1543 provenance_preserved: true,
1544 detail: "fixture derivation",
1545 }],
1546 };
1547
1548 let before = serde_json::to_value(&forest)?;
1549 let graph = forest
1550 .evidence_graph()
1551 .map_err(|_| serde::ser::Error::custom("forest edge must target its node"))?;
1552 let after = serde_json::to_value(&forest)?;
1553
1554 assert_eq!(before, after);
1555 assert_eq!(graph.nodes.len(), 1);
1556 assert_eq!(graph.nodes[0].key.input_identity, "comment-strip#0");
1557 assert_eq!(graph.nodes[0].guarantee, GuaranteeKindV0::Floor);
1558 Ok(())
1559 }
1560}