code wiki / _hdl_build / nx_discovery_selfheal_beat.nx

nx_discovery_selfheal_beat.nx source

↩ module page · 96 lines · 4965 B

1// nx_discovery_selfheal_beat.nx -- makes the discovery-selfheal check ACTUALLY self-heal. 2// 3// THE DEFECT THIS EXISTS TO KILL (measured 2026-07-30): the sweep row ran `nx_toolreg_reconcile heal`, 4// a verb named "heal" that only DIAGNOSES -- it prints `no-schema-residue=N needs-author-schema: ...` 5// and exits 1. Closing it needs a THREE-COMMAND MANUAL SEQUENCE (schema_backfill -> reconcile -> 6// heal), so every time any lane shipped a tool without a schema header the row went RED and STAYED 7// red until a human noticed. It sat red for 24+ consecutive cycles at 0 permille. Clearing the 8// backlog by hand does NOT fix it: within one hour of clearing 14, five MORE arrived 9// (nx_meshprofile, nx_routeguard, nx_wirecensus, nx_arousal_skin_gate, nx_arousal_mesh_gate) from 10// other lanes shipping normally. A treadmill is not a defect in the lanes -- it is a missing loop. 11// 12// So this beat RUNS the loop the check was only ever reporting on: 13// 1. ./nx_schema_backfill.elf harvest schemas from source headers (idempotent) 14// 2. ./nx_toolreg_reconcile.elf publish them into the registry 15// 3. ./nx_toolreg_reconcile.elf heal judge, and EXIT WITH ITS CODE 16// Step 3's rc is the beat's rc, so the rail still judges the real invariant -- we heal first, then 17// report honestly. If a residue SURVIVES the backfill (an organ whose source has no header at all) 18// the beat still goes RED and NAMES it, because that one genuinely needs a human to author it. 19// 20// Rule 10 idempotent: backfill is idempotent by contract; reconcile skips already-registered rows. 21// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 22import "nx_syscalls.nx" 23import "nx_tool_run.nx" 24 25const DB_OUTCAP: i64 = 65536 26const DB_AVCAP: i64 = 40 27const DB_STDOUT: i64 = 1 28const DB_BACKFILL: *u8 = "./nx_schema_backfill.elf" as *u8 29const DB_RECONCILE: *u8 = "./nx_toolreg_reconcile.elf" as *u8 30const DB_HEAL: *u8 = "heal" as *u8 31const DB_STEP_MS: i64 = 120000 32 33func db_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 34func db_puts(s: *u8) -> i64 { sys_write(DB_STDOUT, s, db_len(s)); return 0 } 35func db_putn(v: i64) -> i64 { 36 let t: *u8 = sys_mmap(32) 37 var m: i64 = v 38 if m < 0 { m = 0 - m } 39 var o: i64 = 0 40 if m == 0 { t[0] = 48 as u8; o = 1 } 41 while m > 0 { t[o] = ((m % 10) + 48) as u8; o = o + 1; m = m / 10 } 42 if v < 0 { db_puts("-" as *u8) } 43 var i: i64 = o - 1 44 while i >= 0 { sys_write(DB_STDOUT, (t as i64 + i) as *u8, 1); i = i - 1 } 45 return 0 46} 47func db_tail(out: *u8, n: i64) -> i64 { 48 if n <= 0 { return 0 } 49 var e: i64 = n 50 if out[e - 1] == (10 as u8) { e = e - 1 } 51 var b: i64 = e 52 var go: i64 = 1 53 while go == 1 { 54 if b <= 0 { go = 0 } else { 55 if out[b - 1] == (10 as u8) { go = 0 } else { b = b - 1 } 56 } 57 } 58 sys_write(DB_STDOUT, (out as i64 + b) as *u8, e - b) 59 sys_write(DB_STDOUT, "\n" as *u8, 1) 60 return 0 61} 62 63func main(argc: i64, argv: *i64) -> i64 { 64 let out: *u8 = sys_mmap(DB_OUTCAP) 65 let ol: *i64 = sys_mmap(16) as *i64 66 67 let av1: *i64 = sys_mmap(DB_AVCAP) as *i64 68 av1[0] = DB_BACKFILL as i64 69 av1[1] = 0 70 let rc1: i64 = tr_run_capture_to(DB_BACKFILL, av1, out, DB_OUTCAP - 1, ol, DB_STEP_MS) 71 db_puts("SELFHEAL-BEAT backfill rc=" as *u8); db_putn(rc1); db_puts(" " as *u8); db_tail(out, ol[0]) 72 73 let av2: *i64 = sys_mmap(DB_AVCAP) as *i64 74 av2[0] = DB_RECONCILE as i64 75 av2[1] = 0 76 let rc2: i64 = tr_run_capture_to(DB_RECONCILE, av2, out, DB_OUTCAP - 1, ol, DB_STEP_MS) 77 db_puts("SELFHEAL-BEAT publish rc=" as *u8); db_putn(rc2); db_puts(" " as *u8); db_tail(out, ol[0]) 78 79 let av3: *i64 = sys_mmap(DB_AVCAP) as *i64 80 av3[0] = DB_RECONCILE as i64 81 av3[1] = DB_HEAL as i64 82 av3[2] = 0 83 let rc3: i64 = tr_run_capture_to(DB_RECONCILE, av3, out, DB_OUTCAP - 1, ol, DB_STEP_MS) 84 db_puts("SELFHEAL-BEAT verdict rc=" as *u8); db_putn(rc3); db_puts(" " as *u8); db_tail(out, ol[0]) 85 86 if rc3 == 0 { sys_exit(0); return 0 } 87 // DISTINGUISH THE TWO RED CAUSES. My own negative control caught this: when the child organs could 88 // not even be exec'd (rc 127) the beat still blamed "residue", which is the wrong diagnosis and the 89 // exact misleading-error class this rail exists to kill. A step that COULD NOT RUN and a residue 90 // that SURVIVED are opposite failures with opposite fixes -- never report one as the other. 91 if rc1 != 0 { db_puts("SELFHEAL-BEAT RED -- INSTRUMENT BROKEN: backfill could not run (rc=" as *u8); db_putn(rc1); db_puts("); this is NOT a schema residue\n" as *u8); sys_exit(1); return 1 } 92 if rc2 != 0 { db_puts("SELFHEAL-BEAT RED -- INSTRUMENT BROKEN: publish could not run (rc=" as *u8); db_putn(rc2); db_puts("); this is NOT a schema residue\n" as *u8); sys_exit(1); return 1 } 93 db_puts("SELFHEAL-BEAT RED -- residue survived the backfill; those organs need an AUTHORED header\n" as *u8) 94 sys_exit(1) 95 return 1 96}