nx_phototwin_gate.nx source
↩ module page · 322 lines · 18087 B
1// nx_phototwin_gate.nx -- THE GATE FOR THE PHOTOGRAPH-TO-SUBSTRATE TWIN (nx_phototwin forked for real), 2026-08-24.
2//
3// FIXTURES ARE ASSEMBLED AT RUNTIME in /tmp/nx_phototwin_gate/: a 64x64 P6 PPM (a lossless container, so what the
4// decoder returns IS what was written -- a tooth proves it) holding a grey ramp plus the pure sRGB primaries and
5// secondaries, and a NARROW matrix/TRC ICC profile DERIVED from the mirrored sRGB2014.icc by pulling each primary
6// halfway toward the white point (rXYZ' = rXYZ/2 + wtpt/6, so the three still sum to the white point -- the ICC
7// structural invariant -- and nothing is typed in). The image is read through the sRGB profile in every run; the
8// SUBSTRATE varies: sRGB itself = positive control (inside by construction: out_permil=0, moved=0), the narrow
9// profile = the primaries are OUTSIDE and the proof must move them. That pair is the bite. The first version of this
10// gate handed ONE profile to both roles and its narrow control was VACUOUS (measured 2026-08-24, out=0 on both).
11// The wash ledger fixtures cover OK / FAIL / PARTIAL / EMPTY, and bench refuses partial coverage.
12// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
13import "nx_syscalls.nx"
14import "nx_gate_verdict.nx"
15import "nx_tool_run.nx"
16import "nx_colorsci_lib.nx"
17import "nx_img_to_rgb.nx"
18
19const PG_SUBJECT_DEFAULT: *u8 = "nx_phototwin.elf"
20const PG_SRGB: *u8 = "knowledge/fetched/cmp_phototwin_srgb2014.b64"
21const PG_CONF: *u8 = "knowledge/colorsci.conf"
22const PG_DIR: *u8 = "/tmp/nx_phototwin_gate"
23const PG_OUT: *u8 = "/tmp/nx_phototwin_gate/out"
24const PG_OUT_CTRL: *u8 = "/tmp/nx_phototwin_gate/outctrl"
25const PG_IMG: *u8 = "/tmp/nx_phototwin_gate/fx.ppm"
26const PG_NARROW: *u8 = "/tmp/nx_phototwin_gate/narrow.icc"
27const PG_TWIN: *u8 = "/tmp/nx_phototwin_gate/out/twin.png"
28const PG_HEAT: *u8 = "/tmp/nx_phototwin_gate/out/heat.png"
29const PG_PROOF: *u8 = "/tmp/nx_phototwin_gate/out/proof.txt"
30const PG_LEDGER1: *u8 = "/tmp/nx_phototwin_gate/wash1.tsv"
31const PG_LEDGER2: *u8 = "/tmp/nx_phototwin_gate/wash2.tsv"
32const PG_MODE_DIR: i64 = 493
33const PG_MODE_0644: i64 = 420
34const PG_CAPTURE_CAP: i64 = 262144
35const PG_ARGV_SLOTS: i64 = 10
36const PG_SLOT: i64 = 8
37const PG_W: i64 = 64
38const PG_H: i64 = 64
39const PG_HALF: i64 = 32
40const PG_CHANNELS: i64 = 3
41const PG_CODE_MAX: i64 = 255
42const PG_BLOCKS: i64 = 6
43const PG_GREEN_X: i64 = 16 // inside block 1 (x in 10..21) of the six saturated blocks
44const PG_GREEN_Y: i64 = 48 // inside the bottom half
45const PG_PPM_HDR: *u8 = "P6\n64 64\n255\n"
46const PG_EXIT_OK: i64 = 0
47const PG_EXIT_REFUSED: i64 = 1
48const PG_EXIT_UNOBS: i64 = 3
49const PG_ICC_HDR: i64 = 128
50const PG_ICC_TAGS: i64 = 7
51const PG_ICC_ENTRY: i64 = 12
52const PG_ICC_XYZ_TAG: i64 = 20
53const PG_ICC_CURV_TAG: i64 = 12
54const PG_ICC_MAGIC_OFF: i64 = 36
55const PG_S15_SCALE: i64 = 16384
56const PG_SHRINK_DIV: i64 = 2 // primaries pulled halfway toward white
57const PG_WHITE_DIV: i64 = 6 // white/6 per primary keeps the three summing to white
58const PG_BYTE_MAX: i64 = 255
59const PG_ASCII_ZERO: i64 = 48
60const PG_ASCII_NINE: i64 = 57
61const PG_DECIMAL: i64 = 10
62
63func pg_w4(b: *u8, off: i64, v: i64) -> i64 {
64 b[off] = ((v >> 24) & PG_BYTE_MAX) as u8
65 b[off + 1] = ((v >> 16) & PG_BYTE_MAX) as u8
66 b[off + 2] = ((v >> 8) & PG_BYTE_MAX) as u8
67 b[off + 3] = (v & PG_BYTE_MAX) as u8
68 return 0
69}
70func pg_tag4(b: *u8, off: i64, t: *u8) -> i64 { b[off] = t[0]; b[off + 1] = t[1]; b[off + 2] = t[2]; b[off + 3] = t[3]; return 0 }
71func pg_write_bytes(path: *u8, b: *u8, n: i64) -> i64 {
72 let fd: i64 = sys_openat_wr(path, PG_MODE_0644)
73 if fd < 0 { return 0 - 1 }
74 let wr: i64 = sys_write(fd, b, n)
75 sys_close(fd)
76 if wr != n { return 0 - 1 }
77 return n
78}
79func pg_write_text(path: *u8, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return pg_write_bytes(path, s, n) }
80// a matrix/TRC ICC with identity TRCs whose primaries are the given Q30 columns (rX gX bX rY gY bY rZ gZ bZ) and white
81func pg_write_icc(path: *u8, m: *i64, w: *i64) -> i64 {
82 let tagdata: i64 = PG_ICC_HDR + 4 + PG_ICC_TAGS * PG_ICC_ENTRY
83 let total: i64 = tagdata + 4 * PG_ICC_XYZ_TAG + 3 * PG_ICC_CURV_TAG
84 let b: *u8 = sys_mmap(total)
85 var i: i64 = 0
86 while i < total { b[i] = 0 as u8; i = i + 1 }
87 pg_w4(b, 0, total)
88 pg_tag4(b, PG_ICC_MAGIC_OFF, "acsp" as *u8)
89 pg_w4(b, PG_ICC_HDR, PG_ICC_TAGS)
90 var e: i64 = PG_ICC_HDR + 4
91 var d: i64 = tagdata
92 var c: i64 = 0
93 while c < 4 {
94 var sig: *u8 = "rXYZ" as *u8
95 if c == 1 { sig = "gXYZ" as *u8 }
96 if c == 2 { sig = "bXYZ" as *u8 }
97 if c == 3 { sig = "wtpt" as *u8 }
98 pg_tag4(b, e, sig); pg_w4(b, e + 4, d); pg_w4(b, e + 8, PG_ICC_XYZ_TAG)
99 pg_tag4(b, d, "XYZ " as *u8)
100 var x: i64 = 0
101 var y: i64 = 0
102 var z: i64 = 0
103 if c < 3 { x = m[c]; y = m[3 + c]; z = m[6 + c] } else { x = w[0]; y = w[1]; z = w[2] }
104 pg_w4(b, d + 8, x / PG_S15_SCALE)
105 pg_w4(b, d + 12, y / PG_S15_SCALE)
106 pg_w4(b, d + 16, z / PG_S15_SCALE)
107 e = e + PG_ICC_ENTRY
108 d = d + PG_ICC_XYZ_TAG
109 c = c + 1
110 }
111 c = 0
112 while c < 3 {
113 var sig2: *u8 = "rTRC" as *u8
114 if c == 1 { sig2 = "gTRC" as *u8 }
115 if c == 2 { sig2 = "bTRC" as *u8 }
116 pg_tag4(b, e, sig2); pg_w4(b, e + 4, d); pg_w4(b, e + 8, PG_ICC_CURV_TAG)
117 pg_tag4(b, d, "curv" as *u8)
118 pg_w4(b, d + 8, 0)
119 e = e + PG_ICC_ENTRY
120 d = d + PG_ICC_CURV_TAG
121 c = c + 1
122 }
123 return pg_write_bytes(path, b, total)
124}
125// the fixture image as P6: top half a grey ramp, bottom half six saturated blocks (R G B C M Y)
126func pg_write_image(path: *u8) -> i64 {
127 var hl: i64 = 0
128 while PG_PPM_HDR[hl] != (0 as u8) { hl = hl + 1 }
129 let total: i64 = hl + PG_W * PG_H * PG_CHANNELS
130 let buf: *u8 = sys_mmap(total)
131 var i: i64 = 0
132 while i < hl { buf[i] = PG_PPM_HDR[i]; i = i + 1 }
133 var y: i64 = 0
134 while y < PG_H {
135 var x: i64 = 0
136 while x < PG_W {
137 let o: i64 = hl + (y * PG_W + x) * PG_CHANNELS
138 if y < PG_HALF {
139 let g: i64 = (x * PG_CODE_MAX) / (PG_W - 1)
140 buf[o] = g as u8; buf[o + 1] = g as u8; buf[o + 2] = g as u8
141 } else {
142 let blk: i64 = (x * PG_BLOCKS) / PG_W
143 var r: i64 = 0
144 var g2: i64 = 0
145 var b: i64 = 0
146 if blk == 0 { r = PG_CODE_MAX }
147 if blk == 1 { g2 = PG_CODE_MAX }
148 if blk == 2 { b = PG_CODE_MAX }
149 if blk == 3 { g2 = PG_CODE_MAX; b = PG_CODE_MAX }
150 if blk == 4 { r = PG_CODE_MAX; b = PG_CODE_MAX }
151 if blk == 5 { r = PG_CODE_MAX; g2 = PG_CODE_MAX }
152 buf[o] = r as u8; buf[o + 1] = g2 as u8; buf[o + 2] = b as u8
153 }
154 x = x + 1
155 }
156 y = y + 1
157 }
158 return pg_write_bytes(path, buf, total)
159}
160func pg_run(subject: *u8, a1: *u8, a2: *u8, a3: *u8, a4: *u8, a5: *u8, a6: *u8, out: *u8, outlen: *i64) -> i64 {
161 let av: *i64 = sys_mmap(PG_SLOT * PG_ARGV_SLOTS) as *i64
162 av[0] = subject as i64
163 av[1] = a1 as i64
164 av[2] = a2 as i64
165 av[3] = a3 as i64
166 av[4] = a4 as i64
167 av[5] = a5 as i64
168 av[6] = a6 as i64
169 av[7] = 0
170 return tr_run_capture(subject, av, out, PG_CAPTURE_CAP, outlen)
171}
172// the integer after `key` in buf (first occurrence), or -1
173func pg_num_after(buf: *u8, n: i64, key: *u8) -> i64 {
174 var kl: i64 = 0
175 while key[kl] != (0 as u8) { kl = kl + 1 }
176 var i: i64 = 0
177 while i + kl <= n {
178 var same: i64 = 1
179 var j: i64 = 0
180 while j < kl { if buf[i + j] != key[j] { same = 0; j = kl } j = j + 1 }
181 if same == 1 {
182 var p: i64 = i + kl
183 var v: i64 = 0
184 var digits: i64 = 0
185 var go: i64 = 1
186 while go == 1 {
187 if p >= n { go = 0 } else {
188 let c: i64 = buf[p] as i64
189 if c < PG_ASCII_ZERO { go = 0 }
190 if c > PG_ASCII_NINE { go = 0 }
191 if go == 1 { v = v * PG_DECIMAL + (c - PG_ASCII_ZERO); digits = digits + 1; p = p + 1 }
192 }
193 }
194 if digits > 0 { return v }
195 return 0 - 1
196 }
197 i = i + 1
198 }
199 return 0 - 1
200}
201func pg_decodes(path: *u8, w: i64, h: i64) -> i64 {
202 let wh: *i64 = sys_mmap(PG_SLOT * 2) as *i64
203 wh[0] = 0
204 wh[1] = 0
205 let p: *u8 = nx_img_to_rgb(path, wh)
206 if (p as i64) == 0 { return 0 }
207 if wh[0] != w { return 0 }
208 if wh[1] != h { return 0 }
209 return 1
210}
211// the decoded fixture must return EXACTLY the bytes written (pure green at the green block)
212func pg_fixture_lossless(path: *u8) -> i64 {
213 let wh: *i64 = sys_mmap(PG_SLOT * 2) as *i64
214 wh[0] = 0
215 wh[1] = 0
216 let p: *u8 = nx_img_to_rgb(path, wh)
217 if (p as i64) == 0 { return 0 }
218 if wh[0] != PG_W { return 0 }
219 let o: i64 = (PG_GREEN_Y * PG_W + PG_GREEN_X) * PG_CHANNELS
220 if (p[o] as i64) != 0 { return 0 }
221 if (p[o + 1] as i64) != PG_CODE_MAX { return 0 }
222 if (p[o + 2] as i64) != 0 { return 0 }
223 return 1
224}
225
226func main(argc: i64, argv: *i64) -> i64 {
227 let ctr: *i64 = gv_ctr()
228 gv_head("nx_phototwin gate -- gamut report, chroma-clipped twin, dE00 proof and wash ledger, bite-proven against a derived narrow substrate" as *u8)
229 var subject: *u8 = PG_SUBJECT_DEFAULT
230 if argc >= 2 { subject = argv[1] as *u8 }
231 gv_puts(" subject: " as *u8); gv_puts(subject); gv_puts("\n\n" as *u8)
232 sys_mkdir(PG_DIR, PG_MODE_DIR)
233 sys_mkdir(PG_OUT, PG_MODE_DIR)
234 sys_mkdir(PG_OUT_CTRL, PG_MODE_DIR)
235 sys_unlinkat(PG_TWIN)
236 sys_unlinkat(PG_HEAT)
237 sys_unlinkat(PG_PROOF)
238 let cs: *i64 = cs_ctx()
239 let srgb: *i64 = cs_icc_load(cs, PG_SRGB)
240 let have_srgb: i64 = gv_need("mirrored sRGB2014 profile parses (knowledge/fetched, base64 transport)" as *u8, srgb[CS_P_OK], ctr)
241 let conf_ok: i64 = (cs_conf_int(PG_CONF, "soft_proof_max_tol_de00_micro" as *u8) != CS_CONF_MISS) as i64
242 let have_conf: i64 = gv_need("knowledge/colorsci.conf present" as *u8, conf_ok, ctr)
243 if have_srgb == 0 { return gv_verdict("phototwin" as *u8, ctr, "" as *u8) }
244 if have_conf == 0 { return gv_verdict("phototwin" as *u8, ctr, "" as *u8) }
245 let wi: i64 = pg_write_image(PG_IMG)
246 gv_check("setup-fixture-image-written-and-decodes-64x64" as *u8, (pg_decodes(PG_IMG, PG_W, PG_H) == 1) as i64, ctr)
247 gv_check("setup-fixture-decodes-losslessly (pure green block reads 0,255,0)" as *u8, pg_fixture_lossless(PG_IMG), ctr)
248 let nm: *i64 = sys_mmap(PG_SLOT * CS_MAT_N) as *i64
249 var k: i64 = 0
250 while k < CS_MAT_N {
251 let row: i64 = k / 3
252 nm[k] = srgb[CS_P_MAT + k] / PG_SHRINK_DIV + srgb[CS_P_WTPT + row] / PG_WHITE_DIV
253 k = k + 1
254 }
255 let wt: *i64 = sys_mmap(PG_SLOT * 3) as *i64
256 wt[0] = srgb[CS_P_WTPT]; wt[1] = srgb[CS_P_WTPT + 1]; wt[2] = srgb[CS_P_WTPT + 2]
257 let wicc: i64 = pg_write_icc(PG_NARROW, nm, wt)
258 let narrow: *i64 = cs_icc_load(cs, PG_NARROW)
259 gv_check("setup-derived-narrow-profile-parses-through-the-same-reader" as *u8, narrow[CS_P_OK], ctr)
260 gv_check("setup-fixture-reached-the-condition (narrow red primary has less X than sRGB red)" as *u8, (narrow[CS_P_MAT] < srgb[CS_P_MAT]) as i64, ctr)
261 gv_check("setup-fixture-outputs-absent-before-measuring (gate is idempotent)" as *u8, (pg_decodes(PG_TWIN, PG_W, PG_H) == 0) as i64, ctr)
262
263 let cap: *u8 = sys_mmap(PG_CAPTURE_CAP)
264 let olen: *i64 = sys_mmap(PG_SLOT * 2) as *i64
265 // ---- report: positive control (image sRGB, substrate sRGB) and the narrow substrate ----
266 let rc_rs: i64 = pg_run(subject, "report" as *u8, PG_IMG, PG_SRGB, PG_SRGB, 0 as *u8, 0 as *u8, cap, olen)
267 gv_puts(" [report sRGB->sRGB] rc=" as *u8); gv_num(rc_rs); gv_puts("\n" as *u8); sys_write(1, cap, olen[0])
268 let out_s: i64 = pg_num_after(cap, olen[0], "outside=" as *u8)
269 gv_check("report-control-exits-0-and-partition-sums" as *u8, ((rc_rs == PG_EXIT_OK) as i64) * tr_contains(cap, olen[0], "partition=SUMS" as *u8), ctr)
270 gv_check("positive-control-an-sRGB-image-is-inside-the-sRGB-gamut (outside=0, exact matrix test)" as *u8, (out_s == 0) as i64, ctr)
271 let rc_rn: i64 = pg_run(subject, "report" as *u8, PG_IMG, PG_SRGB, PG_NARROW, 0 as *u8, 0 as *u8, cap, olen)
272 gv_puts(" [report sRGB->narrow] rc=" as *u8); gv_num(rc_rn); gv_puts("\n" as *u8); sys_write(1, cap, olen[0])
273 let out_n: i64 = pg_num_after(cap, olen[0], "outside=" as *u8)
274 let pix_n: i64 = pg_num_after(cap, olen[0], "pixels=" as *u8)
275 gv_check("report-against-the-narrow-substrate-finds-outside-pixels" as *u8, ((rc_rn == PG_EXIT_OK) as i64) * ((out_n > 0) as i64), ctr)
276 gv_check("report-pixels-equal-the-fixture (64x64)" as *u8, (pix_n == PG_W * PG_H) as i64, ctr)
277 // the fixture is top-half grey ramp, bottom-half saturated blocks: with the narrow substrate EVERY saturated pixel is
278 // outside (2048) and every grey is inside, so "greys inside" is exactly outside <= the saturated half -- `<` was an
279 // off-by-one against the fixture's own geometry (measured 2026-08-24: 2048 of 4096 read FAIL on a correct subject)
280 gv_check("report-narrow-keeps-the-grey-ramp-inside (outside <= the saturated half of the fixture)" as *u8, (out_n <= (PG_W * PG_H) / 2) as i64, ctr)
281 gv_bite("neg-control-gamut-report-fires-on-narrow-silent-on-own-profile" as *u8, (out_n > 0) as i64, (out_s != 0) as i64, ctr)
282 // ---- proof against the narrow substrate ----
283 let rc_pn: i64 = pg_run(subject, "proof" as *u8, PG_IMG, PG_SRGB, PG_NARROW, PG_OUT, 0 as *u8, cap, olen)
284 gv_puts(" [proof sRGB->narrow] rc=" as *u8); gv_num(rc_pn); gv_puts("\n" as *u8); sys_write(1, cap, olen[0])
285 var rc_ok: i64 = 0
286 if rc_pn == PG_EXIT_OK { rc_ok = 1 }
287 if rc_pn == PG_EXIT_REFUSED { rc_ok = 1 }
288 gv_check("proof-exits-OK-or-REFUSED-never-UNOBSERVABLE-on-a-decodable-fixture" as *u8, rc_ok, ctr)
289 gv_check("proof-writes-twin.png-that-decodes-64x64" as *u8, pg_decodes(PG_TWIN, PG_W, PG_H), ctr)
290 gv_check("proof-writes-heat.png-that-decodes-64x64" as *u8, pg_decodes(PG_HEAT, PG_W, PG_H), ctr)
291 let moved: i64 = pg_num_after(cap, olen[0], "moved=" as *u8)
292 let mean: i64 = pg_num_after(cap, olen[0], "mean_de00_micro=" as *u8)
293 let mx: i64 = pg_num_after(cap, olen[0], "max_de00_micro=" as *u8)
294 gv_check("proof-moved-exactly-the-outside-pixels" as *u8, (moved == out_n) as i64, ctr)
295 gv_check("proof-stats-consistent (max >= mean > 0)" as *u8, ((mx >= mean) as i64) * ((mean > 0) as i64), ctr)
296 gv_check("proof.txt-carries-a-canonical-verdict-line" as *u8, tr_contains(cap, olen[0], "\nverdict=PROOF-" as *u8), ctr)
297 // ---- proof control: sRGB image against its own profile moves nothing and says CONTROL ----
298 let rc_pc: i64 = pg_run(subject, "proof" as *u8, PG_IMG, PG_SRGB, PG_SRGB, PG_OUT_CTRL, 0 as *u8, cap, olen)
299 gv_puts(" [proof control] rc=" as *u8); gv_num(rc_pc); gv_puts("\n" as *u8); sys_write(1, cap, olen[0])
300 gv_check("control-proof-is-PROOF-OK-with-moved=0-and-labelled-CONTROL" as *u8, ((rc_pc == PG_EXIT_OK) as i64) * tr_contains(cap, olen[0], " moved=0 " as *u8) * tr_contains(cap, olen[0], "substrate=CONTROL" as *u8), ctr)
301
302 // ---- wash ledger ----
303 pg_write_text(PG_LEDGER1, "# fixture\ns1\tA\tblank\tline\t0\t50.0\t10.0\t10.0\ns1\tA\tblank\tline\t5\t50.5\t10.2\t10.1\ns2\tB\tblank\tline\t0\t50.0\t10.0\t10.0\ns2\tB\tblank\tline\t5\t60.0\t30.0\t-10.0\ns3\tC\tblank\tline\t0\t50.0\t10.0\t10.0\n" as *u8)
304 pg_write_text(PG_LEDGER2, "s1\tA\tblank\tline\t0\t50.0\t10.0\t10.0\ns1\tA\tblank\tline\t5\t50.5\t10.2\t10.1\ns2\tB\tblank\tline\t0\t50.0\t10.0\t10.0\ns2\tB\tblank\tline\t5\t60.0\t30.0\t-10.0\n" as *u8)
305 let rc_wa: i64 = pg_run(subject, "wash" as *u8, PG_LEDGER1, "A" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, cap, olen)
306 gv_puts(" [wash A] rc=" as *u8); gv_num(rc_wa); gv_puts("\n" as *u8); sys_write(1, cap, olen[0])
307 gv_check("wash-small-shift-is-WASH-OK (exit 0)" as *u8, ((rc_wa == PG_EXIT_OK) as i64) * tr_contains(cap, olen[0], "verdict=WASH-OK" as *u8), ctr)
308 let rc_wb: i64 = pg_run(subject, "wash" as *u8, PG_LEDGER1, "B" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, cap, olen)
309 gv_puts(" [wash B] rc=" as *u8); gv_num(rc_wb); gv_puts("\n" as *u8); sys_write(1, cap, olen[0])
310 gv_check("wash-large-shift-is-WASH-FAIL (exit 1)" as *u8, ((rc_wb == PG_EXIT_REFUSED) as i64) * tr_contains(cap, olen[0], "verdict=WASH-FAIL" as *u8), ctr)
311 gv_bite("neg-control-wash-fires-on-faded-swatch-silent-on-stable-swatch" as *u8, (rc_wb == PG_EXIT_REFUSED) as i64, (rc_wa != PG_EXIT_OK) as i64, ctr)
312 let rc_wc: i64 = pg_run(subject, "wash" as *u8, PG_LEDGER1, "C" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, cap, olen)
313 gv_check("wash-swatch-with-only-cycle-0-is-UNMEASURED-PARTIAL (exit 3, never a pass)" as *u8, ((rc_wc == PG_EXIT_UNOBS) as i64) * tr_contains(cap, olen[0], "UNMEASURED-PARTIAL" as *u8), ctr)
314 let rc_wd: i64 = pg_run(subject, "wash" as *u8, PG_LEDGER1, "D" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, cap, olen)
315 gv_check("wash-sku-with-no-rows-is-UNMEASURED (exit 3)" as *u8, ((rc_wd == PG_EXIT_UNOBS) as i64) * tr_contains(cap, olen[0], "verdict=UNMEASURED" as *u8), ctr)
316 let rc_b1: i64 = pg_run(subject, "bench" as *u8, PG_LEDGER1, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, cap, olen)
317 gv_check("bench-refuses-partial-coverage (exit 3 while one swatch lacks a later cycle)" as *u8, (rc_b1 == PG_EXIT_UNOBS) as i64, ctr)
318 let rc_b2: i64 = pg_run(subject, "bench" as *u8, PG_LEDGER2, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, cap, olen)
319 gv_check("bench-with-full-coverage-reports-the-failing-swatch (exit 1)" as *u8, ((rc_b2 == PG_EXIT_REFUSED) as i64) * tr_contains(cap, olen[0], "failed=1" as *u8), ctr)
320
321 return gv_verdict("phototwin" as *u8, ctr, "report partitions sum, the derived narrow substrate fires and the own profile is silent, the twin and heat decode, the wash ledger refuses partial coverage" as *u8)
322}