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}