code wiki / (root) / nx_teacher_rt.nx

nx_teacher_rt.nx source

↩ module page · 269 lines · 12565 B

1// RETIRE CANDIDATE -- ORPHANED BYTE-IDENTICAL DUPLICATE (measured 2026-08-15). 2// This file is a byte-for-byte copy of runtime/nx_teacher_lesson.nx: both were 3// 11087 bytes at content-hash h0e2954e3cb38a146 immediately before this note was 4// added (the note is the ONLY difference; re-derive by hashing both). 5// nx_teacher_lesson.nx has THREE importers (nx_teacher_gate, nx_teacher_run, 6// nx_teacher_serve). THIS file has ZERO references anywhere in buildroot -- 7// nx_shelltool grep, 56,311 files, corpus_complete=1. So retiring it cannot cost 8// a capability, and the live twin already carries every function it defines. 9// WHY IT EXISTS: the three importers each carry the comment "the lesson organ the 10// 2026-07-21 dedupe deleted" -- a previous dedupe removed the LIVE organ, broke 11// those three importers, and it had to be restored. This is the leftover of that 12// repair, not a second implementation. ONE FILE, ONE WRITER: both copies append to 13// knowledge/registry/nishi_lessons.tsv, so leaving both buildable invites the 14// two-writers-one-file race. 15// ACTION: `nx_retire_path retire buildroot/runtime/nx_teacher_rt.nx` (rename-only, 16// reversible). NOT done here -- that tool is capability-denied to this seat, and 17// hand-rolling a rename would bypass the guard that refuses protected paths. 18// The header below is INHERITED FROM THE COPY and names nx_teacher.nx, which is a 19// DIFFERENT, REAL organ (3,969 B, the M0->M4 autonomy ladder). Do not trust it. 20// 21// nx_teacher.nx -- the NISHI TEACHER: turn a work-session into a structured, 22// machine-AND-human-educatable LESSON, validate it is S-class, and organize+log it. 23// 24// WHY (operator 2026-06-17): "take our data from [what] we did meaningful for the nishi 25// team and my growth to learn -- machine and human educatable... build a nishi teacher 26// role... organize and log what we need to practice, takeaways, etc." 27// 28// GROUNDED IN LEARNING SCIENCE (Bjork "desirable difficulties", cited evidence in 29// knowledge/registry/teaching_evidence.tsv): a lesson only TRANSFERS if it has 30// - CONTEXT concrete situation (concrete-before-abstract) 31// - TAKEAWAYS the S-class abstractions 32// - CARDINALS durable reusable rules (the MACHINE-applicable principles) -> cardinal log 33// - DRILLS retrieval-practice prompts (the testing effect) -> drill log 34// - EVIDENCE cited provenance ("we do things with evidence & science, ALWAYS") 35// A lesson missing any of these is NOT S-class -> RED (the teacher's liar-kill / publish-gate). 36// 37// The lesson is a markdown file (so the EXISTING wiki ingestor auto-discovers it as 38// /wiki/<slug>); the teacher additionally EXTRACTS the machine-readable structure 39// (cardinals + drills) into registries the Nishi team / spore can ingest. Two audiences, 40// one source. DRY: reuses nx_syscalls only; no new primitives. 41// 42// genealogy_id: nishi_teacher_lesson_capture 43// lineage_id: markdown_section_parse + cardinal_drill_extract + sclass_publish_gate 44// license_tier: ORIGINAL 45import "nx_syscalls.nx" 46 47// verdict codes 48const NX_TEACH_OK: i64 = 0 49const NX_TEACH_NO_FILE: i64 = 1 50const NX_TEACH_NO_TITLE: i64 = 2 51const NX_TEACH_MISSING: i64 = 3 // a required section is absent 52 53// does body[off..] start with the NUL-terminated literal lit (bounded by n)? 54func mem_eq(body: *u8, off: i64, n: i64, lit: *u8) -> i64 { 55 var i: i64 = 0 56 while lit[i] != (0 as u8) { 57 if off + i >= n { return 0 } 58 if body[off + i] != lit[i] { return 0 } 59 i = i + 1 60 } 61 return 1 62} 63 64// find a "## <NAME>" section header at a LINE START. Returns 1 if found and sets 65// cstart (first byte after that header line) and cend (start of the next "## " line, or n). 66func sec_bounds(body: *u8, n: i64, marker: *u8, out: *i64) -> i64 { 67 var i: i64 = 0 68 var found: i64 = 0 - 1 69 while i < n { 70 var at_line_start: i64 = 0 71 if i == 0 { at_line_start = 1 } 72 if i > 0 { if body[i - 1] == (10 as u8) { at_line_start = 1 } } 73 if at_line_start == 1 { 74 if mem_eq(body, i, n, marker) == 1 { found = i; i = n } 75 } 76 if i < n { i = i + 1 } 77 } 78 if found < 0 { return 0 } 79 // content starts after the header line's newline 80 var c: i64 = found 81 while c < n { if body[c] == (10 as u8) { c = c + 1; out[0] = c; c = n } else { c = c + 1 } } 82 if out[0] < found { out[0] = n } 83 // content ends at next line-start "## " 84 var e: i64 = out[0] 85 var cend: i64 = n 86 while e < n { 87 if e > 0 { if body[e - 1] == (10 as u8) { if mem_eq(body, e, n, "## \x00" as *u8) == 1 { cend = e; e = n } } } 88 if e < n { e = e + 1 } 89 } 90 out[1] = cend 91 return 1 92} 93 94// count bullet lines ("- " at a line start) within [start,end) 95func count_bullets(body: *u8, start: i64, end: i64) -> i64 { 96 var i: i64 = start 97 var c: i64 = 0 98 while i < end { 99 var ls: i64 = 0 100 if i == start { ls = 1 } 101 if i > start { if body[i - 1] == (10 as u8) { ls = 1 } } 102 if ls == 1 { if mem_eq(body, i, end, "- \x00" as *u8) == 1 { c = c + 1 } } 103 i = i + 1 104 } 105 return c 106} 107 108// append each bullet line's TEXT (after "- ") as "lesson_id<TAB>text\n" to fd. 109func emit_bullets(fd: i64, lesson_id: *u8, body: *u8, start: i64, end: i64) -> i64 { 110 var i: i64 = start 111 while i < end { 112 var ls: i64 = 0 113 if i == start { ls = 1 } 114 if i > start { if body[i - 1] == (10 as u8) { ls = 1 } } 115 if ls == 1 { 116 if mem_eq(body, i, end, "- \x00" as *u8) == 1 { 117 // write id + TAB 118 var k: i64 = 0 119 while lesson_id[k] != (0 as u8) { k = k + 1 } 120 sys_write(fd, lesson_id, k) 121 sys_write(fd, "\t\x00" as *u8, 1) 122 // write the bullet text (skip "- ") to end of line 123 var j: i64 = i + 2 124 while j < end { if body[j] == (10 as u8) { j = end } else { sys_write(fd, (body as i64 + j) as *u8, 1); j = j + 1 } } 125 sys_write(fd, "\n\x00" as *u8, 1) 126 } 127 } 128 i = i + 1 129 } 130 return 0 131} 132 133func tp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 134func tn(v: i64) -> i64 { 135 let bb: *u8 = sys_mmap(28); var m: i64 = v 136 if m < 0 { sys_write(1, "-\x00" as *u8, 1); m = 0 - m } 137 let t: *u8 = sys_mmap(28); var k: i64 = 0 138 if m == 0 { t[0] = 48 as u8; k = 1 } 139 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 140 var i: i64 = 0 141 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 142 sys_write(1, bb, k); return 0 143} 144 145// EMIT the curriculum index wiki page from nishi_lessons.tsv (the "structurer": one /wiki 146// page that organizes every logged lesson, regenerated from the registry -- emit, never hand-write). 147func nx_teacher_emit_index(out_path: *u8) -> i64 { 148 let szp: *i64 = sys_mmap(16) as *i64 149 let body: *u8 = sys_read_file("knowledge/registry/nishi_lessons.tsv\x00" as *u8, szp) 150 let ofd: i64 = sys_openat_wr(out_path, O_WRONLY_CT) 151 if ofd < 0 { return 0 - 1 } 152 let hdr: *u8 = "# Nishi Lessons (curriculum index)\n\nAuto-emitted by the Nishi Teacher from nishi_lessons.tsv -- each row is a validated S-class lesson (has context, takeaways, cardinals, drills, cited evidence). Machine-readable cardinals + drills live in nishi_cardinals.tsv / nishi_drills.tsv for the team and spore to ingest.\n\n## Lessons\n\n\x00" as *u8 153 var h: i64 = 0 154 while hdr[h] != (0 as u8) { h = h + 1 } 155 sys_write(ofd, hdr, h) 156 if (body as i64) != 0 { 157 let n: i64 = szp[0] 158 var i: i64 = 0 159 while i < n { 160 // find id end (first TAB) and line end (newline) for this line 161 var idend: i64 = 0 - 1 162 var lineend: i64 = n 163 var s: i64 = i 164 while s < n { 165 if body[s] == (10 as u8) { lineend = s; s = n } 166 else { 167 if body[s] == (9 as u8) { if idend < 0 { idend = s } } 168 s = s + 1 169 } 170 } 171 if idend < 0 { idend = lineend } 172 // "- [<id>](/wiki/<id>) <rest of line after tab>\n" 173 sys_write(ofd, "- [\x00" as *u8, 3) 174 var a: i64 = i 175 while a < idend { sys_write(ofd, (body as i64 + a) as *u8, 1); a = a + 1 } 176 sys_write(ofd, "](/wiki/\x00" as *u8, 8) 177 a = i 178 while a < idend { sys_write(ofd, (body as i64 + a) as *u8, 1); a = a + 1 } 179 sys_write(ofd, ") \x00" as *u8, 2) 180 var b: i64 = idend 181 if b < lineend { if body[b] == (9 as u8) { b = b + 1 } } 182 while b < lineend { sys_write(ofd, (body as i64 + b) as *u8, 1); b = b + 1 } 183 sys_write(ofd, "\n\x00" as *u8, 1) 184 i = lineend + 1 185 } 186 } 187 sys_close(ofd) 188 return 0 189} 190 191// write a decimal number to a file descriptor 192func tn_fd(fd: i64, v: i64) -> i64 { 193 let bb: *u8 = sys_mmap(28); var m: i64 = v 194 if m < 0 { sys_write(fd, "-\x00" as *u8, 1); m = 0 - m } 195 let t: *u8 = sys_mmap(28); var k: i64 = 0 196 if m == 0 { t[0] = 48 as u8; k = 1 } 197 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 198 var i: i64 = 0 199 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 200 sys_write(fd, bb, k); return 0 201} 202 203// INGEST one lesson markdown file. Validate required sections, extract cardinals+drills to 204// registries, log the lesson. Returns NX_TEACH_OK (green) or a negative verdict code. 205func nx_teacher_ingest(path_z: *u8, lesson_id: *u8, domain: *u8) -> i64 { 206 let szp: *i64 = sys_mmap(16) as *i64 207 let body: *u8 = sys_read_file(path_z, szp) 208 if (body as i64) == 0 { return 0 - NX_TEACH_NO_FILE } 209 let n: i64 = szp[0] 210 // require a "# " title at the very top 211 if mem_eq(body, 0, n, "# \x00" as *u8) == 0 { return 0 - NX_TEACH_NO_TITLE } 212 213 let ob: *i64 = sys_mmap(16) as *i64 214 // required sections 215 var ok: i64 = 1 216 if sec_bounds(body, n, "## CONTEXT\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## CONTEXT\n\x00" as *u8) } 217 if sec_bounds(body, n, "## TAKEAWAYS\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## TAKEAWAYS\n\x00" as *u8) } 218 if sec_bounds(body, n, "## EVIDENCE\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## EVIDENCE\n\x00" as *u8) } 219 220 // CARDINALS: required + extract 221 var ncard: i64 = 0 222 if sec_bounds(body, n, "## CARDINALS\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## CARDINALS\n\x00" as *u8) } 223 if ok == 1 { 224 sec_bounds(body, n, "## CARDINALS\x00" as *u8, ob) 225 ncard = count_bullets(body, ob[0], ob[1]) 226 let cfd: i64 = sys_openat_append("knowledge/registry/nishi_cardinals.tsv\x00" as *u8, 0x1a4) 227 emit_bullets(cfd, lesson_id, body, ob[0], ob[1]) 228 if cfd > 0 { sys_close(cfd) } 229 } 230 // DRILLS: required + extract 231 var ndrill: i64 = 0 232 if sec_bounds(body, n, "## DRILLS\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## DRILLS\n\x00" as *u8) } 233 if ok == 1 { 234 sec_bounds(body, n, "## DRILLS\x00" as *u8, ob) 235 ndrill = count_bullets(body, ob[0], ob[1]) 236 let dfd: i64 = sys_openat_append("knowledge/registry/nishi_drills.tsv\x00" as *u8, 0x1a4) 237 emit_bullets(dfd, lesson_id, body, ob[0], ob[1]) 238 if dfd > 0 { sys_close(dfd) } 239 } 240 var nev: i64 = 0 241 if sec_bounds(body, n, "## EVIDENCE\x00" as *u8, ob) == 1 { nev = count_bullets(body, ob[0], ob[1]) } 242 243 if ok == 0 { return 0 - NX_TEACH_MISSING } 244 245 // log the lesson row: id<TAB>domain<TAB>cards<TAB>drills<TAB>evidence<TAB>bytes<TAB>GREEN 246 let lfd: i64 = sys_openat_append("knowledge/registry/nishi_lessons.tsv\x00" as *u8, 0x1a4) 247 if lfd > 0 { 248 var k: i64 = 0 249 while lesson_id[k] != (0 as u8) { k = k + 1 } 250 sys_write(lfd, lesson_id, k) 251 sys_write(lfd, "\t\x00" as *u8, 1) 252 k = 0 253 while domain[k] != (0 as u8) { k = k + 1 } 254 sys_write(lfd, domain, k) 255 // counts via a tiny number writer 256 sys_write(lfd, "\tcards=\x00" as *u8, 7) 257 tn_fd(lfd, ncard) 258 sys_write(lfd, "\tdrills=\x00" as *u8, 8) 259 tn_fd(lfd, ndrill) 260 sys_write(lfd, "\tevidence=\x00" as *u8, 10) 261 tn_fd(lfd, nev) 262 sys_write(lfd, "\tbytes=\x00" as *u8, 7) 263 tn_fd(lfd, n) 264 sys_write(lfd, "\tverdict=GREEN\n\x00" as *u8, 15) 265 sys_close(lfd) 266 } 267 tp(" ingested cards=\x00" as *u8); tn(ncard); tp(" drills=\x00" as *u8); tn(ndrill); tp(" evidence=\x00" as *u8); tn(nev); tp(" bytes=\x00" as *u8); tn(n); tp("\n\x00" as *u8) 268 return NX_TEACH_OK 269}