code wiki / _hdl_build / nx_site_quality_gate.nx
nx_site_quality_gate.nx source
↩ module page · 156 lines · 8336 B
1// nx_site_quality_gate.nx -- the STANDING site-quality gate (operator 2026-06-09: "easy for a
2// nielsen norman or other award winning ux cx benchmarking and ada and w3c compliant and all that
3// OVER AND OVER with simple management"). Composes the team's sourced rubric line (nx_ux_benchmark =
4// NN/g + WCAG 2.1 AA) into a RE-RUNNABLE mechanical gate over any HTML artifact: a DATA-DRIVEN
5// criteria table (law #11 -- the team EXPANDS quality by adding rows, never by editing logic),
6// permil score, per-criterion verdicts, durable log. Wire into the Conductor's loop so every site
7// edit re-gates automatically (hot content already swaps live; now quality re-checks ride along).
8// Rung-1 criteria = the mechanically-checkable WCAG/NN slice; contrast/keyboard-order need a DOM/CSS
9// rung (flagged, not faked). license_tier: ORIGINAL
10import "nx_syscalls.nx"
11func _p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func _pn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=48+(m%10);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 }
13func _fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
14func _fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=48+(m%10);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
15func sq_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
16func sq_read(path: *u8, buf: *u8, cap: i64) -> i64 {
17 let fd: i64 = sys_openat_rd(path)
18 if fd < 0 { return 0 - 1 }
19 var total: i64 = 0
20 var go: i64 = 1
21 while go == 1 {
22 let base: i64 = buf as i64
23 let n: i64 = sys_read(fd, (base + total) as *u8, cap - total)
24 if n <= 0 { go = 0 } else { total = total + n }
25 if total >= cap { go = 0 }
26 }
27 sys_close(fd)
28 return total
29}
30func sq_count(buf: *u8, n: i64, pat: *u8) -> i64 {
31 let pl: i64 = sq_slen(pat)
32 var cnt: i64 = 0
33 var i: i64 = 0
34 while i + pl <= n {
35 var k: i64 = 0
36 var hit: i64 = 1
37 while k < pl { if buf[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 } }
38 if hit == 1 { cnt = cnt + 1 }
39 i = i + 1
40 }
41 return cnt
42}
43// THE CRITERIA TABLE (data-driven: the team expands quality by ADDING ROWS here).
44// kind 1 = pattern must appear >= mincount; kind 2 = count(pat) must equal count(pat2) (pairing,
45// e.g. every <img needs alt=); kind 3 = pattern must appear AT MOST maxcount (anti-pattern).
46func sq_criterion(id: i64, buf: *u8, n: i64) -> i64 {
47 // WCAG 3.1.1 language of page
48 if id == 0 { if sq_count(buf, n, "<html lang=" as *u8) >= 1 { return 1 } return 0 }
49 // WCAG 2.4.2 page titled
50 if id == 1 { if sq_count(buf, n, "<title>" as *u8) >= 1 { return 1 } return 0 }
51 // mobile/responsive baseline (NN/g + WCAG 1.4.10 reflow)
52 if id == 2 { if sq_count(buf, n, "name=\"viewport\"" as *u8) >= 1 { return 1 } return 0 }
53 // WCAG 1.1.1 non-text content: every <img has an alt=
54 if id == 3 { if sq_count(buf, n, "<img" as *u8) == sq_count(buf, n, "alt=" as *u8) { return 1 } return 0 }
55 // WCAG 1.3.1 landmarks: nav + main + footer present
56 if id == 4 { if sq_count(buf, n, "<nav" as *u8) >= 1 { if sq_count(buf, n, "<main" as *u8) >= 1 { if sq_count(buf, n, "<footer" as *u8) >= 1 { return 1 } } } return 0 }
57 // NN/g visibility of structure: exactly one <h1
58 if id == 5 { if sq_count(buf, n, "<h1" as *u8) == 1 { return 1 } return 0 }
59 // WCAG 2.4.1 bypass blocks: skip link
60 if id == 6 { if sq_count(buf, n, "skip" as *u8) >= 1 { return 1 } return 0 }
61 // anti-pattern: inline event handlers (CSP/a11y smell) -- at most 0
62 if id == 7 { if sq_count(buf, n, "onclick=" as *u8) == 0 { return 1 } return 0 }
63 // WCAG 1.3.1/4.1.2 forms: every <input has a <label OR aria-label (both are valid techniques --
64 // criterion REFINED 2026-06-09 after a false FAIL on an aria-labelled search input)
65 if id == 8 { if sq_count(buf, n, "<input" as *u8) <= sq_count(buf, n, "<label" as *u8) + sq_count(buf, n, "aria-label=" as *u8) { return 1 } return 0 }
66 // NN/g recognition: charset declared (encoding errors = #1 trust killer)
67 if id == 9 { if sq_count(buf, n, "charset=" as *u8) >= 1 { return 1 } return 0 }
68 // POSITIONAL criteria (rung-2: placement conventions, operator 2026-06-09 "weirdly positioned
69 // things like the search bar in the middle of the page")
70 // NN/g convention: site search lives in the header region (offset(search) < offset(</header>))
71 if id == 10 {
72 let ps: i64 = sq_pos(buf, n, "role=\"search\"" as *u8)
73 if ps < 0 { return 1 }
74 let ph: i64 = sq_pos(buf, n, "</header>" as *u8)
75 if ph < 0 { return 0 }
76 if ps < ph { return 1 }
77 return 0
78 }
79 // heading hierarchy order: the h1 precedes the first h2
80 if id == 11 {
81 let p1: i64 = sq_pos(buf, n, "<h1" as *u8)
82 let p2: i64 = sq_pos(buf, n, "<h2" as *u8)
83 if p2 < 0 { return 1 }
84 if p1 < 0 { return 0 }
85 if p1 < p2 { return 1 }
86 return 0
87 }
88 // landmark order: main closes before the footer opens (content never trails the footer)
89 if id == 12 {
90 let pm: i64 = sq_pos(buf, n, "</main>" as *u8)
91 let pf: i64 = sq_pos(buf, n, "<footer" as *u8)
92 if pf < 0 { return 0 }
93 if pm < 0 { return 0 }
94 if pm < pf { return 1 }
95 return 0
96 }
97 return 0 - 1
98}
99func sq_pos(buf: *u8, n: i64, pat: *u8) -> i64 {
100 let pl: i64 = sq_slen(pat)
101 var i: i64 = 0
102 while i + pl <= n {
103 var k: i64 = 0
104 var hit: i64 = 1
105 while k < pl { if buf[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 } }
106 if hit == 1 { return i }
107 i = i + 1
108 }
109 return 0 - 1
110}
111func sq_name(id: i64) -> *u8 {
112 if id == 0 { return "wcag-3.1.1-lang" as *u8 }
113 if id == 1 { return "wcag-2.4.2-title" as *u8 }
114 if id == 2 { return "reflow-viewport" as *u8 }
115 if id == 3 { return "wcag-1.1.1-img-alt" as *u8 }
116 if id == 4 { return "wcag-1.3.1-landmarks" as *u8 }
117 if id == 5 { return "nng-single-h1" as *u8 }
118 if id == 6 { return "wcag-2.4.1-skip" as *u8 }
119 if id == 7 { return "no-inline-handlers" as *u8 }
120 if id == 8 { return "wcag-1.3.1-labels" as *u8 }
121 if id == 9 { return "charset-declared" as *u8 }
122 if id == 10 { return "nng-search-in-header" as *u8 }
123 if id == 11 { return "heading-order-h1-first" as *u8 }
124 return "main-before-footer" as *u8
125}
126func main(argc: i64, argv: *i64) -> i64 {
127 _p("=== SITE QUALITY GATE (NN/g + WCAG criteria table; re-runnable on ANY page) ===\n" as *u8)
128 var target: *u8 = "knowledge/andelinwest.html" as *u8
129 if argc >= 2 { target = argv[1] as *u8 }
130 _p(" target: " as *u8); _p(target); _p("\n" as *u8)
131 let buf: *u8 = sys_mmap(2097168)
132 let n: i64 = sq_read(target, buf, 2097152)
133 if n <= 0 { _p(" target artifact missing\n" as *u8); sys_exit(1); return 1 }
134 let lfd: i64 = sys_openat_append("knowledge/status/site_quality.log" as *u8, 0x1a4)
135 _fp(lfd, "SITEQ epoch=" as *u8); _fn(lfd, sys_now_realtime_sec())
136 _fp(lfd, " target=" as *u8); _fp(lfd, target)
137 _fp(lfd, " bytes=" as *u8); _fn(lfd, n); _fp(lfd, "\n" as *u8)
138 var passn: i64 = 0
139 var id: i64 = 0
140 while id < 13 {
141 let v: i64 = sq_criterion(id, buf, n)
142 _p(" " as *u8); _p(sq_name(id)); _p(" = " as *u8)
143 if v == 1 { _p("PASS\n" as *u8); passn = passn + 1 } else { _p("FAIL\n" as *u8) }
144 _fp(lfd, "CRIT name=" as *u8); _fp(lfd, sq_name(id))
145 _fp(lfd, " pass=" as *u8); _fn(lfd, v); _fp(lfd, "\n" as *u8)
146 id = id + 1
147 }
148 let pm: i64 = (passn * 1000) / 13
149 _p(" SITE-QUALITY score-permil=" as *u8); _pn(pm); _p(" (" as *u8); _pn(passn); _p("/13)\n" as *u8)
150 _fp(lfd, "SITEQ-SCORE permil=" as *u8); _fn(lfd, pm); _fp(lfd, "\n" as *u8)
151 sys_close(lfd)
152 _p(" durable: knowledge/status/site_quality.log -- expand quality by ADDING TABLE ROWS\n" as *u8)
153 if passn >= 12 { sys_exit(0); return 0 }
154 sys_exit(1)
155 return 1
156}