code wiki / _hdl_build / nx_night_grade.nx

nx_night_grade.nx source

↩ module page · 187 lines · 9615 B

1// nx_night_grade.nx -- SOVEREIGN night-reading benchmark gate (Reader arc, rung W-NIGHT-1). 2// 3// MEASURES the sourced eye-fatigue mechanism (blue light) per reader theme. The palette SSOT now 4// lives in the NATIVE content-addressed seg_store (ncfg / nx_native_config) -- NOT a flat .tsv 5// (operator 2026-06-20: "stop using tsv, nishi ecosystem only, all rungs everywhere"). The gate 6// SEEDS the 6-theme palette into a fresh per-run store then reads it back BY COLUMN NAME, so it has 7// ZERO dependency on knowledge/registry/night_themes.tsv (migrated off + removed). For each theme it 8// computes, from the dominant emitted colors (bg + fg, sRGB 0..255): 9// blue_emit = bb*BG_W + fb*FG_W (emitted blue, area-weighted) 10// total_emit = (br+bg+bb)*BG_W + (fr+fg+fb)*FG_W 11// blue_frac = blue_emit*1000 / total_emit (per-mille -- "how blue is the light", coverage-independent) 12// BG_W:FG_W = 9:1 = documented assumption that page background covers ~90% of the screen. 13// 14// Sourced rationale (knowledge/research/2026-06-16-night-reading-sourced.md): 15// short-wavelength (blue) light drives the circadian/eye-fatigue response (melanopsin/ipRGC); warm 16// 2700-3000K cuts blue; sRGB display white = 6500K (bluish). The night win = LESS BLUE, by composition 17// -- not merely darkness. Negative controls prove the metric measures blue, not dark. 18// 19// KAT order in the store (positional rows): 0 light, 1 sepia, 2 dark, 3 night, 4 black, 5 coolnight(neg). 20// expect_exit: 0 (all assertions green) 21// license_tier: ORIGINAL 22 23import "nx_syscalls.nx" 24import "nx_native_config.nx" 25 26func ng_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 27func ng_putn(v: i64) -> i64 { 28 let bb: *u8 = sys_mmap(28); var m: i64 = v 29 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } 30 let t: *u8 = sys_mmap(28); var k: i64 = 0 31 if m == 0 { t[0] = 48 as u8; k = 1 } 32 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 33 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0 34} 35func ng_assert(label: *u8, cond: i64) -> i64 { 36 if cond != 0 { ng_puts(" [PASS] "); ng_puts(label); ng_puts("\n"); return 1 } 37 ng_puts(" [FAIL] "); ng_puts(label); ng_puts("\n"); return 0 38} 39// parse a NUL-terminated decimal string -> i64 (null-safe: absent field -> 0). 40func ng_atoi(s: *u8) -> i64 { 41 if (s as i64) == 0 { return 0 } 42 var v: i64 = 0 43 var i: i64 = 0 44 while s[i] != (0 as u8) { 45 let c: i64 = s[i] as i64 46 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } 47 i = i + 1 48 } 49 return v 50} 51// fresh unique native store prefix per run (mirrors nx_library_exceed.lib_fresh_prefix). 52func ng_fresh_prefix(out: *u8, base: *u8) -> i64 { 53 var po: i64 = 0 54 while base[po] != (0 as u8) { out[po] = base[po]; po = po + 1 } 55 var m: i64 = sys_now_ms() 56 let ds: *u8 = sys_mmap(28) 57 var k: i64 = 0 58 if m == 0 { ds[0] = 48 as u8; k = 1 } 59 while m > 0 { ds[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 60 var j: i64 = 0 61 while j < k { out[po] = ds[k - 1 - j]; po = po + 1; j = j + 1 } 62 out[po] = 45 as u8; po = po + 1 63 out[po] = 0 as u8 64 return po 65} 66// author one theme row (8 named string columns) into the native store under tag "thm". 67func ng_row(w: *i64, idx: i64, nm: *u8, v0: *u8, v1: *u8, v2: *u8, v3: *u8, v4: *u8, v5: *u8, kind: *u8) -> i64 { 68 let keys: *i64 = sys_mmap(8 * 16) as *i64 69 let vals: *i64 = sys_mmap(8 * 16) as *i64 70 keys[0] = ("name\x00") as i64; vals[0] = (nm as i64) 71 keys[1] = ("bg_r\x00") as i64; vals[1] = (v0 as i64) 72 keys[2] = ("bg_g\x00") as i64; vals[2] = (v1 as i64) 73 keys[3] = ("bg_b\x00") as i64; vals[3] = (v2 as i64) 74 keys[4] = ("fg_r\x00") as i64; vals[4] = (v3 as i64) 75 keys[5] = ("fg_g\x00") as i64; vals[5] = (v4 as i64) 76 keys[6] = ("fg_b\x00") as i64; vals[6] = (v5 as i64) 77 keys[7] = ("kind\x00") as i64; vals[7] = (kind as i64) 78 return ncfg_add_row(w, "thm\x00" as *u8, idx, keys, vals, 8) 79} 80// seed the 6-theme palette FAITHFULLY (values verbatim from the migrated night_themes.tsv). 81func ng_seed(prefix: *u8) -> i64 { 82 let w: *i64 = ncfg_begin() 83 ng_row(w, 0, "light\x00" as *u8, "251\x00" as *u8, "251\x00" as *u8, "249\x00" as *u8, "29\x00" as *u8, "29\x00" as *u8, "27\x00" as *u8, "day\x00" as *u8) 84 ng_row(w, 1, "sepia\x00" as *u8, "244\x00" as *u8, "236\x00" as *u8, "216\x00" as *u8, "67\x00" as *u8, "57\x00" as *u8, "31\x00" as *u8, "day\x00" as *u8) 85 ng_row(w, 2, "dark\x00" as *u8, "21\x00" as *u8, "22\x00" as *u8, "26\x00" as *u8, "216\x00" as *u8, "216\x00" as *u8, "210\x00" as *u8, "dark\x00" as *u8) 86 ng_row(w, 3, "night\x00" as *u8, "26\x00" as *u8, "18\x00" as *u8, "6\x00" as *u8, "232\x00" as *u8, "200\x00" as *u8, "144\x00" as *u8, "night\x00" as *u8) 87 ng_row(w, 4, "black\x00" as *u8, "0\x00" as *u8, "0\x00" as *u8, "0\x00" as *u8, "200\x00" as *u8, "180\x00" as *u8, "140\x00" as *u8, "night\x00" as *u8) 88 ng_row(w, 5, "coolnight\x00" as *u8, "10\x00" as *u8, "10\x00" as *u8, "20\x00" as *u8, "176\x00" as *u8, "196\x00" as *u8, "222\x00" as *u8, "neg\x00" as *u8) 89 ncfg_set_count(w, "thm\x00" as *u8, 6) 90 return ncfg_commit(prefix, w) 91} 92// seed + open + read all 6 themes' ints (file order) into ints[t*6+0..5]; returns total ints read, or -1. 93func ng_load(ints: *i64) -> i64 { 94 let prefix: *u8 = sys_mmap(256) 95 ng_fresh_prefix(prefix, "/tmp/night-themes-\x00" as *u8) 96 if ng_seed(prefix) != 0 { ng_puts("NIGHT-GRADE: native seed/commit failed\n"); return 0 - 1 } 97 let h: *i64 = ncfg_open(prefix) 98 if (h as i64) == 0 { ng_puts("NIGHT-GRADE: cannot open native store\n"); return 0 - 1 } 99 let cnt: i64 = ncfg_count(h, "thm\x00" as *u8) 100 if cnt < 6 { ng_puts("NIGHT-GRADE: expected 6 themes, got "); ng_putn(cnt); ng_puts("\n"); return 0 - 1 } 101 let rk: *i64 = sys_mmap(8 * 16) as *i64 102 let rv: *i64 = sys_mmap(8 * 16) as *i64 103 var nints: i64 = 0 104 var t0: i64 = 0 105 while t0 < cnt { 106 let rf: i64 = ncfg_row(h, "thm\x00" as *u8, t0, rk, rv, 16) 107 if rf > 0 { 108 ints[t0*6+0] = ng_atoi(ncfg_field(rk, rv, rf, "bg_r\x00" as *u8)) 109 ints[t0*6+1] = ng_atoi(ncfg_field(rk, rv, rf, "bg_g\x00" as *u8)) 110 ints[t0*6+2] = ng_atoi(ncfg_field(rk, rv, rf, "bg_b\x00" as *u8)) 111 ints[t0*6+3] = ng_atoi(ncfg_field(rk, rv, rf, "fg_r\x00" as *u8)) 112 ints[t0*6+4] = ng_atoi(ncfg_field(rk, rv, rf, "fg_g\x00" as *u8)) 113 ints[t0*6+5] = ng_atoi(ncfg_field(rk, rv, rf, "fg_b\x00" as *u8)) 114 nints = nints + 6 115 } 116 t0 = t0 + 1 117 } 118 return nints 119} 120 121func main() -> i64 { 122 // ---- load the palette from the NATIVE seg_store (no TSV) ---- 123 let ints: *i64 = sys_mmap(64 * 8) as *i64 124 let nints: i64 = ng_load(ints) 125 if nints < 36 { ng_puts("NIGHT-GRADE: expected >=36 ints, got "); ng_putn(nints); ng_puts("\n"); return 3 } 126 127 let BG_W: i64 = 9 128 let FG_W: i64 = 1 129 let blue: *i64 = sys_mmap(16 * 8) as *i64 130 let tot: *i64 = sys_mmap(16 * 8) as *i64 131 let frac: *i64 = sys_mmap(16 * 8) as *i64 132 133 ng_puts("theme blue_emit total_emit blue_frac(permille)\n") 134 let names: *u8 = "light sepia dark night black coolnight" // 9 chars each 135 var t: i64 = 0 136 while t < 6 { 137 let br: i64 = ints[t*6+0] 138 let bgc: i64 = ints[t*6+1] 139 let bb2: i64 = ints[t*6+2] 140 let fr: i64 = ints[t*6+3] 141 let fgc: i64 = ints[t*6+4] 142 let fb: i64 = ints[t*6+5] 143 let be: i64 = bb2 * BG_W + fb * FG_W 144 let te: i64 = (br + bgc + bb2) * BG_W + (fr + fgc + fb) * FG_W 145 var fr2: i64 = 0 146 if te > 0 { fr2 = be * 1000 / te } 147 blue[t] = be; tot[t] = te; frac[t] = fr2 148 sys_write(1, " " as *u8, 2) 149 sys_write(1, (names as i64 + t*9) as *u8, 9) 150 ng_puts(" "); ng_putn(be) 151 ng_puts(" "); ng_putn(te) 152 ng_puts(" "); ng_putn(fr2) 153 ng_puts("\n") 154 t = t + 1 155 } 156 157 // index map: 0 light, 2 dark, 3 night, 4 black, 5 coolnight(neg) 158 ng_puts("\nassertions (sourced: night = LESS BLUE by composition, not just dark):\n") 159 var pass: i64 = 0 160 var total: i64 = 0 161 162 var c1: i64 = 0; if blue[3]*10 <= blue[0] { c1 = 1 } 163 total = total + 1; pass = pass + ng_assert("A1 night blue_emit*10 <= light blue_emit (>=90% blue cut)", c1) 164 165 var c2: i64 = 0; if blue[4]*10 <= blue[0] { c2 = 1 } 166 total = total + 1; pass = pass + ng_assert("A2 black blue_emit*10 <= light blue_emit (>=90% blue cut)", c2) 167 168 var c3: i64 = 0; if frac[3] <= 250 { c3 = 1 } 169 total = total + 1; pass = pass + ng_assert("A3 night blue_frac <= 250 (low-blue by composition)", c3) 170 171 var c4: i64 = 0; if frac[2] >= 330 { c4 = 1 } 172 total = total + 1; pass = pass + ng_assert("A4[neg] dark blue_frac >= 330 (plain dark is NOT low-blue)", c4) 173 174 var c5: i64 = 0; if frac[5] >= 330 { c5 = 1 } 175 total = total + 1; pass = pass + ng_assert("A5[neg] coolnight blue_frac >= 330 (dark+cool stays blue)", c5) 176 177 var c6: i64 = 0; if blue[3] < blue[2] { c6 = 1 } 178 total = total + 1; pass = pass + ng_assert("A6 night blue_emit < dark blue_emit", c6) 179 180 var c7: i64 = 0; if tot[4] < tot[2] { if tot[2] < tot[0] { c7 = 1 } } 181 total = total + 1; pass = pass + ng_assert("A7 total_emit black < dark < light", c7) 182 183 ng_puts("\nNIGHT-GRADE "); ng_putn(pass); ng_puts("/"); ng_putn(total); ng_puts(" assertions PASS\n") 184 if pass != total { return 9 } 185 ng_puts("NIGHT-GRADE-OK\n") 186 return 0 187}