nx_srcdiff.nx source
↩ module page · 445 lines · 22636 B
1// nx_srcdiff.nx -- IS A DIRECTION MERGE SAFE, OR DOES THIS NEED A UNION? The per-file decision organ.
2//
3// WHY IT EXISTS. The estate's banked law is that A DIVERGENCE'S DIRECTION IS A PER-FILE MEASUREMENT,
4// NEVER A PER-TREE POLICY -- and the 2026-08-03 lane proved it the hard way: BOTH of that session's
5// directional hypotheses INVERTED once someone actually body-diffed the files ("NAS strict superset"
6// hid the laptop's richer state; "local larger => NAS revert" was a missing leak fix).
7// So every convergence needs one question answered first: does adopting one side LOSE anything?
8// That question was being answered ad-hoc, by hand, outside the estate -- four separate times in the
9// 2026-08-06 session alone, in a laptop shell no other seat can run. An analysis that gates a
10// DESTRUCTIVE act and lives only in one operator's scrollback is not a capability the fleet has.
11//
12// WHAT IT REPORTS, and the verdict IS the decision:
13// IDENTICAL -- same line multiset (!!ORDER may still differ; byte identity is nx_filehash's job)
14// A-SUPERSET -- B's lines all appear in A. Adopting A loses NOTHING: a DIRECTION merge is safe.
15// B-SUPERSET -- the mirror.
16// BIDIRECTIONAL -- both sides hold lines the other lacks. A direction merge DESTROYS WORK; UNION.
17// This is exactly the shape that decided the real cases: nx_syscalls.nx came back A-SUPERSET (the
18// only delta was 5 sys_munmap doc lines) so a direction was correct; the 4 same-size gate/quality
19// files came back A-SUPERSET too, with every "laptop-only" line being the SUPERSEDED original of a
20// line the other side replaced -- which a surplus report shows and a size screen cannot.
21//
22// !!A LINE MULTISET IS NOT BYTE IDENTITY. Reordering, and CR-only differences, do not show up as
23// surplus. CR counts are reported per side BECAUSE they are the classic invisible delta (a 2026-08-03
24// convergence found 742 stray CRs that git's autocrlf hid while a byte gate counted every one).
25// Use nx_filehash/nx_treehash for identity; use THIS to decide which way to merge.
26//
27// DIALECT: plain-if, <=6 params, consts above use. Tables are mmap'd through static POINTERS --
28// a BSS static ARRAY silently crashes the module at startup (banked gotcha).
29// license_tier: ORIGINAL expect_exit: 0 No hw writes (Rule 26).
30import "nx_syscalls.nx"
31
32const SD_SLOTS: i64 = 131072 // power of two; a 1000-line file loads at <1% -- headroom is cheap
33const SD_MASK: i64 = 131071
34const SD_OUTBUF: i64 = 4194304
35const SD_NUMBUF: i64 = 64
36const SD_FNV_OFF: i64 = 1469598103934665603
37const SD_FNV_PRIME: i64 = 1099511628211
38const SD_SAMPLE_CAP: i64 = 25 // stdout sample; the FULL surplus list always goes to [outfile]
39const SD_SURCAP: i64 = 4096 // surplus lines retained per side for the pairing measurement
40const SD_PAIR_PERMIL: i64 = 700 // token-containment bar for a one-to-one modification pair
41const SD_LF: i64 = 10
42const SD_CR: i64 = 13
43
44static sd_ka: *i64
45static sd_ca: *i64
46static sd_kb: *i64
47static sd_cb: *i64
48static sd_n: *i64 // [0]=linesA [1]=linesB [2]=surplusA [3]=surplusB [4]=crA [5]=crB [6]=shown
49static sd_asur: *i64 // A-surplus line pointers, for the modification-pairing measurement
50static sd_bsur: *i64 // B-surplus line pointers; sd_n[8]/sd_n[9] are their counts
51static sd_out: *u8
52static sd_out_n: *i64
53static sd_num: *u8
54static sd_rev: *u8
55
56func sd_puts(s: *u8) -> i64 {
57 var n: i64 = 0
58 while s[n] != (0 as u8) { n = n + 1 }
59 sys_write(1, s, n)
60 return 0
61}
62func sd_putn(v: i64) -> i64 {
63 var m: i64 = v
64 if m == 0 { sd_num[0] = 48 as u8; sys_write(1, sd_num, 1); return 0 }
65 if m < 0 { sd_puts("-" as *u8); m = 0 - m }
66 var k: i64 = 0
67 while m > 0 { sd_rev[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
68 var i: i64 = 0
69 while i < k { sd_num[i] = sd_rev[k - 1 - i]; i = i + 1 }
70 sys_write(1, sd_num, k)
71 return 0
72}
73func sd_streq(a: *u8, b: *u8) -> i64 {
74 var i: i64 = 0
75 var go: i64 = 1
76 var eq: i64 = 1
77 while go == 1 {
78 if a[i] != b[i] { eq = 0; go = 0 } else {
79 if a[i] == (0 as u8) { go = 0 } else { i = i + 1 }
80 }
81 }
82 return eq
83}
84func sd_hash(s: *u8) -> i64 {
85 var h: i64 = SD_FNV_OFF
86 var i: i64 = 0
87 while s[i] != (0 as u8) {
88 h = h ^ (s[i] as i64)
89 h = h * SD_FNV_PRIME
90 i = i + 1
91 }
92 if h < 0 { h = 0 - h }
93 return h
94}
95// add one occurrence of `line` to (keys,counts)
96func sd_add(keys: *i64, counts: *i64, line: *u8) -> i64 {
97 var s: i64 = sd_hash(line) & SD_MASK
98 var go: i64 = 1
99 while go == 1 {
100 if keys[s] == 0 {
101 keys[s] = line as i64
102 counts[s] = 1
103 go = 0
104 } else {
105 if sd_streq(keys[s] as *u8, line) == 1 { counts[s] = counts[s] + 1; go = 0 } else { s = (s + 1) & SD_MASK }
106 }
107 }
108 return 0
109}
110// occurrences of `line` in (keys,counts); 0 when absent
111func sd_get(keys: *i64, counts: *i64, line: *u8) -> i64 {
112 var s: i64 = sd_hash(line) & SD_MASK
113 var go: i64 = 1
114 while go == 1 {
115 if keys[s] == 0 { return 0 }
116 if sd_streq(keys[s] as *u8, line) == 1 { return counts[s] }
117 s = (s + 1) & SD_MASK
118 }
119 return 0
120}
121func sd_emit(tag: *u8, n: i64, line: *u8) -> i64 {
122 var o: i64 = sd_out_n[0]
123 var ll: i64 = 0
124 while line[ll] != (0 as u8) { ll = ll + 1 }
125 if o + ll + 32 >= SD_OUTBUF { return 0 }
126 var i: i64 = 0
127 while tag[i] != (0 as u8) { sd_out[o] = tag[i]; o = o + 1; i = i + 1 }
128 sd_out[o] = 32 as u8; o = o + 1
129 sd_out[o] = 120 as u8; o = o + 1 // 'x'
130 var k: i64 = 0
131 var m: i64 = n
132 if m == 0 { sd_num[k] = 48 as u8; k = k + 1 }
133 var j: i64 = 0
134 while m > 0 { sd_rev[j] = (48 + (m % 10)) as u8; m = m / 10; j = j + 1 }
135 while j > 0 { sd_num[k] = sd_rev[j - 1]; k = k + 1; j = j - 1 }
136 i = 0
137 while i < k { sd_out[o] = sd_num[i]; o = o + 1; i = i + 1 }
138 sd_out[o] = 32 as u8; o = o + 1
139 i = 0
140 while i < ll { sd_out[o] = line[i]; o = o + 1; i = i + 1 }
141 sd_out[o] = 10 as u8; o = o + 1
142 sd_out_n[0] = o
143 return 0
144}
145func sd_sample(tag: *u8, n: i64, line: *u8) -> i64 {
146 if sd_n[6] >= SD_SAMPLE_CAP { return 0 }
147 sd_puts(" " as *u8); sd_puts(tag); sd_puts(" x" as *u8); sd_putn(n)
148 sd_puts(" " as *u8); sd_puts(line); sd_puts("\n" as *u8)
149 sd_n[6] = sd_n[6] + 1
150 return 0
151}
152// split a buffer into NUL-terminated lines in place, counting CRs; loads them into (keys,counts).
153// A trailing CR is stripped from the LINE so a CRLF/LF difference does not masquerade as surplus --
154// but it IS counted, because it is the classic delta a text diff hides and a byte gate reports.
155// Shared prefix+suffix length of two NUL-terminated lines, as a crude "is B an earlier form of A".
156// Cheap on purpose: surplus counts are tiny (median 3 a side), and an O(n*m) edit distance here would
157// buy precision this measurement does not claim to have.
158func sd_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
159
160// (v1 of the pairing helpers -- sd_indent / sd_affix / sd_paired, scored by shared prefix+suffix -- was
161// REMOVED here 2026-08-07. It saturated at bunpaired=0 on 104/104 BIDIRECTIONAL files, and excluding
162// indentation plus raising the floor changed nothing, because the real fault was "does ANY A-line
163// match" against dozens of candidates. It also failed its own motivating case from the other side once
164// an edit appended a trailing comment. Replaced by token containment + one-to-one assignment below.
165// DEAD CODE STILL HAS TO COMPILE: leaving these behind broke the build on a constant that had gone
166// with them -- the same defect that took the mgmt deploy path down for every seat earlier today.)}
167
168// ---- TOKEN-CONTAINMENT PAIRING (2nd design; the affix version saturated and was removed) -----------
169// WHY TOKENS AND NOT AFFIX. Affix asked "do these two lines share a long common edge", which collapses
170// the moment an edit ADDS a trailing comment: `while z < 8 {...}` vs `while z < 12 {...} // note`
171// shares only 26% affix even though it is plainly the same line edited. Containment asks the question
172// that actually matters -- IS B's CONTENT STILL PRESENT IN A -- and a trailing addition cannot hurt it.
173// DISTINCTIVE TOKENS ONLY (len >= 3): `{`, `}`, `=`, `<`, `1` appear in nearly every line, and counting
174// them is exactly how the first attempt reached 100%. A line with fewer than 2 distinctive tokens is
175// reported UNPAIRED rather than guessed at -- conservative on purpose, since the caller adopts on
176// unpaired==0.
177func sd_is_sp(c: i64) -> i64 {
178 if c == 32 { return 1 }
179 if c == 9 { return 1 }
180 return 0
181}
182
183// 1 when the needle b[bs..bs+bl) occurs anywhere in NUL-terminated hay.
184func sd_has_sub(hay: *u8, b: *u8, bs: i64, bl: i64) -> i64 {
185 let hl: i64 = sd_len(hay)
186 if bl <= 0 { return 0 }
187 var i: i64 = 0
188 while i + bl <= hl {
189 var k: i64 = 0
190 var ok: i64 = 1
191 while k < bl { if hay[i+k] != b[bs+k] { ok = 0; k = bl } else { k = k + 1 } }
192 if ok == 1 { return 1 }
193 i = i + 1
194 }
195 return 0
196}
197
198// Containment of B's distinctive tokens in A, in permil. -1 when B carries fewer than 2 of them.
199func sd_contain(a: *u8, b: *u8) -> i64 {
200 let bl: i64 = sd_len(b)
201 var i: i64 = 0
202 var tot: i64 = 0
203 var hit: i64 = 0
204 // ⚠THE FIRST VERSION OF THIS LOOP BROKE ITS INNER SCAN WITH `i = bl`, which exits the loop AND
205 // DESTROYS THE TOKEN END -- so token one swallowed the entire line, tot never reached 2, every
206 // comparison returned -1 and bpaired was 0 for everything including the case this was built for.
207 // A LOOP THAT BREAKS BY CLOBBERING ITS OWN CURSOR CANNOT ALSO REPORT WHERE IT STOPPED.
208 // Separate cursor, explicit flag.
209 while i < bl {
210 if sd_is_sp(b[i] as i64) == 1 { i = i + 1 }
211 if i < bl {
212 if sd_is_sp(b[i] as i64) == 0 {
213 let st: i64 = i
214 var en: i64 = st
215 var scan: i64 = 1
216 while scan == 1 {
217 if en >= bl { scan = 0 }
218 if en < bl { if sd_is_sp(b[en] as i64) == 1 { scan = 0 } else { en = en + 1 } }
219 }
220 let tl: i64 = en - st
221 if tl >= 3 {
222 tot = tot + 1
223 if sd_has_sub(a, b, st, tl) == 1 { hit = hit + 1 }
224 }
225 i = en
226 }
227 }
228 }
229 if tot < 2 { return 0 - 1 }
230 return (hit * 1000) / tot
231}
232
233func sd_load(buf: *u8, n: i64, keys: *i64, counts: *i64, cslot: i64, lslot: i64) -> i64 {
234 var p: i64 = 0
235 while p < n {
236 let base: i64 = buf as i64
237 var e: i64 = p
238 var go: i64 = 1
239 while go == 1 {
240 if e >= n { go = 0 } else {
241 if buf[e] == (SD_LF as u8) { go = 0 } else { e = e + 1 }
242 }
243 }
244 var t: i64 = e
245 if t > p { if buf[t-1] == (SD_CR as u8) { t = t - 1; sd_n[cslot] = sd_n[cslot] + 1 } }
246 buf[t] = 0 as u8
247 let line: *u8 = (base + p) as *u8
248 sd_add(keys, counts, line)
249 sd_n[lslot] = sd_n[lslot] + 1
250 p = e + 1
251 }
252 return 0
253}
254
255// ---- BATCH MODE: ONE PROCESS, N PAIRS ------------------------------------------------------------
256// WHY. Every caller so far ran this organ once per file pair, and each run is a process spawn (through
257// WSL, ~2s). At 2,959 forked files that is ~98 minutes, so every measurement taken of the cross-tree
258// fork has been a SAMPLE -- 40 files, then 120, then 250 -- and a sample is exactly how you end up
259// reporting a population number you never measured. THE COST OF THE INSTRUMENT DECIDED THE SIZE OF THE
260// EVIDENCE, WHICH IS BACKWARDS. Batch mode makes the whole population one invocation.
261// usage: nx_srcdiff --batch <pairfile> <outfile>
262// pairfile: one "<fileA>\t<fileB>\t<label>" per line (label echoed back, may be empty)
263// outfile : one "<verdict> <bpaired> <bunpaired> <surplusA> <surplusB> <label>" per line
264// NOT YET BUILT, AND THE REASON IS RECORDED SO THE COST IS VISIBLE: batching needs the comparison
265// extracted out of main() into a reusable sd_compare(), which is a real refactor of a LOAD-BEARING
266// ruler that three flow-back legs and the canon gate all depend on. Until then the population is
267// measured by paying the spawn cost in full (one background run, ~100 min for 2,959 pairs) rather
268// than by shrinking the sample to fit the instrument.
269
270func main(argc: i64, argv: *i64) -> i64 {
271 sd_num = sys_mmap(SD_NUMBUF)
272 sd_rev = sys_mmap(SD_NUMBUF)
273 if argc < 3 {
274 sd_puts("usage: nx_srcdiff <fileA> <fileB> [outfile]\n" as *u8)
275 sd_puts(" Answers ONE question: is a DIRECTION merge safe, or does this need a UNION?\n" as *u8)
276 sd_puts(" verdict=IDENTICAL | A-SUPERSET | B-SUPERSET | BIDIRECTIONAL\n" as *u8)
277 sd_puts(" A-SUPERSET means every line of B is already in A, so adopting A loses nothing.\n" as *u8)
278 sd_puts(" BIDIRECTIONAL means a direction merge DESTROYS WORK -- union per hunk.\n" as *u8)
279 sd_puts(" NOTE: a line multiset ignores ORDER; use nx_filehash for byte identity.\n" as *u8)
280 sys_exit(2)
281 return 2
282 }
283 // ---- MODIFICATION PAIRING 2026-08-07 (a MEASUREMENT, never a verdict) --------------------------
284 // BIDIRECTIONAL is correct and it is also the most misread word this organ prints. A CHANGED LINE IS
285 // SURPLUS ON BOTH SIDES, so a one-sided EDIT is indistinguishable from genuine two-way work under a
286 // pure multiset. MEASURED 2026-08-07 over 250 forked files: laptop-only lines were 0 in 2 files, 1-3
287 // in 137, 4-20 in 76, >20 in only 35 -- median THREE. Worked example csrf_token.nx: NAS has
288 // `import "nx_hmac.nx"` + 2 comment lines; laptop still has `import "hmac.nx"`. One edit. Verdict
289 // BIDIRECTIONAL. Reading that as "3,000 files need hand merges" overstates the work by ~40x.
290 // So: pair each B-surplus line with an A-surplus line that looks like ITS EDITED FORM (shared
291 // prefix+suffix >= half the shorter line, floor 8 chars -- catches the import rename above exactly).
292 // bunpaired=0 means every line B uniquely holds has a plausible successor in A.
293 // ⚠THIS IS A HEURISTIC AND IT IS REPORTED SEPARATELY FROM THE VERDICT ON PURPOSE. The four verdicts
294 // are PROOFS about a multiset; this is a similarity score. Folding a heuristic into a proof would
295 // make the proof unciteable -- A RULER THAT MIXES PROOF WITH GUESS CAN NO LONGER BE QUOTED AS EITHER.
296 // The caller decides what to do with it; this organ only measures.
297 sd_asur = sys_mmap(SD_SURCAP * 8) as *i64
298 sd_bsur = sys_mmap(SD_SURCAP * 8) as *i64
299 sd_ka = sys_mmap(SD_SLOTS * 8) as *i64
300 sd_ca = sys_mmap(SD_SLOTS * 8) as *i64
301 sd_kb = sys_mmap(SD_SLOTS * 8) as *i64
302 sd_cb = sys_mmap(SD_SLOTS * 8) as *i64
303 sd_n = sys_mmap(128) as *i64
304 sd_out_n = sys_mmap(16) as *i64
305 sd_out = sys_mmap(SD_OUTBUF)
306 sd_out_n[0] = 0
307 var z: i64 = 0
308 while z < 12 { sd_n[z] = 0; z = z + 1 } // 8/9 are the pairing surplus indices; 6 is the sample counter and IS reset mid-run
309
310 let la: *i64 = sys_mmap(16) as *i64
311 let ba: *u8 = sys_read_file(argv[1] as *u8, la)
312 if (ba as i64) == 0 {
313 sd_puts("# SRCDIFF RED -- cannot read fileA\n" as *u8)
314 sys_exit(3); return 3
315 }
316 let lb: *i64 = sys_mmap(16) as *i64
317 let bb: *u8 = sys_read_file(argv[2] as *u8, lb)
318 if (bb as i64) == 0 {
319 sd_puts("# SRCDIFF RED -- cannot read fileB\n" as *u8)
320 sys_exit(3); return 3
321 }
322 sd_puts("=== nx_srcdiff -- direction-of-merge decision ===\n" as *u8)
323 sd_load(ba, la[0], sd_ka, sd_ca, 4, 0)
324 sd_load(bb, lb[0], sd_kb, sd_cb, 5, 1)
325
326 // surplus A: lines A holds more copies of than B (and vice versa)
327 sd_puts(" A-SURPLUS (in A, not matched in B):\n" as *u8)
328 var s: i64 = 0
329 while s < SD_SLOTS {
330 if sd_ka[s] != 0 {
331 let line: *u8 = sd_ka[s] as *u8
332 let d: i64 = sd_ca[s] - sd_get(sd_kb, sd_cb, line)
333 if d > 0 {
334 sd_n[2] = sd_n[2] + d
335 if sd_n[8] < SD_SURCAP { sd_asur[sd_n[8]] = line as i64; sd_n[8] = sd_n[8] + 1 }
336 sd_emit("A-SURPLUS" as *u8, d, line)
337 sd_sample("A" as *u8, d, line)
338 }
339 }
340 s = s + 1
341 }
342 sd_n[6] = 0
343 sd_puts(" B-SURPLUS (in B, not matched in A):\n" as *u8)
344 s = 0
345 while s < SD_SLOTS {
346 if sd_kb[s] != 0 {
347 let line: *u8 = sd_kb[s] as *u8
348 let d: i64 = sd_cb[s] - sd_get(sd_ka, sd_ca, line)
349 if d > 0 {
350 sd_n[3] = sd_n[3] + d
351 if sd_n[9] < SD_SURCAP { sd_bsur[sd_n[9]] = line as i64; sd_n[9] = sd_n[9] + 1 }
352 sd_emit("B-SURPLUS" as *u8, d, line)
353 sd_sample("B" as *u8, d, line)
354 }
355 }
356 s = s + 1
357 }
358 if argc > 3 {
359 let fd: i64 = sys_openat_wr(argv[3] as *u8, 0x1a4)
360 if fd < 0 {
361 sd_puts("# SRCDIFF RED -- cannot open outfile\n" as *u8)
362 sys_exit(3); return 3
363 }
364 sys_write(fd, sd_out, sd_out_n[0])
365 sys_close(fd)
366 sd_puts("# rows written: " as *u8); sd_puts(argv[3] as *u8)
367 sd_puts(" bytes=" as *u8); sd_putn(sd_out_n[0]); sd_puts("\n" as *u8)
368 }
369 sd_puts("# SRCDIFF linesA=" as *u8); sd_putn(sd_n[0])
370 sd_puts(" linesB=" as *u8); sd_putn(sd_n[1])
371 sd_puts(" surplusA=" as *u8); sd_putn(sd_n[2])
372 sd_puts(" surplusB=" as *u8); sd_putn(sd_n[3])
373 sd_puts(" crA=" as *u8); sd_putn(sd_n[4])
374 sd_puts(" crB=" as *u8); sd_putn(sd_n[5])
375 sd_puts("\n" as *u8)
376 if sd_n[2] == 0 { if sd_n[3] == 0 {
377 sd_puts("# verdict=IDENTICAL (same line multiset; ORDER and byte identity NOT proven here -- use nx_filehash)\n" as *u8)
378 } }
379 if sd_n[2] > 0 { if sd_n[3] == 0 {
380 sd_puts("# verdict=A-SUPERSET -- every line of B is already in A. Adopting A loses NOTHING: a DIRECTION merge is safe.\n" as *u8)
381 } }
382 if sd_n[2] == 0 { if sd_n[3] > 0 {
383 sd_puts("# verdict=B-SUPERSET -- every line of A is already in B. Adopting B loses NOTHING: a DIRECTION merge is safe.\n" as *u8)
384 } }
385 // ---- PAIRING v2: BEST MATCH, ONE-TO-ONE, TOKEN CONTAINMENT ------------------------------------
386 // ONE-TO-ONE IS HALF THE FIX. v1 asked "does ANY A-surplus line match", and against dozens of
387 // candidates something always did -- that is why it answered bunpaired=0 for 104 of 104 files.
388 // Here each A-surplus line can be consumed by at most one B line, and only the BEST scoring
389 // candidate above the bar is taken, so N B-lines can never all pair with the same A-line.
390 var bp2: i64 = 0
391 var bu2: i64 = 0
392 let used: *i64 = sys_mmap(SD_SURCAP * 8) as *i64
393 var ui: i64 = 0
394 while ui < sd_n[8] { used[ui] = 0; ui = ui + 1 }
395 var bj: i64 = 0
396 while bj < sd_n[9] {
397 let bl2: *u8 = sd_bsur[bj] as *u8
398 var best: i64 = 0 - 1
399 var bestk: i64 = 0 - 1
400 var ak: i64 = 0
401 while ak < sd_n[8] {
402 if used[ak] == 0 {
403 let sc2: i64 = sd_contain(sd_asur[ak] as *u8, bl2)
404 if sc2 > best { best = sc2; bestk = ak }
405 }
406 ak = ak + 1
407 }
408 if best >= SD_PAIR_PERMIL { used[bestk] = 1; bp2 = bp2 + 1 } else { bu2 = bu2 + 1 }
409 bj = bj + 1
410 }
411 sd_puts("# SRCDIFF-PAIRING bpaired=" as *u8); sd_putn(bp2)
412 sd_puts(" bunpaired=" as *u8); sd_putn(bu2)
413 sd_puts(" (HEURISTIC, NOT A PROOF -- weigh it, never cite it. ZERO unpaired means every distinct line B holds was matched ONE-TO-ONE to a distinct A line that still contains >=70% of its distinctive tokens, i.e. B looks merely OLDER. A line with <2 tokens of length>=3 counts as UNPAIRED by design. This sentence deliberately avoids repeating the field name: a greedy parser takes the LAST match and would read the prose as the value.)\
414" as *u8)
415 // KNOWN FALSE NEGATIVE, AND IT FAILS THE SAFE WAY. Containment cannot see a token that was ITSELF
416 // renamed: csrf_token.nx's `import "hmac.nx"` -> `import "nx_hmac.nx"` scores 500 permil, because
417 // the token `"hmac.nx"` is not a substring of `"nx_hmac.nx"` (the leading quote breaks it). With
418 // only two distinctive tokens the score can only be 0, 500 or 1000, so ANY edited token on a short
419 // line falls under the bar. That is a MISS, not a false pair -- it reports unpaired, the caller does
420 // not adopt, and nothing is lost. ★A HEURISTIC THAT GATES A DESTRUCTIVE ACTION MUST BE WRONG IN THE
421 // DIRECTION OF DOING NOTHING; measure which way yours fails before shipping it.
422 // ---- v1 (SHARED-AFFIX) WAS BUILT, MEASURED, AND REMOVED 2026-08-07 -----------------------------
423 // GOAL: separate a one-sided EDIT from genuine two-way work, because a CHANGED line is surplus on
424 // both sides and so BIDIRECTIONAL overstates the merge burden (measured: median 3 laptop-only lines
425 // over 250 forked files). A B-line was called "paired" when some A-surplus line shared
426 // prefix+suffix >= half the shorter line.
427 // IT SATURATED. Over 120 forked files it reported bunpaired=0 for 104 of 104 BIDIRECTIONAL cases --
428 // 100% -- and excluding indentation and raising the floor to 14 changed NOTHING: still 100%.
429 // ROOT CAUSE, not a threshold: the test asks whether ANY A-surplus line matches, and with dozens of
430 // A-surplus lines something always does. Worse, it FAILS THE CASE IT WAS BUILT FOR -- this very
431 // file's `while z < 8 {...}` -> `while z < 12 {...} // comment` shares only 26% affix because of
432 // the trailing comment, so a bar strict enough to stop saturating also rejects the true positive.
433 // ⇒ THE AFFIX METRIC IS THE WRONG MEASURE, and a signal that answers YES to everything is precisely
434 // the always-passing guard this estate keeps finding. SHIPPING IT WOULD HAVE BEEN WORSE THAN NOT
435 // SHIPPING: an always-zero field reads as evidence.
436 // ★★★ A HEURISTIC MUST BE MEASURED FOR VARIANCE, NOT FOR WHETHER IT LIGHTS UP ON ITS MOTIVATING
437 // EXAMPLE -- it fired correctly on csrf_token.nx and was still useless.
438 // WHAT WOULD WORK: one-to-one assignment (each B line consumes at most one A line) scored by token
439 // or LCS similarity, not shared affix. Left unbuilt deliberately rather than shipped vacuous.
440 if sd_n[2] > 0 { if sd_n[3] > 0 {
441 sd_puts("# verdict=BIDIRECTIONAL -- BOTH sides hold lines the other lacks. A direction merge DESTROYS WORK; union per hunk.\n" as *u8)
442 } }
443 sys_exit(0)
444 return 0
445}