Skip to main content

sim_lib_class/
characterization.rs

1//! Canonical `CHARACTERIZE_1` class-semantic scenarios.
2
3#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4pub enum FailureMode {
5    UnknownParent,
6    DuplicateParent,
7    InconsistentC3,
8    ParentCycle,
9    ReadConstructorMissing,
10    ReadShapeMismatch,
11}
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub enum ScenarioKind {
15    C3Resolution,
16    DeclaredParentTraversal,
17    SubclassTest,
18    ReadConstruction,
19    Failure(FailureMode),
20}
21
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub enum ExpectedOutcome {
24    Linearization(&'static [&'static str]),
25    Traversal(&'static [&'static str]),
26    Subclass(bool),
27    Constructed(&'static str),
28    Rejected(&'static str),
29}
30
31/// One canonical scenario. `canonical` is the complete stable capture payload.
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub struct CharacterizationScenario {
34    pub id: &'static str,
35    pub kind: ScenarioKind,
36    pub canonical: &'static str,
37    pub expected: ExpectedOutcome,
38}
39
40pub const fn characterization_scenarios() -> &'static [CharacterizationScenario] {
41    &[
42        CharacterizationScenario {
43            id: "characterize-1/c3-diamond",
44            kind: ScenarioKind::C3Resolution,
45            canonical: "class O(); class A(O); class B(O); class C(A,B)",
46            expected: ExpectedOutcome::Linearization(&["C", "A", "B", "O"]),
47        },
48        CharacterizationScenario {
49            id: "characterize-1/declared-parent-depth-first",
50            kind: ScenarioKind::DeclaredParentTraversal,
51            canonical: "class Root(); class Left(Root); class Right(Root); class Leaf(Left,Right)",
52            expected: ExpectedOutcome::Traversal(&["Left", "Root", "Right", "Root"]),
53        },
54        CharacterizationScenario {
55            id: "characterize-1/subclass-transitive",
56            kind: ScenarioKind::SubclassTest,
57            canonical: "class Root(); class Middle(Root); class Leaf(Middle); subclass(Leaf,Root)",
58            expected: ExpectedOutcome::Subclass(true),
59        },
60        CharacterizationScenario {
61            id: "characterize-1/subclass-unrelated",
62            kind: ScenarioKind::SubclassTest,
63            canonical: "class Left(); class Right(); subclass(Left,Right)",
64            expected: ExpectedOutcome::Subclass(false),
65        },
66        CharacterizationScenario {
67            id: "characterize-1/read-construction",
68            kind: ScenarioKind::ReadConstruction,
69            canonical: "class Point(x:i64,y:i64); read #(Point 3 5)",
70            expected: ExpectedOutcome::Constructed("Point{x=3,y=5}"),
71        },
72        CharacterizationScenario {
73            id: "characterize-1/fail-unknown-parent",
74            kind: ScenarioKind::Failure(FailureMode::UnknownParent),
75            canonical: "class Child(Missing)",
76            expected: ExpectedOutcome::Rejected("class/unknown-parent"),
77        },
78        CharacterizationScenario {
79            id: "characterize-1/fail-duplicate-parent",
80            kind: ScenarioKind::Failure(FailureMode::DuplicateParent),
81            canonical: "class Child(Base,Base)",
82            expected: ExpectedOutcome::Rejected("class/duplicate-parent"),
83        },
84        CharacterizationScenario {
85            id: "characterize-1/fail-inconsistent-c3",
86            kind: ScenarioKind::Failure(FailureMode::InconsistentC3),
87            canonical: "class A(X,Y); class B(Y,X); class Z(A,B)",
88            expected: ExpectedOutcome::Rejected("class/inconsistent-c3"),
89        },
90        CharacterizationScenario {
91            id: "characterize-1/fail-parent-cycle",
92            kind: ScenarioKind::Failure(FailureMode::ParentCycle),
93            canonical: "class A(B); class B(A)",
94            expected: ExpectedOutcome::Rejected("class/parent-cycle"),
95        },
96        CharacterizationScenario {
97            id: "characterize-1/fail-read-constructor-missing",
98            kind: ScenarioKind::Failure(FailureMode::ReadConstructorMissing),
99            canonical: "class Opaque(); read #(Opaque)",
100            expected: ExpectedOutcome::Rejected("class/read-constructor-missing"),
101        },
102        CharacterizationScenario {
103            id: "characterize-1/fail-read-shape",
104            kind: ScenarioKind::Failure(FailureMode::ReadShapeMismatch),
105            canonical: "class Point(x:i64,y:i64); read #(Point three 5)",
106            expected: ExpectedOutcome::Rejected("class/read-shape-mismatch"),
107        },
108    ]
109}
110
111/// Stable 256-bit identity over the schema, id, input, and expected observation.
112pub fn scenario_content_id(scenario: &CharacterizationScenario) -> [u8; 32] {
113    let observation = format!("{:?}", scenario.expected);
114    let fields = [
115        b"sim.class-characterization/v1".as_slice(),
116        scenario.id.as_bytes(),
117        scenario.canonical.as_bytes(),
118        observation.as_bytes(),
119    ];
120    let mut output = [0_u8; 32];
121    for lane in 0..4 {
122        let mut hash = 0xcbf29ce484222325_u64 ^ (lane as u64).wrapping_mul(0x9e3779b97f4a7c15);
123        for field in fields {
124            for byte in field {
125                hash ^= u64::from(*byte);
126                hash = hash.wrapping_mul(0x100000001b3);
127            }
128            hash ^= 0xff;
129            hash = hash.wrapping_mul(0x100000001b3);
130        }
131        output[lane * 8..(lane + 1) * 8].copy_from_slice(&hash.to_be_bytes());
132    }
133    output
134}