code wiki / _hdl_build / nx_coach_curriculum_lib.nx

nx_coach_curriculum_lib.nx source

↩ module page · 137 lines · 7684 B

1// nx_coach_curriculum_lib.nx -- the CURRICULUM-COACH engine as a PURE CORE (no main), extracted verbatim from 2// nx_coach_curriculum.nx so a second discipline can ADOPT the engine instead of forking it. 3// 4// WHY THE EXTRACTION. nx_coach_curriculum.nx was a lib wearing an organ's clothes: the whole engine plus a 5// main(). Nothing can import a file that defines main(), so the only way to reuse it was to copy it -- which is 6// exactly the duplication the estate is already RED on (179 cross-tree dup basenames). The estate already has 7// the split convention (nx_gate_verdict / nx_gate_verdict_lib); this applies it here. The organ keeps its main() 8// and imports this; behaviour is unchanged and proven by re-running it. 9// 10// THE ENGINE, unchanged: assess -> serve the FRAMEWORK from the store -> the person practises -> grade the 11// SELF-REPORT (a bitmask of which framework elements they used) against the checklist -> name the MISSING 12// element -> hand back its drill. "Coaching is coaching": the framework's required elements are the target 13// chord, the reported elements are the played notes, missing is the gap. Works for any discipline whose 14// technique decomposes into nameable elements -- interpersonal frameworks, or a knife on a board. 15// 16// Frameworks are DATA in knowledge/store/coach-curriculum- (rule 11), so a new discipline is rows, not code. 17// license_tier: ORIGINAL No hw writes (Rule 26). 18import "nx_seg_store.nx" 19import "nx_itoa_lib.nx" 20import "nx_syscalls.nx" 21 22const CC_PFX: *u8 = "knowledge/store/coach-curriculum-" as *u8 23 24func cc_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 25func cc_putn(v: i64) -> i64 { nxi_out(v); return 0 } 26func cc_atoi(s: *u8, n: i64) -> i64 { var v: i64 = 0; var i: i64 = 0; while i < n { let c: i64 = s[i]; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 } return v } 27func cc_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 28func cc_add(w: *i64, key: *u8, val: *u8) -> i64 { return ss_add(w, 1, key, val, cc_slen(val)) } 29 30// build "<skill>:<suffix>" or "<skill>:<suffix>:<idx>" into out 31func cc_key(skill: *u8, suffix: *u8, idx: i64, hasidx: i64, out: *u8) -> i64 { 32 var o: i64 = ss_cat(out, 0, skill); o = ss_cat(out, o, ":" as *u8); o = ss_cat(out, o, suffix) 33 if hasidx == 1 { 34 o = ss_cat(out, o, ":" as *u8) 35 let t: *u8 = sys_mmap(8); var k: i64 = 0; var m: i64 = idx 36 if m == 0 { t[0] = 48 as u8; k = 1 } 37 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 38 var j: i64 = k - 1; while j >= 0 { out[o] = t[j]; o = o + 1; j = j - 1 } 39 } 40 out[o] = 0 as u8; return o 41} 42 43func cc_get(h: *i64, key: *u8, outlen: *i64) -> *u8 { 44 let pp: *i64 = sys_mmap(16) as *i64; let ll: *i64 = sys_mmap(16) as *i64 45 if ss_hget(h, key, pp, ll) != 1 { outlen[0] = 0; return 0 as *u8 } 46 outlen[0] = ll[0]; return pp[0] as *u8 47} 48 49func cc_seed(prefix: *u8) -> i64 { 50 let w: *i64 = ss_begin() 51 // CONFRONTATION = Nonviolent Communication (4 elements) 52 cc_add(w, "confront:prompt" as *u8, "A coworker took credit for your work. Respond using all 4 NVC steps." as *u8) 53 cc_add(w, "confront:n" as *u8, "4" as *u8) 54 cc_add(w, "confront:elem:0" as *u8, "Observation (the fact, no judgment)" as *u8) 55 cc_add(w, "confront:elem:1" as *u8, "Feeling (name how you feel)" as *u8) 56 cc_add(w, "confront:elem:2" as *u8, "Need (the underlying need)" as *u8) 57 cc_add(w, "confront:elem:3" as *u8, "Request (a clear, doable ask)" as *u8) 58 cc_add(w, "confront:drill:0" as *u8, "state ONLY the observable fact, strip the judgment" as *u8) 59 cc_add(w, "confront:drill:1" as *u8, "name the feeling ('I feel...') without blaming" as *u8) 60 cc_add(w, "confront:drill:2" as *u8, "connect it to the need ('because I need...')" as *u8) 61 cc_add(w, "confront:drill:3" as *u8, "end with a specific, doable request" as *u8) 62 // CONVERSATION = active listening (3 elements) 63 cc_add(w, "converse:prompt" as *u8, "A friend is venting about a hard day. Practice active listening." as *u8) 64 cc_add(w, "converse:n" as *u8, "3" as *u8) 65 cc_add(w, "converse:elem:0" as *u8, "Paraphrase (reflect back what you heard)" as *u8) 66 cc_add(w, "converse:elem:1" as *u8, "Open question (invite more)" as *u8) 67 cc_add(w, "converse:elem:2" as *u8, "Validate (acknowledge the feeling)" as *u8) 68 cc_add(w, "converse:drill:0" as *u8, "paraphrase in your own words before responding" as *u8) 69 cc_add(w, "converse:drill:1" as *u8, "ask an open 'what/how' question" as *u8) 70 cc_add(w, "converse:drill:2" as *u8, "validate ('that sounds really...')" as *u8) 71 return ss_commit(prefix, w, sys_now_ms()) 72} 73 74// one curriculum attempt: response_mask = which framework elements the person used. Returns # missing (0=complete). 75func cc_attempt(h: *i64, skill: *u8, response_mask: i64) -> i64 { 76 let key: *u8 = sys_mmap(96) 77 let ol: *i64 = sys_mmap(16) as *i64 78 cc_key(skill, "n" as *u8, 0, 0, key) 79 let ns: *u8 = cc_get(h, key, ol); var n: i64 = 0; if (ns as i64) != 0 { n = cc_atoi(ns, ol[0]) } 80 let checklist: i64 = (1 << n) - 1 81 let missing: i64 = checklist & (0xffffff ^ response_mask) 82 cc_key(skill, "prompt" as *u8, 0, 0, key); let pr: *u8 = cc_get(h, key, ol) 83 cc_puts(" ["); cc_puts(skill); cc_puts("] "); if (pr as i64) != 0 { sys_write(1, pr, ol[0]) } cc_puts("\n" as *u8) 84 var nmiss: i64 = 0 85 var i: i64 = 0 86 while i < n { 87 if (missing & (1 << i)) != 0 { 88 nmiss = nmiss + 1 89 cc_key(skill, "elem" as *u8, i, 1, key); let em: *u8 = cc_get(h, key, ol) 90 cc_puts(" MISSED: "); if (em as i64) != 0 { sys_write(1, em, ol[0]) } cc_puts(" -> DRILL: ") 91 cc_key(skill, "drill" as *u8, i, 1, key); let dr: *u8 = cc_get(h, key, ol) 92 if (dr as i64) != 0 { sys_write(1, dr, ol[0]) } cc_puts("\n" as *u8) 93 } 94 i = i + 1 95 } 96 if nmiss == 0 { cc_puts(" COMPLETE -- all framework elements present -> advance (harder scenario)\n" as *u8) } 97 return nmiss 98} 99 100// ---- ADDED BY THE EXTRACTION (the organ never needed these; a second discipline does) ---- 101 102// how many elements a framework declares (0 = the store has never heard of this skill). 103func cc_element_count(h: *i64, skill: *u8) -> i64 { 104 let key: *u8 = sys_mmap(96) 105 let ol: *i64 = sys_mmap(16) as *i64 106 cc_key(skill, "n" as *u8, 0, 0, key) 107 let ns: *u8 = cc_get(h, key, ol) 108 if (ns as i64) == 0 { return 0 } 109 return cc_atoi(ns, ol[0]) 110} 111 112// SILENT grade: same arithmetic as cc_attempt with no printing, so a page renderer can use the engine without 113// the CLI's stdout. Returns the missing-element BITMASK (0 = complete), or -1 for an unknown skill -- 114// an unknown framework must never grade as a perfect attempt. 115func cc_missing_mask(h: *i64, skill: *u8, response_mask: i64) -> i64 { 116 let n: i64 = cc_element_count(h, skill) 117 if n <= 0 { return 0 - 1 } 118 let checklist: i64 = (1 << n) - 1 119 return checklist & (0xffffff ^ response_mask) 120} 121 122// the element text / drill text for one index; length into outlen (0 = absent). 123func cc_element(h: *i64, skill: *u8, idx: i64, outlen: *i64) -> *u8 { 124 let key: *u8 = sys_mmap(96) 125 cc_key(skill, "elem" as *u8, idx, 1, key) 126 return cc_get(h, key, outlen) 127} 128func cc_drill(h: *i64, skill: *u8, idx: i64, outlen: *i64) -> *u8 { 129 let key: *u8 = sys_mmap(96) 130 cc_key(skill, "drill" as *u8, idx, 1, key) 131 return cc_get(h, key, outlen) 132} 133func cc_prompt(h: *i64, skill: *u8, outlen: *i64) -> *u8 { 134 let key: *u8 = sys_mmap(96) 135 cc_key(skill, "prompt" as *u8, 0, 0, key) 136 return cc_get(h, key, outlen) 137}