code wiki / (root) / nx_srcdiff.nx

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}