nx_token_merge_test.nx source
↩ module page · 185 lines · 7524 B
1// nx_token_merge_test.nx -- smoke for H8 token merging plan.
2
3import "nx_syscalls.nx"
4import "nx_token_merge.nx"
5
6func main() -> i64 {
7 // ----- 1. Empty-plan construction -----
8 let p: *NxTokenMergePlan = nx_token_merge_plan_new(16)
9 if nx_token_merge_plan_is_valid(p) != 1 { return 1 }
10 if nx_token_merge_n_tokens(p) != 16 { return 2 }
11 if nx_token_merge_n_merged(p) != 0 { return 3 }
12 if nx_token_merge_n_kept(p) != 16 { return 4 }
13 // Every token is its own root.
14 var i: i64 = 0
15 while i < 16 {
16 if nx_token_merge_target_for(p, i) != i { return 5 }
17 if nx_token_merge_is_kept(p, i) != 1 { return 6 }
18 i = i + 1
19 }
20 if nx_token_merge_reduction_q16(p) != 0 { return 7 }
21
22 // ----- 2. Apply 3 non-conflicting merges -----
23 // sorted_pairs layout: 3 i64 per pair (left, right, score).
24 let pairs: *i64 = (sys_mmap(256)) as *i64
25 // Pair 0: (0, 1, score 1000)
26 pairs[0] = 0
27 pairs[1] = 1
28 pairs[2] = 1000
29 // Pair 1: (2, 3, 900)
30 pairs[3] = 2
31 pairs[4] = 3
32 pairs[5] = 900
33 // Pair 2: (4, 5, 800)
34 pairs[6] = 4
35 pairs[7] = 5
36 pairs[8] = 800
37 let merged: i64 = nx_token_merge_apply(p, pairs, 3, 3)
38 if merged != 3 { return 8 }
39 if nx_token_merge_n_merged(p) != 3 { return 9 }
40 if nx_token_merge_n_kept(p) != 13 { return 10 }
41 // Token 1 -> root 0; token 3 -> root 2; token 5 -> root 4.
42 if nx_token_merge_target_for(p, 1) != 0 { return 11 }
43 if nx_token_merge_target_for(p, 3) != 2 { return 12 }
44 if nx_token_merge_target_for(p, 5) != 4 { return 13 }
45 // Roots and unmentioned tokens are kept.
46 if nx_token_merge_is_kept(p, 0) != 1 { return 14 }
47 if nx_token_merge_is_kept(p, 2) != 1 { return 15 }
48 if nx_token_merge_is_kept(p, 4) != 1 { return 16 }
49 if nx_token_merge_is_kept(p, 6) != 1 { return 17 }
50 if nx_token_merge_is_kept(p, 1) != 0 { return 18 }
51
52 // Reduction ratio: 3/16 in Q16 = 12288
53 if nx_token_merge_reduction_q16(p) != 12288 { return 19 }
54
55 // ----- 3. Conflicting pair skipped -----
56 let p2: *NxTokenMergePlan = nx_token_merge_plan_new(8)
57 // Pair 0: (0, 1) -- merges
58 pairs[0] = 0
59 pairs[1] = 1
60 pairs[2] = 99
61 // Pair 1: (0, 2) -- 0 is still root but the priority pair already
62 // claimed 0; in V1 we want CONFLICTS to skip, so (0, 2) where 0 is
63 // STILL root and 2 is fresh -- this is actually NOT a conflict
64 // under V1. Change to (1, 2) where 1 is no longer root.
65 pairs[3] = 1
66 pairs[4] = 2
67 pairs[5] = 98
68 // Pair 2: (3, 4) -- fresh, merges
69 pairs[6] = 3
70 pairs[7] = 4
71 pairs[8] = 97
72 let merged2: i64 = nx_token_merge_apply(p2, pairs, 3, 3)
73 if merged2 != 2 { return 20 }
74 if nx_token_merge_n_merged(p2) != 2 { return 21 }
75 // Token 2 stayed root because its conflict pair was skipped.
76 if nx_token_merge_is_kept(p2, 2) != 1 { return 22 }
77
78 // ----- 4. target_merges caps actual merges -----
79 let p3: *NxTokenMergePlan = nx_token_merge_plan_new(8)
80 pairs[0] = 0
81 pairs[1] = 1
82 pairs[2] = 99
83 pairs[3] = 2
84 pairs[4] = 3
85 pairs[5] = 98
86 pairs[6] = 4
87 pairs[7] = 5
88 pairs[8] = 97
89 // 3 pairs available but only ask for 1.
90 let merged3: i64 = nx_token_merge_apply(p3, pairs, 3, 1)
91 if merged3 != 1 { return 23 }
92 if nx_token_merge_n_merged(p3) != 1 { return 24 }
93 // The first pair (top-score) wins.
94 if nx_token_merge_target_for(p3, 1) != 0 { return 25 }
95 // Subsequent pairs stay roots.
96 if nx_token_merge_is_kept(p3, 3) != 1 { return 26 }
97 if nx_token_merge_is_kept(p3, 5) != 1 { return 27 }
98
99 // ----- 5. Idempotent re-apply -----
100 // Calling apply with an already-merged pair is a no-op.
101 let merged3b: i64 = nx_token_merge_apply(p3, pairs, 1, 1) // try (0,1) again
102 if merged3b != 0 { return 28 } // nothing more to do; both touched
103
104 // ----- 6. Exhausted pairs returns fewer than requested -----
105 let p4: *NxTokenMergePlan = nx_token_merge_plan_new(8)
106 pairs[0] = 0
107 pairs[1] = 1
108 pairs[2] = 99
109 let merged4: i64 = nx_token_merge_apply(p4, pairs, 1, 5)
110 if merged4 != 1 { return 29 }
111
112 // ----- 7. Out-of-bound indices in pairs are skipped, not crashed -----
113 let p5: *NxTokenMergePlan = nx_token_merge_plan_new(4)
114 pairs[0] = 0
115 pairs[1] = 99 // out of bounds
116 pairs[2] = 99
117 pairs[3] = 1
118 pairs[4] = 2
119 pairs[5] = 98
120 let merged5: i64 = nx_token_merge_apply(p5, pairs, 2, 5)
121 if merged5 != 1 { return 30 }
122 if nx_token_merge_is_kept(p5, 0) != 1 { return 31 }
123
124 // ----- 8. Self-merge (left == right) skipped -----
125 let p6: *NxTokenMergePlan = nx_token_merge_plan_new(4)
126 pairs[0] = 2
127 pairs[1] = 2
128 pairs[2] = 99
129 let merged6: i64 = nx_token_merge_apply(p6, pairs, 1, 5)
130 if merged6 != 0 { return 32 }
131 if nx_token_merge_is_kept(p6, 2) != 1 { return 33 }
132
133 // ----- 9. Bad inputs -----
134 let null_p: *i64 = (0 as i64) as *i64
135 if nx_token_merge_apply(p, null_p, 1, 1) != (0 - NX_TOMERGE_BAD_INPUT) { return 34 }
136 if nx_token_merge_apply(p, pairs, -1, 1) != (0 - NX_TOMERGE_BAD_INPUT) { return 35 }
137 if nx_token_merge_apply(p, pairs, 1, -1) != (0 - NX_TOMERGE_BAD_INPUT) { return 36 }
138
139 // ----- 10. Bad plan_new inputs -----
140 if (nx_token_merge_plan_new(0) as i64) != 0 { return 37 }
141 if (nx_token_merge_plan_new(-1) as i64) != 0 { return 38 }
142 if (nx_token_merge_plan_new(NX_TOMERGE_MAX_TOKENS + 1) as i64) != 0 { return 39 }
143
144 // ----- 11. Out-of-range accessors -----
145 if nx_token_merge_target_for(p, -1) != (0 - NX_TOMERGE_BAD_INPUT) { return 40 }
146 if nx_token_merge_target_for(p, 16) != (0 - NX_TOMERGE_BAD_INPUT) { return 41 }
147 if nx_token_merge_is_kept(p, -1) != (0 - NX_TOMERGE_BAD_INPUT) { return 42 }
148 if nx_token_merge_is_kept(p, 16) != (0 - NX_TOMERGE_BAD_INPUT) { return 43 }
149
150 // ----- 12. Tamper -----
151 let tamper_p: *NxTokenMergePlan = nx_token_merge_plan_new(4)
152 tamper_p.canary_post = 0xDEADBEEF
153 if nx_token_merge_plan_is_valid(tamper_p) != 0 { return 44 }
154 if nx_token_merge_apply(tamper_p, pairs, 1, 1) != (0 - NX_TOMERGE_TAMPER) { return 45 }
155 if nx_token_merge_target_for(tamper_p, 0) != (0 - NX_TOMERGE_TAMPER) { return 46 }
156 if nx_token_merge_is_kept(tamper_p, 0) != (0 - NX_TOMERGE_TAMPER) { return 47 }
157 if nx_token_merge_n_kept(tamper_p) != -1 { return 48 }
158 if nx_token_merge_n_merged(tamper_p) != -1 { return 49 }
159 if nx_token_merge_n_tokens(tamper_p) != -1 { return 50 }
160 if nx_token_merge_reduction_q16(tamper_p) != -1 { return 51 }
161
162 // ----- 13. Sealed-enum verdict gates -----
163 if nx_tomerge_verdict_is_valid(NX_TOMERGE_OK) != 1 { return 52 }
164 if nx_tomerge_verdict_is_valid(NX_TOMERGE_TAMPER) != 1 { return 53 }
165 if nx_tomerge_verdict_is_valid(-1) != 0 { return 54 }
166 if nx_tomerge_verdict_is_valid(NX_TOMERGE_N_VERDICTS) != 0 { return 55 }
167
168 // ----- 14. Root-invariant (no chain length > 1 in V1) -----
169 // After our applied merges, every assignment[idx] either == idx
170 // OR points to a root. Verify on p (16 tokens, 3 merges done above).
171 var idx: i64 = 0
172 while idx < p.n_tokens {
173 let tgt: i64 = p.assignment[idx]
174 if tgt != idx {
175 // tgt must itself be a root.
176 if p.assignment[tgt] != tgt { return 56 }
177 }
178 idx = idx + 1
179 }
180
181 // ----- 15. n_kept + n_merged == n_tokens invariant -----
182 if (nx_token_merge_n_kept(p) + nx_token_merge_n_merged(p)) != nx_token_merge_n_tokens(p) { return 57 }
183
184 return 0
185}