code wiki / (root) / nx_teacher_publish.nx

nx_teacher_publish.nx source

↩ module page · 112 lines · 6168 B

1// nx_teacher_publish.nx -- the PUBLISHER of the Nishi Teacher loop (Teacher arc, rung R5 = surface it). 2// 3// Operator: "see the nishi teacher and the nishi trainer and the nishi publisher COORDINATING." The 4// publisher EMITS a data-driven curriculum page FROM the unified native capability store (the teacher's 5// output) annotated with the trainer's coverage meter + per-insight practiced/due badge -- so the page 6// is a JOINT artifact of teacher (insights) + trainer (schedule), the coordination made visible. 7// Emit-never-handwrite ([[feedback-live-testable-publish-loop-standard]]); a LIVE push to the site is 8// outward-facing -> operator go-ahead (this organ only STAGES the page to web_assets/). 9// 10// tpub_emit(cap_store, state_store, out_path, now) -> bytes written (or -1) 11// The page carries machine-checkable markers (INSIGHTS=/COVERED=/DUE=/COVERAGE_PERMIL=) + a card per 12// insight (source, id, HTML-escaped rule, practiced|due badge). No hardware writes/network (Rule 26). 13// license_tier: ORIGINAL 14import "nx_teacher_trainer.nx" 15import "nx_syscalls.nx" 16 17func tpub_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != 0 as u8 { n = n + 1 } sys_write(1, s, n); return 0 } 18func tpub_putn(v: i64) -> i64 { 19 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 20 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 21 let d: *u8 = sys_mmap(24); var k: i64 = 0 22 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 23 var j: i64 = k - 1 24 while j >= 0 { sys_write(1, ((d as i64)+j) as *u8, 1); j = j - 1 } 25 return 0 26} 27func tpub_wr(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return n } 28func tpub_wrn(fd: i64, v: i64) -> i64 { 29 let b: *u8 = sys_mmap(28) 30 if v == 0 { b[0] = 48 as u8; sys_write(fd, b, 1); return 1 } 31 var m: i64 = v; var neg: i64 = 0 32 if m < 0 { neg = 1; m = 0 - m } 33 let t: *u8 = sys_mmap(28); var k: i64 = 0 34 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 35 var o: i64 = 0 36 if neg == 1 { b[0] = 45 as u8; o = 1 } 37 var i: i64 = 0 38 while i < k { b[o + i] = t[k - 1 - i]; i = i + 1 } 39 sys_write(fd, b, o + k); return o + k 40} 41// HTML-escaped write of a NUL-terminated string (& < >). returns bytes written. 42func tpub_wresc(fd: i64, s: *u8) -> i64 { 43 var n: i64 = 0 44 var i: i64 = 0 45 while s[i] != (0 as u8) { 46 let c: i64 = s[i] as i64 47 if c == 38 { sys_write(fd, "&amp;" as *u8, 5); n = n + 5 } 48 else { if c == 60 { sys_write(fd, "&lt;" as *u8, 4); n = n + 4 } 49 else { if c == 62 { sys_write(fd, "&gt;" as *u8, 4); n = n + 4 } 50 else { sys_write(fd, (s as i64 + i) as *u8, 1); n = n + 1 } } } 51 i = i + 1 52 } 53 return n 54} 55// EMIT the curriculum page from the unified store + the trainer meter. returns bytes, or -1. 56func tpub_emit(cap_store: *u8, state_store: *u8, out_path: *u8, now: i64) -> i64 { 57 let h: *i64 = ncfg_open(cap_store) 58 if (h as i64) == 0 { return 0 - 1 } 59 let total: i64 = ncfg_count(h, "insight\x00" as *u8) 60 let covered: i64 = trn_coverage(cap_store, state_store) 61 let due: i64 = trn_due_count(cap_store, state_store, now) 62 var permil: i64 = 0 63 if total > 0 { permil = covered * 1000 / total } 64 let fd: i64 = sys_openat_wr(out_path, 0x1a4) 65 if fd < 0 { return 0 - 1 } 66 var bytes: i64 = 0 67 bytes = bytes + tpub_wr(fd, "<!doctype html><html><head><meta charset=\"utf-8\"><title>Nishi Teacher Capability Curriculum</title></head><body>\n" as *u8) 68 bytes = bytes + tpub_wr(fd, "<h1>Nishi Teacher Capability Curriculum</h1>\n<p class=\"meter\">INSIGHTS=" as *u8) 69 bytes = bytes + tpub_wrn(fd, total) 70 bytes = bytes + tpub_wr(fd, " COVERED=" as *u8); bytes = bytes + tpub_wrn(fd, covered) 71 bytes = bytes + tpub_wr(fd, " DUE=" as *u8); bytes = bytes + tpub_wrn(fd, due) 72 bytes = bytes + tpub_wr(fd, " COVERAGE_PERMIL=" as *u8); bytes = bytes + tpub_wrn(fd, permil) 73 bytes = bytes + tpub_wr(fd, "</p>\n<ul>\n" as *u8) 74 let rk: *i64 = sys_mmap(8 * 16) as *i64 75 let rv: *i64 = sys_mmap(8 * 16) as *i64 76 let st: *i64 = sys_mmap(8 * 4) as *i64 77 var i: i64 = 0 78 while i < total { 79 let rf: i64 = ncfg_row(h, "insight\x00" as *u8, i, rk, rv, 16) 80 if rf > 0 { 81 let src: *u8 = ncfg_field(rk, rv, rf, "source\x00" as *u8) 82 let id: *u8 = ncfg_field(rk, rv, rf, "id\x00" as *u8) 83 let rule: *u8 = ncfg_field(rk, rv, rf, "rule\x00" as *u8) 84 bytes = bytes + tpub_wr(fd, "<li>[" as *u8) 85 if (src as i64) != 0 { bytes = bytes + tpub_wresc(fd, src) } 86 bytes = bytes + tpub_wr(fd, "] " as *u8) 87 if (id as i64) != 0 { bytes = bytes + tpub_wresc(fd, id) } 88 bytes = bytes + tpub_wr(fd, ": " as *u8) 89 if (rule as i64) != 0 { bytes = bytes + tpub_wresc(fd, rule) } 90 var practiced: i64 = 0 91 if (id as i64) != 0 { if trn_state(state_store, id, st) == 1 { if st[0] >= 1 { practiced = 1 } } } 92 if practiced == 1 { bytes = bytes + tpub_wr(fd, " <span class=\"b\">practiced</span>" as *u8) } 93 else { bytes = bytes + tpub_wr(fd, " <span class=\"b\">due</span>" as *u8) } 94 bytes = bytes + tpub_wr(fd, "</li>\n" as *u8) 95 } 96 i = i + 1 97 } 98 bytes = bytes + tpub_wr(fd, "</ul>\n<p>Emitted by nx_teacher_publish from the native unified capability store (data-driven, not hand-written).</p>\n</body></html>\n" as *u8) 99 sys_close(fd) 100 return bytes 101} 102 103func main() -> i64 { 104 let cap: *u8 = "knowledge/store/teacher-capability-\x00" as *u8 105 let state: *u8 = "knowledge/store/teacher-review-\x00" as *u8 106 let out: *u8 = "web_assets/nishi-curriculum.html\x00" as *u8 107 let now: i64 = sys_now_realtime_sec() 108 let bytes: i64 = tpub_emit(cap, state, out, now) 109 if bytes < 0 { tpub_puts("nx_teacher_publish: FATAL (no capability store -- run nx_teacher_merge first)\n"); sys_exit(1); return 1 } 110 tpub_puts("nx_teacher_publish: emitted "); tpub_putn(bytes); tpub_puts(" bytes -> web_assets/nishi-curriculum.html (STAGED; live publish needs operator go-ahead)\n") 111 sys_exit(0); return 0 112}