code wiki / (root) / nx_toolreg_reconcile.nx

nx_toolreg_reconcile.nx source

↩ module page · 89 lines · 5929 B

1// nx_toolreg_reconcile.nx -- CLI half of the discovery reconciler / drift auditor. Run from nishihost CWD: 2// nx_toolreg_reconcile [allowlist] [schemas] reconcile (register missing rows); default paths 3// nx_toolreg_reconcile check [allowlist] [schemas] AUDIT: register NOTHING, exit 1 if drift>0 4// Reconcile registers every GREEN allowlisted tool missing from discovery using the author's own schema 5// row; skips (reports) tools with no schema row. Idempotent. `check` is the read-only regression tooth: 6// it exits non-zero if ANY GREEN tool is unregistered or schema-less -- run it in the standing sweep so 7// the discovery-complete state (allowlist == tools/list) can never silently regrow. 8// exit: 0 clean | 1 io / failed rows / (check) drift>0 license_tier: ORIGINAL 9import "nx_toolreg_reconcile_lib.nx" 10 11const RC_ARG_ALLOW: i64 = 1 // argv: optional allowlist path (reconcile mode) 12const RC_ARG_SCH: i64 = 2 // argv: optional schemas path (reconcile mode) 13const RC_ARGC_A: i64 = 2 // argc with allowlist 14const RC_ARGC_S: i64 = 3 // argc with both 15const RC_CK_ARG_ALLOW: i64 = 2 // argv: optional allowlist path (check mode, after the verb) 16const RC_CK_ARG_SCH: i64 = 3 // argv: optional schemas path (check mode) 17const RC_CK_ARGC_A: i64 = 3 // argc: check + allowlist 18const RC_CK_ARGC_S: i64 = 4 // argc: check + allowlist + schemas 19const RC_ASCII_0: i64 = 48 // '0' 20const RC_DEC: i64 = 10 // decimal base 21 22func rc_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 23func rc_putn(v: i64) -> i64 { 24 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 25 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 26 let d: *u8 = sys_mmap(32); var k: i64 = 0 27 while m > 0 { d[k] = (RC_ASCII_0 + (m % RC_DEC)) as u8; m = m / RC_DEC; k = k + 1 } 28 let o: *u8 = sys_mmap(32); var i: i64 = 0 29 while i < k { o[i] = d[k-1-i]; i = i + 1 } sys_write(1, o, k) 30 return 0 31} 32 33func rc_seq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 } 34 35func main(argc: i64, argv: *i64) -> i64 { 36 var allow: *u8 = "tool_allowlist.conf" as *u8 37 var sch: *u8 = "knowledge/tool_schemas.conf" as *u8 38 let counts: *i64 = sys_mmap(RR_COUNTS) as *i64 39 // AUDIT MODE: `check [allow] [schemas]` -- register nothing, exit 1 if drift>0 (the regression tooth) 40 if argc >= RC_ARGC_A { if rc_seq(argv[RC_ARG_ALLOW] as *u8, "check" as *u8) == 1 { 41 if argc >= RC_CK_ARGC_A { allow = argv[RC_CK_ARG_ALLOW] as *u8 } 42 if argc >= RC_CK_ARGC_S { sch = argv[RC_CK_ARG_SCH] as *u8 } 43 let drift: i64 = rr_drift(TOOL_PREFIX, allow, sch, counts) 44 if drift < 0 { rc_puts("NX-TOOLREG-AUDIT IO: cannot read allowlist/schemas\n" as *u8); return 1 } 45 rc_puts("NX-TOOLREG-AUDIT drift=" as *u8); rc_putn(drift) 46 rc_puts(" (would-register=" as *u8); rc_putn(counts[RR_C_REG]) 47 rc_puts(" no-schema=" as *u8); rc_putn(counts[RR_C_NOSCHEMA]) 48 rc_puts(" already-discoverable=" as *u8); rc_putn(counts[RR_C_ALREADY]) 49 rc_puts(") verdict=" as *u8) 50 if drift == 0 { rc_puts("GREEN (allowlist == tools/list; every tool contracted)\n" as *u8); return 0 } 51 rc_puts("RED (run reconcile / add missing tool_schemas.conf rows)\n" as *u8) 52 return 1 53 } } 54 // HEAL MODE: `heal [allow] [schemas]` -- SELF-MANAGING. Auto-register all has-schema tools (the 55 // mechanical drift that needs no human), then report ONLY the genuine no-schema residue (named). Exit 0 56 // when the residue is empty (discovery self-healed), exit 1 when tools are allowlisted with NO contract 57 // (real AUTHOR debt a human must fix). This is what the standing sweep runs: it FIXES what it can and 58 // reds only on the un-authorable -- retiring the manual-reconcile treadmill. 59 if argc >= RC_ARGC_A { if rc_seq(argv[RC_ARG_ALLOW] as *u8, "heal" as *u8) == 1 { 60 if argc >= RC_CK_ARGC_A { allow = argv[RC_CK_ARG_ALLOW] as *u8 } 61 if argc >= RC_CK_ARGC_S { sch = argv[RC_CK_ARG_SCH] as *u8 } 62 if rr_reconcile(TOOL_PREFIX, allow, sch, counts) < 0 { rc_puts("NX-TOOLREG-HEAL IO: cannot read allowlist/schemas\n" as *u8); return 1 } 63 let names: *u8 = sys_mmap(RR_FILE_CAP) 64 let ns: i64 = rr_no_schema_names(TOOL_PREFIX, allow, sch, names, RR_FILE_CAP) 65 rc_puts("NX-TOOLREG-HEAL auto-registered=" as *u8); rc_putn(counts[RR_C_REG]) 66 rc_puts(" already=" as *u8); rc_putn(counts[RR_C_ALREADY]) 67 rc_puts(" no-schema-residue=" as *u8); rc_putn(ns) 68 rc_puts(" verdict=" as *u8) 69 if ns == 0 { rc_puts("GREEN (discovery self-healed; every tool contracted)\n" as *u8); return 0 } 70 rc_puts("RED needs-author-schema: " as *u8); rc_puts(names); rc_puts("\n" as *u8) 71 return 1 72 } } 73 // RECONCILE MODE (default): register missing rows 74 if argc >= RC_ARGC_A { allow = argv[RC_ARG_ALLOW] as *u8 } 75 if argc >= RC_ARGC_S { sch = argv[RC_ARG_SCH] as *u8 } 76 let rows: i64 = rr_reconcile(TOOL_PREFIX, allow, sch, counts) 77 if rows < 0 { rc_puts("NX-TOOLREG-RECONCILE IO: cannot read allowlist/schemas\n" as *u8); return 1 } 78 rc_puts("NX-TOOLREG-RECONCILE rows=" as *u8); rc_putn(rows) 79 rc_puts(" registered=" as *u8); rc_putn(counts[RR_C_REG]) 80 rc_puts(" already=" as *u8); rc_putn(counts[RR_C_ALREADY]) 81 // UPDATED is reported separately from REGISTERED so a description CORRECTION is visible as 82 // work done, not hidden inside 'already' (debt seq1526). 0 on a no-change run = idempotence. 83 rc_puts(" updated=" as *u8); rc_putn(counts[RR_C_UPDATED]) 84 rc_puts(" skipped-no-schema=" as *u8); rc_putn(counts[RR_C_NOSCHEMA]) 85 rc_puts(" failed=" as *u8); rc_putn(counts[RR_C_FAIL]) 86 rc_puts("\n" as *u8) 87 if counts[RR_C_FAIL] > 0 { return 1 } 88 return 0 89}