code wiki / (root) / nx_png_real_smoke.nx

nx_png_real_smoke.nx source

↩ module page · 235 lines · 8842 B

1// nx_png_real_smoke.nx -- end-to-end PNG decode verification. 2// 3// CAPABILITY_COMPLETENESS: FULL 4// 5// Constructs a valid 1x1 RGB PNG byte-for-byte at runtime 6// (computing chunk CRC32s and zlib Adler-32 via the shipped 7// substrate primitives), then decodes it via nx_png_decode + the 8// full v0 grader pipeline, asserting: 9// - decoder produces (1, 1) RGB pixel matching the source 10// - grader returns OK + correctly-classed verdict 11// 12// This is the smoke the user explicitly asked for: the bridge 13// from "compile-clean" to "actually works against a real PNG 14// file." No external file needed; the smoke is fully 15// self-contained. 16// 17// genealogy_id: substrate_png_e2e_verification_2026_05_16 18// lineage_id: nx_png_real_smoke_v1 19 20// nx_safety_envelope: 21// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 22// sil_target: SIL1 23// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 24// verdict: NOT_YET_EVALUATED 25 26import "nx_syscalls.nx" 27import "nx_runtime.nx" 28import "nx_tier.nx" 29import "nx_crc32.nx" 30import "nx_adler32.nx" 31import "nx_png_decoder.nx" 32import "nx_image_grade_v0.nx" 33 34// ===== big-endian 4-byte writer ================================== 35 36func _png_smoke_write_u32_be(buf: *u8, off: nx_int, value: nx_int) -> nx_int { 37 buf[off] = ((value >> 24) & 255) as u8 38 buf[off + 1] = ((value >> 16) & 255) as u8 39 buf[off + 2] = ((value >> 8) & 255) as u8 40 buf[off + 3] = (value & 255) as u8 41 return 0 42} 43 44// ===== build a 1x1 RGB PNG with caller-chosen pixel color ======== 45// 46// Returns (buf, total_size) by writing to out_buf and returning size. 47 48func _png_smoke_build(r_val: nx_int, g_val: nx_int, b_val: nx_int, 49 out_buf: *u8) -> nx_int { 50 // Signature (8 bytes). 51 out_buf[0] = 137 as u8 52 out_buf[1] = 80 as u8 53 out_buf[2] = 78 as u8 54 out_buf[3] = 71 as u8 55 out_buf[4] = 13 as u8 56 out_buf[5] = 10 as u8 57 out_buf[6] = 26 as u8 58 out_buf[7] = 10 as u8 59 var pos: nx_int = 8 60 61 // ---- IHDR chunk ---- 62 // length = 13 63 _png_smoke_write_u32_be(out_buf, pos, 13) 64 pos = pos + 4 65 let ihdr_type_off: nx_int = pos 66 out_buf[pos] = 73 as u8 // 'I' 67 out_buf[pos + 1] = 72 as u8 // 'H' 68 out_buf[pos + 2] = 68 as u8 // 'D' 69 out_buf[pos + 3] = 82 as u8 // 'R' 70 pos = pos + 4 71 // Data: width(4)=1, height(4)=1, bd=8, ct=2 (RGB), cm=0, fm=0, il=0 72 _png_smoke_write_u32_be(out_buf, pos, 1) 73 pos = pos + 4 74 _png_smoke_write_u32_be(out_buf, pos, 1) 75 pos = pos + 4 76 out_buf[pos] = 8 as u8 77 out_buf[pos + 1] = 2 as u8 78 out_buf[pos + 2] = 0 as u8 79 out_buf[pos + 3] = 0 as u8 80 out_buf[pos + 4] = 0 as u8 81 pos = pos + 5 82 // CRC over type+data = 4+13 bytes 83 let ihdr_crc_buf: *u8 = (out_buf as nx_int + ihdr_type_off) as *u8 84 let ihdr_crc: nx_int = nx_crc32(ihdr_crc_buf, 17) 85 _png_smoke_write_u32_be(out_buf, pos, ihdr_crc) 86 pos = pos + 4 87 88 // ---- IDAT chunk ---- 89 // 90 // zlib-wrapped DEFLATE stored block carrying [filter_byte, R, G, B]: 91 // CMF/FLG = 78 01 (2 bytes) 92 // DEFLATE stored header: BFINAL=1 BTYPE=00 (1 byte = 0x01), 93 // LEN_lo LEN_hi (LEN=4), NLEN_lo NLEN_hi (~LEN = 0xFFFB) 94 // -> 01 04 00 FB FF 95 // payload: 00 R G B 96 // Adler-32 BE: 4 bytes 97 // Total zlib stream = 2 + 5 + 4 + 4 = 15 bytes. 98 let zlib_len: nx_int = 15 99 _png_smoke_write_u32_be(out_buf, pos, zlib_len) 100 pos = pos + 4 101 let idat_type_off: nx_int = pos 102 out_buf[pos] = 73 as u8 // 'I' 103 out_buf[pos + 1] = 68 as u8 // 'D' 104 out_buf[pos + 2] = 65 as u8 // 'A' 105 out_buf[pos + 3] = 84 as u8 // 'T' 106 pos = pos + 4 107 // CMF/FLG 108 out_buf[pos] = 0x78 as u8 109 out_buf[pos + 1] = 0x01 as u8 110 pos = pos + 2 111 // DEFLATE stored header 112 out_buf[pos] = 0x01 as u8 113 out_buf[pos + 1] = 4 as u8 114 out_buf[pos + 2] = 0 as u8 115 out_buf[pos + 3] = 0xFB as u8 116 out_buf[pos + 4] = 0xFF as u8 117 pos = pos + 5 118 // Payload: filter byte 0 then RGB 119 let payload_off: nx_int = pos 120 out_buf[pos] = 0 as u8 121 out_buf[pos + 1] = r_val as u8 122 out_buf[pos + 2] = g_val as u8 123 out_buf[pos + 3] = b_val as u8 124 pos = pos + 4 125 // Compute Adler-32 over the 4-byte payload. 126 let payload_ptr: *u8 = (out_buf as nx_int + payload_off) as *u8 127 let adler: nx_int = adler32(payload_ptr, 4) 128 _png_smoke_write_u32_be(out_buf, pos, adler) 129 pos = pos + 4 130 // CRC over IDAT type+data = 4 + 15 = 19 bytes 131 let idat_crc_buf: *u8 = (out_buf as nx_int + idat_type_off) as *u8 132 let idat_crc: nx_int = nx_crc32(idat_crc_buf, 19) 133 _png_smoke_write_u32_be(out_buf, pos, idat_crc) 134 pos = pos + 4 135 136 // ---- IEND chunk ---- 137 _png_smoke_write_u32_be(out_buf, pos, 0) 138 pos = pos + 4 139 let iend_type_off: nx_int = pos 140 out_buf[pos] = 73 as u8 // 'I' 141 out_buf[pos + 1] = 69 as u8 // 'E' 142 out_buf[pos + 2] = 78 as u8 // 'N' 143 out_buf[pos + 3] = 68 as u8 // 'D' 144 pos = pos + 4 145 let iend_crc_buf: *u8 = (out_buf as nx_int + iend_type_off) as *u8 146 let iend_crc: nx_int = nx_crc32(iend_crc_buf, 4) 147 _png_smoke_write_u32_be(out_buf, pos, iend_crc) 148 pos = pos + 4 149 150 return pos 151} 152 153// ===== self-test ================================================== 154 155func main() -> nx_int { 156 let png_buf: *u8 = (sys_mmap(128)) as *u8 157 158 // ---- pure red 1x1 PNG: decode through nx_png_decode ---- 159 let red_size: nx_int = _png_smoke_build(255, 0, 0, png_buf) 160 if red_size < 50 { return 1 } 161 if red_size > 100 { return 2 } 162 let r_red: *NxPngResult = nx_png_decode(png_buf, red_size) 163 if r_red == (0 as *NxPngResult) { return 3 } 164 if r_red.error_code != NX_PNG_OK { return 4 } 165 if r_red.header == (0 as *NxPngHeader) { return 5 } 166 if r_red.header.width != 1 { return 6 } 167 if r_red.header.height != 1 { return 7 } 168 if r_red.n_channels != 3 { return 8 } 169 if r_red.bytes_per_pix != 3 { return 9 } 170 if r_red.pixels_size != 3 { return 10 } 171 let red_r: nx_int = (r_red.pixels[0] as nx_int) & 255 172 let red_g: nx_int = (r_red.pixels[1] as nx_int) & 255 173 let red_b: nx_int = (r_red.pixels[2] as nx_int) & 255 174 if red_r != 255 { return 11 } 175 if red_g != 0 { return 12 } 176 if red_b != 0 { return 13 } 177 178 // ---- pure green 1x1 PNG ---- 179 let png_buf2: *u8 = (sys_mmap(128)) as *u8 180 let green_size: nx_int = _png_smoke_build(0, 255, 0, png_buf2) 181 let r_green: *NxPngResult = nx_png_decode(png_buf2, green_size) 182 if r_green.error_code != NX_PNG_OK { return 20 } 183 let g_r: nx_int = (r_green.pixels[0] as nx_int) & 255 184 let g_g: nx_int = (r_green.pixels[1] as nx_int) & 255 185 let g_b: nx_int = (r_green.pixels[2] as nx_int) & 255 186 if g_r != 0 { return 21 } 187 if g_g != 255 { return 22 } 188 if g_b != 0 { return 23 } 189 190 // ---- mid skin tone 1x1 PNG via the full v0 grader pipeline ---- 191 // 192 // (200, 170, 150) is a warm-light skin tone. Pipeline should: 193 // - decode PNG -> 1x1 RGB pixel 194 // - scan_means -> mean R=200, G=170, B=150 195 // - lab_from_rgb -> Lab 196 // - skin_tone_ita -> light/intermediate band 197 // - undertone -> warm 198 let png_buf3: *u8 = (sys_mmap(128)) as *u8 199 let skin_size: nx_int = _png_smoke_build(200, 170, 150, png_buf3) 200 let rep: *NxIgv0Report = nx_image_grade_v0(png_buf3, skin_size) 201 if rep == (0 as *NxIgv0Report) { return 30 } 202 if rep.error_code != NX_IGV0_OK { return 31 } 203 if rep.source_format != NX_IGV0_FORMAT_PNG { return 32 } 204 if rep.width != 1 { return 33 } 205 if rep.height != 1 { return 34 } 206 if rep.mean_r != 200 { return 35 } 207 if rep.mean_g != 170 { return 36 } 208 if rep.mean_b != 150 { return 37 } 209 210 // Verify the per-axis verdicts are populated. 211 if rep.n_axes < 12 { return 40 } 212 213 // Skin-tone-ITA axis (index 0) should be OK. 214 let ax0: *NxIgv0AxisVerdict = 215 (rep.axes as *u8 + (0 as nx_size) * NX_IGV0_AXIS_VERDICT_BYTES) as *NxIgv0AxisVerdict 216 if ax0.status != NX_IGV0_AXIS_OK { return 41 } 217 // Band should be light or intermediate (1 or 2) for (200,170,150). 218 if ax0.verdict_value > 3 { return 42 } 219 220 // Undertone axis (index 1) should be OK + WARM (3) or NEUTRAL (2). 221 let ax1: *NxIgv0AxisVerdict = 222 (rep.axes as *u8 + (1 as nx_size) * NX_IGV0_AXIS_VERDICT_BYTES) as *NxIgv0AxisVerdict 223 if ax1.status != NX_IGV0_AXIS_OK { return 50 } 224 if ax1.verdict_value != 3 { 225 if ax1.verdict_value != 2 { return 51 } 226 } 227 228 // A PENDING axis (vein-signal at index 5) should be PENDING_SEG. 229 let ax_vein: *NxIgv0AxisVerdict = 230 (rep.axes as *u8 + (5 as nx_size) * NX_IGV0_AXIS_VERDICT_BYTES) as *NxIgv0AxisVerdict 231 if ax_vein.status != NX_IGV0_AXIS_PENDING_SEGMENTATION { return 60 } 232 if ax_vein.phrase_len < 10 { return 61 } 233 234 return 0 235}