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}