code wiki / (root) / nx_uxcx_grade.nx

nx_uxcx_grade.nx source

↩ module page · 156 lines · 5748 B

1// nx_uxcx_grade.nx -- sovereign UX/CX grader core (substrate-native). 2// 3// Byte-scan detectors for the two operator-reported bug classes plus key 4// structural checks. No third-party, no Python: pure *u8 scanning over the 5// artifact bytes (read via sys_read_file by a caller, or embedded fixtures 6// by the gate nx_uxcx_grade_test.nx). The Python nishilib.uxcx grader is the 7// cross-check BENCHMARK; this is the sovereign engine. 8// 9// Every check returns 1 = good/clean, 0 = bad/bug-present. 10// 11// genealogy_id: nishi_library_uxcx_sovereign_2026_06_30 12// lineage_id: uxcx_grader_core 13 14// strlen for a null-terminated literal. 15func uxg_len(s: *u8) -> i64 { 16 var n: i64 = 0 17 while s[n] != 0 { n = n + 1 } 18 return n 19} 20 21// Naive substring search: 1 if needle occurs in haystack, else 0. 22func uxg_has(hay: *u8, hay_n: i64, needle: *u8, n_n: i64) -> i64 { 23 if n_n == 0 { return 1 } 24 if hay_n < n_n { return 0 } 25 let last: i64 = hay_n - n_n 26 var i: i64 = 0 27 while i <= last { 28 var j: i64 = 0 29 var st: i64 = 0 30 while st == 0 { 31 if j >= n_n { st = 2 } 32 if st == 0 { 33 if hay[i + j] != needle[j] { st = 1 } 34 if st == 0 { j = j + 1 } 35 } 36 } 37 if st == 2 { return 1 } 38 i = i + 1 39 } 40 return 0 41} 42 43// Convenience: search for a null-terminated literal. 44func uxg_has_lit(hay: *u8, hay_n: i64, needle: *u8) -> i64 { 45 return uxg_has(hay, hay_n, needle, uxg_len(needle)) 46} 47 48// CHECK escaping integrity: clean(1) unless a DOUBLE-encoded entity is 49// present (the literal-"&amp;" bug as the reader would see it). 50func uxg_escaping_ok(html: *u8, n: i64) -> i64 { 51 if uxg_has_lit(html, n, "&amp;amp;" as *u8) == 1 { return 0 } 52 if uxg_has_lit(html, n, "&amp;lt;" as *u8) == 1 { return 0 } 53 if uxg_has_lit(html, n, "&amp;gt;" as *u8) == 1 { return 0 } 54 if uxg_has_lit(html, n, "&amp;quot;" as *u8) == 1 { return 0 } 55 if uxg_has_lit(html, n, "&amp;#" as *u8) == 1 { return 0 } 56 return 1 57} 58 59// CHECK back navigation: ok(1) unless a back control is wired inline straight 60// to history.back() AND there is no in-app fallback (goBack / userNavigated / 61// lastListHash). Distinguishes the buggy inline arrow wiring from the fixed 62// named-handler form. 63func uxg_back_ok(js: *u8, n: i64) -> i64 { 64 if uxg_has_lit(js, n, "=> history.back()" as *u8) == 0 { return 1 } 65 if uxg_has_lit(js, n, "lastListHash" as *u8) == 1 { return 1 } 66 if uxg_has_lit(js, n, "userNavigated" as *u8) == 1 { return 1 } 67 if uxg_has_lit(js, n, "goBack" as *u8) == 1 { return 1 } 68 return 0 69} 70 71// CHECK mobile viewport: width=device-width present. 72func uxg_viewport_ok(html: *u8, n: i64) -> i64 { 73 return uxg_has_lit(html, n, "width=device-width" as *u8) 74} 75 76// CHECK skip-to-content link present. 77func uxg_skiplink_ok(html: *u8, n: i64) -> i64 { 78 return uxg_has_lit(html, n, "skip-link" as *u8) 79} 80 81// Combined permil over the four checks (250 each), given the artifact bytes 82// classified as page(html)+js. Mirrors the Python grader's permil flavour. 83func uxg_permil(html: *u8, hn: i64, js: *u8, jn: i64) -> i64 { 84 var p: i64 = 0 85 if uxg_escaping_ok(html, hn) == 1 { p = p + 250 } 86 if uxg_viewport_ok(html, hn) == 1 { p = p + 250 } 87 if uxg_skiplink_ok(html, hn) == 1 { p = p + 250 } 88 if uxg_back_ok(js, jn) == 1 { p = p + 250 } 89 return p 90} 91 92// ---- additional byte-scannable checks (page) ---- 93 94// <html lang="..."> declared. 95func uxg_lang_ok(html: *u8, n: i64) -> i64 { 96 return uxg_has_lit(html, n, "lang=\"" as *u8) 97} 98 99// non-empty <title>. 100func uxg_title_ok(html: *u8, n: i64) -> i64 { 101 return uxg_has_lit(html, n, "<title>" as *u8) 102} 103 104// a <nav> landmark. 105func uxg_nav_ok(html: *u8, n: i64) -> i64 { 106 return uxg_has_lit(html, n, "<nav" as *u8) 107} 108 109// sovereignty: no externally-loaded asset (src="http...). Content <a href> 110// links are not flagged (only src= asset loads). 111func uxg_sovereign_ok(html: *u8, n: i64) -> i64 { 112 if uxg_has_lit(html, n, "src=\"http" as *u8) == 1 { return 0 } 113 return 1 114} 115 116// ---- additional byte-scannable checks (spa js) ---- 117 118// async views set a loading placeholder. 119func uxg_loading_ok(js: *u8, n: i64) -> i64 { 120 if uxg_has_lit(js, n, "loading" as *u8) == 1 { return 1 } 121 if uxg_has_lit(js, n, "searching" as *u8) == 1 { return 1 } 122 return 0 123} 124 125// failures are caught AND surfaced. 126func uxg_error_ok(js: *u8, n: i64) -> i64 { 127 if uxg_has_lit(js, n, "catch" as *u8) == 0 { return 0 } 128 if uxg_has_lit(js, n, "empty" as *u8) == 1 { return 1 } 129 if uxg_has_lit(js, n, "failed" as *u8) == 1 { return 1 } 130 if uxg_has_lit(js, n, "error" as *u8) == 1 { return 1 } 131 return 0 132} 133 134// empty result sets are explained. 135func uxg_empty_ok(js: *u8, n: i64) -> i64 { 136 if uxg_has_lit(js, n, "no matches" as *u8) == 1 { return 1 } 137 if uxg_has_lit(js, n, "empty" as *u8) == 1 { return 1 } 138 return 0 139} 140 141// Full grade: permil over all 11 checks (7 page + 4 js), evenly weighted. 142func uxg_grade_full(page: *u8, pn: i64, js: *u8, jn: i64) -> i64 { 143 var pass: i64 = 0 144 if uxg_escaping_ok(page, pn) == 1 { pass = pass + 1 } 145 if uxg_viewport_ok(page, pn) == 1 { pass = pass + 1 } 146 if uxg_skiplink_ok(page, pn) == 1 { pass = pass + 1 } 147 if uxg_lang_ok(page, pn) == 1 { pass = pass + 1 } 148 if uxg_title_ok(page, pn) == 1 { pass = pass + 1 } 149 if uxg_nav_ok(page, pn) == 1 { pass = pass + 1 } 150 if uxg_sovereign_ok(page, pn) == 1 { pass = pass + 1 } 151 if uxg_back_ok(js, jn) == 1 { pass = pass + 1 } 152 if uxg_loading_ok(js, jn) == 1 { pass = pass + 1 } 153 if uxg_error_ok(js, jn) == 1 { pass = pass + 1 } 154 if uxg_empty_ok(js, jn) == 1 { pass = pass + 1 } 155 return (pass * 1000) / 11 156}