code wiki / _hdl_build / nx_vizsla_docgen.nx
nx_vizsla_docgen.nx source
↩ module page · 295 lines · 10652 B
1// nx_vizsla_docgen.nx -- NISHI VIZSLA OFFICE DOCUMENT GENERATION: turn coordination data into a real
2// office document and FILE it in the never-lose doc manager. Operator 2026-07-08: "office ... along with
3// document management and all the other things". This is the bridge that ties the three named domains:
4// COORDINATION (a venue booking / plan / event supplies the fields) -> OFFICE (a valid .docx via nx_docx) ->
5// DOCUMENT MANAGEMENT (a versioned, rel-linked doc: record nx_vizsla_doc reads back byte-exact).
6//
7// GENERIC by design (rule 22, no venue/plan reader duplication): the input is a simple fields file --
8// line 1 = the document TITLE (first paragraph)
9// lines 2..N = one paragraph each (e.g. "Venue: Lakeside Pavilion"); blank lines skipped
10// so venue agreements, invite letters, plan summaries, meeting notes are all the SAME organ over different
11// fields (produced by the venue/plan/group boards). Output = a real Word .docx stored as a doc: record.
12//
13// Command:
14// build <docprefix> <docid> <doctype> <rel> <date> <fieldsfile> [segid]
15// -> writes a .docx (nx_docx docx_write) + stores it in <docprefix> as doc:<cid> (doctype/rel/date),
16// additive + CID-idempotent (re-build identical fields => already stored, new=0). The stored bytes are
17// the exact .docx (byte-exact retrievable via nx_vizsla_doc get; readable via nx_docx read).
18// Loud-fail: missing/empty fieldsfile, bad date, docx build fail, oversize (> 512KB).
19// DRY debt: the doc: record framing is replicated from nx_vizsla_doc's put (both should import a shared
20// nx_vizsla_docstore lib later); the gate CROSS-CHECKS it by reading the record back with the REAL doc organ.
21// spec: knowledge/research/2026-06-22-vizsla-sclass-roadmap.md license_tier: ORIGINAL
22import "nx_syscalls.nx"
23import "nx_canon_cid.nx"
24import "nx_seg_store.nx"
25import "nx_docx.nx"
26const K_MAGIC_1970: i64 = 1970
27const K_MAGIC_65536: i64 = 65536
28const K_MAGIC_4096: i64 = 4096
29const K_MAGIC_524288: i64 = 524288
30const K_MAGIC_1024: i64 = 1024
31
32func dg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
33func dg_p(s: *u8) -> i64 { sys_write(1, s, dg_slen(s)); return 0 }
34
35func dg_eq(a: *u8, b: *u8) -> i64 {
36 var i: i64 = 0
37 var go: i64 = 1
38 while go == 1 {
39 if a[i] != b[i] { return 0 }
40 if a[i] == (0 as u8) { return 1 }
41 i = i + 1
42 }
43 return 0
44}
45
46func dg_dup(s: *u8) -> *u8 {
47 let n: i64 = dg_slen(s)
48 let d: *u8 = sys_mmap(n + 2)
49 var i: i64 = 0
50 while i <= n { d[i] = s[i]; i = i + 1 }
51 return d
52}
53
54func dg_atoi(s: *u8) -> i64 {
55 var v: i64 = 0
56 var i: i64 = 0
57 while s[i] != (0 as u8) {
58 let d: i64 = (s[i] as i64) - 48
59 if d >= 0 { if d <= 9 { v = v * 10 + d } }
60 i = i + 1
61 }
62 return v
63}
64
65func dg_cat(dst: *u8, off: i64, s: *u8) -> i64 {
66 var i: i64 = 0
67 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
68 return off + i
69}
70
71func dg_catn(dst: *u8, off: i64, v: i64) -> i64 {
72 var o: i64 = off
73 var m: i64 = v
74 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m }
75 let t: *u8 = sys_mmap(28)
76 var k: i64 = 0
77 if m == 0 { t[0] = 48 as u8; k = 1 }
78 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
79 var i: i64 = 0
80 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 }
81 return o + k
82}
83
84func dg_datedays(s: *u8) -> i64 {
85 let nums: *i64 = sys_mmap(8 * 4) as *i64
86 var nn: i64 = 0
87 var cur: i64 = 0
88 var indig: i64 = 0
89 var i: i64 = 0
90 var go: i64 = 1
91 while go == 1 {
92 let c: i64 = s[i] as i64
93 var isd: i64 = 0
94 if c >= 48 { if c <= 57 { isd = 1 } }
95 if isd == 1 { cur = cur * 10 + (c - 48); indig = 1 }
96 if isd == 0 {
97 if indig == 1 {
98 if nn < 4 { nums[nn] = cur; nn = nn + 1 }
99 cur = 0
100 indig = 0
101 }
102 }
103 if c == 0 { go = 0 }
104 i = i + 1
105 }
106 if nn != 3 { return 0 - 1 }
107 let y: i64 = nums[0]
108 let m: i64 = nums[1]
109 let d: i64 = nums[2]
110 if y < K_MAGIC_1970 { return 0 - 1 }
111 if m < 1 { return 0 - 1 }
112 if m > 12 { return 0 - 1 }
113 if d < 1 { return 0 - 1 }
114 if d > 31 { return 0 - 1 }
115 return 1
116}
117
118func dg_readall(path: *u8, szout: *i64) -> *u8 {
119 let fd: i64 = sys_openat_rd(path)
120 if fd < 0 { szout[0] = 0 - 1; return 0 as *u8 }
121 let sz: i64 = sys_lseek(fd, 0, 2)
122 sys_lseek(fd, 0, 0)
123 let buf: *u8 = sys_mmap(sz + 64)
124 var got: i64 = 0
125 var n: i64 = 1
126 while n > 0 {
127 n = sys_read(fd, (buf as i64 + got) as *u8, K_MAGIC_65536)
128 if n > 0 { got = got + n }
129 }
130 sys_close(fd)
131 szout[0] = got
132 return buf
133}
134
135// store the .docx bytes as a doc: record (framing MIRRORS nx_vizsla_doc's put -- BIG-endian ss_w32).
136// returns 1 committed / 0 already-in-store (CID dedup) / -1 error.
137func dg_store_doc(prefix: *u8, docid: *u8, dtype: *u8, rel: *u8, date: *u8, content: *u8, csz: i64, segid: i64) -> i64 {
138 let keys: *i64 = sys_mmap(8 * 8) as *i64
139 let vals: *i64 = sys_mmap(8 * 8) as *i64
140 let lens: *i64 = sys_mmap(8 * 8) as *i64
141 keys[0] = "kind" as *u8 as i64
142 keys[1] = "docid" as *u8 as i64
143 keys[2] = "doctype" as *u8 as i64
144 keys[3] = "rel" as *u8 as i64
145 keys[4] = "date" as *u8 as i64
146 keys[5] = "content" as *u8 as i64
147 vals[0] = "doc" as *u8 as i64
148 vals[1] = docid as i64
149 vals[2] = dtype as i64
150 vals[3] = rel as i64
151 vals[4] = date as i64
152 vals[5] = content as i64
153 lens[0] = 3
154 lens[1] = dg_slen(docid)
155 lens[2] = dg_slen(dtype)
156 lens[3] = dg_slen(rel)
157 lens[4] = dg_slen(date)
158 lens[5] = csz
159
160 let enc: *u8 = sys_mmap(csz + K_MAGIC_4096)
161 var o: i64 = 0
162 ss_w32(enc, 0, 0)
163 ss_w32(enc, 4, 6)
164 o = 8
165 var f: i64 = 0
166 while f < 6 {
167 let k: *u8 = keys[f] as *u8
168 let kl: i64 = dg_slen(k)
169 ss_w32(enc, o, kl)
170 o = o + 4
171 var i: i64 = 0
172 while i < kl { enc[o + i] = k[i]; i = i + 1 }
173 o = o + kl
174 ss_w32(enc, o, lens[f])
175 o = o + 4
176 let v: *u8 = vals[f] as *u8
177 i = 0
178 while i < lens[f] { enc[o + i] = v[i]; i = i + 1 }
179 o = o + lens[f]
180 f = f + 1
181 }
182 let el: i64 = o
183
184 let cid: *u8 = sys_mmap(96)
185 cid_of(enc, el, cid)
186 let kbuf: *u8 = sys_mmap(160)
187 var ko: i64 = 0
188 ko = dg_cat(kbuf, ko, "doc:" as *u8)
189 ko = dg_cat(kbuf, ko, cid)
190 kbuf[ko] = 0 as u8
191
192 let pp: *i64 = sys_mmap(16) as *i64
193 let ll: *i64 = sys_mmap(16) as *i64
194 if ss_get_idx(prefix, kbuf, pp, ll) == 1 { return 0 }
195 let w: *i64 = ss_begin()
196 if ss_add(w, 1, kbuf, enc, el) != 0 { return 0 - 1 }
197 if ss_commit(prefix, w, segid) != 0 { return 0 - 1 }
198 return 1
199}
200
201// ---------------- BUILD ----------------
202func dg_cmd_build(argc: i64, argv: *i64) -> i64 {
203 if argc < 8 { dg_p("VIZSLA-DOCGEN build needs <docprefix> <docid> <doctype> <rel> <date> <fieldsfile> [segid] -- fail loud\n" as *u8); return 1 }
204 let prefix: *u8 = argv[2] as *u8
205 let docid: *u8 = argv[3] as *u8
206 let dtype: *u8 = argv[4] as *u8
207 let rel: *u8 = argv[5] as *u8
208 let date: *u8 = argv[6] as *u8
209 let fieldsfile: *u8 = argv[7] as *u8
210 if dg_datedays(date) < 0 { dg_p("VIZSLA-DOCGEN build bad date -- fail loud\n" as *u8); return 1 }
211 var segid: i64 = 0
212 if argc > 8 { segid = dg_atoi(argv[8] as *u8) }
213 if segid == 0 { segid = sys_now_us() }
214
215 let szp: *i64 = sys_mmap(16) as *i64
216 let b: *u8 = dg_readall(fieldsfile, szp)
217 let bn: i64 = szp[0]
218 if bn <= 0 { dg_p("VIZSLA-DOCGEN fieldsfile MISSING/EMPTY -- fail loud\n" as *u8); return 1 }
219
220 // one paragraph per non-empty line (CR stripped)
221 let paras: *i64 = sys_mmap(8 * 512) as *i64
222 var np: i64 = 0
223 var i: i64 = 0
224 while i < bn {
225 var e: i64 = i
226 var go: i64 = 1
227 while go == 1 { if e >= bn { go = 0 } else { if b[e] == (10 as u8) { go = 0 } else { e = e + 1 } } }
228 var end: i64 = e
229 if end > i { if b[end - 1] == (13 as u8) { end = end - 1 } } // strip CR
230 if end > i {
231 let line: *u8 = sys_mmap(end - i + 2)
232 var t: i64 = 0
233 var p: i64 = i
234 while p < end { line[t] = b[p]; t = t + 1; p = p + 1 }
235 line[t] = 0 as u8
236 if np < 512 { paras[np] = line as i64; np = np + 1 }
237 }
238 i = e + 1
239 }
240 if np == 0 { dg_p("VIZSLA-DOCGEN fieldsfile has NO content lines -- fail loud\n" as *u8); return 1 }
241
242 // build the .docx to a temp path, then read its bytes back
243 let tmp: *u8 = sys_mmap(128)
244 var to: i64 = 0
245 to = dg_cat(tmp, to, "/tmp/dgx_" as *u8)
246 to = dg_catn(tmp, to, sys_now_us())
247 to = dg_cat(tmp, to, ".docx" as *u8)
248 tmp[to] = 0 as u8
249 let dsz: i64 = docx_write(tmp, paras, np)
250 if dsz < 0 { dg_p("VIZSLA-DOCGEN docx write FAILED -- fail loud\n" as *u8); return 1 }
251
252 let csp: *i64 = sys_mmap(16) as *i64
253 let content: *u8 = dg_readall(tmp, csp)
254 let csz: i64 = csp[0]
255 if csz <= 0 { dg_p("VIZSLA-DOCGEN docx readback FAILED -- fail loud\n" as *u8); return 1 }
256 if csz > K_MAGIC_524288 { dg_p("VIZSLA-DOCGEN docx exceeds 512KB -- fail loud\n" as *u8); return 1 }
257
258 let st: i64 = dg_store_doc(prefix, docid, dtype, rel, date, content, csz, segid)
259 if st < 0 { dg_p("VIZSLA-DOCGEN doc-store FAILED -- fail loud\n" as *u8); return 1 }
260
261 let rep: *u8 = sys_mmap(K_MAGIC_1024)
262 var o: i64 = 0
263 o = dg_cat(rep, o, "VIZSLA-DOCGEN docid=" as *u8)
264 o = dg_cat(rep, o, docid)
265 o = dg_cat(rep, o, " doctype=" as *u8)
266 o = dg_cat(rep, o, dtype)
267 o = dg_cat(rep, o, " rel=" as *u8)
268 o = dg_cat(rep, o, rel)
269 o = dg_cat(rep, o, " date=" as *u8)
270 o = dg_cat(rep, o, date)
271 o = dg_cat(rep, o, " paras=" as *u8)
272 o = dg_catn(rep, o, np)
273 o = dg_cat(rep, o, " docx_bytes=" as *u8)
274 o = dg_catn(rep, o, csz)
275 o = dg_cat(rep, o, " stored=" as *u8)
276 o = dg_catn(rep, o, st)
277 o = dg_cat(rep, o, " segment=" as *u8)
278 if st == 1 {
279 o = dg_cat(rep, o, "seg-" as *u8)
280 o = dg_catn(rep, o, segid)
281 } else {
282 o = dg_cat(rep, o, "none" as *u8)
283 }
284 o = dg_cat(rep, o, "\n" as *u8)
285 sys_write(1, rep, o)
286 return 0
287}
288
289func main(argc: i64, argv: *i64) -> i64 {
290 if argc < 2 { dg_p("VIZSLA-DOCGEN usage: build <docprefix> <docid> <doctype> <rel> <date> <fieldsfile> [segid] -- fail loud\n" as *u8); return 1 }
291 let cmd: *u8 = argv[1] as *u8
292 if dg_eq(cmd, "build" as *u8) == 1 { return dg_cmd_build(argc, argv) }
293 dg_p("VIZSLA-DOCGEN unknown command (build) -- fail loud\n" as *u8)
294 return 1
295}