code wiki / _hdl_build / nx_collision_plan.nx
nx_collision_plan.nx source
↩ module page · 114 lines · 6638 B
1// nx_collision_plan.nx -- the RESOLUTION PROPOSER: mechanizes the careful merge method for each shadow
2// collision so the team can resolve sprawl without hand-judging every pair (and without ever losing a
3// capability). For a shadowed basename it reads BOTH copies (runtime/<n> = A, runtime/_hdl_build/<n> = B),
4// extracts each copy's FUNCTION-NAME SET, and from the set relationship proposes the resolution:
5// shared==0 -> CODE 0 RENAME_DISTINCT : disjoint = two DIFFERENT capabilities sharing
6// a name -> rename both to clear names (GROWTH, like nx_extract vs nx_func_extract).
7// shared>0, onlyA==0, onlyB==0 -> CODE 1 KEEP_NEWER_GEN : same func-set, different bytes = the SAME
8// capability in two GENERATIONS -> keep the _hdl_build (probe-first) canon, retire the old runtime gen.
9// shared>0, onlyA==0, onlyB>0 -> CODE 2 RETIRE_A_SUBSET : B is the SUPERSET and B already RUNS (probe-first) = correct -> retire the runtime subset A.
10// shared>0, onlyA>0, onlyB==0 -> CODE 3 CAPABILITY-LOSS!: A (runtime) is the SUPERSET but the LESS-capable
11// B shadows it -> we are SILENTLY LOSING A's extra funcs -> must merge A's extras into B (or promote A). The highest-value catch.
12// shared>0, onlyA>0, onlyB>0 -> CODE 4 MERGE_UNION : each copy has unique funcs -> merge the union into one.
13// Toolchain-critical organs (nx_link = the ELF linker, never-brick #26) are flagged REVIEW regardless -- the
14// proposer NEVER auto-executes; it emits a plan the warden/operator gates. READ-ONLY (never-brick by construction).
15// RESIDUAL CAVEAT (honest): the program-vs-library signal is "has a top-level main". A LIBRARY that also carries
16// a self-test main (e.g. nx_research_ledger, prints GREEN x2) looks like a program, so a library-vs-report pair
17// can still slip through as MERGE_UNION. Full disambiguation needs IMPORT-ANALYSIS (does anything import it and
18// call its exported funcs?) -- the next rung; for now the benchmark/human layer catches that edge. license_tier: ORIGINAL
19import "nx_janitor_dupname.nx"
20import "nx_syscalls.nx"
21const K_MAGIC_1024: i64 = 1024
22const K_MAGIC_1048576: i64 = 1048576
23const K_MAGIC_4000: i64 = 4000
24
25// identifier char: [0-9A-Za-z_]
26func crp_is_ident(ch: u8) -> i64 {
27 let c: i64 = ch as i64
28 if c>=48 { if c<=57 { return 1 } }
29 if c>=65 { if c<=90 { return 1 } }
30 if c>=97 { if c<=122 { return 1 } }
31 if c==95 { return 1 }
32 return 0
33}
34
35// extract every top-level "func NAME" basename into names (NUL-term) + noff[k]=start. returns count.
36func crp_extract_funcs(buf: *u8, len: i64, names: *u8, noff: *i64, maxn: i64) -> i64 {
37 var k: i64=0; noff[0]=0; var i: i64=0
38 while i+5 <= len {
39 var hit: i64=0
40 if buf[i]==(102 as u8) { if buf[i+1]==(117 as u8) { if buf[i+2]==(110 as u8) { if buf[i+3]==(99 as u8) { if buf[i+4]==(32 as u8) {
41 if i==0 { hit=1 } else { if buf[i-1]==(10 as u8) { hit=1 } }
42 } } } } }
43 if hit==1 {
44 var p: i64=i+5
45 var sp: i64=1
46 while sp==1 { if p<len { if buf[p]==(32 as u8) { p=p+1 } else { sp=0 } } else { sp=0 } }
47 let start: i64=noff[k]; var c: i64=0; var rd: i64=1
48 while rd==1 { if p<len { if crp_is_ident(buf[p])==1 { names[start+c]=buf[p]; c=c+1; p=p+1 } else { rd=0 } } else { rd=0 } }
49 names[start+c]=0 as u8
50 if c>0 { if k<maxn { noff[k+1]=start+c+1; k=k+1 } }
51 i=p
52 }
53 i=i+1
54 }
55 return k
56}
57
58func crp_name_in(name: *u8, names: *u8, noff: *i64, count: i64) -> i64 {
59 var j: i64=0
60 while j<count { if jdn_streq(name, (names as i64 + noff[j]) as *u8)==1 { return 1 } j=j+1 }
61 return 0
62}
63// out[0]=shared out[1]=onlyA out[2]=onlyB
64func crp_setcmp(na: *u8, oa: *i64, ca: i64, nb: *u8, ob: *i64, cb: i64, out: *i64) -> i64 {
65 var shared: i64=0; var onlyA: i64=0; var i: i64=0
66 while i<ca { if crp_name_in((na as i64+oa[i]) as *u8, nb,ob,cb)==1 { shared=shared+1 } else { onlyA=onlyA+1 } i=i+1 }
67 var onlyB: i64=0; var j: i64=0
68 while j<cb { if crp_name_in((nb as i64+ob[j]) as *u8, na,oa,ca)==0 { onlyB=onlyB+1 } j=j+1 }
69 out[0]=shared; out[1]=onlyA; out[2]=onlyB; return 0
70}
71
72func crp_is_toolchain(name: *u8) -> i64 {
73 if jdn_streq(name, "nx_link.nx\x00" as *u8)==1 { return 1 }
74 if jdn_streq(name, "nx_asm.nx\x00" as *u8)==1 { return 1 }
75 if jdn_streq(name, "nx_cc.nx\x00" as *u8)==1 { return 1 }
76 return 0
77}
78
79// the resolution decision from the set relationship (see header).
80func crp_classify(shared: i64, onlyA: i64, onlyB: i64) -> i64 {
81 if shared==0 { return 0 }
82 if onlyA==0 { if onlyB==0 { return 1 } else { return 2 } }
83 if onlyB==0 { return 3 }
84 return 4
85}
86
87// CODE 5 DISTINCT_KIND: one copy is a runnable PROGRAM (has a top-level `main`), the other an imported LIBRARY
88// (no main). They are different KINDS sharing a name -- an incidental helper overlap (e.g. g_puts) can fool the
89// name-set classifier into MERGE/SUBSET, but a program and a library must NOT be merged; rename the mis-named one.
90// This kind-mismatch OVERRIDES the set relationship. (Caught the real nx_research_ledger case: RESEARCH_MEMORY
91// library shadowed by an integrated-research REPORT program.)
92func crp_classify2(shared: i64, onlyA: i64, onlyB: i64, hasMainA: i64, hasMainB: i64) -> i64 {
93 if hasMainA != hasMainB { return 5 }
94 return crp_classify(shared, onlyA, onlyB)
95}
96
97// plan ONE shadowed basename. out[0]=shared out[1]=onlyA out[2]=onlyB out[3]=cntA out[4]=cntB.
98// caller supplies reusable buffers (ba/bb >=1MB, na/nb >=64KB, oa/ob >=4096 slots). returns CODE 0..4, or -1 read err.
99func crp_plan_one(name: *u8, ba: *u8, bb: *u8, na: *u8, oa: *i64, nb: *u8, ob: *i64, out: *i64) -> i64 {
100 let pr: *u8=sys_mmap(K_MAGIC_1024); let ph: *u8=sys_mmap(K_MAGIC_1024)
101 jdn_path("runtime/\x00" as *u8, name, pr)
102 jdn_path("runtime/_hdl_build/\x00" as *u8, name, ph)
103 let la: i64=jdn_read(pr, ba, K_MAGIC_1048576); let lb: i64=jdn_read(ph, bb, K_MAGIC_1048576)
104 if la<0 { return 0-1 }
105 if lb<0 { return 0-1 }
106 let ca: i64=crp_extract_funcs(ba, la, na, oa, K_MAGIC_4000)
107 let cb: i64=crp_extract_funcs(bb, lb, nb, ob, K_MAGIC_4000)
108 let s3: *i64=sys_mmap(32) as *i64
109 crp_setcmp(na,oa,ca, nb,ob,cb, s3)
110 let hma: i64=crp_name_in("main\x00" as *u8, na, oa, ca)
111 let hmb: i64=crp_name_in("main\x00" as *u8, nb, ob, cb)
112 out[0]=s3[0]; out[1]=s3[1]; out[2]=s3[2]; out[3]=ca; out[4]=cb; out[5]=hma; out[6]=hmb
113 return crp_classify2(s3[0], s3[1], s3[2], hma, hmb)
114}