nx_photo_count_gate.nx source
↩ module page · 91 lines · 5845 B
1// nx_photo_count_gate.nx -- REFEREE for the five-pics fix and the conversation-album arithmetic (2026-08-30): a photo count
2// parses from digits AND number words but ONLY beside a photo noun, clamps to the batch cap, and is spliced out of the scene
3// the diffusion model reads (the measured defect: "send me five pics" clamped to ONE request whose prompt still said "five
4// pics", so the model painted a five-panel collage into one image); the album emitter groups tsv rows into days under a
5// clock offset with hand-derivable 1970-epoch fixtures. GPU-free, in-process (imports the orchestrator lib directly).
6// license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_gate_verdict.nx"
9import "nx_gen_orchestrator.nx"
10
11const PG_TOKBUF: i64 = 32
12const PG_OUT: i64 = 8192
13const PG_ALBUM_FIXTURE: *u8 = "0\tnxc1-aa\n86399\tnxc1-bb\n86400\tnxc1-cc\n" as *u8
14
15func pg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
16func pg_eq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] == b[i] { if a[i] == (0 as u8) { return 1 } i = i + 1 } return 0 }
17func pg_find(buf: *u8, n: i64, needle: *u8) -> i64 {
18 let nl: i64 = pg_len(needle)
19 if nl <= 0 { return 0 - 1 }
20 var i: i64 = 0
21 while i + nl <= n {
22 var j: i64 = 0
23 var same: i64 = 1
24 var scan: i64 = 1
25 while scan == 1 { if j >= nl { scan = 0 } else { if buf[i + j] != needle[j] { same = 0; scan = 0 } else { j = j + 1 } } }
26 if same == 1 { return i }
27 i = i + 1
28 }
29 return 0 - 1
30}
31func pg_count(s: *u8, tok: *i64) -> i64 { return go_parse_count_any(s, pg_len(s), tok) }
32
33func main() -> i64 {
34 gv_head("nx_photo_count_gate -- the five-pics fix: digits and number words count only beside a photo noun, clamp to the batch cap, splice out of the scene; the album groups by day under a clock offset" as *u8)
35 let ctr: *i64 = gv_ctr()
36 let tok: *i64 = sys_mmap(PG_TOKBUF) as *i64
37 let out: *u8 = sys_mmap(PG_OUT)
38
39 // T1 digits beside a noun
40 var v: i64 = pg_count("send me 5 pics" as *u8, tok)
41 gv_check("digits-beside-a-photo-noun-count" as *u8, (v == 5) & (tok[0] == 8) & (tok[1] == 1), ctr)
42 // T2 number words
43 v = pg_count("send me five pics of you at the beach" as *u8, tok)
44 gv_check("number-word-beside-a-photo-noun-counts" as *u8, (v == 5) & (tok[0] == 8) & (tok[1] == 4), ctr)
45 v = pg_count("three selfies please" as *u8, tok)
46 gv_check("word-count-works-on-selfies" as *u8, (v == 3) & (tok[0] == 0), ctr)
47 v = pg_count("a couple pics?" as *u8, tok)
48 gv_check("couple-reads-as-two" as *u8, v == 2, ctr)
49 v = pg_count("two shots" as *u8, tok)
50 gv_check("a-small-gap-between-number-and-noun-still-counts" as *u8, v == 2, ctr)
51 // T3 NEG-CONTROLS: a number away from a photo noun is NOT a count; a plain ask is one photo
52 v = pg_count("we're five friends, send a pic" as *u8, tok)
53 gv_check("neg-control-number-not-beside-a-photo-noun-is-one-photo" as *u8, (v == 1) & (tok[0] < 0), ctr)
54 v = pg_count("send me a pic" as *u8, tok)
55 gv_check("neg-control-no-number-is-one-photo" as *u8, (v == 1) & (tok[0] < 0), ctr)
56 v = pg_count("send me a pic of 3 dogs" as *u8, tok)
57 gv_check("neg-control-a-count-of-subjects-is-not-a-count-of-photos" as *u8, (v == 1) & (tok[0] < 0), ctr)
58 // T4 the clamp
59 v = pg_count("send 99 pics" as *u8, tok)
60 gv_check("count-clamps-to-the-batch-cap" as *u8, v == GEN_BATCH_CAP, ctr)
61 // T5 the scene splice: the model must never read the count
62 let s1: *u8 = "send me five pics at the beach" as *u8
63 v = pg_count(s1, tok)
64 var n1: i64 = go_scene_decount(s1, pg_len(s1), tok, out, PG_OUT)
65 gv_check("scene-splice-replaces-the-word-count-with-a" as *u8, (n1 > 0) & (pg_eq(out, "send me a pics at the beach" as *u8) == 1), ctr)
66 let s2: *u8 = "send 3 photos now" as *u8
67 v = pg_count(s2, tok)
68 n1 = go_scene_decount(s2, pg_len(s2), tok, out, PG_OUT)
69 gv_check("scene-splice-replaces-the-digit-count-with-a" as *u8, (n1 > 0) & (pg_eq(out, "send a photos now" as *u8) == 1), ctr)
70 // T6 the album: hand-derivable 1970 fixtures -- 0 and 86399 are 1970-01-01, 86400 is 1970-01-02; newest day first
71 let fx: *u8 = PG_ALBUM_FIXTURE
72 var an: i64 = go_album_emit(fx, pg_len(fx), 0, out, 0)
73 out[an] = 0 as u8
74 let p2: i64 = pg_find(out, an, "{\"day\":\"1970-01-02\",\"cids\":[\"nxc1-cc\"]}" as *u8)
75 let p1: i64 = pg_find(out, an, "{\"day\":\"1970-01-01\",\"cids\":[\"nxc1-bb\",\"nxc1-aa\"]}" as *u8)
76 gv_check("album-groups-by-utc-day-newest-first-rows-newest-first" as *u8, (p2 >= 0) & (p1 >= 0) & (p2 < p1), ctr)
77 // T7 the offset moves the midnight boundary: at -6 h, 86400 (06:00 utc-6=00:00) stays on 01-01
78 an = go_album_emit(fx, pg_len(fx), 0 - 6, out, 0)
79 out[an] = 0 as u8
80 gv_check("album-offset-moves-the-midnight-boundary" as *u8, (pg_find(out, an, "1970-01-02" as *u8) < 0) & (pg_find(out, an, "{\"day\":\"1970-01-01\",\"cids\":[\"nxc1-cc\",\"nxc1-bb\",\"nxc1-aa\"]}" as *u8) >= 0), ctr)
81 // T8 a modern date lands in the right month (the civil algorithm on a current epoch)
82 let db: *u8 = sys_mmap(PG_TOKBUF * 2)
83 go_day_str(1788145449, 0, db)
84 gv_check("civil-date-on-a-current-epoch-reads-august-2026" as *u8, pg_find(db, pg_len(db), "2026-08-3" as *u8) == 0, ctr)
85 // T9 neg-control: an empty album is exactly empty
86 an = go_album_emit("" as *u8, 0, 0, out, 0)
87 out[an] = 0 as u8
88 gv_check("neg-control-empty-album-emits-an-empty-days-array" as *u8, pg_eq(out, "{\"days\":[]}" as *u8) == 1, ctr)
89
90 return gv_verdict("PHOTO-COUNT-GATE" as *u8, ctr, "the five-pics done-rule: a count parses from digits or words only beside a photo noun, clamps to the batch cap, and is spliced out of the scene the model reads; the album groups by day under the operator's clock offset" as *u8)
91}