code wiki / (root) / nx_teacher_lesson.nx

nx_teacher_lesson.nx source

↩ module page · 249 lines · 11087 B

1// nx_teacher.nx -- the NISHI TEACHER: turn a work-session into a structured, 2// machine-AND-human-educatable LESSON, validate it is S-class, and organize+log it. 3// 4// WHY (operator 2026-06-17): "take our data from [what] we did meaningful for the nishi 5// team and my growth to learn -- machine and human educatable... build a nishi teacher 6// role... organize and log what we need to practice, takeaways, etc." 7// 8// GROUNDED IN LEARNING SCIENCE (Bjork "desirable difficulties", cited evidence in 9// knowledge/registry/teaching_evidence.tsv): a lesson only TRANSFERS if it has 10// - CONTEXT concrete situation (concrete-before-abstract) 11// - TAKEAWAYS the S-class abstractions 12// - CARDINALS durable reusable rules (the MACHINE-applicable principles) -> cardinal log 13// - DRILLS retrieval-practice prompts (the testing effect) -> drill log 14// - EVIDENCE cited provenance ("we do things with evidence & science, ALWAYS") 15// A lesson missing any of these is NOT S-class -> RED (the teacher's liar-kill / publish-gate). 16// 17// The lesson is a markdown file (so the EXISTING wiki ingestor auto-discovers it as 18// /wiki/<slug>); the teacher additionally EXTRACTS the machine-readable structure 19// (cardinals + drills) into registries the Nishi team / spore can ingest. Two audiences, 20// one source. DRY: reuses nx_syscalls only; no new primitives. 21// 22// genealogy_id: nishi_teacher_lesson_capture 23// lineage_id: markdown_section_parse + cardinal_drill_extract + sclass_publish_gate 24// license_tier: ORIGINAL 25import "nx_syscalls.nx" 26 27// verdict codes 28const NX_TEACH_OK: i64 = 0 29const NX_TEACH_NO_FILE: i64 = 1 30const NX_TEACH_NO_TITLE: i64 = 2 31const NX_TEACH_MISSING: i64 = 3 // a required section is absent 32 33// does body[off..] start with the NUL-terminated literal lit (bounded by n)? 34func mem_eq(body: *u8, off: i64, n: i64, lit: *u8) -> i64 { 35 var i: i64 = 0 36 while lit[i] != (0 as u8) { 37 if off + i >= n { return 0 } 38 if body[off + i] != lit[i] { return 0 } 39 i = i + 1 40 } 41 return 1 42} 43 44// find a "## <NAME>" section header at a LINE START. Returns 1 if found and sets 45// cstart (first byte after that header line) and cend (start of the next "## " line, or n). 46func sec_bounds(body: *u8, n: i64, marker: *u8, out: *i64) -> i64 { 47 var i: i64 = 0 48 var found: i64 = 0 - 1 49 while i < n { 50 var at_line_start: i64 = 0 51 if i == 0 { at_line_start = 1 } 52 if i > 0 { if body[i - 1] == (10 as u8) { at_line_start = 1 } } 53 if at_line_start == 1 { 54 if mem_eq(body, i, n, marker) == 1 { found = i; i = n } 55 } 56 if i < n { i = i + 1 } 57 } 58 if found < 0 { return 0 } 59 // content starts after the header line's newline 60 var c: i64 = found 61 while c < n { if body[c] == (10 as u8) { c = c + 1; out[0] = c; c = n } else { c = c + 1 } } 62 if out[0] < found { out[0] = n } 63 // content ends at next line-start "## " 64 var e: i64 = out[0] 65 var cend: i64 = n 66 while e < n { 67 if e > 0 { if body[e - 1] == (10 as u8) { if mem_eq(body, e, n, "## \x00" as *u8) == 1 { cend = e; e = n } } } 68 if e < n { e = e + 1 } 69 } 70 out[1] = cend 71 return 1 72} 73 74// count bullet lines ("- " at a line start) within [start,end) 75func count_bullets(body: *u8, start: i64, end: i64) -> i64 { 76 var i: i64 = start 77 var c: i64 = 0 78 while i < end { 79 var ls: i64 = 0 80 if i == start { ls = 1 } 81 if i > start { if body[i - 1] == (10 as u8) { ls = 1 } } 82 if ls == 1 { if mem_eq(body, i, end, "- \x00" as *u8) == 1 { c = c + 1 } } 83 i = i + 1 84 } 85 return c 86} 87 88// append each bullet line's TEXT (after "- ") as "lesson_id<TAB>text\n" to fd. 89func emit_bullets(fd: i64, lesson_id: *u8, body: *u8, start: i64, end: i64) -> i64 { 90 var i: i64 = start 91 while i < end { 92 var ls: i64 = 0 93 if i == start { ls = 1 } 94 if i > start { if body[i - 1] == (10 as u8) { ls = 1 } } 95 if ls == 1 { 96 if mem_eq(body, i, end, "- \x00" as *u8) == 1 { 97 // write id + TAB 98 var k: i64 = 0 99 while lesson_id[k] != (0 as u8) { k = k + 1 } 100 sys_write(fd, lesson_id, k) 101 sys_write(fd, "\t\x00" as *u8, 1) 102 // write the bullet text (skip "- ") to end of line 103 var j: i64 = i + 2 104 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 } } 105 sys_write(fd, "\n\x00" as *u8, 1) 106 } 107 } 108 i = i + 1 109 } 110 return 0 111} 112 113func tp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 114func tn(v: i64) -> i64 { 115 let bb: *u8 = sys_mmap(28); var m: i64 = v 116 if m < 0 { sys_write(1, "-\x00" as *u8, 1); m = 0 - m } 117 let t: *u8 = sys_mmap(28); var k: i64 = 0 118 if m == 0 { t[0] = 48 as u8; k = 1 } 119 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 120 var i: i64 = 0 121 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 122 sys_write(1, bb, k); return 0 123} 124 125// EMIT the curriculum index wiki page from nishi_lessons.tsv (the "structurer": one /wiki 126// page that organizes every logged lesson, regenerated from the registry -- emit, never hand-write). 127func nx_teacher_emit_index(out_path: *u8) -> i64 { 128 let szp: *i64 = sys_mmap(16) as *i64 129 let body: *u8 = sys_read_file("knowledge/registry/nishi_lessons.tsv\x00" as *u8, szp) 130 let ofd: i64 = sys_openat_wr(out_path, O_WRONLY_CT) 131 if ofd < 0 { return 0 - 1 } 132 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 133 var h: i64 = 0 134 while hdr[h] != (0 as u8) { h = h + 1 } 135 sys_write(ofd, hdr, h) 136 if (body as i64) != 0 { 137 let n: i64 = szp[0] 138 var i: i64 = 0 139 while i < n { 140 // find id end (first TAB) and line end (newline) for this line 141 var idend: i64 = 0 - 1 142 var lineend: i64 = n 143 var s: i64 = i 144 while s < n { 145 if body[s] == (10 as u8) { lineend = s; s = n } 146 else { 147 if body[s] == (9 as u8) { if idend < 0 { idend = s } } 148 s = s + 1 149 } 150 } 151 if idend < 0 { idend = lineend } 152 // "- [<id>](/wiki/<id>) <rest of line after tab>\n" 153 sys_write(ofd, "- [\x00" as *u8, 3) 154 var a: i64 = i 155 while a < idend { sys_write(ofd, (body as i64 + a) as *u8, 1); a = a + 1 } 156 sys_write(ofd, "](/wiki/\x00" as *u8, 8) 157 a = i 158 while a < idend { sys_write(ofd, (body as i64 + a) as *u8, 1); a = a + 1 } 159 sys_write(ofd, ") \x00" as *u8, 2) 160 var b: i64 = idend 161 if b < lineend { if body[b] == (9 as u8) { b = b + 1 } } 162 while b < lineend { sys_write(ofd, (body as i64 + b) as *u8, 1); b = b + 1 } 163 sys_write(ofd, "\n\x00" as *u8, 1) 164 i = lineend + 1 165 } 166 } 167 sys_close(ofd) 168 return 0 169} 170 171// write a decimal number to a file descriptor 172func tn_fd(fd: i64, v: i64) -> i64 { 173 let bb: *u8 = sys_mmap(28); var m: i64 = v 174 if m < 0 { sys_write(fd, "-\x00" as *u8, 1); m = 0 - m } 175 let t: *u8 = sys_mmap(28); var k: i64 = 0 176 if m == 0 { t[0] = 48 as u8; k = 1 } 177 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 178 var i: i64 = 0 179 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 180 sys_write(fd, bb, k); return 0 181} 182 183// INGEST one lesson markdown file. Validate required sections, extract cardinals+drills to 184// registries, log the lesson. Returns NX_TEACH_OK (green) or a negative verdict code. 185func nx_teacher_ingest(path_z: *u8, lesson_id: *u8, domain: *u8) -> i64 { 186 let szp: *i64 = sys_mmap(16) as *i64 187 let body: *u8 = sys_read_file(path_z, szp) 188 if (body as i64) == 0 { return 0 - NX_TEACH_NO_FILE } 189 let n: i64 = szp[0] 190 // require a "# " title at the very top 191 if mem_eq(body, 0, n, "# \x00" as *u8) == 0 { return 0 - NX_TEACH_NO_TITLE } 192 193 let ob: *i64 = sys_mmap(16) as *i64 194 // required sections 195 var ok: i64 = 1 196 if sec_bounds(body, n, "## CONTEXT\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## CONTEXT\n\x00" as *u8) } 197 if sec_bounds(body, n, "## TAKEAWAYS\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## TAKEAWAYS\n\x00" as *u8) } 198 if sec_bounds(body, n, "## EVIDENCE\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## EVIDENCE\n\x00" as *u8) } 199 200 // CARDINALS: required + extract 201 var ncard: i64 = 0 202 if sec_bounds(body, n, "## CARDINALS\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## CARDINALS\n\x00" as *u8) } 203 if ok == 1 { 204 sec_bounds(body, n, "## CARDINALS\x00" as *u8, ob) 205 ncard = count_bullets(body, ob[0], ob[1]) 206 let cfd: i64 = sys_openat_append("knowledge/registry/nishi_cardinals.tsv\x00" as *u8, 0x1a4) 207 emit_bullets(cfd, lesson_id, body, ob[0], ob[1]) 208 if cfd > 0 { sys_close(cfd) } 209 } 210 // DRILLS: required + extract 211 var ndrill: i64 = 0 212 if sec_bounds(body, n, "## DRILLS\x00" as *u8, ob) == 0 { ok = 0; tp(" MISSING ## DRILLS\n\x00" as *u8) } 213 if ok == 1 { 214 sec_bounds(body, n, "## DRILLS\x00" as *u8, ob) 215 ndrill = count_bullets(body, ob[0], ob[1]) 216 let dfd: i64 = sys_openat_append("knowledge/registry/nishi_drills.tsv\x00" as *u8, 0x1a4) 217 emit_bullets(dfd, lesson_id, body, ob[0], ob[1]) 218 if dfd > 0 { sys_close(dfd) } 219 } 220 var nev: i64 = 0 221 if sec_bounds(body, n, "## EVIDENCE\x00" as *u8, ob) == 1 { nev = count_bullets(body, ob[0], ob[1]) } 222 223 if ok == 0 { return 0 - NX_TEACH_MISSING } 224 225 // log the lesson row: id<TAB>domain<TAB>cards<TAB>drills<TAB>evidence<TAB>bytes<TAB>GREEN 226 let lfd: i64 = sys_openat_append("knowledge/registry/nishi_lessons.tsv\x00" as *u8, 0x1a4) 227 if lfd > 0 { 228 var k: i64 = 0 229 while lesson_id[k] != (0 as u8) { k = k + 1 } 230 sys_write(lfd, lesson_id, k) 231 sys_write(lfd, "\t\x00" as *u8, 1) 232 k = 0 233 while domain[k] != (0 as u8) { k = k + 1 } 234 sys_write(lfd, domain, k) 235 // counts via a tiny number writer 236 sys_write(lfd, "\tcards=\x00" as *u8, 7) 237 tn_fd(lfd, ncard) 238 sys_write(lfd, "\tdrills=\x00" as *u8, 8) 239 tn_fd(lfd, ndrill) 240 sys_write(lfd, "\tevidence=\x00" as *u8, 10) 241 tn_fd(lfd, nev) 242 sys_write(lfd, "\tbytes=\x00" as *u8, 7) 243 tn_fd(lfd, n) 244 sys_write(lfd, "\tverdict=GREEN\n\x00" as *u8, 15) 245 sys_close(lfd) 246 } 247 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) 248 return NX_TEACH_OK 249}