nx_capres.nx source
↩ module page · 192 lines · 8518 B
1// nx_capres.nx -- CLI for the CAPTURE-RESOLUTION RULER (core = nx_capres_lib, gate = nx_capres_gate).
2// Operator standing order 2026-08-28: full resolution everywhere, and the cost is accepted.
3//
4// ONE QUESTION THIS ESTATE COULD NOT ANSWER BEFORE: "is this capture full resolution?" Every capture
5// organ announced w= and h=; not one said what FULL was, so a 240x150 frame and a 1920x1200 frame read
6// identically to every downstream consumer and to every reader of a verdict built on them.
7//
8// VERBS
9// nx_capres dims <artifact> what resolution IS this file (PNG or NXFH1)
10// nx_capres check <artifact> <subject> is it the subject's declared FULL resolution
11// nx_capres judge <artifact> <judge-organ> can that judge SEE this many pixels
12// nx_capres selftest KATs over the pure predicates
13//
14// EXIT CODES ARE THE VERDICT, one scale shared with the lib:
15// 0 FULL / JUDGE-SEES-ALL 1 REDUCED / UNJUDGED-AT-RESOLUTION 2 usage 3 UNPROVEN
16// UNPROVEN covers unreadable artifact, unknown subject and unknown judge. Abstaining is not acquitting:
17// a caller must never be able to read "I could not look" as "it is fine".
18//
19// The final line is always "verdict=<TOKEN>" so a reader can anchor BY POSITION rather than by
20// matching text that also appears in the diagnostics above it.
21// license_tier: ORIGINAL No hw writes (Rule 26).
22import "nx_syscalls.nx"
23import "nx_capres_lib.nx"
24
25const CX_OUT_BYTES: i64 = 64
26const CX_KEY_BYTES: i64 = 256
27const CX_USAGE: i64 = 2
28const CX_JUDGE_PREFIX: *u8 = "judge." as *u8
29const CX_KAT_TOTAL: i64 = 12
30
31func cx_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
32func cx_n(v: i64) -> i64 {
33 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
34 var m: i64 = v
35 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
36 let t: *u8 = sys_mmap(32)
37 var k: i64 = 0
38 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
39 let o: *u8 = sys_mmap(32)
40 var i: i64 = 0
41 while i < k { o[i] = t[k-1-i]; i = i + 1 }
42 sys_write(1, o, k)
43 return 0
44}
45func cx_streq(a: *u8, b: *u8) -> i64 {
46 var i: i64 = 0
47 while a[i] != (0 as u8) {
48 if a[i] != b[i] { return 0 }
49 i = i + 1
50 }
51 if b[i] != (0 as u8) { return 0 }
52 return 1
53}
54func cx_cat(d: *u8, o: i64, s: *u8) -> i64 {
55 var i: i64 = 0
56 var p: i64 = o
57 while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 }
58 d[p] = 0 as u8
59 return p
60}
61func cx_kind_name(k: i64) -> i64 {
62 if k == CR_KIND_PNG { cx_p("PNG" as *u8); return 0 }
63 if k == CR_KIND_NXFH1 { cx_p("NXFH1" as *u8); return 0 }
64 cx_p("UNKNOWN" as *u8)
65 return 0
66}
67func cx_usage() -> i64 {
68 cx_p("usage: nx_capres dims <artifact>\n" as *u8)
69 cx_p(" nx_capres check <artifact> <subject> 0 FULL / 1 REDUCED / 3 UNPROVEN\n" as *u8)
70 cx_p(" nx_capres judge <artifact> <judge-organ> 0 SEES-ALL / 1 UNJUDGED-AT-RESOLUTION / 3 UNPROVEN\n" as *u8)
71 cx_p(" nx_capres selftest\n" as *u8)
72 cx_p("subjects and judge ceilings are declared in knowledge/capres.conf -- never in this binary\n" as *u8)
73 return CX_USAGE
74}
75
76// KATs over the PURE predicates. They take numbers, not files, precisely so this cannot pass by
77// accident on a fixture that never reached the condition.
78func cx_selftest() -> i64 {
79 var pass: i64 = 0
80 // cr_permil: identical extents are exactly full
81 if cr_permil(1920, 1200, 1920, 1200) == CR_PERMIL { pass = pass + 1 }
82 // the measured world defect: 240x150 of 1920x1200 is 15 permil, not "a bit smaller"
83 if cr_permil(240, 150, 1920, 1200) == 15 { pass = pass + 1 }
84 // a zero denominator is UNPROVEN, never a pass
85 if cr_permil(100, 100, 0, 100) < 0 { pass = pass + 1 }
86 if cr_permil(0, 100, 100, 100) < 0 { pass = pass + 1 }
87 // cr_verdict maps the fraction onto the exit scale
88 if cr_verdict(CR_PERMIL) == CR_V_FULL { pass = pass + 1 }
89 if cr_verdict(CR_PERMIL - 1) == CR_V_REDUCED { pass = pass + 1 }
90 if cr_verdict(15) == CR_V_REDUCED { pass = pass + 1 }
91 if cr_verdict(0 - 1) == CR_V_UNPROVEN { pass = pass + 1 }
92 // a SUPERSET capture is still full: more pixels than declared is not a reduction
93 if cr_verdict(cr_permil(3840, 2400, 1920, 1200)) == CR_V_FULL { pass = pass + 1 }
94 // cr_judge: the measured nx_percept case -- a 400x240 judge handed a 1920x1200 frame is BLIND
95 if cr_judge(1920, 1200, 400, 240) == CR_J_BLIND { pass = pass + 1 }
96 if cr_judge(400, 240, 400, 240) == CR_J_SEES { pass = pass + 1 }
97 // one axis over the ceiling is enough to blind it -- the failure is not area, it is extent
98 if cr_judge(401, 240, 400, 240) == CR_J_BLIND { pass = pass + 1 }
99 cx_p("CAPRES-SELFTEST passed=" as *u8); cx_n(pass)
100 cx_p(" of=" as *u8); cx_n(CX_KAT_TOTAL); cx_p("\n" as *u8)
101 if pass == CX_KAT_TOTAL { cx_p("verdict=SELFTEST-GREEN\n" as *u8); return 0 }
102 cx_p("verdict=SELFTEST-RED\n" as *u8)
103 return 1
104}
105
106func main(argc: i64, argv: *i64) -> i64 {
107 if argc < 2 { return cx_usage() }
108 let verb: *u8 = argv[1] as *u8
109 if cx_streq(verb, "selftest" as *u8) == 1 { return cx_selftest() }
110 if argc < 3 { return cx_usage() }
111 let path: *u8 = argv[2] as *u8
112 let d: *i64 = sys_mmap(CX_OUT_BYTES) as *i64
113 let kind: i64 = cr_dims_of_file(path, d)
114 let cw: i64 = d[1]
115 let ch: i64 = d[2]
116
117 cx_p("CAPRES artifact=" as *u8); cx_p(path)
118 cx_p(" kind=" as *u8); cx_kind_name(kind)
119 cx_p(" w=" as *u8); cx_n(cw)
120 cx_p(" h=" as *u8); cx_n(ch)
121
122 if cx_streq(verb, "dims" as *u8) == 1 {
123 cx_p("\n" as *u8)
124 if kind == CR_KIND_UNKNOWN { cx_p("verdict=UNREADABLE\n" as *u8); return CR_V_UNPROVEN }
125 cx_p("verdict=DIMS-READ\n" as *u8)
126 return 0
127 }
128 if argc < 4 { cx_p("\n" as *u8); return cx_usage() }
129 let key: *u8 = argv[3] as *u8
130
131 // AN UNREADABLE ARTIFACT ENDS EVERY VERB THE SAME WAY. It is not a small capture and it is not a
132 // failing subject -- it is the absence of evidence, and the exit code says so.
133 if kind == CR_KIND_UNKNOWN {
134 cx_p(" subject=" as *u8); cx_p(key)
135 cx_p("\nverdict=UNREADABLE\n" as *u8)
136 return CR_V_UNPROVEN
137 }
138
139 if cx_streq(verb, "check" as *u8) == 1 {
140 let f: *i64 = sys_mmap(CX_OUT_BYTES) as *i64
141 let got: i64 = cr_conf_res(CR_CONF, key, f)
142 cx_p(" subject=" as *u8); cx_p(key)
143 if got == 0 {
144 cx_p(" declared=NONE\nverdict=UNKNOWN-SUBJECT\n" as *u8)
145 return CR_V_UNPROVEN
146 }
147 let permil: i64 = cr_permil(cw, ch, f[0], f[1])
148 let v: i64 = cr_verdict(permil)
149 cx_p(" full_w=" as *u8); cx_n(f[0])
150 cx_p(" full_h=" as *u8); cx_n(f[1])
151 cx_p(" res_permil=" as *u8); cx_n(permil)
152 cx_p("\n" as *u8)
153 if v == CR_V_FULL { cx_p("verdict=FULL\n" as *u8); return CR_V_FULL }
154 if v == CR_V_REDUCED {
155 cx_p("verdict=REDUCED\n" as *u8)
156 return CR_V_REDUCED
157 }
158 cx_p("verdict=UNPROVEN\n" as *u8)
159 return CR_V_UNPROVEN
160 }
161
162 if cx_streq(verb, "judge" as *u8) == 1 {
163 // the conf key for a judge ceiling is "judge.<organ>" -- one namespace, so a subject and a
164 // judge of the same name can never be confused for one another
165 let jk: *u8 = sys_mmap(CX_KEY_BYTES)
166 let e: i64 = cx_cat(jk, 0, CX_JUDGE_PREFIX)
167 cx_cat(jk, e, key)
168 let j: *i64 = sys_mmap(CX_OUT_BYTES) as *i64
169 let got: i64 = cr_conf_res(CR_CONF, jk, j)
170 cx_p(" judge=" as *u8); cx_p(key)
171 if got == 0 {
172 cx_p(" ceiling=NONE\nverdict=UNKNOWN-JUDGE\n" as *u8)
173 return CR_V_UNPROVEN
174 }
175 cx_p(" ceiling_w=" as *u8); cx_n(j[0])
176 cx_p(" ceiling_h=" as *u8); cx_n(j[1])
177 let jv: i64 = cr_judge(cw, ch, j[0], j[1])
178 cx_p("\n" as *u8)
179 if jv == CR_J_SEES { cx_p("verdict=JUDGE-SEES-ALL\n" as *u8); return CR_J_SEES }
180 if jv == CR_J_BLIND {
181 // NOT a low score. NO score. The judge cannot examine this many pixels, so whatever it
182 // prints is about a downsample, a crop or a prefix -- and reading that as a quality
183 // verdict is how a resolution ceiling gets mistaken for a quality ceiling.
184 cx_p("verdict=UNJUDGED-AT-RESOLUTION\n" as *u8)
185 return CR_J_BLIND
186 }
187 cx_p("verdict=UNPROVEN\n" as *u8)
188 return CR_V_UNPROVEN
189 }
190 cx_p("\n" as *u8)
191 return cx_usage()
192}