code wiki / _hdl_build / nx_presubmit_lib.nx
nx_presubmit_lib.nx source
↩ module page · 89 lines · 5021 B
1// nx_presubmit_lib.nx -- PRE-SUBMIT correctness guard (stage 1 of the 3-stage lifecycle: catch BEFORE a
2// build cycle is spent, to save token waste). The at-submit dup_shadow warning (seq207) fires AFTER a build;
3// this fires BEFORE, so a session/agent never spends a build+revert on a name collision (the nx_emit landmine
4// 2026-07-21 was caught at-submit and cost a full cycle -- this makes it a one-call pre-check).
5// Composes: nx_build_admit = the RESOURCE pre-submit gate (headroom); this = the CORRECTNESS pre-submit gate
6// (name/collision). Dogfoods the nx_estr shared base (2nd adopter). ZERO deps beyond nx_syscalls+nx_estr so a
7// preflight can never itself be the heavy thing that fails. license_tier: ORIGINAL No hw writes (Rule 26).
8import "nx_syscalls.nx"
9import "nx_estr.nx"
10
11const PS_DIRBUF: i64 = 65536 // getdents read buffer (rule 11: named, not an inline magic number)
12
13// does exactly "<name>.nx" exist as a directory entry of dir?
14func ps_has(dir: *u8, name: *u8) -> i64 {
15 let fd: i64 = sys_openat_rd(dir)
16 if fd < 0 { return 0 }
17 let dbuf: *u8 = sys_mmap(PS_DIRBUF)
18 let tgt: *u8 = sys_mmap(256)
19 var t: i64 = es_cat(tgt, 0, name)
20 t = es_cat(tgt, t, ".nx" as *u8)
21 tgt[t] = 0 as u8
22 var found: i64 = 0
23 var go: i64 = 1
24 while go == 1 {
25 let nr: i64 = sys_getdents64(fd, dbuf, PS_DIRBUF)
26 if nr <= 0 { go = 0 } else {
27 var off: i64 = 0
28 while off < nr {
29 let rec: *u8 = (dbuf as i64 + off) as *u8
30 let nm: *u8 = dirent_name(rec)
31 var i: i64 = 0
32 var scan: i64 = 1
33 while scan == 1 {
34 if tgt[i] == (0 as u8) { if nm[i] == (0 as u8) { found = 1 } scan = 0 }
35 else { if nm[i] != tgt[i] { scan = 0 } else { i = i + 1 } }
36 }
37 off = off + dirent_reclen(rec)
38 }
39 }
40 }
41 sys_close(fd)
42 return found
43}
44
45// write the JSON verdict for creating an organ named `name`, given the two source dirs. returns rc:
46// 0 FREE -- name in neither dir: safe to create
47// 4 EXISTS-in-hdl_build -- already in the primary dir: you are EDITING, or the name is taken
48// 3 SHADOW-RISK / DUAL -- present in the OTHER (or both) dir: creating here makes a dual-copy landmine
49func ps_check(name: *u8, hdl: *u8, rt: *u8, out: *u8) -> i64 {
50 let in_hdl: i64 = ps_has(hdl, name)
51 let in_rt: i64 = ps_has(rt, name)
52 var o: i64 = es_cat(out, 0, "{\"tool\":\"nx_presubmit\",\"name\":\"" as *u8)
53 o = es_cat(out, o, name)
54 o = es_cat(out, o, "\",\"in_hdl_build\":" as *u8)
55 o = es_catn(out, o, in_hdl)
56 o = es_cat(out, o, ",\"in_runtime\":" as *u8)
57 o = es_catn(out, o, in_rt)
58 // every verdict carries a why + a fix RECOMMENDATION (operator 2026-07-21: a refusal must tell the AI+
59 // human what/why/how, never a bare verdict).
60 o = es_cat(out, o, ",\"verdict\":\"" as *u8)
61 var rc: i64 = 0
62 var done: i64 = 0
63 if in_hdl == 1 { if in_rt == 1 {
64 o = es_cat(out, o, "DUAL-COPY-ALREADY\",\"why\":\"" as *u8)
65 o = es_cat(out, o, name)
66 o = es_cat(out, o, ".nx exists in BOTH source dirs. Imports resolve DIRECTORY-LOCAL (proven 2026-07-21): _hdl_build organs bind the _hdl_build copy and runtime organs bind the runtime copy, so BOTH are load-bearing (neither auto-stale); the real hazard is DIVERGENCE -- the twins drift apart and same-named consumers in different trees silently get different behavior (seq207)\",\"fix\":\"do NOT blind-delete either twin -- it may serve dozens of importers; count importers per tree first, then reconcile via STAGED MERGE to one canonical tree (unify the sources, migrate the other-tree consumers, retire the emptied copy per rule 13). Direct retire is safe ONLY when a copy has 0 importers AND no standalone deploy" as *u8)
67 rc = 3; done = 1
68 } }
69 if done == 0 { if in_hdl == 1 {
70 o = es_cat(out, o, "EXISTS-in-hdl_build\",\"why\":\"an organ named " as *u8)
71 o = es_cat(out, o, name)
72 o = es_cat(out, o, " already exists in the primary source dir\",\"fix\":\"to CHANGE it, EDIT that file; for a NEW organ, pick a different name" as *u8)
73 rc = 4; done = 1
74 } }
75 if done == 0 { if in_rt == 1 {
76 o = es_cat(out, o, "SHADOW-RISK-runtime-twin\",\"why\":\"" as *u8)
77 o = es_cat(out, o, name)
78 o = es_cat(out, o, ".nx exists in buildroot/runtime; creating a copy in _hdl_build makes a dual-copy that diverges and silently regresses (the nx_emit landmine)\",\"fix\":\"either EDIT the existing buildroot/runtime/" as *u8)
79 o = es_cat(out, o, name)
80 o = es_cat(out, o, ".nx, or pick a DIFFERENT name for the new organ" as *u8)
81 rc = 3; done = 1
82 } }
83 if done == 0 {
84 o = es_cat(out, o, "FREE\",\"why\":\"the name is free in both source dirs\",\"fix\":\"safe to create -- no action needed" as *u8)
85 }
86 o = es_cat(out, o, "\"}" as *u8)
87 out[o] = 0 as u8
88 return rc
89}