nx_learnmine_gate.nx source
↩ module page · 194 lines · 14519 B
1// nx_learnmine_gate.nx -- THE LEARNING-MINING GATE (2026-09-06). An archive.org advancedsearch listing is assembled at runtime
2// under /tmp/nx_learnmine_gate/ from bytes the gate writes itself (quotes, escapes, a unicode escape, an array-valued
3// description and subject, a pipe and a newline inside a value, an item with no date and no downloads, a description longer
4// than the announced head) and digested through the lib: the item count, the census by media type, newest and oldest
5// dates, decoded and sanitised fields, the subject table ordered by count, the truncation announcement; then the refusals
6// by name (an unclosed object, a listing without docs, an absent file) and the command through the ladder.
7// usage: nx_learnmine_gate (no args)
8// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
9import "nx_syscalls.nx"
10import "nx_gate_verdict.nx"
11import "nx_gatekit_lib.nx"
12import "nx_learnmine_lib.nx"
13
14const LG_DIR: *u8 = "/tmp/nx_learnmine_gate"
15const LG_GOOD: *u8 = "/tmp/nx_learnmine_gate/listing.json"
16const LG_BAD: *u8 = "/tmp/nx_learnmine_gate/unclosed.json"
17const LG_NODOCS: *u8 = "/tmp/nx_learnmine_gate/nodocs.json"
18const LG_ABSENT: *u8 = "/tmp/nx_learnmine_gate/absent.json"
19const LG_ELF_LIVE: *u8 = "./nx_learnmine.elf"
20const LG_ELF_STAGE: *u8 = "./nx_learnmine.sov.elf.new"
21const LG_ELF_BUILD: *u8 = "buildroot/_build/nx_learnmine.sov.elf"
22const LG_DIR_MODE: i64 = 493
23const LG_FILE_MODE: i64 = 420
24const LG_CAP: i64 = 65536
25const LG_ITEMS: i64 = 4
26const LG_LONG_DESC: i64 = 300
27const LG_Q: i64 = 34
28const LG_BS: i64 = 92
29const LG_ID1: *u8 = "anime-nyan-mmd-physics-2025"
30
31func lg_write_file(path: *u8, b: *u8, n: i64) -> i64 {
32 let fd: i64 = sys_openat_wr(path, LG_FILE_MODE)
33 if fd < 0 { return 0 - 1 }
34 var done: i64 = 0
35 while done < n { let k: i64 = sys_write(fd, b + done, n - done); if k <= 0 { break } done = done + k }
36 sys_close(fd)
37 return done
38}
39func lg_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
40// JSON assembly with the quote byte spelled once, so no string literal in this source carries a quote
41func lg_b(buf: *u8, o: i64, c: i64) -> i64 { buf[o] = c as u8; return o + 1 }
42func lg_q(buf: *u8, o: i64, s: *u8) -> i64 { var p: i64 = lg_b(buf, o, LG_Q); p = lm_cat(buf, p, s); return lg_b(buf, p, LG_Q) }
43func lg_k(buf: *u8, o: i64, key: *u8) -> i64 { var p: i64 = lg_q(buf, o, key); return lg_b(buf, p, 58) }
44func lg_kv(buf: *u8, o: i64, key: *u8, val: *u8) -> i64 { var p: i64 = lg_k(buf, o, key); return lg_q(buf, p, val) }
45func lg_comma(buf: *u8, o: i64) -> i64 { return lg_b(buf, o, 44) }
46// the listing: four docs
47func lg_build_listing(buf: *u8, long: i64) -> i64 {
48 var o: i64 = 0
49 o = lg_b(buf, o, 123)
50 o = lg_k(buf, o, "responseHeader" as *u8); o = lg_b(buf, o, 123); o = lg_k(buf, o, "status" as *u8); o = lm_cat(buf, o, "0" as *u8); o = lg_b(buf, o, 125)
51 o = lg_comma(buf, o); o = lg_k(buf, o, "response" as *u8); o = lg_b(buf, o, 123)
52 o = lg_k(buf, o, "numFound" as *u8); o = lm_cat(buf, o, "4" as *u8); o = lg_comma(buf, o)
53 o = lg_k(buf, o, "start" as *u8); o = lm_cat(buf, o, "0" as *u8); o = lg_comma(buf, o)
54 o = lg_k(buf, o, "docs" as *u8); o = lg_b(buf, o, 91)
55 // doc 1: escapes, unicode, arrays
56 o = lg_b(buf, o, 123)
57 o = lg_kv(buf, o, "identifier" as *u8, LG_ID1); o = lg_comma(buf, o)
58 o = lg_k(buf, o, "title" as *u8); o = lg_b(buf, o, LG_Q); o = lm_cat(buf, o, "MMD physics tutorial " as *u8)
59 o = lg_b(buf, o, LG_BS); o = lm_cat(buf, o, "u00e9 " as *u8); o = lg_b(buf, o, LG_BS); o = lg_b(buf, o, LG_Q); o = lm_cat(buf, o, "quoted" as *u8); o = lg_b(buf, o, LG_BS); o = lg_b(buf, o, LG_Q); o = lg_b(buf, o, LG_Q); o = lg_comma(buf, o)
60 o = lg_kv(buf, o, "mediatype" as *u8, "movies" as *u8); o = lg_comma(buf, o)
61 o = lg_kv(buf, o, "date" as *u8, "2025-11-03T00:00:00Z" as *u8); o = lg_comma(buf, o)
62 o = lg_k(buf, o, "description" as *u8); o = lg_b(buf, o, 91); o = lg_q(buf, o, "part one" as *u8); o = lg_comma(buf, o); o = lg_q(buf, o, "part two" as *u8); o = lg_b(buf, o, 93); o = lg_comma(buf, o)
63 o = lg_k(buf, o, "subject" as *u8); o = lg_b(buf, o, 91); o = lg_q(buf, o, "MMD" as *u8); o = lg_comma(buf, o); o = lg_q(buf, o, "hair physics" as *u8); o = lg_comma(buf, o); o = lg_q(buf, o, "Blender" as *u8); o = lg_b(buf, o, 93); o = lg_comma(buf, o)
64 o = lg_k(buf, o, "downloads" as *u8); o = lm_cat(buf, o, "1234" as *u8)
65 o = lg_b(buf, o, 125); o = lg_comma(buf, o)
66 // doc 2: a pipe and a newline escape inside the description, a scalar subject
67 o = lg_b(buf, o, 123)
68 o = lg_kv(buf, o, "identifier" as *u8, "item-two" as *u8); o = lg_comma(buf, o)
69 o = lg_kv(buf, o, "title" as *u8, "Plain" as *u8); o = lg_comma(buf, o)
70 o = lg_kv(buf, o, "mediatype" as *u8, "texts" as *u8); o = lg_comma(buf, o)
71 o = lg_kv(buf, o, "date" as *u8, "2024-01-15T00:00:00Z" as *u8); o = lg_comma(buf, o)
72 o = lg_k(buf, o, "description" as *u8); o = lg_b(buf, o, LG_Q); o = lm_cat(buf, o, "a|b" as *u8); o = lg_b(buf, o, LG_BS); o = lm_cat(buf, o, "nc" as *u8); o = lg_b(buf, o, LG_Q); o = lg_comma(buf, o)
73 o = lg_kv(buf, o, "subject" as *u8, "MMD" as *u8); o = lg_comma(buf, o)
74 o = lg_k(buf, o, "downloads" as *u8); o = lm_cat(buf, o, "5" as *u8)
75 o = lg_b(buf, o, 125); o = lg_comma(buf, o)
76 // doc 3: no date, no downloads, no subject, no description
77 o = lg_b(buf, o, 123)
78 o = lg_kv(buf, o, "identifier" as *u8, "item-three" as *u8); o = lg_comma(buf, o)
79 o = lg_kv(buf, o, "title" as *u8, "No date" as *u8); o = lg_comma(buf, o)
80 o = lg_kv(buf, o, "mediatype" as *u8, "audio" as *u8)
81 o = lg_b(buf, o, 125); o = lg_comma(buf, o)
82 // doc 4: a description longer than the announced head
83 o = lg_b(buf, o, 123)
84 o = lg_kv(buf, o, "identifier" as *u8, "item-four" as *u8); o = lg_comma(buf, o)
85 o = lg_kv(buf, o, "title" as *u8, "Long" as *u8); o = lg_comma(buf, o)
86 o = lg_kv(buf, o, "mediatype" as *u8, "movies" as *u8); o = lg_comma(buf, o)
87 o = lg_kv(buf, o, "date" as *u8, "2026-08-30" as *u8); o = lg_comma(buf, o)
88 o = lg_k(buf, o, "description" as *u8); o = lg_b(buf, o, LG_Q)
89 var k: i64 = 0
90 while k < long { o = lg_b(buf, o, 97 + (k % 26)); k = k + 1 }
91 o = lg_b(buf, o, LG_Q); o = lg_comma(buf, o)
92 o = lg_kv(buf, o, "subject" as *u8, "Blender" as *u8)
93 o = lg_b(buf, o, 125)
94 o = lg_b(buf, o, 93); o = lg_b(buf, o, 125); o = lg_b(buf, o, 125)
95 buf[o] = 0 as u8
96 return o
97}
98
99func main(argc: i64, argv: *i64) -> i64 {
100 let ctr: *i64 = gv_ctr()
101 sys_mkdir(LG_DIR, LG_DIR_MODE)
102 let buf: *u8 = sys_mmap(LG_CAP)
103 let n: i64 = lg_build_listing(buf, LG_LONG_DESC)
104 gv_check("fixture-listing-assembled (>0 bytes)" as *u8, (n > 0) as i64, ctr)
105 gv_check_eq("fixture-listing-written" as *u8, lg_write_file(LG_GOOD, buf, n), n, ctr)
106 // an unclosed object: cut the listing inside doc 2
107 lg_write_file(LG_BAD, buf, n / 2)
108 // a listing with no docs key
109 let nd: *u8 = sys_mmap(256)
110 var q: i64 = 0
111 q = lg_b(nd, q, 123); q = lg_k(nd, q, "response" as *u8); q = lg_b(nd, q, 123); q = lg_k(nd, q, "numFound" as *u8); q = lm_cat(nd, q, "0" as *u8); q = lg_b(nd, q, 125); q = lg_b(nd, q, 125)
112 lg_write_file(LG_NODOCS, nd, q)
113 // ---- 1. parse the listing ----
114 let items: *i64 = sys_mmap(8 * LM_I_SLOTS * 64) as *i64
115 let lst: *i64 = sys_mmap(8 * LM_L_SLOTS) as *i64
116 gv_check_eq("listing-parses-OK" as *u8, lm_parse_listing(buf, n, items, 64, lst), LM_OK, ctr)
117 gv_check_eq("items-4" as *u8, lst[LM_L_ITEMS], LG_ITEMS, ctr)
118 gv_check_eq("numfound-4" as *u8, lst[LM_L_NUMFOUND], 4, ctr)
119 gv_check_eq("census-movies-2" as *u8, lst[LM_L_MOVIES], 2, ctr)
120 gv_check_eq("census-texts-1" as *u8, lst[LM_L_TEXTS], 1, ctr)
121 gv_check_eq("census-audio-1" as *u8, lst[LM_L_AUDIO], 1, ctr)
122 gv_check_eq("census-other-0" as *u8, lst[LM_L_OTHER], 0, ctr)
123 gv_check_eq("census-partition-sums-to-items" as *u8, lst[LM_L_MOVIES] + lst[LM_L_TEXTS] + lst[LM_L_AUDIO] + lst[LM_L_IMAGE] + lst[LM_L_OTHER], lst[LM_L_ITEMS], ctr)
124 gv_check("newest-is-2026-08-30 (a date without a time part still compares)" as *u8, lm_streq(lst[LM_L_NEWEST] as *u8, "2026-08-30" as *u8), ctr)
125 gv_check("oldest-is-2024-01-15 (the undated item never wins)" as *u8, lm_streq(lst[LM_L_OLDEST] as *u8, "2024-01-15" as *u8), ctr)
126 gv_check_eq("downloads-sum-1239" as *u8, lst[LM_L_DOWNLOADS], 1239, ctr)
127 gv_check_eq("truncated-descs-1 (the long one is announced)" as *u8, lst[LM_L_TRUNCATED_DESCS], 1, ctr)
128 // ---- 2. the decoded fields ----
129 gv_check("item0-identifier" as *u8, lm_streq(items[LM_I_ID] as *u8, LG_ID1), ctr)
130 gv_check("item0-date-cut-to-YYYY-MM-DD" as *u8, lm_streq(items[LM_I_DATE] as *u8, "2025-11-03" as *u8), ctr)
131 gv_check_eq("item0-downloads-1234" as *u8, items[LM_I_DOWNLOADS], 1234, ctr)
132 let t0: *u8 = items[LM_I_TITLE] as *u8
133 gv_check("item0-title-decodes-the-unicode-escape (e-acute as UTF-8)" as *u8, gk_out_has(t0, lm_len(t0), "tutorial é " as *u8), ctr)
134 gv_check("item0-title-keeps-the-escaped-quotes" as *u8, gk_out_has(t0, lm_len(t0), "quoted" as *u8), ctr)
135 gv_check_eq("item0-title-length-32 (decoded, not the escape length)" as *u8, lm_len(t0), 32, ctr)
136 gv_check("item0-subjects-joined" as *u8, lm_streq(items[LM_I_SUBJECTS] as *u8, "MMD; hair physics; Blender" as *u8), ctr)
137 gv_check("item0-array-description-joined-by-space" as *u8, lm_streq(items[LM_I_DESC] as *u8, "part one part two" as *u8), ctr)
138 let b1: i64 = 1 * LM_I_SLOTS
139 gv_check("item1-description-sanitised (pipe to slash, newline to space)" as *u8, lm_streq(items[b1 + LM_I_DESC] as *u8, "a/b c" as *u8), ctr)
140 gv_check_eq("item1-downloads-5" as *u8, items[b1 + LM_I_DOWNLOADS], 5, ctr)
141 gv_check("item1-scalar-subject" as *u8, lm_streq(items[b1 + LM_I_SUBJECTS] as *u8, "MMD" as *u8), ctr)
142 let b2: i64 = 2 * LM_I_SLOTS
143 gv_check("item2-no-date-is-empty" as *u8, ((items[b2 + LM_I_DATE] as *u8)[0] == (0 as u8)) as i64, ctr)
144 gv_check_eq("item2-no-downloads-is-0" as *u8, items[b2 + LM_I_DOWNLOADS], 0, ctr)
145 gv_check_eq("item2-no-description-len-0" as *u8, items[b2 + LM_I_DESC_LEN], 0, ctr)
146 let b3: i64 = 3 * LM_I_SLOTS
147 gv_check_eq("item3-description-full-length-announced" as *u8, items[b3 + LM_I_DESC_LEN], LG_LONG_DESC, ctr)
148 gv_check_eq("item3-description-head-cut-to-the-announced-head" as *u8, lm_len(items[b3 + LM_I_DESC] as *u8), LM_DESC_HEAD, ctr)
149 // ---- 3. subjects ----
150 let subj: *i64 = sys_mmap(8 * 64) as *i64
151 let counts: *i64 = sys_mmap(8 * 64) as *i64
152 let full: *i64 = sys_mmap(16) as *i64
153 let d: i64 = lm_subjects(items, lst[LM_L_ITEMS], subj, counts, 64, full)
154 gv_check_eq("subjects-distinct-3" as *u8, d, 3, ctr)
155 gv_check("subjects-top-is-MMD" as *u8, lm_streq(subj[0] as *u8, "MMD" as *u8), ctr)
156 gv_check_eq("subjects-top-count-2" as *u8, counts[0], 2, ctr)
157 gv_check_eq("subjects-second-count-2 (Blender)" as *u8, counts[1], 2, ctr)
158 gv_check_eq("subjects-not-a-floor" as *u8, full[0], 0, ctr)
159 let d2: i64 = lm_subjects(items, lst[LM_L_ITEMS], subj, counts, 2, full)
160 gv_check_eq("neg-control-subject-table-cap-reports-a-floor" as *u8, full[0], 1, ctr)
161 gv_check_eq("neg-control-subject-table-cap-distinct-2" as *u8, d2, 2, ctr)
162 // ---- 4. refusals ----
163 gv_check_eq("neg-control-unclosed-object-MALFORMED" as *u8, lm_parse_listing(buf, n / 2, items, 64, lst), LM_ERR_MALFORMED, ctr)
164 gv_check_eq("neg-control-no-docs-NO-DOCS" as *u8, lm_parse_listing(nd, q, items, 64, lst), LM_ERR_NO_DOCS, ctr)
165 gv_check_eq("neg-control-capacity-1-CAPACITY" as *u8, lm_parse_listing(buf, n, items, 1, lst), LM_ERR_CAPACITY, ctr)
166 // ---- 5. the command ----
167 var elf: *u8 = 0 as *u8
168 if lg_exists(LG_ELF_LIVE) == 1 { elf = LG_ELF_LIVE }
169 else { if lg_exists(LG_ELF_STAGE) == 1 { elf = LG_ELF_STAGE } else { if lg_exists(LG_ELF_BUILD) == 1 { elf = LG_ELF_BUILD } } }
170 gv_need("cli-witness-present (live, staged or build fossil of nx_learnmine)" as *u8, ((elf as i64) != 0) as i64, ctr)
171 if (elf as i64) != 0 {
172 let out: *u8 = sys_mmap(LG_CAP)
173 let bl: *i64 = sys_mmap(16) as *i64
174 let rc0: i64 = gk_run_capture(elf, "items" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, out, LG_CAP, bl)
175 gv_check_eq("cli-items-without-a-listing-is-usage-exit-2" as *u8, rc0, 2, ctr)
176 let rc1: i64 = gk_run_capture(elf, "items" as *u8, LG_GOOD, 0 as *u8, 0 as *u8, out, LG_CAP, bl)
177 gv_check_eq("cli-items-exits-0" as *u8, rc1, 0, ctr)
178 gv_check("cli-items-row-0" as *u8, gk_out_has(out, bl[0], "ITEM|0|anime-nyan-mmd-physics-2025|movies|2025-11-03|1234|" as *u8), ctr)
179 gv_check("cli-items-desc-row-announces-the-full-length" as *u8, gk_out_has(out, bl[0], "DESC|item-four|300|" as *u8), ctr)
180 gv_check("cli-items-summary-last" as *u8, gk_out_has(out, bl[0], "LEARNMINE items=4 numfound=4 movies=2 texts=1 audio=1 image=0 other=0 newest=2026-08-30 oldest=2024-01-15 downloads=1239 truncated_descs=1 verdict=GREEN" as *u8), ctr)
181 let rc2: i64 = gk_run_capture(elf, "subjects" as *u8, LG_GOOD, "2" as *u8, 0 as *u8, out, LG_CAP, bl)
182 gv_check_eq("cli-subjects-exits-0" as *u8, rc2, 0, ctr)
183 gv_check("cli-subjects-top-row" as *u8, gk_out_has(out, bl[0], "SUBJECT|1|2|MMD" as *u8), ctr)
184 gv_check("cli-subjects-shown-2-of-3" as *u8, gk_out_has(out, bl[0], "SUBJECTS distinct=3 shown=2 floor=0" as *u8), ctr)
185 let rc3: i64 = gk_run_capture(elf, "census" as *u8, LG_BAD, 0 as *u8, 0 as *u8, out, LG_CAP, bl)
186 gv_check_eq("cli-census-unclosed-exits-3" as *u8, rc3, 3, ctr)
187 gv_check("cli-census-unclosed-names-MALFORMED" as *u8, gk_out_has(out, bl[0], "rule=MALFORMED" as *u8), ctr)
188 let rc4: i64 = gk_run_capture(elf, "census" as *u8, LG_ABSENT, 0 as *u8, 0 as *u8, out, LG_CAP, bl)
189 gv_check_eq("cli-census-absent-file-exits-3" as *u8, rc4, 3, ctr)
190 gv_check("cli-census-absent-file-names-UNREADABLE" as *u8, gk_out_has(out, bl[0], "rule=UNREADABLE" as *u8), ctr)
191 }
192 gv_kv("fixture_bytes" as *u8, n)
193 return gv_verdict("NX-LEARNMINE" as *u8, ctr, "an archive.org listing assembled from its own bytes digests into item rows and a census with decoded, sanitised fields, dated newest and oldest, an announced description head, a subject table with a floor flag; an unclosed object, a listing without docs, a capacity cut and an absent file refuse by name; the command agrees" as *u8)
194}