code wiki / _hdl_build / nx_buildmode_gate.nx
nx_buildmode_gate.nx source
↩ module page · 112 lines · 6248 B
1// nx_buildmode_gate.nx -- THE REFEREE for nx_buildmode_lib (LN44, 2026-09-03).
2//
3// The subject decides which flags the build lane hands the compiler, so its failure modes are expensive in
4// both directions: too eager and it silently changes every artifact in the estate on adoption day; too
5// quiet and the estate keeps shipping its slowest mode. The load-bearing tooth here is therefore the
6// SAFETY property, not the feature: with NO conf present the reader must return ZERO flags and an EMPTY
7// cache-key token, so adopting the lib cannot change one byte of one artifact until somebody writes a row.
8//
9// THE CACHE-KEY TOOTH IS NOT DECORATION. nx_sov_build_run caches artifacts under a key that today encodes
10// the compiler sha, the assembler sha and the debug flag. A mode that changes emitted code without
11// entering that key would serve an artifact compiled under the OTHER mode and present it as a cache hit --
12// silently correct-looking and wrong. So the gate asserts two different modes yield two different tokens,
13// and that no mode yields an empty one.
14//
15// Fixture is PER-RUN via gk_fixture_dir, so two concurrent runs cannot clobber each other into a false
16// SKIP -- the defect measured on nx_bck_elide_gate the same day this shipped.
17// exit: 0 GREEN . 1 RED license_tier: ORIGINAL No hw writes.
18import "nx_syscalls.nx"
19import "nx_gate_verdict.nx"
20import "nx_gatekit_lib.nx"
21import "nx_buildmode_lib.nx"
22
23const BG_PATH: i64 = 1024
24const BG_CAP: i64 = 512
25const BG_SLOTS: i64 = 16
26
27func bg_write(path: *u8, text: *u8) -> i64 {
28 let fd: i64 = sys_openat_wr(path, 420)
29 if fd < 0 { return 0 - 1 }
30 var n: i64 = 0
31 while text[n] != (0 as u8) { n = n + 1 }
32 var off: i64 = 0
33 while off < n { let r: i64 = sys_write(fd, ((text as i64) + off) as *u8, n - off); if r <= 0 { sys_close(fd); return 0 - 2 } off = off + r }
34 sys_close(fd)
35 return 0
36}
37
38func main(argc: i64, argv: *i64) -> i64 {
39 let ctr: *i64 = gv_ctr()
40 gv_head("NX-BUILDMODE-GATE: the compile mode is DATA, and an absent declaration changes nothing" as *u8)
41
42 let root: *u8 = sys_mmap(BG_PATH)
43 gk_fixture_dir("nx_buildmode_gate" as *u8, root)
44 let kdir: *u8 = sys_mmap(BG_PATH)
45 var o: i64 = gk_cat(kdir, 0, root); o = gk_cat(kdir, o, "/knowledge" as *u8)
46 gk_mkdir(kdir)
47 let conf: *u8 = sys_mmap(BG_PATH)
48 o = gk_cat(conf, 0, kdir); o = gk_cat(conf, o, "/build_modes.conf" as *u8)
49
50 let cwd: *u8 = sys_mmap(BG_PATH)
51 sys_getcwd(cwd, BG_PATH)
52 sys_chdir(root)
53
54 let f: *u8 = sys_mmap(BG_CAP)
55 let t: *u8 = sys_mmap(BG_CAP)
56
57 // ---- A: NO CONF AT ALL -- the safety property, and the reason adoption is a no-op ----
58 let a_n: i64 = bm_flags_for("nx_anything" as *u8, f)
59 let a_k: i64 = bm_key_token("nx_anything" as *u8, t)
60 gv_check_eq("A-absent-conf-yields-ZERO-flags-so-adoption-changes-no-artifact" as *u8, a_n, 0, ctr)
61 gv_check_eq("A-absent-conf-yields-an-EMPTY-cache-key-token-so-every-existing-cache-entry-stays-valid" as *u8, a_k, 0, ctr)
62
63 // ---- B: a per-target row ----
64 bg_write(conf, "# fixture\ntarget|nx_alpha|--bckelide\n" as *u8)
65 let b_n: i64 = bm_flags_for("nx_alpha" as *u8, f)
66 gv_check("B-target-row-returns-its-declared-flags" as *u8, gk_streq(f, "--bckelide" as *u8), ctr)
67 gv_check_eq("B-flag-length-is-nonzero" as *u8, (b_n > 0) as i64, 1, ctr)
68 let b_other: i64 = bm_flags_for("nx_beta" as *u8, f)
69 gv_check_eq("B-neg-control-an-UNDECLARED-target-still-gets-nothing" as *u8, b_other, 0, ctr)
70
71 // ---- C: `all` is the fallback, and a per-target row BEATS it ----
72 bg_write(conf, "all|--bckelide\ntarget|nx_special|--bckelide --chkarith\n" as *u8)
73 let c_any: i64 = bm_flags_for("nx_random" as *u8, f)
74 gv_check("C-all-row-is-the-fallback-for-an-undeclared-target" as *u8, gk_streq(f, "--bckelide" as *u8), ctr)
75 gv_check_eq("C-fallback-nonempty" as *u8, (c_any > 0) as i64, 1, ctr)
76 bm_flags_for("nx_special" as *u8, f)
77 gv_check("C-a-per-target-row-BEATS-the-all-row" as *u8, gk_streq(f, "--bckelide --chkarith" as *u8), ctr)
78
79 // ---- D: comments and blanks are not rows ----
80 bg_write(conf, "# target|nx_gamma|--bckelide\n; target|nx_gamma|--bckelide\n\n" as *u8)
81 let d_n: i64 = bm_flags_for("nx_gamma" as *u8, f)
82 gv_check_eq("D-a-commented-row-is-NOT-a-declaration" as *u8, d_n, 0, ctr)
83
84 // ---- E: THE CACHE-KEY CONTRACT. Two modes must not share a key, or a hit serves the wrong artifact ----
85 bg_write(conf, "target|nx_k|--bckelide\n" as *u8)
86 let k1: *u8 = sys_mmap(BG_CAP)
87 bm_key_token("nx_k" as *u8, k1)
88 bg_write(conf, "target|nx_k|--chkarith\n" as *u8)
89 let k2: *u8 = sys_mmap(BG_CAP)
90 bm_key_token("nx_k" as *u8, k2)
91 gv_check_eq("E-two-different-modes-yield-DIFFERENT-cache-key-tokens" as *u8, 1 - gk_streq(k1, k2), 1, ctr)
92 gv_check_eq("E-a-declared-mode-yields-a-NONEMPTY-token" as *u8, (gk_len(k1) > 0) as i64, 1, ctr)
93 gv_bite("bite-the-key-token-separates-two-modes-and-stays-empty-when-none-is-declared" as *u8, 1 - gk_streq(k1, k2), (a_k != 0) as i64, ctr)
94
95 // ---- F: the flag list becomes SEPARATE argv tokens, never one glued string ----
96 bg_write(conf, "target|nx_s|--bckelide --chkarith\n" as *u8)
97 bm_flags_for("nx_s" as *u8, f)
98 let store: *u8 = sys_mmap(BG_CAP)
99 let slots: *i64 = sys_mmap(BG_SLOTS * 8) as *i64
100 let nsplit: i64 = bm_split(f, store, slots, BG_SLOTS)
101 gv_check_eq("F-two-flags-split-into-TWO-argv-tokens" as *u8, nsplit, 2, ctr)
102 gv_check("F-first-token-is-exactly-the-first-flag" as *u8, gk_streq(slots[0] as *u8, "--bckelide" as *u8), ctr)
103 gv_check("F-second-token-is-exactly-the-second-flag" as *u8, gk_streq(slots[1] as *u8, "--chkarith" as *u8), ctr)
104 let zero: i64 = bm_split("" as *u8, store, slots, BG_SLOTS)
105 gv_check_eq("F-neg-control-an-empty-flag-list-splits-into-ZERO-tokens" as *u8, zero, 0, ctr)
106
107 sys_chdir(cwd)
108 gv_kv("absent_conf_flags" as *u8, a_n)
109 gv_kv("absent_conf_keylen" as *u8, a_k)
110 gv_kv("split_tokens" as *u8, nsplit)
111 return gv_verdict("nx_buildmode_gate" as *u8, ctr, "an absent declaration yields no flags and no key bytes, a declared one reaches the compiler as separate tokens, and two modes can never share a cache key" as *u8)
112}