1use omena_abstract_value::{AbstractCssValueV0, FactPrecision};
10use omena_cascade::{
11 CascadeDeclaration, CascadeLevel, CascadeOriginV0, CascadeOutcome, CascadeProof,
12 ElementSignature, GuardedCascadeWinnerAuthorityV0, GuardedCascadeWinnerPlaneAnswerV0,
13 GuardedCascadeWinnerRootV0, SupportsTargetCapabilityV0,
14};
15use omena_cascade_proof::{
16 CanonicalSmtInputV0, DischargeLedgerLookupStatusV0, DischargeLedgerLookupV0,
17 DischargeLedgerVerdictV0,
18};
19use omena_evidence_graph::{
20 EvidenceDemandEdgeV0, EvidenceGraphBuildErrorV0, EvidenceGraphV0, EvidenceNodeKeyV0,
21 EvidenceNodeSeedV0, GuaranteeFamilyV0, GuaranteeKindV0, build_evidence_graph_from_edges_v0,
22};
23use omena_incremental::{IncrementalComputationPlanV0, IncrementalSnapshotV0};
24use omena_parser::ModuleInstanceKeyV0;
25use omena_syntax::ident::AuthoredPropertyTextV0;
26use omena_transform_cst::{
27 StableNodeKeyV0, TransformBuildProfileV0, TransformDagEdgeV0, TransformPassContractV0,
28 TransformPassDescriptorV0, TransformPassKind, TransformStrictPolicyDescriptorV0,
29 strict_policy_descriptor_for_profile,
30};
31use serde::{Deserialize, Serialize};
32use serde_json::Value;
33
34const TRANSFORM_PASS_OUTCOME_EVIDENCE_QUERY_V0: &str =
35 "omena-transform-passes.transform-pass-execution-outcome";
36const TRANSFORM_PROVENANCE_NODE_EVIDENCE_QUERY_V0: &str =
37 "omena-transform-passes.provenance-derivation-node";
38const TRANSFORM_EVIDENCE_EDGE_KIND_V0: &str = "transform-evidence";
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
41#[serde(rename_all = "camelCase")]
42pub enum TransformPassExecutionStatus {
43 RegistryAndPlannerReady,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
47#[serde(rename_all = "camelCase")]
48pub enum TransformPassDispatchKindV0 {
49 TextLocalSliceRewrite,
50 StructuralIrTransaction,
51 ModuleEvaluationHandler,
52 EmissionBoundary,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
56#[serde(rename_all = "camelCase")]
57pub struct TransformPassRegistryEntryV0 {
58 pub contract: TransformPassContractV0,
59 pub descriptor: TransformPassDescriptorV0,
60 pub module_family: &'static str,
61 pub query_family: &'static str,
62 pub dispatch_kind: TransformPassDispatchKindV0,
63 pub execution_status: TransformPassExecutionStatus,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
67#[serde(rename_all = "camelCase")]
68pub struct TransformPassRegistryV0 {
69 pub schema_version: &'static str,
70 pub product: &'static str,
71 pub entries: Vec<TransformPassRegistryEntryV0>,
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
75#[serde(rename_all = "camelCase")]
76pub struct TransformPassesBoundarySummaryV0 {
77 pub schema_version: &'static str,
78 pub product: &'static str,
79 pub registry_entries: Vec<TransformPassRegistryEntryV0>,
80 pub dag_edges: Vec<TransformDagEdgeV0>,
81 pub pass_count: usize,
82 pub full_catalog_registered: bool,
83 pub semantic_aware_pass_count: usize,
84 pub cascade_aware_pass_count: usize,
85 pub structural_pass_count: usize,
86 pub text_local_pass_count: usize,
87 pub module_evaluation_pass_count: usize,
88 pub planner_enforces_dag_edges: bool,
89 pub planner_uses_pass_descriptors: bool,
90 pub ordinal_has_execution_semantics: bool,
91 pub execution_runtime_ready: bool,
92 pub incremental_execution_runtime_ready: bool,
93 pub module_evaluation_native_output_marker: &'static str,
94 pub module_evaluation_requires_native_product_output: bool,
95 pub module_evaluation_requires_oracle_readiness: bool,
96 pub module_evaluation_legacy_output_is_oracle_only: bool,
97 pub module_evaluation_preserves_source_without_native_output: bool,
98 pub implemented_mutation_pass_ids: Vec<&'static str>,
99 pub next_surfaces: Vec<&'static str>,
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
103#[serde(rename_all = "camelCase")]
104pub struct TransformPassPlanV0 {
105 pub schema_version: &'static str,
106 pub product: &'static str,
107 pub build_profile: TransformBuildProfileV0,
108 pub requested_pass_ids: Vec<&'static str>,
109 pub ordered_pass_ids: Vec<&'static str>,
110 pub satisfied_dag_edge_count: usize,
111 pub violated_dag_edge_count: usize,
112 pub all_requested_registered: bool,
113 pub conflicting_unordered_pass_pairs: Vec<TransformPlanPassConflictV0>,
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
117#[serde(rename_all = "camelCase")]
118pub struct TransformPlanPassConflictV0 {
119 pub pass_a: &'static str,
120 pub pass_b: &'static str,
121}
122
123#[non_exhaustive]
124#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
125#[serde(rename_all = "camelCase")]
126pub struct TransformPlanDependencyEdgeV0 {
128 pub prerequisite_pass_id: &'static str,
129 pub dependent_pass_id: &'static str,
130}
131
132#[non_exhaustive]
133#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
134#[serde(rename_all = "camelCase")]
135pub struct TransformPlanDependencyCycleV0 {
137 pub cycle_path: Vec<&'static str>,
139 pub dependency_edges: Vec<TransformPlanDependencyEdgeV0>,
140}
141
142#[non_exhaustive]
143#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
144#[serde(
145 tag = "kind",
146 rename_all = "camelCase",
147 rename_all_fields = "camelCase"
148)]
149pub enum TransformPassPlanningErrorV0 {
151 DependencyCycle {
152 cycle: TransformPlanDependencyCycleV0,
153 },
154 UnorderedPassConflict {
155 conflict: TransformPlanPassConflictV0,
156 },
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
160#[serde(rename_all = "camelCase")]
161pub struct TransformStructuralIrShadowFieldReportV0 {
162 pub field: &'static str,
163 pub string_path_values: Vec<String>,
164 pub ir_path_values: Vec<String>,
165 pub typed_path_values: Vec<String>,
166 pub matches: bool,
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
170#[serde(rename_all = "camelCase")]
171pub struct TransformStructuralIrShadowFixtureReportV0 {
172 pub schema_version: &'static str,
173 pub product: &'static str,
174 pub fixture: String,
175 pub pass_id: &'static str,
176 pub dialect: &'static str,
177 pub string_path_mutation_count: Option<usize>,
178 pub ir_path_mutation_count: Option<usize>,
179 pub typed_path_mutation_count: Option<usize>,
180 pub ir_path_transaction_commit_count: Option<u64>,
181 pub typed_payload_projections_consumed: usize,
182 pub typed_payload_memo_hits: usize,
183 pub fields: Vec<TransformStructuralIrShadowFieldReportV0>,
184 pub all_fields_match: bool,
185 pub all_typed_path_fields_match: bool,
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
189#[serde(rename_all = "camelCase")]
190pub struct TransformStructuralIrShadowEquivalenceReportV0 {
191 pub schema_version: &'static str,
192 pub product: &'static str,
193 pub fixture_count: usize,
194 pub compared_pass_ids: Vec<&'static str>,
195 pub compared_fields: Vec<&'static str>,
196 pub reports: Vec<TransformStructuralIrShadowFixtureReportV0>,
197 pub all_fields_match: bool,
198 pub all_typed_path_fields_match: bool,
199 pub typed_payload_projections_consumed: usize,
200 pub typed_payload_memo_hits: usize,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
204#[serde(rename_all = "camelCase")]
205pub enum TransformPassRuntimeStatus {
206 Applied,
207 NoChange,
208 PlannedOnly,
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
212#[serde(rename_all = "camelCase")]
213pub struct TransformPassExecutionOutcomeV0 {
214 pub pass_id: &'static str,
215 pub status: TransformPassRuntimeStatus,
216 pub input_byte_len: usize,
217 pub output_byte_len: usize,
218 pub mutation_count: usize,
219 pub provenance_preserved: bool,
220 pub detail: &'static str,
221}
222
223impl TransformPassExecutionOutcomeV0 {
224 pub fn evidence_node_key(&self) -> EvidenceNodeKeyV0 {
225 EvidenceNodeKeyV0::new(TRANSFORM_PASS_OUTCOME_EVIDENCE_QUERY_V0, self.pass_id)
226 }
227
228 pub fn evidence_node_seed(&self) -> EvidenceNodeSeedV0 {
229 EvidenceNodeSeedV0::new(
230 self.evidence_node_key(),
231 vec![
232 ["pass:", self.pass_id].concat(),
233 ["detail:", self.detail].concat(),
234 ["mutationCount:", self.mutation_count.to_string().as_str()].concat(),
235 [
236 "provenancePreserved:",
237 self.provenance_preserved.to_string().as_str(),
238 ]
239 .concat(),
240 ],
241 GuaranteeKindV0::for_label_less_family(),
242 )
243 }
244
245 pub fn evidence_demand_edge(&self) -> EvidenceDemandEdgeV0 {
246 EvidenceDemandEdgeV0::new(
247 TRANSFORM_PASS_OUTCOME_EVIDENCE_QUERY_V0,
248 self.evidence_node_key(),
249 TRANSFORM_EVIDENCE_EDGE_KIND_V0,
250 )
251 }
252}
253
254#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
255#[serde(rename_all = "camelCase")]
256pub enum TransformEvaluationProfileV0 {
257 Scss,
258 Less,
259}
260
261#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
262#[serde(tag = "kind", rename_all = "camelCase")]
263pub enum TransformPreconditionV0 {
264 EvaluatorOutput {
265 profile: TransformEvaluationProfileV0,
266 },
267 ResolvedImportReplacements,
268 CssModulesComposesResolution,
269 DesignTokenRoutes,
270 SelectorIdentity,
271 ClosedStyleWorldBundle,
272 ClosedWorldBundle,
273}
274
275#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
276#[serde(tag = "kind", rename_all = "camelCase")]
277pub enum TransformNoChangeReasonV0 {
278 NoMutation,
279 EmissionBoundary,
280 ProfileNotApplicable {
281 profile: TransformEvaluationProfileV0,
282 },
283 NoMatchingSelectorRewrite,
284 DialectNotApplicable,
285}
286
287#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
288#[serde(
289 tag = "kind",
290 rename_all = "camelCase",
291 rename_all_fields = "camelCase"
292)]
293pub enum TransformBlockedReasonV0 {
294 MissingPrecondition {
295 precondition: TransformPreconditionV0,
296 },
297 PrecisionBelowFloor {
298 required: FactPrecision,
299 observed: FactPrecision,
300 },
301 DischargeMissing {
302 lookup_status: Option<DischargeLedgerLookupStatusV0>,
303 verdict: Option<DischargeLedgerVerdictV0>,
304 },
305 StrictVerification {
306 reasons: Vec<TransformStrictPolicyReasonV0>,
307 },
308 PassImplementation,
309 ClosedWorldAdmission {
310 reasons: Vec<TransformStrictPolicyReasonV0>,
311 },
312}
313
314#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
315#[serde(tag = "kind", rename_all = "camelCase")]
316pub enum TransformRejectionReasonV0 {
317 IrTransaction {
318 pass: TransformPassKind,
319 },
320 SemanticPreservation,
321 StrictVerification {
322 reasons: Vec<TransformStrictPolicyReasonV0>,
323 },
324 ModuleExportPreservation {
325 pass: TransformPassKind,
326 reason: String,
327 },
328}
329
330#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
331#[serde(
332 tag = "kind",
333 rename_all = "camelCase",
334 rename_all_fields = "camelCase"
335)]
336pub enum TransformStructuralDecisionClassV0 {
337 FactConsuming { required_precision: FactPrecision },
338 StaticExact,
339 ObligationDischarge,
340 NonRemovalRewrite,
341}
342
343#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
344#[serde(rename_all = "camelCase")]
345pub struct TransformStructuralDecisionPolicyV0 {
346 pub pass: TransformPassKind,
347 pub class: TransformStructuralDecisionClassV0,
348 pub reason: &'static str,
349}
350
351impl TransformStructuralDecisionPolicyV0 {
352 pub const fn new(
353 pass: TransformPassKind,
354 class: TransformStructuralDecisionClassV0,
355 reason: &'static str,
356 ) -> Self {
357 Self {
358 pass,
359 class,
360 reason,
361 }
362 }
363
364 pub const fn required_precision(self) -> Option<FactPrecision> {
365 match self.class {
366 TransformStructuralDecisionClassV0::FactConsuming { required_precision } => {
367 Some(required_precision)
368 }
369 TransformStructuralDecisionClassV0::StaticExact
370 | TransformStructuralDecisionClassV0::ObligationDischarge
371 | TransformStructuralDecisionClassV0::NonRemovalRewrite => None,
372 }
373 }
374}
375
376pub const TRANSFORM_STRUCTURAL_DECISION_POLICIES_V0: &[TransformStructuralDecisionPolicyV0] = &[
377 TransformStructuralDecisionPolicyV0::new(
378 TransformPassKind::ImportInline,
379 TransformStructuralDecisionClassV0::NonRemovalRewrite,
380 "materializes explicitly resolved imports without reachability pruning",
381 ),
382 TransformStructuralDecisionPolicyV0::new(
383 TransformPassKind::ResolveCssModulesComposes,
384 TransformStructuralDecisionClassV0::NonRemovalRewrite,
385 "materializes explicit CSS Modules composition resolution",
386 ),
387 TransformStructuralDecisionPolicyV0::new(
388 TransformPassKind::DesignTokenRouting,
389 TransformStructuralDecisionClassV0::NonRemovalRewrite,
390 "rewrites values through explicit design-token routes",
391 ),
392 TransformStructuralDecisionPolicyV0::new(
393 TransformPassKind::HashCssModuleClassNames,
394 TransformStructuralDecisionClassV0::NonRemovalRewrite,
395 "rewrites selectors through an explicit identity map",
396 ),
397 TransformStructuralDecisionPolicyV0::new(
398 TransformPassKind::RuleDeduplication,
399 TransformStructuralDecisionClassV0::StaticExact,
400 "removes only statically equivalent duplicate rules",
401 ),
402 TransformStructuralDecisionPolicyV0::new(
403 TransformPassKind::RuleMerging,
404 TransformStructuralDecisionClassV0::NonRemovalRewrite,
405 "combines adjacent declarations without reachability pruning",
406 ),
407 TransformStructuralDecisionPolicyV0::new(
408 TransformPassKind::SelectorMerging,
409 TransformStructuralDecisionClassV0::NonRemovalRewrite,
410 "combines equivalent selector blocks without reachability pruning",
411 ),
412 TransformStructuralDecisionPolicyV0::new(
413 TransformPassKind::NestingUnwrap,
414 TransformStructuralDecisionClassV0::NonRemovalRewrite,
415 "expands nested selectors without reachability pruning",
416 ),
417 TransformStructuralDecisionPolicyV0::new(
418 TransformPassKind::ScopeFlatten,
419 TransformStructuralDecisionClassV0::ObligationDischarge,
420 "requires accepted scope-flatten obligations",
421 ),
422 TransformStructuralDecisionPolicyV0::new(
423 TransformPassKind::LayerFlatten,
424 TransformStructuralDecisionClassV0::ObligationDischarge,
425 "requires accepted layer-flatten obligations",
426 ),
427 TransformStructuralDecisionPolicyV0::new(
428 TransformPassKind::SupportsStaticEval,
429 TransformStructuralDecisionClassV0::StaticExact,
430 "removes only statically decided supports branches",
431 ),
432 TransformStructuralDecisionPolicyV0::new(
433 TransformPassKind::MediaStaticEval,
434 TransformStructuralDecisionClassV0::StaticExact,
435 "removes only statically unsatisfiable media branches",
436 ),
437 TransformStructuralDecisionPolicyV0::new(
438 TransformPassKind::ContainerStaticEval,
439 TransformStructuralDecisionClassV0::StaticExact,
440 "removes only statically unsatisfiable container branches",
441 ),
442 TransformStructuralDecisionPolicyV0::new(
443 TransformPassKind::NativeCssStaticEval,
444 TransformStructuralDecisionClassV0::StaticExact,
445 "folds only statically evaluable native CSS expressions",
446 ),
447 TransformStructuralDecisionPolicyV0::new(
448 TransformPassKind::DeadMediaBranchRemoval,
449 TransformStructuralDecisionClassV0::StaticExact,
450 "removes only media branches selected by explicit static policy",
451 ),
452 TransformStructuralDecisionPolicyV0::new(
453 TransformPassKind::DeadSupportsBranchRemoval,
454 TransformStructuralDecisionClassV0::StaticExact,
455 "removes only statically decided supports branches",
456 ),
457 TransformStructuralDecisionPolicyV0::new(
458 TransformPassKind::TreeShakeClass,
459 TransformStructuralDecisionClassV0::FactConsuming {
460 required_precision: FactPrecision::Conservative,
461 },
462 "removes class rules only from a closed-world reachability over-approximation",
463 ),
464 TransformStructuralDecisionPolicyV0::new(
465 TransformPassKind::TreeShakeKeyframes,
466 TransformStructuralDecisionClassV0::FactConsuming {
467 required_precision: FactPrecision::Conservative,
468 },
469 "removes keyframes only from a closed-world reachability over-approximation",
470 ),
471 TransformStructuralDecisionPolicyV0::new(
472 TransformPassKind::TreeShakeValue,
473 TransformStructuralDecisionClassV0::FactConsuming {
474 required_precision: FactPrecision::Conservative,
475 },
476 "removes CSS Modules values only from a closed-world reachability over-approximation",
477 ),
478 TransformStructuralDecisionPolicyV0::new(
479 TransformPassKind::TreeShakeCustomProperty,
480 TransformStructuralDecisionClassV0::FactConsuming {
481 required_precision: FactPrecision::Conservative,
482 },
483 "removes custom properties only from a closed-world reachability over-approximation",
484 ),
485 TransformStructuralDecisionPolicyV0::new(
486 TransformPassKind::EmptyRuleRemoval,
487 TransformStructuralDecisionClassV0::StaticExact,
488 "removes only structurally empty rules",
489 ),
490];
491
492pub fn transform_structural_decision_policy(
493 pass: TransformPassKind,
494) -> Option<&'static TransformStructuralDecisionPolicyV0> {
495 TRANSFORM_STRUCTURAL_DECISION_POLICIES_V0
496 .iter()
497 .find(|policy| policy.pass == pass)
498}
499
500#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
501#[serde(tag = "kind", rename_all = "camelCase")]
502pub enum RollbackScopeV0 {
503 RejectPreservedInput,
504 InversePatch,
505 CommittedIrrecoverable,
506}
507
508#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
509#[serde(rename_all = "camelCase")]
510pub struct RollbackReceiptV0 {
511 pub pass_id: String,
512 pub attempted_mutation_count: Option<usize>,
513 pub input_content_signature: String,
514 #[serde(skip_serializing_if = "Option::is_none")]
515 pub output_preserved_content_signature: Option<String>,
516 pub restorable: RollbackScopeV0,
517}
518
519#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
520#[serde(rename_all = "camelCase")]
521pub struct TransformDischargeEvidenceV0 {
522 pub evidence_node_key: EvidenceNodeKeyV0,
523 pub guarantee_family: GuaranteeFamilyV0,
524 pub ledger_cell_key: String,
525 pub boundedness_kind: String,
526}
527
528#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
533#[serde(rename_all = "camelCase")]
534pub enum TransformWinnerEqualityAxisV0 {
535 CascadeLevel,
536 LayerRank,
537 ScopeProximity,
538 Specificity,
539 SourceOrder,
540}
541
542#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
544#[serde(
545 tag = "kind",
546 rename_all = "camelCase",
547 rename_all_fields = "camelCase"
548)]
549pub enum TransformWinnerEqualityAbsenceReasonV0 {
550 DriverUnavailable {
551 level: Option<CascadeLevel>,
552 },
553 AffectedPairUnavailable,
554 SpecificityInexact,
555 WinnerNotDefinite,
556 WinnerChanged,
557 GuardedWinnerFunctionsDiffer {
558 input_root: GuardedCascadeWinnerRootV0,
559 output_root: GuardedCascadeWinnerRootV0,
560 },
561 GuardedWinnerPlaneDisagreement {
562 side: &'static str,
563 canonical_mtbdd: GuardedCascadeWinnerPlaneAnswerV0,
564 scenario_sweep: GuardedCascadeWinnerPlaneAnswerV0,
565 },
566}
567
568#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
570#[serde(rename_all = "camelCase")]
571pub struct TransformWinnerEqualityAbsenceV0 {
572 pub axis: TransformWinnerEqualityAxisV0,
573 pub reason: TransformWinnerEqualityAbsenceReasonV0,
574}
575
576#[derive(Debug, Clone, Serialize)]
578#[serde(rename_all = "camelCase")]
579pub struct TransformWinnerEqualityAffectedPairV0 {
580 pub element_signature: ElementSignature,
581 pub property: AuthoredPropertyTextV0,
582}
583
584impl PartialEq for TransformWinnerEqualityAffectedPairV0 {
585 fn eq(&self, other: &Self) -> bool {
586 self.element_signature == other.element_signature
587 && self
588 .property
589 .to_property_name()
590 .same_as(&other.property.to_property_name())
591 }
592}
593
594impl Eq for TransformWinnerEqualityAffectedPairV0 {}
595
596#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
601#[serde(rename_all = "camelCase")]
602pub struct TransformWinnerEqualityWitnessV0 {
603 pub winner: CascadeDeclaration,
604 pub proof: CascadeProof,
605}
606
607impl TransformWinnerEqualityWitnessV0 {
608 pub fn from_cascade_outcome(outcome: &CascadeOutcome) -> Option<Self> {
609 match outcome {
610 CascadeOutcome::Definite { winner, proof, .. } => Some(Self {
611 winner: winner.clone(),
612 proof: proof.as_ref().clone(),
613 }),
614 CascadeOutcome::RankedSet(_) | CascadeOutcome::Inherit | CascadeOutcome::Top => None,
615 }
616 }
617}
618
619#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
621#[serde(
622 tag = "kind",
623 rename_all = "camelCase",
624 rename_all_fields = "camelCase"
625)]
626pub enum TransformWinnerEqualityObservationV0 {
627 ObservedEqual {
628 axes: Vec<TransformWinnerEqualityAxisV0>,
629 input: TransformWinnerEqualityWitnessV0,
630 output: TransformWinnerEqualityWitnessV0,
631 },
632 ObservedDifferent {
633 axes: Vec<TransformWinnerEqualityAxisV0>,
634 input: TransformWinnerEqualityWitnessV0,
635 output: TransformWinnerEqualityWitnessV0,
636 },
637 Absent {
638 reasons: Vec<TransformWinnerEqualityAbsenceV0>,
639 },
640 ObservedGuardedEqual {
641 axes: Vec<TransformWinnerEqualityAxisV0>,
642 input: TransformWinnerEqualityWitnessV0,
643 output: TransformWinnerEqualityWitnessV0,
644 authority: GuardedCascadeWinnerAuthorityV0,
645 },
646}
647
648#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
650#[serde(rename_all = "camelCase")]
651pub struct TransformWinnerEqualityObligationV0 {
652 pub pass_id: &'static str,
653 pub affected_pair: TransformWinnerEqualityAffectedPairV0,
654 pub observation: TransformWinnerEqualityObservationV0,
655}
656
657#[derive(Debug, Clone, Default, PartialEq, Eq)]
658pub struct TransformExecutionPolicyV0 {
659 pub strict_policy: Option<TransformStrictPolicyDescriptorV0>,
660}
661
662impl TransformExecutionPolicyV0 {
663 pub fn for_profile(profile_id: &str) -> Option<Self> {
664 strict_policy_descriptor_for_profile(profile_id).map(|strict_policy| Self {
665 strict_policy: Some(strict_policy),
666 })
667 }
668}
669
670#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
671#[serde(
672 tag = "kind",
673 rename_all = "camelCase",
674 rename_all_fields = "camelCase"
675)]
676pub enum TransformStrictPolicyReasonV0 {
677 RequiredAxisUnavailable {
678 axis: TransformWinnerEqualityAxisV0,
679 },
680 CascadeEnvironmentUnavailable,
681 WinnerChanged {
682 axes: Vec<TransformWinnerEqualityAxisV0>,
683 },
684 ObservationUnavailable {
685 reasons: Vec<TransformWinnerEqualityAbsenceV0>,
686 },
687 UnknownPass,
688 ClosedWorldEvidenceUnavailable,
689 DecisionCoverageIncomplete,
690 ClosedWorldEvidenceIncomplete {
691 missing: Vec<String>,
692 },
693 LivenessNotClosed {
694 symbol: String,
695 from_module: ModuleInstanceKeyV0,
696 via_edge: &'static str,
697 },
698 EvidenceUnavailable,
699 OwnershipNotSeparable {
700 token: String,
701 module_paths: Vec<String>,
702 },
703}
704
705#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
706#[serde(rename_all = "camelCase")]
707#[non_exhaustive]
708pub enum CssModuleTokenCollisionPathScopeV0 {
709 BothPaths,
710 ImportInlineLegacyOnly,
711 LinkedOrderOnly,
712}
713
714impl CssModuleTokenCollisionPathScopeV0 {
715 pub const fn as_wire_label(self) -> &'static str {
716 match self {
717 Self::BothPaths => "bothPaths",
718 Self::ImportInlineLegacyOnly => "importInlineLegacyOnly",
719 Self::LinkedOrderOnly => "linkedOrderOnly",
720 }
721 }
722}
723
724#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
725#[serde(rename_all = "camelCase")]
726#[non_exhaustive]
727pub struct CssModuleTokenOwnershipV0 {
728 pub emitted_token: String,
729 pub module_instances: Vec<ModuleInstanceKeyV0>,
730 pub module_paths: Vec<String>,
731 pub original_names: Vec<String>,
732}
733
734impl CssModuleTokenOwnershipV0 {
735 pub fn new(
736 emitted_token: impl Into<String>,
737 module_instances: Vec<ModuleInstanceKeyV0>,
738 module_paths: Vec<String>,
739 original_names: Vec<String>,
740 ) -> Self {
741 Self {
742 emitted_token: emitted_token.into(),
743 module_instances,
744 module_paths,
745 original_names,
746 }
747 }
748}
749
750#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
751#[serde(rename_all = "camelCase")]
752#[non_exhaustive]
753pub struct CssModuleTokenCollisionV0 {
754 pub emitted_token: String,
755 pub module_instances: Vec<ModuleInstanceKeyV0>,
756 pub module_paths: Vec<String>,
757 pub original_names: Vec<String>,
758 pub observed_emission_paths: Vec<&'static str>,
759 pub path_scope: CssModuleTokenCollisionPathScopeV0,
760}
761
762impl CssModuleTokenCollisionV0 {
763 pub fn new(
764 ownership: CssModuleTokenOwnershipV0,
765 observed_emission_paths: Vec<&'static str>,
766 path_scope: CssModuleTokenCollisionPathScopeV0,
767 ) -> Self {
768 Self {
769 emitted_token: ownership.emitted_token,
770 module_instances: ownership.module_instances,
771 module_paths: ownership.module_paths,
772 original_names: ownership.original_names,
773 observed_emission_paths,
774 path_scope,
775 }
776 }
777}
778
779#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
780#[serde(rename_all = "camelCase")]
781#[non_exhaustive]
782pub struct CssModuleTokenInterfaceMismatchV0 {
783 pub module_instance: ModuleInstanceKeyV0,
784 pub module_path: String,
785 pub original_name: String,
786 pub promised_token: String,
787 pub emitted_token: String,
788}
789
790impl CssModuleTokenInterfaceMismatchV0 {
791 pub fn new(
792 module_instance: ModuleInstanceKeyV0,
793 module_path: impl Into<String>,
794 original_name: impl Into<String>,
795 promised_token: impl Into<String>,
796 emitted_token: impl Into<String>,
797 ) -> Self {
798 Self {
799 module_instance,
800 module_path: module_path.into(),
801 original_name: original_name.into(),
802 promised_token: promised_token.into(),
803 emitted_token: emitted_token.into(),
804 }
805 }
806}
807
808#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
809#[serde(rename_all = "camelCase")]
810#[non_exhaustive]
811pub struct CssModuleTokenOwnershipCensusV0 {
812 pub schema_version: &'static str,
813 pub product: &'static str,
814 pub scope: &'static str,
815 pub emission_path: &'static str,
816 pub complete: bool,
817 pub modeled_preimage_count: usize,
818 pub emitted_token_count: usize,
819 pub token_ownerships: Vec<CssModuleTokenOwnershipV0>,
820 pub module_token_collision_count: usize,
821 pub module_token_collisions: Vec<CssModuleTokenCollisionV0>,
822 pub unattributed_emitted_tokens: Vec<String>,
823 pub interface_mismatches: Vec<CssModuleTokenInterfaceMismatchV0>,
824 pub unavailable_reasons: Vec<String>,
825}
826
827impl CssModuleTokenOwnershipCensusV0 {
828 pub fn new(
829 emission_path: &'static str,
830 modeled_preimage_count: usize,
831 token_ownerships: Vec<CssModuleTokenOwnershipV0>,
832 module_token_collisions: Vec<CssModuleTokenCollisionV0>,
833 unattributed_emitted_tokens: Vec<String>,
834 interface_mismatches: Vec<CssModuleTokenInterfaceMismatchV0>,
835 ) -> Self {
836 let module_token_collision_count = module_token_collisions.len();
837 let emitted_token_count = token_ownerships.len() + unattributed_emitted_tokens.len();
838 Self {
839 schema_version: "0",
840 product: "omena-query.css-module-token-ownership-census",
841 scope: "bundleEmission",
842 emission_path,
843 complete: unattributed_emitted_tokens.is_empty(),
844 modeled_preimage_count,
845 emitted_token_count,
846 token_ownerships,
847 module_token_collision_count,
848 module_token_collisions,
849 unattributed_emitted_tokens,
850 interface_mismatches,
851 unavailable_reasons: Vec::new(),
852 }
853 }
854
855 pub fn unavailable(emission_path: &'static str, reason: impl Into<String>) -> Self {
856 Self {
857 schema_version: "0",
858 product: "omena-query.css-module-token-ownership-census",
859 scope: "bundleEmission",
860 emission_path,
861 complete: false,
862 modeled_preimage_count: 0,
863 emitted_token_count: 0,
864 token_ownerships: Vec::new(),
865 module_token_collision_count: 0,
866 module_token_collisions: Vec::new(),
867 unattributed_emitted_tokens: Vec::new(),
868 interface_mismatches: Vec::new(),
869 unavailable_reasons: vec![reason.into()],
870 }
871 }
872}
873
874#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
875#[serde(rename_all = "camelCase")]
876pub struct TransformStrictPolicyEventV0 {
877 pub pass_id: String,
878 pub reasons: Vec<TransformStrictPolicyReasonV0>,
879}
880
881#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
882#[serde(rename_all = "camelCase")]
883pub struct TransformStrictPolicySummaryV0 {
884 pub profile_id: Option<String>,
885 pub refused_count: usize,
886 pub rolled_back_count: usize,
887 pub refusal_reasons: Vec<TransformStrictPolicyEventV0>,
888 pub rollback_reasons: Vec<TransformStrictPolicyEventV0>,
889}
890
891impl TransformStrictPolicySummaryV0 {
892 pub fn for_profile(profile_id: &str) -> Self {
893 Self {
894 profile_id: Some(profile_id.to_string()),
895 ..Self::default()
896 }
897 }
898
899 pub fn record_refusal(
900 &mut self,
901 pass_id: impl Into<String>,
902 reasons: Vec<TransformStrictPolicyReasonV0>,
903 ) {
904 self.refusal_reasons.push(TransformStrictPolicyEventV0 {
905 pass_id: pass_id.into(),
906 reasons,
907 });
908 self.refused_count = self.refusal_reasons.len();
909 }
910
911 pub fn record_rollback(
912 &mut self,
913 pass_id: impl Into<String>,
914 reasons: Vec<TransformStrictPolicyReasonV0>,
915 ) {
916 self.rollback_reasons.push(TransformStrictPolicyEventV0 {
917 pass_id: pass_id.into(),
918 reasons,
919 });
920 self.rolled_back_count = self.rollback_reasons.len();
921 }
922}
923
924#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
925pub struct ClosedWorldAdmissionTierV0;
926
927#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
928#[serde(rename_all = "camelCase")]
929pub struct TransformClosedWorldAdmissionEventV0 {
930 pub pass_id: String,
931 pub module_instance: Option<ModuleInstanceKeyV0>,
932 pub reasons: Vec<TransformStrictPolicyReasonV0>,
933}
934
935#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
936#[serde(rename_all = "camelCase")]
937pub struct TransformClosedWorldAdmissionSummaryV0 {
938 pub refused_count: usize,
939 #[serde(skip_serializing_if = "Option::is_none")]
940 pub evidence_scope: Option<&'static str>,
941 pub refusal_reasons: Vec<TransformClosedWorldAdmissionEventV0>,
942}
943
944impl TransformClosedWorldAdmissionSummaryV0 {
945 pub fn record_refusal(
946 &mut self,
947 pass_id: impl Into<String>,
948 module_instance: Option<ModuleInstanceKeyV0>,
949 reasons: Vec<TransformStrictPolicyReasonV0>,
950 ) {
951 self.refusal_reasons
952 .push(TransformClosedWorldAdmissionEventV0 {
953 pass_id: pass_id.into(),
954 module_instance,
955 reasons,
956 });
957 self.refused_count = self.refusal_reasons.len();
958 }
959}
960
961#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
968#[serde(
969 tag = "kind",
970 rename_all = "camelCase",
971 rename_all_fields = "camelCase"
972)]
973pub enum TransformSemanticGuaranteeTierV0 {
974 L0Observed,
975 WinnerEqualityObserved {
976 axes: Vec<TransformWinnerEqualityAxisV0>,
977 },
978 Absent {
979 reasons: Vec<TransformWinnerEqualityAbsenceV0>,
980 },
981}
982
983impl RollbackReceiptV0 {
984 pub fn preserves_rejected_input(&self) -> bool {
985 self.restorable == RollbackScopeV0::RejectPreservedInput
986 && self.output_preserved_content_signature.as_deref()
987 == Some(self.input_content_signature.as_str())
988 }
989
990 pub fn covers_inverse_patch(
991 &self,
992 inverse_patch_count: usize,
993 input_content_signature: &str,
994 ) -> bool {
995 self.restorable == RollbackScopeV0::InversePatch
996 && self.attempted_mutation_count == Some(inverse_patch_count)
997 && self.input_content_signature == input_content_signature
998 && self.output_preserved_content_signature.is_none()
999 }
1000}
1001
1002#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1003#[serde(
1004 tag = "kind",
1005 rename_all = "camelCase",
1006 rename_all_fields = "camelCase"
1007)]
1008pub enum TransformDecision {
1009 Applied {
1010 outcome: TransformPassExecutionOutcomeV0,
1011 rollback_receipt: RollbackReceiptV0,
1012 #[serde(skip_serializing_if = "Option::is_none")]
1013 semantic_guarantee_tier: Option<TransformSemanticGuaranteeTierV0>,
1014 #[serde(skip_serializing_if = "Vec::is_empty")]
1015 discharge_evidence: Vec<TransformDischargeEvidenceV0>,
1016 },
1017 NoChange {
1018 reason: TransformNoChangeReasonV0,
1019 outcome: TransformPassExecutionOutcomeV0,
1020 },
1021 Blocked {
1022 reason: TransformBlockedReasonV0,
1023 outcome: TransformPassExecutionOutcomeV0,
1024 },
1025 Rejected {
1026 reason: TransformRejectionReasonV0,
1027 outcome: TransformPassExecutionOutcomeV0,
1028 rollback_receipt: RollbackReceiptV0,
1029 },
1030}
1031
1032impl TransformDecision {
1033 pub fn compatibility_outcome(&self) -> &TransformPassExecutionOutcomeV0 {
1034 match self {
1035 Self::Applied { outcome, .. }
1036 | Self::NoChange { outcome, .. }
1037 | Self::Blocked { outcome, .. }
1038 | Self::Rejected { outcome, .. } => outcome,
1039 }
1040 }
1041
1042 pub fn into_compatibility_outcome(self) -> TransformPassExecutionOutcomeV0 {
1043 match self {
1044 Self::Applied { outcome, .. }
1045 | Self::NoChange { outcome, .. }
1046 | Self::Blocked { outcome, .. }
1047 | Self::Rejected { outcome, .. } => outcome,
1048 }
1049 }
1050
1051 pub fn rollback_receipt(&self) -> Option<&RollbackReceiptV0> {
1052 match self {
1053 Self::Applied {
1054 rollback_receipt, ..
1055 }
1056 | Self::Rejected {
1057 rollback_receipt, ..
1058 } => Some(rollback_receipt),
1059 Self::NoChange { .. } | Self::Blocked { .. } => None,
1060 }
1061 }
1062
1063 pub fn semantic_guarantee_tier(&self) -> Option<&TransformSemanticGuaranteeTierV0> {
1064 match self {
1065 Self::Applied {
1066 semantic_guarantee_tier,
1067 ..
1068 } => semantic_guarantee_tier.as_ref(),
1069 Self::NoChange { .. } | Self::Blocked { .. } | Self::Rejected { .. } => None,
1070 }
1071 }
1072}
1073
1074#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1075#[serde(rename_all = "camelCase")]
1076pub struct TransformProvenanceDerivationForestV0 {
1077 pub schema_version: &'static str,
1078 pub product: &'static str,
1079 pub root_count: usize,
1080 pub node_count: usize,
1081 pub nodes: Vec<TransformProvenanceDerivationNodeV0>,
1082}
1083
1084impl TransformProvenanceDerivationForestV0 {
1085 pub fn evidence_graph(&self) -> Result<EvidenceGraphV0, EvidenceGraphBuildErrorV0> {
1086 build_evidence_graph_from_edges_v0(
1087 self.nodes
1088 .iter()
1089 .map(TransformProvenanceDerivationNodeV0::evidence_node_seed),
1090 self.nodes
1091 .iter()
1092 .map(TransformProvenanceDerivationNodeV0::evidence_demand_edge),
1093 )
1094 }
1095}
1096
1097#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1098#[serde(rename_all = "camelCase")]
1099pub struct TransformProvenanceDerivationNodeV0 {
1100 pub node_index: usize,
1101 pub parent_index: Option<usize>,
1102 pub pass_id: &'static str,
1103 pub status: TransformPassRuntimeStatus,
1104 pub input_byte_len: usize,
1105 pub output_byte_len: usize,
1106 pub source_span_start: usize,
1107 pub source_span_end: usize,
1108 pub generated_span_start: usize,
1109 pub generated_span_end: usize,
1110 pub mutation_spans: Vec<TransformProvenanceMutationSpanV0>,
1111 pub mutation_count: usize,
1112 pub provenance_preserved: bool,
1113 pub detail: &'static str,
1114}
1115
1116impl TransformProvenanceDerivationNodeV0 {
1117 pub fn evidence_node_key(&self) -> EvidenceNodeKeyV0 {
1118 EvidenceNodeKeyV0::new(
1119 TRANSFORM_PROVENANCE_NODE_EVIDENCE_QUERY_V0,
1120 format!("{}#{}", self.pass_id, self.node_index),
1121 )
1122 }
1123
1124 pub fn evidence_node_seed(&self) -> EvidenceNodeSeedV0 {
1125 EvidenceNodeSeedV0::new(
1126 self.evidence_node_key(),
1127 vec![
1128 ["pass:", self.pass_id].concat(),
1129 ["detail:", self.detail].concat(),
1130 ["mutationCount:", self.mutation_count.to_string().as_str()].concat(),
1131 [
1132 "provenancePreserved:",
1133 self.provenance_preserved.to_string().as_str(),
1134 ]
1135 .concat(),
1136 ],
1137 GuaranteeKindV0::for_label_less_family(),
1138 )
1139 }
1140
1141 pub fn evidence_demand_edge(&self) -> EvidenceDemandEdgeV0 {
1142 EvidenceDemandEdgeV0::new(
1143 TRANSFORM_PROVENANCE_NODE_EVIDENCE_QUERY_V0,
1144 self.evidence_node_key(),
1145 TRANSFORM_EVIDENCE_EDGE_KIND_V0,
1146 )
1147 }
1148}
1149
1150#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1151#[serde(rename_all = "camelCase")]
1152pub struct TransformProvenanceMutationSpanV0 {
1153 pub source_span_start: usize,
1154 pub source_span_end: usize,
1155 pub generated_span_start: usize,
1156 pub generated_span_end: usize,
1157 #[serde(skip_serializing_if = "Option::is_none")]
1158 pub node_key: Option<StableNodeKeyV0>,
1159}
1160
1161#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize)]
1166#[serde(rename_all = "camelCase")]
1167pub struct TransformLexCacheSpliceTelemetryV0 {
1168 pub splice_hit_count: u64,
1170 pub full_relex_fallback_count: u64,
1172 pub window_derivation_fallback_count: u64,
1174 pub full_output_window_fallback_count: u64,
1176 pub token_offset_fallback_count: u64,
1178}
1179
1180#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize)]
1183#[serde(rename_all = "camelCase")]
1184#[non_exhaustive]
1185pub struct TransformStructuralIrTransactionTelemetryV0 {
1186 pub transaction_commit_count: u64,
1187 pub ir_metadata_refresh_count: u64,
1188 pub ir_transaction_commit_count: u64,
1189 pub ir_materialization_count: u64,
1190 pub ir_mutation_count: u64,
1191}
1192
1193#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
1194#[serde(rename_all = "camelCase")]
1195pub enum TransformSemanticObservationKeyAxisV0 {
1196 Selector,
1197 Property,
1198 Context,
1199}
1200
1201#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
1202#[serde(rename_all = "camelCase")]
1203pub enum TransformSemanticObservationValueAxisV0 {
1204 Value,
1205 Important,
1206}
1207
1208#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
1209#[serde(rename_all = "camelCase")]
1210pub enum TransformSemanticObservationOrderingRuleV0 {
1211 SourceOrder,
1212 ImportantPrecedence,
1213}
1214
1215#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
1216#[serde(rename_all = "camelCase")]
1217pub enum TransformSemanticUnobservedAxisV0 {
1218 InterSelectorSpecificityCompetition,
1219 CascadeLayerOrder,
1220 Origin,
1221 ScopeProximity,
1222 DomDependentMatching,
1223 Inheritance,
1224 CustomPropertyEnvironment,
1225 AnimationAndTransition,
1226 NonStyleRuleDeclarationCarriers,
1227 IntraRuleDeclarationOrdering,
1228}
1229
1230#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
1231#[serde(rename_all = "camelCase")]
1232pub enum TransformSemanticPreservationClaimScopeV0 {
1233 ObservedSurfaceOnly,
1234}
1235
1236#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
1237#[serde(rename_all = "camelCase")]
1238pub enum TransformSemanticPreservationVocabularyReviewV0 {
1239 DeferredUntilFullCascadeObservation,
1240}
1241
1242#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1244#[serde(rename_all = "camelCase")]
1245pub struct TransformSemanticObservationSurfaceV0 {
1246 pub key_axes: Vec<TransformSemanticObservationKeyAxisV0>,
1247 pub value_axes: Vec<TransformSemanticObservationValueAxisV0>,
1248 pub ordering_rules: Vec<TransformSemanticObservationOrderingRuleV0>,
1249 pub unobserved_axes: Vec<TransformSemanticUnobservedAxisV0>,
1250 pub claim_scope: TransformSemanticPreservationClaimScopeV0,
1251 pub vocabulary_review: TransformSemanticPreservationVocabularyReviewV0,
1252}
1253
1254#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1255#[serde(rename_all = "camelCase")]
1256pub struct TransformSemanticPreservationTelemetryV0 {
1257 pub observed_pass_count: u64,
1258 pub preserved_pass_count: u64,
1259 pub blocked_pass_count: u64,
1260 pub observed_surface: TransformSemanticObservationSurfaceV0,
1261}
1262
1263#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
1264#[serde(rename_all = "camelCase")]
1265pub struct TransformDischargeLedgerTelemetryV0 {
1266 pub lookup_count: u64,
1267 pub matched_lookup_count: u64,
1268 pub accepted_stamp_count: u64,
1269 pub blocked_lookup_count: u64,
1270}
1271
1272#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1273#[serde(rename_all = "camelCase")]
1274pub struct TransformModuleExportPreservationEvidenceV0 {
1275 pub pass_id: &'static str,
1276 pub module_instance: ModuleInstanceKeyV0,
1277 pub before_premise_digest: String,
1278 pub after_premise_digest: String,
1279 pub catalog_schema_id: &'static str,
1280 pub catalog_content_digest: String,
1281 pub checked_rule_ids: Vec<String>,
1282}
1283
1284#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
1285#[serde(rename_all = "camelCase")]
1286pub struct TransformModuleExportPreservationTelemetryV0 {
1287 pub certificate_construction_count: u64,
1288 pub checked_token_count: u64,
1289 pub rejected_certificate_count: u64,
1290 pub evidence: Vec<TransformModuleExportPreservationEvidenceV0>,
1291}
1292
1293impl TransformModuleExportPreservationTelemetryV0 {
1294 pub fn is_empty(&self) -> bool {
1295 self.certificate_construction_count == 0
1296 && self.checked_token_count == 0
1297 && self.rejected_certificate_count == 0
1298 && self.evidence.is_empty()
1299 }
1300}
1301
1302#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1303#[serde(rename_all = "camelCase")]
1304pub struct TransformExecutionSummaryV0 {
1305 pub schema_version: &'static str,
1306 pub product: &'static str,
1307 pub input_byte_len: usize,
1308 pub output_byte_len: usize,
1309 pub requested_pass_ids: Vec<&'static str>,
1310 pub ordered_pass_ids: Vec<&'static str>,
1311 pub executed_pass_ids: Vec<&'static str>,
1312 pub planned_only_pass_ids: Vec<&'static str>,
1313 pub mutation_count: usize,
1314 pub provenance_preserved: bool,
1315 pub output_css: String,
1316 pub css_module_evaluation: Option<TransformModuleEvaluationV0>,
1317 pub css_import_inlines: Vec<TransformImportInlineV0>,
1318 pub css_module_composes_exports: Vec<TransformCssModuleComposesResolutionV0>,
1319 pub design_token_routes: Vec<TransformDesignTokenRouteV0>,
1320 pub semantic_removals: Vec<TransformSemanticRemovalV0>,
1321 #[serde(skip_serializing_if = "Option::is_none")]
1322 pub module_qualified_shake: Option<TransformModuleQualifiedShakeSummaryV0>,
1323 pub cascade_proof_obligations: TransformCascadeProofObligationReportV0,
1324 #[serde(skip_serializing_if = "Vec::is_empty")]
1325 pub winner_equality_obligations: Vec<TransformWinnerEqualityObligationV0>,
1326 pub provenance_derivation_forest: TransformProvenanceDerivationForestV0,
1327 pub structural_ir_transaction_telemetry: TransformStructuralIrTransactionTelemetryV0,
1328 pub semantic_preservation_telemetry: TransformSemanticPreservationTelemetryV0,
1329 pub discharge_ledger_telemetry: TransformDischargeLedgerTelemetryV0,
1330 #[serde(skip_serializing_if = "TransformModuleExportPreservationTelemetryV0::is_empty")]
1331 pub module_export_preservation_telemetry: TransformModuleExportPreservationTelemetryV0,
1332 pub strict_policy: TransformStrictPolicySummaryV0,
1333 pub closed_world_admission: TransformClosedWorldAdmissionSummaryV0,
1334 pub decisions: Vec<TransformDecision>,
1335 pub outcomes: Vec<TransformPassExecutionOutcomeV0>,
1336 pub pass_plan: TransformPassPlanV0,
1337}
1338
1339#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1340#[serde(rename_all = "camelCase")]
1341pub struct TransformModuleQualifiedShakeSummaryV0 {
1342 pub module_instance: ModuleInstanceKeyV0,
1343 pub removed_count: usize,
1344}
1345
1346#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1347#[serde(
1348 tag = "kind",
1349 rename_all = "camelCase",
1350 rename_all_fields = "camelCase"
1351)]
1352pub enum TransformModuleQualifiedExecutionErrorV0 {
1353 UnknownModuleInstance {
1354 module_instance: ModuleInstanceKeyV0,
1355 },
1356}
1357
1358#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1359#[serde(rename_all = "camelCase")]
1360pub struct TransformCascadeProofObligationReportV0 {
1361 pub schema_version: &'static str,
1362 pub product: &'static str,
1363 pub obligation_count: usize,
1364 pub accepted_count: usize,
1365 pub blocked_count: usize,
1366 pub checked_pass_ids: Vec<&'static str>,
1367 pub obligations: Vec<TransformCascadeProofObligationV0>,
1368}
1369
1370#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1371#[serde(rename_all = "camelCase")]
1372pub struct TransformCascadeProofObligationV0 {
1373 pub pass_id: &'static str,
1374 pub proof_product: &'static str,
1375 pub accepted: bool,
1376 pub blocked_reason: Option<String>,
1377 pub provenance_preserved: bool,
1378 pub cascade_safe_witness: String,
1379 pub source_span_start: Option<usize>,
1380 pub source_span_end: Option<usize>,
1381 pub checked_obligations: Vec<&'static str>,
1382 #[serde(skip_serializing_if = "Option::is_none")]
1383 pub canonical_smt_input: Option<CanonicalSmtInputV0>,
1384 #[serde(skip_serializing_if = "Option::is_none")]
1385 pub discharge_ledger_lookup: Option<DischargeLedgerLookupV0>,
1386 #[serde(skip_serializing_if = "Option::is_none")]
1387 pub discharge_evidence: Option<TransformDischargeEvidenceV0>,
1388 pub proof_payload: Value,
1389}
1390
1391#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1392#[serde(rename_all = "camelCase")]
1393pub struct TransformSemanticRemovalV0 {
1394 pub pass_id: &'static str,
1395 pub symbol_kind: &'static str,
1396 pub name: String,
1397 pub source_span_start: usize,
1398 pub source_span_end: usize,
1399 pub reason: &'static str,
1400 pub certainty: &'static str,
1401 pub derivation_steps: Vec<&'static str>,
1402}
1403
1404#[derive(Debug, Clone, PartialEq, Eq)]
1405pub(crate) struct TransformSemanticRemovalCandidate {
1406 pub(crate) symbol_kind: &'static str,
1407 pub(crate) name: String,
1408 pub(crate) source_span_start: usize,
1409 pub(crate) source_span_end: usize,
1410 pub(crate) reason: &'static str,
1411}
1412
1413impl TransformSemanticRemovalCandidate {
1414 pub(crate) fn into_public(self, pass_id: &'static str) -> TransformSemanticRemovalV0 {
1415 TransformSemanticRemovalV0 {
1416 pass_id,
1417 symbol_kind: self.symbol_kind,
1418 name: self.name,
1419 source_span_start: self.source_span_start,
1420 source_span_end: self.source_span_end,
1421 reason: self.reason,
1422 certainty: "high",
1423 derivation_steps: vec![
1424 "closedStyleWorld",
1425 "reachableRootSetComputed",
1426 "symbolNotMarkedReachable",
1427 "sourceRangeRemoved",
1428 ],
1429 }
1430 }
1431}
1432
1433#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1434#[serde(rename_all = "camelCase")]
1435pub struct TransformIncrementalExecutionSummaryV0 {
1436 pub schema_version: &'static str,
1437 pub product: &'static str,
1438 pub incremental_engine: &'static str,
1439 pub query_model: &'static str,
1440 pub reuse_policy: &'static str,
1441 pub reused_previous_execution: bool,
1442 pub incremental_plan: IncrementalComputationPlanV0,
1443 pub next_snapshot: IncrementalSnapshotV0,
1444 pub execution: TransformExecutionSummaryV0,
1445 pub ready_surfaces: Vec<&'static str>,
1446}
1447
1448#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1449#[serde(rename_all = "camelCase")]
1450pub struct TransformCascadeSafetyFuzzCaseV0 {
1451 pub seed: u64,
1452 pub pass_count: usize,
1453}
1454
1455#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1456#[serde(rename_all = "camelCase")]
1457pub struct TransformCascadeSafetyFuzzResultV0 {
1458 pub seed: u64,
1459 pub pass_count: usize,
1460 pub requested_pass_ids: Vec<&'static str>,
1461 pub executed_pass_ids: Vec<&'static str>,
1462 pub output_byte_len: usize,
1463 pub output_token_count: usize,
1464 pub output_error_count: usize,
1465 pub provenance_node_count: usize,
1466 pub passed: bool,
1467}
1468
1469#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
1470#[serde(rename_all = "camelCase")]
1471pub struct TransformFuzzSeedReportV0 {
1472 pub schema_version: &'static str,
1473 pub product: &'static str,
1474 pub case_count: usize,
1475 pub passed_count: usize,
1476 pub failed_count: usize,
1477 pub results: Vec<TransformCascadeSafetyFuzzResultV0>,
1478}
1479
1480#[derive(Debug, Clone, Default, Deserialize, Serialize)]
1481#[serde(default, rename_all = "camelCase")]
1482pub struct TransformExecutionContextV0 {
1483 pub drop_dark_mode_media_queries: bool,
1484 pub supports_target_capability: Option<SupportsTargetCapabilityV0>,
1485 pub vendor_prefix_policy: Option<TransformVendorPrefixPolicyV0>,
1486 pub reachable_class_names: Vec<String>,
1487 pub reachable_keyframe_names: Vec<String>,
1488 pub reachable_value_names: Vec<String>,
1489 pub reachable_custom_property_names: Vec<AuthoredPropertyTextV0>,
1490 pub scss_module_evaluation: Option<TransformModuleEvaluationV0>,
1491 pub less_module_evaluation: Option<TransformModuleEvaluationV0>,
1492 pub import_inlines: Vec<TransformImportInlineV0>,
1493 pub class_name_rewrites: Vec<TransformClassNameRewriteV0>,
1494 pub css_module_composes_resolutions: Vec<TransformCssModuleComposesResolutionV0>,
1495 pub css_module_value_resolutions: Vec<TransformCssModuleValueResolutionV0>,
1496 pub design_token_routes: Vec<TransformDesignTokenRouteV0>,
1497 #[serde(default, skip_serializing_if = "Option::is_none")]
1500 pub cascade_environment: Option<TransformCascadeEnvironmentV0>,
1501}
1502
1503impl PartialEq for TransformExecutionContextV0 {
1504 fn eq(&self, other: &Self) -> bool {
1505 self.drop_dark_mode_media_queries == other.drop_dark_mode_media_queries
1506 && self.supports_target_capability == other.supports_target_capability
1507 && self.vendor_prefix_policy == other.vendor_prefix_policy
1508 && self.reachable_class_names == other.reachable_class_names
1509 && self.reachable_keyframe_names == other.reachable_keyframe_names
1510 && self.reachable_value_names == other.reachable_value_names
1511 && authored_custom_property_sequences_same(
1512 &self.reachable_custom_property_names,
1513 &other.reachable_custom_property_names,
1514 )
1515 && self.scss_module_evaluation == other.scss_module_evaluation
1516 && self.less_module_evaluation == other.less_module_evaluation
1517 && self.import_inlines == other.import_inlines
1518 && self.class_name_rewrites == other.class_name_rewrites
1519 && self.css_module_composes_resolutions == other.css_module_composes_resolutions
1520 && self.css_module_value_resolutions == other.css_module_value_resolutions
1521 && self.design_token_routes == other.design_token_routes
1522 && self.cascade_environment == other.cascade_environment
1523 }
1524}
1525
1526impl Eq for TransformExecutionContextV0 {}
1527
1528fn authored_custom_property_sequences_same(
1529 left: &[AuthoredPropertyTextV0],
1530 right: &[AuthoredPropertyTextV0],
1531) -> bool {
1532 left.len() == right.len()
1533 && left
1534 .iter()
1535 .zip(right)
1536 .all(|(left, right)| left.to_custom_key() == right.to_custom_key())
1537}
1538
1539#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
1540#[serde(default, rename_all = "camelCase")]
1541pub struct TransformCascadeEnvironmentV0 {
1542 pub stylesheet_source_order_base: u32,
1545 pub declarations: Vec<TransformCascadeEnvironmentDeclarationV0>,
1546}
1547
1548#[derive(Debug, Clone, Deserialize, Serialize)]
1549#[serde(rename_all = "camelCase")]
1550pub struct TransformCascadeEnvironmentDeclarationV0 {
1551 pub declaration_id: String,
1552 pub selector: String,
1553 pub property: AuthoredPropertyTextV0,
1554 pub value: String,
1555 pub origin: CascadeOriginV0,
1556 pub important: bool,
1557 #[serde(default, skip_serializing_if = "Option::is_none")]
1558 pub layer_rank: Option<i32>,
1559 #[serde(default, skip_serializing_if = "Option::is_none")]
1560 pub scope_proximity: Option<u32>,
1561 pub source_order: u32,
1562}
1563
1564impl PartialEq for TransformCascadeEnvironmentDeclarationV0 {
1565 fn eq(&self, other: &Self) -> bool {
1566 self.declaration_id == other.declaration_id
1567 && self.selector == other.selector
1568 && self
1569 .property
1570 .to_property_name()
1571 .same_as(&other.property.to_property_name())
1572 && self.value == other.value
1573 && self.origin == other.origin
1574 && self.important == other.important
1575 && self.layer_rank == other.layer_rank
1576 && self.scope_proximity == other.scope_proximity
1577 && self.source_order == other.source_order
1578 }
1579}
1580
1581impl Eq for TransformCascadeEnvironmentDeclarationV0 {}
1582
1583#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
1584#[serde(rename_all = "camelCase")]
1585pub struct TransformVendorPrefixPolicyV0 {
1586 pub webkit: bool,
1587 pub moz: bool,
1588 pub ms: bool,
1589}
1590
1591impl TransformVendorPrefixPolicyV0 {
1592 pub const fn none() -> Self {
1593 Self {
1594 webkit: false,
1595 moz: false,
1596 ms: false,
1597 }
1598 }
1599
1600 pub const fn conservative() -> Self {
1601 Self {
1602 webkit: true,
1603 moz: true,
1604 ms: true,
1605 }
1606 }
1607
1608 pub const fn is_empty(self) -> bool {
1609 !(self.webkit || self.moz || self.ms)
1610 }
1611
1612 pub fn allows_prefix(self, prefixed_name: &str) -> bool {
1613 if prefixed_name.starts_with("-webkit-") {
1614 return self.webkit;
1615 }
1616 if prefixed_name.starts_with("-moz-") {
1617 return self.moz;
1618 }
1619 if prefixed_name.starts_with("-ms-") {
1620 return self.ms;
1621 }
1622 true
1623 }
1624}
1625
1626#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1627#[serde(rename_all = "camelCase")]
1628pub struct TransformModuleEvaluationV0 {
1629 pub evaluator: String,
1630 #[serde(default, skip_serializing_if = "Option::is_none")]
1631 pub product_output_source: Option<String>,
1632 pub evaluated_css: String,
1633 #[serde(default, skip_serializing_if = "Option::is_none")]
1634 pub native_edit_output: Option<String>,
1635 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1636 pub native_replacements: Vec<TransformModuleEvaluationNativeReplacementV0>,
1637 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1638 pub native_edits: Vec<TransformModuleEvaluationNativeEditV0>,
1639 #[serde(default, skip_serializing_if = "Option::is_none")]
1640 pub oracle: Option<TransformModuleEvaluationOracleV0>,
1641}
1642
1643impl TransformModuleEvaluationV0 {
1644 pub fn declares_native_product_output(&self) -> bool {
1645 self.product_output_source
1646 .as_deref()
1647 .is_some_and(|source| source == "nativeEditOutput")
1648 }
1649
1650 pub fn oracle_allows_native_product_output(&self) -> bool {
1659 self.oracle.as_ref().is_some_and(|oracle| {
1660 oracle.mode == "oracleOnly"
1661 && oracle.divergence_count == 0
1662 && oracle.all_legacy_declaration_values_preserved
1663 })
1664 }
1665
1666 pub fn may_consume_native_product_output(&self) -> bool {
1667 self.declares_native_product_output() && self.oracle_allows_native_product_output()
1668 }
1669
1670 pub fn native_output_matches_retained_oracle(&self, native_output: &str) -> bool {
1675 self.oracle
1676 .as_ref()
1677 .is_some_and(|_| native_output == self.evaluated_css)
1678 }
1679}
1680
1681#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1682#[serde(rename_all = "camelCase")]
1683pub struct TransformModuleEvaluationNativeReplacementV0 {
1684 pub name: String,
1685 pub start: usize,
1686 pub end: usize,
1687 pub text: String,
1688 #[serde(default, skip_serializing_if = "Option::is_none")]
1689 pub rendered_value: Option<String>,
1690 pub abstract_value: AbstractCssValueV0,
1691 pub abstract_value_kind: String,
1692}
1693
1694#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1695#[serde(rename_all = "camelCase")]
1696pub struct TransformModuleEvaluationNativeEditV0 {
1697 pub start: usize,
1698 pub end: usize,
1699 pub replacement: String,
1700 pub edit_kind: String,
1701 #[serde(default, skip_serializing_if = "Option::is_none")]
1702 pub abstract_value: Option<AbstractCssValueV0>,
1703 #[serde(default, skip_serializing_if = "Option::is_none")]
1704 pub abstract_value_kind: Option<String>,
1705}
1706
1707#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
1708#[serde(default, rename_all = "camelCase")]
1709pub struct TransformModuleEvaluationOracleV0 {
1710 pub mode: String,
1711 pub product_output_source: String,
1712 pub legacy_declaration_value_count: usize,
1713 pub abstract_value_count: usize,
1714 pub exact_value_count: usize,
1715 pub raw_value_count: usize,
1716 pub bottom_value_count: usize,
1717 pub top_value_count: usize,
1718 pub divergence_count: usize,
1719 pub all_legacy_declaration_values_preserved: bool,
1720 pub native_replacement_count: usize,
1721 pub native_replacement_legacy_reflection_count: usize,
1722 pub native_replacement_legacy_unreflected_count: usize,
1723 pub native_value_reference_count: usize,
1724 pub native_resolved_value_count: usize,
1725 pub native_raw_value_count: usize,
1726 pub native_top_value_count: usize,
1727 pub native_cycle_count: usize,
1728 pub native_fuel_exhausted_count: usize,
1729 pub native_unresolved_reference_count: usize,
1730 pub native_unsupported_dynamic_count: usize,
1731}
1732
1733#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1734#[serde(rename_all = "camelCase")]
1735pub struct TransformImportInlineV0 {
1736 pub import_source: String,
1737 pub replacement_css: String,
1738}
1739
1740#[derive(Debug, Clone, PartialEq, Eq)]
1741pub struct TransformLessInlineLiteralPlaceholderV0 {
1742 pub placeholder: String,
1743 pub literal_css: String,
1744}
1745
1746#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1747#[serde(rename_all = "camelCase")]
1748pub struct TransformClassNameRewriteV0 {
1749 pub original_name: String,
1750 pub rewritten_name: String,
1751}
1752
1753#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1762#[serde(rename_all = "camelCase")]
1763#[non_exhaustive]
1764pub struct TransformModuleCssModuleContextV0 {
1765 pub module_instance: ModuleInstanceKeyV0,
1766 pub class_name_rewrites: Vec<TransformClassNameRewriteV0>,
1767 pub composes_resolutions: Vec<TransformCssModuleComposesResolutionV0>,
1768}
1769
1770impl TransformModuleCssModuleContextV0 {
1771 pub fn new(module_instance: ModuleInstanceKeyV0) -> Self {
1772 Self {
1773 module_instance,
1774 class_name_rewrites: Vec::new(),
1775 composes_resolutions: Vec::new(),
1776 }
1777 }
1778
1779 pub fn with_class_name_rewrites(
1780 mut self,
1781 class_name_rewrites: Vec<TransformClassNameRewriteV0>,
1782 ) -> Self {
1783 self.class_name_rewrites = class_name_rewrites;
1784 self
1785 }
1786
1787 pub fn with_composes_resolutions(
1788 mut self,
1789 composes_resolutions: Vec<TransformCssModuleComposesResolutionV0>,
1790 ) -> Self {
1791 self.composes_resolutions = composes_resolutions;
1792 self
1793 }
1794}
1795
1796#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1797#[serde(rename_all = "camelCase")]
1798pub struct TransformCssModuleComposesResolutionV0 {
1799 pub local_class_name: String,
1800 pub exported_class_names: Vec<String>,
1801}
1802
1803#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
1804#[serde(rename_all = "camelCase")]
1805pub struct TransformCssModuleValueResolutionV0 {
1806 pub local_name: String,
1807 pub resolved_value: String,
1808}
1809
1810#[derive(Debug, Clone, Deserialize, Serialize)]
1811#[serde(rename_all = "camelCase")]
1812pub struct TransformDesignTokenRouteV0 {
1813 pub token_name: AuthoredPropertyTextV0,
1814 pub routed_value: String,
1815}
1816
1817impl PartialEq for TransformDesignTokenRouteV0 {
1818 fn eq(&self, other: &Self) -> bool {
1819 self.token_name.to_custom_key() == other.token_name.to_custom_key()
1820 && self.routed_value == other.routed_value
1821 }
1822}
1823
1824impl Eq for TransformDesignTokenRouteV0 {}
1825
1826#[cfg(test)]
1827mod authored_property_identity_tests {
1828 use super::*;
1829
1830 #[test]
1831 fn winner_equality_affected_pair_identity_uses_sealed_property_keys() {
1832 let pair = |property: &str| TransformWinnerEqualityAffectedPairV0 {
1833 element_signature: ElementSignature::concrete(
1834 None::<String>,
1835 None::<String>,
1836 ["button"],
1837 ),
1838 property: AuthoredPropertyTextV0::new(property),
1839 };
1840
1841 assert_eq!(pair("COLOR"), pair(r"C\4f LOR"));
1842 assert_ne!(pair("--foo"), pair("--FOO"));
1843 }
1844
1845 #[test]
1846 fn execution_context_identity_uses_custom_property_keys() {
1847 let context = |property: &str| TransformExecutionContextV0 {
1848 reachable_custom_property_names: vec![AuthoredPropertyTextV0::new(property)],
1849 ..TransformExecutionContextV0::default()
1850 };
1851
1852 assert_eq!(context(r"--f\6f o"), context("--foo"));
1853 assert_ne!(context("--foo"), context("--FOO"));
1854 }
1855
1856 #[test]
1857 fn cascade_environment_declaration_identity_uses_sealed_property_keys() {
1858 let declaration = |property: &str| TransformCascadeEnvironmentDeclarationV0 {
1859 declaration_id: "declaration".to_string(),
1860 selector: ".button".to_string(),
1861 property: AuthoredPropertyTextV0::new(property),
1862 value: "red".to_string(),
1863 origin: CascadeOriginV0::Author,
1864 important: false,
1865 layer_rank: None,
1866 scope_proximity: None,
1867 source_order: 0,
1868 };
1869
1870 assert_eq!(declaration("COLOR"), declaration(r"C\4f LOR"));
1871 assert_ne!(declaration("--foo"), declaration("--FOO"));
1872 }
1873
1874 #[test]
1875 fn design_token_route_identity_uses_custom_property_keys() {
1876 let route = |name: &str| TransformDesignTokenRouteV0 {
1877 token_name: AuthoredPropertyTextV0::new(name),
1878 routed_value: "red".to_string(),
1879 };
1880
1881 assert_eq!(route(r"--f\6f o"), route("--foo"));
1882 assert_ne!(route("--foo"), route("--FOO"));
1883 }
1884}
1885
1886#[cfg(test)]
1887mod evidence_graph_tests {
1888 use super::*;
1889 use omena_cascade::{
1890 CascadeKey, CascadeValue, LayerOrdinal, OpenWorldTieEvidence, Specificity,
1891 cascade_property, normalized_layer_rank,
1892 };
1893
1894 fn winner_equality_test_declaration(
1895 id: &str,
1896 value: &str,
1897 source_order: u32,
1898 ) -> CascadeDeclaration {
1899 CascadeDeclaration {
1900 id: id.to_string(),
1901 property: omena_syntax::ident::AuthoredPropertyTextV0::new("color"),
1902 property_key: omena_syntax::ident::PropertyNameV0::standard("color").canonical_key(),
1903 value: CascadeValue::Literal(value.to_string()),
1904 key: CascadeKey::new(
1905 CascadeLevel::AuthorNormal,
1906 normalized_layer_rank(false, LayerOrdinal::new(0)),
1907 0,
1908 Specificity::new(0, 1, 0),
1909 source_order,
1910 ),
1911 open_world_tie_evidence: OpenWorldTieEvidence::NONE,
1912 specificity_exactness: omena_cascade::SpecificityExactnessV0::Exact,
1913 }
1914 }
1915
1916 #[test]
1917 fn winner_equality_witness_consumes_the_cascade_authority_outcome() -> Result<(), String> {
1918 let outcome = cascade_property(
1919 [
1920 winner_equality_test_declaration("earlier", "red", 0),
1921 winner_equality_test_declaration("later", "blue", 1),
1922 ],
1923 "color",
1924 );
1925 let witness = TransformWinnerEqualityWitnessV0::from_cascade_outcome(&outcome)
1926 .ok_or_else(|| "the closed cascade should have a definite winner".to_string())?;
1927
1928 assert_eq!(witness.winner.id, "later");
1929 assert_eq!(
1930 witness.proof,
1931 CascadeProof::from_declaration(&witness.winner)
1932 );
1933 Ok(())
1934 }
1935
1936 #[test]
1937 fn winner_equality_witness_stays_absent_for_non_definite_outcomes() {
1938 assert!(
1939 TransformWinnerEqualityWitnessV0::from_cascade_outcome(&CascadeOutcome::Top).is_none()
1940 );
1941 assert!(
1942 TransformWinnerEqualityWitnessV0::from_cascade_outcome(&CascadeOutcome::Inherit)
1943 .is_none()
1944 );
1945 }
1946
1947 #[test]
1948 fn winner_equality_trust_records_name_covered_axes() -> Result<(), serde_json::Error> {
1949 let tier = TransformSemanticGuaranteeTierV0::WinnerEqualityObserved {
1950 axes: vec![
1951 TransformWinnerEqualityAxisV0::CascadeLevel,
1952 TransformWinnerEqualityAxisV0::LayerRank,
1953 ],
1954 };
1955
1956 assert_eq!(
1957 serde_json::to_value(tier)?,
1958 serde_json::json!({
1959 "kind": "winnerEqualityObserved",
1960 "axes": ["cascadeLevel", "layerRank"]
1961 })
1962 );
1963 Ok(())
1964 }
1965
1966 #[test]
1967 fn winner_equality_absence_names_the_undriven_level() -> Result<(), serde_json::Error> {
1968 let tier = TransformSemanticGuaranteeTierV0::Absent {
1969 reasons: vec![TransformWinnerEqualityAbsenceV0 {
1970 axis: TransformWinnerEqualityAxisV0::CascadeLevel,
1971 reason: TransformWinnerEqualityAbsenceReasonV0::DriverUnavailable {
1972 level: Some(CascadeLevel::Animation),
1973 },
1974 }],
1975 };
1976
1977 assert_eq!(
1978 serde_json::to_value(tier)?,
1979 serde_json::json!({
1980 "kind": "absent",
1981 "reasons": [{
1982 "axis": "cascadeLevel",
1983 "reason": {
1984 "kind": "driverUnavailable",
1985 "level": "animation"
1986 }
1987 }]
1988 })
1989 );
1990 Ok(())
1991 }
1992
1993 #[test]
1994 fn transform_outcome_evidence_graph_preserves_public_shape() -> Result<(), serde_json::Error> {
1995 let outcome = TransformPassExecutionOutcomeV0 {
1996 pass_id: "number-compression",
1997 status: TransformPassRuntimeStatus::Applied,
1998 input_byte_len: 32,
1999 output_byte_len: 28,
2000 mutation_count: 1,
2001 provenance_preserved: true,
2002 detail: "fixture pass",
2003 };
2004
2005 let before = serde_json::to_value(&outcome)?;
2006 let node = outcome.evidence_node_seed();
2007 let graph = build_evidence_graph_from_edges_v0([node], [outcome.evidence_demand_edge()])
2008 .map_err(|_| serde::ser::Error::custom("outcome edge must target its node"))?;
2009 let after = serde_json::to_value(&outcome)?;
2010
2011 assert_eq!(before, after);
2012 assert_eq!(graph.nodes.len(), 1);
2013 assert_eq!(graph.nodes[0].key.input_identity, "number-compression");
2014 assert_eq!(graph.nodes[0].guarantee, GuaranteeKindV0::Floor);
2015 assert!(
2016 graph.nodes[0]
2017 .provenance
2018 .iter()
2019 .any(|item| item == "mutationCount:1")
2020 );
2021 Ok(())
2022 }
2023
2024 #[test]
2025 fn transform_derivation_forest_evidence_graph_preserves_public_shape()
2026 -> Result<(), serde_json::Error> {
2027 let forest = TransformProvenanceDerivationForestV0 {
2028 schema_version: "0",
2029 product: "omena-transform-passes.provenance-derivation-forest",
2030 root_count: 1,
2031 node_count: 1,
2032 nodes: vec![TransformProvenanceDerivationNodeV0 {
2033 node_index: 0,
2034 parent_index: None,
2035 pass_id: "comment-strip",
2036 status: TransformPassRuntimeStatus::Applied,
2037 input_byte_len: 48,
2038 output_byte_len: 36,
2039 source_span_start: 0,
2040 source_span_end: 12,
2041 generated_span_start: 0,
2042 generated_span_end: 0,
2043 mutation_spans: Vec::new(),
2044 mutation_count: 1,
2045 provenance_preserved: true,
2046 detail: "fixture derivation",
2047 }],
2048 };
2049
2050 let before = serde_json::to_value(&forest)?;
2051 let graph = forest
2052 .evidence_graph()
2053 .map_err(|_| serde::ser::Error::custom("forest edge must target its node"))?;
2054 let after = serde_json::to_value(&forest)?;
2055
2056 assert_eq!(before, after);
2057 assert_eq!(graph.nodes.len(), 1);
2058 assert_eq!(graph.nodes[0].key.input_identity, "comment-strip#0");
2059 assert_eq!(graph.nodes[0].guarantee, GuaranteeKindV0::Floor);
2060 Ok(())
2061 }
2062}