code wiki / _hdl_build / nx_survey_quality_gate.nx
nx_survey_quality_gate.nx source
↩ module page · 164 lines · 7822 B
1import "nx_gate_gn.nx"
2// nx_survey_quality_gate.nx -- GATE for the C/IER data-quality detector. Hand-KAT'd, with the ADVERSARY that
3// matters for welfare: a genuinely struggling family (varied LOW scores) must NOT be flagged careless, while a
4// straight-liner (identical answers) and an attention-check failer MUST be. Ballots built directly (canon_encode
5// a_<qid> fields = what se_ballots yields). Exits 0 iff ALL pass. license_tier: ORIGINAL expect_exit: 0
6import "nx_syscalls.nx"
7import "nx_survey_quality.nx"
8
9func gp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
10func chk(name: *u8, got: i64, want: i64, st: *i64) -> i64 {
11 if got == want { st[0] = st[0] + 1; gp(" PASS " as *u8); gp(name); gp("\n" as *u8) }
12 else { st[1] = st[1] + 1; gp(" FAIL " as *u8); gp(name); gp(" got=" as *u8); gn(got); gp(" want=" as *u8); gn(want); gp("\n" as *u8) }
13 return 0
14}
15// build one ballot from parallel qid-name / value arrays (value <0 => omit that answer). ptr into outp[0], returns len.
16func mkballot(qids: *i64, vals: *i64, n: i64, outp: *i64) -> i64 {
17 let ks: *i64 = sys_mmap(8 * (n + 4)) as *i64
18 let vs: *i64 = sys_mmap(8 * (n + 4)) as *i64
19 var nf: i64 = 0
20 ks[nf] = "type" as *u8 as i64
21 vs[nf] = "rsp" as *u8 as i64
22 nf = nf + 1
23 var i: i64 = 0
24 while i < n {
25 if vals[i] >= 0 {
26 let fk: *u8 = sys_mmap(40)
27 var o: i64 = se_cat(fk, 0, "a_" as *u8)
28 o = se_cat(fk, o, qids[i] as *u8)
29 fk[o] = 0 as u8
30 let vb: *u8 = sys_mmap(16)
31 se_catn(vb, 0, vals[i])
32 ks[nf] = fk as i64
33 vs[nf] = vb as i64
34 nf = nf + 1
35 }
36 i = i + 1
37 }
38 let rec: *u8 = sys_mmap(8192)
39 let rl: i64 = canon_encode(ks, vs, nf, rec)
40 outp[0] = rec as i64
41 return rl
42}
43
44func main() -> i64 {
45 let st: *i64 = sys_mmap(16) as *i64
46 st[0] = 0
47 st[1] = 0
48 gp("=== nx_survey_quality_gate (attention checks + longstring + consistency; adversary: genuine low-scorer NOT flagged) ===\n" as *u8)
49
50 // qid block: q2 = attention-check (choice), q1/q3/q5 = scale items (the straight-line block)
51 let qn: *i64 = sys_mmap(8 * 8) as *i64
52 qn[0] = "q1" as *u8 as i64
53 qn[1] = "q2" as *u8 as i64
54 qn[2] = "q3" as *u8 as i64
55 qn[3] = "q5" as *u8 as i64
56 let sqids: *i64 = sys_mmap(8 * 4) as *i64
57 sqids[0] = "q1" as *u8 as i64
58 sqids[1] = "q3" as *u8 as i64
59 sqids[2] = "q5" as *u8 as i64
60 let checks: *u8 = "q2:1," as *u8
61 let vals: *i64 = sys_mmap(8 * 8) as *i64
62 let op: *i64 = sys_mmap(16) as *i64
63 let ao: *i64 = sys_mmap(16) as *i64
64 let reason: *i64 = sys_mmap(32) as *i64
65
66 // ---- Q1 attention check ----
67 // clean: q2=1 (expected) -> 0 failed of 1
68 vals[0] = 8; vals[1] = 1; vals[2] = 6; vals[3] = 7
69 let l1: i64 = mkballot(qn, vals, 4, op)
70 sq_attention(op[0] as *u8, l1, checks, ao)
71 var q1: i64 = 0
72 if ao[0] == 0 { if ao[1] == 1 { q1 = 1 } }
73 chk("Q1 attention pass: 0 failed of 1" as *u8, q1, 1, st)
74 // wrong: q2=0 -> 1 failed
75 vals[1] = 0
76 let l2: i64 = mkballot(qn, vals, 4, op)
77 sq_attention(op[0] as *u8, l2, checks, ao)
78 chk("Q1b attention WRONG answer -> 1 failed" as *u8, ao[0], 1, st)
79 // absent: omit q2 -> 1 failed (not reading = didn't answer the instructed item)
80 vals[1] = 0 - 1
81 let l3: i64 = mkballot(qn, vals, 4, op)
82 sq_attention(op[0] as *u8, l3, checks, ao)
83 chk("Q1c attention ABSENT answer -> 1 failed" as *u8, ao[0], 1, st)
84 // two checks
85 vals[1] = 1
86 let l4: i64 = mkballot(qn, vals, 4, op)
87 sq_attention(op[0] as *u8, l4, "q2:1,q1:8," as *u8, ao)
88 var q1d: i64 = 0
89 if ao[0] == 0 { if ao[1] == 2 { q1d = 1 } }
90 chk("Q1d two checks both pass -> 0 of 2" as *u8, q1d, 1, st)
91
92 // ---- Q2 longstring ----
93 vals[0] = 5; vals[1] = 1; vals[2] = 5; vals[3] = 5
94 let l5: i64 = mkballot(qn, vals, 4, op)
95 chk("Q2 straight-line q1=q3=q5=5 -> longstring 3" as *u8, sq_longstring(op[0] as *u8, l5, sqids, 3), 3, st)
96 vals[0] = 5; vals[2] = 3; vals[3] = 7
97 let l6: i64 = mkballot(qn, vals, 4, op)
98 chk("Q2b varied 5,3,7 -> longstring 1" as *u8, sq_longstring(op[0] as *u8, l6, sqids, 3), 1, st)
99 vals[0] = 5; vals[2] = 5; vals[3] = 3
100 let l7: i64 = mkballot(qn, vals, 4, op)
101 chk("Q2c 5,5,3 -> longstring 2" as *u8, sq_longstring(op[0] as *u8, l7, sqids, 3), 2, st)
102
103 // ---- Q3 consistency ----
104 vals[0] = 8; vals[2] = 9
105 let l8: i64 = mkballot(qn, vals, 4, op)
106 chk("Q3 consistent 8 vs 9 (maxdiff 2) -> 0" as *u8, sq_consistency(op[0] as *u8, l8, "q1" as *u8, "q3" as *u8, 2), 0, st)
107 vals[0] = 8; vals[2] = 2
108 let l9: i64 = mkballot(qn, vals, 4, op)
109 chk("Q3b inconsistent 8 vs 2 (maxdiff 2) -> 1" as *u8, sq_consistency(op[0] as *u8, l9, "q1" as *u8, "q3" as *u8, 2), 1, st)
110
111 // ---- Q4 composite careless (checks=q2:1, block=q1/q3/q5, ls_thresh=3) ----
112 // CLEAN: attention pass + varied
113 vals[0] = 8; vals[1] = 1; vals[2] = 6; vals[3] = 7
114 let la: i64 = mkballot(qn, vals, 4, op)
115 chk("Q4 clean respondent NOT flagged" as *u8, sq_ballot_careless(op[0] as *u8, la, checks, sqids, 3, 3, reason), 0, st)
116 // STRAIGHT-LINER: attention pass but identical scale answers
117 vals[0] = 5; vals[1] = 1; vals[2] = 5; vals[3] = 5
118 let lb: i64 = mkballot(qn, vals, 4, op)
119 var q4b: i64 = sq_ballot_careless(op[0] as *u8, lb, checks, sqids, 3, 3, reason)
120 var q4bok: i64 = 0
121 if q4b == 1 { if reason[1] == 3 { if reason[0] == 0 { q4bok = 1 } } }
122 chk("Q4b straight-liner flagged (longstring=3, attention ok)" as *u8, q4bok, 1, st)
123 // ATTENTION-FAILER: varied answers but failed the instructed item
124 vals[0] = 8; vals[1] = 0; vals[2] = 6; vals[3] = 7
125 let lc: i64 = mkballot(qn, vals, 4, op)
126 var q4c: i64 = sq_ballot_careless(op[0] as *u8, lc, checks, sqids, 3, 3, reason)
127 var q4cok: i64 = 0
128 if q4c == 1 { if reason[0] == 1 { q4cok = 1 } }
129 chk("Q4c attention-failer flagged (attn_fails=1)" as *u8, q4cok, 1, st)
130 // ADVERSARY: a genuinely struggling family -- VARIED low scores + attention pass -> NOT careless
131 vals[0] = 2; vals[1] = 1; vals[2] = 1; vals[3] = 3
132 let ld: i64 = mkballot(qn, vals, 4, op)
133 chk("Q4d ADVERSARY genuine low-scorer (varied 2,1,3) NOT flagged" as *u8, sq_ballot_careless(op[0] as *u8, ld, checks, sqids, 3, 3, reason), 0, st)
134
135 // ---- Q5 rollup over the 4 above (2 clean, 2 flagged; 1 attention-failer, 1 straightliner) ----
136 let vout: *i64 = sys_mmap(8 * 8) as *i64
137 let lout: *i64 = sys_mmap(8 * 8) as *i64
138 let p0: *i64 = sys_mmap(16) as *i64
139 vals[0] = 8; vals[1] = 1; vals[2] = 6; vals[3] = 7
140 lout[0] = mkballot(qn, vals, 4, p0); vout[0] = p0[0]
141 let p1: *i64 = sys_mmap(16) as *i64
142 vals[0] = 5; vals[1] = 1; vals[2] = 5; vals[3] = 5
143 lout[1] = mkballot(qn, vals, 4, p1); vout[1] = p1[0]
144 let p2: *i64 = sys_mmap(16) as *i64
145 vals[0] = 8; vals[1] = 0; vals[2] = 6; vals[3] = 7
146 lout[2] = mkballot(qn, vals, 4, p2); vout[2] = p2[0]
147 let p3: *i64 = sys_mmap(16) as *i64
148 vals[0] = 2; vals[1] = 1; vals[2] = 1; vals[3] = 3
149 lout[3] = mkballot(qn, vals, 4, p3); vout[3] = p3[0]
150 let ro: *i64 = sys_mmap(32) as *i64
151 sq_rollup(vout, lout, 4, checks, sqids, 3, 3, ro)
152 var q5: i64 = 0
153 if ro[0] == 2 { if ro[1] == 2 { if ro[2] == 1 { if ro[3] == 1 { q5 = 1 } } } }
154 chk("Q5 rollup: 2 clean, 2 flagged, 1 attention-fail, 1 straightliner" as *u8, q5, 1, st)
155
156 gp("nx_survey_quality_gate: PASS=" as *u8)
157 gn(st[0])
158 gp(" FAIL=" as *u8)
159 gn(st[1])
160 gp("\n" as *u8)
161 if st[1] == 0 { gp("VERDICT: verdict=GREEN (C/IER: attention checks + longstring + consistency; genuine low-scorers protected)\n" as *u8); return 0 }
162 gp("VERDICT: RED\n" as *u8)
163 return 1
164}