nx_quality_driver.nx source
↩ module page · 100 lines · 3379 B
1// nx_quality_driver.nx -- MINIMAL substrate driver: real image -> verdict JSON.
2//
3// Reads /tmp/nx_img.raw (24-byte LE header + raw RGB bytes), runs the
4// safest detectors that don't trip the codegen bug (single function call,
5// no struct returns mid-chain), emits JSON to stdout. svc-quality
6// invokes this as a subprocess per render.
7//
8// Inline-in-main pattern because nxc2 codegen bug forbids the wrapper
9// pattern for some detector compositions. The driver does each detector
10// inline; result fields packed into one flat-array and printed as JSON.
11//
12// Output:
13// {"palette_kind":N,"warm_q10":N,"saturation_q10":N,"mean_r":N,"mean_g":N,"mean_b":N,"image_w":N,"image_h":N}
14
15// nx_safety_envelope:
16// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
17// sil_target: SIL1
18// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
19// verdict: NOT_YET_EVALUATED
20
21import "nx_syscalls.nx"
22import "nx_image.nx"
23import "nx_image_load_raw.nx"
24import "nx_color_palette.nx"
25const K_MAGIC_2048: i64 = 2048
26
27// Write null-terminated key string into buf at pos. Returns new pos.
28func nx_qd_puts(buf: *u8, pos: i64, s: *u8) -> i64 {
29 var p: i64 = pos
30 var i: i64 = 0
31 while s[i] != 0 {
32 buf[p] = s[i]
33 p = p + 1
34 i = i + 1
35 }
36 return p
37}
38
39// Write i64 as decimal to buf. Returns new pos.
40func nx_qd_putint(buf: *u8, pos: i64, v: i64) -> i64 {
41 if v == 0 { buf[pos] = 48; return pos + 1 }
42 var n: i64 = v
43 var p: i64 = pos
44 if n < 0 { buf[p] = 45; p = p + 1; n = -n }
45 let start: i64 = p
46 while n > 0 {
47 let d: i64 = n - (n / 10) * 10
48 buf[p] = 48 + d
49 p = p + 1
50 n = n / 10
51 }
52 var a: i64 = start
53 var b: i64 = p - 1
54 while a < b {
55 let t: i64 = buf[a]
56 buf[a] = buf[b]
57 buf[b] = t
58 a = a + 1
59 b = b - 1
60 }
61 return p
62}
63
64func main() -> i64 {
65 let path: *u8 = "/tmp/nx_img.raw"
66 let img: *Image = nx_image_load_raw(path)
67 if img == (0 as *Image) {
68 let err: *u8 = "{\"error\":\"image_load_failed\"}\n"
69 let len_e: *i64 = (sys_mmap(8 + 8)) as *i64
70 sys_read_file(err, len_e) // hack: use sys_write would be cleaner
71 return 1
72 }
73
74 // Run color palette classifier inline.
75 let pal_res: *i64 = (sys_mmap(NX_PAL_RES_FIELDS * 8 + 16)) as *i64
76 nx_color_palette(img, pal_res)
77
78 // Build JSON output in a buffer.
79 let out: *u8 = sys_mmap(K_MAGIC_2048)
80 var p: i64 = 0
81 p = nx_qd_puts(out, p, "{\"image_w\":")
82 p = nx_qd_putint(out, p, img.width)
83 p = nx_qd_puts(out, p, ",\"image_h\":")
84 p = nx_qd_putint(out, p, img.height)
85 p = nx_qd_puts(out, p, ",\"palette_kind\":")
86 p = nx_qd_putint(out, p, pal_res[NX_PAL_RES_KIND])
87 p = nx_qd_puts(out, p, ",\"warm_q10\":")
88 p = nx_qd_putint(out, p, pal_res[NX_PAL_RES_WARM_Q10])
89 p = nx_qd_puts(out, p, ",\"saturation_q10\":")
90 p = nx_qd_putint(out, p, pal_res[NX_PAL_RES_SAT_Q10])
91 p = nx_qd_puts(out, p, ",\"mean_r\":")
92 p = nx_qd_putint(out, p, pal_res[NX_PAL_RES_MEAN_R])
93 p = nx_qd_puts(out, p, ",\"mean_g\":")
94 p = nx_qd_putint(out, p, pal_res[NX_PAL_RES_MEAN_G])
95 p = nx_qd_puts(out, p, ",\"mean_b\":")
96 p = nx_qd_putint(out, p, pal_res[NX_PAL_RES_MEAN_B])
97 p = nx_qd_puts(out, p, "}\n")
98 sys_write(1, out, p)
99 return 0
100}