code wiki / (root) / nx_survey.nx

nx_survey.nx source

↩ module page · 105 lines · 4503 B

1// nx_survey.nx -- R0 of THE NISHI SITUATION-MANAGEMENT arc: the POLL / SURVEY intake engine. The front 2// door for a person to manage their situation and climb out of it: ask about income, debts, bills, 3// hardships, goals; CAPTURE the response as a sovereign content-addressed record; derive a TRIAGE score 4// that routes them to the right help (debt payoff / overbilling audit / affordable-funding / bills). Data- 5// driven (#11): questions + triage weights + band thresholds are DATA, never hardcoded -- any survey, any 6// scoring. Reuses canon_cid + seg_store (DRY). Commits with sys_now_us() (per reference-segstore-segid-use- 7// now-us). No floats, no hardware writes, no auto-action -- records + scores; the person + engines act. 8// license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_canon_cid.nx" 11import "nx_uxf_decode.nx" 12import "nx_seg_store.nx" 13 14func sv_itoa(v: i64, out: *u8) -> i64 { 15 if v == 0 { out[0] = 0x30 as u8; out[1] = 0 as u8; return 1 } 16 var neg: i64 = 0 17 var m: i64 = v 18 if m < 0 { neg = 1; m = 0 - m } 19 let tmp: *u8 = sys_mmap(32); var k: i64 = 0 20 while m > 0 { tmp[k] = (0x30 + (m % 10)) as u8; m = m / 10; k = k + 1 } 21 var p: i64 = 0 22 if neg == 1 { out[p] = 0x2d as u8; p = p + 1 } 23 var i: i64 = k - 1 24 while i >= 0 { out[p] = tmp[i]; p = p + 1; i = i - 1 } 25 out[p] = 0 as u8 26 return p 27} 28func sv_atoi(s: *u8) -> i64 { 29 var i: i64 = 0; var neg: i64 = 0 30 if s[0] == (0x2d as u8) { neg = 1; i = 1 } 31 var v: i64 = 0 32 while s[i] != (0 as u8) { let c: i64 = s[i]; if c >= 0x30 { if c <= 0x39 { v = v * 10 + (c - 0x30) } } i = i + 1 } 33 if neg == 1 { return 0 - v } 34 return v 35} 36func sv_streq(a: *u8, b: *u8) -> i64 { 37 var i: i64 = 0 38 while 1 == 1 { if a[i] != b[i] { return 0 } if a[i] == (0 as u8) { return 1 } i = i + 1 } 39 return 1 40} 41func sv_get(keys: *i64, vals: *i64, nf: i64, key: *u8) -> *u8 { 42 var i: i64 = 0 43 while i < nf { let kp: *u8 = keys[i] as *u8; if sv_streq(kp, key) == 1 { return vals[i] as *u8 } i = i + 1 } 44 return 0 as *u8 45} 46 47// record a survey response (qids[] = i64 array of question-id *u8 ptrs; vals[] = numeric answers) as a 48// content-addressed record. writes the CID to out_cid (>=80 bytes). returns 0 ok, negative on error. 49func sv_record(prefix: *u8, respondent: *u8, qids: *i64, vals: *i64, n: i64, out_cid: *u8) -> i64 { 50 let keys: *i64 = sys_mmap(8 * (n + 4)) as *i64 51 let vlist: *i64 = sys_mmap(8 * (n + 4)) as *i64 52 var nf: i64 = 0 53 keys[nf] = "type\x00" as *u8 as i64; vlist[nf] = "survey\x00" as *u8 as i64; nf = nf + 1 54 keys[nf] = "respondent\x00" as *u8 as i64; vlist[nf] = respondent as i64; nf = nf + 1 55 var i: i64 = 0 56 while i < n { 57 let vb: *u8 = sys_mmap(24) 58 sv_itoa(vals[i], vb) 59 keys[nf] = qids[i]; vlist[nf] = vb as i64; nf = nf + 1 60 i = i + 1 61 } 62 let rec: *u8 = sys_mmap(8192) 63 let rl: i64 = canon_encode(keys, vlist, nf, rec) 64 cid_of(rec, rl, out_cid) 65 let w: *i64 = ss_begin() 66 if ss_add(w, 1, out_cid, rec, rl) != 0 { return 0 - 10 } 67 if ss_commit(prefix, w, sys_now_us()) != 0 { return 0 - 11 } 68 return 0 69} 70 71// load a stored response by CID into decoded out_keys/out_vals; returns field count or negative. 72func sv_load(prefix: *u8, cid: *u8, out_keys: *i64, out_vals: *i64, maxf: i64) -> i64 { 73 let h: *i64 = ss_open(prefix) 74 if (h as i64) == 0 { return 0 - 1 } 75 let pp: *i64 = sys_mmap(16) as *i64 76 let lq: *i64 = sys_mmap(16) as *i64 77 if ss_hget(h, cid, pp, lq) != 1 { return 0 - 2 } 78 return canon_decode(pp[0] as *u8, lq[0], out_keys, out_vals, maxf) 79} 80 81// numeric answer to a question id in a decoded response (0 if absent). 82func sv_answer(keys: *i64, vals: *i64, nf: i64, qid: *u8) -> i64 { 83 let v: *u8 = sv_get(keys, vals, nf, qid) 84 if (v as i64) == 0 { return 0 } 85 return sv_atoi(v) 86} 87 88// triage score: for each weighted RISK question, add its weight iff the answer is > 0. Data-driven. 89func sv_triage(keys: *i64, vals: *i64, nf: i64, wqids: *i64, weights: *i64, nw: i64) -> i64 { 90 var s: i64 = 0 91 var i: i64 = 0 92 while i < nw { 93 let q: *u8 = wqids[i] as *u8 94 if sv_answer(keys, vals, nf, q) > 0 { s = s + weights[i] } 95 i = i + 1 96 } 97 return s 98} 99 100// triage band from a score: 0 = stable, 1 = strained, 2 = crisis (thresholds are DATA). 101func sv_band(score: i64, t_strained: i64, t_crisis: i64) -> i64 { 102 if score >= t_crisis { return 2 } 103 if score >= t_strained { return 1 } 104 return 0 105}