nx_isa_manager.nx source
↩ module page · 1148 lines · 43395 B
1// nx_isa_manager.nx -- THE MASTER ISA MANAGER.
2//
3// WHAT IT IS: not another conformance gate. The gates measure ONE
4// architecture each and answer "does this emulator obey its manual".
5// This organ measures THE POPULATION and answers a different question:
6// of every ISA the estate has declared in scope, which ones does
7// anything at all measure, which have an emulator nobody rules on,
8// which are declared and untouched, and what is the next actionable
9// name in each of those classes.
10//
11// THE DENOMINATOR IS PUBLISHED. knowledge/isa_targets.conf is the
12// population and it is READ, never inferred. A coverage ratio whose
13// denominator is "the ISAs I happened to think of" flatters itself by
14// omission; 14 of 122 is an honest number and 14 of 14 is not.
15//
16// impl AND ext ROWS ARE NOT TARGETS AND ARE EXCLUDED FROM EVERY
17// EMITTER/EMULATOR RATIO. An impl row is a HOST that implements another
18// row's ISA (Phytium implements aarch64) and an ext row is an EXTENSION
19// of a base ISA (SVE extends aarch64). Counting either in a codegen
20// ratio double-counts the base ISA and inflates the number in the one
21// direction nobody audits. They get their own named state,
22// NOT-A-TARGET, so they are visible and excluded at the same time.
23//
24// HOW A NEW ISA JOINS -- NO EDIT TO THIS ORGAN, EVER:
25// 1. add a row to knowledge/isa_targets.conf. It reads DECLARED-ONLY.
26// 2. write buildroot/runtime/nx_emu_<id>.nx. It reads EMULATOR-ONLY.
27// 3. write buildroot/runtime/nx_isa_<id>_gate.nx, or import
28// nx_emu_<id>.nx from nx_isa_conform_gate.nx. It reads
29// GATE-PRESENT-UNRUN.
30// 4. let that gate bank "<id> <passed>" into
31// knowledge/status/isa_<id>.ratchet, or into the core gate's
32// shared knowledge/status/isa_conform.ratchet. It reads
33// MEASURED-GREEN.
34// If the organs are already named something other than the conf id, add
35// ONE row to knowledge/isa_emu_alias.conf. That file is DATA and the
36// manager reports how many rows it used and names any alias whose id is
37// not in the population, because an alias for an undeclared id is a
38// typo that silently hides a target.
39//
40// DISCOVERY IS A PROBE, NOT A LIST. There is no array of architecture
41// names in this file. Every state comes from stat-ing a path derived
42// from a conf row and from scanning the core gate's own source for the
43// emulator it imports. A hardcoded roster is a name list, and a name
44// list always lags the next generator -- this estate has measured that
45// four times in three weeks on the compare trees alone.
46//
47// TWO TREES, FOUR CANDIDATE ROOTS. buildroot/runtime and runtime are
48// different trees and the builder probes _hdl_build FIRST, so a probe
49// that knows only one of them returns a confident, complete-looking
50// false negative. Every existence question here is asked against all
51// four and the answer carries the root it resolved from.
52//
53// WHY THE TEETH DO NOT MEASURE THE ISAs. Every gv_check below asserts
54// something THIS ORGAN controls: that the partitions sum, that discovery
55// did not silently stop finding gates, that no target was left without a
56// state, that the ratchet was not touched. A manager whose verdict went
57// RED because an ISA is incomplete would be RED on the day it shipped
58// and every day after, and a permanently red detector is one everyone
59// learns to ignore. The ISA numbers are PUBLISHED, and the worklist at
60// the end is what a seat acts on. The verdict is the fence; the numbers
61// are the work.
62//
63// THE RATCHET IS READ-ONLY HERE. The gates own it. A tooth re-reads it
64// at the end of the run and byte-compares against the copy taken at the
65// start, so "the manager does not write the ratchet" is measured rather
66// than promised. Size is never an identity, so the comparison is over
67// content.
68//
69// license_tier: ORIGINAL
70
71import "nx_gate_verdict.nx"
72import "nx_syscalls.nx"
73
74// ---- population and evidence paths -----------------------------
75const IM_CONF_NAME: *u8 = "isa_targets.conf"
76const IM_ALIAS_NAME: *u8 = "isa_emu_alias.conf"
77const IM_CORE_GATE: *u8 = "nx_isa_conform_gate.nx"
78const IM_CORE_RATCH: *u8 = "status/isa_conform.ratchet"
79const IM_RATCH_PRE: *u8 = "status/isa_"
80const IM_RATCH_SUF: *u8 = ".ratchet"
81const IM_EMU_PRE: *u8 = "nx_emu_"
82const IM_GATE_PRE: *u8 = "nx_isa_"
83const IM_GATE_SUF: *u8 = "_gate.nx"
84const IM_NX_SUF: *u8 = ".nx"
85
86// Runtime roots, probed in this order. _hdl_build first inside each
87// tree because that is the order the builder resolves imports in, so
88// reporting on the other one would report on a file that does not
89// compile.
90const IM_ROOTS: i64 = 4
91func im_root(i: i64) -> *u8 {
92 if i == 0 { return "buildroot/runtime/_hdl_build/" as *u8 }
93 if i == 1 { return "buildroot/runtime/" as *u8 }
94 if i == 2 { return "runtime/_hdl_build/" as *u8 }
95 return "runtime/" as *u8
96}
97const IM_KROOTS: i64 = 2
98func im_kroot(i: i64) -> *u8 {
99 if i == 0 { return "knowledge/" as *u8 }
100 return "buildroot/knowledge/" as *u8
101}
102
103// ---- sizes. No silent caps: every one of these is asserted by a
104// tooth and announced when reached, because a cap reached in silence
105// becomes a measurement nobody knows is partial.
106const IM_MAX_TARGETS: i64 = 512
107const IM_MAX_ALIAS: i64 = 256
108const IM_PATH_BYTES: i64 = 1024
109const IM_SLICE_BYTES: i64 = 256
110const IM_BOX_BYTES: i64 = 16
111const IM_ALIAS_COLS: i64 = 4
112const IM_WORD: i64 = 8
113const IM_ALIAS_TAG: i64 = 6
114const IM_ISA_TAG: i64 = 4
115// The schema is SEVEN '|'-separated fields and the FIRST IS THE LITERAL
116// TAG "isa", which the tag test has already consumed -- so the walk that
117// starts after it sees SIX. The first cut of this constant said 7 and
118// every one of the 122 rows read as malformed: a fixture with the real
119// population found it in one run, and a fixture built from a row I had
120// typed myself would have agreed with my own miscount.
121const IM_FIELDS_AFTER_TAG: i64 = 6
122
123// ---- discovery floors. NOT health bars: regression fences on the
124// DISCOVERY mechanism itself. Measured 2026-09-03 the estate carried
125// six conformance gate sources and eleven emulator sources. If a root
126// moves or a naming rule changes and discovery silently stops finding
127// them, these fire. They ratchet upward by hand, never downward.
128const IM_GATE_FLOOR: i64 = 6
129const IM_EMU_FLOOR: i64 = 6
130
131// ---- byte constants --------------------------------------------
132const IM_NL: i64 = 10
133const IM_CR: i64 = 13
134const IM_SPACE: i64 = 32
135const IM_PIPE: i64 = 124
136const IM_DIG_LO: i64 = 48
137const IM_DIG_HI: i64 = 57
138const IM_BYTE_M: i64 = 255
139const IM_PERMIL: i64 = 1000
140const IM_B10: i64 = 10
141const IM_SEEK_END: i64 = 2
142const IM_NUL: i64 = 0
143
144// ---- classes. UNKNOWN is its own bucket and never folds into a known
145// one: the bucket an unrecognised class lands in becomes the number
146// somebody plans against.
147const IM_C_CPU: i64 = 0
148const IM_C_MCU: i64 = 1
149const IM_C_GPU: i64 = 2
150const IM_C_ACCEL: i64 = 3
151const IM_C_DSP: i64 = 4
152const IM_C_VM: i64 = 5
153const IM_C_FPGA: i64 = 6
154const IM_C_LEGACY: i64 = 7
155const IM_C_IMPL: i64 = 8
156const IM_C_EXT: i64 = 9
157const IM_C_NISHI: i64 = 10
158const IM_C_UNKNOWN: i64 = 11
159const IM_C_COUNT: i64 = 12
160
161func im_class_name(c: i64) -> *u8 {
162 if c == IM_C_CPU { return "cpu" as *u8 }
163 if c == IM_C_MCU { return "mcu" as *u8 }
164 if c == IM_C_GPU { return "gpu" as *u8 }
165 if c == IM_C_ACCEL { return "accel" as *u8 }
166 if c == IM_C_DSP { return "dsp" as *u8 }
167 if c == IM_C_VM { return "vm" as *u8 }
168 if c == IM_C_FPGA { return "fpga" as *u8 }
169 if c == IM_C_LEGACY { return "legacy" as *u8 }
170 if c == IM_C_IMPL { return "impl" as *u8 }
171 if c == IM_C_EXT { return "ext" as *u8 }
172 if c == IM_C_NISHI { return "nishi" as *u8 }
173 return "UNKNOWN-CLASS" as *u8
174}
175
176// ---- states. UNSET is a real value the array is initialised to, so
177// "every target got exactly one named state" is a MEASUREMENT and not
178// an assumption: any row the classifier failed to reach is still UNSET
179// at the end and the tooth names it.
180const IM_S_UNSET: i64 = -1
181const IM_S_GREEN: i64 = 0
182const IM_S_RED: i64 = 1
183const IM_S_UNRUN: i64 = 2
184const IM_S_EMUONLY: i64 = 3
185const IM_S_DECLARED: i64 = 4
186const IM_S_NOTARGET: i64 = 5
187const IM_S_COUNT: i64 = 6
188
189func im_state_name(s: i64) -> *u8 {
190 if s == IM_S_GREEN { return "MEASURED-GREEN" as *u8 }
191 if s == IM_S_RED { return "MEASURED-RED" as *u8 }
192 if s == IM_S_UNRUN { return "GATE-PRESENT-UNRUN" as *u8 }
193 if s == IM_S_EMUONLY { return "EMULATOR-ONLY" as *u8 }
194 if s == IM_S_DECLARED { return "DECLARED-ONLY" as *u8 }
195 if s == IM_S_NOTARGET { return "NOT-A-TARGET" as *u8 }
196 return "UNSET-CLASSIFIER-DID-NOT-REACH-THIS-ROW" as *u8
197}
198
199func im_state_meaning(s: i64) -> *u8 {
200 if s == IM_S_GREEN { return "a ratchet banks a passing score for it" as *u8 }
201 if s == IM_S_RED { return "a ratchet banks a score of zero: measured, and nothing passes" as *u8 }
202 if s == IM_S_UNRUN { return "a gate covers it, no ratchet banks a score, so no run was ever recorded" as *u8 }
203 if s == IM_S_EMUONLY { return "an emulator exists and nothing rules on it" as *u8 }
204 if s == IM_S_DECLARED { return "in the population, no emulator, no gate: the frontier" as *u8 }
205 if s == IM_S_NOTARGET { return "impl or ext row: a host or an extension, never a standalone codegen target" as *u8 }
206 return "the classifier did not reach this row -- a defect in this organ" as *u8
207}
208
209// ---- tiny string helpers ---------------------------------------
210
211func im_nl() -> i64 {
212 let b: *u8 = sys_mmap(IM_WORD)
213 b[0] = IM_NL as u8
214 sys_write(1, b, 1)
215 return 0
216}
217
218// Compare a (buf, off, len) slice against a NUL-terminated string.
219func im_slice_eq(buf: *u8, off: i64, len: i64, s: *u8) -> i64 {
220 var i: i64 = 0
221 var ok: i64 = 1
222 while s[i] != (IM_NUL as u8) {
223 if i >= len { ok = 0 }
224 if ok == 1 {
225 if buf[off + i] != s[i] { ok = 0 }
226 }
227 i = i + 1
228 }
229 if i != len { ok = 0 }
230 return ok
231}
232
233func im_slice_eq_slice(a: *u8, ao: i64, al: i64, b: *u8, bo: i64, bl: i64) -> i64 {
234 if al != bl { return 0 }
235 var i: i64 = 0
236 var ok: i64 = 1
237 while i < al {
238 if a[ao + i] != b[bo + i] { ok = 0 }
239 i = i + 1
240 }
241 return ok
242}
243
244func im_cat_slice(d: *u8, o: i64, buf: *u8, off: i64, len: i64) -> i64 {
245 var i: i64 = 0
246 var p: i64 = o
247 while i < len {
248 d[p] = buf[off + i]
249 p = p + 1
250 i = i + 1
251 }
252 return p
253}
254
255// Print a slice. Slices are not NUL-terminated so they are copied into
256// scratch first, which keeps every emitter going through gv_puts.
257func im_puts_slice(scratch: *u8, buf: *u8, off: i64, len: i64) -> i64 {
258 var n: i64 = len
259 if n > (IM_SLICE_BYTES - 1) { n = IM_SLICE_BYTES - 1 }
260 let p: i64 = im_cat_slice(scratch, 0, buf, off, n)
261 scratch[p] = IM_NUL as u8
262 gv_puts(scratch)
263 return n
264}
265
266// ---- existence probing -----------------------------------------
267
268func im_exists(path: *u8) -> i64 {
269 let fd: i64 = sys_openat_rd(path)
270 if fd < 0 { return 0 }
271 sys_close(fd)
272 return 1
273}
274
275// Build <root><pre><slug><suf> and return the root index it resolved
276// from, or -1. Asking all four roots is the whole point: a probe that
277// knows one tree answers a confident false negative for anything that
278// lives in the other.
279func im_probe_roots(scratch: *u8, pre: *u8, buf: *u8, off: i64, len: i64, suf: *u8) -> i64 {
280 var r: i64 = 0
281 var hit: i64 = -1
282 while r < IM_ROOTS {
283 if hit < 0 {
284 var p: i64 = gv_cat(scratch, 0, im_root(r))
285 p = gv_cat(scratch, p, pre)
286 p = im_cat_slice(scratch, p, buf, off, len)
287 p = gv_cat(scratch, p, suf)
288 scratch[p] = IM_NUL as u8
289 if im_exists(scratch) == 1 { hit = r }
290 }
291 r = r + 1
292 }
293 return hit
294}
295
296// Read a knowledge-rooted file from whichever tree carries it.
297func im_kread(scratch: *u8, name: *u8, lenbox: *i64) -> *u8 {
298 var r: i64 = 0
299 var got: *u8 = 0 as *u8
300 while r < IM_KROOTS {
301 if (got as i64) == 0 {
302 var p: i64 = gv_cat(scratch, 0, im_kroot(r))
303 p = gv_cat(scratch, p, name)
304 scratch[p] = IM_NUL as u8
305 got = sys_read_file(scratch, lenbox)
306 }
307 r = r + 1
308 }
309 return got
310}
311
312// ---- substring search (core-gate import detection) --------------
313func im_contains(buf: *u8, n: i64, s: *u8) -> i64 {
314 var sl: i64 = 0
315 while s[sl] != (IM_NUL as u8) { sl = sl + 1 }
316 if sl == 0 { return 0 }
317 if sl > n { return 0 }
318 var i: i64 = 0
319 var hit: i64 = 0
320 let last: i64 = n - sl
321 while i <= last {
322 if hit == 0 {
323 var j: i64 = 0
324 var ok: i64 = 1
325 while j < sl {
326 if ok == 1 {
327 if buf[i + j] != s[j] { ok = 0 }
328 }
329 j = j + 1
330 }
331 if ok == 1 { hit = 1 }
332 }
333 i = i + 1
334 }
335 return hit
336}
337
338// Same question, asked with a slug slice rather than a literal.
339func im_contains_slug(scratch: *u8, buf: *u8, n: i64, pre: *u8, sb: *u8, so: i64, sl: i64, suf: *u8) -> i64 {
340 var p: i64 = gv_cat(scratch, 0, pre)
341 p = im_cat_slice(scratch, p, sb, so, sl)
342 p = gv_cat(scratch, p, suf)
343 scratch[p] = IM_NUL as u8
344 return im_contains(buf, n, scratch)
345}
346
347// ---- ratchet reading (READ ONLY -- the gates own these files) ----
348// Format, identical in the shared core file and in every per-arch file:
349// one line per arch, "<slug> <passed>". Reading both through ONE
350// function is deliberate: two readers of one format is the duplicate
351// ruler defect, and they drift.
352func im_digits_at(buf: *u8, n: i64, p0: i64) -> i64 {
353 var v: i64 = 0
354 var any: i64 = 0
355 var p: i64 = p0
356 var go: i64 = 1
357 while go == 1 {
358 if p >= n { go = 0 }
359 if go == 1 {
360 let c: i64 = buf[p] & IM_BYTE_M
361 if c < IM_DIG_LO { go = 0 }
362 if go == 1 {
363 if c > IM_DIG_HI { go = 0 }
364 }
365 if go == 1 {
366 v = v * IM_B10 + (c - IM_DIG_LO)
367 any = 1
368 p = p + 1
369 }
370 }
371 }
372 if any == 0 { return -1 }
373 return v
374}
375
376func im_ratchet_score(buf: *u8, n: i64, sb: *u8, so: i64, sl: i64) -> i64 {
377 var i: i64 = 0
378 var found: i64 = -1
379 while i < n {
380 if found < 0 {
381 if (i + sl) < n {
382 if im_slice_eq_slice(buf, i, sl, sb, so, sl) == 1 {
383 if buf[i + sl] == (IM_SPACE as u8) {
384 found = im_digits_at(buf, n, i + sl + 1)
385 }
386 }
387 }
388 }
389 var adv: i64 = 1
390 while adv == 1 {
391 if i >= n { adv = 0 }
392 if adv == 1 {
393 if buf[i] == (IM_NL as u8) { adv = 0 }
394 i = i + 1
395 }
396 }
397 }
398 return found
399}
400
401// ---- box layout for the population table -----------------------
402// Parallel arrays rather than a struct: this dialect resolves a field
403// name across every struct, so parallel arrays with named index
404// constants are the safer shape here.
405const IM_A_IDOFF: i64 = 0
406const IM_A_IDLEN: i64 = 1
407const IM_A_CLS: i64 = 2
408const IM_A_SRC: i64 = 3
409const IM_A_SOFF: i64 = 4
410const IM_A_SLEN: i64 = 5
411const IM_A_STATE: i64 = 6
412const IM_A_SCORE: i64 = 7
413const IM_A_GATE: i64 = 8
414const IM_A_EMU: i64 = 9
415const IM_A_RATSRC: i64 = 10
416const IM_A_COUNT: i64 = 11
417
418const IM_SRC_CONF: i64 = 0
419const IM_SRC_ALIAS: i64 = 1
420
421// Which ratchet a score came from, so a reader can tell the shared core
422// file from a per-arch one without opening either.
423const IM_RS_NONE: i64 = 0
424const IM_RS_PER: i64 = 1
425const IM_RS_CORE: i64 = 2
426func im_ratsrc_name(r: i64) -> *u8 {
427 if r == IM_RS_PER { return "per-arch" as *u8 }
428 if r == IM_RS_CORE { return "core-shared" as *u8 }
429 return "none" as *u8
430}
431
432func im_cell(tab: *i64, i: i64, f: i64) -> i64 { return tab[i * IM_A_COUNT + f] }
433func im_setcell(tab: *i64, i: i64, f: i64, v: i64) -> i64 {
434 tab[i * IM_A_COUNT + f] = v
435 return v
436}
437
438func im_permil(a: i64, b: i64) -> i64 {
439 if b <= 0 { return -1 }
440 return (a * IM_PERMIL) / b
441}
442
443func im_class_of(buf: *u8, off: i64, len: i64) -> i64 {
444 if im_slice_eq(buf, off, len, "cpu" as *u8) == 1 { return IM_C_CPU }
445 if im_slice_eq(buf, off, len, "mcu" as *u8) == 1 { return IM_C_MCU }
446 if im_slice_eq(buf, off, len, "gpu" as *u8) == 1 { return IM_C_GPU }
447 if im_slice_eq(buf, off, len, "accel" as *u8) == 1 { return IM_C_ACCEL }
448 if im_slice_eq(buf, off, len, "dsp" as *u8) == 1 { return IM_C_DSP }
449 if im_slice_eq(buf, off, len, "vm" as *u8) == 1 { return IM_C_VM }
450 if im_slice_eq(buf, off, len, "fpga" as *u8) == 1 { return IM_C_FPGA }
451 if im_slice_eq(buf, off, len, "legacy" as *u8) == 1 { return IM_C_LEGACY }
452 if im_slice_eq(buf, off, len, "impl" as *u8) == 1 { return IM_C_IMPL }
453 if im_slice_eq(buf, off, len, "ext" as *u8) == 1 { return IM_C_EXT }
454 if im_slice_eq(buf, off, len, "nishi" as *u8) == 1 { return IM_C_NISHI }
455 return IM_C_UNKNOWN
456}
457
458// Is this class a codegen target at all? impl and ext are not, and the
459// answer is asked ONCE here so the exclusion cannot be spelled two ways
460// in two places.
461func im_is_target(c: i64) -> i64 {
462 if c == IM_C_IMPL { return 0 }
463 if c == IM_C_EXT { return 0 }
464 return 1
465}
466
467// ---- the state decision, in ONE place --------------------------
468// Two organs that must agree should be made unable to disagree; this
469// classifier is the single place a state is decided, so the worklist,
470// the counts and the per-row print can never drift apart.
471func im_classify(is_target: i64, score: i64, gate: i64, emu: i64) -> i64 {
472 if is_target == 0 { return IM_S_NOTARGET }
473 if score > 0 { return IM_S_GREEN }
474 if score == 0 { return IM_S_RED }
475 if gate == 1 { return IM_S_UNRUN }
476 if emu == 1 { return IM_S_EMUONLY }
477 return IM_S_DECLARED
478}
479
480// ===== main =====================================================
481
482func main(argc: i64, argv: *i64) -> i64 {
483 gv_head("nx_isa_manager -- the master ISA manager: declared population, discovered evidence, one named state per ISA, coverage with its denominator, worklist last" as *u8)
484 let ctr: *i64 = gv_ctr()
485
486 let scratch: *u8 = sys_mmap(IM_PATH_BYTES)
487 let scr2: *u8 = sys_mmap(IM_PATH_BYTES)
488 let slice: *u8 = sys_mmap(IM_SLICE_BYTES)
489 let tab: *i64 = sys_mmap(IM_MAX_TARGETS * IM_A_COUNT * IM_WORD) as *i64
490 let alid: *i64 = sys_mmap(IM_MAX_ALIAS * IM_ALIAS_COLS * IM_WORD) as *i64
491
492 // ---- read the population ----
493 let clen: *i64 = sys_mmap(IM_BOX_BYTES) as *i64
494 let conf: *u8 = im_kread(scratch, IM_CONF_NAME, clen)
495 var cn: i64 = 0
496 if (conf as i64) != 0 { cn = clen[0] }
497
498 gv_puts("population conf: " as *u8)
499 gv_puts(IM_CONF_NAME)
500 gv_puts(" bytes=" as *u8)
501 gv_num(cn)
502 im_nl()
503
504 // ---- read the alias table (optional DATA) ----
505 let alen: *i64 = sys_mmap(IM_BOX_BYTES) as *i64
506 let abuf: *u8 = im_kread(scratch, IM_ALIAS_NAME, alen)
507 var an: i64 = 0
508 if (abuf as i64) != 0 { an = alen[0] }
509 var alias_rows: i64 = 0
510 var alias_over: i64 = 0
511
512 var i: i64 = 0
513 while i < an {
514 let als: i64 = i
515 var ale: i64 = i
516 var asc: i64 = 1
517 while asc == 1 {
518 if ale >= an { asc = 0 }
519 if asc == 1 {
520 if abuf[ale] == (IM_NL as u8) { asc = 0 }
521 if asc == 1 { ale = ale + 1 }
522 }
523 }
524 var alend: i64 = ale
525 if alend > als {
526 if abuf[alend - 1] == (IM_CR as u8) { alend = alend - 1 }
527 }
528 if im_slice_eq(abuf, als, IM_ALIAS_TAG, "alias|" as *u8) == 1 {
529 let aido: i64 = als + IM_ALIAS_TAG
530 var q: i64 = aido
531 var aidl: i64 = -1
532 while q < alend {
533 if aidl < 0 {
534 if abuf[q] == (IM_PIPE as u8) { aidl = q - aido }
535 }
536 q = q + 1
537 }
538 if aidl > 0 {
539 let aslo: i64 = aido + aidl + 1
540 var q2: i64 = aslo
541 var asll: i64 = -1
542 while q2 < alend {
543 if asll < 0 {
544 if abuf[q2] == (IM_PIPE as u8) { asll = q2 - aslo }
545 }
546 q2 = q2 + 1
547 }
548 if asll < 0 { asll = alend - aslo }
549 if asll > 0 {
550 if alias_rows < IM_MAX_ALIAS {
551 alid[alias_rows * IM_ALIAS_COLS] = aido
552 alid[alias_rows * IM_ALIAS_COLS + 1] = aidl
553 alid[alias_rows * IM_ALIAS_COLS + 2] = aslo
554 alid[alias_rows * IM_ALIAS_COLS + 3] = asll
555 alias_rows = alias_rows + 1
556 }
557 if alias_rows >= IM_MAX_ALIAS { alias_over = 1 }
558 }
559 }
560 }
561 i = ale + 1
562 }
563
564 gv_puts("alias conf: " as *u8)
565 gv_puts(IM_ALIAS_NAME)
566 gv_puts(" bytes=" as *u8)
567 gv_num(an)
568 gv_puts(" rows=" as *u8)
569 gv_num(alias_rows)
570 if an == 0 {
571 gv_puts(" ABSENT -- every id resolves to itself, which is the default and not an error" as *u8)
572 }
573 im_nl()
574
575 // ---- read the core gate source and the shared ratchet ----
576 var core_n: i64 = 0
577 var core_root: i64 = -1
578 var core: *u8 = 0 as *u8
579 let corelen: *i64 = sys_mmap(IM_BOX_BYTES) as *i64
580 var rr: i64 = 0
581 while rr < IM_ROOTS {
582 if (core as i64) == 0 {
583 var cp: i64 = gv_cat(scratch, 0, im_root(rr))
584 cp = gv_cat(scratch, cp, IM_CORE_GATE)
585 scratch[cp] = IM_NUL as u8
586 core = sys_read_file(scratch, corelen)
587 if (core as i64) != 0 { core_root = rr }
588 }
589 rr = rr + 1
590 }
591 if (core as i64) != 0 { core_n = corelen[0] }
592
593 gv_puts("core gate: " as *u8)
594 gv_puts(IM_CORE_GATE)
595 gv_puts(" bytes=" as *u8)
596 gv_num(core_n)
597 gv_puts(" root=" as *u8)
598 if core_root >= 0 { gv_puts(im_root(core_root)) }
599 if core_root < 0 { gv_puts("UNRESOLVED-in-all-4-roots" as *u8) }
600 im_nl()
601
602 let crlen: *i64 = sys_mmap(IM_BOX_BYTES) as *i64
603 let cratch: *u8 = im_kread(scratch, IM_CORE_RATCH, crlen)
604 var crn: i64 = 0
605 if (cratch as i64) != 0 { crn = crlen[0] }
606 gv_puts("shared ratchet: " as *u8)
607 gv_puts(IM_CORE_RATCH)
608 gv_puts(" bytes=" as *u8)
609 gv_num(crn)
610 gv_puts(" READ-ONLY here: the gates own it" as *u8)
611 im_nl()
612 im_nl()
613
614 // ---- parse the population ----
615 var n: i64 = 0
616 var malformed: i64 = 0
617 var isa_lines: i64 = 0
618 var over_cap: i64 = 0
619
620 i = 0
621 while i < cn {
622 let ls: i64 = i
623 var le: i64 = i
624 var sc: i64 = 1
625 while sc == 1 {
626 if le >= cn { sc = 0 }
627 if sc == 1 {
628 if conf[le] == (IM_NL as u8) { sc = 0 }
629 if sc == 1 { le = le + 1 }
630 }
631 }
632 var lend: i64 = le
633 if lend > ls {
634 if conf[lend - 1] == (IM_CR as u8) { lend = lend - 1 }
635 }
636 if im_slice_eq(conf, ls, IM_ISA_TAG, "isa|" as *u8) == 1 {
637 isa_lines = isa_lines + 1
638 var fo: i64 = ls + IM_ISA_TAG
639 var fields: i64 = 1
640 let ido: i64 = fo
641 var idl: i64 = -1
642 var clo: i64 = -1
643 var cll: i64 = -1
644 var p: i64 = fo
645 while p <= lend {
646 var atend: i64 = 0
647 if p == lend { atend = 1 }
648 if atend == 0 {
649 if conf[p] == (IM_PIPE as u8) { atend = 1 }
650 }
651 if atend == 1 {
652 if fields == 1 { idl = p - fo }
653 if fields == 3 {
654 clo = fo
655 cll = p - fo
656 }
657 fields = fields + 1
658 fo = p + 1
659 }
660 p = p + 1
661 }
662 let nfields: i64 = fields - 1
663 var good: i64 = 1
664 if nfields != IM_FIELDS_AFTER_TAG { good = 0 }
665 if idl <= 0 { good = 0 }
666 if cll <= 0 { good = 0 }
667 if good == 0 { malformed = malformed + 1 }
668 if good == 1 {
669 if n < IM_MAX_TARGETS {
670 im_setcell(tab, n, IM_A_IDOFF, ido)
671 im_setcell(tab, n, IM_A_IDLEN, idl)
672 im_setcell(tab, n, IM_A_CLS, im_class_of(conf, clo, cll))
673 im_setcell(tab, n, IM_A_SRC, IM_SRC_CONF)
674 im_setcell(tab, n, IM_A_SOFF, ido)
675 im_setcell(tab, n, IM_A_SLEN, idl)
676 im_setcell(tab, n, IM_A_STATE, IM_S_UNSET)
677 im_setcell(tab, n, IM_A_SCORE, -1)
678 im_setcell(tab, n, IM_A_GATE, 0)
679 im_setcell(tab, n, IM_A_EMU, 0)
680 im_setcell(tab, n, IM_A_RATSRC, IM_RS_NONE)
681 n = n + 1
682 }
683 if n >= IM_MAX_TARGETS { over_cap = 1 }
684 }
685 }
686 i = le + 1
687 }
688
689 // ---- resolve slugs from the alias table ----
690 var aliased: i64 = 0
691 var alias_unknown: i64 = 0
692 var ai: i64 = 0
693 while ai < alias_rows {
694 let aio: i64 = alid[ai * IM_ALIAS_COLS]
695 let ail: i64 = alid[ai * IM_ALIAS_COLS + 1]
696 let aso: i64 = alid[ai * IM_ALIAS_COLS + 2]
697 let asl: i64 = alid[ai * IM_ALIAS_COLS + 3]
698 var matched: i64 = 0
699 var t: i64 = 0
700 while t < n {
701 if im_slice_eq_slice(conf, im_cell(tab, t, IM_A_IDOFF), im_cell(tab, t, IM_A_IDLEN), abuf, aio, ail) == 1 {
702 im_setcell(tab, t, IM_A_SRC, IM_SRC_ALIAS)
703 im_setcell(tab, t, IM_A_SOFF, aso)
704 im_setcell(tab, t, IM_A_SLEN, asl)
705 matched = 1
706 }
707 t = t + 1
708 }
709 if matched == 1 { aliased = aliased + 1 }
710 if matched == 0 {
711 alias_unknown = alias_unknown + 1
712 gv_puts("ALIAS-ID-NOT-IN-POPULATION " as *u8)
713 im_puts_slice(slice, abuf, aio, ail)
714 gv_puts(" an alias for an undeclared id silently hides a target" as *u8)
715 im_nl()
716 }
717 ai = ai + 1
718 }
719
720 // ---- probe evidence and classify ----
721 var t2: i64 = 0
722 while t2 < n {
723 let cls: i64 = im_cell(tab, t2, IM_A_CLS)
724 let istgt: i64 = im_is_target(cls)
725 if istgt == 1 {
726 var sb: *u8 = conf
727 if im_cell(tab, t2, IM_A_SRC) == IM_SRC_ALIAS { sb = abuf }
728 let so: i64 = im_cell(tab, t2, IM_A_SOFF)
729 let sl: i64 = im_cell(tab, t2, IM_A_SLEN)
730
731 let emur: i64 = im_probe_roots(scratch, IM_EMU_PRE, sb, so, sl, IM_NX_SUF)
732 var emu: i64 = 0
733 if emur >= 0 { emu = 1 }
734
735 let gr: i64 = im_probe_roots(scratch, IM_GATE_PRE, sb, so, sl, IM_GATE_SUF)
736 var gate: i64 = 0
737 if gr >= 0 { gate = 1 }
738 // A gate need not be a separate file: the core gate imports
739 // the emulators it measures, so its own source is evidence.
740 if gate == 0 {
741 if core_n > 0 {
742 if im_contains_slug(scr2, core, core_n, IM_EMU_PRE, sb, so, sl, IM_NX_SUF) == 1 { gate = 1 }
743 }
744 }
745
746 // score: per-arch ratchet first, shared core ratchet second.
747 var score: i64 = -1
748 var rsrc: i64 = IM_RS_NONE
749 let prl: *i64 = sys_mmap(IM_BOX_BYTES) as *i64
750 var rp: i64 = gv_cat(scratch, 0, IM_RATCH_PRE)
751 rp = im_cat_slice(scratch, rp, sb, so, sl)
752 rp = gv_cat(scratch, rp, IM_RATCH_SUF)
753 scratch[rp] = IM_NUL as u8
754 let pr: *u8 = im_kread(scr2, scratch, prl)
755 if (pr as i64) != 0 {
756 let prn: i64 = prl[0]
757 let s2: i64 = im_ratchet_score(pr, prn, sb, so, sl)
758 if s2 >= 0 {
759 score = s2
760 rsrc = IM_RS_PER
761 }
762 }
763 if score < 0 {
764 if crn > 0 {
765 let s3: i64 = im_ratchet_score(cratch, crn, sb, so, sl)
766 if s3 >= 0 {
767 score = s3
768 rsrc = IM_RS_CORE
769 }
770 }
771 }
772
773 im_setcell(tab, t2, IM_A_EMU, emu)
774 im_setcell(tab, t2, IM_A_GATE, gate)
775 im_setcell(tab, t2, IM_A_SCORE, score)
776 im_setcell(tab, t2, IM_A_RATSRC, rsrc)
777 im_setcell(tab, t2, IM_A_STATE, im_classify(1, score, gate, emu))
778 }
779 if istgt == 0 {
780 im_setcell(tab, t2, IM_A_STATE, im_classify(0, -1, 0, 0))
781 }
782 t2 = t2 + 1
783 }
784
785 // ---- CLASS PARTITION ----
786 let ccnt: *i64 = sys_mmap(IM_C_COUNT * IM_WORD) as *i64
787 var ci: i64 = 0
788 while ci < IM_C_COUNT {
789 ccnt[ci] = 0
790 ci = ci + 1
791 }
792 var t3: i64 = 0
793 while t3 < n {
794 let c: i64 = im_cell(tab, t3, IM_A_CLS)
795 ccnt[c] = ccnt[c] + 1
796 t3 = t3 + 1
797 }
798 var csum: i64 = 0
799 gv_puts("=== CLASS PARTITION (a partition is a claim: the parts must sum) ===" as *u8)
800 im_nl()
801 ci = 0
802 while ci < IM_C_COUNT {
803 if ccnt[ci] > 0 {
804 gv_puts(" class " as *u8)
805 gv_puts(im_class_name(ci))
806 gv_puts(" = " as *u8)
807 gv_num(ccnt[ci])
808 if im_is_target(ci) == 0 { gv_puts(" NOT A CODEGEN TARGET: excluded from every emulator and gate ratio" as *u8) }
809 im_nl()
810 }
811 csum = csum + ccnt[ci]
812 ci = ci + 1
813 }
814 gv_puts(" class parts sum = " as *u8)
815 gv_num(csum)
816 gv_puts(" rows parsed = " as *u8)
817 gv_num(n)
818 gv_puts(" isa-tagged lines seen = " as *u8)
819 gv_num(isa_lines)
820 gv_puts(" malformed = " as *u8)
821 gv_num(malformed)
822 im_nl()
823 im_nl()
824
825 // ---- STATE PARTITION ----
826 let scnt: *i64 = sys_mmap((IM_S_COUNT + 1) * IM_WORD) as *i64
827 var si: i64 = 0
828 while si < IM_S_COUNT {
829 scnt[si] = 0
830 si = si + 1
831 }
832 var unset: i64 = 0
833 var t4: i64 = 0
834 while t4 < n {
835 let s: i64 = im_cell(tab, t4, IM_A_STATE)
836 if s == IM_S_UNSET { unset = unset + 1 }
837 if s != IM_S_UNSET { scnt[s] = scnt[s] + 1 }
838 t4 = t4 + 1
839 }
840 var ssum: i64 = unset
841 gv_puts("=== PER-ISA STATE PARTITION (every row gets exactly one NAMED state) ===" as *u8)
842 im_nl()
843 si = 0
844 while si < IM_S_COUNT {
845 gv_puts(" " as *u8)
846 gv_puts(im_state_name(si))
847 gv_puts(" = " as *u8)
848 gv_num(scnt[si])
849 gv_puts(" " as *u8)
850 gv_puts(im_state_meaning(si))
851 im_nl()
852 ssum = ssum + scnt[si]
853 si = si + 1
854 }
855 gv_puts(" UNSET (classifier did not reach) = " as *u8)
856 gv_num(unset)
857 im_nl()
858 gv_puts(" state parts sum = " as *u8)
859 gv_num(ssum)
860 gv_puts(" rows parsed = " as *u8)
861 gv_num(n)
862 im_nl()
863 im_nl()
864
865 // ---- COVERAGE WITH ITS DENOMINATOR ----
866 let targetable: i64 = n - scnt[IM_S_NOTARGET]
867 var with_emu: i64 = 0
868 var with_gate: i64 = 0
869 var measured: i64 = 0
870 var banked_total: i64 = 0
871 var t5: i64 = 0
872 while t5 < n {
873 if im_is_target(im_cell(tab, t5, IM_A_CLS)) == 1 {
874 if im_cell(tab, t5, IM_A_EMU) == 1 { with_emu = with_emu + 1 }
875 if im_cell(tab, t5, IM_A_GATE) == 1 { with_gate = with_gate + 1 }
876 if im_cell(tab, t5, IM_A_SCORE) >= 0 {
877 measured = measured + 1
878 banked_total = banked_total + im_cell(tab, t5, IM_A_SCORE)
879 }
880 }
881 t5 = t5 + 1
882 }
883
884 // Distinct emulator SLUGS, not rows. A reference count is not a work
885 // count: two ids aliased onto one emulator would read as two covered
886 // targets from one organ, and only the distinct count exposes that.
887 var distinct_emu: i64 = 0
888 var t6: i64 = 0
889 while t6 < n {
890 if im_is_target(im_cell(tab, t6, IM_A_CLS)) == 1 {
891 if im_cell(tab, t6, IM_A_EMU) == 1 {
892 var seen: i64 = 0
893 var u: i64 = 0
894 while u < t6 {
895 if im_is_target(im_cell(tab, u, IM_A_CLS)) == 1 {
896 if im_cell(tab, u, IM_A_EMU) == 1 {
897 var ab: *u8 = conf
898 if im_cell(tab, u, IM_A_SRC) == IM_SRC_ALIAS { ab = abuf }
899 var bb: *u8 = conf
900 if im_cell(tab, t6, IM_A_SRC) == IM_SRC_ALIAS { bb = abuf }
901 if im_slice_eq_slice(ab, im_cell(tab, u, IM_A_SOFF), im_cell(tab, u, IM_A_SLEN), bb, im_cell(tab, t6, IM_A_SOFF), im_cell(tab, t6, IM_A_SLEN)) == 1 { seen = 1 }
902 }
903 }
904 u = u + 1
905 }
906 if seen == 0 { distinct_emu = distinct_emu + 1 }
907 }
908 }
909 t6 = t6 + 1
910 }
911
912 gv_puts("=== COVERAGE (the denominator travels with every ratio) ===" as *u8)
913 im_nl()
914 gv_puts(" population rows = " as *u8)
915 gv_num(n)
916 im_nl()
917 gv_puts(" NOT-A-TARGET (impl + ext) = " as *u8)
918 gv_num(scnt[IM_S_NOTARGET])
919 gv_puts(" excluded from every ratio below" as *u8)
920 im_nl()
921 gv_puts(" TARGETABLE denominator = " as *u8)
922 gv_num(targetable)
923 im_nl()
924 gv_puts(" with an emulator = " as *u8)
925 gv_num(with_emu)
926 gv_puts(" of " as *u8)
927 gv_num(targetable)
928 gv_puts(" permil=" as *u8)
929 gv_num(im_permil(with_emu, targetable))
930 im_nl()
931 gv_puts(" distinct emulator slugs = " as *u8)
932 gv_num(distinct_emu)
933 gv_puts(" a reference count is not a work count" as *u8)
934 im_nl()
935 gv_puts(" covered by a gate = " as *u8)
936 gv_num(with_gate)
937 gv_puts(" of " as *u8)
938 gv_num(targetable)
939 gv_puts(" permil=" as *u8)
940 gv_num(im_permil(with_gate, targetable))
941 im_nl()
942 gv_puts(" MEASURED (a banked score) = " as *u8)
943 gv_num(measured)
944 gv_puts(" of " as *u8)
945 gv_num(targetable)
946 gv_puts(" permil=" as *u8)
947 gv_num(im_permil(measured, targetable))
948 im_nl()
949 im_nl()
950
951 // ---- PER-CLASS COVERAGE ----
952 gv_puts("=== COVERAGE BY CLASS (measured / with-emulator / rows) ===" as *u8)
953 im_nl()
954 ci = 0
955 while ci < IM_C_COUNT {
956 if ccnt[ci] > 0 {
957 var cm: i64 = 0
958 var ce: i64 = 0
959 var t7: i64 = 0
960 while t7 < n {
961 if im_cell(tab, t7, IM_A_CLS) == ci {
962 if im_cell(tab, t7, IM_A_SCORE) >= 0 { cm = cm + 1 }
963 if im_cell(tab, t7, IM_A_EMU) == 1 { ce = ce + 1 }
964 }
965 t7 = t7 + 1
966 }
967 gv_puts(" " as *u8)
968 gv_puts(im_class_name(ci))
969 gv_puts(" measured=" as *u8)
970 gv_num(cm)
971 gv_puts(" emulated=" as *u8)
972 gv_num(ce)
973 gv_puts(" rows=" as *u8)
974 gv_num(ccnt[ci])
975 if im_is_target(ci) == 0 { gv_puts(" NOT-A-TARGET class: zeros here are correct, not a gap" as *u8) }
976 im_nl()
977 }
978 ci = ci + 1
979 }
980 im_nl()
981
982 // ---- RATCHET LEVELS (read, never written) ----
983 gv_puts("=== BANKED RATCHET SCORES (good-when-higher; the gates own these files) ===" as *u8)
984 im_nl()
985 gv_puts(" A ratchet file holds a LEVEL. A level cannot express a trajectory:" as *u8)
986 im_nl()
987 gv_puts(" one reading gives a number, two readings say whether the estate is climbing." as *u8)
988 im_nl()
989 gv_puts(" banked_total is the single scalar to watch across runs." as *u8)
990 im_nl()
991 var t8: i64 = 0
992 while t8 < n {
993 if im_cell(tab, t8, IM_A_SCORE) >= 0 {
994 gv_puts(" " as *u8)
995 im_puts_slice(slice, conf, im_cell(tab, t8, IM_A_IDOFF), im_cell(tab, t8, IM_A_IDLEN))
996 gv_puts(" banked=" as *u8)
997 gv_num(im_cell(tab, t8, IM_A_SCORE))
998 gv_puts(" from=" as *u8)
999 gv_puts(im_ratsrc_name(im_cell(tab, t8, IM_A_RATSRC)))
1000 im_nl()
1001 }
1002 t8 = t8 + 1
1003 }
1004 gv_puts(" banked_total = " as *u8)
1005 gv_num(banked_total)
1006 gv_puts(" over " as *u8)
1007 gv_num(measured)
1008 gv_puts(" measured architectures" as *u8)
1009 im_nl()
1010 im_nl()
1011
1012 // ---- PER-ISA TABLE ----
1013 gv_puts("=== PER-ISA STATE (id class slug emu gate score STATE) ===" as *u8)
1014 im_nl()
1015 var t9: i64 = 0
1016 while t9 < n {
1017 gv_puts(" " as *u8)
1018 im_puts_slice(slice, conf, im_cell(tab, t9, IM_A_IDOFF), im_cell(tab, t9, IM_A_IDLEN))
1019 gv_puts(" " as *u8)
1020 gv_puts(im_class_name(im_cell(tab, t9, IM_A_CLS)))
1021 gv_puts(" slug=" as *u8)
1022 var sb2: *u8 = conf
1023 if im_cell(tab, t9, IM_A_SRC) == IM_SRC_ALIAS { sb2 = abuf }
1024 im_puts_slice(slice, sb2, im_cell(tab, t9, IM_A_SOFF), im_cell(tab, t9, IM_A_SLEN))
1025 if im_cell(tab, t9, IM_A_SRC) == IM_SRC_ALIAS { gv_puts("(alias)" as *u8) }
1026 gv_puts(" emu=" as *u8)
1027 gv_num(im_cell(tab, t9, IM_A_EMU))
1028 gv_puts(" gate=" as *u8)
1029 gv_num(im_cell(tab, t9, IM_A_GATE))
1030 gv_puts(" score=" as *u8)
1031 gv_num(im_cell(tab, t9, IM_A_SCORE))
1032 gv_puts(" " as *u8)
1033 gv_puts(im_state_name(im_cell(tab, t9, IM_A_STATE)))
1034 im_nl()
1035 t9 = t9 + 1
1036 }
1037 im_nl()
1038
1039 // ---- TEETH: structural only ----
1040 gv_puts("=== TEETH (structural: what THIS organ controls, never the health of an ISA) ===" as *u8)
1041 im_nl()
1042
1043 gv_check("fixture-reached-population-conf-is-nonempty" as *u8, cn > 0, ctr)
1044 gv_check("fixture-reached-rows-were-parsed" as *u8, n > 0, ctr)
1045 gv_check("class-partition-sums-to-rows-parsed" as *u8, csum == n, ctr)
1046 gv_check("isa-lines-reconcile-parsed-plus-malformed" as *u8, isa_lines == (n + malformed), ctr)
1047 gv_check("state-partition-sums-to-rows-parsed" as *u8, ssum == n, ctr)
1048 gv_check("every-row-got-exactly-one-named-state" as *u8, unset == 0, ctr)
1049 gv_check("no-silent-cap-on-the-population-table" as *u8, over_cap == 0, ctr)
1050 gv_check("no-silent-cap-on-the-alias-table" as *u8, alias_over == 0, ctr)
1051 gv_check("every-alias-id-exists-in-the-population" as *u8, alias_unknown == 0, ctr)
1052 gv_check("core-gate-source-resolved-in-some-root" as *u8, core_n > 0, ctr)
1053 gv_check("discovery-found-at-least-the-known-gate-floor" as *u8, with_gate >= IM_GATE_FLOOR, ctr)
1054 gv_check("discovery-found-at-least-the-known-emulator-floor" as *u8, distinct_emu >= IM_EMU_FLOOR, ctr)
1055
1056 // Negative control: a slug that cannot exist must NOT probe present.
1057 // Without it a probe that returned 1 for everything would score a
1058 // perfect discovery and every ISA would read covered.
1059 let bogus: *u8 = "zzz_no_such_isa_qq" as *u8
1060 var bl: i64 = 0
1061 while bogus[bl] != (IM_NUL as u8) { bl = bl + 1 }
1062 let bogus_emu: i64 = im_probe_roots(scratch, IM_EMU_PRE, bogus, 0, bl, IM_NX_SUF)
1063 let bogus_gate: i64 = im_probe_roots(scratch, IM_GATE_PRE, bogus, 0, bl, IM_GATE_SUF)
1064 gv_check("neg-control-absent-slug-must-not-resolve-an-emulator" as *u8, bogus_emu < 0, ctr)
1065 gv_check("neg-control-absent-slug-must-not-resolve-a-gate" as *u8, bogus_gate < 0, ctr)
1066
1067 // Negative control on the classifier: impl/ext short-circuits ahead
1068 // of every evidence test, so evidence can never promote a non-target.
1069 gv_check("neg-control-not-a-target-outranks-every-evidence-axis" as *u8, im_classify(0, 99, 1, 1) == IM_S_NOTARGET, ctr)
1070 gv_check("neg-control-a-zero-score-is-RED-not-UNRUN" as *u8, im_classify(1, 0, 1, 1) == IM_S_RED, ctr)
1071 gv_check("neg-control-no-evidence-is-DECLARED-ONLY" as *u8, im_classify(1, -1, 0, 0) == IM_S_DECLARED, ctr)
1072
1073 // The manager must not write the ratchet the gates own. Measured by
1074 // re-reading it and comparing CONTENT -- size is never an identity,
1075 // and a same-size rewrite is exactly what a size guard misses.
1076 let cr2len: *i64 = sys_mmap(IM_BOX_BYTES) as *i64
1077 let cratch2: *u8 = im_kread(scratch, IM_CORE_RATCH, cr2len)
1078 var same: i64 = 0
1079 // BOTH ABSENT IS UNCHANGED. The first cut of this tooth failed
1080 // whenever the ratchet did not exist, which reads as "the manager
1081 // wrote it" -- an instrument that cannot observe must not convict.
1082 // Caught by running the organ against a tree with no knowledge dir.
1083 if (cratch as i64) == 0 {
1084 if (cratch2 as i64) == 0 { same = 1 }
1085 }
1086 if (cratch2 as i64) != 0 {
1087 if cr2len[0] == crn {
1088 var eq: i64 = 1
1089 var z: i64 = 0
1090 while z < crn {
1091 if cratch[z] != cratch2[z] { eq = 0 }
1092 z = z + 1
1093 }
1094 same = eq
1095 }
1096 }
1097 gv_puts(" ratchet before=" as *u8)
1098 gv_num(crn)
1099 gv_puts("B after=" as *u8)
1100 if (cratch2 as i64) != 0 { gv_num(cr2len[0]) }
1101 if (cratch2 as i64) == 0 { gv_puts("ABSENT" as *u8) }
1102 gv_puts("B identical=" as *u8)
1103 gv_num(same)
1104 im_nl()
1105 gv_check("ratchet-content-unchanged-by-this-run" as *u8, same == 1, ctr)
1106
1107 im_nl()
1108
1109 // ---- WORKLIST LAST. A count without a worklist is not actionable,
1110 // and a worklist printed in the body is lost the moment a caller
1111 // tails the output.
1112 gv_puts("=== WORKLIST (the named ISAs in each actionable state) ===" as *u8)
1113 im_nl()
1114 var ws: i64 = 0
1115 while ws < IM_S_COUNT {
1116 var actionable: i64 = 1
1117 if ws == IM_S_GREEN { actionable = 0 }
1118 if ws == IM_S_NOTARGET { actionable = 0 }
1119 if actionable == 1 {
1120 gv_puts("[" as *u8)
1121 gv_puts(im_state_name(ws))
1122 gv_puts("] n=" as *u8)
1123 gv_num(scnt[ws])
1124 gv_puts(" remedy: " as *u8)
1125 if ws == IM_S_RED { gv_puts("the emulator runs and computes the wrong answer -- fix the emulator, its gate already names which KAT" as *u8) }
1126 if ws == IM_S_UNRUN { gv_puts("a gate covers it but banks no score -- run the gate and let it write knowledge/status/isa_<slug>.ratchet" as *u8) }
1127 if ws == IM_S_EMUONLY { gv_puts("an emulator exists and nothing rules on it -- write nx_isa_<slug>_gate.nx with KATs taken from the ISA manual" as *u8) }
1128 if ws == IM_S_DECLARED { gv_puts("the frontier -- write nx_emu_<slug>.nx, then its gate. This is the largest class and it is supposed to be" as *u8) }
1129 im_nl()
1130 var wt: i64 = 0
1131 while wt < n {
1132 if im_cell(tab, wt, IM_A_STATE) == ws {
1133 gv_puts(" " as *u8)
1134 im_puts_slice(slice, conf, im_cell(tab, wt, IM_A_IDOFF), im_cell(tab, wt, IM_A_IDLEN))
1135 gv_puts(" (" as *u8)
1136 gv_puts(im_class_name(im_cell(tab, wt, IM_A_CLS)))
1137 gv_puts(")" as *u8)
1138 im_nl()
1139 }
1140 wt = wt + 1
1141 }
1142 }
1143 ws = ws + 1
1144 }
1145 im_nl()
1146
1147 return gv_verdict("nx_isa_manager" as *u8, ctr, "structural teeth only: a manager that went RED because an ISA is incomplete would be RED the day it shipped and every day after, so the numbers above are the work and this verdict is only the fence" as *u8)
1148}