code wiki / _hdl_build / nx_coach_rubric.nx

nx_coach_rubric.nx source

↩ module page · 91 lines · 5688 B

1// nx_coach_rubric.nx -- SKILL-COACH rung R2: the DATA-DRIVEN RUBRIC STORE (rule #11/#25). The R1/R3 coach verdicts 2// map to DRILLS via a sovereign seg_store (knowledge/store/coach-rubric-), keyed "<discipline>:<verdict>" -> drill 3// text, + numeric thresholds. The coach ENGINE reads drills FROM the store (not hardcoded), so the team extends the 4// curriculum (new drills, disciplines, voice-types) by editing DATA, no recompile -- and it's sovereign + content- 5// addressed, not a .tsv/.json. Composes ss_* (the store pattern proven this session). Self-gate: seed -> reopen -> 6// drills + threshold byte-faithful + a MISSING key returns ABSENT (liar-kill: never a fabricated drill). ORIGINAL 7import "nx_seg_store.nx" 8import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 9import "nx_syscalls.nx" 10 11const RB_PFX: *u8 = "knowledge/store/coach-rubric-" as *u8 12 13func rb_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 14// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 15// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 16// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 17// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 18func rb_putn(v: i64) -> i64 { nxi_out(v); return 0 } 19func rb_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 20func rb_has(b: *u8, n: i64, needle: *u8) -> i64 { 21 let ln: i64 = rb_slen(needle) 22 if ln == 0 { return 1 } 23 var p: i64 = 0 24 while p + ln <= n { 25 var j: i64 = 0; var hit: i64 = 1 26 while j < ln { if b[p + j] != needle[j] { hit = 0; j = ln } else { j = j + 1 } } 27 if hit == 1 { return 1 } 28 p = p + 1 29 } 30 return 0 31} 32func rb_eq(a: *u8, an: i64, b: *u8, bn: i64) -> i64 { 33 if an != bn { return 0 } 34 var i: i64 = 0; while i < an { if a[i] != b[i] { return 0 } i = i + 1 } 35 return 1 36} 37// add one rubric row (key + NUL-terminated drill string) 38func rb_add(w: *i64, key: *u8, drill: *u8) -> i64 { return ss_add(w, 1, key, drill, rb_slen(drill)) } 39// seed the full rubric into a fresh segment + commit 40func rubric_seed(prefix: *u8) -> i64 { 41 let w: *i64 = ss_begin() 42 rb_add(w, "sing:in_tune" as *u8, "ON PITCH -> advance: next note / wider interval" as *u8) 43 rb_add(w, "sing:sharp" as *u8, "SHARP -> relax throat, lower slightly; DRILL: sustained-tone pitch-matching" as *u8) 44 rb_add(w, "sing:flat" as *u8, "FLAT -> add breath support; DRILL: breath-support long-tones" as *u8) 45 rb_add(w, "sing:too_high" as *u8, "WRONG NOTE (too high) -> DRILL: descending-interval ear-training" as *u8) 46 rb_add(w, "sing:too_low" as *u8, "WRONG NOTE (too low) -> DRILL: ascending-interval ear-training" as *u8) 47 rb_add(w, "chord:clean" as *u8, "CLEAN chord -> advance: next chord / faster changes" as *u8) 48 rb_add(w, "chord:missing" as *u8, "MISSING note(s) -> DRILL: chord-tone isolation (fret each string)" as *u8) 49 rb_add(w, "chord:extra" as *u8, "EXTRA note(s) (open/muted string?) -> DRILL: clean-press + string muting" as *u8) 50 rb_add(w, "chord:wrong" as *u8, "WRONG QUALITY -> DRILL: chord-shape correction (minor vs major = the 3rd)" as *u8) 51 rb_add(w, "sing:tol_cents" as *u8, "20" as *u8) 52 rb_add(w, "chord:min_conf_pct" as *u8, "12" as *u8) 53 rb_add(w, "__count" as *u8, "11" as *u8) 54 return ss_commit(prefix, w, sys_now_ms()) 55} 56// the coach ENGINE's reader: drill text for a (discipline:verdict) key, or 0 if absent (no fabricated drill) 57func rubric_get(h: *i64, key: *u8, outlen: *i64) -> *u8 { 58 let pp: *i64 = sys_mmap(16) as *i64 59 let ll: *i64 = sys_mmap(16) as *i64 60 if ss_hget(h, key, pp, ll) != 1 { outlen[0] = 0; return 0 as *u8 } 61 outlen[0] = ll[0] 62 return pp[0] as *u8 63} 64func main() -> i64 { 65 rb_puts("SKILL-COACH (R2): seed the DATA-DRIVEN rubric -> sovereign seg_store (coach reads drills FROM the store)\n" as *u8) 66 rubric_seed(RB_PFX) 67 let h: *i64 = ss_open(RB_PFX) 68 if (h as i64) == 0 { rb_puts(" store open FAILED\n" as *u8); return 1 } 69 let ol: *i64 = sys_mmap(16) as *i64 70 var pass: i64 = 0 71 // demo: the engine looks up a drill by discipline:verdict 72 let flat: *u8 = rubric_get(h, "sing:flat" as *u8, ol) 73 if (flat as i64) != 0 { rb_puts(" sing:flat -> "); sys_write(1, flat, ol[0]); rb_puts("\n" as *u8) 74 if rb_has(flat, ol[0], "breath support" as *u8) == 1 { pass = pass + 1 } } 75 let miss: *u8 = rubric_get(h, "chord:missing" as *u8, ol) 76 if (miss as i64) != 0 { rb_puts(" chord:missing -> "); sys_write(1, miss, ol[0]); rb_puts("\n" as *u8) 77 if rb_has(miss, ol[0], "chord-tone isolation" as *u8) == 1 { pass = pass + 1 } } 78 // numeric threshold (data-driven, not a magic number in code) 79 let tol: *u8 = rubric_get(h, "sing:tol_cents" as *u8, ol) 80 if (tol as i64) != 0 { if rb_eq(tol, ol[0], "20" as *u8, 2) == 1 { pass = pass + 1 } } 81 // liar-kill: a missing key returns ABSENT, never a fabricated drill 82 let bogus: *u8 = rubric_get(h, "sing:does_not_exist" as *u8, ol) 83 if (bogus as i64) == 0 { pass = pass + 1 } 84 // count 85 let cnt: *u8 = rubric_get(h, "__count" as *u8, ol) 86 if (cnt as i64) != 0 { if rb_eq(cnt, ol[0], "11" as *u8, 2) == 1 { pass = pass + 1 } } 87 rb_puts(" checks passed = "); rb_putn(pass); rb_puts("/5\n" as *u8) 88 if pass == 5 { rb_puts("COACH-RUBRIC: GREEN -- curriculum is sovereign DATA (seg_store), editable without recompile, missing-key liar-killed; the coach engine reads drills from here\n" as *u8); return 0 } 89 rb_puts("COACH-RUBRIC: RED\n" as *u8) 90 return 1 91}