nx_teacher_trainer.nx source
↩ module page · 178 lines · 8599 B
1// nx_teacher_trainer.nx -- the TRAINER half of the Nishi Teacher (Teacher arc, rung R3 = spaced review).
2//
3// Operator: "consume all our information from the nishi teacher AND TRAINER so we get insights to
4// improve the team's capabilities." The teacher SYNTHESIZES insights into the unified native capability
5// store (nx_teacher_merge); the trainer SCHEDULES spaced retrieval practice over them and MEASURES
6// coverage. Grounding = the cited learning science already in knowledge/registry/teaching_evidence.tsv
7// (Bjork desirable difficulties: retrieval practice + spacing beat re-reading).
8//
9// Append-only review state in the native seg_store (tag "rev", row = {id, reps, interval, due}); current
10// state of an id = its LAST appended row (additive, history-sacred #13). Spacing: first practice -> 1-day
11// interval, each subsequent success DOUBLES it; an insight is DUE if never practiced OR now >= its due
12// epoch. Coverage = (insights practiced >=1) *1000 / total -- a MEASURED readiness number.
13//
14// trn_practice(state, id, now) -- record a retrieval-practice event (advances spacing)
15// trn_due_count(cap, state, now) -- how many unified insights are due for practice
16// trn_coverage(cap, state) -- how many are under active practice (the meter)
17//
18// HONEST SCOPE (no-overclaim, [[feedback-no-wave-measured-exceed]]): this SCHEDULES practice and MEASURES
19// coverage; it does NOT by itself prove the team got "smarter" -- a real capability LIFT needs the team to
20// actually practice + a before/after task-performance measure (a further rung). license_tier: ORIGINAL
21import "nx_teacher_merge.nx"
22import "nx_syscalls.nx"
23
24const TRN_DAY: i64 = 86400
25
26func trn_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != 0 as u8 { n = n + 1 } sys_write(1, s, n); return 0 }
27func trn_putn(v: i64) -> i64 {
28 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
29 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
30 let d: *u8 = sys_mmap(24); var k: i64 = 0
31 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
32 var j: i64 = k - 1
33 while j >= 0 { sys_write(1, ((d as i64)+j) as *u8, 1); j = j - 1 }
34 return 0
35}
36func trn_itoa(v: i64, out: *u8) -> i64 {
37 if v == 0 { out[0] = 48 as u8; out[1] = 0 as u8; return 1 }
38 var m: i64 = v; var neg: i64 = 0
39 if m < 0 { neg = 1; m = 0 - m }
40 let t: *u8 = sys_mmap(28); var k: i64 = 0
41 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
42 var o: i64 = 0
43 if neg == 1 { out[0] = 45 as u8; o = 1 }
44 var i: i64 = 0
45 while i < k { out[o + i] = t[k - 1 - i]; i = i + 1 }
46 out[o + k] = 0 as u8
47 return o + k
48}
49func trn_atoi(s: *u8) -> i64 {
50 if (s as i64) == 0 { return 0 }
51 var v: i64 = 0; var i: i64 = 0
52 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 }
53 return v
54}
55// current review state of `id` (LAST appended row): out3[0]=reps out3[1]=interval out3[2]=due. 1=found.
56func trn_state(state_store: *u8, id: *u8, out3: *i64) -> i64 {
57 out3[0] = 0; out3[1] = 0; out3[2] = 0
58 let h: *i64 = ncfg_open(state_store)
59 if (h as i64) == 0 { return 0 }
60 let cnt: i64 = ncfg_count(h, "rev\x00" as *u8)
61 let rk: *i64 = sys_mmap(8 * 16) as *i64
62 let rv: *i64 = sys_mmap(8 * 16) as *i64
63 var found: i64 = 0
64 var i: i64 = 0
65 while i < cnt {
66 let rf: i64 = ncfg_row(h, "rev\x00" as *u8, i, rk, rv, 16)
67 if rf > 0 {
68 let idb: *u8 = ncfg_field(rk, rv, rf, "id\x00" as *u8)
69 if (idb as i64) != 0 { if tsyn_streq(idb, id) == 1 {
70 out3[0] = trn_atoi(ncfg_field(rk, rv, rf, "reps\x00" as *u8))
71 out3[1] = trn_atoi(ncfg_field(rk, rv, rf, "interval\x00" as *u8))
72 out3[2] = trn_atoi(ncfg_field(rk, rv, rf, "due\x00" as *u8))
73 found = 1
74 } }
75 }
76 i = i + 1
77 }
78 return found
79}
80func trn_append_state(state_store: *u8, id: *u8, reps: i64, interval: i64, due: i64) -> i64 {
81 let h0: *i64 = ncfg_open(state_store)
82 var base: i64 = 0
83 if (h0 as i64) != 0 { base = ncfg_count(h0, "rev\x00" as *u8) }
84 let w: *i64 = ncfg_begin()
85 let kb: *i64 = sys_mmap(8 * 8) as *i64
86 let vb: *i64 = sys_mmap(8 * 8) as *i64
87 let rs: *u8 = sys_mmap(28); trn_itoa(reps, rs)
88 let is: *u8 = sys_mmap(28); trn_itoa(interval, is)
89 let ds: *u8 = sys_mmap(28); trn_itoa(due, ds)
90 kb[0] = ("id\x00") as i64; vb[0] = (id as i64)
91 kb[1] = ("reps\x00") as i64; vb[1] = (rs as i64)
92 kb[2] = ("interval\x00") as i64; vb[2] = (is as i64)
93 kb[3] = ("due\x00") as i64; vb[3] = (ds as i64)
94 ncfg_add_row(w, "rev\x00" as *u8, base, kb, vb, 4)
95 ncfg_set_count(w, "rev\x00" as *u8, base + 1)
96 return ncfg_commit(state_store, w)
97}
98// record a retrieval-practice event for `id`: reps+1, interval 1 then doubling, due = now + interval days.
99func trn_practice(state_store: *u8, id: *u8, now: i64) -> i64 {
100 let st: *i64 = sys_mmap(8 * 4) as *i64
101 let had: i64 = trn_state(state_store, id, st)
102 var ninterval: i64 = 1
103 if had == 1 { if st[0] >= 1 { ninterval = st[1] * 2 } }
104 let nreps: i64 = st[0] + 1
105 let due: i64 = now + ninterval * TRN_DAY
106 return trn_append_state(state_store, id, nreps, ninterval, due)
107}
108// how many unified insights are DUE (never practiced OR now >= due epoch).
109func trn_due_count(cap_store: *u8, state_store: *u8, now: i64) -> i64 {
110 let h: *i64 = ncfg_open(cap_store)
111 if (h as i64) == 0 { return 0 }
112 let cnt: i64 = ncfg_count(h, "insight\x00" as *u8)
113 let rk: *i64 = sys_mmap(8 * 16) as *i64
114 let rv: *i64 = sys_mmap(8 * 16) as *i64
115 let st: *i64 = sys_mmap(8 * 4) as *i64
116 var due: i64 = 0
117 var i: i64 = 0
118 while i < cnt {
119 let rf: i64 = ncfg_row(h, "insight\x00" as *u8, i, rk, rv, 16)
120 if rf > 0 {
121 let idb: *u8 = ncfg_field(rk, rv, rf, "id\x00" as *u8)
122 if (idb as i64) != 0 {
123 let had: i64 = trn_state(state_store, idb, st)
124 var isdue: i64 = 0
125 if had == 0 { isdue = 1 } else { if now >= st[2] { isdue = 1 } }
126 if isdue == 1 { due = due + 1 }
127 }
128 }
129 i = i + 1
130 }
131 return due
132}
133// how many unified insights are under active practice (reps >= 1) -- the coverage meter.
134func trn_coverage(cap_store: *u8, state_store: *u8) -> i64 {
135 let h: *i64 = ncfg_open(cap_store)
136 if (h as i64) == 0 { return 0 }
137 let cnt: i64 = ncfg_count(h, "insight\x00" as *u8)
138 let rk: *i64 = sys_mmap(8 * 16) as *i64
139 let rv: *i64 = sys_mmap(8 * 16) as *i64
140 let st: *i64 = sys_mmap(8 * 4) as *i64
141 var cov: i64 = 0
142 var i: i64 = 0
143 while i < cnt {
144 let rf: i64 = ncfg_row(h, "insight\x00" as *u8, i, rk, rv, 16)
145 if rf > 0 {
146 let idb: *u8 = ncfg_field(rk, rv, rf, "id\x00" as *u8)
147 if (idb as i64) != 0 {
148 let had: i64 = trn_state(state_store, idb, st)
149 if had == 1 { if st[0] >= 1 { cov = cov + 1 } }
150 }
151 }
152 i = i + 1
153 }
154 return cov
155}
156
157func main() -> i64 {
158 trn_puts("=== Nishi Teacher TRAINER: spaced-retrieval scheduler + coverage meter over the unified store ===\n")
159 let cap: *u8 = "knowledge/store/teacher-capability-\x00" as *u8
160 let state: *u8 = "knowledge/store/teacher-review-\x00" as *u8
161 let now: i64 = sys_now_realtime_sec()
162 let h: *i64 = ncfg_open(cap)
163 var total: i64 = 0
164 if (h as i64) != 0 { total = ncfg_count(h, "insight\x00" as *u8) }
165 trn_puts(" unified insights: "); trn_putn(total); trn_puts("\n")
166 trn_puts(" before: due="); trn_putn(trn_due_count(cap, state, now)); trn_puts(" covered="); trn_putn(trn_coverage(cap, state)); trn_puts("\n")
167 // demonstrate the loop: practice three unique-id insights (process lesson + technical trap + lesson)
168 trn_practice(state, "BL-001\x00" as *u8, now)
169 trn_practice(state, "LM-001\x00" as *u8, now)
170 trn_practice(state, "BL-002\x00" as *u8, now)
171 let cov1: i64 = trn_coverage(cap, state)
172 trn_puts(" after practicing BL-001,LM-001,BL-002: due="); trn_putn(trn_due_count(cap, state, now)); trn_puts(" covered="); trn_putn(cov1)
173 var permil: i64 = 0
174 if total > 0 { permil = cov1 * 1000 / total }
175 trn_puts(" coverage_permil="); trn_putn(permil); trn_puts("\n")
176 trn_puts(" HONEST: coverage = fraction under active spaced retrieval; capability LIFT needs the team to practice + a before/after performance measure (further rung)\n")
177 sys_exit(0); return 0
178}