nx_cachewatch_gate.nx source
↩ module page · 229 lines · 12037 B
1// nx_cachewatch_gate.nx -- THE GATE FOR THE WRITE-CACHE AXIS, 2026-09-03.
2//
3// SUBJECT: the BUILT nx_cachewatch elf, forked against fixture /proc trees this gate writes at runtime.
4// It never reads the real /proc, so it is deterministic on any host and cannot pass or fail because of
5// the box it happens to run on -- which matters especially here, since the real host is currently in the
6// RED state and a gate that read it would be indistinguishable from one hardcoded to say RED.
7//
8// T2 IS THE TOOTH THAT CARRIES THE FILE. Fixtures 1 and 2 have BYTE-IDENTICAL cache_info -- both say
9// `mode=WRITE_BACK` -- and differ ONLY in flashcache_progress. If the organ keyed its verdict on `mode`
10// (the obvious field, and the one a reader reaches for first) both would return the same answer and the
11// detector would have read GREEN through the entire outage that motivated it. T2 requires them to
12// DIFFER, so it can only pass on an organ that discriminates on the right field.
13//
14// T3 IS THE POSITIVE CONTROL. T1/T2/T4/T5 all assert a non-GREEN verdict, and a detector hardwired to
15// alarm passes every one. T3 demands a fully healthy tree return GREEN at exit 0.
16//
17// T6 IS THE COUNTER TRAP, AND IT IS THE DEFECT THAT MOTIVATED THE ORGAN. The fixture plants
18// `dirty_writeback_kb=31543788` -- the real live value -- beside `dirty_blocks=0`. A reader that treats
19// the counter as a level reports tens of GB of stranded dirty data on a degraded unmirrored device: an
20// alarming, actionable, WRONG conclusion that this estate's memory recorded once and this organ's author
21// nearly published again. T6 requires the reported level to stay 0 and the counters to be NAMED as
22// refused.
23//
24// Teeth, in order:
25// T1 the live-host condition (cache flushed+disabled, mirror degraded) -> RED, exit 1.
26// T2 DISCRIMINATOR: identical cache_info, progress differs -> AMBER not RED (mode is not the field).
27// T3 POSITIVE CONTROL: a healthy tree -> GREEN, exit 0.
28// T4 an absent flashcache -> UNOBSERVABLE (3), and specifically NOT GREEN.
29// T5 an unreadable progress file -> UNOBSERVABLE, not a cheerful GREEN.
30// T6 COUNTER TRAP: a huge lifetime counter beside dirty_blocks=0 must not become a level.
31// T7 the degraded count reads [2/1] as degraded and leaves [2/2] and [8/8] alone.
32// T8 ANTI-VACUITY: the four verdicts are four DISTINCT exit codes.
33// MEASURED 8/8 GREEN 2026-09-03, bite-proven killed=1 (source 13321 B and deployed subject 23297 B both
34// restored byte-identical).
35// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
36import "nx_syscalls.nx"
37import "nx_gate_verdict.nx"
38import "nx_tool_run.nx"
39
40const CWG_S_A: *u8 = "buildroot/_build/nx_cachewatch.sov.elf" as *u8
41const CWG_S_B: *u8 = "_build/nx_cachewatch.sov.elf" as *u8
42const CWG_S_C: *u8 = "_offc/nx_cachewatch.elf" as *u8
43const CWG_S_D: *u8 = "nx_cachewatch.elf" as *u8
44
45const CWG_ROOT: *u8 = "/tmp/cachewatch" as *u8
46const CWG_PROC: *u8 = "/tmp/cachewatch/proc" as *u8
47const CWG_FCD: *u8 = "/tmp/cachewatch/proc/flashcache" as *u8
48const CWG_INST: *u8 = "/tmp/cachewatch/proc/flashcache/vgtest_cache_1+volume_1" as *u8
49const CWG_CI: *u8 = "/tmp/cachewatch/proc/flashcache/vgtest_cache_1+volume_1/cache_info" as *u8
50const CWG_PG: *u8 = "/tmp/cachewatch/proc/flashcache/vgtest_cache_1+volume_1/flashcache_progress" as *u8
51const CWG_ST: *u8 = "/tmp/cachewatch/proc/flashcache/vgtest_cache_1+volume_1/flashcache_stats" as *u8
52const CWG_MD: *u8 = "/tmp/cachewatch/proc/mdstat" as *u8
53const CWG_ABSENT: *u8 = "/tmp/cachewatch_absent/proc" as *u8
54
55const CWG_CAP: i64 = 16384
56const CWG_MODE: i64 = 420
57const CWG_DIRMODE: i64 = 0x1ff
58
59const CWG_GREEN: i64 = 0
60const CWG_RED: i64 = 1
61const CWG_AMBER: i64 = 2
62const CWG_UNOBS: i64 = 3
63
64// cache_info is BYTE-IDENTICAL for fixtures 1 and 2 -- see T2.
65const CWG_CI_TXT: *u8 = "ssd_dev=/dev/x disk_dev=/dev/y mode=WRITE_BACK total_blocks=15249408 cached_blocks=14501872 dirty_blocks=0 synced_blocks=0 occupied_blocks=670386 \n"
66const CWG_PG_OFF: *u8 = "status=uncacheable_flush_done initial_num_of_dirty=0 remaining_num_of_dirty=0\n"
67const CWG_PG_ON: *u8 = "status=none initial_num_of_dirty=0 remaining_num_of_dirty=0\n"
68const CWG_MD_DEG: *u8 = "md3 : active raid1 nvme1n1p1[1]\n 976757952 blocks super 1.2 [2/1] [_U]\nmd2 : active raid5 a b\n 1 blocks [8/8] [UUUUUUUU]\n"
69const CWG_MD_OK: *u8 = "md3 : active raid1 nvme0n1p1[0] nvme1n1p1[1]\n 976757952 blocks super 1.2 [2/2] [UU]\nmd2 : active raid5 a b\n 1 blocks [8/8] [UUUUUUUU]\n"
70const CWG_STATS: *u8 = "reads=1 writes=2 dirty_writeback_kb=31543788 dirty_write_hits=43493286 write_hits=44269137\n"
71
72func cwg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
73func cwg_write(path: *u8, s: *u8) -> i64 {
74 let n: i64 = cwg_slen(s)
75 let fd: i64 = sys_openat_wr(path, CWG_MODE)
76 if fd < 0 { return 0 - 1 }
77 var off: i64 = 0
78 var go: i64 = 1
79 while go == 1 {
80 if off >= n { go = 0 } else {
81 let w: i64 = sys_write(fd, (s as i64 + off) as *u8, n - off)
82 if w <= 0 { go = 0 } else { off = off + w }
83 }
84 }
85 sys_close(fd)
86 return off
87}
88func cwg_rm(path: *u8) -> i64 { return __syscall(263, 0 - 100, path, 0, 0, 0, 0) }
89func cwg_exists(p: *u8) -> i64 {
90 let fd: i64 = sys_openat_rd(p)
91 if fd < 0 { return 0 }
92 sys_close(fd)
93 return 1
94}
95func cwg_resolve() -> *u8 {
96 if cwg_exists(CWG_S_A) == 1 { return CWG_S_A }
97 if cwg_exists(CWG_S_B) == 1 { return CWG_S_B }
98 if cwg_exists(CWG_S_C) == 1 { return CWG_S_C }
99 if cwg_exists(CWG_S_D) == 1 { return CWG_S_D }
100 return 0 as *u8
101}
102func cwg_find(buf: *u8, n: i64, needle: *u8) -> i64 {
103 let m: i64 = cwg_slen(needle)
104 if m == 0 { return 0 - 1 }
105 var i: i64 = 0
106 var hit: i64 = 0 - 1
107 while i + m <= n {
108 var j: i64 = 0
109 var same: i64 = 1
110 while j < m {
111 if buf[i + j] != needle[j] { same = 0; j = m } else { j = j + 1 }
112 }
113 if same == 1 { if hit < 0 { hit = i + m } }
114 i = i + 1
115 }
116 return hit
117}
118func cwg_run(subj: *u8, verb: *u8, root: *u8, out: *u8, ol: *i64) -> i64 {
119 let av: *i64 = sys_mmap(64) as *i64
120 av[0] = subj as i64
121 av[1] = verb as i64
122 av[2] = root as i64
123 av[3] = 0
124 return tr_run_capture(subj, av, out, CWG_CAP, ol)
125}
126
127func main(argc: i64, argv: *i64) -> i64 {
128 let ctr: *i64 = gv_ctr()
129 gv_head("nx_cachewatch gate -- is the write cache actually caching, and is a lifetime counter ever read as a level" as *u8)
130
131 var subj: *u8 = cwg_resolve()
132 if argc > 1 { subj = argv[1] as *u8 }
133 if subj as i64 == 0 {
134 gv_need("a-built-nx_cachewatch-artifact-on-any-known-path" as *u8, 0, ctr)
135 return gv_verdict("cachewatch" as *u8, ctr, "ABSTAINED: no built subject found, so nothing was measured" as *u8)
136 }
137 gv_puts(" subject resolved by stat: " as *u8); gv_puts(subj); gv_puts("\n" as *u8)
138
139 // fixtures under /tmp/<gate>/ -- never beside a production beat, and built at SETUP because a
140 // teardown does not run when a run crashes.
141 sys_mkdir(CWG_ROOT, CWG_DIRMODE)
142 sys_mkdir(CWG_PROC, CWG_DIRMODE)
143 sys_mkdir(CWG_FCD, CWG_DIRMODE)
144 sys_mkdir(CWG_INST, CWG_DIRMODE)
145
146 let out: *u8 = sys_mmap(CWG_CAP + 16)
147 let ol: *i64 = sys_mmap(16) as *i64
148
149 // ---- T1 the live-host condition ----
150 cwg_write(CWG_CI, CWG_CI_TXT)
151 cwg_write(CWG_PG, CWG_PG_OFF)
152 cwg_write(CWG_MD, CWG_MD_DEG)
153 let r1: i64 = cwg_run(subj, "check" as *u8, CWG_PROC, out, ol)
154 let n1: i64 = *ol
155 gv_puts(" [T1] cache disabled + mirror degraded -> exit=" as *u8); gv_num(r1)
156 gv_puts(" want=" as *u8); gv_num(CWG_RED); gv_puts("\n" as *u8)
157 var t1: i64 = 0
158 if r1 == CWG_RED { if cwg_find(out, n1, "caching=NO" as *u8) >= 0 { t1 = 1 } }
159 gv_check("the-live-host-condition-cache-flushed-and-disabled-reads-RED" as *u8, t1, ctr)
160
161 // ---- T2 THE DISCRIMINATOR: only flashcache_progress changes ----
162 cwg_write(CWG_PG, CWG_PG_ON)
163 let r2: i64 = cwg_run(subj, "check" as *u8, CWG_PROC, out, ol)
164 let n2: i64 = *ol
165 gv_puts(" [T2] SAME cache_info (mode=WRITE_BACK both), progress differs -> exit=" as *u8); gv_num(r2)
166 gv_puts(" want=" as *u8); gv_num(CWG_AMBER); gv_puts(" (T1 was " as *u8); gv_num(r1); gv_puts(")\n" as *u8)
167 var t2: i64 = 0
168 if r2 == CWG_AMBER { if r2 != r1 { if cwg_find(out, n2, "caching=YES" as *u8) >= 0 { t2 = 1 } } }
169 gv_check("DISCRIMINATOR-identical-cache_info-yields-a-DIFFERENT-verdict (an organ keyed on mode would answer the same twice and read GREEN through the whole outage)" as *u8, t2, ctr)
170
171 // ---- T3 POSITIVE CONTROL ----
172 cwg_write(CWG_MD, CWG_MD_OK)
173 let r3: i64 = cwg_run(subj, "check" as *u8, CWG_PROC, out, ol)
174 let n3: i64 = *ol
175 gv_puts(" [T3] fully healthy -> exit=" as *u8); gv_num(r3); gv_puts(" want=0\n" as *u8)
176 var t3: i64 = 0
177 if r3 == CWG_GREEN { if cwg_find(out, n3, "verdict=GREEN" as *u8) >= 0 { t3 = 1 } }
178 gv_check("POSITIVE-CONTROL-a-healthy-tree-reads-GREEN (without this every alarm tooth passes on a detector hardwired to alarm)" as *u8, t3, ctr)
179
180 // ---- T4 absent cache ----
181 let r4: i64 = cwg_run(subj, "check" as *u8, CWG_ABSENT, out, ol)
182 let n4: i64 = *ol
183 gv_puts(" [T4] no flashcache present -> exit=" as *u8); gv_num(r4); gv_puts(" want=3\n" as *u8)
184 var t4: i64 = 0
185 if r4 == CWG_UNOBS { if r4 != CWG_GREEN { if cwg_find(out, n4, "UNOBSERVABLE" as *u8) >= 0 { t4 = 1 } } }
186 gv_check("an-absent-flashcache-is-UNOBSERVABLE-and-specifically-NOT-GREEN" as *u8, t4, ctr)
187
188 // ---- T5 unreadable progress ----
189 cwg_rm(CWG_PG)
190 let r5: i64 = cwg_run(subj, "check" as *u8, CWG_PROC, out, ol)
191 gv_puts(" [T5] progress file removed -> exit=" as *u8); gv_num(r5); gv_puts(" want=3\n" as *u8)
192 gv_check("an-unreadable-progress-file-ABSTAINS-rather-than-reporting-a-cheerful-GREEN" as *u8, (r5 == CWG_UNOBS) as i64, ctr)
193
194 // ---- T6 THE COUNTER TRAP ----
195 cwg_write(CWG_PG, CWG_PG_OFF)
196 cwg_write(CWG_MD, CWG_MD_DEG)
197 cwg_write(CWG_ST, CWG_STATS)
198 let r6: i64 = cwg_run(subj, "explain" as *u8, CWG_PROC, out, ol)
199 let n6: i64 = *ol
200 var t6: i64 = 0
201 if cwg_find(out, n6, "dirty_blocks=0" as *u8) >= 0 {
202 if cwg_find(out, n6, "REFUSED-AS-LEVEL" as *u8) >= 0 {
203 if cwg_find(out, n6, "dirty_writeback_kb" as *u8) >= 0 { t6 = 1 }
204 }
205 }
206 gv_puts(" [T6] stats plant dirty_writeback_kb=31543788 beside dirty_blocks=0 -> level_reported_0=" as *u8)
207 gv_num(t6); gv_puts("\n" as *u8)
208 gv_check("COUNTER-TRAP-a-huge-lifetime-counter-does-NOT-become-a-level-and-both-counters-are-NAMED-as-refused" as *u8, t6, ctr)
209
210 // ---- T7 the degraded count ----
211 var t7: i64 = 0
212 if cwg_find(out, n6, "degraded_mirrors=1" as *u8) >= 0 { t7 = 1 }
213 gv_puts(" [T7] mdstat carries [2/1] and [8/8] -> degraded counted as 1 = " as *u8); gv_num(t7); gv_puts("\n" as *u8)
214 gv_check("the-degraded-count-reads-2-of-1-as-degraded-and-leaves-a-full-8-of-8-alone" as *u8, t7, ctr)
215
216 // ---- T8 ANTI-VACUITY ----
217 var t8: i64 = 0
218 if r1 != r2 { if r2 != r3 { if r3 != r4 { if r1 != r3 { if r1 != r4 { if r2 != r4 { t8 = 1 } } } } } }
219 gv_puts(" [T8] four verdicts: " as *u8); gv_num(r1); gv_puts("," as *u8); gv_num(r2)
220 gv_puts("," as *u8); gv_num(r3); gv_puts("," as *u8); gv_num(r4); gv_puts(" all distinct=" as *u8); gv_num(t8); gv_puts("\n" as *u8)
221 gv_check("ANTI-VACUITY-the-four-states-are-four-DISTINCT-exit-codes (a detector returning one constant fails here)" as *u8, t8, ctr)
222
223 gv_kv("red_exit" as *u8, r1)
224 gv_kv("amber_exit" as *u8, r2)
225 gv_kv("green_exit" as *u8, r3)
226 gv_kv("unobservable_exit" as *u8, r4)
227
228 return gv_verdict("cachewatch" as *u8, ctr, "the write-cache axis proven on fixture trees: the disabled-cache condition reads RED, an identical cache_info with a different progress file reads AMBER so mode is provably not the discriminator, a healthy tree reads GREEN, and a lifetime counter is never reported as a level" as *u8)
229}