nx_office_serve.nx source
↩ module page · 3769 lines · 237163 B
1// nx_office_serve.nx -- NISHI OFFICE v1, the PRODUCT surface over the gated format organs (operator 2026-07-09:
2// "we need to build our own nishi office"). Until now the suite was organs + scattered sample pages; THIS organ is
3// the office: a zero-JS web app where a family member CREATES, EDITS, VERSIONS, PREVIEWS and DOWNLOADS real
4// documents / spreadsheets / decks. Every save = a NEW version (v1,v2,...) -- nothing is ever overwritten; that
5// additive never-lose history is the suite's one measured exceed, now surfaced as the product spine.
6// Engines (forked ELFs, the gated organs): doc = _offc/nx_docx.elf writerich (H/B/I/P + T pipe-cells) ?
7// sheet = _offc/nx_xlsx.elf fromtsv (TSV grid, =SUM/AVERAGE/MIN/MAX/COUNT formulas) ? deck = _offc/nx_pptx.elf
8// fromspec (S title / B bullet). Preview = each organ's own html mode. Honest v1 scope: SPEC editors (plain
9// textarea round-trip), NOT WYSIWYG -- that is the named next rung, along with co-edit (CRDT) and in-app AI.
10// Layout under <root>/: index.txt (append-only name\tkind registry) + <name>/manifest.txt (append-only
11// v<N>\t<kind>\t<usec> lines) + <name>/v<N>/{spec.txt, file.<ext>, preview.html}.
12// PURE CORE (no main): of_handle (request -> response), of_read_req/of_write_all (fd shells), of_selftest (the
13// offline gate body). Consumers: _hdl_build/nx_office_gate (offline gate) + _hdl_build/nx_office_daemon (accept
14// loop, port 8030). Same discipline as nx_relate_serve. license_tier: ORIGINAL
15import "nx_tool_run.nx"
16import "nx_gate_verdict.nx" // D001: the selftest's teeth inherit the shared verdict base (gv_check / gv_verdict)
17import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
18import "nx_itoa_lib.nx" // shared integer emitter: nxi_out (fd) and nxi_buf (NUL-free buffer form)
19import "nx_rebac.nx" // the shared ReBAC plane: doc ownership + sharing are rb_ tuples (doc:<name> owner|viewer|editor)
20import "nx_http_client.nx" // loopback POST to our own sovereign LLM seat (:11434) for in-app AI drafting
21import "nx_multipart.nx" // RFC 7578 multipart/form-data parser (the docportal's proven <input type=file> path) -- LP1 import
22import "nx_sign_ceremony_lib.nx" // UETA consent-gated signing over the hash-chained audit + sealed certificate -- LP4 sign-from-version
23
24// office authz store. The office daemon runs as ELDERWESTO (its reconcile cron), NOT root -- so the store must be
25// in the elderwesto-writable cwd (nishihost/officeauthz_*), NOT the root-owned knowledge/status/ (which relate,
26// running as root, created). Tuples live OUTSIDE office/ so they never render as documents. A doc with NO owner
27// tuple stays PUBLIC (legacy/demo -> non-breaking).
28const OF_AUTHZ: *u8 = "officeauthz_"
29const OF_RELATE: *u8 = "knowledge/status/relate_"
30
31func p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
32// MIGRATED to the shared emitter (debt 1785557603): the old body mmapped TWO buffers per call
33// (LSB-first digits + a reverse buffer) and freed neither. nxi_out is the ONE shim, always balanced.
34func pn(v: i64) -> i64 { nxi_out(v); return 0 }
35func of_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
36func of_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i }
37func of_catc(dst: *u8, off: i64, code: i64) -> i64 { dst[off] = code as u8; return off + 1 }
38// MIGRATED to nxi_buf, the NUL-FREE shared form. The old body mmapped a reverse buffer per call and
39// never freed it -- and this function has 60 CALL SITES, so the leak was per-call in a long-lived
40// server. nxi_buf is MSB-first (allocates nothing) and, unlike ccz_cat_num, writes NO byte past the
41// returned offset -- gate tooth T15 proves that difference by biting.
42func of_catn(dst: *u8, off: i64, v: i64) -> i64 { return nxi_buf(dst, off, v) }
43func of_seq(a: *u8, b: *u8) -> i64 {
44 var i: i64 = 0
45 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
46 if b[i] != (0 as u8) { return 0 }
47 return 1
48}
49func of_starts(s: *u8, pfx: *u8) -> i64 { var i: i64 = 0; while pfx[i] != (0 as u8) { if s[i] != pfx[i] { return 0 } i = i + 1 } return 1 }
50func of_memhas(buf: *u8, n: i64, needle: *u8) -> i64 {
51 let nl: i64 = of_slen(needle)
52 if nl == 0 { return 0 }
53 var i: i64 = 0
54 while i + nl <= n {
55 var k: i64 = 0; var hit: i64 = 1
56 while k < nl { if buf[i+k] != needle[k] { hit = 0; k = nl } else { k = k + 1 } }
57 if hit == 1 { return 1 }
58 i = i + 1
59 }
60 return 0
61}
62// escape & < > while appending a NUL-terminated string (safe for html text and textarea content)
63func of_esc(dst: *u8, off: i64, s: *u8) -> i64 {
64 var o: i64 = off; var i: i64 = 0
65 while s[i] != (0 as u8) {
66 let c: i64 = s[i] as i64
67 if c == 38 { o = of_cat(dst, o, "&" as *u8) } else {
68 if c == 60 { o = of_cat(dst, o, "<" as *u8) } else {
69 if c == 62 { o = of_cat(dst, o, ">" as *u8) } else { dst[o] = s[i]; o = o + 1 } } }
70 i = i + 1
71 }
72 return o
73}
74func of_hexval(c: i64) -> i64 {
75 if c >= 48 { if c <= 57 { return c - 48 } }
76 if c >= 65 { if c <= 70 { return c - 55 } }
77 if c >= 97 { if c <= 102 { return c - 87 } }
78 return 0
79}
80// urldecode form value for key from body (handles + and %XX). proven pattern (nx_relate_serve).
81func of_form_get(body: *u8, blen: i64, key: *u8, out: *u8, cap: i64) -> i64 {
82 let kl: i64 = of_slen(key)
83 var i: i64 = 0
84 while i < blen {
85 var atk: i64 = 0
86 if i == 0 { atk = 1 } else { if body[i-1] == (38 as u8) { atk = 1 } }
87 if atk == 1 {
88 var m: i64 = 1; var j: i64 = 0
89 while j < kl { if i + j >= blen { m = 0; j = kl } else { if body[i+j] != key[j] { m = 0; j = kl } else { j = j + 1 } } }
90 if m == 1 { if i + kl < blen { if body[i+kl] == (61 as u8) {
91 var q: i64 = i + kl + 1; var t: i64 = 0
92 var go: i64 = 1
93 while go == 1 {
94 if q >= blen { go = 0 } else {
95 let c: i64 = body[q] as i64
96 if c == 38 { go = 0 } else {
97 var ch: i64 = c
98 if c == 43 { ch = 32 }
99 if c == 37 { if q + 2 < blen { ch = of_hexval(body[q+1] as i64) * 16 + of_hexval(body[q+2] as i64); q = q + 2 } }
100 if t < cap - 1 { out[t] = ch as u8; t = t + 1 }
101 q = q + 1
102 }
103 }
104 }
105 out[t] = 0 as u8; return t
106 } } }
107 }
108 i = i + 1
109 }
110 out[0] = 0 as u8; return 0
111}
112func of_write_all(fd: i64, buf: *u8, n: i64) -> i64 {
113 var w: i64 = 0
114 while w < n { let k: i64 = sys_write(fd, (buf as i64 + w) as *u8, n - w); if k <= 0 { return 0 - 1 } w = w + k }
115 return 0
116}
117// read ONE full HTTP request: headers until CRLFCRLF plus Content-Length body. proven pattern.
118func of_read_req(fd: i64, buf: *u8, cap: i64) -> i64 {
119 var n: i64 = 0
120 var hdr_end: i64 = 0 - 1
121 var want: i64 = 0 - 1
122 var go: i64 = 1
123 while go == 1 {
124 if n >= cap - 1 { go = 0 } else {
125 let r: i64 = sys_read(fd, (buf as i64 + n) as *u8, cap - 1 - n)
126 if r <= 0 { go = 0 } else {
127 n = n + r
128 if hdr_end < 0 {
129 var i: i64 = 0
130 while i + 3 < n {
131 if buf[i] == (13 as u8) { if buf[i+1] == (10 as u8) { if buf[i+2] == (13 as u8) { if buf[i+3] == (10 as u8) { hdr_end = i + 4; i = n } } } }
132 i = i + 1
133 }
134 if hdr_end >= 0 {
135 var cl: i64 = 0 - 1
136 let key: *u8 = "Content-Length:" as *u8
137 let kl: i64 = 15
138 var j: i64 = 0
139 while j + kl < hdr_end {
140 var m: i64 = 1
141 var q: i64 = 0
142 while q < kl { if buf[j+q] != key[q] { m = 0; q = kl } else { q = q + 1 } }
143 if m == 1 {
144 var v: i64 = 0
145 var t: i64 = j + kl
146 while t < hdr_end {
147 let c: i64 = buf[t] as i64
148 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } }
149 if c == 13 { t = hdr_end }
150 t = t + 1
151 }
152 cl = v
153 j = hdr_end
154 }
155 j = j + 1
156 }
157 if cl < 0 { want = hdr_end } else { want = hdr_end + cl }
158 }
159 }
160 if want >= 0 { if n >= want { go = 0 } }
161 }
162 }
163 }
164 return n
165}
166func of_read_file(path: *u8, buf: *u8, cap: i64) -> i64 {
167 let fd: i64 = sys_openat_rd(path)
168 if fd < 0 { return 0 - 1 }
169 var tot: i64 = 0
170 while tot < cap { let r: i64 = sys_read(fd, (buf as i64 + tot) as *u8, cap - tot); if r <= 0 { break } tot = tot + r }
171 sys_close(fd)
172 return tot
173}
174func of_write_file(path: *u8, buf: *u8, n: i64) -> i64 {
175 let fd: i64 = sys_openat_wr(path, 420)
176 if fd < 0 { return 0 - 1 }
177 let rc: i64 = of_write_all(fd, buf, n)
178 sys_close(fd)
179 return rc
180}
181// extract a header value (key like "Origin:") from the header region; trims one leading space; stops at CR.
182func of_hdr_get(req: *u8, reqlen: i64, key: *u8, out: *u8, cap: i64) -> i64 {
183 out[0] = 0 as u8
184 var he: i64 = reqlen
185 var i: i64 = 0
186 while i + 3 < reqlen {
187 if req[i] == (13 as u8) { if req[i+1] == (10 as u8) { if req[i+2] == (13 as u8) { if req[i+3] == (10 as u8) { he = i; i = reqlen } } } }
188 i = i + 1
189 }
190 let kl: i64 = of_slen(key)
191 var j: i64 = 0
192 while j + kl < he {
193 var m: i64 = 1
194 var q: i64 = 0
195 while q < kl { if req[j+q] != key[q] { m = 0; q = kl } else { q = q + 1 } }
196 if m == 1 {
197 var t: i64 = j + kl
198 if req[t] == (32 as u8) { t = t + 1 }
199 var o: i64 = 0
200 while t < he { if req[t] == (13 as u8) { t = he } else { if o < cap - 1 { out[o] = req[t]; o = o + 1 } t = t + 1 } }
201 out[o] = 0 as u8
202 return o
203 }
204 j = j + 1
205 }
206 return 0
207}
208func of_atoi(s: *u8) -> i64 {
209 var v: i64 = 0
210 var i: i64 = 0
211 while s[i] != (0 as u8) {
212 let d: i64 = (s[i] as i64) - 48
213 if d >= 0 { if d <= 9 { v = v * 10 + d } }
214 i = i + 1
215 }
216 return v
217}
218
219// ---- domain: names, kinds, layout ----
220func of_name_ok(name: *u8) -> i64 {
221 var i: i64 = 0
222 while name[i] != (0 as u8) {
223 let c: i64 = name[i] as i64
224 var ok: i64 = 0
225 if c >= 97 { if c <= 122 { ok = 1 } }
226 if c >= 48 { if c <= 57 { ok = 1 } }
227 if c == 45 { ok = 1 }
228 if ok == 0 { return 0 }
229 i = i + 1
230 }
231 if i < 1 { return 0 }
232 if i > 40 { return 0 }
233 return 1
234}
235func of_kind_idx(kind: *u8) -> i64 {
236 if of_seq(kind, "doc" as *u8) == 1 { return 0 }
237 if of_seq(kind, "sheet" as *u8) == 1 { return 1 }
238 if of_seq(kind, "deck" as *u8) == 1 { return 2 }
239 return 0 - 1
240}
241func of_ext(k: i64) -> *u8 {
242 if k == 0 { return "docx" as *u8 }
243 if k == 1 { return "xlsx" as *u8 }
244 return "pptx" as *u8
245}
246func of_elf(k: i64) -> *u8 {
247 if k == 0 { return "_offc/nx_docx.elf" as *u8 }
248 if k == 1 { return "_offc/nx_xlsx.elf" as *u8 }
249 return "_offc/nx_pptx.elf" as *u8
250}
251func of_ct(k: i64) -> *u8 {
252 if k == 0 { return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" as *u8 }
253 if k == 1 { return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" as *u8 }
254 return "application/vnd.openxmlformats-officedocument.presentationml.presentation" as *u8
255}
256func of_kind_name(k: i64) -> *u8 {
257 if k == 0 { return "doc" as *u8 }
258 if k == 1 { return "sheet" as *u8 }
259 return "deck" as *u8
260}
261// versions so far for <name> (0 = does not exist); kind of the file copied into kindout.
262func of_manifest_count(root: *u8, name: *u8, kindout: *u8, kcap: i64) -> i64 {
263 kindout[0] = 0 as u8
264 let mp: *u8 = sys_mmap(512)
265 var o: i64 = of_cat(mp, 0, root); o = of_cat(mp, o, "/" as *u8); o = of_cat(mp, o, name); o = of_cat(mp, o, "/manifest.txt" as *u8); mp[o] = 0 as u8
266 let buf: *u8 = sys_mmap(65536)
267 let n: i64 = of_read_file(mp, buf, 65536)
268 if n <= 0 { return 0 }
269 var lines: i64 = 0
270 var i: i64 = 0
271 while i < n { if buf[i] == (10 as u8) { lines = lines + 1 } i = i + 1 }
272 // kind = field 2 of the FIRST line (v<N> \t kind \t usec)
273 var t: i64 = 0
274 while t < n { if buf[t] == (9 as u8) { break } t = t + 1 }
275 t = t + 1
276 var ko: i64 = 0
277 while t < n { if buf[t] == (9 as u8) { t = n } else { if buf[t] == (10 as u8) { t = n } else { if ko < kcap - 1 { kindout[ko] = buf[t]; ko = ko + 1 } t = t + 1 } } }
278 kindout[ko] = 0 as u8
279 return lines
280}
281// build "<root>/<name>/v<N>" into out, return offset
282func of_vdir(root: *u8, name: *u8, vn: i64, out: *u8) -> i64 {
283 var o: i64 = of_cat(out, 0, root); o = of_cat(out, o, "/" as *u8); o = of_cat(out, o, name); o = of_cat(out, o, "/v" as *u8); o = of_catn(out, o, vn)
284 out[o] = 0 as u8
285 return o
286}
287// append one line to an append-only file (creates if missing)
288func of_append_line(path: *u8, line: *u8, n: i64) -> i64 {
289 let fd: i64 = sys_openat_append(path, 420)
290 if fd < 0 { return 0 - 1 }
291 let rc: i64 = of_write_all(fd, line, n)
292 sys_close(fd)
293 return rc
294}
295// ---- PER-DOCUMENT LOCK (2026-08-19, measured regression from the fork-per-request daemon) --------------------
296// of_save / of_import / of_sign_version are read-modify-writes (manifest count -> mkdir v<N+1> -> append row;
297// sign.head read -> chain -> write) that the old serial accept loop protected BY ACCIDENT. Fork-per-request removed
298// that accident and the race was MEASURED live: 4 concurrent creates of one name -> TWO v1 manifest rows (one
299// writer's artifacts silently clobbered) + two 500s. The lock is per document ("<root>/<name>.lock", the estate's
300// <prefix>plock idiom), taken in thin wrappers so every caller -- /save, /restore, /import, /sign -- inherits it
301// and no body return path can leak it. flock is per open file description, and no body takes this lock again, so
302// self-deadlock is impossible by construction. Fail-open on OPEN failure (loud, behaviour = the pre-lock daemon):
303// wrong in the direction of doing nothing new.
304const OF_LOCK_EX: i64 = 2
305const OF_LOCK_UN: i64 = 8
306const OF_LOCKMODE: i64 = 420
307func of_doc_lock(root: *u8, name: *u8) -> i64 {
308 let lkp: *u8 = sys_mmap(600)
309 var o: i64 = of_cat(lkp, 0, root)
310 o = of_cat(lkp, o, "/" as *u8)
311 o = of_cat(lkp, o, name)
312 o = of_cat(lkp, o, ".lock" as *u8)
313 lkp[o] = 0 as u8
314 let fd: i64 = sys_openat_append(lkp, OF_LOCKMODE)
315 sys_munmap(lkp, 600)
316 if fd < 0 { p("OF-DOC-LOCK open-failed (proceeding UNLOCKED, the pre-lock behaviour)
317" as *u8); return 0 - 1 }
318 sys_flock(fd, OF_LOCK_EX)
319 return fd
320}
321func of_doc_unlock(fd: i64) -> i64 {
322 if fd < 0 { return 0 }
323 sys_flock(fd, OF_LOCK_UN)
324 sys_close(fd)
325 return 0
326}
327// SAVE: validate -> new version dir -> spec -> fork the format organ (artifact) -> fork html (preview) ->
328// register in manifest (+ index on v1). auto=1 (background autosave) tags the manifest line with an ADDITIVE
329// 4th field "auto" -- older parsers read fields 1-3 unchanged. Returns the new version N, or a LOUD negative:
330// -1 invalid name/kind/spec -2 kind mismatch with existing file -3 organ build failed -4 preview failed
331func of_save(root: *u8, base: *u8, name: *u8, kind: *u8, spec: *u8, sl: i64, auto: i64) -> i64 {
332 if of_name_ok(name) == 0 { return 0 - 1 }
333 sys_mkdir(root, 493)
334 let lk: i64 = of_doc_lock(root, name)
335 let rc: i64 = of_save_body(root, base, name, kind, spec, sl, auto)
336 of_doc_unlock(lk)
337 return rc
338}
339func of_save_body(root: *u8, base: *u8, name: *u8, kind: *u8, spec: *u8, sl: i64, auto: i64) -> i64 {
340 if of_name_ok(name) == 0 { return 0 - 1 }
341 let k: i64 = of_kind_idx(kind)
342 if k < 0 { return 0 - 1 }
343 if sl <= 0 { return 0 - 1 }
344 if sl > 131072 { return 0 - 1 }
345 sys_mkdir(root, 493)
346 let nd: *u8 = sys_mmap(512)
347 var no: i64 = of_cat(nd, 0, root); no = of_cat(nd, no, "/" as *u8); no = of_cat(nd, no, name); nd[no] = 0 as u8
348 sys_mkdir(nd, 493)
349 let kbuf: *u8 = sys_mmap(64)
350 let cur: i64 = of_manifest_count(root, name, kbuf, 64)
351 if cur > 0 { if of_seq(kbuf, kind) == 0 { return 0 - 2 } }
352 let vn: i64 = cur + 1
353 let vd: *u8 = sys_mmap(512)
354 of_vdir(root, name, vn, vd)
355 sys_mkdir(vd, 493)
356 let specp: *u8 = sys_mmap(600)
357 var so: i64 = of_cat(specp, 0, vd); so = of_cat(specp, so, "/spec.txt" as *u8); specp[so] = 0 as u8
358 if of_write_file(specp, spec, sl) != 0 { return 0 - 3 }
359 let artp: *u8 = sys_mmap(600)
360 let ext: *u8 = of_ext(k)
361 var ao: i64 = of_cat(artp, 0, vd); ao = of_cat(artp, ao, "/file." as *u8); ao = of_cat(artp, ao, ext); artp[ao] = 0 as u8
362 let prevp: *u8 = sys_mmap(600)
363 var po: i64 = of_cat(prevp, 0, vd); po = of_cat(prevp, po, "/preview.html" as *u8); prevp[po] = 0 as u8
364 let dlu: *u8 = sys_mmap(600)
365 var du: i64 = of_cat(dlu, 0, base); du = of_cat(dlu, du, "/file/" as *u8); du = of_cat(dlu, du, name); du = of_cat(dlu, du, "/v" as *u8); du = of_catn(dlu, du, vn); dlu[du] = 0 as u8
366 let elf: *u8 = of_elf(k)
367 let av: *i64 = sys_mmap(8 * 8) as *i64
368 av[0] = elf as i64
369 if k == 0 { av[1] = "writerich" as *u8 as i64; av[2] = artp as i64; av[3] = specp as i64 } else {
370 if k == 1 { av[1] = "fromtsv" as *u8 as i64; av[2] = specp as i64; av[3] = artp as i64 } else {
371 av[1] = "fromspec" as *u8 as i64; av[2] = specp as i64; av[3] = artp as i64 } }
372 av[4] = 0
373 let capbuf: *u8 = sys_mmap(65536)
374 let ol: *i64 = sys_mmap(16) as *i64
375 let rc: i64 = tr_run_capture(elf, av, capbuf, 65536, ol)
376 if rc != 0 { return 0 - 3 }
377 let av2: *i64 = sys_mmap(8 * 8) as *i64
378 av2[0] = elf as i64
379 av2[1] = "html" as *u8 as i64
380 av2[2] = artp as i64
381 av2[3] = prevp as i64
382 av2[4] = dlu as i64
383 av2[5] = 0
384 let rc2: i64 = tr_run_capture(elf, av2, capbuf, 65536, ol)
385 if rc2 != 0 { return 0 - 4 }
386 let mp: *u8 = sys_mmap(600)
387 var mo: i64 = of_cat(mp, 0, nd); mo = of_cat(mp, mo, "/manifest.txt" as *u8); mp[mo] = 0 as u8
388 let line: *u8 = sys_mmap(256)
389 var lo: i64 = of_cat(line, 0, "v" as *u8); lo = of_catn(line, lo, vn); lo = of_catc(line, lo, 9); lo = of_cat(line, lo, kind); lo = of_catc(line, lo, 9); lo = of_catn(line, lo, sys_now_us())
390 if auto == 1 { lo = of_catc(line, lo, 9); lo = of_cat(line, lo, "auto" as *u8) }
391 lo = of_catc(line, lo, 10)
392 if of_append_line(mp, line, lo) != 0 { return 0 - 3 }
393 if vn == 1 {
394 let ip: *u8 = sys_mmap(600)
395 var io: i64 = of_cat(ip, 0, root); io = of_cat(ip, io, "/index.txt" as *u8); ip[io] = 0 as u8
396 let il: *u8 = sys_mmap(256)
397 var ilo: i64 = of_cat(il, 0, name); ilo = of_catc(il, ilo, 9); ilo = of_cat(il, ilo, kind); ilo = of_catc(il, ilo, 10)
398 of_append_line(ip, il, ilo)
399 }
400 return vn
401}
402
403// ---- pages (zero-JS, sovereign styling, no hash-colors) ----
404func of_css(out: *u8, off: i64) -> i64 {
405 // CSS custom properties drive light/dark so the JS theme toggle is one class flip (:root.dark / :root.light);
406 // system preference wins unless the user chose. U-axes rung: app shell, card grid, thumbnails, transitions.
407 var o: i64 = off
408 // canonical --nx-color tokens (fleet bar / ui_rubric) with local shorthand ALIASES so every existing
409 // var(--bg)-style usage keeps working; dark redefines only the canon and the aliases follow.
410 o = of_cat(out, o, "<style>:root{--nx-color-bg:rgb(244,246,251);--nx-color-ink:rgb(23,25,35);--nx-color-surface:rgb(255,255,255);--nx-color-line:rgb(224,227,237);--nx-color-muted:rgb(107,112,128);--nx-color-accent:rgb(41,84,164);--nx-radius:12px;--bg:var(--nx-color-bg);--fg:var(--nx-color-ink);--card:var(--nx-color-surface);--line:var(--nx-color-line);--muted:var(--nx-color-muted);--acc:var(--nx-color-accent);--accfg:rgb(255,255,255);--accbg:rgb(234,240,252);--soft:rgb(249,250,253);--sh:rgba(20,28,55,0.07);--sh2:rgba(20,28,55,0.16);--mark:rgb(255,233,148);--good:rgb(21,110,48)}\n" as *u8)
411 o = of_cat(out, o, "@media(prefers-color-scheme:dark){:root:not(.light){--nx-color-bg:rgb(13,14,19);--nx-color-ink:rgb(226,228,238);--nx-color-surface:rgb(21,23,31);--nx-color-line:rgb(42,45,58);--nx-color-muted:rgb(146,150,165);--nx-color-accent:rgb(124,163,235);--accfg:rgb(16,22,38);--accbg:rgb(31,39,60);--soft:rgb(17,19,26);--sh:rgba(0,0,0,0.4);--sh2:rgba(0,0,0,0.55);--mark:rgb(126,100,14);--good:rgb(89,196,124)}}\n" as *u8)
412 o = of_cat(out, o, ":root.dark{--nx-color-bg:rgb(13,14,19);--nx-color-ink:rgb(226,228,238);--nx-color-surface:rgb(21,23,31);--nx-color-line:rgb(42,45,58);--nx-color-muted:rgb(146,150,165);--nx-color-accent:rgb(124,163,235);--accfg:rgb(16,22,38);--accbg:rgb(31,39,60);--soft:rgb(17,19,26);--sh:rgba(0,0,0,0.4);--sh2:rgba(0,0,0,0.55);--mark:rgb(126,100,14);--good:rgb(89,196,124)}\n" as *u8)
413 o = of_cat(out, o, "*{box-sizing:border-box}html{scroll-behavior:smooth}body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--fg);margin:0;line-height:1.55;font-size:clamp(15px,1vw + 12px,17px)}\n" as *u8)
414 o = of_cat(out, o, "a{color:var(--acc)}h1{margin:0 0 2px;font-size:clamp(20px,2.6vw,26px)}h2{font-size:clamp(15px,1.8vw,18px);margin:22px 0 4px}.sub{color:var(--muted);margin:0 0 14px}\n" as *u8)
415 // fleet-bar accessibility + motion: skip-link, visible keyboard focus, entrance rise (stagger via
416 // nth-child), and a reduced-motion kill-switch.
417 o = of_cat(out, o, ".skip-link{position:absolute;left:-999px;top:0;background:var(--acc);color:rgb(255,255,255);padding:12px 16px;z-index:99;border-radius:0 0 8px 0}.skip-link:focus{left:0}\n" as *u8)
418 o = of_cat(out, o, ":focus-visible{outline:2px solid var(--acc);outline-offset:2px}.top input[type=text]:focus-visible{outline:0}\n" as *u8)
419 o = of_cat(out, o, "@keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}main>*{animation:rise .35s ease both}main>*:nth-child(2){animation-delay:.06s}main>*:nth-child(3){animation-delay:.12s}main>*:nth-child(4){animation-delay:.18s}\n" as *u8)
420 o = of_cat(out, o, "@media(prefers-reduced-motion:reduce){main>*{animation:none}.fcard,button,.chips a,.top input[type=text],.thm{transition:none}html{scroll-behavior:auto}}\n" as *u8)
421 o = of_cat(out, o, ".top{position:sticky;top:0;z-index:9;padding:5px 20px;background:var(--card);border-bottom:1px solid var(--line);box-shadow:0 1px 10px var(--sh)}.top nav{display:flex;align-items:center;gap:12px;max-width:1200px;margin:0 auto}\n" as *u8)
422 o = of_cat(out, o, ".logo{width:30px;height:30px;min-width:30px;border-radius:8px;background:linear-gradient(135deg,rgb(64,110,200),rgb(35,66,132))}\n" as *u8)
423 o = of_cat(out, o, "a.bname{display:inline-flex;align-items:center;gap:9px;min-height:44px;font-weight:700;font-size:1.02rem;color:var(--fg);text-decoration:none;white-space:nowrap}.top form{flex:1;max-width:560px;margin:0}\n" as *u8)
424 o = of_cat(out, o, ".top input[type=text]{width:100%;border:1px solid var(--line);border-radius:20px;padding:8px 16px;font-size:.93rem;background:var(--soft);color:var(--fg);transition:border-color .15s,box-shadow .15s}.top input[type=text]:focus{outline:0;border-color:var(--acc);box-shadow:0 0 0 3px var(--accbg)}\n" as *u8)
425 o = of_cat(out, o, ".thm{display:none;margin-left:auto;background:transparent;color:var(--muted);border:1px solid var(--line);border-radius:16px;padding:5px 12px;font-size:.8rem;cursor:pointer;transition:color .15s,border-color .15s}.js .thm{display:block}.thm:hover{color:var(--acc);border-color:var(--acc)}\n" as *u8)
426 o = of_cat(out, o, ".wrap{max-width:1200px;margin:0 auto;padding:16px 20px 44px}\n" as *u8)
427 o = of_cat(out, o, ".card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:16px 18px;margin:14px 0}\n" as *u8)
428 o = of_cat(out, o, "table{border-collapse:collapse;width:100%}th,td{text-align:left;padding:7px 10px;border-bottom:1px solid var(--line);font-size:.95rem}thead th{color:var(--muted);font-weight:600;font-size:.85rem}\n" as *u8)
429 o = of_cat(out, o, ".k{display:inline-block;padding:1px 10px;border-radius:20px;font-size:.8rem;font-weight:600;color:rgb(255,255,255)}.k0{background:rgb(41,84,164)}.k1{background:rgb(26,127,55)}.k2{background:rgb(178,106,0)}\n" as *u8)
430 o = of_cat(out, o, "textarea{width:100%;min-height:220px;font-family:ui-monospace,Consolas,monospace;font-size:.92rem;border:1px solid var(--line);border-radius:8px;padding:10px;background:var(--soft);color:var(--fg)}\n" as *u8)
431 o = of_cat(out, o, "input[type=text]{border:1px solid var(--line);border-radius:8px;padding:7px 10px;font-size:.95rem;background:var(--soft);color:var(--fg)}\n" as *u8)
432 o = of_cat(out, o, "button{background:var(--acc);color:var(--accfg);border:0;border-radius:8px;padding:9px 18px;font-size:.95rem;font-weight:600;cursor:pointer;transition:filter .15s,transform .1s}button:hover{filter:brightness(1.08)}button:active{transform:scale(.97)}button.ghost{background:var(--soft);color:var(--acc);border:1px solid var(--line);padding:4px 12px;font-size:.82rem}button.ghost:hover{filter:none;border-color:var(--acc)}\n" as *u8)
433 o = of_cat(out, o, ".hint{color:var(--muted);font-size:.85rem;margin-top:6px}.foot{max-width:1200px;margin:26px auto 0;padding:10px 20px 20px;color:var(--muted);font-size:.8rem;border-top:1px solid var(--line)}\n" as *u8)
434 // ---- home: create tiles, files header (chips + sort), card grid with REAL thumbnails, empty states
435 o = of_cat(out, o, ".newrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:12px;margin:10px 0 4px}\n" as *u8)
436 o = of_cat(out, o, ".newt{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:12px 14px;transition:box-shadow .18s,border-color .18s}.newt:hover{border-color:var(--acc);box-shadow:0 4px 14px var(--sh)}.newt h3{margin:0 0 8px;font-size:.95rem;display:flex;align-items:center;gap:8px}.newt p{margin:8px 0 0}.newt p.row{display:flex;gap:8px}.newt input[type=text]{flex:1;min-width:0}.newt button{padding:7px 14px;font-size:.88rem}\n" as *u8)
437 o = of_cat(out, o, ".fico{width:26px;height:26px;min-width:26px;border-radius:7px;color:rgb(255,255,255);font-weight:700;font-size:.7rem;display:flex;align-items:center;justify-content:center}\n" as *u8)
438 o = of_cat(out, o, ".fhead{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:20px 0 2px}.fhead h1{margin:0;font-size:clamp(17px,2vw,21px)}.cnt{color:var(--muted);font-size:.85rem;font-weight:400}\n" as *u8)
439 o = of_cat(out, o, ".chips{display:flex;gap:6px;flex-wrap:wrap}.chips a{text-decoration:none;font-size:.82rem;font-weight:600;padding:4px 14px;min-height:44px;display:inline-flex;align-items:center;border-radius:22px;border:1px solid var(--line);color:var(--muted);transition:color .15s,border-color .15s,background .15s}.chips a:hover{color:var(--acc);border-color:var(--acc)}.chips a.on{background:var(--accbg);color:var(--acc);border-color:var(--acc)}\n" as *u8)
440 o = of_cat(out, o, ".sortl{margin-left:auto;display:flex;align-items:center;font-size:.82rem;color:var(--muted)}.sortl a{text-decoration:none;margin-left:4px;color:var(--muted);min-height:44px;display:inline-flex;align-items:center;padding:0 6px}.sortl a.on{font-weight:700;color:var(--acc)}\n" as *u8)
441 o = of_cat(out, o, ".fgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(225px,1fr));gap:14px;margin-top:12px}\n" as *u8)
442 o = of_cat(out, o, ".fcard{display:block;background:var(--card);border:1px solid var(--line);border-radius:12px;overflow:hidden;text-decoration:none;color:var(--fg);transition:box-shadow .18s,transform .18s,border-color .18s}.fcard:hover{transform:translateY(-2px);border-color:var(--acc);box-shadow:0 8px 22px var(--sh2)}\n" as *u8)
443 o = of_cat(out, o, ".thumb{height:128px;overflow:hidden;background:var(--soft);border-bottom:1px solid var(--line);padding:10px 12px;pointer-events:none}\n" as *u8)
444 o = of_cat(out, o, ".tdoc{font-size:.55rem;line-height:1.5;color:var(--fg)}.tdoc .th{font-weight:700;font-size:.72rem;margin:0 0 2px}.tdoc .tb{font-weight:700}.tdoc .ti{font-style:italic}\n" as *u8)
445 o = of_cat(out, o, "table.tsheet{border-collapse:collapse;font-size:.55rem;width:auto}table.tsheet td{border:1px solid var(--line);padding:2px 6px;max-width:64px;overflow:hidden;white-space:nowrap}table.tsheet tr:first-child td{background:var(--accbg);font-weight:700}\n" as *u8)
446 o = of_cat(out, o, ".tslide{border:1px solid var(--line);border-radius:6px;background:var(--card);padding:8px 10px;box-shadow:0 2px 6px var(--sh)}.tslide .tst{font-weight:700;font-size:.66rem;margin-bottom:3px}.tslide .tsb{font-size:.55rem;color:var(--muted)}\n" as *u8)
447 o = of_cat(out, o, ".fmeta{display:flex;align-items:center;gap:9px;padding:10px 12px}.fmeta .nm{min-width:0}.fmeta .nm b{display:block;font-size:.9rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fmeta .nm span{font-size:.76rem;color:var(--muted)}\n" as *u8)
448 o = of_cat(out, o, ".empty{text-align:center;padding:44px 20px;color:var(--muted)}.empty .row{display:flex;gap:10px;justify-content:center;margin-bottom:14px}.empty .fico{width:38px;height:38px;font-size:.95rem;border-radius:10px}.empty h2{margin:0 0 4px;color:var(--fg)}.empty p{margin:0}\n" as *u8)
449 // ---- editor page: crumb, saved stamp, find highlights
450 o = of_cat(out, o, ".stamp{display:inline-block;margin-left:10px;font-size:.78rem;font-weight:600;color:var(--good);background:var(--accbg);border-radius:12px;padding:2px 10px;vertical-align:middle}\n" as *u8)
451 o = of_cat(out, o, "mark.fm{background:var(--mark);color:inherit;border-radius:2px;padding:0 1px}mark.fm.cur{outline:2px solid var(--acc)}\n" as *u8)
452 // ---- visual editor (WYSIWYG surfaces; hidden until app.js flips html.js -> progressive enhancement)
453 o = of_cat(out, o, ".starter{display:none}.toolbar{display:none;flex-wrap:wrap;gap:6px;margin:0 0 10px;align-items:center}.js .toolbar{display:flex}\n" as *u8)
454 o = of_cat(out, o, ".toolbar button{background:var(--accbg);color:var(--acc);padding:5px 11px;font-size:.85rem;font-weight:600}.findw{display:flex;gap:6px;margin-left:auto;align-items:center}.findw input{padding:5px 10px;font-size:.85rem;border-radius:16px;max-width:150px}\n" as *u8)
455 o = of_cat(out, o, ".visual{display:none}.js .visual{display:block}[contenteditable]{outline:0}[contenteditable]:focus-within,[contenteditable]:focus{box-shadow:0 0 0 2px var(--accbg)}\n" as *u8)
456 o = of_cat(out, o, ".doc{border:1px solid var(--line);border-radius:8px;padding:14px 16px;min-height:220px;background:var(--soft)}.doc h2{font-size:1.2rem;margin:.4em 0 .2em}.doc p{margin:.35em 0}\n" as *u8)
457 o = of_cat(out, o, ".doc table.edt{border-collapse:collapse;margin:.5em 0}.doc table.edt td{border:1px solid var(--line);padding:4px 8px;min-width:60px}\n" as *u8)
458 o = of_cat(out, o, "table.sheet{border-collapse:collapse;width:100%}table.sheet td{border:1px solid var(--line);padding:5px 9px;min-width:70px}table.sheet tr:first-child td{background:var(--accbg);font-weight:600}\n" as *u8)
459 o = of_cat(out, o, ".deck{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px}.slide{border:1px solid var(--line);border-radius:8px;padding:12px;overflow:auto;background:var(--soft)}.slide h3{margin:0 0 6px;font-size:1rem}.slide ul{margin:0;padding-left:18px}.slide .tools{margin:8px 0 0}.slide .tools button{background:transparent;color:var(--muted);padding:2px 6px;font-size:.72rem;font-weight:500}\n" as *u8)
460 o = of_cat(out, o, ".rawwrap{margin:12px 0}.rawwrap summary{cursor:pointer;color:var(--muted);font-size:.85rem}button.save{margin-top:4px}\n" as *u8)
461 // wide tables never sideways-scroll the page on a phone -- they scroll inside their own wrapper
462 o = of_cat(out, o, ".tablewrap{overflow-x:auto}
463/* U4 loading skeletons: a shimmer placeholder honestly says work-in-progress, where a blank pane reads as broken.
464 Held to prefers-reduced-motion like every other animation here. */
465.skel{background:linear-gradient(90deg,var(--soft) 25%,var(--line) 37%,var(--soft) 63%);background-size:400% 100%;animation:shim 1.4s ease infinite;border-radius:6px;color:transparent!important}
466.skel *{visibility:hidden}
467@keyframes shim{0%{background-position:100% 50%}100%{background-position:0 50%}}
468@media(prefers-reduced-motion:reduce){.skel{animation:none}}
469.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n" as *u8)
470 // ---- version diff (sibling lane; rgba overlays read on BOTH themes so no dark block needed)
471 o = of_cat(out, o, ".crumb{font-size:.85rem;margin:2px 0 12px}.crumb a{text-decoration:none}.diff{font-family:ui-monospace,Consolas,monospace;font-size:.85rem;border:1px solid var(--line);border-radius:8px;overflow:auto}.diff>div{padding:2px 10px;white-space:pre-wrap;border-bottom:1px solid var(--line)}.dadd{background:rgba(46,160,84,0.15);color:var(--good)}.ddel{background:rgba(205,70,70,0.13);color:rgb(190,85,85)}.dkeep{color:var(--muted)}\n" as *u8)
472 // ---- responsive: the shell collapses gracefully on phones
473 o = of_cat(out, o, "@media(max-width:640px){.top{padding:8px 12px;gap:8px}a.bname span+span{display:none}.wrap{padding:12px 12px 34px}.fgrid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}.thumb{height:96px}.sortl{margin-left:0}}\n" as *u8)
474 o = of_cat(out, o, "</style>" as *u8)
475 return o
476}
477// escape src[a,b) (XML & < >) while appending -> for emitting substrings without a NUL terminator
478func of_esc_n(out: *u8, off: i64, src: *u8, a: i64, b: i64) -> i64 {
479 var o: i64 = off
480 var i: i64 = a
481 while i < b {
482 let c: i64 = src[i] as i64
483 if c == 38 { o = of_cat(out, o, "&" as *u8) } else {
484 if c == 60 { o = of_cat(out, o, "<" as *u8) } else {
485 if c == 62 { o = of_cat(out, o, ">" as *u8) } else { out[o] = src[i]; o = o + 1 } } }
486 i = i + 1
487 }
488 return o
489}
490// render a doc spec (H/B/I/P/T lines) as an editable block tree (#ed). Consecutive T lines = one table.
491func of_render_doc(out: *u8, off: i64, spec: *u8, sl: i64) -> i64 {
492 var o: i64 = of_cat(out, off, "<div id='ed' class='visual doc' contenteditable='true'>" as *u8)
493 var i: i64 = 0
494 var intable: i64 = 0
495 while i < sl {
496 var e: i64 = i
497 while e < sl { if spec[e] == (10 as u8) { break } e = e + 1 }
498 let c0: i64 = spec[i] as i64
499 var cs: i64 = i
500 if e >= i + 2 { if spec[i+1] == (32 as u8) { cs = i + 2 } }
501 if c0 == 84 { // 'T' table row
502 if intable == 0 { o = of_cat(out, o, "<table class='edt'><tbody>" as *u8); intable = 1 }
503 o = of_cat(out, o, "<tr>" as *u8)
504 var cstart: i64 = cs
505 var k: i64 = cs
506 while k <= e {
507 if k == e { o = of_cat(out, o, "<td>" as *u8); o = of_esc_n(out, o, spec, cstart, k); o = of_cat(out, o, "</td>" as *u8); k = k + 1 }
508 else { if spec[k] == (124 as u8) { o = of_cat(out, o, "<td>" as *u8); o = of_esc_n(out, o, spec, cstart, k); o = of_cat(out, o, "</td>" as *u8); cstart = k + 1; k = k + 1 } else { k = k + 1 } }
509 }
510 o = of_cat(out, o, "</tr>" as *u8)
511 } else {
512 if intable == 1 { o = of_cat(out, o, "</tbody></table>" as *u8); intable = 0 }
513 if c0 == 72 { o = of_cat(out, o, "<h2>" as *u8); o = of_esc_n(out, o, spec, cs, e); o = of_cat(out, o, "</h2>" as *u8) }
514 else { if c0 == 66 { o = of_cat(out, o, "<p data-k='B'><b>" as *u8); o = of_esc_n(out, o, spec, cs, e); o = of_cat(out, o, "</b></p>" as *u8) }
515 else { if c0 == 73 { o = of_cat(out, o, "<p data-k='I'><i>" as *u8); o = of_esc_n(out, o, spec, cs, e); o = of_cat(out, o, "</i></p>" as *u8) }
516 else { o = of_cat(out, o, "<p>" as *u8); o = of_esc_n(out, o, spec, cs, e); o = of_cat(out, o, "</p>" as *u8) } } }
517 }
518 i = e + 1
519 }
520 if intable == 1 { o = of_cat(out, o, "</tbody></table>" as *u8) }
521 o = of_cat(out, o, "</div>" as *u8)
522 return o
523}
524// render a sheet spec (TSV) as an editable grid (#grid).
525func of_render_sheet(out: *u8, off: i64, spec: *u8, sl: i64) -> i64 {
526 var o: i64 = of_cat(out, off, "<table id='grid' class='visual sheet'><tbody>" as *u8)
527 var i: i64 = 0
528 while i < sl {
529 var e: i64 = i
530 while e < sl { if spec[e] == (10 as u8) { break } e = e + 1 }
531 o = of_cat(out, o, "<tr>" as *u8)
532 var cstart: i64 = i
533 var k: i64 = i
534 while k <= e {
535 if k == e { o = of_cat(out, o, "<td contenteditable='true'>" as *u8); o = of_esc_n(out, o, spec, cstart, k); o = of_cat(out, o, "</td>" as *u8); k = k + 1 }
536 else { if spec[k] == (9 as u8) { o = of_cat(out, o, "<td contenteditable='true'>" as *u8); o = of_esc_n(out, o, spec, cstart, k); o = of_cat(out, o, "</td>" as *u8); cstart = k + 1; k = k + 1 } else { k = k + 1 } }
537 }
538 o = of_cat(out, o, "</tr>" as *u8)
539 i = e + 1
540 }
541 o = of_cat(out, o, "</tbody></table>" as *u8)
542 return o
543}
544// render a deck spec (S title / B bullet) as editable slide cards (#deck).
545func of_render_deck(out: *u8, off: i64, spec: *u8, sl: i64) -> i64 {
546 var o: i64 = of_cat(out, off, "<div id='deck' class='visual deck'>" as *u8)
547 var i: i64 = 0
548 var inslide: i64 = 0
549 while i < sl {
550 var e: i64 = i
551 while e < sl { if spec[e] == (10 as u8) { break } e = e + 1 }
552 let c0: i64 = spec[i] as i64
553 var cs: i64 = i
554 if e >= i + 2 { if spec[i+1] == (32 as u8) { cs = i + 2 } }
555 if c0 == 83 { // 'S' new slide
556 if inslide == 1 { o = of_cat(out, o, "</ul><p class='tools'><button type='button' data-act='bullet'>+ bullet</button> <button type='button' data-act='delslide'>remove slide</button></p></div>" as *u8) }
557 o = of_cat(out, o, "<div class='slide'><h3 contenteditable='true'>" as *u8); o = of_esc_n(out, o, spec, cs, e); o = of_cat(out, o, "</h3><ul>" as *u8)
558 inslide = 1
559 } else { if c0 == 66 { // 'B' bullet
560 if inslide == 0 { o = of_cat(out, o, "<div class='slide'><h3 contenteditable='true'>Slide</h3><ul>" as *u8); inslide = 1 }
561 o = of_cat(out, o, "<li contenteditable='true'>" as *u8); o = of_esc_n(out, o, spec, cs, e); o = of_cat(out, o, "</li>" as *u8)
562 } }
563 i = e + 1
564 }
565 if inslide == 1 { o = of_cat(out, o, "</ul><p class='tools'><button type='button' data-act='bullet'>+ bullet</button> <button type='button' data-act='delslide'>remove slide</button></p></div>" as *u8) }
566 o = of_cat(out, o, "</div>" as *u8)
567 return o
568}
569// kind-specific editing toolbar (buttons carry data-act -> app.js) + shared undo/redo/find controls.
570func of_toolbar(out: *u8, off: i64, ks: i64) -> i64 {
571 var o: i64 = of_cat(out, off, "<div class='toolbar'>" as *u8)
572 if ks == 0 { o = of_cat(out, o, "<button type='button' data-act='h'>Heading</button><button type='button' data-act='b'>Bold line</button><button type='button' data-act='i'>Italic line</button><button type='button' data-act='p'>Plain</button><button type='button' data-act='table'>+ table</button><button type='button' data-act='trow'>+ row</button>" as *u8) }
573 if ks == 1 { o = of_cat(out, o, "<button type='button' data-act='row'>+ row</button><button type='button' data-act='col'>+ column</button>" as *u8) }
574 if ks == 2 { o = of_cat(out, o, "<button type='button' data-act='slide'>+ slide</button>" as *u8) }
575 o = of_cat(out, o, "<button type='button' data-act='u' title='Undo (Ctrl+Z)'>Undo</button><button type='button' data-act='r' title='Redo (Ctrl+Y)'>Redo</button><span class='findw'><input id='findq' type='text' placeholder='Find in file'><button type='button' data-act='find'>Find</button></span>" as *u8)
576 o = of_cat(out, o, "</div>" as *u8)
577 return o
578}
579// serve the client at /app.js (read from CWD; NishiLang literal traps -> JS MUST live in a file, never inlined).
580// Static client assets (office_app.js, office_sw.js) live beside the SERVICE root, but a gate runs
581// from buildroot/. A bare cwd-relative read therefore resolves for the daemon and 404s for the gate,
582// which is how five teeth (T3c, T12i, T13d, T-U4-b, T-U4-c) failed while the server itself was fine.
583// Resolve through an ORDERED ROOT LIST so the answer does not depend on where the process happened
584// to be launched -- the build-cwd-is-not-run-cwd law, and rule 17's configuration hierarchy applied
585// to a file path. A symlink would have hidden this; it is the consumer that has to resolve.
586// Returns bytes read, or <=0 if no root has the asset. Frees what it takes.
587func of_read_asset(name: *u8, buf: *u8, cap: i64) -> i64 {
588 var n: i64 = of_read_file(name, buf, cap)
589 if n > 0 { return n }
590 let p: *u8 = sys_mmap(1024)
591 var o: i64 = of_cat(p, 0, "../" as *u8)
592 o = of_cat(p, o, name)
593 p[o] = 0 as u8
594 n = of_read_file(p, buf, cap)
595 sys_munmap(p, 1024)
596 return n
597}
598
599func of_serve_js(out: *u8, cap: i64) -> i64 {
600 let fb: *u8 = sys_mmap(131072)
601 let fl: i64 = of_read_asset("office_app.js" as *u8, fb, 131071)
602 if fl <= 0 { return of_err(out, "404 Not Found" as *u8, "app.js missing" as *u8) }
603 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: application/javascript; charset=utf-8\r\nContent-Length: " as *u8)
604 o = of_catn(out, o, fl)
605 o = of_cat(out, o, "\r\nCache-Control: max-age=300\r\n\r\n" as *u8)
606 var i: i64 = 0
607 while i < fl { if o + i < cap { out[o + i] = fb[i] } i = i + 1 }
608 return o + fl
609}
610// U4 OFFLINE/PWA. The service worker lives in a FILE for the same reason app.js does -- NishiLang literal
611// traps make inlining JS a hazard. It is served at /sw.js so its scope covers the whole office mount; a worker
612// served from a deeper path could not control the app it is meant to make offline-capable.
613func of_serve_sw(out: *u8, cap: i64) -> i64 {
614 let fb: *u8 = sys_mmap(65536)
615 let fl: i64 = of_read_asset("office_sw.js" as *u8, fb, 65535)
616 if fl <= 0 { return of_err(out, "404 Not Found" as *u8, "sw.js missing" as *u8) }
617 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK
618
619Content-Type: application/javascript; charset=utf-8
620
621Service-Worker-Allowed: /
622
623Content-Length: " as *u8)
624 o = of_catn(out, o, fl)
625 o = of_cat(out, o, "
626
627Cache-Control: max-age=60
628
629
630
631" as *u8)
632 var i: i64 = 0
633 while i < fl { if o + i < cap { out[o + i] = fb[i] } i = i + 1 }
634 return o + fl
635}
636// Web app manifest -- installable to a home screen, which is what "offline" means to a family on a phone.
637func of_serve_manifest(out: *u8, base: *u8, cap: i64) -> i64 {
638 let b: *u8 = sys_mmap(4096)
639 var m: i64 = of_cat(b, 0, "{\"name\":\"Nishi Office\",\"short_name\":\"Office\",\"display\":\"standalone\",\"background_color\":\"rgb(244,246,251)\",\"theme_color\":\"rgb(41,84,164)\",\"start_url\":\"" as *u8)
640 m = of_cat(b, m, base)
641 m = of_cat(b, m, "/\"}" as *u8)
642 b[m] = 0 as u8
643 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK
644
645Content-Type: application/manifest+json
646
647Content-Length: " as *u8)
648 o = of_catn(out, o, m)
649 o = of_cat(out, o, "
650
651
652
653" as *u8)
654 o = of_cat(out, o, b)
655 return o
656}
657func of_page_top(out: *u8, off: i64, title: *u8) -> i64 {
658 var o: i64 = off
659 o = of_cat(out, o, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<" as *u8)
660 o = of_catc(out, o, 33)
661 o = of_cat(out, o, "DOCTYPE html>\n<html lang=" as *u8)
662 o = of_catc(out, o, 34)
663 o = of_cat(out, o, "en" as *u8)
664 o = of_catc(out, o, 34)
665 o = of_cat(out, o, "><head><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>" as *u8)
666 o = of_esc(out, o, title)
667 // favicon: inline SVG data URI, percent-encoded (no raw hash/bang -- nx_cc literal law)
668 o = of_cat(out, o, "</title><link rel='icon' href='data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 32 32%22%3E%3Crect width=%2232%22 height=%2232%22 rx=%227%22 fill=%22rgb(41,84,164)%22/%3E%3Ctext x=%2216%22 y=%2223%22 font-size=%2218%22 font-weight=%22bold%22 font-family=%22sans-serif%22 fill=%22white%22 text-anchor=%22middle%22%3EN%3C/text%3E%3C/svg%3E'>" as *u8)
669 o = of_css(out, o)
670 o = of_cat(out, o, "</head><body>\n" as *u8)
671 return o
672}
673func of_page_foot(out: *u8, off: i64) -> i64 {
674 var o: i64 = off
675 o = of_cat(out, o, "<p class='foot'>Nishi Office — sovereign engines nx_docx · nx_xlsx · nx_pptx (gated); every save is a NEW version, history is never lost. Search, thumbnails, diffs and raw-spec editing work with ZERO JS; visual editing, find, undo, shortcuts and autosave light up with it. Co-edit wiring and in-app AI are the named next rungs.</p></body></html>\n" as *u8)
676 return o
677}
678// the app shell: sticky top bar with brand, live search (GET <base>/?q=) and a JS-only theme toggle.
679// q = the current search text (prefilled so the state is visible); pass an empty buffer elsewhere.
680func of_shell_top(out: *u8, off: i64, title: *u8, base: *u8, q: *u8) -> i64 {
681 var o: i64 = of_page_top(out, off, title)
682 // U4 PWA: installable + a theme colour so the OS chrome matches the app instead of flashing white.
683 // Emitted HERE, not in of_page_top: only the APP SHELL is installable. The bare share/error pages have no
684 // base mount and are not an app -- advertising a manifest from them would install a broken scope.
685 o = of_cat(out, o, "<meta name='theme-color' content='rgb(41,84,164)'><link rel='manifest' href='" as *u8)
686 o = of_cat(out, o, base)
687 o = of_cat(out, o, "/manifest.webmanifest'>" as *u8)
688 // skip-to-content for keyboard/screen-reader users (href='#main'; hash composed via catc)
689 o = of_cat(out, o, "<a class='skip-link' href='" as *u8)
690 o = of_catc(out, o, 35)
691 o = of_cat(out, o, "main'>Skip to content</a><header class='top'><nav><a class='bname' href='" as *u8)
692 o = of_cat(out, o, base)
693 o = of_cat(out, o, "/'><svg class='logo' viewBox='0 0 32 32' aria-hidden='true'><rect width='32' height='32' rx='7' fill='rgb(41,84,164)'/><text x='16' y='23' font-size='18' font-weight='bold' fill='white' text-anchor='middle'>N</text></svg><span>Nishi Office</span></a><form method='get' action='" as *u8)
694 o = of_cat(out, o, base)
695 o = of_cat(out, o, "/'><input type='text' name='q' placeholder='Search files' value='" as *u8)
696 o = of_esc(out, o, q)
697 o = of_cat(out, o, "'></form><button type='button' class='thm' data-act='theme'>Theme</button></nav></header>\n" as *u8)
698 return o
699}
700// human "edited ago" from a usec timestamp (0 = unknown)
701func of_ago(out: *u8, off: i64, us: i64) -> i64 {
702 if us <= 0 { return of_cat(out, off, "—" as *u8) }
703 var d: i64 = (sys_now_us() - us) / 1000000
704 if d < 0 { d = 0 }
705 if d < 90 { return of_cat(out, off, "just now" as *u8) }
706 if d < 5400 { var o: i64 = of_catn(out, off, d / 60); return of_cat(out, o, "m ago" as *u8) }
707 if d < 129600 { var o2: i64 = of_catn(out, off, d / 3600); return of_cat(out, o2, "h ago" as *u8) }
708 var o3: i64 = of_catn(out, off, d / 86400)
709 return of_cat(out, o3, "d ago" as *u8)
710}
711// usec of the LATEST save = field 3 of the last non-empty manifest line (0 if missing) -> recency sort + stamps
712func of_manifest_last_us(root: *u8, name: *u8) -> i64 {
713 let mp: *u8 = sys_mmap(512)
714 var o: i64 = of_cat(mp, 0, root); o = of_cat(mp, o, "/" as *u8); o = of_cat(mp, o, name); o = of_cat(mp, o, "/manifest.txt" as *u8); mp[o] = 0 as u8
715 let buf: *u8 = sys_mmap(65536)
716 let n: i64 = of_read_file(mp, buf, 65536)
717 if n <= 0 { return 0 }
718 var e: i64 = n
719 while e > 0 { if buf[e-1] == (10 as u8) { e = e - 1 } else { break } }
720 if e <= 0 { return 0 }
721 var s: i64 = e
722 while s > 0 { if buf[s-1] == (10 as u8) { break } s = s - 1 }
723 var tabs: i64 = 0
724 var i: i64 = s
725 while i < e { if buf[i] == (9 as u8) { tabs = tabs + 1; i = i + 1; if tabs == 2 { break } } else { i = i + 1 } }
726 if tabs < 2 { return 0 }
727 var v: i64 = 0
728 while i < e { let c: i64 = buf[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 }
729 return v
730}
731// 1 if the manifest line for v<N> carries the additive 4th field "auto" (a background autosave), else 0
732func of_manifest_is_auto(root: *u8, name: *u8, vn: i64) -> i64 {
733 let mp: *u8 = sys_mmap(512)
734 var o: i64 = of_cat(mp, 0, root); o = of_cat(mp, o, "/" as *u8); o = of_cat(mp, o, name); o = of_cat(mp, o, "/manifest.txt" as *u8); mp[o] = 0 as u8
735 let buf: *u8 = sys_mmap(65536)
736 let n: i64 = of_read_file(mp, buf, 65536)
737 if n <= 0 { return 0 }
738 let pfx: *u8 = sys_mmap(32)
739 var po: i64 = of_cat(pfx, 0, "v" as *u8); po = of_catn(pfx, po, vn); po = of_catc(pfx, po, 9); pfx[po] = 0 as u8
740 var i: i64 = 0
741 while i < n {
742 var m: i64 = 1
743 var k: i64 = 0
744 while pfx[k] != (0 as u8) {
745 if i + k >= n { m = 0; break }
746 if buf[i+k] != pfx[k] { m = 0; break }
747 k = k + 1
748 }
749 var e: i64 = i
750 while e < n { if buf[e] == (10 as u8) { break } e = e + 1 }
751 if m == 1 {
752 var tabs: i64 = 0
753 var j: i64 = i
754 while j < e {
755 if buf[j] == (9 as u8) {
756 tabs = tabs + 1
757 if tabs == 3 {
758 if j + 4 < e { if buf[j+1] == (97 as u8) { if buf[j+2] == (117 as u8) { if buf[j+3] == (116 as u8) { if buf[j+4] == (111 as u8) { return 1 } } } } }
759 return 0
760 }
761 }
762 j = j + 1
763 }
764 return 0
765 }
766 i = e + 1
767 }
768 return 0
769}
770// server-rendered mini preview of the LATEST spec -> the home card thumbnail (real content, zero JS)
771func of_thumb(out: *u8, off: i64, root: *u8, name: *u8, ks: i64, vc: i64) -> i64 {
772 var o: i64 = of_cat(out, off, "<div class='thumb'>" as *u8)
773 let vd: *u8 = sys_mmap(512)
774 of_vdir(root, name, vc, vd)
775 let sp: *u8 = sys_mmap(600)
776 var so: i64 = of_cat(sp, 0, vd); so = of_cat(sp, so, "/spec.txt" as *u8); sp[so] = 0 as u8
777 let buf: *u8 = sys_mmap(600)
778 let sl: i64 = of_read_file(sp, buf, 520)
779 if sl <= 0 { return of_cat(out, o, "<div class='tdoc'>…</div></div>" as *u8) }
780 if ks == 0 {
781 o = of_cat(out, o, "<div class='tdoc'>" as *u8)
782 var i: i64 = 0
783 var lines: i64 = 0
784 while i < sl {
785 if lines >= 7 { break }
786 var e: i64 = i
787 while e < sl { if buf[e] == (10 as u8) { break } e = e + 1 }
788 let c0: i64 = buf[i] as i64
789 var cs: i64 = i
790 if e >= i + 2 { if buf[i+1] == (32 as u8) { cs = i + 2 } }
791 var ce: i64 = e
792 if ce > cs + 64 { ce = cs + 64 }
793 if c0 == 72 { o = of_cat(out, o, "<div class='th'>" as *u8) } else {
794 if c0 == 66 { o = of_cat(out, o, "<div class='tb'>" as *u8) } else {
795 if c0 == 73 { o = of_cat(out, o, "<div class='ti'>" as *u8) } else { o = of_cat(out, o, "<div>" as *u8) } } }
796 o = of_esc_n(out, o, buf, cs, ce)
797 o = of_cat(out, o, "</div>" as *u8)
798 lines = lines + 1
799 i = e + 1
800 }
801 o = of_cat(out, o, "</div>" as *u8)
802 }
803 if ks == 1 {
804 o = of_cat(out, o, "<table class='tsheet'><tbody>" as *u8)
805 var i2: i64 = 0
806 var rows: i64 = 0
807 while i2 < sl {
808 if rows >= 5 { break }
809 var e2: i64 = i2
810 while e2 < sl { if buf[e2] == (10 as u8) { break } e2 = e2 + 1 }
811 o = of_cat(out, o, "<tr>" as *u8)
812 var cstart: i64 = i2
813 var k: i64 = i2
814 var cells: i64 = 0
815 while k <= e2 {
816 if cells >= 4 { break }
817 var hit: i64 = 0
818 if k == e2 { hit = 1 } else { if buf[k] == (9 as u8) { hit = 1 } }
819 if hit == 1 {
820 var ce2: i64 = k
821 if ce2 > cstart + 14 { ce2 = cstart + 14 }
822 o = of_cat(out, o, "<td>" as *u8); o = of_esc_n(out, o, buf, cstart, ce2); o = of_cat(out, o, "</td>" as *u8)
823 cstart = k + 1
824 cells = cells + 1
825 }
826 k = k + 1
827 }
828 o = of_cat(out, o, "</tr>" as *u8)
829 rows = rows + 1
830 i2 = e2 + 1
831 }
832 o = of_cat(out, o, "</tbody></table>" as *u8)
833 }
834 if ks == 2 {
835 o = of_cat(out, o, "<div class='tslide'>" as *u8)
836 var i3: i64 = 0
837 var started: i64 = 0
838 var bl: i64 = 0
839 while i3 < sl {
840 var e3: i64 = i3
841 while e3 < sl { if buf[e3] == (10 as u8) { break } e3 = e3 + 1 }
842 let c3: i64 = buf[i3] as i64
843 var cs3: i64 = i3
844 if e3 >= i3 + 2 { if buf[i3+1] == (32 as u8) { cs3 = i3 + 2 } }
845 var ce3: i64 = e3
846 if ce3 > cs3 + 56 { ce3 = cs3 + 56 }
847 if c3 == 83 {
848 if started == 1 { break }
849 o = of_cat(out, o, "<div class='tst'>" as *u8); o = of_esc_n(out, o, buf, cs3, ce3); o = of_cat(out, o, "</div>" as *u8)
850 started = 1
851 } else { if c3 == 66 { if bl < 3 {
852 o = of_cat(out, o, "<div class='tsb'>• " as *u8); o = of_esc_n(out, o, buf, cs3, ce3); o = of_cat(out, o, "</div>" as *u8)
853 bl = bl + 1
854 } } }
855 i3 = e3 + 1
856 }
857 o = of_cat(out, o, "</div>" as *u8)
858 }
859 o = of_cat(out, o, "</div>" as *u8)
860 return o
861}
862// lowercase in place (search is case-insensitive; stored names are already lowercase by of_name_ok)
863func of_lower(s: *u8) -> i64 {
864 var i: i64 = 0
865 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 65 { if c <= 90 { s[i] = (c + 32) as u8 } } i = i + 1 }
866 return 0
867}
868// one filter/sort pill: preserves q, sets type (tv, empty = All) and sort (sv) explicitly
869func of_chip(out: *u8, off: i64, base: *u8, q: *u8, tv: *u8, sv: *u8, label: *u8, on: i64) -> i64 {
870 var o: i64 = of_cat(out, off, "<a class='" as *u8)
871 if on == 1 { o = of_cat(out, o, "on" as *u8) }
872 o = of_cat(out, o, "' href='" as *u8)
873 o = of_cat(out, o, base)
874 o = of_cat(out, o, "/?" as *u8)
875 if q[0] != (0 as u8) { o = of_cat(out, o, "q=" as *u8); o = of_esc(out, o, q); o = of_cat(out, o, "&" as *u8) }
876 if tv[0] != (0 as u8) { o = of_cat(out, o, "type=" as *u8); o = of_cat(out, o, tv); o = of_cat(out, o, "&" as *u8) }
877 o = of_cat(out, o, "sort=" as *u8)
878 o = of_cat(out, o, sv)
879 o = of_cat(out, o, "'>" as *u8)
880 o = of_cat(out, o, label)
881 o = of_cat(out, o, "</a>" as *u8)
882 return o
883}
884// first byte offset of needle in buf[0,n), or -1 -- lets the gate assert ORDERING, not just presence
885func of_findpos(buf: *u8, n: i64, needle: *u8) -> i64 {
886 let nl: i64 = of_slen(needle)
887 if nl == 0 { return 0 - 1 }
888 var i: i64 = 0
889 while i + nl <= n {
890 var k: i64 = 0
891 var hit: i64 = 1
892 while k < nl { if buf[i+k] != needle[k] { hit = 0; k = nl } else { k = k + 1 } }
893 if hit == 1 { return i }
894 i = i + 1
895 }
896 return 0 - 1
897}
898// one Start-new tile: pick a name, Create -> lands on the visual editor. The starter spec rides a HIDDEN INPUT
899// (a hidden default value is what type=hidden is FOR -- and unlike a display:none <textarea> it renders NOTHING
900// in every engine incl. Nishi Browser, so the tile shows no leaked spec text; newlines/tabs survive the POST via
901// URL-encoding, which of_form_get decodes). Submitted as-is, works with NO JS; the editor is where you compose.
902// ---- U3 LIBRARY ORGANISATION: starred + folders ------------------------------------------------------
903// Both are SIDECAR files next to the manifest, exactly like agent.txt: the document spec stays pure content,
904// nothing about the file format changes, and a missing sidecar simply means "not starred / no folder". No
905// migration, no schema version, and an older daemon reading a newer tree just ignores them.
906func of_side_path(root: *u8, name: *u8, leaf: *u8, out: *u8) -> i64 {
907 var o: i64 = of_cat(out, 0, root); o = of_cat(out, o, "/" as *u8); o = of_cat(out, o, name)
908 o = of_cat(out, o, "/" as *u8); o = of_cat(out, o, leaf); out[o] = 0 as u8
909 return o
910}
911func of_starred(root: *u8, name: *u8) -> i64 {
912 let p: *u8 = sys_mmap(512)
913 of_side_path(root, name, "starred" as *u8, p)
914 let b: *u8 = sys_mmap(8)
915 if of_read_file(p, b, 4) > 0 { return 1 }
916 return 0
917}
918// toggle and return the NEW state. Unstar writes "0" rather than deleting: a retired star is still history,
919// and a write we can read back beats a delete we cannot audit.
920// Toggle and return the NEW state. Unstar writes a zeroed byte rather than deleting: a retired star is still
921// history, and a write we can read back beats a delete we cannot audit.
922// NOTE: never pass the "" literal here -- the nx_cc constant pool ALIASES an empty literal onto the NEXT
923// literal in the pool, so the "empty" write would emit someone else's bytes. Use a real zeroed buffer.
924func of_star_toggle(root: *u8, name: *u8) -> i64 {
925 let p: *u8 = sys_mmap(512)
926 of_side_path(root, name, "starred" as *u8, p)
927 if of_starred(root, name) == 1 {
928 let z: *u8 = sys_mmap(8); z[0] = 0 as u8
929 of_write_file(p, z, 0)
930 return 0
931 }
932 of_write_file(p, "1" as *u8, 1)
933 return 1
934}
935func of_folder_get(root: *u8, name: *u8, out: *u8, cap: i64) -> i64 {
936 let p: *u8 = sys_mmap(512)
937 of_side_path(root, name, "folder" as *u8, p)
938 let n: i64 = of_read_file(p, out, cap - 1)
939 if n <= 0 { out[0] = 0 as u8; return 0 }
940 var e: i64 = n
941 var trim: i64 = 1
942 while trim == 1 {
943 if e <= 0 { trim = 0 } else {
944 let c: i64 = out[e-1] as i64
945 if c == 10 { e = e - 1 } else { if c == 13 { e = e - 1 } else { trim = 0 } }
946 }
947 }
948 out[e] = 0 as u8
949 return e
950}
951func of_folder_set(root: *u8, name: *u8, val: *u8) -> i64 {
952 let p: *u8 = sys_mmap(512)
953 of_side_path(root, name, "folder" as *u8, p)
954 return of_write_file(p, val, of_slen(val))
955}
956// One template card. Same POST /save contract as of_form, so a template is not a special kind of file --
957// it is an ordinary document that happens to start with useful content, and every downstream feature
958// (versioning, diff, AI, agent, sharing) works on it unchanged.
959func of_tmpl(out: *u8, off: i64, base: *u8, k: i64, icon: *u8, title: *u8, blurb: *u8, spec: *u8) -> i64 {
960 var o: i64 = of_cat(out, off, "<div class='newt'><h3><div class='fico k" as *u8)
961 o = of_catn(out, o, k)
962 o = of_cat(out, o, "'>" as *u8)
963 o = of_cat(out, o, icon)
964 o = of_cat(out, o, "</div>" as *u8)
965 o = of_cat(out, o, title)
966 o = of_cat(out, o, " <span class='cnt'>." as *u8); o = of_cat(out, o, of_ext(k)); o = of_cat(out, o, "</span></h3><form method='post' action='" as *u8)
967 o = of_cat(out, o, base)
968 o = of_cat(out, o, "/save'><input type='hidden' name='kind' value='" as *u8)
969 o = of_cat(out, o, of_kind_name(k))
970 o = of_cat(out, o, "'><input type='hidden' name='spec' value='" as *u8)
971 o = of_esc(out, o, spec)
972 o = of_cat(out, o, "'><p class='hint' style='margin:0'>" as *u8)
973 o = of_cat(out, o, blurb)
974 o = of_cat(out, o, "</p><p class='row'><input type='text' name='name' placeholder='file-name (a-z 0-9 dash)' required><button type='submit'>Use</button></p></form></div>\n" as *u8)
975 return o
976}
977func of_form(out: *u8, off: i64, base: *u8, k: i64) -> i64 {
978 var o: i64 = off
979 o = of_cat(out, o, "<div class='newt'><h3><div class='fico k" as *u8)
980 o = of_catn(out, o, k)
981 o = of_cat(out, o, "'>" as *u8)
982 if k == 0 { o = of_cat(out, o, "W" as *u8) }
983 if k == 1 { o = of_cat(out, o, "S" as *u8) }
984 if k == 2 { o = of_cat(out, o, "P" as *u8) }
985 o = of_cat(out, o, "</div>New " as *u8)
986 o = of_cat(out, o, of_kind_name(k))
987 o = of_cat(out, o, " <span class='cnt'>." as *u8); o = of_cat(out, o, of_ext(k)); o = of_cat(out, o, "</span></h3><form method='post' action='" as *u8)
988 o = of_cat(out, o, base)
989 o = of_cat(out, o, "/save'><input type='hidden' name='kind' value='" as *u8)
990 o = of_cat(out, o, of_kind_name(k))
991 o = of_cat(out, o, "'><input type='hidden' name='spec' value='" as *u8)
992 if k == 0 { o = of_cat(out, o, "H Untitled document\nP Start writing here." as *u8) }
993 if k == 1 { o = of_cat(out, o, "Item\tAmount\nExample\t1" as *u8) }
994 if k == 2 { o = of_cat(out, o, "S Untitled deck\nB First point" as *u8) }
995 o = of_cat(out, o, "'>" as *u8)
996 if k == 0 { o = of_cat(out, o, "<p class='hint' style='margin:0'>Headings, bold, tables. Opens in Word.</p>" as *u8) }
997 if k == 1 { o = of_cat(out, o, "<p class='hint' style='margin:0'>Real formulas (=SUM, =AVERAGE…). Opens in Excel.</p>" as *u8) }
998 if k == 2 { o = of_cat(out, o, "<p class='hint' style='margin:0'>Titles and bullets. Opens in PowerPoint.</p>" as *u8) }
999 o = of_cat(out, o, "<p class='row'><input type='text' name='name' placeholder='file-name (a-z 0-9 dash)' required><button type='submit'>Create</button></p></form></div>\n" as *u8)
1000 return o
1001}
1002// the home APP SHELL (U-axes rung): search + type chips + recency/name sort + card grid with REAL content
1003// thumbnails + onboarding/no-match empty states. All server-rendered -- works with ZERO JS.
1004// qs = the raw query string (q=&type=&sort=), form-urlencoded exactly like a POST body.
1005func of_home(root: *u8, base: *u8, qs: *u8, out: *u8, cap: i64, azprefix: *u8, me: *u8, authed: i64) -> i64 {
1006 let ql: i64 = of_slen(qs)
1007 let q: *u8 = sys_mmap(96)
1008 let srt: *u8 = sys_mmap(24)
1009 let tf: *u8 = sys_mmap(24)
1010 of_form_get(qs, ql, "q" as *u8, q, 80)
1011 of_form_get(qs, ql, "sort" as *u8, srt, 24)
1012 of_form_get(qs, ql, "type" as *u8, tf, 24)
1013 let flt: *u8 = sys_mmap(24)
1014 let fld: *u8 = sys_mmap(64)
1015 of_form_get(qs, ql, "filter" as *u8, flt, 24)
1016 of_form_get(qs, ql, "folder" as *u8, fld, 48)
1017 // "shared with me" = docs the ReBAC reverse index grants me that I do NOT own. Answered from the existing
1018 // index rather than a second store, so sharing and the library view can never disagree.
1019 let shd: *i64 = sys_mmap(8 * 64) as *i64
1020 let own: *i64 = sys_mmap(8 * 64) as *i64
1021 var nshd: i64 = 0
1022 var nown: i64 = 0
1023 if of_seq(flt, "shared" as *u8) == 1 { if authed == 1 {
1024 nshd = of_my_docs(azprefix, me, shd, 64)
1025 nown = of_collect_docs(azprefix, me, "owner" as *u8, own, 0, 64)
1026 } }
1027 of_lower(q)
1028 var o: i64 = of_shell_top(out, 0, "Nishi Office" as *u8, base, q)
1029 o = of_cat(out, o, "<main id='main' class='wrap'>" as *u8)
1030 // collect entries from the append-only registry, filtered by type chip + search text
1031 let idx: *u8 = sys_mmap(512)
1032 var io: i64 = of_cat(idx, 0, root); io = of_cat(idx, io, "/index.txt" as *u8); idx[io] = 0 as u8
1033 let ib: *u8 = sys_mmap(65536)
1034 let n: i64 = of_read_file(idx, ib, 65536)
1035 let names: *u8 = sys_mmap(256 * 64)
1036 let kidx: *i64 = sys_mmap(256 * 8) as *i64
1037 let vcs: *i64 = sys_mmap(256 * 8) as *i64
1038 let uss: *i64 = sys_mmap(256 * 8) as *i64
1039 let ord: *i64 = sys_mmap(256 * 8) as *i64
1040 var total: i64 = 0
1041 var ne: i64 = 0
1042 let nm: *u8 = sys_mmap(64)
1043 let kd: *u8 = sys_mmap(32)
1044 let kb: *u8 = sys_mmap(64)
1045 var i: i64 = 0
1046 while i < n {
1047 var t: i64 = 0
1048 while i < n { if ib[i] == (9 as u8) { i = i + 1; break } if t < 63 { nm[t] = ib[i]; t = t + 1 } i = i + 1 }
1049 nm[t] = 0 as u8
1050 var t2: i64 = 0
1051 while i < n { if ib[i] == (10 as u8) { i = i + 1; break } if t2 < 31 { kd[t2] = ib[i]; t2 = t2 + 1 } i = i + 1 }
1052 kd[t2] = 0 as u8
1053 if t > 0 {
1054 total = total + 1
1055 var keep: i64 = 1
1056 if tf[0] != (0 as u8) { if of_seq(tf, kd) == 0 { keep = 0 } }
1057 if keep == 1 { if q[0] != (0 as u8) { if of_memhas(nm, of_slen(nm), q) == 0 { keep = 0 } } }
1058 if keep == 1 { if of_seq(flt, "starred" as *u8) == 1 { if of_starred(root, nm) == 0 { keep = 0 } } }
1059 if keep == 1 { if fld[0] != (0 as u8) {
1060 let fbuf: *u8 = sys_mmap(64)
1061 of_folder_get(root, nm, fbuf, 64)
1062 if of_seq(fbuf, fld) == 0 { keep = 0 }
1063 } }
1064 if keep == 1 { if of_seq(flt, "shared" as *u8) == 1 {
1065 var mine: i64 = 0
1066 var si: i64 = 0
1067 while si < nshd { if of_seq(shd[si] as *u8, nm) == 1 { mine = 1; si = nshd } else { si = si + 1 } }
1068 if mine == 0 { keep = 0 }
1069 if mine == 1 {
1070 var owned: i64 = 0
1071 var oi: i64 = 0
1072 while oi < nown { if of_seq(own[oi] as *u8, nm) == 1 { owned = 1; oi = nown } else { oi = oi + 1 } }
1073 if owned == 1 { keep = 0 }
1074 }
1075 } }
1076 if keep == 1 { if ne < 256 {
1077 let ki: i64 = of_kind_idx(kd)
1078 var ks: i64 = ki
1079 if ks < 0 { ks = 0 }
1080 var w: i64 = 0
1081 while nm[w] != (0 as u8) { names[ne * 64 + w] = nm[w]; w = w + 1 }
1082 names[ne * 64 + w] = 0 as u8
1083 kidx[ne] = ks
1084 vcs[ne] = of_manifest_count(root, nm, kb, 64)
1085 uss[ne] = of_manifest_last_us(root, nm)
1086 ord[ne] = ne
1087 ne = ne + 1
1088 } }
1089 }
1090 }
1091 // order: default = most recently edited first (Docs-style); sort=name = alphabetical
1092 var by_name: i64 = 0
1093 if of_seq(srt, "name" as *u8) == 1 { by_name = 1 }
1094 var a: i64 = 0
1095 while a < ne {
1096 var b: i64 = a + 1
1097 while b < ne {
1098 var sw: i64 = 0
1099 if by_name == 1 {
1100 let pa: *u8 = (names as i64 + ord[a] * 64) as *u8
1101 let pb: *u8 = (names as i64 + ord[b] * 64) as *u8
1102 var ci: i64 = 0
1103 var cmp: i64 = 0
1104 while cmp == 0 {
1105 let ca: i64 = pa[ci] as i64
1106 let cb: i64 = pb[ci] as i64
1107 if ca < cb { cmp = 0 - 1 } else { if ca > cb { cmp = 1 } else { if ca == 0 { cmp = 2 } else { ci = ci + 1 } } }
1108 }
1109 if cmp == 1 { sw = 1 }
1110 } else {
1111 if uss[ord[b]] > uss[ord[a]] { sw = 1 }
1112 }
1113 if sw == 1 { let tmp: i64 = ord[a]; ord[a] = ord[b]; ord[b] = tmp }
1114 b = b + 1
1115 }
1116 a = a + 1
1117 }
1118 // first-run onboarding: nothing exists yet
1119 if total == 0 {
1120 o = of_cat(out, o, "<div class='empty'><div class='row'><div class='fico k0'>W</div><div class='fico k1'>S</div><div class='fico k2'>P</div></div><h1>Create your first document</h1><p>Documents, spreadsheets and decks — created, versioned and downloadable, all on our own stack. Pick a name below to start.</p></div><div class='newrow'>" as *u8)
1121 o = of_form(out, o, base, 0)
1122 o = of_form(out, o, base, 1)
1123 o = of_form(out, o, base, 2)
1124 o = of_import_form(out, o, base)
1125 o = of_cat(out, o, "</div></main>" as *u8)
1126 o = of_page_foot(out, o)
1127 return o
1128 }
1129 o = of_cat(out, o, "<h2>Start new</h2><div class='newrow'>" as *u8)
1130 o = of_form(out, o, base, 0)
1131 o = of_form(out, o, base, 1)
1132 o = of_form(out, o, base, 2)
1133 o = of_import_form(out, o, base)
1134 o = of_cat(out, o, "</div>" as *u8)
1135 // ---- TEMPLATES GALLERY (U3): a blank page is the worst onboarding a suite can offer. Every template is a
1136 // REAL working spec -- the budget carries live =SUM and a #CF rule, the agenda a real table -- so opening one
1137 // demonstrates the engine instead of describing it. Zero JS: each card is a plain POST to the same /save.
1138 o = of_cat(out, o, "<h2>Templates</h2><p class='hint' style='margin:0 0 6px'>Start from something real rather than a blank page. Each one opens as a normal file you can edit, version and download.</p><div class='newrow'>" as *u8)
1139 o = of_tmpl(out, o, base, 0, "W", "Letter", "A dated letter with greeting and sign-off.", "H Letter\nP Dear friend,\nP Write your message here.\nP Warm regards,\nP The Nishi family")
1140 o = of_tmpl(out, o, base, 0, "W", "Meeting agenda", "Heading, attendees and a real table.", "H Meeting Agenda\nB Attendees\nP Add names here.\nT Time|Item|Lead\nT 9:00|Welcome|Host\nT 9:30|Main topic|Team\nP Notes and actions below.")
1141 o = of_tmpl(out, o, base, 1, "S", "Monthly budget", "Live =SUM plus a conditional-format rule.", "Item\tAmount\nGroceries\t400\nUtilities\t180\nTotal\t=SUM(B2:B3)\n#CF B2:B3 greaterThan 300")
1142 o = of_tmpl(out, o, base, 2, "P", "Project update", "Title and bullet slides ready to present.", "S Project Update\nB Where we are\nB What changed\nS Next steps\nB Owner and date")
1143 o = of_cat(out, o, "</div>" as *u8)
1144 // files header: count + type chips + sort links (every control is a plain link -- zero JS)
1145 o = of_cat(out, o, "<div class='fhead'><h1>Files</h1><span class='cnt'>" as *u8)
1146 o = of_catn(out, o, ne)
1147 if ne != total { o = of_cat(out, o, " of " as *u8); o = of_catn(out, o, total) }
1148 o = of_cat(out, o, "</span><span class='chips'>" as *u8)
1149 // U3 chips: Starred and Shared-with-me sit alongside the type chips. Shared is shown only when a caller is
1150 // actually signed in -- an always-visible control that can only ever be empty is a lie about the product.
1151 o = of_cat(out, o, "<a class='" as *u8)
1152 if of_seq(flt, "starred" as *u8) == 1 { o = of_cat(out, o, "on" as *u8) }
1153 o = of_cat(out, o, "' href='" as *u8); o = of_cat(out, o, base)
1154 o = of_cat(out, o, "/?filter=starred'>★ Starred</a>" as *u8)
1155 if authed == 1 {
1156 o = of_cat(out, o, "<a class='" as *u8)
1157 if of_seq(flt, "shared" as *u8) == 1 { o = of_cat(out, o, "on" as *u8) }
1158 o = of_cat(out, o, "' href='" as *u8); o = of_cat(out, o, base)
1159 o = of_cat(out, o, "/?filter=shared'>Shared with me</a>" as *u8)
1160 }
1161 let e0: *u8 = sys_mmap(4)
1162 e0[0] = 0 as u8
1163 var srtv: *u8 = "recent" as *u8
1164 if by_name == 1 { srtv = "name" as *u8 }
1165 var all_on: i64 = 0
1166 if tf[0] == (0 as u8) { all_on = 1 }
1167 o = of_chip(out, o, base, q, e0, srtv, "All" as *u8, all_on)
1168 o = of_chip(out, o, base, q, "doc" as *u8, srtv, "Docs" as *u8, of_seq(tf, "doc" as *u8))
1169 o = of_chip(out, o, base, q, "sheet" as *u8, srtv, "Sheets" as *u8, of_seq(tf, "sheet" as *u8))
1170 o = of_chip(out, o, base, q, "deck" as *u8, srtv, "Decks" as *u8, of_seq(tf, "deck" as *u8))
1171 o = of_cat(out, o, "</span><span class='sortl'>Sort:" as *u8)
1172 o = of_chip(out, o, base, q, tf, "recent" as *u8, "Recent" as *u8, 1 - by_name)
1173 o = of_chip(out, o, base, q, tf, "name" as *u8, "Name" as *u8, by_name)
1174 o = of_cat(out, o, "</span></div>" as *u8)
1175 if ne == 0 {
1176 // no-match empty state (search/filter found nothing)
1177 o = of_cat(out, o, "<div class='empty'><h2>No files match</h2><p>" as *u8)
1178 if q[0] != (0 as u8) { o = of_cat(out, o, "Nothing named like "" as *u8); o = of_esc(out, o, q); o = of_cat(out, o, "". " as *u8) }
1179 o = of_cat(out, o, "<a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/'>Clear search & filters</a></p></div>" as *u8)
1180 } else {
1181 o = of_cat(out, o, "<div class='fgrid'>" as *u8)
1182 var r: i64 = 0
1183 while r < ne {
1184 let ei: i64 = ord[r]
1185 let pnm: *u8 = (names as i64 + ei * 64) as *u8
1186 o = of_cat(out, o, "<a class='fcard' href='" as *u8)
1187 o = of_cat(out, o, base); o = of_cat(out, o, "/doc/" as *u8); o = of_cat(out, o, pnm)
1188 o = of_cat(out, o, "'>" as *u8)
1189 // thumbnails for the first 60 cards keep the page bounded; the rest stay plain cards
1190 if r < 60 { o = of_thumb(out, o, root, pnm, kidx[ei], vcs[ei]) }
1191 o = of_cat(out, o, "<div class='fmeta'><div class='fico k" as *u8)
1192 o = of_catn(out, o, kidx[ei])
1193 o = of_cat(out, o, "'>" as *u8)
1194 if kidx[ei] == 0 { o = of_cat(out, o, "W" as *u8) }
1195 if kidx[ei] == 1 { o = of_cat(out, o, "S" as *u8) }
1196 if kidx[ei] == 2 { o = of_cat(out, o, "P" as *u8) }
1197 o = of_cat(out, o, "</div><span class='nm'><b>" as *u8)
1198 o = of_esc(out, o, pnm)
1199 o = of_cat(out, o, "</b><span>v" as *u8)
1200 o = of_catn(out, o, vcs[ei])
1201 o = of_cat(out, o, " · " as *u8)
1202 o = of_ago(out, o, uss[ei])
1203 o = of_cat(out, o, "</span></span></div></a>" as *u8)
1204 r = r + 1
1205 }
1206 o = of_cat(out, o, "</div>" as *u8)
1207 if ne == 256 { o = of_cat(out, o, "<p class='hint'>Showing the first 256 files.</p>" as *u8) }
1208 }
1209 o = of_cat(out, o, "</main>" as *u8)
1210 o = of_page_foot(out, o)
1211 return o
1212}
1213// ---- version DIFF (leverages the never-lose store: every version's spec.txt is on disk) ----
1214func of_lineeq(a: *u8, b: *u8) -> i64 {
1215 var i: i64 = 0
1216 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
1217 if b[i] != (0 as u8) { return 0 }
1218 return 1
1219}
1220// split buf[0,n) into NUL-terminated lines in place; store start pointers in lp[]; return count (<=maxl). Caller sets buf[n]=0.
1221func of_split_lines(buf: *u8, n: i64, lp: *i64, maxl: i64) -> i64 {
1222 var c: i64 = 0
1223 var i: i64 = 0
1224 while i < n {
1225 if c >= maxl { return c }
1226 lp[c] = (buf as i64) + i
1227 c = c + 1
1228 while i < n { if buf[i] == (10 as u8) { break } i = i + 1 }
1229 if i < n { buf[i] = 0 as u8; i = i + 1 }
1230 }
1231 return c
1232}
1233func of_read_version_spec(root: *u8, name: *u8, vn: i64, buf: *u8, cap: i64) -> i64 {
1234 let vd: *u8 = sys_mmap(512)
1235 of_vdir(root, name, vn, vd)
1236 let sp: *u8 = sys_mmap(600)
1237 var so: i64 = of_cat(sp, 0, vd); so = of_cat(sp, so, "/spec.txt" as *u8); sp[so] = 0 as u8
1238 let n: i64 = of_read_file(sp, buf, cap)
1239 if n > 0 { buf[n] = 0 as u8; return n }
1240 buf[0] = 0 as u8; return 0
1241}
1242// render an LCS line-diff of specA vs specB into out. added=in B not A (green), removed=in A not B (red).
1243func of_render_diff(out: *u8, off: i64, bufa: *u8, na_bytes: i64, bufb: *u8, nb_bytes: i64) -> i64 {
1244 let MAXL: i64 = 400
1245 let la: *i64 = sys_mmap(MAXL * 8) as *i64
1246 let lb: *i64 = sys_mmap(MAXL * 8) as *i64
1247 let na: i64 = of_split_lines(bufa, na_bytes, la, MAXL)
1248 let nb: i64 = of_split_lines(bufb, nb_bytes, lb, MAXL)
1249 let W: i64 = nb + 1
1250 let dp: *i64 = sys_mmap((na + 1) * (nb + 1) * 8) as *i64
1251 var i: i64 = na
1252 while i >= 0 {
1253 var j: i64 = nb
1254 while j >= 0 {
1255 if i == na { dp[i*W + j] = 0 } else { if j == nb { dp[i*W + j] = 0 } else {
1256 if of_lineeq(la[i] as *u8, lb[j] as *u8) == 1 { dp[i*W + j] = dp[(i+1)*W + (j+1)] + 1 }
1257 else { let d1: i64 = dp[(i+1)*W + j]; let d2: i64 = dp[i*W + (j+1)]; if d1 >= d2 { dp[i*W + j] = d1 } else { dp[i*W + j] = d2 } }
1258 } }
1259 j = j - 1
1260 }
1261 i = i - 1
1262 }
1263 var o: i64 = of_cat(out, off, "<div class='diff'>" as *u8)
1264 var add: i64 = 0; var del: i64 = 0
1265 var a: i64 = 0; var b: i64 = 0
1266 var go: i64 = 1
1267 while go == 1 {
1268 if a < na { if b < nb {
1269 if of_lineeq(la[a] as *u8, lb[b] as *u8) == 1 {
1270 o = of_cat(out, o, "<div class='dkeep'> " as *u8); o = of_esc(out, o, la[a] as *u8); o = of_cat(out, o, "</div>" as *u8); a = a + 1; b = b + 1
1271 } else { if dp[(a+1)*W + b] >= dp[a*W + (b+1)] {
1272 o = of_cat(out, o, "<div class='ddel'>− " as *u8); o = of_esc(out, o, la[a] as *u8); o = of_cat(out, o, "</div>" as *u8); a = a + 1; del = del + 1
1273 } else {
1274 o = of_cat(out, o, "<div class='dadd'>+ " as *u8); o = of_esc(out, o, lb[b] as *u8); o = of_cat(out, o, "</div>" as *u8); b = b + 1; add = add + 1
1275 } }
1276 } else {
1277 o = of_cat(out, o, "<div class='ddel'>− " as *u8); o = of_esc(out, o, la[a] as *u8); o = of_cat(out, o, "</div>" as *u8); a = a + 1; del = del + 1
1278 } } else { if b < nb {
1279 o = of_cat(out, o, "<div class='dadd'>+ " as *u8); o = of_esc(out, o, lb[b] as *u8); o = of_cat(out, o, "</div>" as *u8); b = b + 1; add = add + 1
1280 } else { go = 0 } }
1281 }
1282 o = of_cat(out, o, "</div><p class='sub' style='margin-top:8px'><b>" as *u8); o = of_catn(out, o, add); o = of_cat(out, o, "</b> line(s) added, <b>" as *u8); o = of_catn(out, o, del); o = of_cat(out, o, "</b> removed.</p>" as *u8)
1283 return o
1284}
1285func of_diffpage(root: *u8, base: *u8, name: *u8, va: i64, vb: i64, out: *u8, cap: i64) -> i64 {
1286 let kb: *u8 = sys_mmap(64)
1287 let vc: i64 = of_manifest_count(root, name, kb, 64)
1288 if vc <= 0 { return 0 - 1 }
1289 if va < 1 { return 0 - 1 }
1290 if vb < 1 { return 0 - 1 }
1291 if va > vc { return 0 - 1 }
1292 if vb > vc { return 0 - 1 }
1293 let ba: *u8 = sys_mmap(131072)
1294 let bb: *u8 = sys_mmap(131072)
1295 let nab: i64 = of_read_version_spec(root, name, va, ba, 131071)
1296 let nbb: i64 = of_read_version_spec(root, name, vb, bb, 131071)
1297 let eqd: *u8 = sys_mmap(4)
1298 eqd[0] = 0 as u8
1299 var o: i64 = of_shell_top(out, 0, name, base, eqd)
1300 o = of_cat(out, o, "<main id='main' class='wrap'><p class='crumb'><a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/doc/" as *u8); o = of_cat(out, o, name); o = of_cat(out, o, "'>← " as *u8); o = of_esc(out, o, name); o = of_cat(out, o, "</a></p><h1>Changes: v" as *u8)
1301 o = of_catn(out, o, va); o = of_cat(out, o, " → v" as *u8); o = of_catn(out, o, vb)
1302 o = of_cat(out, o, "</h1><p class='sub'>Every version is kept forever — this compares the two specs line by line.</p>\n<div class='card'>" as *u8)
1303 o = of_render_diff(out, o, ba, nab, bb, nbb)
1304 o = of_cat(out, o, "</div></main>\n" as *u8)
1305 o = of_page_foot(out, o)
1306 return o
1307}
1308func of_docpage(root: *u8, base: *u8, name: *u8, out: *u8, cap: i64) -> i64 {
1309 let kb: *u8 = sys_mmap(64)
1310 let vc: i64 = of_manifest_count(root, name, kb, 64)
1311 if vc <= 0 { return 0 - 1 }
1312 let ki: i64 = of_kind_idx(kb)
1313 var ks: i64 = ki
1314 if ks < 0 { ks = 0 }
1315 let eq: *u8 = sys_mmap(4)
1316 eq[0] = 0 as u8
1317 var o: i64 = of_shell_top(out, 0, name, base, eq)
1318 o = of_cat(out, o, "<main id='main' class='wrap'><p class='crumb'><a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/'>← All files</a></p><h1>" as *u8)
1319 o = of_esc(out, o, name)
1320 o = of_cat(out, o, " <span class='k k" as *u8); o = of_catn(out, o, ks); o = of_cat(out, o, "'>" as *u8); o = of_esc(out, o, kb)
1321 o = of_cat(out, o, "</span> <span class='stamp'>Saved v" as *u8)
1322 o = of_catn(out, o, vc)
1323 o = of_cat(out, o, " · " as *u8)
1324 o = of_ago(out, o, of_manifest_last_us(root, name))
1325 o = of_cat(out, o, "</span></h1><p class='sub'>" as *u8)
1326 o = of_catn(out, o, vc)
1327 o = of_cat(out, o, " version(s), additive — saving creates v" as *u8)
1328 o = of_catn(out, o, vc + 1)
1329 o = of_cat(out, o, ", earlier versions stay forever.</p>\n" as *u8)
1330 let vd: *u8 = sys_mmap(512)
1331 of_vdir(root, name, vc, vd)
1332 let sp: *u8 = sys_mmap(600)
1333 var so: i64 = of_cat(sp, 0, vd); so = of_cat(sp, so, "/spec.txt" as *u8); sp[so] = 0 as u8
1334 let spec: *u8 = sys_mmap(131072)
1335 let sl: i64 = of_read_file(sp, spec, 131071)
1336 if sl > 0 { spec[sl] = 0 as u8 }
1337 // ---- the visual editor card: toolbar + WYSIWYG surface + raw-spec fallback, all in one form ----
1338 o = of_cat(out, o, "<div class='card'>" as *u8)
1339 o = of_toolbar(out, o, ks)
1340 o = of_cat(out, o, "<form id='savef' method='post' action='" as *u8)
1341 o = of_cat(out, o, base)
1342 o = of_cat(out, o, "/save'><input type='hidden' name='kind' value='" as *u8)
1343 o = of_cat(out, o, kb)
1344 o = of_cat(out, o, "'><input type='hidden' name='name' value='" as *u8)
1345 o = of_cat(out, o, name)
1346 o = of_cat(out, o, "'>" as *u8)
1347 if ks == 0 { o = of_render_doc(out, o, spec, sl) }
1348 if ks == 1 { o = of_render_sheet(out, o, spec, sl) }
1349 if ks == 2 { o = of_render_deck(out, o, spec, sl) }
1350 o = of_cat(out, o, "<details id='rawd' class='rawwrap' open><summary>Edit raw spec</summary><textarea id='specta' name='spec'>" as *u8)
1351 if sl > 0 { o = of_esc(out, o, spec) }
1352 o = of_cat(out, o, "</textarea></details>" as *u8)
1353 o = of_cat(out, o, "<p><button type='submit' class='save'>Save as v" as *u8)
1354 o = of_catn(out, o, vc + 1)
1355 o = of_cat(out, o, "</button> <span id='savest' class='hint'></span></p></form></div>\n" as *u8)
1356 if ks == 0 {
1357 o = of_cat(out, o, "<div class='card'><h2 style='margin:0 0 8px'>✨ AI draft</h2><p class='hint' style='margin:0 0 10px'>Continue this document with our OWN sovereign no-float 0.5B model, on our own hardware — zero OpenAI. The draft is appended as a NEW version you can edit, diff or restore. <b>Experimental</b> (0.5B is small — quality is rough).</p><form method='post' action='" as *u8)
1358 o = of_cat(out, o, base)
1359 o = of_cat(out, o, "/ai'><input type='hidden' name='name' value='" as *u8)
1360 o = of_cat(out, o, name)
1361 o = of_cat(out, o, "'><button type='submit' class='ghost'>✨ Continue with AI</button></form></div>\n" as *u8)
1362 // ---- OF-A4 AGENT MODE card: plan -> execute -> refine, one turn per click ----
1363 let agb: *u8 = sys_mmap(8192)
1364 let agn: i64 = of_agent_read(root, name, agb, 8000)
1365 let agsteps: i64 = of_agent_tagcount(agb, agn, 83)
1366 let agdone: i64 = of_agent_done(agb, agn)
1367 o = of_cat(out, o, "<div class='card'><h2 style='margin:0 0 8px'>🤖 Agent mode</h2><p class='hint' style='margin:0 0 10px'>Give it a goal and it <b>plans, executes and refines</b> multi-step work on this document — on OUR own sovereign model, zero cloud. Each step lands as a <b>new version</b>, so the agent's whole trajectory stays diffable and restorable. One click = one turn (each model turn takes several seconds). <b>Experimental</b> (0.5B is small — quality is rough).</p>" as *u8)
1368 if agn <= 0 {
1369 o = of_cat(out, o, "<form method='post' action='" as *u8)
1370 o = of_cat(out, o, base)
1371 o = of_cat(out, o, "/agent'><input type='hidden' name='name' value='" as *u8)
1372 o = of_cat(out, o, name)
1373 o = of_cat(out, o, "'><input type='text' name='goal' placeholder='e.g. add a section on summer plans and a closing' style='width:100%;margin-bottom:8px'><button type='submit' class='ghost'>🤖 Plan it</button></form>" as *u8)
1374 } else {
1375 let agg: *u8 = sys_mmap(512)
1376 of_agent_tagline(agb, agn, 71, 0, agg, 512)
1377 o = of_cat(out, o, "<p style='margin:0 0 6px'><b>Goal:</b> " as *u8)
1378 o = of_esc(out, o, agg)
1379 o = of_cat(out, o, "</p><ol class='agentplan' style='margin:0 0 10px 18px'>" as *u8)
1380 let agsb: *u8 = sys_mmap(256)
1381 var agi: i64 = 0
1382 while agi < agsteps {
1383 of_agent_tagline(agb, agn, 83, agi, agsb, 256)
1384 o = of_cat(out, o, "<li>" as *u8)
1385 if agi < agdone { o = of_cat(out, o, "<span class='cnt'>✓</span> " as *u8) }
1386 o = of_esc(out, o, agsb)
1387 o = of_cat(out, o, "</li>" as *u8)
1388 agi = agi + 1
1389 }
1390 o = of_cat(out, o, "</ol>" as *u8)
1391 if agdone > agsteps {
1392 o = of_cat(out, o, "<p class='hint' style='margin:0 0 10px'>✓ <b>Run complete</b> — every step drafted and refined. Give a new goal to start another run.</p><form method='post' action='" as *u8)
1393 o = of_cat(out, o, base)
1394 o = of_cat(out, o, "/agent'><input type='hidden' name='name' value='" as *u8)
1395 o = of_cat(out, o, name)
1396 o = of_cat(out, o, "'><input type='text' name='goal' placeholder='new goal' style='width:100%;margin-bottom:8px'><button type='submit' class='ghost'>🤖 Plan again</button></form>" as *u8)
1397 } else {
1398 o = of_cat(out, o, "<p class='hint' style='margin:0 0 10px'>Turn " as *u8)
1399 o = of_catn(out, o, agdone + 1)
1400 o = of_cat(out, o, " of " as *u8)
1401 o = of_catn(out, o, agsteps + 1)
1402 o = of_cat(out, o, " (the last turn is the refine pass).</p><form method='post' action='" as *u8)
1403 o = of_cat(out, o, base)
1404 o = of_cat(out, o, "/agent'><input type='hidden' name='name' value='" as *u8)
1405 o = of_cat(out, o, name)
1406 o = of_cat(out, o, "'><button type='submit' class='ghost'>▶ " as *u8)
1407 if agdone < agsteps { o = of_cat(out, o, "Run next step" as *u8) } else { o = of_cat(out, o, "Run final refine" as *u8) }
1408 o = of_cat(out, o, "</button></form>" as *u8)
1409 }
1410 }
1411 o = of_cat(out, o, "</div>\n" as *u8)
1412 }
1413 // OF-A2 (sheets) / OF-A3 (decks): the same sovereign seat, in each artifact's own grammar. Agent mode stays
1414 // doc-only for now (it appends prose), so these get the single-turn card, not the plan/execute/refine loop.
1415 if ks != 0 {
1416 o = of_cat(out, o, "<div class='card'><h2 style='margin:0 0 8px'>✨ " as *u8)
1417 if ks == 1 { o = of_cat(out, o, "AI insight" as *u8) } else { o = of_cat(out, o, "AI slide" as *u8) }
1418 o = of_cat(out, o, "</h2><p class='hint' style='margin:0 0 10px'>" as *u8)
1419 if ks == 1 {
1420 o = of_cat(out, o, "Ask our OWN sovereign model to read this grid and add one insight as a new row — zero cloud. It lands as a NEW version you can edit, diff or restore." as *u8)
1421 } else {
1422 o = of_cat(out, o, "Ask our OWN sovereign model to draft the next slide (title + bullet) from the deck so far — zero cloud. It lands as a NEW version you can edit, diff or restore." as *u8)
1423 }
1424 o = of_cat(out, o, " <b>Experimental</b> (0.5B is small — quality is rough).</p><form method='post' action='" as *u8)
1425 o = of_cat(out, o, base)
1426 o = of_cat(out, o, "/ai'><input type='hidden' name='name' value='" as *u8)
1427 o = of_cat(out, o, name)
1428 o = of_cat(out, o, "'><button type='submit' class='ghost'>✨ " as *u8)
1429 if ks == 1 { o = of_cat(out, o, "Add an AI insight" as *u8) } else { o = of_cat(out, o, "Draft the next slide" as *u8) }
1430 o = of_cat(out, o, "</button></form></div>\n" as *u8)
1431 }
1432 // U3: star + folder controls. Zero-JS forms, same additive spirit as everything else -- neither touches
1433 // the spec or the version chain, so organising a file can never damage its content.
1434 o = of_cat(out, o, "<div class='card'><h2 style='margin:0 0 8px'>Organise</h2><p class='hint' style='margin:0 0 10px'>Star it to pin it to the top of your library, or file it in a folder. Neither changes the document or its history.</p><form method='post' action='" as *u8)
1435 o = of_cat(out, o, base)
1436 o = of_cat(out, o, "/star' style='display:inline'><input type='hidden' name='name' value='" as *u8)
1437 o = of_cat(out, o, name)
1438 o = of_cat(out, o, "'><button type='submit' class='ghost'>" as *u8)
1439 if of_starred(root, name) == 1 { o = of_cat(out, o, "★ Starred (click to unstar)" as *u8) } else { o = of_cat(out, o, "☆ Star this file" as *u8) }
1440 o = of_cat(out, o, "</button></form> <form method='post' action='" as *u8)
1441 o = of_cat(out, o, base)
1442 o = of_cat(out, o, "/folder' style='display:inline'><input type='hidden' name='name' value='" as *u8)
1443 o = of_cat(out, o, name)
1444 o = of_cat(out, o, "'><input type='text' name='folder' placeholder='folder' value='" as *u8)
1445 let fcur: *u8 = sys_mmap(64)
1446 of_folder_get(root, name, fcur, 64)
1447 o = of_esc(out, o, fcur)
1448 o = of_cat(out, o, "'><button type='submit' class='ghost'>File it</button></form></div>
1449" as *u8)
1450 o = of_cat(out, o, "<div class='card'><h2 style='margin:0 0 8px'>Versions</h2><div class='tablewrap'><table><thead><tr><th>Version</th><th>Changes</th><th>Preview</th><th>Download</th><th>Restore</th><th>Sign</th></tr></thead><tbody>" as *u8)
1451 var v: i64 = vc
1452 while v >= 1 {
1453 o = of_cat(out, o, "<tr><td><b>v" as *u8); o = of_catn(out, o, v)
1454 o = of_cat(out, o, "</b>" as *u8)
1455 if of_manifest_is_auto(root, name, v) == 1 { o = of_cat(out, o, " <span class='cnt'>(auto)</span>" as *u8) }
1456 o = of_cat(out, o, "</td><td>" as *u8)
1457 if v >= 2 { o = of_cat(out, o, "<a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/diff/" as *u8); o = of_cat(out, o, name); o = of_cat(out, o, "/" as *u8); o = of_catn(out, o, v - 1); o = of_cat(out, o, "/" as *u8); o = of_catn(out, o, v); o = of_cat(out, o, "'>vs v" as *u8); o = of_catn(out, o, v - 1); o = of_cat(out, o, "</a>" as *u8) }
1458 else { o = of_cat(out, o, "—" as *u8) }
1459 o = of_cat(out, o, "</td><td><a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/preview/" as *u8); o = of_cat(out, o, name); o = of_cat(out, o, "/v" as *u8); o = of_catn(out, o, v)
1460 o = of_cat(out, o, "'>preview</a></td><td><a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/file/" as *u8); o = of_cat(out, o, name); o = of_cat(out, o, "/v" as *u8); o = of_catn(out, o, v)
1461 o = of_cat(out, o, "'>" as *u8); o = of_esc(out, o, name); o = of_cat(out, o, "." as *u8); o = of_cat(out, o, of_ext(ks)); o = of_cat(out, o, "</a></td><td>" as *u8)
1462 if v < vc {
1463 o = of_cat(out, o, "<form method='post' action='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/restore' style='margin:0'><input type='hidden' name='name' value='" as *u8); o = of_cat(out, o, name); o = of_cat(out, o, "'><input type='hidden' name='version' value='" as *u8); o = of_catn(out, o, v); o = of_cat(out, o, "'><button type='submit' class='ghost' title='Save this version as the newest (nothing is lost)'>Restore</button></form>" as *u8)
1464 } else { o = of_cat(out, o, "<span class='cnt'>current</span>" as *u8) }
1465 o = of_cat(out, o, "</td><td>" as *u8)
1466 o = of_sign_cell(out, o, root, base, name, v)
1467 o = of_cat(out, o, "</td></tr>" as *u8)
1468 v = v - 1
1469 }
1470 o = of_cat(out, o, "</tbody></table></div></div></main>\n<script src='" as *u8)
1471 o = of_cat(out, o, base)
1472 o = of_cat(out, o, "/app.js'></script>\n" as *u8)
1473 o = of_page_foot(out, o)
1474 return o
1475}
1476func of_err(out: *u8, status: *u8, msg: *u8) -> i64 {
1477 // body = "LOUD: " + msg + "\n" (6 + len(msg) + 1). Emit Content-Length + Connection: close so a STRICT
1478 // CL-stop client (our own nx_https TLS stack / nx_office_live_verify) can frame the error without hanging.
1479 let bl: i64 = 6 + of_slen(msg) + 1
1480 var o: i64 = of_cat(out, 0, "HTTP/1.1 " as *u8)
1481 o = of_cat(out, o, status)
1482 o = of_cat(out, o, "\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: " as *u8)
1483 o = of_catn(out, o, bl)
1484 o = of_cat(out, o, "\r\nConnection: close\r\n\r\nLOUD: " as *u8)
1485 o = of_cat(out, o, msg)
1486 o = of_catc(out, o, 10)
1487 return o
1488}
1489// ---- IN-APP AI (the marquee): draft with OUR OWN sovereign no-float 0.5B LLM served on loopback :11434 ----
1490// HONEST: it is a 0.5B integer model -- draft quality is EXPERIMENTAL, not GPT/Copilot-class. The point is
1491// sovereign convergence: our office drafting off our own model on our own hardware, zero OpenAI. Graceful:
1492// if the seat is down, the caller returns a LOUD 503 (never an office error).
1493// extract the FIRST "content":"..." value (JSON-unescaped) from buf into out; returns length or -1 if absent.
1494func of_extract_json_content(buf: *u8, n: i64, out: *u8, cap: i64) -> i64 {
1495 let key: *u8 = "\"content\":\"" as *u8
1496 var i: i64 = 0
1497 var found: i64 = 0 - 1
1498 while i + 11 <= n {
1499 var m: i64 = 1; var j: i64 = 0
1500 while j < 11 { if buf[i+j] != key[j] { m = 0; j = 11 } else { j = j + 1 } }
1501 if m == 1 { found = i + 11; i = n } else { i = i + 1 }
1502 }
1503 if found < 0 { return 0 - 1 }
1504 var o: i64 = 0
1505 var k: i64 = found
1506 var go: i64 = 1
1507 while go == 1 {
1508 if k >= n { go = 0 } else {
1509 let c: i64 = buf[k] as i64
1510 if c == 34 { go = 0 } else {
1511 if c == 92 {
1512 k = k + 1
1513 if k < n {
1514 let e: i64 = buf[k] as i64
1515 if e == 110 { if o < cap-1 { out[o] = 10 as u8; o = o + 1 } } else {
1516 if e == 116 { if o < cap-1 { out[o] = 9 as u8; o = o + 1 } } else {
1517 if e == 34 { if o < cap-1 { out[o] = 34 as u8; o = o + 1 } } else {
1518 if e == 92 { if o < cap-1 { out[o] = 92 as u8; o = o + 1 } } else {
1519 if o < cap-1 { out[o] = buf[k]; o = o + 1 } } } } }
1520 }
1521 k = k + 1
1522 } else {
1523 if o < cap-1 { out[o] = buf[k]; o = o + 1 }
1524 k = k + 1
1525 } }
1526 }
1527 }
1528 out[o] = 0 as u8
1529 return o
1530}
1531// flatten a doc spec (H/B/I/P lines; T table rows) into plain running text for the LLM prompt (strip the 2-char
1532// kind prefix, '|' table cells -> spaces). Keeps only the tail (last ~cap chars) since the 0.5B context is small.
1533func of_spec_to_text(spec: *u8, sl: i64, out: *u8, cap: i64) -> i64 {
1534 let tmp: *u8 = sys_mmap(sl + 16)
1535 var to: i64 = 0
1536 var i: i64 = 0
1537 while i < sl {
1538 var e: i64 = i
1539 while e < sl { if spec[e] == (10 as u8) { break } e = e + 1 }
1540 var cs: i64 = i
1541 if e >= i + 2 { if spec[i+1] == (32 as u8) { cs = i + 2 } }
1542 var k: i64 = cs
1543 while k < e { let c: i64 = spec[k] as i64; if c == 124 { tmp[to] = 32 as u8 } else { tmp[to] = spec[k] } to = to + 1; k = k + 1 }
1544 tmp[to] = 32 as u8; to = to + 1
1545 i = e + 1
1546 }
1547 // keep the tail
1548 var start: i64 = 0
1549 if to > cap { start = to - cap }
1550 var oo: i64 = 0
1551 var t: i64 = start
1552 while t < to { if oo < cap - 1 { out[oo] = tmp[t]; oo = oo + 1 } t = t + 1 }
1553 out[oo] = 0 as u8
1554 return oo
1555}
1556// call our sovereign LLM seat (POST /complete on 127.0.0.1:11434) to continue `prompt`. Fills out with the
1557// completion (JSON-unescaped); returns length, or <0 on conn-fail / non-200 / empty (caller -> graceful 503).
1558// max_tokens is a PARAMETER (of_llm_complete keeps the proven 24 default) because agent mode needs a longer
1559// budget for its PLAN turn than for a step turn. Keep every value small enough that ONE call finishes well
1560// under the edge's ~15s proxy timeout -- measured ~0.29s/token, so 32 tokens ~= 9.3s is the safe ceiling.
1561func of_llm_complete_n(prompt: *u8, plen: i64, out: *u8, cap: i64, maxtok: i64) -> i64 {
1562 let bcap: i64 = plen * 2 + 256
1563 let jb: *u8 = sys_mmap(bcap)
1564 var bo: i64 = of_cat(jb, 0, "{\"content\":\"" as *u8)
1565 var i: i64 = 0
1566 while i < plen {
1567 let c: i64 = prompt[i] as i64
1568 if c == 34 { jb[bo] = 92 as u8; bo = bo + 1; jb[bo] = 34 as u8; bo = bo + 1 } else {
1569 if c == 92 { jb[bo] = 92 as u8; bo = bo + 1; jb[bo] = 92 as u8; bo = bo + 1 } else {
1570 if c == 10 { jb[bo] = 92 as u8; bo = bo + 1; jb[bo] = 110 as u8; bo = bo + 1 } else {
1571 if c == 9 { jb[bo] = 32 as u8; bo = bo + 1 } else {
1572 if c == 13 { } else {
1573 if c < 32 { jb[bo] = 32 as u8; bo = bo + 1 } else { jb[bo] = prompt[i]; bo = bo + 1 } } } } } }
1574 i = i + 1
1575 }
1576 bo = of_cat(jb, bo, "\",\"max_tokens\":" as *u8)
1577 bo = of_catn(jb, bo, maxtok)
1578 bo = of_catc(jb, bo, 125)
1579 jb[bo] = 0 as u8
1580 let addr: *u8 = sys_mmap(16)
1581 nx_http_client_sockaddr_ipv4(addr, 127, 0, 0, 1, 11434)
1582 let fd: i64 = sys_socket(2, 1, 0)
1583 if fd < 0 { return 0 - 1 }
1584 if nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { sys_close(fd); return 0 - 2 }
1585 sys_set_socket_timeout(fd, 14)
1586 let ct: *u8 = "application/json" as *u8
1587 let req: *u8 = sys_mmap(8192 + bo)
1588 let reqlen: i64 = nx_http_client_build_request_post("/complete" as *u8, 9, "localhost" as *u8, 9, ct, 16, jb, bo, req)
1589 sys_write(fd, req, reqlen)
1590 let resp: *u8 = sys_mmap(262144)
1591 var rn: i64 = 0
1592 var go: i64 = 1
1593 while go == 1 { if rn >= 262143 { go = 0 } else { let r: i64 = sys_read(fd, (resp as i64 + rn) as *u8, 262143 - rn); if r <= 0 { go = 0 } else { rn = rn + r } } }
1594 sys_close(fd)
1595 if rn < 15 { return 0 - 3 }
1596 if (resp[9] as i64) != 50 { return 0 - 4 }
1597 if (resp[10] as i64) != 48 { return 0 - 4 }
1598 if (resp[11] as i64) != 48 { return 0 - 4 }
1599 resp[rn] = 0 as u8
1600 let cl: i64 = of_extract_json_content(resp, rn, out, cap)
1601 if cl <= 0 { return 0 - 5 }
1602 return cl
1603}
1604func of_llm_complete(prompt: *u8, plen: i64, out: *u8, cap: i64) -> i64 {
1605 return of_llm_complete_n(prompt, plen, out, cap, 24)
1606}
1607// OF-A2 / OF-A3: each kind gets its OWN prompt builder rather than one function with a kind flag, so the
1608// census can needle a DEFINITION per axis (its own anti-faking law: a comment mentioning a bare name must
1609// never flip an axis) and each stays independently editable.
1610func of_ai_prompt_sheet(ptext: *u8, out: *u8) -> i64 {
1611 var o: i64 = of_cat(out, 0, "This is a spreadsheet, tab separated. Data: " as *u8)
1612 o = of_cat(out, o, ptext)
1613 o = of_cat(out, o, " . State one short insight about this data:" as *u8)
1614 out[o] = 0 as u8
1615 return o
1616}
1617func of_ai_prompt_deck(ptext: *u8, out: *u8) -> i64 {
1618 var o: i64 = of_cat(out, 0, "Slides so far: " as *u8)
1619 o = of_cat(out, o, ptext)
1620 o = of_cat(out, o, " . Write the next slide as a title, then one bullet:" as *u8)
1621 out[o] = 0 as u8
1622 return o
1623}
1624
1625// ================= OF-A4 AGENT MODE -- multi-step PLAN -> EXECUTE -> REFINE =========================
1626// The 2025/2026 headline differentiator the SOTA bar names (M365 Copilot "Agent Mode" GA 2026-04-22:
1627// Copilot plans, executes and refines MULTI-STEP work in the app). Ours runs on OUR OWN sovereign seat.
1628//
1629// WHY IT IS STEP-DRIVEN, NOT A SINGLE LONG CALL: one LLM turn costs ~7-10s and the edge proxy times out at
1630// ~15s. A 4-step agent in one request would ALWAYS exceed it. So each POST /office/agent advances EXACTLY
1631// ONE turn and persists its state; the loop is driven by repeated POSTs. That is a real constraint honestly
1632// handled, not a reduced capability -- the agent is still multi-step, state-carrying and resumable.
1633//
1634// WHERE THE EXCEEDS IS: every executed step lands as a NEW ADDITIVE VERSION through of_save, so the entire
1635// agent trajectory is diffable and restorable. The cloud leaders' agent steps are ephemeral -- you get the
1636// final artifact and the reasoning is gone. Ours is content-addressed history you can walk backwards.
1637//
1638// State lives in a SIDECAR <root>/<name>/agent.txt so the document spec stays PURE CONTENT (no new spec line
1639// kinds = no renderer risk, no format migration). Line-based, same idiom as the spec:
1640// G <goal> one line, the operator's goal
1641// S <step> one line per planned step, in order
1642// D <n> how many turns are DONE. n in 0..steps = executing; n > steps = refined + complete.
1643func of_agent_path(root: *u8, name: *u8, out: *u8) -> i64 {
1644 var o: i64 = of_cat(out, 0, root); o = of_cat(out, o, "/" as *u8); o = of_cat(out, o, name)
1645 o = of_cat(out, o, "/agent.txt" as *u8); out[o] = 0 as u8
1646 return o
1647}
1648func of_agent_read(root: *u8, name: *u8, buf: *u8, cap: i64) -> i64 {
1649 let p: *u8 = sys_mmap(512)
1650 of_agent_path(root, name, p)
1651 return of_read_file(p, buf, cap)
1652}
1653func of_agent_write(root: *u8, name: *u8, buf: *u8, n: i64) -> i64 {
1654 let p: *u8 = sys_mmap(512)
1655 of_agent_path(root, name, p)
1656 return of_write_file(p, buf, n)
1657}
1658// count the lines whose FIRST byte is `tag` (tags: 71='G' 83='S' 68='D')
1659func of_agent_tagcount(buf: *u8, n: i64, tag: i64) -> i64 {
1660 var c: i64 = 0
1661 var i: i64 = 0
1662 var bol: i64 = 1
1663 while i < n {
1664 if bol == 1 { if (buf[i] as i64) == tag { c = c + 1 } }
1665 if buf[i] == (10 as u8) { bol = 1 } else { bol = 0 }
1666 i = i + 1
1667 }
1668 return c
1669}
1670// copy the body of the idx-th (0-based) line carrying `tag` into out; returns its length (0 = no such line)
1671func of_agent_tagline(buf: *u8, n: i64, tag: i64, idx: i64, out: *u8, cap: i64) -> i64 {
1672 var seen: i64 = 0
1673 var i: i64 = 0
1674 var bol: i64 = 1
1675 while i < n {
1676 if bol == 1 {
1677 if (buf[i] as i64) == tag {
1678 if seen == idx {
1679 var s: i64 = i + 1
1680 if s < n { if buf[s] == (32 as u8) { s = s + 1 } }
1681 var o: i64 = 0
1682 while s < n {
1683 if buf[s] == (10 as u8) { s = n } else {
1684 if o < cap - 1 { out[o] = buf[s]; o = o + 1 }
1685 s = s + 1 }
1686 }
1687 out[o] = 0 as u8
1688 return o
1689 }
1690 seen = seen + 1
1691 }
1692 }
1693 if buf[i] == (10 as u8) { bol = 1 } else { bol = 0 }
1694 i = i + 1
1695 }
1696 out[0] = 0 as u8
1697 return 0
1698}
1699func of_agent_done(buf: *u8, n: i64) -> i64 {
1700 let t: *u8 = sys_mmap(32)
1701 if of_agent_tagline(buf, n, 68, 0, t, 32) <= 0 { return 0 }
1702 return of_atoi(t)
1703}
1704// Turn ONE free-text LLM completion into at most 4 plan steps. Splits on newlines first; if that yields
1705// fewer than 2 steps, falls back to splitting on ". " so a single-line reply still becomes a real plan.
1706// Leading list punctuation (digits, '.', ')', '-', '*', spaces) is stripped so "1. Draft intro" -> "Draft intro".
1707// Emits "S <step>\n" lines into out. Returns how many steps were written (0 = the model gave us nothing usable).
1708func of_agent_plan_parse(comp: *u8, cl: i64, out: *u8, cap: i64) -> i64 {
1709 var steps: i64 = 0
1710 var o: i64 = 0
1711 var ph: i64 = 0
1712 while ph < 2 {
1713 steps = 0
1714 o = 0
1715 var i: i64 = 0
1716 while i < cl {
1717 if steps >= 4 { i = cl } else {
1718 // find the end of this chunk: newline always ends it; in phase 1 ". " ends it too
1719 var e: i64 = i
1720 var scan: i64 = 1
1721 while scan == 1 {
1722 if e >= cl { scan = 0 } else {
1723 if comp[e] == (10 as u8) { scan = 0 } else {
1724 var brk: i64 = 0
1725 if ph == 1 {
1726 if comp[e] == (46 as u8) {
1727 if e + 1 < cl { if comp[e+1] == (32 as u8) { brk = 1 } }
1728 }
1729 }
1730 if brk == 1 { scan = 0 } else { e = e + 1 }
1731 }
1732 }
1733 }
1734 // strip leading list punctuation + spaces: "1. Draft intro" -> "Draft intro"
1735 var s: i64 = i
1736 var strip: i64 = 1
1737 while strip == 1 {
1738 if s >= e { strip = 0 } else {
1739 let c: i64 = comp[s] as i64
1740 if c == 32 { s = s + 1 } else {
1741 if c == 46 { s = s + 1 } else {
1742 if c == 41 { s = s + 1 } else {
1743 if c == 45 { s = s + 1 } else {
1744 if c == 42 { s = s + 1 } else {
1745 if c >= 48 { if c <= 57 { s = s + 1 } else { strip = 0 } } else { strip = 0 } } } } } }
1746 }
1747 }
1748 // keep it only if real text survives (>= 4 chars) and it fits the buffer
1749 if e - s >= 4 {
1750 if o + (e - s) + 8 < cap {
1751 o = of_cat(out, o, "S " as *u8)
1752 var k: i64 = s
1753 var w: i64 = 0
1754 while k < e {
1755 if w < 120 {
1756 let c2: i64 = comp[k] as i64
1757 if c2 == 9 { out[o] = 32 as u8 } else { if c2 == 13 { out[o] = 32 as u8 } else { out[o] = comp[k] } }
1758 o = o + 1; w = w + 1
1759 }
1760 k = k + 1
1761 }
1762 o = of_catc(out, o, 10)
1763 steps = steps + 1
1764 }
1765 }
1766 i = e + 1
1767 }
1768 }
1769 // phase 0 (newline split) wins if it found a real multi-step plan; else retry splitting sentences
1770 if steps >= 2 { ph = 2 } else { ph = ph + 1 }
1771 }
1772 out[o] = 0 as u8
1773 return steps
1774}
1775// Insert Content-Length before the header terminator so a STRICT HTTP client (the sovereign Nishi Browser)
1776// can frame the body. Static docroot files send it; our HTML pages (of_page_top) did NOT, so the in-browser
1777// GET of /office failed to frame after a clean TLS handshake (Waterfox tolerates it by reading until close).
1778// out holds a full "HTTP/.. \r\n<headers>\r\n\r\n<body>" of length n; returns the new length. Idempotent
1779// (skips if Content-Length already present, e.g. of_serve downloads) and fail-safe (no room -> unchanged).
1780func of_cl_frame(out: *u8, n: i64, cap: i64) -> i64 {
1781 if n <= 0 { return n }
1782 var p: i64 = 0 - 1
1783 var i: i64 = 0
1784 while i + 3 < n { if out[i] == (13 as u8) { if out[i+1] == (10 as u8) { if out[i+2] == (13 as u8) { if out[i+3] == (10 as u8) { p = i; i = n } } } } i = i + 1 }
1785 if p < 0 { return n }
1786 if of_memhas(out, p, "Content-Length:" as *u8) == 1 { return n }
1787 let bodylen: i64 = n - (p + 4)
1788 let ins: *u8 = sys_mmap(48)
1789 var io: i64 = of_cat(ins, 0, "Content-Length: " as *u8)
1790 io = of_catn(ins, io, bodylen)
1791 io = of_catc(ins, io, 13); io = of_catc(ins, io, 10)
1792 if n + io >= cap { return n }
1793 var s: i64 = n - 1
1794 while s >= p + 2 { out[s + io] = out[s]; s = s - 1 }
1795 var k: i64 = 0
1796 while k < io { out[p + 2 + k] = ins[k]; k = k + 1 }
1797 return n + io
1798}
1799// serve <root>/<name>/v<N>/{file.<ext>|preview.html}. mode 0 = artifact download, 1 = preview html.
1800func of_serve(root: *u8, name: *u8, vn: i64, mode: i64, out: *u8, cap: i64) -> i64 {
1801 let kb: *u8 = sys_mmap(64)
1802 let vc: i64 = of_manifest_count(root, name, kb, 64)
1803 if vc <= 0 { return 0 - 1 }
1804 if vn < 1 { return 0 - 1 }
1805 if vn > vc { return 0 - 1 }
1806 let ki: i64 = of_kind_idx(kb)
1807 var ks: i64 = ki
1808 if ks < 0 { ks = 0 }
1809 let vd: *u8 = sys_mmap(512)
1810 of_vdir(root, name, vn, vd)
1811 let fp: *u8 = sys_mmap(600)
1812 var fo: i64 = of_cat(fp, 0, vd)
1813 if mode == 1 { fo = of_cat(fp, fo, "/preview.html" as *u8) } else { fo = of_cat(fp, fo, "/file." as *u8); fo = of_cat(fp, fo, of_ext(ks)) }
1814 fp[fo] = 0 as u8
1815 let fb: *u8 = sys_mmap(1048576)
1816 let fl: i64 = of_read_file(fp, fb, 1048576)
1817 if fl < 0 { return 0 - 1 }
1818 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8)
1819 if mode == 1 { o = of_cat(out, o, "text/html; charset=utf-8" as *u8) } else { o = of_cat(out, o, of_ct(ks)) }
1820 o = of_cat(out, o, "\r\nContent-Length: " as *u8)
1821 o = of_catn(out, o, fl)
1822 if mode == 0 {
1823 o = of_cat(out, o, "\r\nContent-Disposition: attachment; filename=" as *u8)
1824 o = of_cat(out, o, name)
1825 o = of_cat(out, o, "." as *u8)
1826 o = of_cat(out, o, of_ext(ks))
1827 }
1828 o = of_cat(out, o, "\r\n\r\n" as *u8)
1829 var i: i64 = 0
1830 while i < fl { if o + i < cap { out[o + i] = fb[i] } i = i + 1 }
1831 return o + fl
1832}
1833// parse "/<pfx>/<name>/v<N>" -> name + N. returns N (>=1) or -1.
1834func of_parse_nv(path: *u8, pfxlen: i64, name: *u8, ncap: i64) -> i64 {
1835 var i: i64 = pfxlen
1836 var t: i64 = 0
1837 while path[i] != (0 as u8) { if path[i] == (47 as u8) { break } if t < ncap - 1 { name[t] = path[i]; t = t + 1 } i = i + 1 }
1838 name[t] = 0 as u8
1839 if t == 0 { return 0 - 1 }
1840 if path[i] != (47 as u8) { return 0 - 1 }
1841 i = i + 1
1842 if path[i] != (118 as u8) { return 0 - 1 }
1843 i = i + 1
1844 var v: i64 = 0
1845 var d: i64 = 0
1846 while path[i] != (0 as u8) {
1847 let c: i64 = path[i] as i64
1848 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); d = d + 1; i = i + 1 } else { return 0 - 1 } } else { return 0 - 1 }
1849 }
1850 if d == 0 { return 0 - 1 }
1851 return v
1852}
1853
1854// the app: request bytes -> response bytes. returns response length.
1855// base = the URL mount prefix (e.g. "/office" when reverse-proxied at nishifamily.com/office, "" for the raw
1856// daemon). The edge forwards the FULL path verbatim, so we STRIP base off the incoming path before routing while
1857// build "doc:<name>" / "user:<handle>" refs for the ReBAC plane.
1858func of_docref(out: *u8, name: *u8) -> i64 { var o: i64 = of_cat(out, 0, "doc:" as *u8); o = of_cat(out, o, name); out[o] = 0 as u8; return o }
1859func of_meref(out: *u8, handle: *u8) -> i64 { var o: i64 = of_cat(out, 0, "user:" as *u8); o = of_cat(out, o, handle); out[o] = 0 as u8; return o }
1860func of_grpref(out: *u8, gname: *u8) -> i64 { var o: i64 = of_cat(out, 0, "group:" as *u8); o = of_cat(out, o, gname); out[o] = 0 as u8; return o }
1861// the userset "group:<g>#member" -- sharing a doc with THIS grants every member of the group (Zanzibar userset).
1862func of_grpmemberref(out: *u8, gname: *u8) -> i64 { var o: i64 = of_grpref(out, gname); o = of_cat(out, o, "#member" as *u8); out[o] = 0 as u8; return o }
1863// a share target handle must be [a-zA-Z0-9_-] 1..64 -- so ':' or '#' can never forge a type/userset in a tuple ref.
1864func of_tok_ok(s: *u8) -> i64 {
1865 if s[0] == (0 as u8) { return 0 }
1866 var i: i64 = 0
1867 while s[i] != (0 as u8) {
1868 let c: i64 = s[i] as i64
1869 var ok: i64 = 0
1870 if c >= 97 { if c <= 122 { ok = 1 } }
1871 if c >= 65 { if c <= 90 { ok = 1 } }
1872 if c >= 48 { if c <= 57 { ok = 1 } }
1873 if c == 95 { ok = 1 }
1874 if c == 45 { ok = 1 }
1875 if ok == 0 { return 0 }
1876 if i >= 64 { return 0 }
1877 i = i + 1
1878 }
1879 return 1
1880}
1881func of_sess_field(dst: *u8, off: i64, tok: *u8) -> i64 {
1882 var o: i64 = off
1883 if tok[0] != (0 as u8) { o = of_cat(dst, o, "<input type='hidden' name='sess' value='" as *u8); o = of_cat(dst, o, tok); o = of_cat(dst, o, "'>" as *u8) }
1884 return o
1885}
1886// authz refusal (fail-closed: owned doc, caller not allowed).
1887func of_deny_read(out: *u8) -> i64 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
1888func of_deny_write(out: *u8) -> i64 { return of_err(out, "403 Forbidden" as *u8, "this document is owned; you need edit access (ask the owner to share it)" as *u8) }
1889func of_after_colon(s: *u8) -> *u8 { var i: i64 = 0; while s[i] != (0 as u8) { if (s[i] as i64) == 58 { return (s as i64 + i + 1) as *u8 } i = i + 1 } return s }
1890// TENANT ISOLATION OF THE GROUP PLANE (2026-08-19, LP3 -- one binary, N realm-bound instances): the nishifamily
1891// instance (the default authz prefix) keeps resolving group membership through the cross-surface relate plane exactly
1892// as before; ANY OTHER instance (a firm with its own authz prefix and its own realm of handles) resolves membership
1893// ONLY from its own plane, so a nishifamily group name can never grant a firm document and a handle that happens to
1894// be spelled the same in two realms never crosses them. Derived from the prefix, never a second configuration knob.
1895func of_relate_pfx(azprefix: *u8) -> *u8 {
1896 if of_seq(azprefix, OF_AUTHZ) == 1 { return OF_RELATE }
1897 return azprefix
1898}
1899// read/write authorization for a doc by name. UNOWNED = PUBLIC (1). OWNED = the caller needs the relation.
1900func of_read_ok(azprefix: *u8, me: *u8, authed: i64, nm: *u8) -> i64 {
1901 let dref: *u8 = sys_mmap(320); of_docref(dref, nm)
1902 if rb_obj_has_owner(azprefix, dref) == 0 { return 1 }
1903 if authed == 0 { return 0 }
1904 return rb_check2(azprefix, of_relate_pfx(azprefix), me, "read" as *u8, dref, 0)
1905}
1906func of_write_ok(azprefix: *u8, me: *u8, authed: i64, nm: *u8) -> i64 {
1907 let dref: *u8 = sys_mmap(320); of_docref(dref, nm)
1908 if rb_obj_has_owner(azprefix, dref) == 0 { return 1 }
1909 if authed == 0 { return 0 }
1910 return rb_check2(azprefix, of_relate_pfx(azprefix), me, "write" as *u8, dref, 0)
1911}
1912// SHARE(grant=1)/UNSHARE(grant=0) an OWNED doc -- owner-only. doc:<name> viewer|editor user:<who>.
1913func of_do_share(base: *u8, azprefix: *u8, me: *u8, handle: *u8, authed: i64, body: *u8, blen: i64, out: *u8, grant: i64) -> i64 {
1914 if authed == 0 { return of_deny_write(out) }
1915 let nm: *u8 = sys_mmap(64); let who: *u8 = sys_mmap(64); let lv: *u8 = sys_mmap(16)
1916 of_form_get(body, blen, "name" as *u8, nm, 64)
1917 of_form_get(body, blen, "who" as *u8, who, 64)
1918 of_form_get(body, blen, "level" as *u8, lv, 16)
1919 if of_name_ok(nm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
1920 if of_tok_ok(who) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad handle" as *u8) }
1921 let dref: *u8 = sys_mmap(320); of_docref(dref, nm)
1922 if rb_obj_has_owner(azprefix, dref) == 0 { return of_err(out, "400 Bad Request" as *u8, "save the document first (it becomes yours), then share it" as *u8) }
1923 if rb_check(azprefix, me, "manage" as *u8, dref, 0) == 0 { return of_deny_write(out) }
1924 var rel: *u8 = "viewer" as *u8
1925 if of_seq(lv, "editor" as *u8) == 1 { rel = "editor" as *u8 }
1926 // target=group -> share with the userset group:<who>#member (every group member gets access); else a person.
1927 let tgt: *u8 = sys_mmap(16); of_form_get(body, blen, "target" as *u8, tgt, 16)
1928 let wref: *u8 = sys_mmap(320)
1929 if of_seq(tgt, "group" as *u8) == 1 { of_grpmemberref(wref, who) } else { of_meref(wref, who) }
1930 rb_put(azprefix, dref, rel, wref, handle, grant)
1931 var o: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
1932 o = of_cat(out, o, base); o = of_cat(out, o, "/manage/" as *u8); o = of_cat(out, o, nm); o = of_cat(out, o, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
1933 return o
1934}
1935// copy s into dst up to a '#' (or end), NUL-term. "elders#member" -> "elders".
1936func of_before_hash(dst: *u8, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { if (s[i] as i64) == 35 { dst[i] = 0 as u8; return i } dst[i] = s[i]; i = i + 1 } dst[i] = 0 as u8; return i }
1937// render one shared-with row + its unshare button. subref = "user:<h>" (a person) OR "group:<g>#member" (a group).
1938func of_share_row(out: *u8, off: i64, base: *u8, nm: *u8, subref: *u8, rel: *u8, tok: *u8) -> i64 {
1939 var target: *u8 = "user" as *u8
1940 let who: *u8 = sys_mmap(96)
1941 let label: *u8 = sys_mmap(128)
1942 if of_starts(subref, "group:" as *u8) == 1 {
1943 target = "group" as *u8
1944 of_before_hash(who, of_after_colon(subref))
1945 var lo: i64 = of_cat(label, 0, "group " as *u8); lo = of_cat(label, lo, who); label[lo] = 0 as u8
1946 } else {
1947 var wo: i64 = of_cat(who, 0, of_after_colon(subref)); who[wo] = 0 as u8
1948 var lo: i64 = of_cat(label, 0, who); label[lo] = 0 as u8
1949 }
1950 var o: i64 = of_cat(out, off, "<div class='row'>" as *u8)
1951 o = of_cat(out, o, label); o = of_cat(out, o, " <span class='mut'>" as *u8); o = of_cat(out, o, rel)
1952 o = of_cat(out, o, "</span> <form method='post' action='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/unshare' style='display:inline'>" as *u8)
1953 o = of_sess_field(out, o, tok)
1954 o = of_cat(out, o, "<input type='hidden' name='name' value='" as *u8); o = of_cat(out, o, nm)
1955 o = of_cat(out, o, "'><input type='hidden' name='who' value='" as *u8); o = of_cat(out, o, who)
1956 o = of_cat(out, o, "'><input type='hidden' name='target' value='" as *u8); o = of_cat(out, o, target)
1957 o = of_cat(out, o, "'><input type='hidden' name='level' value='" as *u8); o = of_cat(out, o, rel)
1958 o = of_cat(out, o, "'><button class='ghost'>unshare</button></form></div>" as *u8)
1959 return o
1960}
1961// the owner's Sharing panel for a doc. returns inner-HTML length, or negative (=-1 unauth / -2 not-owned / -3 not-owner).
1962func of_managepage(base: *u8, azprefix: *u8, me: *u8, authed: i64, nm: *u8, tok: *u8, out: *u8, cap: i64) -> i64 {
1963 let dref: *u8 = sys_mmap(320); of_docref(dref, nm)
1964 if authed == 0 { return 0 - 1 }
1965 if rb_obj_has_owner(azprefix, dref) == 0 { return 0 - 2 }
1966 if rb_check(azprefix, me, "manage" as *u8, dref, 0) == 0 { return 0 - 3 }
1967 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>Sharing</title><style>body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;max-width:720px;margin:5vh auto;padding:0 20px;color:#222}.row{padding:8px 0;border-bottom:1px solid #e5e7eb}.mut{color:#888}button{border:0;border-radius:8px;padding:8px 12px;background:rgb(41,84,164);color:#fff;font-weight:600}.ghost{background:#eee;color:#333;padding:4px 10px}input,select{padding:7px;border:1px solid #ccc;border-radius:8px;margin-right:6px}</style></head><body><div class='wrap'><h2>Sharing: " as *u8); o = of_cat(out, o, nm); o = of_cat(out, o, "</h2>" as *u8)
1968 o = of_cat(out, o, "<p class='mut'>You own this document. Share it with a person by handle as viewer or editor; unshare revokes.</p><h3>Shared with</h3>" as *u8)
1969 let vv: *i64 = sys_mmap(8 * 64) as *i64
1970 let nv: i64 = rb_list_subjects(azprefix, dref, "viewer" as *u8, vv, 64)
1971 let ee: *i64 = sys_mmap(8 * 64) as *i64
1972 let ne: i64 = rb_list_subjects(azprefix, dref, "editor" as *u8, ee, 64)
1973 if nv == 0 { if ne == 0 { o = of_cat(out, o, "<div class='mut'>(not shared with anyone yet)</div>" as *u8) } }
1974 var qi: i64 = 0
1975 while qi < ne { o = of_share_row(out, o, base, nm, ee[qi] as *u8, "editor" as *u8, tok); qi = qi + 1 }
1976 qi = 0
1977 while qi < nv { o = of_share_row(out, o, base, nm, vv[qi] as *u8, "viewer" as *u8, tok); qi = qi + 1 }
1978 o = of_cat(out, o, "<h3>Share with someone</h3><form method='post' action='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/share'>" as *u8)
1979 o = of_sess_field(out, o, tok)
1980 o = of_cat(out, o, "<input type='hidden' name='name' value='" as *u8); o = of_cat(out, o, nm)
1981 o = of_cat(out, o, "'><input name='who' placeholder='person handle or group name'> <select name='target'><option value='user'>person</option><option value='group'>group</option></select> <select name='level'><option>viewer</option><option>editor</option></select> <button>Share</button></form>" as *u8)
1982 o = of_cat(out, o, "<p class='mut'>Share with a <a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/groups'>group</a> and every member gets access.</p>" as *u8)
1983 o = of_cat(out, o, "<p><a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/doc/" as *u8); o = of_cat(out, o, nm); o = of_cat(out, o, "'>← back to document</a></p></div></body></html>" as *u8)
1984 return o
1985}
1986
1987// GROUP membership handler: add(1)/remove(0) a member. The caller bootstraps/owns the group. 303 -> /groups.
1988func of_do_group(base: *u8, azprefix: *u8, me: *u8, handle: *u8, authed: i64, body: *u8, blen: i64, out: *u8, add: i64) -> i64 {
1989 if authed == 0 { return of_deny_write(out) }
1990 let gn: *u8 = sys_mmap(64); let who: *u8 = sys_mmap(64)
1991 of_form_get(body, blen, "group" as *u8, gn, 64)
1992 of_form_get(body, blen, "who" as *u8, who, 64)
1993 if of_tok_ok(gn) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad group name" as *u8) }
1994 if of_tok_ok(who) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad handle" as *u8) }
1995 let gref: *u8 = sys_mmap(320); of_grpref(gref, gn)
1996 if rb_may_grant(azprefix, me, gref) == 0 { return of_deny_write(out) }
1997 if rb_obj_has_owner(azprefix, gref) == 0 {
1998 rb_put(azprefix, gref, "owner" as *u8, me, handle, 1)
1999 rb_put(azprefix, gref, "member" as *u8, me, handle, 1)
2000 }
2001 let wref: *u8 = sys_mmap(320); of_meref(wref, who)
2002 rb_put(azprefix, gref, "member" as *u8, wref, handle, add)
2003 var o: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2004 o = of_cat(out, o, base); o = of_cat(out, o, "/groups\r\n\r\n" as *u8)
2005 return o
2006}
2007// the caller's GROUPS page (owned groups + members + management forms). returns a FULL HTTP response.
2008func of_groupspage(base: *u8, azprefix: *u8, me: *u8, authed: i64, tok: *u8, out: *u8, cap: i64) -> i64 {
2009 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>My groups</title><style>body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;max-width:720px;margin:5vh auto;padding:0 20px;color:#222}.row{padding:6px 0;border-bottom:1px solid #eee}.mut{color:#888}button{border:0;border-radius:8px;padding:8px 12px;background:rgb(41,84,164);color:#fff;font-weight:600}.ghost{background:#eee;color:#333;padding:3px 9px}input{padding:7px;border:1px solid #ccc;border-radius:8px;margin-right:6px}</style></head><body><h2>My groups</h2>" as *u8)
2010 if authed == 0 { o = of_cat(out, o, "<p>Sign in to manage groups.</p></body></html>" as *u8); return o }
2011 o = of_cat(out, o, "<p class='mut'>Groups you own. Add people by handle; share a document with a group and every member gets access (revoke a member and they lose it everywhere).</p>" as *u8)
2012 let gg: *i64 = sys_mmap(8 * 64) as *i64
2013 let ng: i64 = rb_list_objects_for_sub(azprefix, me, "owner" as *u8, gg, 64)
2014 if ng == 0 { o = of_cat(out, o, "<div class='mut'>(no groups yet -- create one below)</div>" as *u8) }
2015 var gi: i64 = 0
2016 while gi < ng {
2017 let gref: *u8 = gg[gi] as *u8
2018 let gbare: *u8 = of_after_colon(gref)
2019 o = of_cat(out, o, "<h3>" as *u8); o = of_cat(out, o, gbare); o = of_cat(out, o, "</h3>" as *u8)
2020 let mm: *i64 = sys_mmap(8 * 64) as *i64
2021 let nm2: i64 = rb_list_subjects(azprefix, gref, "member" as *u8, mm, 64)
2022 var mi: i64 = 0
2023 while mi < nm2 {
2024 let mbare: *u8 = of_after_colon(mm[mi] as *u8)
2025 o = of_cat(out, o, "<div class='row'>" as *u8); o = of_cat(out, o, mbare)
2026 o = of_cat(out, o, " <form method='post' action='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/group-remove' style='display:inline'>" as *u8)
2027 o = of_sess_field(out, o, tok)
2028 o = of_cat(out, o, "<input type='hidden' name='group' value='" as *u8); o = of_cat(out, o, gbare)
2029 o = of_cat(out, o, "'><input type='hidden' name='who' value='" as *u8); o = of_cat(out, o, mbare)
2030 o = of_cat(out, o, "'><button class='ghost'>remove</button></form></div>" as *u8)
2031 mi = mi + 1
2032 }
2033 o = of_cat(out, o, "<form method='post' action='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/group-add'>" as *u8)
2034 o = of_sess_field(out, o, tok)
2035 o = of_cat(out, o, "<input type='hidden' name='group' value='" as *u8); o = of_cat(out, o, gbare)
2036 o = of_cat(out, o, "'><input name='who' placeholder='handle to add'><button>Add member</button></form>" as *u8)
2037 gi = gi + 1
2038 }
2039 o = of_cat(out, o, "<h3>Create a group</h3><form method='post' action='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/group-add'>" as *u8)
2040 o = of_sess_field(out, o, tok)
2041 o = of_cat(out, o, "<input name='group' placeholder='new group name'><input name='who' placeholder='first member handle'><button>Create</button></form>" as *u8)
2042 o = of_cat(out, o, "<p><a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/'>← back to office</a></p></body></html>" as *u8)
2043 return o
2044}
2045
2046// REVERSE INDEX: append the doc: objects where (obj, rel, sub) is current into out[] (deduped). returns new count.
2047func of_collect_docs(azprefix: *u8, sub: *u8, rel: *u8, out: *i64, n: i64, cap: i64) -> i64 {
2048 let tmp: *i64 = sys_mmap(8 * 64) as *i64
2049 let k: i64 = rb_list_objects_for_sub(azprefix, sub, rel, tmp, 64)
2050 var i: i64 = 0; var nn: i64 = n
2051 while i < k {
2052 let o: *u8 = tmp[i] as *u8
2053 if of_starts(o, "doc:" as *u8) == 1 { if nn < cap { if rb_in_list(out, nn, o) == 0 { out[nn] = o as i64; nn = nn + 1 } } }
2054 i = i + 1
2055 }
2056 return nn
2057}
2058// "what documents can I access?" -- the reverse-index query: docs I own/view/edit DIRECTLY, plus docs shared with
2059// any GROUP I'm a member of (userset expansion on the read side). Deduped. This is the SOTA list-objects primitive.
2060func of_my_docs(azprefix: *u8, me: *u8, out: *i64, cap: i64) -> i64 {
2061 var n: i64 = 0
2062 n = of_collect_docs(azprefix, me, "owner" as *u8, out, n, cap)
2063 n = of_collect_docs(azprefix, me, "viewer" as *u8, out, n, cap)
2064 n = of_collect_docs(azprefix, me, "editor" as *u8, out, n, cap)
2065 let grps: *i64 = sys_mmap(8 * 64) as *i64
2066 let ng: i64 = rb_list_objects_for_sub(azprefix, me, "member" as *u8, grps, 64)
2067 var gi: i64 = 0
2068 while gi < ng {
2069 let g: *u8 = grps[gi] as *u8
2070 if of_starts(g, "group:" as *u8) == 1 {
2071 let gm: *u8 = sys_mmap(320); var go: i64 = of_cat(gm, 0, g); go = of_cat(gm, go, "#member" as *u8); gm[go] = 0 as u8
2072 n = of_collect_docs(azprefix, gm, "viewer" as *u8, out, n, cap)
2073 n = of_collect_docs(azprefix, gm, "editor" as *u8, out, n, cap)
2074 }
2075 gi = gi + 1
2076 }
2077 return n
2078}
2079// the "Shared with me" page: every doc the caller can reach (direct or via a group). FULL HTTP response.
2080func of_sharedpage(base: *u8, azprefix: *u8, me: *u8, authed: i64, out: *u8, cap: i64) -> i64 {
2081 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>Shared with me</title><style>body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;max-width:720px;margin:5vh auto;padding:0 20px;color:#222}.row{padding:8px 0;border-bottom:1px solid #eee}.mut{color:#888}a{color:rgb(41,84,164)}</style></head><body><h2>Documents you can access</h2>" as *u8)
2082 if authed == 0 { o = of_cat(out, o, "<p>Sign in to see documents shared with you.</p></body></html>" as *u8); return o }
2083 let docs: *i64 = sys_mmap(8 * 128) as *i64
2084 let nd: i64 = of_my_docs(azprefix, me, docs, 128)
2085 o = of_cat(out, o, "<p class='mut'>Owned by you, shared with you directly, or shared with a group you belong to.</p>" as *u8)
2086 if nd == 0 { o = of_cat(out, o, "<div class='mut'>(nothing yet)</div>" as *u8) }
2087 var di: i64 = 0
2088 while di < nd {
2089 let dbare: *u8 = of_after_colon(docs[di] as *u8)
2090 o = of_cat(out, o, "<div class='row'><a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/doc/" as *u8); o = of_cat(out, o, dbare); o = of_cat(out, o, "'>" as *u8); o = of_cat(out, o, dbare); o = of_cat(out, o, "</a></div>" as *u8)
2091 di = di + 1
2092 }
2093 o = of_cat(out, o, "<p><a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/'>← back to office</a></p></body></html>" as *u8)
2094 return o
2095}
2096
2097// generated links KEEP base -> the app is mount-point agnostic (works at :8030/ and at nishifamily.com/office/).
2098// ==== LP1 IMPORT + LP4 SIGN + firm-instance helpers (2026-08-19, /compare/legalpractice 0.1) =============================
2099// Every constant below is NAMED for one purpose; sizes that depend on the input are derived from it, never guessed.
2100const OF_IMPORT_MAXPARTS: i64 = 8 // an import form carries file + name (+ sess); 8 is the parser slot count, refused above
2101const OF_SPEC_CAP: i64 = 131072 // the spec ceiling of_save already enforces (sl > 131072 is refused there too)
2102const OF_CAPTURE_CAP: i64 = 262144 // capture of the format organ's spec dump = spec cap + marker lines + slack
2103const OF_HEADSZ: i64 = 32 // sha256 audit head (se_chain out32)
2104const OF_HEXSZ: i64 = 64 // its hex form
2105const OF_EID_CAP: i64 = 128 // "<name>-v<N>" envelope id
2106const OF_CERT_CAP: i64 = 2048 // canon_encode of the 5-key completion certificate
2107const OF_USEC_PER_SEC: i64 = 1000000
2108const OF_NAME_MAX: i64 = 40 // of_name_ok's own limit (a-z 0-9 dash, max 40)
2109const OF_IMPORT_DOCX: i64 = 1
2110const OF_IMPORT_ODT: i64 = 2
2111const OF_ODT_ELF: *u8 = "_offc/nx_odt.elf"
2112
2113// Content-Type boundary token of a multipart request (0 = absent). Quotes stripped, stops at ';'.
2114func of_ct_boundary(req: *u8, reqlen: i64, out: *u8, cap: i64) -> i64 {
2115 let ct: *u8 = sys_mmap(512)
2116 of_hdr_get(req, reqlen, "Content-Type:" as *u8, ct, 512)
2117 var i: i64 = 0
2118 var bs: i64 = 0 - 1
2119 while ct[i] != (0 as u8) { if bs < 0 { if of_starts((ct as i64 + i) as *u8, "boundary=" as *u8) == 1 { bs = i + 9 } } i = i + 1 }
2120 if bs < 0 { out[0] = 0 as u8; return 0 }
2121 var w: i64 = 0
2122 var k: i64 = bs
2123 while ct[k] != (0 as u8) { let c: i64 = ct[k] as i64; if c == 59 { break } if c != 34 { if w < cap - 1 { out[w] = ct[k]; w = w + 1 } } k = k + 1 }
2124 out[w] = 0 as u8
2125 return w
2126}
2127// a quoted value (key like name=" or filename=") out of one part's header block; 0 = absent
2128func of_cd_extract(body: *u8, hoff: i64, hlen: i64, key: *u8, out: *u8, cap: i64) -> i64 {
2129 let kl: i64 = of_slen(key)
2130 let end: i64 = hoff + hlen
2131 var i: i64 = hoff
2132 var start: i64 = 0 - 1
2133 while i + kl <= end { if start < 0 { var m: i64 = 1; var j: i64 = 0; while j < kl { if body[i + j] != key[j] { m = 0; j = kl } else { j = j + 1 } } if m == 1 { start = i + kl } } i = i + 1 }
2134 if start < 0 { out[0] = 0 as u8; return 0 }
2135 var w: i64 = 0
2136 var k: i64 = start
2137 while k < end { if (body[k] as i64) == 34 { k = end } else { if w < cap - 1 { out[w] = body[k]; w = w + 1 } k = k + 1 } }
2138 out[w] = 0 as u8
2139 return w
2140}
2141// an office name from an uploaded filename: drop the extension (last '.'), lowercase, keep a-z 0-9 dash, space/_ -> dash
2142func of_name_from_filename(fn: *u8, out: *u8) -> i64 {
2143 var last: i64 = 0 - 1
2144 var i: i64 = 0
2145 while fn[i] != (0 as u8) { if (fn[i] as i64) == 46 { last = i } i = i + 1 }
2146 var stop: i64 = i
2147 if last > 0 { stop = last }
2148 var o: i64 = 0
2149 i = 0
2150 while i < stop {
2151 var c: i64 = fn[i] as i64
2152 if c >= 65 { if c <= 90 { c = c + 32 } }
2153 var keep: i64 = 0
2154 if c >= 97 { if c <= 122 { keep = 1 } }
2155 if c >= 48 { if c <= 57 { keep = 1 } }
2156 if c == 45 { keep = 1 }
2157 if c == 32 { c = 45; keep = 1 }
2158 if c == 95 { c = 45; keep = 1 }
2159 if keep == 1 { if o < OF_NAME_MAX { out[o] = c as u8; o = o + 1 } }
2160 i = i + 1
2161 }
2162 out[o] = 0 as u8
2163 return o
2164}
2165// what was uploaded: OF_IMPORT_DOCX / OF_IMPORT_ODT by extension, and ONLY if the bytes are a ZIP package (PK\3\4)
2166func of_import_kind(fn: *u8, bytes: *u8, n: i64) -> i64 {
2167 if n < 4 { return 0 }
2168 if bytes[0] != (80 as u8) { return 0 }
2169 if bytes[1] != (75 as u8) { return 0 }
2170 if bytes[2] != (3 as u8) { return 0 }
2171 if bytes[3] != (4 as u8) { return 0 }
2172 let l: i64 = of_slen(fn)
2173 let low: *u8 = sys_mmap(l + 1)
2174 var i: i64 = 0
2175 while i < l { var c: i64 = fn[i] as i64; if c >= 65 { if c <= 90 { c = c + 32 } } low[i] = c as u8; i = i + 1 }
2176 low[l] = 0 as u8
2177 if l >= 5 { if of_seq((low as i64 + l - 5) as *u8, ".docx" as *u8) == 1 { return OF_IMPORT_DOCX } }
2178 if l >= 4 { if of_seq((low as i64 + l - 4) as *u8, ".odt" as *u8) == 1 { return OF_IMPORT_ODT } }
2179 return 0
2180}
2181// IMPORT (LP1): an uploaded .docx/.odt lands as v1 of a NEW document. The ORIGINAL bytes are kept byte for byte
2182// (v1/original.<ext>; for .docx v1/file.docx IS the original, so /file serves it untouched until the first edit);
2183// the spec is extracted PARAGRAPH-FAITHFULLY by the format organ's `spec` verb (H/P/T lines), the preview is
2184// rendered by the same organ, and the manifest row carries the additive 4th field "import". Returns 1, or LOUD:
2185// -1 bad name -2 name exists (import never appends to a document) -3 not a .docx/.odt package -4 extract failed
2186// -5 convert/preview/write failed -6 nothing readable in the document
2187func of_import(root: *u8, base: *u8, name: *u8, fn: *u8, bytes: *u8, n: i64) -> i64 {
2188 if of_name_ok(name) == 0 { return 0 - 1 }
2189 sys_mkdir(root, 493)
2190 let lk: i64 = of_doc_lock(root, name)
2191 let rc: i64 = of_import_body(root, base, name, fn, bytes, n)
2192 of_doc_unlock(lk)
2193 return rc
2194}
2195func of_import_body(root: *u8, base: *u8, name: *u8, fn: *u8, bytes: *u8, n: i64) -> i64 {
2196 if of_name_ok(name) == 0 { return 0 - 1 }
2197 let kbuf: *u8 = sys_mmap(64)
2198 if of_manifest_count(root, name, kbuf, 64) > 0 { return 0 - 2 }
2199 let ik: i64 = of_import_kind(fn, bytes, n)
2200 if ik == 0 { return 0 - 3 }
2201 sys_mkdir(root, 493)
2202 let nd: *u8 = sys_mmap(512)
2203 var no: i64 = of_cat(nd, 0, root); no = of_cat(nd, no, "/" as *u8); no = of_cat(nd, no, name); nd[no] = 0 as u8
2204 sys_mkdir(nd, 493)
2205 let vd: *u8 = sys_mmap(512)
2206 of_vdir(root, name, 1, vd)
2207 sys_mkdir(vd, 493)
2208 let origp: *u8 = sys_mmap(600)
2209 var oo: i64 = of_cat(origp, 0, vd); oo = of_cat(origp, oo, "/original." as *u8)
2210 if ik == OF_IMPORT_DOCX { oo = of_cat(origp, oo, "docx" as *u8) } else { oo = of_cat(origp, oo, "odt" as *u8) }
2211 origp[oo] = 0 as u8
2212 if of_write_file(origp, bytes, n) != 0 { return 0 - 5 }
2213 let elf: *u8 = of_elf(0)
2214 var xelf: *u8 = elf
2215 if ik == OF_IMPORT_ODT { xelf = OF_ODT_ELF }
2216 let av: *i64 = sys_mmap(8 * 8) as *i64
2217 av[0] = xelf as i64; av[1] = "spec" as *u8 as i64; av[2] = origp as i64; av[3] = 0
2218 let capbuf: *u8 = sys_mmap(OF_CAPTURE_CAP)
2219 let ol: *i64 = sys_mmap(16) as *i64
2220 let rc: i64 = tr_run_capture(xelf, av, capbuf, OF_CAPTURE_CAP, ol)
2221 if rc != 0 { return 0 - 4 }
2222 let bpos: i64 = of_findpos(capbuf, ol[0], "-SPEC-BEGIN\n" as *u8)
2223 if bpos < 0 { return 0 - 4 }
2224 let s: i64 = bpos + 12
2225 let epos: i64 = of_findpos(capbuf, ol[0], "-SPEC-END len=" as *u8)
2226 if epos < s { return 0 - 4 }
2227 var e: i64 = epos
2228 while e > s { if capbuf[e - 1] == (10 as u8) { break } e = e - 1 }
2229 let sl: i64 = e - s
2230 if sl <= 0 { return 0 - 6 }
2231 if sl > OF_SPEC_CAP { return 0 - 4 }
2232 let spec: *u8 = sys_mmap(sl + 1)
2233 var q: i64 = 0
2234 while q < sl { spec[q] = capbuf[s + q]; q = q + 1 }
2235 spec[sl] = 0 as u8
2236 let specp: *u8 = sys_mmap(600)
2237 var so: i64 = of_cat(specp, 0, vd); so = of_cat(specp, so, "/spec.txt" as *u8); specp[so] = 0 as u8
2238 if of_write_file(specp, spec, sl) != 0 { return 0 - 5 }
2239 let artp: *u8 = sys_mmap(600)
2240 var ao: i64 = of_cat(artp, 0, vd); ao = of_cat(artp, ao, "/file.docx" as *u8); artp[ao] = 0 as u8
2241 if ik == OF_IMPORT_DOCX { if of_write_file(artp, bytes, n) != 0 { return 0 - 5 } } else {
2242 let av1: *i64 = sys_mmap(8 * 8) as *i64
2243 av1[0] = elf as i64; av1[1] = "writerich" as *u8 as i64; av1[2] = artp as i64; av1[3] = specp as i64; av1[4] = 0
2244 let rc1: i64 = tr_run_capture(elf, av1, capbuf, OF_CAPTURE_CAP, ol)
2245 if rc1 != 0 { return 0 - 5 }
2246 }
2247 let prevp: *u8 = sys_mmap(600)
2248 var po: i64 = of_cat(prevp, 0, vd); po = of_cat(prevp, po, "/preview.html" as *u8); prevp[po] = 0 as u8
2249 let dlu: *u8 = sys_mmap(600)
2250 var du: i64 = of_cat(dlu, 0, base); du = of_cat(dlu, du, "/file/" as *u8); du = of_cat(dlu, du, name); du = of_cat(dlu, du, "/v1" as *u8); dlu[du] = 0 as u8
2251 let av2: *i64 = sys_mmap(8 * 8) as *i64
2252 av2[0] = elf as i64; av2[1] = "html" as *u8 as i64; av2[2] = artp as i64; av2[3] = prevp as i64; av2[4] = dlu as i64; av2[5] = 0
2253 let rc2: i64 = tr_run_capture(elf, av2, capbuf, OF_CAPTURE_CAP, ol)
2254 if rc2 != 0 { return 0 - 5 }
2255 let mp: *u8 = sys_mmap(600)
2256 var mo: i64 = of_cat(mp, 0, nd); mo = of_cat(mp, mo, "/manifest.txt" as *u8); mp[mo] = 0 as u8
2257 let line: *u8 = sys_mmap(256)
2258 var lo: i64 = of_cat(line, 0, "v1" as *u8); lo = of_catc(line, lo, 9); lo = of_cat(line, lo, "doc" as *u8); lo = of_catc(line, lo, 9); lo = of_catn(line, lo, sys_now_us()); lo = of_catc(line, lo, 9); lo = of_cat(line, lo, "import" as *u8); lo = of_catc(line, lo, 10)
2259 if of_append_line(mp, line, lo) != 0 { return 0 - 5 }
2260 let ip: *u8 = sys_mmap(600)
2261 var io: i64 = of_cat(ip, 0, root); io = of_cat(ip, io, "/index.txt" as *u8); ip[io] = 0 as u8
2262 let il: *u8 = sys_mmap(256)
2263 var ilo: i64 = of_cat(il, 0, name); ilo = of_catc(il, ilo, 9); ilo = of_cat(il, ilo, "doc" as *u8); ilo = of_catc(il, ilo, 10)
2264 of_append_line(ip, il, ilo)
2265 return 1
2266}
2267// /original/<name>/v<N>: the untouched upload (original.odt | original.docx), else the version's file.docx
2268func of_serve_original(root: *u8, name: *u8, vn: i64, out: *u8, cap: i64) -> i64 {
2269 let kb: *u8 = sys_mmap(64)
2270 let vc: i64 = of_manifest_count(root, name, kb, 64)
2271 if vc <= 0 { return 0 - 1 }
2272 if vn < 1 { return 0 - 1 }
2273 if vn > vc { return 0 - 1 }
2274 let vd: *u8 = sys_mmap(512)
2275 of_vdir(root, name, vn, vd)
2276 let pth: *u8 = sys_mmap(600)
2277 var ct: *u8 = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" as *u8
2278 var ext: *u8 = "docx" as *u8
2279 var po: i64 = of_cat(pth, 0, vd); po = of_cat(pth, po, "/original.odt" as *u8); pth[po] = 0 as u8
2280 var fd: i64 = sys_openat_rd(pth)
2281 if fd >= 0 { sys_close(fd); ct = "application/vnd.oasis.opendocument.text" as *u8; ext = "odt" as *u8 } else {
2282 po = of_cat(pth, 0, vd); po = of_cat(pth, po, "/original.docx" as *u8); pth[po] = 0 as u8
2283 fd = sys_openat_rd(pth)
2284 if fd >= 0 { sys_close(fd) } else { po = of_cat(pth, 0, vd); po = of_cat(pth, po, "/file.docx" as *u8); pth[po] = 0 as u8 }
2285 }
2286 let szp: *i64 = sys_mmap(16) as *i64
2287 let fb: *u8 = ss_readall(pth, szp)
2288 if (fb as i64) == 0 { return 0 - 1 }
2289 let fl: i64 = szp[0]
2290 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8)
2291 o = of_cat(out, o, ct)
2292 o = of_cat(out, o, "\r\nContent-Length: " as *u8)
2293 o = of_catn(out, o, fl)
2294 o = of_cat(out, o, "\r\nContent-Disposition: attachment; filename=" as *u8)
2295 o = of_cat(out, o, name); o = of_cat(out, o, "." as *u8); o = of_cat(out, o, ext)
2296 o = of_cat(out, o, "\r\n\r\n" as *u8)
2297 if o + fl > cap { sys_munmap(fb, fl); return 0 - 2 }
2298 var i: i64 = 0
2299 while i < fl { out[o + i] = fb[i]; i = i + 1 }
2300 sys_munmap(fb, fl)
2301 return o + fl
2302}
2303// hex (64 chars) -> 32 bytes; returns 1 on a clean parse, 0 if any char is not hex
2304func of_is_hex(c: i64) -> i64 {
2305 if c >= 48 { if c <= 57 { return 1 } }
2306 if c >= 65 { if c <= 70 { return 1 } }
2307 if c >= 97 { if c <= 102 { return 1 } }
2308 return 0
2309}
2310func of_unhex32(hx: *u8, out32: *u8) -> i64 {
2311 var i: i64 = 0
2312 while i < OF_HEADSZ {
2313 let ca: i64 = hx[i * 2] as i64
2314 let cb: i64 = hx[i * 2 + 1] as i64
2315 if of_is_hex(ca) == 0 { return 0 }
2316 if of_is_hex(cb) == 0 { return 0 }
2317 out32[i] = (of_hexval(ca) * 16 + of_hexval(cb)) as u8
2318 i = i + 1
2319 }
2320 return 1
2321}
2322func of_count_lines(path: *u8) -> i64 {
2323 let szp: *i64 = sys_mmap(16) as *i64
2324 let b: *u8 = ss_readall(path, szp)
2325 if (b as i64) == 0 { return 0 }
2326 var n: i64 = 0
2327 var i: i64 = 0
2328 while i < szp[0] { if b[i] == (10 as u8) { n = n + 1 } i = i + 1 }
2329 sys_munmap(b, szp[0])
2330 return n
2331}
2332func of_cert_exists(root: *u8, name: *u8, vn: i64) -> i64 {
2333 let vd: *u8 = sys_mmap(512)
2334 of_vdir(root, name, vn, vd)
2335 let cp: *u8 = sys_mmap(600)
2336 var co: i64 = of_cat(cp, 0, vd); co = of_cat(cp, co, "/cert.txt" as *u8); cp[co] = 0 as u8
2337 let fd: i64 = sys_openat_rd(cp)
2338 if fd < 0 { return 0 }
2339 sys_close(fd)
2340 return 1
2341}
2342// SIGN (LP4): the UETA consent-gated ceremony over a document VERSION. doc CID = cid_of the version's bytes; the
2343// envelope id is "<name>-v<N>"; every signature chains the audit head (se_genesis -> sc_sign), persisted beside the
2344// version (v<N>/sign.head hex + v<N>/sign.log append-only); the sealed certificate (sc_cert) is written to
2345// v<N>/cert.txt, put on the registry plane under root/<name>/sign- and its CID returned; the document-level ledger
2346// <name>/signatures.txt gains one row. Returns 1, or -1 no such version -2 consent refused (no intent, no
2347// signature, head untouched) -3 bad signer -4 write failed.
2348func of_sign_version(root: *u8, name: *u8, vn: i64, signer: *u8, consent: *u8, out_cert_cid: *u8) -> i64 {
2349 if of_name_ok(name) == 0 { return 0 - 1 }
2350 let lk: i64 = of_doc_lock(root, name)
2351 let rc: i64 = of_sign_version_body(root, name, vn, signer, consent, out_cert_cid)
2352 of_doc_unlock(lk)
2353 return rc
2354}
2355func of_sign_version_body(root: *u8, name: *u8, vn: i64, signer: *u8, consent: *u8, out_cert_cid: *u8) -> i64 {
2356 let kb: *u8 = sys_mmap(64)
2357 let vc: i64 = of_manifest_count(root, name, kb, 64)
2358 if vc <= 0 { return 0 - 1 }
2359 if vn < 1 { return 0 - 1 }
2360 if vn > vc { return 0 - 1 }
2361 if of_tok_ok(signer) == 0 { return 0 - 3 }
2362 if sc_consent_ok(consent) == 0 { return 0 - 2 }
2363 let ki: i64 = of_kind_idx(kb)
2364 var ks: i64 = ki
2365 if ks < 0 { ks = 0 }
2366 let vd: *u8 = sys_mmap(512)
2367 of_vdir(root, name, vn, vd)
2368 let fp: *u8 = sys_mmap(600)
2369 var fo: i64 = of_cat(fp, 0, vd); fo = of_cat(fp, fo, "/file." as *u8); fo = of_cat(fp, fo, of_ext(ks)); fp[fo] = 0 as u8
2370 let szbox: *i64 = sys_mmap(16) as *i64
2371 let doccid: *u8 = sys_mmap(128)
2372 if cid_of_file(fp, szbox, doccid) < 0 { return 0 - 1 }
2373 let eid: *u8 = sys_mmap(OF_EID_CAP)
2374 var eo: i64 = of_cat(eid, 0, name); eo = of_cat(eid, eo, "-v" as *u8); eo = of_catn(eid, eo, vn); eid[eo] = 0 as u8
2375 let headp: *u8 = sys_mmap(600)
2376 var hpo: i64 = of_cat(headp, 0, vd); hpo = of_cat(headp, hpo, "/sign.head" as *u8); headp[hpo] = 0 as u8
2377 let logp: *u8 = sys_mmap(600)
2378 var lpo: i64 = of_cat(logp, 0, vd); lpo = of_cat(logp, lpo, "/sign.log" as *u8); logp[lpo] = 0 as u8
2379 let prev: *u8 = sys_mmap(OF_HEADSZ)
2380 let hexin: *u8 = sys_mmap(OF_HEXSZ + 2)
2381 let hl: i64 = of_read_file(headp, hexin, OF_HEXSZ)
2382 var seq: i64 = 1
2383 var chained: i64 = 0
2384 if hl == OF_HEXSZ { if of_unhex32(hexin, prev) == 1 { chained = 1; seq = of_count_lines(logp) + 1 } }
2385 if chained == 0 { se_genesis(prev) }
2386 let head: *u8 = sys_mmap(OF_HEADSZ)
2387 let ts: i64 = sys_now_us() / OF_USEC_PER_SEC
2388 if sc_sign(eid, seq, signer, ts, consent, prev, head) != 1 { return 0 - 2 }
2389 let hexh: *u8 = sys_mmap(OF_HEXSZ + 2)
2390 se_hex(head, hexh)
2391 if of_write_file(headp, hexh, OF_HEXSZ) != 0 { return 0 - 4 }
2392 let row: *u8 = sys_mmap(512)
2393 var ro: i64 = of_catn(row, 0, seq); ro = of_catc(row, ro, 9); ro = of_cat(row, ro, signer); ro = of_catc(row, ro, 9); ro = of_catn(row, ro, ts); ro = of_catc(row, ro, 9)
2394 var z: i64 = 0
2395 while z < OF_HEXSZ { row[ro] = hexh[z]; ro = ro + 1; z = z + 1 }
2396 ro = of_catc(row, ro, 10)
2397 if of_append_line(logp, row, ro) != 0 { return 0 - 4 }
2398 let nsb: *u8 = sys_mmap(32)
2399 var nso: i64 = of_catn(nsb, 0, seq); nsb[nso] = 0 as u8
2400 let cert: *u8 = sys_mmap(OF_CERT_CAP)
2401 let cl: i64 = sc_cert(eid, doccid, nsb, hexh, cert)
2402 if cl <= 0 { return 0 - 4 }
2403 cid_of(cert, cl, out_cert_cid)
2404 let sprefix: *u8 = sys_mmap(600)
2405 var spo: i64 = of_cat(sprefix, 0, root); spo = of_cat(sprefix, spo, "/" as *u8); spo = of_cat(sprefix, spo, name); spo = of_cat(sprefix, spo, "/sign-" as *u8); sprefix[spo] = 0 as u8
2406 sc_cert_put(sprefix, eid, cert, cl)
2407 let certp: *u8 = sys_mmap(600)
2408 var cpo: i64 = of_cat(certp, 0, vd); cpo = of_cat(certp, cpo, "/cert.txt" as *u8); certp[cpo] = 0 as u8
2409 let ct: *u8 = sys_mmap(1024)
2410 var co: i64 = of_cat(ct, 0, "certificate=" as *u8); co = of_cat(ct, co, out_cert_cid); co = of_catc(ct, co, 10)
2411 co = of_cat(ct, co, "envelope=" as *u8); co = of_cat(ct, co, eid); co = of_catc(ct, co, 10)
2412 co = of_cat(ct, co, "document=" as *u8); co = of_cat(ct, co, doccid); co = of_catc(ct, co, 10)
2413 co = of_cat(ct, co, "signers=" as *u8); co = of_catn(ct, co, seq); co = of_catc(ct, co, 10)
2414 co = of_cat(ct, co, "audit_head=" as *u8)
2415 z = 0
2416 while z < OF_HEXSZ { ct[co] = hexh[z]; co = co + 1; z = z + 1 }
2417 co = of_catc(ct, co, 10)
2418 co = of_cat(ct, co, "status=completed" as *u8); co = of_catc(ct, co, 10)
2419 if of_write_file(certp, ct, co) != 0 { return 0 - 4 }
2420 let slp: *u8 = sys_mmap(600)
2421 var slo: i64 = of_cat(slp, 0, root); slo = of_cat(slp, slo, "/" as *u8); slo = of_cat(slp, slo, name); slo = of_cat(slp, slo, "/signatures.txt" as *u8); slp[slo] = 0 as u8
2422 let srow: *u8 = sys_mmap(512)
2423 var sro: i64 = of_cat(srow, 0, "v" as *u8); sro = of_catn(srow, sro, vn); sro = of_catc(srow, sro, 9); sro = of_cat(srow, sro, signer); sro = of_catc(srow, sro, 9); sro = of_catn(srow, sro, ts); sro = of_catc(srow, sro, 9); sro = of_cat(srow, sro, out_cert_cid); sro = of_catc(srow, sro, 10)
2424 of_append_line(slp, srow, sro)
2425 return 1
2426}
2427// /cert/<name>/v<N>: the human-readable signing receipt (text/plain), 404 when the version was never signed
2428func of_serve_cert(root: *u8, name: *u8, vn: i64, out: *u8, cap: i64) -> i64 {
2429 if of_cert_exists(root, name, vn) == 0 { return 0 - 1 }
2430 let vd: *u8 = sys_mmap(512)
2431 of_vdir(root, name, vn, vd)
2432 let cp: *u8 = sys_mmap(600)
2433 var co: i64 = of_cat(cp, 0, vd); co = of_cat(cp, co, "/cert.txt" as *u8); cp[co] = 0 as u8
2434 let szp: *i64 = sys_mmap(16) as *i64
2435 let b: *u8 = ss_readall(cp, szp)
2436 if (b as i64) == 0 { return 0 - 1 }
2437 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: " as *u8)
2438 o = of_catn(out, o, szp[0])
2439 o = of_cat(out, o, "\r\n\r\n" as *u8)
2440 if o + szp[0] > cap { sys_munmap(b, szp[0]); return 0 - 2 }
2441 var i: i64 = 0
2442 while i < szp[0] { out[o + i] = b[i]; i = i + 1 }
2443 sys_munmap(b, szp[0])
2444 return o + szp[0]
2445}
2446// the import card on the home shell: a standard <input type=file>; the original is kept byte for byte as v1
2447func of_import_form(out: *u8, off: i64, base: *u8) -> i64 {
2448 var o: i64 = of_cat(out, off, "<div class='newt'><h3><div class='fico k0'>↑</div>Import <span class='cnt'>.docx .odt</span></h3><form method='post' enctype='multipart/form-data' action='" as *u8)
2449 o = of_cat(out, o, base)
2450 o = of_cat(out, o, "/import'><p class='hint' style='margin:0'>Bring in a Word, Google Docs (export as .docx or .odt) or LibreOffice file. The original is kept byte for byte as v1; every edit after that is a new version.</p><p class='row'><input type='file' name='file' accept='.docx,.odt' required></p><p class='row'><input type='text' name='name' placeholder='file-name (blank = from the filename)'><button type='submit'>Import</button></p></form></div>\n" as *u8)
2451 return o
2452}
2453// the per-version Sign cell on the document page: receipt link when signed, then the consent-gated form
2454func of_sign_cell(out: *u8, off: i64, root: *u8, base: *u8, name: *u8, vn: i64) -> i64 {
2455 var o: i64 = off
2456 if of_cert_exists(root, name, vn) == 1 {
2457 o = of_cat(out, o, "<a href='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/cert/" as *u8); o = of_cat(out, o, name); o = of_cat(out, o, "/v" as *u8); o = of_catn(out, o, vn)
2458 o = of_cat(out, o, "' title='sealed completion certificate (CID over envelope, document, signers and audit head)'>✓ signed · receipt</a><br>" as *u8)
2459 }
2460 o = of_cat(out, o, "<form method='post' action='" as *u8); o = of_cat(out, o, base); o = of_cat(out, o, "/sign' style='margin:0'><input type='hidden' name='name' value='" as *u8); o = of_cat(out, o, name)
2461 o = of_cat(out, o, "'><input type='hidden' name='version' value='" as *u8); o = of_catn(out, o, vn)
2462 o = of_cat(out, o, "'><input type='text' name='signer' placeholder='your handle' size='9' required> <label><input type='checkbox' name='consent' value='yes'> I agree to sign electronically (UETA/ESIGN consent)</label> <button type='submit' class='ghost' title='No consent, no signature: the ceremony refuses without it'>Sign</button></form>" as *u8)
2463 return o
2464}
2465// SESSION PROPAGATION for the no-JS path (the docportal pattern): when a session token is known, every same-app
2466// href='<base>/...' and action='<base>/...' in an HTML response gains ?s=<tok> (or &s= if a query exists) so a
2467// click keeps the session without cookies (C1). Rewrites in place into `out` (cap-bounded, REFUSES -> returns n
2468// unchanged if the rewritten page would not fit); non-HTML responses are returned untouched.
2469func of_propagate_tok(out: *u8, n: i64, base: *u8, tok: *u8, cap: i64) -> i64 {
2470 if tok[0] == (0 as u8) { return n }
2471 if of_memhas(out, n, "Content-Type: text/html" as *u8) == 0 { return n }
2472 let bl: i64 = of_slen(base)
2473 let tl: i64 = of_slen(tok)
2474 // one scratch page for the rewrite, UNMAPPED on every exit: a per-response map that is never released is the
2475 // exact leak class that took nx_opaque_login to 177 GB (2 MiB per response, never unmapped)
2476 let tmp: *u8 = sys_mmap(cap)
2477 var o: i64 = 0
2478 var i: i64 = 0
2479 var fits: i64 = 1
2480 while i < n {
2481 var hit: i64 = 0
2482 if out[i] == (61 as u8) { if i + 1 < n { if out[i + 1] == (39 as u8) {
2483 if i >= 4 { if of_memhas((out as i64 + i - 4) as *u8, 4, "href" as *u8) == 1 { hit = 1 } }
2484 if hit == 0 { if i >= 6 { if of_memhas((out as i64 + i - 6) as *u8, 6, "action" as *u8) == 1 { hit = 1 } } }
2485 if hit == 1 {
2486 var m: i64 = 1
2487 var k: i64 = 0
2488 while k < bl { if i + 2 + k >= n { m = 0; k = bl } else { if out[i + 2 + k] != base[k] { m = 0; k = bl } else { k = k + 1 } } }
2489 if m == 1 { if i + 2 + bl < n { if out[i + 2 + bl] != (47 as u8) { m = 0 } } else { m = 0 } }
2490 if m == 0 { hit = 0 }
2491 }
2492 } } }
2493 if hit == 1 {
2494 var j: i64 = i + 2
2495 var hasq: i64 = 0
2496 while j < n { if out[j] == (39 as u8) { break } if out[j] == (63 as u8) { hasq = 1 } j = j + 1 }
2497 if o + (j - i) + tl + 4 >= cap { fits = 0; i = n } else {
2498 var c: i64 = i
2499 while c < j { tmp[o] = out[c]; o = o + 1; c = c + 1 }
2500 if hasq == 1 { tmp[o] = 38 as u8 } else { tmp[o] = 63 as u8 }
2501 o = o + 1
2502 tmp[o] = 115 as u8; tmp[o + 1] = 61 as u8; o = o + 2
2503 var t: i64 = 0
2504 while t < tl { tmp[o] = tok[t]; o = o + 1; t = t + 1 }
2505 i = j
2506 }
2507 } else {
2508 if o + 1 >= cap { fits = 0; i = n } else { tmp[o] = out[i]; o = o + 1; i = i + 1 }
2509 }
2510 }
2511 var rn: i64 = n
2512 if fits == 1 {
2513 var k2: i64 = 0
2514 while k2 < o { out[k2] = tmp[k2]; k2 = k2 + 1 }
2515 rn = of_fix_content_length(out, o, cap)
2516 }
2517 sys_munmap(tmp, cap)
2518 return rn
2519}
2520// recompute "Content-Length: N" for an in-buffer HTTP response whose body length changed; returns the new total
2521func of_fix_content_length(out: *u8, n: i64, cap: i64) -> i64 {
2522 var hdr_end: i64 = 0 - 1
2523 var i: i64 = 0
2524 while i + 3 < n { if out[i] == (13 as u8) { if out[i+1] == (10 as u8) { if out[i+2] == (13 as u8) { if out[i+3] == (10 as u8) { hdr_end = i + 4; i = n } } } } i = i + 1 }
2525 if hdr_end < 0 { return n }
2526 let body: i64 = n - hdr_end
2527 let key: *u8 = "Content-Length: " as *u8
2528 let kl: i64 = of_slen(key)
2529 var p: i64 = 0 - 1
2530 var j: i64 = 0
2531 while j + kl < hdr_end { if p < 0 { if of_memhas((out as i64 + j) as *u8, kl, key) == 1 { if j == 0 { p = j } else { if out[j - 1] == (10 as u8) { p = j } } } } j = j + 1 }
2532 if p < 0 { return n }
2533 var q: i64 = p + kl
2534 while q < hdr_end { if out[q] == (13 as u8) { break } q = q + 1 }
2535 let tmp: *u8 = sys_mmap(cap)
2536 var o: i64 = 0
2537 var c: i64 = 0
2538 while c < p + kl { tmp[o] = out[c]; o = o + 1; c = c + 1 }
2539 o = of_catn(tmp, o, body)
2540 c = q
2541 var fits: i64 = 1
2542 while c < n { if o >= cap { fits = 0; c = n } else { tmp[o] = out[c]; o = o + 1; c = c + 1 } }
2543 var rn: i64 = n
2544 if fits == 1 { var k: i64 = 0; while k < o { out[k] = tmp[k]; k = k + 1 } rn = o }
2545 sys_munmap(tmp, cap)
2546 return rn
2547}
2548// OPEN-MODE wrapper: no handle -> no authz gating (current PUBLIC behavior; the 34-test offline gate runs here).
2549func of_handle(root: *u8, base: *u8, req: *u8, reqlen: i64, out: *u8, cap: i64) -> i64 {
2550 let mt: *u8 = sys_mmap(8); mt[0] = 0 as u8
2551 return of_handle_auth(root, base, req, reqlen, out, cap, mt, OF_AUTHZ, mt)
2552}
2553// AUTH-AWARE handler. handle = resolved caller ("" = unauthed/open). azprefix = ReBAC tuple store. tok = session
2554// token embedded in owner forms (zero-JS). A doc with NO owner tuple is PUBLIC; an OWNED doc: read needs
2555// rb_check(user:me, read, doc), a new version needs write, only the owner may share/unshare/manage.
2556func of_handle_auth(root: *u8, base: *u8, req: *u8, reqlen: i64, out: *u8, cap: i64, handle: *u8, azprefix: *u8, tok: *u8) -> i64 {
2557 var authed: i64 = 0; let me: *u8 = sys_mmap(320); me[0] = 0 as u8
2558 if handle[0] != (0 as u8) { authed = 1; of_meref(me, handle) }
2559 // fullpath = token between the first two spaces
2560 let fullpath: *u8 = sys_mmap(300)
2561 var i: i64 = 0
2562 while i < reqlen { if req[i] == (32 as u8) { i = i + 1; break } i = i + 1 }
2563 var t: i64 = 0
2564 while i < reqlen { if req[i] == (32 as u8) { break } if t < 299 { fullpath[t] = req[i]; t = t + 1 } i = i + 1 }
2565 fullpath[t] = 0 as u8
2566 // split off the query string (home search/sort/filter reads it) so routing sees a clean path
2567 let qs: *u8 = sys_mmap(300)
2568 qs[0] = 0 as u8
2569 var qi: i64 = 0
2570 while fullpath[qi] != (0 as u8) {
2571 if fullpath[qi] == (63 as u8) {
2572 var qq: i64 = qi + 1
2573 var qt: i64 = 0
2574 while fullpath[qq] != (0 as u8) { if qt < 299 { qs[qt] = fullpath[qq]; qt = qt + 1 } qq = qq + 1 }
2575 qs[qt] = 0 as u8
2576 fullpath[qi] = 0 as u8
2577 } else { qi = qi + 1 }
2578 }
2579 // strip the mount prefix -> path is relative to the app root ("/office/doc/x" -> "/doc/x", "/office" -> "")
2580 var path: *u8 = fullpath
2581 if base[0] != (0 as u8) {
2582 var bm: i64 = 1
2583 var bi: i64 = 0
2584 while base[bi] != (0 as u8) { if fullpath[bi] != base[bi] { bm = 0; bi = of_slen(base) } else { bi = bi + 1 } }
2585 if bm == 1 { path = (fullpath as i64 + of_slen(base)) as *u8 }
2586 }
2587 var is_post: i64 = 0
2588 if req[0] == (80 as u8) { if req[1] == (79 as u8) { is_post = 1 } }
2589 if is_post == 1 {
2590 var is_save: i64 = of_seq(path, "/save" as *u8)
2591 var is_restore: i64 = of_seq(path, "/restore" as *u8)
2592 var is_share: i64 = of_seq(path, "/share" as *u8)
2593 var is_unshare: i64 = of_seq(path, "/unshare" as *u8)
2594 var is_gadd: i64 = of_seq(path, "/group-add" as *u8)
2595 var is_gremove: i64 = of_seq(path, "/group-remove" as *u8)
2596 var is_ai: i64 = of_seq(path, "/ai" as *u8)
2597 var is_agent: i64 = of_seq(path, "/agent" as *u8)
2598 var is_star: i64 = of_seq(path, "/star" as *u8)
2599 var is_folder: i64 = of_seq(path, "/folder" as *u8)
2600 var is_import: i64 = of_seq(path, "/import" as *u8)
2601 var is_sign: i64 = of_seq(path, "/sign" as *u8)
2602 if (is_save + is_restore + is_share + is_unshare + is_gadd + is_gremove + is_ai + is_agent + is_star + is_folder + is_import + is_sign) == 0 { return of_err(out, "404 Not Found" as *u8, "no such POST route" as *u8) }
2603 // same-origin guard: if Origin present it must contain our Host
2604 let ob: *u8 = sys_mmap(300)
2605 let hb: *u8 = sys_mmap(300)
2606 of_hdr_get(req, reqlen, "Origin:" as *u8, ob, 300)
2607 of_hdr_get(req, reqlen, "Host:" as *u8, hb, 300)
2608 if ob[0] != (0 as u8) { if hb[0] != (0 as u8) {
2609 if of_memhas(ob, of_slen(ob), hb) == 0 { return of_err(out, "403 Forbidden" as *u8, "cross-origin POST refused" as *u8) }
2610 } }
2611 var bs: i64 = 0 - 1
2612 var j: i64 = 0
2613 while j + 3 < reqlen {
2614 if req[j] == (13 as u8) { if req[j+1] == (10 as u8) { if req[j+2] == (13 as u8) { if req[j+3] == (10 as u8) { bs = j + 4; j = reqlen } } } }
2615 j = j + 1
2616 }
2617 if bs < 0 { return of_err(out, "400 Bad Request" as *u8, "no body" as *u8) }
2618 let body: *u8 = (req as i64 + bs) as *u8
2619 let blen: i64 = reqlen - bs
2620 // IMPORT (LP1): a multipart upload lands as v1 of a NEW document; the original bytes are kept byte for byte.
2621 if is_import == 1 {
2622 // a truncated body is refused LOUDLY: the daemon's request buffer is a NAMED ceiling, never a silent cut
2623 let clb: *u8 = sys_mmap(32)
2624 of_hdr_get(req, reqlen, "Content-Length:" as *u8, clb, 32)
2625 if of_atoi(clb) > blen { return of_err(out, "413 Payload Too Large" as *u8, "the upload is larger than the office request buffer; split the document or raise the daemon's request ceiling" as *u8) }
2626 let bnd: *u8 = sys_mmap(256)
2627 if of_ct_boundary(req, reqlen, bnd, 256) <= 0 { return of_err(out, "400 Bad Request" as *u8, "import needs a multipart/form-data upload" as *u8) }
2628 let parts: *MultipartPart = sys_mmap(32 * OF_IMPORT_MAXPARTS) as *MultipartPart
2629 let np: i64 = multipart_parse(body, blen, bnd, of_slen(bnd), parts, OF_IMPORT_MAXPARTS)
2630 if np <= 0 { return of_err(out, "400 Bad Request" as *u8, "malformed multipart upload" as *u8) }
2631 let inm: *u8 = sys_mmap(64)
2632 let ifn: *u8 = sys_mmap(256)
2633 let pnm: *u8 = sys_mmap(64)
2634 var foff: i64 = 0 - 1
2635 var flen: i64 = 0
2636 inm[0] = 0 as u8
2637 ifn[0] = 0 as u8
2638 var pi: i64 = 0
2639 while pi < np {
2640 let pp: *MultipartPart = ((parts as i64) + pi * 32) as *MultipartPart
2641 of_cd_extract(body, pp.headers_off, pp.headers_len, "name=\"" as *u8, pnm, 64)
2642 if of_seq(pnm, "file" as *u8) == 1 { foff = pp.body_off; flen = pp.body_len; of_cd_extract(body, pp.headers_off, pp.headers_len, "filename=\"" as *u8, ifn, 256) }
2643 if of_seq(pnm, "name" as *u8) == 1 { var w: i64 = 0; while w < pp.body_len { if w < 63 { inm[w] = body[pp.body_off + w] } w = w + 1 } if pp.body_len < 63 { inm[pp.body_len] = 0 as u8 } else { inm[63] = 0 as u8 } }
2644 pi = pi + 1
2645 }
2646 if flen <= 0 { return of_err(out, "400 Bad Request" as *u8, "no file part in the upload" as *u8) }
2647 if inm[0] == (0 as u8) { of_name_from_filename(ifn, inm) }
2648 if of_name_ok(inm) == 0 { return of_err(out, "400 Bad Request" as *u8, "invalid name (a-z 0-9 dash, max 40) -- give the import a name" as *u8) }
2649 let irc: i64 = of_import(root, base, inm, ifn, (body as i64 + foff) as *u8, flen)
2650 if irc == 1 {
2651 if authed == 1 { let dref2: *u8 = sys_mmap(320); of_docref(dref2, inm); rb_put(azprefix, dref2, "owner" as *u8, me, handle, 1) }
2652 var io2: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2653 io2 = of_cat(out, io2, base); io2 = of_cat(out, io2, "/doc/" as *u8); io2 = of_cat(out, io2, inm); io2 = of_cat(out, io2, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2654 return io2
2655 }
2656 if irc == (0 - 2) { return of_err(out, "409 Conflict" as *u8, "that name already exists -- import creates a new document; pick another name" as *u8) }
2657 if irc == (0 - 3) { return of_err(out, "415 Unsupported Media Type" as *u8, "not a .docx or .odt package (Word, Google Docs export or LibreOffice Writer files only)" as *u8) }
2658 if irc == (0 - 4) { return of_err(out, "422 Unprocessable Entity" as *u8, "the document package could not be read" as *u8) }
2659 if irc == (0 - 6) { return of_err(out, "422 Unprocessable Entity" as *u8, "no readable paragraphs in that document" as *u8) }
2660 return of_err(out, "500 Internal Server Error" as *u8, "import failed while converting or writing the version" as *u8)
2661 }
2662 // SIGN (LP4): the consent-gated ceremony over one version; refused without consent; needs read access
2663 if is_sign == 1 {
2664 let snm2: *u8 = sys_mmap(64)
2665 let svs: *u8 = sys_mmap(16)
2666 let sgn: *u8 = sys_mmap(64)
2667 let cns: *u8 = sys_mmap(8)
2668 of_form_get(body, blen, "name" as *u8, snm2, 64)
2669 of_form_get(body, blen, "version" as *u8, svs, 16)
2670 of_form_get(body, blen, "signer" as *u8, sgn, 64)
2671 of_form_get(body, blen, "consent" as *u8, cns, 8)
2672 if of_name_ok(snm2) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2673 if of_read_ok(azprefix, me, authed, snm2) == 0 { return of_deny_read(out) }
2674 let ccid: *u8 = sys_mmap(128)
2675 let src: i64 = of_sign_version(root, snm2, of_atoi(svs), sgn, cns, ccid)
2676 if src == 1 {
2677 var so2: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2678 so2 = of_cat(out, so2, base); so2 = of_cat(out, so2, "/doc/" as *u8); so2 = of_cat(out, so2, snm2); so2 = of_cat(out, so2, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2679 return so2
2680 }
2681 if src == (0 - 2) { return of_err(out, "403 Forbidden" as *u8, "no consent, no signature: tick the consent box (UETA/ESIGN intent and consent to transact electronically)" as *u8) }
2682 if src == (0 - 3) { return of_err(out, "400 Bad Request" as *u8, "signer must be a simple handle (a-z 0-9 dash underscore)" as *u8) }
2683 if src == (0 - 1) { return of_err(out, "404 Not Found" as *u8, "no such file or version" as *u8) }
2684 return of_err(out, "500 Internal Server Error" as *u8, "the signing record could not be written" as *u8)
2685 }
2686 // SHARE / UNSHARE an owned doc (owner-only; additive grant / tombstone revoke). GROUP add/remove members.
2687 if is_share == 1 { return of_do_share(base, azprefix, me, handle, authed, body, blen, out, 1) }
2688 if is_unshare == 1 { return of_do_share(base, azprefix, me, handle, authed, body, blen, out, 0) }
2689 if is_gadd == 1 { return of_do_group(base, azprefix, me, handle, authed, body, blen, out, 1) }
2690 if is_gremove == 1 { return of_do_group(base, azprefix, me, handle, authed, body, blen, out, 0) }
2691 // AI CONTINUE: draft a continuation with OUR OWN sovereign 0.5B model (:11434) + append it as a NEW
2692 // version (additive -- the AI draft is a version you can diff/restore). Doc kind only. Graceful 503 if
2693 // the seat is down. Write-gated like a save (owned docs need edit access).
2694 if is_ai == 1 {
2695 let anm: *u8 = sys_mmap(64)
2696 of_form_get(body, blen, "name" as *u8, anm, 64)
2697 if of_name_ok(anm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2698 if of_write_ok(azprefix, me, authed, anm) == 0 { return of_deny_write(out) }
2699 let akb: *u8 = sys_mmap(64)
2700 let avc: i64 = of_manifest_count(root, anm, akb, 64)
2701 if avc <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2702 // ONE sovereign seat, THREE kinds. The prompt AND the append are kind-specific so the model edits each
2703 // artifact in ITS OWN grammar: prose for a doc, an insight ROW for a sheet (OF-A2, the "Fill with
2704 // Gemini" class), a whole new SLIDE for a deck (OF-A3, prompt-to-slide). Every kind stays additive.
2705 let akind: i64 = of_kind_idx(akb)
2706 let aspec: *u8 = sys_mmap(131073)
2707 let asl: i64 = of_read_version_spec(root, anm, avc, aspec, 131072)
2708 let ptext: *u8 = sys_mmap(2048)
2709 let ptl: i64 = of_spec_to_text(aspec, asl, ptext, 1200)
2710 let aprompt: *u8 = sys_mmap(4096)
2711 var api: i64 = 0
2712 if akind == 1 { api = of_ai_prompt_sheet(ptext, aprompt) } else {
2713 if akind == 2 { api = of_ai_prompt_deck(ptext, aprompt) } else { api = of_cat(aprompt, 0, ptext) }
2714 }
2715 aprompt[api] = 0 as u8
2716 let comp: *u8 = sys_mmap(8192)
2717 let cl: i64 = of_llm_complete(aprompt, api, comp, 8000)
2718 if cl <= 0 { return of_err(out, "503 Service Unavailable" as *u8, "the sovereign AI seat (our own 0.5B model on :11434) is not answering -- start nx_f32_llm_serve or try again" as *u8) }
2719 let nspec: *u8 = sys_mmap(140000)
2720 var no: i64 = 0
2721 var ci: i64 = 0
2722 while ci < asl { nspec[no] = aspec[ci]; no = no + 1; ci = ci + 1 }
2723 if no > 0 { if nspec[no-1] != (10 as u8) { nspec[no] = 10 as u8; no = no + 1 } }
2724 if akind == 2 {
2725 // deck: everything up to the first sentence end becomes the TITLE, the remainder the BULLET
2726 var dsp: i64 = 0 - 1
2727 var dfi: i64 = 0
2728 while dfi < cl { if comp[dfi] == (46 as u8) { dsp = dfi; dfi = cl } else { dfi = dfi + 1 } }
2729 var tend: i64 = cl
2730 if dsp > 3 { tend = dsp }
2731 no = of_cat(nspec, no, "S " as *u8)
2732 var dti: i64 = 0
2733 while dti < tend { let tc: i64 = comp[dti] as i64; if tc == 10 { nspec[no] = 32 as u8 } else { if tc == 9 { nspec[no] = 32 as u8 } else { nspec[no] = comp[dti] } } no = no + 1; dti = dti + 1 }
2734 if dsp > 3 { if dsp + 2 < cl {
2735 no = of_catc(nspec, no, 10)
2736 no = of_cat(nspec, no, "B " as *u8)
2737 var dbi: i64 = dsp + 1
2738 while dbi < cl { let bc: i64 = comp[dbi] as i64; if bc == 10 { nspec[no] = 32 as u8 } else { if bc == 9 { nspec[no] = 32 as u8 } else { nspec[no] = comp[dbi] } } no = no + 1; dbi = dbi + 1 }
2739 } }
2740 } else {
2741 // sheet -> a REAL two-cell TSV row so the insight lands IN the grid; doc -> a P paragraph
2742 if akind == 1 { no = of_cat(nspec, no, "AI insight" as *u8); no = of_catc(nspec, no, 9) } else { no = of_cat(nspec, no, "P " as *u8) }
2743 var di: i64 = 0
2744 while di < cl { let c: i64 = comp[di] as i64; if c == 10 { nspec[no] = 32 as u8 } else { if c == 9 { nspec[no] = 32 as u8 } else { nspec[no] = comp[di] } } no = no + 1; di = di + 1 }
2745 }
2746 nspec[no] = 0 as u8
2747 let nvn: i64 = of_save(root, base, anm, akb, nspec, no, 0)
2748 if nvn > 0 {
2749 var ao: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2750 ao = of_cat(out, ao, base); ao = of_cat(out, ao, "/doc/" as *u8); ao = of_cat(out, ao, anm); ao = of_cat(out, ao, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2751 return ao
2752 }
2753 return of_err(out, "500 Internal Server Error" as *u8, "AI draft save failed" as *u8)
2754 }
2755 // AGENT MODE (OF-A4, the 2026 marquee): ONE POST = ONE agent turn. PLAN when there is no plan yet (or
2756 // a fresh goal arrives), otherwise EXECUTE the next step, and once every step is drafted run one final
2757 // REFINE turn. Each executed turn lands as a NEW VERSION, so the whole trajectory is diffable/restorable.
2758 // D is bumped ONLY AFTER its version lands, so a 503 mid-run is safely retryable (no step is skipped).
2759 if is_agent == 1 {
2760 let gnm: *u8 = sys_mmap(64)
2761 of_form_get(body, blen, "name" as *u8, gnm, 64)
2762 if of_name_ok(gnm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2763 if of_write_ok(azprefix, me, authed, gnm) == 0 { return of_deny_write(out) }
2764 let gkb: *u8 = sys_mmap(64)
2765 let gvc: i64 = of_manifest_count(root, gnm, gkb, 64)
2766 if gvc <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2767 if of_kind_idx(gkb) != 0 { return of_err(out, "400 Bad Request" as *u8, "agent mode is for documents (doc kind) only" as *u8) }
2768 let goal: *u8 = sys_mmap(512)
2769 of_form_get(body, blen, "goal" as *u8, goal, 512)
2770 let ast: *u8 = sys_mmap(8192)
2771 let an: i64 = of_agent_read(root, gnm, ast, 8000)
2772 // ground EVERY turn in the CURRENT document, not the one the plan was written against
2773 let gspec: *u8 = sys_mmap(131073)
2774 let gsl: i64 = of_read_version_spec(root, gnm, gvc, gspec, 131072)
2775 let gtext: *u8 = sys_mmap(2048)
2776 let gtl: i64 = of_spec_to_text(gspec, gsl, gtext, 1100)
2777 let agloc: *u8 = sys_mmap(512)
2778
2779 // ---- PLAN turn ----
2780 var want_plan: i64 = 0
2781 if an <= 0 { want_plan = 1 }
2782 if of_slen(goal) > 0 { want_plan = 1 }
2783 if want_plan == 1 {
2784 if of_slen(goal) == 0 { return of_err(out, "400 Bad Request" as *u8, "agent mode needs a goal to plan against" as *u8) }
2785 let pp: *u8 = sys_mmap(4096)
2786 var po2: i64 = of_cat(pp, 0, "You are planning edits to a document. Goal: " as *u8)
2787 po2 = of_cat(pp, po2, goal)
2788 po2 = of_cat(pp, po2, ". Document so far: " as *u8)
2789 po2 = of_cat(pp, po2, gtext)
2790 po2 = of_cat(pp, po2, " . List the steps, one per line:" as *u8)
2791 pp[po2] = 0 as u8
2792 let pcomp: *u8 = sys_mmap(8192)
2793 let pcl: i64 = of_llm_complete_n(pp, po2, pcomp, 8000, 32)
2794 if pcl <= 0 { return of_err(out, "503 Service Unavailable" as *u8, "the sovereign AI seat (our own 0.5B model on :11434) is not answering -- start nx_f32_llm_serve or try again" as *u8) }
2795 let plan: *u8 = sys_mmap(4096)
2796 let nst: i64 = of_agent_plan_parse(pcomp, pcl, plan, 4000)
2797 if nst <= 0 { return of_err(out, "502 Bad Gateway" as *u8, "the model returned no usable plan -- try a more specific goal" as *u8) }
2798 let nstate: *u8 = sys_mmap(8192)
2799 var so2: i64 = of_cat(nstate, 0, "G " as *u8)
2800 so2 = of_cat(nstate, so2, goal)
2801 so2 = of_catc(nstate, so2, 10)
2802 so2 = of_cat(nstate, so2, plan)
2803 so2 = of_cat(nstate, so2, "D 0\n" as *u8)
2804 nstate[so2] = 0 as u8
2805 if of_agent_write(root, gnm, nstate, so2) != 0 { return of_err(out, "500 Internal Server Error" as *u8, "agent plan save failed" as *u8) }
2806 var pl: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2807 pl = of_cat(out, pl, base); pl = of_cat(out, pl, "/doc/" as *u8); pl = of_cat(out, pl, gnm)
2808 pl = of_cat(out, pl, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2809 return pl
2810 }
2811
2812 // ---- EXECUTE / REFINE turn ----
2813 let nsteps: i64 = of_agent_tagcount(ast, an, 83)
2814 let dn: i64 = of_agent_done(ast, an)
2815 if dn > nsteps { return of_err(out, "409 Conflict" as *u8, "this agent run is already complete -- give it a new goal to start another" as *u8) }
2816 let gg: *u8 = sys_mmap(512)
2817 of_agent_tagline(ast, an, 71, 0, gg, 512)
2818 let sp: *u8 = sys_mmap(4096)
2819 var qo: i64 = 0
2820 if dn < nsteps {
2821 let stx: *u8 = sys_mmap(256)
2822 of_agent_tagline(ast, an, 83, dn, stx, 256)
2823 qo = of_cat(sp, 0, "Goal: " as *u8)
2824 qo = of_cat(sp, qo, gg)
2825 qo = of_cat(sp, qo, ". Now do step " as *u8)
2826 qo = of_catn(sp, qo, dn + 1)
2827 qo = of_cat(sp, qo, ": " as *u8)
2828 qo = of_cat(sp, qo, stx)
2829 qo = of_cat(sp, qo, ". Document so far: " as *u8)
2830 qo = of_cat(sp, qo, gtext)
2831 qo = of_cat(sp, qo, " . Write that section:" as *u8)
2832 } else {
2833 qo = of_cat(sp, 0, "Goal: " as *u8)
2834 qo = of_cat(sp, qo, gg)
2835 qo = of_cat(sp, qo, ". Every step is drafted. Document: " as *u8)
2836 qo = of_cat(sp, qo, gtext)
2837 qo = of_cat(sp, qo, " . Write a short closing paragraph that ties it together:" as *u8)
2838 }
2839 sp[qo] = 0 as u8
2840 let scomp: *u8 = sys_mmap(8192)
2841 let scl: i64 = of_llm_complete(sp, qo, scomp, 8000)
2842 if scl <= 0 { return of_err(out, "503 Service Unavailable" as *u8, "the sovereign AI seat (our own 0.5B model on :11434) is not answering -- the agent kept its place, retry this step" as *u8) }
2843 let gnspec: *u8 = sys_mmap(140000)
2844 var gno: i64 = 0
2845 var gci: i64 = 0
2846 while gci < gsl { gnspec[gno] = gspec[gci]; gno = gno + 1; gci = gci + 1 }
2847 if gno > 0 { if gnspec[gno-1] != (10 as u8) { gnspec[gno] = 10 as u8; gno = gno + 1 } }
2848 gno = of_cat(gnspec, gno, "P " as *u8)
2849 var gdi: i64 = 0
2850 while gdi < scl {
2851 let gc: i64 = scomp[gdi] as i64
2852 if gc == 10 { gnspec[gno] = 32 as u8 } else { if gc == 9 { gnspec[gno] = 32 as u8 } else { gnspec[gno] = scomp[gdi] } }
2853 gno = gno + 1; gdi = gdi + 1
2854 }
2855 gnspec[gno] = 0 as u8
2856 let gvn: i64 = of_save(root, base, gnm, gkb, gnspec, gno, 0)
2857 if gvn <= 0 { return of_err(out, "500 Internal Server Error" as *u8, "agent step save failed" as *u8) }
2858 // the version landed -- NOW advance the cursor
2859 let ns2: *u8 = sys_mmap(8192)
2860 let sbuf: *u8 = sys_mmap(256)
2861 var xo: i64 = of_cat(ns2, 0, "G " as *u8)
2862 xo = of_cat(ns2, xo, gg)
2863 xo = of_catc(ns2, xo, 10)
2864 var si: i64 = 0
2865 while si < nsteps {
2866 of_agent_tagline(ast, an, 83, si, sbuf, 256)
2867 xo = of_cat(ns2, xo, "S " as *u8)
2868 xo = of_cat(ns2, xo, sbuf)
2869 xo = of_catc(ns2, xo, 10)
2870 si = si + 1
2871 }
2872 xo = of_cat(ns2, xo, "D " as *u8)
2873 xo = of_catn(ns2, xo, dn + 1)
2874 xo = of_catc(ns2, xo, 10)
2875 ns2[xo] = 0 as u8
2876 of_agent_write(root, gnm, ns2, xo)
2877 var al: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2878 al = of_cat(out, al, base); al = of_cat(out, al, "/doc/" as *u8); al = of_cat(out, al, gnm)
2879 al = of_cat(out, al, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2880 return al
2881 }
2882 // U3 STAR / FOLDER: library organisation, write-gated exactly like a save so a reader cannot reorganise
2883 // someone else's library. Neither touches the document spec or its versions.
2884 if is_star == 1 {
2885 let snm: *u8 = sys_mmap(64)
2886 of_form_get(body, blen, "name" as *u8, snm, 64)
2887 if of_name_ok(snm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2888 if of_write_ok(azprefix, me, authed, snm) == 0 { return of_deny_write(out) }
2889 let skb: *u8 = sys_mmap(64)
2890 if of_manifest_count(root, snm, skb, 64) <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2891 of_star_toggle(root, snm)
2892 var so: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other
2893
2894Location: " as *u8)
2895 so = of_cat(out, so, base); so = of_cat(out, so, "/" as *u8)
2896 so = of_cat(out, so, "
2897
2898Content-Length: 0
2899
2900Connection: close
2901
2902
2903
2904" as *u8)
2905 return so
2906 }
2907 if is_folder == 1 {
2908 let fnm: *u8 = sys_mmap(64)
2909 let fvl: *u8 = sys_mmap(64)
2910 of_form_get(body, blen, "name" as *u8, fnm, 64)
2911 of_form_get(body, blen, "folder" as *u8, fvl, 48)
2912 if of_name_ok(fnm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2913 if of_write_ok(azprefix, me, authed, fnm) == 0 { return of_deny_write(out) }
2914 let fkb: *u8 = sys_mmap(64)
2915 if of_manifest_count(root, fnm, fkb, 64) <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2916 // a folder is a plain label; reuse the handle validator so it cannot carry separators or markup
2917 if fvl[0] != (0 as u8) { if of_tok_ok(fvl) == 0 { return of_err(out, "400 Bad Request" as *u8, "folder name must be simple (a-z 0-9 dash underscore)" as *u8) } }
2918 of_folder_set(root, fnm, fvl)
2919 var fo: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other
2920
2921Location: " as *u8)
2922 fo = of_cat(out, fo, base); fo = of_cat(out, fo, "/doc/" as *u8); fo = of_cat(out, fo, fnm)
2923 fo = of_cat(out, fo, "
2924
2925Content-Length: 0
2926
2927Connection: close
2928
2929
2930
2931" as *u8)
2932 return fo
2933 }
2934 // RESTORE: put an old version back by SAVING its spec as a NEW version (additive -- never destroys history).
2935 if is_restore == 1 {
2936 let rnm: *u8 = sys_mmap(64)
2937 let rvs: *u8 = sys_mmap(16)
2938 of_form_get(body, blen, "name" as *u8, rnm, 64)
2939 of_form_get(body, blen, "version" as *u8, rvs, 16)
2940 if of_name_ok(rnm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2941 if of_write_ok(azprefix, me, authed, rnm) == 0 { return of_deny_write(out) }
2942 let rkb: *u8 = sys_mmap(64)
2943 let rvc: i64 = of_manifest_count(root, rnm, rkb, 64)
2944 if rvc <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2945 let rv: i64 = of_atoi(rvs)
2946 if rv < 1 { return of_err(out, "400 Bad Request" as *u8, "bad version" as *u8) }
2947 if rv > rvc { return of_err(out, "400 Bad Request" as *u8, "bad version" as *u8) }
2948 let rspec: *u8 = sys_mmap(131073)
2949 let rsl: i64 = of_read_version_spec(root, rnm, rv, rspec, 131072)
2950 let rnew: i64 = of_save(root, base, rnm, rkb, rspec, rsl, 0)
2951 if rnew > 0 {
2952 var ro2: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2953 ro2 = of_cat(out, ro2, base); ro2 = of_cat(out, ro2, "/doc/" as *u8); ro2 = of_cat(out, ro2, rnm); ro2 = of_cat(out, ro2, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2954 return ro2
2955 }
2956 return of_err(out, "500 Internal Server Error" as *u8, "restore failed (organ rejected the spec)" as *u8)
2957 }
2958 let nm: *u8 = sys_mmap(64)
2959 let kd: *u8 = sys_mmap(32)
2960 let spec: *u8 = sys_mmap(131073)
2961 of_form_get(body, blen, "name" as *u8, nm, 64)
2962 of_form_get(body, blen, "kind" as *u8, kd, 32)
2963 let sl: i64 = of_form_get(body, blen, "spec" as *u8, spec, 131073)
2964 // AUTHZ: an OWNED doc's new version needs write access; remember owned-ness to CLAIM on first save.
2965 var was_owned: i64 = 0
2966 if of_name_ok(nm) == 1 { let dref0: *u8 = sys_mmap(320); of_docref(dref0, nm); if rb_obj_has_owner(azprefix, dref0) == 1 { was_owned = 1 } }
2967 if was_owned == 1 { if of_write_ok(azprefix, me, authed, nm) == 0 { return of_deny_write(out) } }
2968 // ajax=1 = background AUTOSAVE (fetch from office_app.js): answer 200 OK v<N> instead of the 303
2969 let ax: *u8 = sys_mmap(8)
2970 of_form_get(body, blen, "ajax" as *u8, ax, 8)
2971 var auto: i64 = 0
2972 if ax[0] == (49 as u8) { auto = 1 }
2973 let vn: i64 = of_save(root, base, nm, kd, spec, sl, auto)
2974 if vn > 0 {
2975 // CLAIM ownership on first save by an authed user: unowned doc -> owner tuple (now private + shareable).
2976 if was_owned == 0 { if authed == 1 { let dref1: *u8 = sys_mmap(320); of_docref(dref1, nm); rb_put(azprefix, dref1, "owner" as *u8, me, handle, 1) } }
2977 if auto == 1 {
2978 // body = "OK v" + vn + "\n" (4 + digits(vn) + 1) -> Content-Length so strict clients frame it.
2979 var nd: i64 = 1
2980 var tv: i64 = vn
2981 while tv >= 10 { nd = nd + 1; tv = tv / 10 }
2982 var oa: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: " as *u8)
2983 oa = of_catn(out, oa, 4 + nd + 1)
2984 oa = of_cat(out, oa, "\r\nConnection: close\r\n\r\nOK v" as *u8)
2985 oa = of_catn(out, oa, vn)
2986 oa = of_catc(out, oa, 10)
2987 return oa
2988 }
2989 var o: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2990 o = of_cat(out, o, base)
2991 o = of_cat(out, o, "/doc/" as *u8)
2992 o = of_cat(out, o, nm)
2993 o = of_cat(out, o, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2994 return o
2995 }
2996 if vn == (0 - 2) {
2997 // a refusal that knows the remedy must NAME it: which kind holds the name, and where to open it
2998 let ek: *u8 = sys_mmap(64)
2999 of_manifest_count(root, nm, ek, 64)
3000 let msg: *u8 = sys_mmap(512)
3001 var mo: i64 = of_cat(msg, 0, "kind mismatch: '" as *u8)
3002 mo = of_cat(msg, mo, nm)
3003 mo = of_cat(msg, mo, "' already exists as a " as *u8)
3004 mo = of_cat(msg, mo, of_kind_name(of_kind_idx(ek)))
3005 mo = of_cat(msg, mo, " -- open " as *u8)
3006 mo = of_cat(msg, mo, base)
3007 mo = of_cat(msg, mo, "/doc/" as *u8)
3008 mo = of_cat(msg, mo, nm)
3009 mo = of_cat(msg, mo, " to edit it, or choose a new name" as *u8)
3010 msg[mo] = 0 as u8
3011 let en: i64 = of_err(out, "400 Bad Request" as *u8, msg)
3012 sys_munmap(msg, 512)
3013 sys_munmap(ek, 64)
3014 return en
3015 }
3016 if vn == (0 - 3) { return of_err(out, "500 Internal Server Error" as *u8, "the format organ rejected the spec (build failed)" as *u8) }
3017 if vn == (0 - 4) { return of_err(out, "500 Internal Server Error" as *u8, "preview render failed" as *u8) }
3018 return of_err(out, "400 Bad Request" as *u8, "invalid name (a-z 0-9 dash, max 40), kind, or empty spec" as *u8)
3019 }
3020 // GET routes
3021 if of_seq(path, "/app.js" as *u8) == 1 { return of_serve_js(out, cap) }
3022 if of_seq(path, "/sw.js" as *u8) == 1 { return of_serve_sw(out, cap) }
3023 if of_seq(path, "/manifest.webmanifest" as *u8) == 1 { return of_serve_manifest(out, base, cap) }
3024 if of_seq(path, "/" as *u8) == 1 { return of_cl_frame(out, of_home(root, base, qs, out, cap, azprefix, me, authed), cap) }
3025 if path[0] == (0 as u8) { return of_cl_frame(out, of_home(root, base, qs, out, cap, azprefix, me, authed), cap) }
3026 if of_starts(path, "/doc/" as *u8) == 1 {
3027 let nm: *u8 = sys_mmap(64)
3028 var q: i64 = 5
3029 var t2: i64 = 0
3030 while path[q] != (0 as u8) { if t2 < 63 { nm[t2] = path[q]; t2 = t2 + 1 } q = q + 1 }
3031 nm[t2] = 0 as u8
3032 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
3033 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
3034 let n: i64 = of_docpage(root, base, nm, out, cap)
3035 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
3036 return of_cl_frame(out, n, cap)
3037 }
3038 if of_starts(path, "/preview/" as *u8) == 1 {
3039 let nm: *u8 = sys_mmap(64)
3040 let vn: i64 = of_parse_nv(path, 9, nm, 64)
3041 if vn < 1 { return of_err(out, "404 Not Found" as *u8, "bad preview path" as *u8) }
3042 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
3043 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
3044 let n: i64 = of_serve(root, nm, vn, 1, out, cap)
3045 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such version" as *u8) }
3046 return n
3047 }
3048 if of_starts(path, "/file/" as *u8) == 1 {
3049 let nm: *u8 = sys_mmap(64)
3050 let vn: i64 = of_parse_nv(path, 6, nm, 64)
3051 if vn < 1 { return of_err(out, "404 Not Found" as *u8, "bad file path" as *u8) }
3052 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
3053 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
3054 let n: i64 = of_serve(root, nm, vn, 0, out, cap)
3055 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such version" as *u8) }
3056 return n
3057 }
3058 if of_starts(path, "/original/" as *u8) == 1 {
3059 // LP1: the untouched upload bytes of an imported version (original.odt | original.docx), else the version file
3060 let nm: *u8 = sys_mmap(64)
3061 let vn: i64 = of_parse_nv(path, 10, nm, 64)
3062 if vn < 1 { return of_err(out, "404 Not Found" as *u8, "bad original path" as *u8) }
3063 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
3064 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
3065 let n: i64 = of_serve_original(root, nm, vn, out, cap)
3066 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such version" as *u8) }
3067 return n
3068 }
3069 if of_starts(path, "/cert/" as *u8) == 1 {
3070 // LP4: the signing receipt of a version (certificate CID, envelope, document CID, signers, audit head)
3071 let nm: *u8 = sys_mmap(64)
3072 let vn: i64 = of_parse_nv(path, 6, nm, 64)
3073 if vn < 1 { return of_err(out, "404 Not Found" as *u8, "bad cert path" as *u8) }
3074 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
3075 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
3076 let n: i64 = of_serve_cert(root, nm, vn, out, cap)
3077 if n < 0 { return of_err(out, "404 Not Found" as *u8, "this version has not been signed" as *u8) }
3078 return n
3079 }
3080 if of_starts(path, "/diff/" as *u8) == 1 {
3081 // /diff/<name>/<a>/<b>
3082 let nm: *u8 = sys_mmap(64)
3083 var q: i64 = 6
3084 var t: i64 = 0
3085 while path[q] != (0 as u8) { if path[q] == (47 as u8) { break } if t < 63 { nm[t] = path[q]; t = t + 1 } q = q + 1 }
3086 nm[t] = 0 as u8
3087 if path[q] != (47 as u8) { return of_err(out, "404 Not Found" as *u8, "bad diff path" as *u8) }
3088 q = q + 1
3089 var va: i64 = 0; var da: i64 = 0
3090 while path[q] != (0 as u8) { let c: i64 = path[q] as i64; if c >= 48 { if c <= 57 { va = va * 10 + (c - 48); da = da + 1; q = q + 1 } else { break } } else { break } }
3091 if path[q] != (47 as u8) { return of_err(out, "404 Not Found" as *u8, "bad diff path" as *u8) }
3092 q = q + 1
3093 var vb: i64 = 0; var db: i64 = 0
3094 while path[q] != (0 as u8) { let c: i64 = path[q] as i64; if c >= 48 { if c <= 57 { vb = vb * 10 + (c - 48); db = db + 1; q = q + 1 } else { break } } else { break } }
3095 if da == 0 { return of_err(out, "404 Not Found" as *u8, "bad diff versions" as *u8) }
3096 if db == 0 { return of_err(out, "404 Not Found" as *u8, "bad diff versions" as *u8) }
3097 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
3098 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
3099 let n: i64 = of_diffpage(root, base, nm, va, vb, out, cap)
3100 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such file or version" as *u8) }
3101 return of_cl_frame(out, n, cap)
3102 }
3103 if of_seq(path, "/groups" as *u8) == 1 {
3104 let n: i64 = of_groupspage(base, azprefix, me, authed, tok, out, cap)
3105 return of_cl_frame(out, n, cap)
3106 }
3107 if of_seq(path, "/shared-with-me" as *u8) == 1 {
3108 let n: i64 = of_sharedpage(base, azprefix, me, authed, out, cap)
3109 return of_cl_frame(out, n, cap)
3110 }
3111 if of_starts(path, "/manage/" as *u8) == 1 {
3112 let nm: *u8 = sys_mmap(64)
3113 var q: i64 = 8
3114 var t2: i64 = 0
3115 while path[q] != (0 as u8) { if t2 < 63 { nm[t2] = path[q]; t2 = t2 + 1 } q = q + 1 }
3116 nm[t2] = 0 as u8
3117 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
3118 let n: i64 = of_managepage(base, azprefix, me, authed, nm, tok, out, cap)
3119 if n == (0 - 1) { return of_err(out, "401 Unauthorized" as *u8, "sign in to manage sharing" as *u8) }
3120 if n == (0 - 2) { return of_err(out, "404 Not Found" as *u8, "this document has no owner (it is public)" as *u8) }
3121 if n == (0 - 3) { return of_err(out, "403 Forbidden" as *u8, "only the owner can manage sharing" as *u8) }
3122 return of_cl_frame(out, n, cap)
3123 }
3124 return of_err(out, "404 Not Found" as *u8, "no such route" as *u8)
3125}
3126
3127// ---- the offline gate body (consumed by _hdl_build/nx_office_gate) ----
3128// D001 migration (2026-09-02): the selftest's 94 teeth all flow through this ONE ruler, so inheriting the shared
3129// verdict base is a change here and nowhere else. When a gv counter is armed (the gate arms it through
3130// of_selftest_gv) every tooth is a gv_check -- declared == executed by construction -- and the exit code carries
3131// the verdict through gv_verdict; the daemon's own `selftest` verb keeps the legacy PASS/FAIL print.
3132static g_of_gv: i64 // the armed gv counter as an address; module-level state is `static` (zero-initialised), never `var`
3133func of_ck(name: *u8, cond: i64, pass: *i64, fail: *i64) -> i64 {
3134 if g_of_gv != 0 {
3135 gv_check(name, cond, g_of_gv as *i64)
3136 if cond == 1 { pass[0] = pass[0] + 1; return 1 }
3137 fail[0] = fail[0] + 1
3138 return 0
3139 }
3140 if cond == 1 { p(" PASS " as *u8); p(name); p("\n" as *u8); pass[0] = pass[0] + 1; return 1 }
3141 p(" FAIL " as *u8); p(name); p("\n" as *u8); fail[0] = fail[0] + 1
3142 return 0
3143}
3144// the gate's entry: arm the shared counter, run every tooth through it, and let the caller emit gv_verdict LAST.
3145func of_selftest_gv(root: *u8, c: *i64) -> i64 {
3146 g_of_gv = c as i64
3147 return of_selftest(root)
3148}
3149func of_selftest(root: *u8) -> i64 {
3150 p("=== NX-OFFICE SELFTEST root=" as *u8); p(root); p(" (create/edit/version/preview/download, additive-proven, LOUD negatives) ===\n" as *u8)
3151 let base: *u8 = sys_mmap(4)
3152 base[0] = 0 as u8
3153 let pass: *i64 = sys_mmap(16) as *i64
3154 let fail: *i64 = sys_mmap(16) as *i64
3155 pass[0] = 0
3156 fail[0] = 0
3157 let out: *u8 = sys_mmap(1048576)
3158 let req: *u8 = sys_mmap(262144)
3159 let bod: *u8 = sys_mmap(131072)
3160 // T1 empty home
3161 var n: i64 = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
3162 of_ck("T1 home renders" as *u8, of_memhas(out, n, "Nishi Office" as *u8), pass, fail)
3163 // helper-free POST builder: body first, then request with exact Content-Length
3164 var bo: i64 = of_cat(bod, 0, "name=family-letter&kind=doc&spec=H+Family+Letter%0AB+Dear+family%0AP+We+love+each+other." as *u8)
3165 var ro: i64 = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3166 ro = of_catn(req, ro, bo)
3167 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
3168 ro = of_cat(req, ro, bod)
3169 n = of_handle(root, base, req, ro, out, 1048576)
3170 var t2ok: i64 = 0
3171 if of_memhas(out, n, "303 See Other" as *u8) == 1 { if of_memhas(out, n, "/doc/family-letter" as *u8) == 1 { t2ok = 1 } }
3172 of_ck("T2 create doc v1 (303 redirect)" as *u8, t2ok, pass, fail)
3173 let fb: *u8 = sys_mmap(1048576)
3174 let ap: *u8 = sys_mmap(600)
3175 var ao: i64 = of_cat(ap, 0, root); ao = of_cat(ap, ao, "/family-letter/v1/file.docx" as *u8); ap[ao] = 0 as u8
3176 let fl1: i64 = of_read_file(ap, fb, 1048576)
3177 var t2b: i64 = 0
3178 if fl1 > 200 { t2b = 1 }
3179 of_ck("T2b v1 .docx built on disk" as *u8, t2b, pass, fail)
3180 let pp: *u8 = sys_mmap(600)
3181 var po: i64 = of_cat(pp, 0, root); po = of_cat(pp, po, "/family-letter/v1/preview.html" as *u8); pp[po] = 0 as u8
3182 let pv: *u8 = sys_mmap(1048576)
3183 let pl: i64 = of_read_file(pp, pv, 1048576)
3184 var t2c: i64 = 0
3185 if pl > 0 { t2c = of_memhas(pv, pl, "Family Letter" as *u8) }
3186 of_ck("T2c v1 preview renders the heading" as *u8, t2c, pass, fail)
3187 // T3 doc page round-trips the spec into the editor
3188 n = of_handle(root, base, "GET /doc/family-letter HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 56, out, 1048576)
3189 var t3: i64 = 0
3190 if of_memhas(out, n, "H Family Letter" as *u8) == 1 { if of_memhas(out, n, "Save as v2" as *u8) == 1 { t3 = 1 } }
3191 of_ck("T3 editor page carries latest spec (raw fallback)" as *u8, t3, pass, fail)
3192 // T3b VISUAL editor: doc spec rendered as editable blocks (#ed, <h2>, <b>) + app.js wired
3193 var t3b: i64 = 0
3194 if of_memhas(out, n, "id='ed' class='visual doc' contenteditable" as *u8) == 1 {
3195 if of_memhas(out, n, "<h2>Family Letter</h2>" as *u8) == 1 {
3196 if of_memhas(out, n, "<p data-k='B'><b>Dear family</b></p>" as *u8) == 1 {
3197 if of_memhas(out, n, "/app.js'></script>" as *u8) == 1 { t3b = 1 } } } }
3198 of_ck("T3b doc renders editable blocks (#ed h2/b) + app.js" as *u8, t3b, pass, fail)
3199 // T3c the client is served at /app.js as javascript
3200 var na: i64 = of_handle(root, base, "GET /app.js HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 44, out, 1048576)
3201 var t3c: i64 = 0
3202 if of_memhas(out, na, "Content-Type: application/javascript" as *u8) == 1 { if of_memhas(out, na, "getElementById" as *u8) == 1 { t3c = 1 } }
3203 of_ck("T3c /app.js serves the client as javascript" as *u8, t3c, pass, fail)
3204 // snapshot v1 spec bytes for the additive proof
3205 let s1p: *u8 = sys_mmap(600)
3206 var s1o: i64 = of_cat(s1p, 0, root); s1o = of_cat(s1p, s1o, "/family-letter/v1/spec.txt" as *u8); s1p[s1o] = 0 as u8
3207 let s1a: *u8 = sys_mmap(131072)
3208 let s1n: i64 = of_read_file(s1p, s1a, 131072)
3209 // T4 save v2 (edited)
3210 bo = of_cat(bod, 0, "name=family-letter&kind=doc&spec=H+Family+Letter+EDITED%0AP+Now+with+a+second+version." as *u8)
3211 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3212 ro = of_catn(req, ro, bo)
3213 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
3214 ro = of_cat(req, ro, bod)
3215 n = of_handle(root, base, req, ro, out, 1048576)
3216 let s2p: *u8 = sys_mmap(600)
3217 var s2o: i64 = of_cat(s2p, 0, root); s2o = of_cat(s2p, s2o, "/family-letter/v2/spec.txt" as *u8); s2p[s2o] = 0 as u8
3218 let s2a: *u8 = sys_mmap(131072)
3219 let s2n: i64 = of_read_file(s2p, s2a, 131072)
3220 var t4: i64 = 0
3221 if of_memhas(out, n, "303" as *u8) == 1 { if s2n > 0 { t4 = 1 } }
3222 of_ck("T4 save again creates v2" as *u8, t4, pass, fail)
3223 let s1b: *u8 = sys_mmap(131072)
3224 let s1n2: i64 = of_read_file(s1p, s1b, 131072)
3225 var addv: i64 = 0
3226 if s1n2 == s1n { if s1n > 0 {
3227 addv = 1
3228 var ci: i64 = 0
3229 while ci < s1n { if s1a[ci] != s1b[ci] { addv = 0; ci = s1n } ci = ci + 1 }
3230 } }
3231 of_ck("T4b ADDITIVE: v1 spec bytes unchanged after v2" as *u8, addv, pass, fail)
3232 // T5 artifact download: response body == on-disk v2 bytes
3233 n = of_handle(root, base, "GET /file/family-letter/v2 HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 60, out, 1048576)
3234 var bs: i64 = 0 - 1
3235 var bi: i64 = 0
3236 while bi + 3 < n {
3237 if out[bi] == (13 as u8) { if out[bi+1] == (10 as u8) { if out[bi+2] == (13 as u8) { if out[bi+3] == (10 as u8) { bs = bi + 4; bi = n } } } }
3238 bi = bi + 1
3239 }
3240 var a2o2: i64 = of_cat(ap, 0, root)
3241 a2o2 = of_cat(ap, a2o2, "/family-letter/v2/file.docx" as *u8)
3242 ap[a2o2] = 0 as u8
3243 let fl2: i64 = of_read_file(ap, fb, 1048576)
3244 var t5: i64 = 0
3245 if bs > 0 { if n - bs == fl2 { if fl2 > 0 {
3246 t5 = 1
3247 var di: i64 = 0
3248 while di < fl2 { if out[bs + di] != fb[di] { t5 = 0; di = fl2 } di = di + 1 }
3249 } } }
3250 var t5h: i64 = of_memhas(out, bs, "wordprocessingml" as *u8)
3251 var t5ok: i64 = 0
3252 if t5 == 1 { if t5h == 1 { t5ok = 1 } }
3253 of_ck("T5 download == on-disk bytes + docx content-type" as *u8, t5ok, pass, fail)
3254 // T6 sheet with a real formula: preview shows the COMPUTED 30
3255 bo = of_cat(bod, 0, "name=family-budget&kind=sheet&spec=Item%09Cost%0AApples%0910%0APears%0920%0ATotal%09=SUM(B2:B3)" as *u8)
3256 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3257 ro = of_catn(req, ro, bo)
3258 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
3259 ro = of_cat(req, ro, bod)
3260 n = of_handle(root, base, req, ro, out, 1048576)
3261 var t6r: i64 = of_memhas(out, n, "303" as *u8)
3262 n = of_handle(root, base, "GET /preview/family-budget/v1 HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 63, out, 1048576)
3263 var t6: i64 = 0
3264 if t6r == 1 { if of_memhas(out, n, "30" as *u8) == 1 { t6 = 1 } }
3265 of_ck("T6 sheet formula computed in preview (SUM=30)" as *u8, t6, pass, fail)
3266 // T7 deck
3267 bo = of_cat(bod, 0, "name=reunion-deck&kind=deck&spec=S+Reunion+2026%0AB+Where:+the+lake%0AS+Food%0AB+Friday:+burgers" as *u8)
3268 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3269 ro = of_catn(req, ro, bo)
3270 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
3271 ro = of_cat(req, ro, bod)
3272 n = of_handle(root, base, req, ro, out, 1048576)
3273 var t7r: i64 = of_memhas(out, n, "303" as *u8)
3274 n = of_handle(root, base, "GET /preview/reunion-deck/v1 HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 62, out, 1048576)
3275 var t7: i64 = 0
3276 if t7r == 1 { if of_memhas(out, n, "Reunion 2026" as *u8) == 1 { t7 = 1 } }
3277 of_ck("T7 deck builds + preview shows slide title" as *u8, t7, pass, fail)
3278 // T7b VISUAL editors for sheet + deck (editable grid #grid, editable slides #deck)
3279 n = of_handle(root, base, "GET /doc/family-budget HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 56, out, 1048576)
3280 var t7b: i64 = 0
3281 if of_memhas(out, n, "id='grid' class='visual sheet'" as *u8) == 1 { if of_memhas(out, n, "<td contenteditable='true'>Apples</td>" as *u8) == 1 { t7b = 1 } }
3282 of_ck("T7b sheet renders an editable grid (#grid cells)" as *u8, t7b, pass, fail)
3283 n = of_handle(root, base, "GET /doc/reunion-deck HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 55, out, 1048576)
3284 var t7c: i64 = 0
3285 if of_memhas(out, n, "id='deck' class='visual deck'" as *u8) == 1 { if of_memhas(out, n, "<h3 contenteditable='true'>Reunion 2026</h3>" as *u8) == 1 { if of_memhas(out, n, "data-act='slide'" as *u8) == 1 { t7c = 1 } } }
3286 of_ck("T7c deck renders editable slides (#deck h3 + toolbar)" as *u8, t7c, pass, fail)
3287 // T8 LOUD negatives
3288 bo = of_cat(bod, 0, "name=Bad/Name&kind=doc&spec=P+x" as *u8)
3289 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3290 ro = of_catn(req, ro, bo)
3291 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
3292 ro = of_cat(req, ro, bod)
3293 n = of_handle(root, base, req, ro, out, 1048576)
3294 of_ck("T8a bad name refused 400" as *u8, of_memhas(out, n, "400" as *u8), pass, fail)
3295 bo = of_cat(bod, 0, "name=family-letter&kind=sheet&spec=A%09B" as *u8)
3296 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3297 ro = of_catn(req, ro, bo)
3298 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
3299 ro = of_cat(req, ro, bod)
3300 n = of_handle(root, base, req, ro, out, 1048576)
3301 of_ck("T8b kind flip on existing name refused 400" as *u8, of_memhas(out, n, "kind mismatch" as *u8), pass, fail)
3302 n = of_handle(root, base, "GET /file/family-letter/v9 HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 60, out, 1048576)
3303 of_ck("T8c missing version 404" as *u8, of_memhas(out, n, "404" as *u8), pass, fail)
3304 bo = of_cat(bod, 0, "name=family-letter&kind=doc&spec=P+evil" as *u8)
3305 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nOrigin: http://evil.example\r\nContent-Length: " as *u8)
3306 ro = of_catn(req, ro, bo)
3307 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
3308 ro = of_cat(req, ro, bod)
3309 n = of_handle(root, base, req, ro, out, 1048576)
3310 of_ck("T8d cross-origin POST refused 403" as *u8, of_memhas(out, n, "403" as *u8), pass, fail)
3311 let kb: *u8 = sys_mmap(64)
3312 var t8e: i64 = 0
3313 if of_manifest_count(root, "family-letter" as *u8, kb, 64) == 2 { t8e = 1 }
3314 of_ck("T8e negatives left NO new versions (still 2)" as *u8, t8e, pass, fail)
3315 // T9 home lists all three
3316 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
3317 var t9: i64 = 0
3318 if of_memhas(out, n, "family-letter" as *u8) == 1 { if of_memhas(out, n, "family-budget" as *u8) == 1 { if of_memhas(out, n, "reunion-deck" as *u8) == 1 { t9 = 1 } } }
3319 of_ck("T9 home lists all three files" as *u8, t9, pass, fail)
3320 // T10 MOUNTED at /office: the edge forwards the full path; stripping routes it, links carry the prefix.
3321 let mbase: *u8 = "/office" as *u8
3322 n = of_handle(root, mbase, "GET /office HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8, 46, out, 1048576)
3323 var t10a: i64 = 0
3324 if of_memhas(out, n, "Nishi Office" as *u8) == 1 { if of_memhas(out, n, "/office/doc/family-letter" as *u8) == 1 { t10a = 1 } }
3325 of_ck("T10a /office home renders + links carry the mount prefix" as *u8, t10a, pass, fail)
3326 n = of_handle(root, mbase, "GET /office/file/family-letter/v2 HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8, 68, out, 1048576)
3327 var t10b: i64 = 0
3328 if of_memhas(out, n, "200 OK" as *u8) == 1 { if of_memhas(out, n, "wordprocessingml" as *u8) == 1 { t10b = 1 } }
3329 of_ck("T10b /office/file/.../v2 downloads through the mount" as *u8, t10b, pass, fail)
3330 // T10c a query string (cache-bust, browser params) must not break routing -> home still renders
3331 n = of_handle(root, mbase, "GET /office?v=golive9f2 HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8, 58, out, 1048576)
3332 of_ck("T10c /office?query still routes to home (no 404)" as *u8, of_memhas(out, n, "Nishi Office" as *u8), pass, fail)
3333 // T11 VERSION DIFF: controlled v1/v2 with a partial overlap -> LCS keeps 2, adds 1, removes 1.
3334 // NOTE: of_cat does NOT NUL-terminate -> terminate bod at bo so of_cat(req,ro,bod) copies EXACTLY the body
3335 // (else a shorter body trails leftover bytes from a longer prior test = spec contamination).
3336 bo = of_cat(bod, 0, "name=diffdoc&kind=doc&spec=H+Title%0AP+Line+A%0AP+Line+B" as *u8); bod[bo] = 0 as u8
3337 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3338 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3339 n = of_handle(root, base, req, ro, out, 1048576)
3340 bo = of_cat(bod, 0, "name=diffdoc&kind=doc&spec=H+Title%0AP+Line+A+CHANGED%0AP+Line+B" as *u8); bod[bo] = 0 as u8
3341 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3342 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3343 n = of_handle(root, base, req, ro, out, 1048576)
3344 n = of_handle(root, base, "GET /diff/diffdoc/1/2 HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 53, out, 1048576)
3345 var t11: i64 = 0
3346 if of_memhas(out, n, "Changes: v1 → v2" as *u8) == 1 {
3347 if of_memhas(out, n, "class='ddel'>− P Line A</div>" as *u8) == 1 {
3348 if of_memhas(out, n, "class='dadd'>+ P Line A CHANGED</div>" as *u8) == 1 {
3349 if of_memhas(out, n, "class='dkeep'> H Title</div>" as *u8) == 1 {
3350 if of_memhas(out, n, "<b>1</b> line(s) added, <b>1</b> removed" as *u8) == 1 { t11 = 1 } } } } }
3351 of_ck("T11 version diff: LCS keep/add/del + counts (1 added, 1 removed)" as *u8, t11, pass, fail)
3352 // T11b the doc page links the diff for v>=2
3353 n = of_handle(root, base, "GET /doc/diffdoc HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 50, out, 1048576)
3354 of_ck("T11b doc page links 'vs v1' diff for v2" as *u8, of_memhas(out, n, "/diff/diffdoc/1/2'>vs v1" as *u8), pass, fail)
3355 // T11c doc page offers a Restore button for the older version (v1), not for the current (v2)
3356 of_ck("T11c versions table has a Restore form for v1" as *u8, of_memhas(out, n, "/restore' style='margin:0'><input type='hidden' name='name' value='diffdoc'><input type='hidden' name='version' value='1'" as *u8), pass, fail)
3357 // T11d RESTORE: put diffdoc v1 back -> creates v3 == v1 spec, ADDITIVE (v1 + v2 untouched)
3358 bo = of_cat(bod, 0, "name=diffdoc&version=1" as *u8); bod[bo] = 0 as u8
3359 ro = of_cat(req, 0, "POST /restore HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3360 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3361 n = of_handle(root, base, req, ro, out, 1048576)
3362 var t11d: i64 = of_memhas(out, n, "303" as *u8)
3363 // v3 spec must byte-equal v1 spec; manifest now has 3 versions
3364 let rkbx: *u8 = sys_mmap(64)
3365 let rvcx: i64 = of_manifest_count(root, "diffdoc" as *u8, rkbx, 64)
3366 let s1x: *u8 = sys_mmap(4096)
3367 let s3x: *u8 = sys_mmap(4096)
3368 let n1x: i64 = of_read_version_spec(root, "diffdoc" as *u8, 1, s1x, 4095)
3369 let n3x: i64 = of_read_version_spec(root, "diffdoc" as *u8, 3, s3x, 4095)
3370 var eqx: i64 = 0
3371 if rvcx == 3 { if n1x == n3x { if n1x > 0 {
3372 eqx = 1
3373 var ci: i64 = 0
3374 while ci < n1x { if s1x[ci] != s3x[ci] { eqx = 0; ci = n1x } ci = ci + 1 }
3375 } } }
3376 var t11dok: i64 = 0
3377 if t11d == 1 { if eqx == 1 { t11dok = 1 } }
3378 of_ck("T11d restore v1 -> v3==v1 spec, additive (now 3 versions)" as *u8, t11dok, pass, fail)
3379 // T12 the PRODUCT SHELL (U-axes rung): search / type chips / sort order / REAL thumbnails / empty states /
3380 // editor chrome. Ordering asserted with of_findpos, not just presence.
3381 n = of_handle(root, base, "GET /?q=budget HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 47, out, 1048576)
3382 var t12a: i64 = 0
3383 if of_memhas(out, n, "family-budget" as *u8) == 1 { if of_memhas(out, n, "/doc/family-letter" as *u8) == 0 { t12a = 1 } }
3384 of_ck("T12a search q=budget filters the card grid" as *u8, t12a, pass, fail)
3385 n = of_handle(root, base, "GET /?type=deck HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 48, out, 1048576)
3386 var t12b: i64 = 0
3387 if of_memhas(out, n, "reunion-deck" as *u8) == 1 { if of_memhas(out, n, "/doc/family-budget" as *u8) == 0 { t12b = 1 } }
3388 of_ck("T12b type=deck chip filters to decks only" as *u8, t12b, pass, fail)
3389 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
3390 var pd: i64 = of_findpos(out, n, "/doc/reunion-deck" as *u8)
3391 var plt: i64 = of_findpos(out, n, "/doc/family-letter" as *u8)
3392 var t12c: i64 = 0
3393 if pd >= 0 { if plt >= 0 { if pd < plt { t12c = 1 } } }
3394 of_ck("T12c default sort = recently edited first (deck before letter)" as *u8, t12c, pass, fail)
3395 n = of_handle(root, base, "GET /?sort=name HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 48, out, 1048576)
3396 var pb2: i64 = of_findpos(out, n, "/doc/family-budget" as *u8)
3397 var pl2: i64 = of_findpos(out, n, "/doc/family-letter" as *u8)
3398 var pd2: i64 = of_findpos(out, n, "/doc/reunion-deck" as *u8)
3399 var t12d: i64 = 0
3400 if pb2 >= 0 { if pl2 > pb2 { if pd2 > pl2 { t12d = 1 } } }
3401 of_ck("T12d sort=name orders the grid alphabetically" as *u8, t12d, pass, fail)
3402 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
3403 var t12e: i64 = 0
3404 if of_memhas(out, n, "class='thumb'" as *u8) == 1 { if of_memhas(out, n, "tsheet" as *u8) == 1 { if of_memhas(out, n, "Apples" as *u8) == 1 { if of_memhas(out, n, "Family Letter EDITED" as *u8) == 1 { t12e = 1 } } } }
3405 of_ck("T12e home cards carry REAL content thumbnails (sheet cells + doc heading)" as *u8, t12e, pass, fail)
3406 n = of_handle(root, base, "GET /?q=zzzz HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 45, out, 1048576)
3407 of_ck("T12f no-match search shows an empty state" as *u8, of_memhas(out, n, "No files match" as *u8), pass, fail)
3408 let root2: *u8 = sys_mmap(600)
3409 var r2o: i64 = of_cat(root2, 0, root); r2o = of_cat(root2, r2o, "-fresh" as *u8); root2[r2o] = 0 as u8
3410 n = of_handle(root2, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
3411 of_ck("T12g first-run onboarding empty state" as *u8, of_memhas(out, n, "Create your first document" as *u8), pass, fail)
3412 n = of_handle(root, base, "GET /doc/family-letter HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 56, out, 1048576)
3413 var t12h: i64 = 0
3414 if of_memhas(out, n, "Saved v2" as *u8) == 1 { if of_memhas(out, n, "data-act='u'" as *u8) == 1 { if of_memhas(out, n, "data-act='find'" as *u8) == 1 { if of_memhas(out, n, "id='savest'" as *u8) == 1 { t12h = 1 } } } }
3415 of_ck("T12h editor carries saved-stamp + undo/find controls + save-state slot" as *u8, t12h, pass, fail)
3416 var nj: i64 = of_handle(root, base, "GET /app.js HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 44, out, 1048576)
3417 var t12i: i64 = 0
3418 if of_memhas(out, nj, "ctrlKey" as *u8) == 1 { if of_memhas(out, nj, "createTreeWalker" as *u8) == 1 { if of_memhas(out, nj, "localStorage" as *u8) == 1 { t12i = 1 } } }
3419 of_ck("T12i app.js ships find/shortcuts/theme (ctrlKey+TreeWalker+localStorage)" as *u8, t12i, pass, fail)
3420 // T13 TRUE AUTOSAVE (U4 rung): ajax=1 -> 200 OK v<N> (no 303 navigation), manifest tags the version with
3421 // the additive 4th field "auto", and the Versions table labels it. The JS side (debounce + changed-only)
3422 // ships in app.js (T13d needles) -- browser timing itself is not headless-executed here (honest caveat).
3423 bo = of_cat(bod, 0, "name=family-letter&kind=doc&spec=H+Family+Letter+AUTO%0AP+Background+save.&ajax=1" as *u8)
3424 bod[bo] = 0 as u8
3425 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3426 ro = of_catn(req, ro, bo)
3427 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
3428 ro = of_cat(req, ro, bod)
3429 n = of_handle(root, base, req, ro, out, 1048576)
3430 var t13a: i64 = 0
3431 if of_memhas(out, n, "200 OK" as *u8) == 1 { if of_memhas(out, n, "OK v3" as *u8) == 1 { if of_memhas(out, n, "303" as *u8) == 0 { t13a = 1 } } }
3432 of_ck("T13a ajax autosave answers 200 OK v3 (no 303)" as *u8, t13a, pass, fail)
3433 var t13b: i64 = 0
3434 if of_manifest_is_auto(root, "family-letter" as *u8, 3) == 1 { if of_manifest_is_auto(root, "family-letter" as *u8, 2) == 0 { t13b = 1 } }
3435 of_ck("T13b manifest tags v3 auto, v2 not" as *u8, t13b, pass, fail)
3436 n = of_handle(root, base, "GET /doc/family-letter HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 56, out, 1048576)
3437 var t13c: i64 = 0
3438 if of_memhas(out, n, "(auto)" as *u8) == 1 { if of_memhas(out, n, "Save as v4" as *u8) == 1 { t13c = 1 } }
3439 of_ck("T13c versions table labels the autosave + next save renumbers v4" as *u8, t13c, pass, fail)
3440 var nj2: i64 = of_handle(root, base, "GET /app.js HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 44, out, 1048576)
3441 var t13d: i64 = 0
3442 if of_memhas(out, nj2, "ajax=1" as *u8) == 1 { if of_memhas(out, nj2, "lastSpec" as *u8) == 1 { if of_memhas(out, nj2, "Autosaved v" as *u8) == 1 { t13d = 1 } } }
3443 of_ck("T13d app.js ships the autosave engine (ajax=1 + changed-only lastSpec)" as *u8, t13d, pass, fail)
3444 // T14 HTML pages carry Content-Length so the STRICT sovereign browser can frame them (the /office in-browser
3445 // fetch failed without it). Assert present on the home response AND that its value == the actual body length.
3446 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
3447 var t14: i64 = 0
3448 if of_memhas(out, n, "Content-Length: " as *u8) == 1 {
3449 var hp: i64 = 0 - 1
3450 var xi: i64 = 0
3451 while xi + 3 < n { if out[xi] == (13 as u8) { if out[xi+1] == (10 as u8) { if out[xi+2] == (13 as u8) { if out[xi+3] == (10 as u8) { hp = xi; xi = n } } } } xi = xi + 1 }
3452 if hp >= 0 {
3453 let bodylen: i64 = n - (hp + 4)
3454 var cl: i64 = 0
3455 var found: i64 = 0
3456 var ci: i64 = 0
3457 let key: *u8 = "Content-Length: " as *u8
3458 while ci + 16 < hp {
3459 if of_starts((out as i64 + ci) as *u8, key) == 1 {
3460 var t: i64 = ci + 16
3461 while t < hp { let dch: i64 = out[t] as i64; if dch >= 48 { if dch <= 57 { cl = cl * 10 + (dch - 48); found = 1 } } if out[t] == (13 as u8) { t = hp } else { t = t + 1 } }
3462 ci = hp
3463 } else { ci = ci + 1 }
3464 }
3465 if found == 1 { if cl == bodylen { t14 = 1 } }
3466 }
3467 }
3468 of_ck("T14 home carries a CORRECT Content-Length (strict-client framable)" as *u8, t14, pass, fail)
3469
3470 // ---- AUTHZ (nx_rebac): owner-binding + read/write gating + share/unshare -- the office integration ----
3471 let azp: *u8 = sys_mmap(96); var azo: i64 = of_cat(azp, 0, "/tmp/ofauthz_" as *u8); azo = of_catn(azp, azo, sys_now_us()); azo = of_cat(azp, azo, "_" as *u8); azp[azo] = 0 as u8
3472 let azal: *u8 = sys_mmap(24); of_meref(azal, "alice" as *u8)
3473 let azbo: *u8 = sys_mmap(24); of_meref(azbo, "bob" as *u8)
3474 let azca: *u8 = sys_mmap(24); of_meref(azca, "carol" as *u8)
3475 let azempty: *u8 = sys_mmap(4); azempty[0] = 0 as u8
3476 of_ck("AZ0a unowned doc PUBLIC to authed (non-breaking)" as *u8, of_read_ok(azp, azal, 1, "flyer" as *u8), pass, fail)
3477 of_ck("AZ0b unowned doc PUBLIC to anon (non-breaking)" as *u8, of_read_ok(azp, azempty, 0, "flyer" as *u8), pass, fail)
3478 let azsref: *u8 = sys_mmap(32); of_docref(azsref, "secret" as *u8)
3479 rb_put(azp, azsref, "owner" as *u8, azal, "alice" as *u8, 1)
3480 of_ck("AZ1 owner alice reads owned secret" as *u8, of_read_ok(azp, azal, 1, "secret" as *u8), pass, fail)
3481 of_ck("AZ2 anon DENIED on owned secret" as *u8, 1 - of_read_ok(azp, azempty, 0, "secret" as *u8), pass, fail)
3482 of_ck("AZ3 bob (no grant) DENIED read" as *u8, 1 - of_read_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
3483 of_ck("AZ4 bob DENIED write" as *u8, 1 - of_write_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
3484 rb_put(azp, azsref, "viewer" as *u8, azbo, "alice" as *u8, 1)
3485 of_ck("AZ5 bob now READS (shared viewer)" as *u8, of_read_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
3486 of_ck("AZ6 bob viewer still cannot WRITE" as *u8, 1 - of_write_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
3487 rb_put(azp, azsref, "editor" as *u8, azca, "alice" as *u8, 1)
3488 of_ck("AZ7 carol editor CAN write" as *u8, of_write_ok(azp, azca, 1, "secret" as *u8), pass, fail)
3489 rb_put(azp, azsref, "viewer" as *u8, azbo, "alice" as *u8, 0)
3490 of_ck("AZ8 bob REVOKED (unshare tombstone)" as *u8, 1 - of_read_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
3491 of_ck("AZ9 alice may_grant (owner)" as *u8, rb_may_grant(azp, azal, azsref), pass, fail)
3492 of_ck("AZ10 bob may_grant DENIED (not owner)" as *u8, 1 - rb_may_grant(azp, azbo, azsref), pass, fail)
3493 let azdob: *u8 = sys_mmap(8192)
3494 let azsh1: *u8 = "name=secret&who=dan&level=viewer" as *u8
3495 let azr1: i64 = of_do_share("/office" as *u8, azp, azal, "alice" as *u8, 1, azsh1, of_slen(azsh1), azdob, 1)
3496 let azdan: *u8 = sys_mmap(16); of_meref(azdan, "dan" as *u8)
3497 of_ck("AZ11a of_do_share owner->dan = 303" as *u8, of_memhas(azdob, azr1, "303" as *u8), pass, fail)
3498 of_ck("AZ11b dan now reads secret" as *u8, of_read_ok(azp, azdan, 1, "secret" as *u8), pass, fail)
3499 let azr2: i64 = of_do_share("/office" as *u8, azp, azbo, "bob" as *u8, 1, azsh1, of_slen(azsh1), azdob, 1)
3500 of_ck("AZ12 of_do_share by non-owner bob = 403" as *u8, of_memhas(azdob, azr2, "403" as *u8), pass, fail)
3501 let azsh2: *u8 = "name=secret&who=ev:il&level=viewer" as *u8
3502 let azr3: i64 = of_do_share("/office" as *u8, azp, azal, "alice" as *u8, 1, azsh2, of_slen(azsh2), azdob, 1)
3503 of_ck("AZ13 of_do_share bad handle = 400 (no forge)" as *u8, of_memhas(azdob, azr3, "400" as *u8), pass, fail)
3504 let azmob: *u8 = sys_mmap(65536)
3505 let azm1: i64 = of_managepage("/office" as *u8, azp, azal, 1, "secret" as *u8, "TOK" as *u8, azmob, 65536)
3506 of_ck("AZ14 owner manage page renders" as *u8, of_memhas(azmob, azm1, "Sharing: secret" as *u8), pass, fail)
3507 let azm2: i64 = of_managepage("/office" as *u8, azp, azbo, 1, "secret" as *u8, "TOK" as *u8, azmob, 65536)
3508 var azm2ok: i64 = 0
3509 if azm2 == (0 - 3) { azm2ok = 1 }
3510 of_ck("AZ15 non-owner manage DENIED (-3)" as *u8, azm2ok, pass, fail)
3511 let azm3: i64 = of_managepage("/office" as *u8, azp, azal, 1, "flyer" as *u8, "TOK" as *u8, azmob, 65536)
3512 var azm3ok: i64 = 0
3513 if azm3 == (0 - 2) { azm3ok = 1 }
3514 of_ck("AZ16 manage unowned = not-owned (-2)" as *u8, azm3ok, pass, fail)
3515 of_ck("AZ17 handle validator rejects colon (no type forge)" as *u8, 1 - of_tok_ok("ev:il" as *u8), pass, fail)
3516 of_ck("AZ18 handle validator accepts ok_h-1" as *u8, of_tok_ok("ok_h-1" as *u8), pass, fail)
3517
3518 // ---- GROUP SHARING (the userset differentiator): share a doc with a GROUP, members inherit access ----
3519 let azgadd: *u8 = "group=team&who=rose" as *u8
3520 let azgr: i64 = of_do_group("/office" as *u8, azp, azal, "alice" as *u8, 1, azgadd, of_slen(azgadd), azdob, 1)
3521 of_ck("AZ19 alice creates group team + adds rose = 303" as *u8, of_memhas(azdob, azgr, "303" as *u8), pass, fail)
3522 let azgshare: *u8 = "name=secret&who=team&level=viewer&target=group" as *u8
3523 let azgs: i64 = of_do_share("/office" as *u8, azp, azal, "alice" as *u8, 1, azgshare, of_slen(azgshare), azdob, 1)
3524 of_ck("AZ20 share secret with GROUP team = 303" as *u8, of_memhas(azdob, azgs, "303" as *u8), pass, fail)
3525 let azrose: *u8 = sys_mmap(16); of_meref(azrose, "rose" as *u8)
3526 of_ck("AZ21 rose reads secret VIA GROUP membership (userset)" as *u8, of_read_ok(azp, azrose, 1, "secret" as *u8), pass, fail)
3527 // reverse index (list-objects): what docs can each subject reach?
3528 let azmd: *i64 = sys_mmap(8 * 128) as *i64
3529 let aznd: i64 = of_my_docs(azp, azrose, azmd, 128)
3530 of_ck("AZ21b reverse-index: rose's docs include secret VIA GROUP" as *u8, rb_in_list(azmd, aznd, "doc:secret" as *u8), pass, fail)
3531 let azmd2: *i64 = sys_mmap(8 * 128) as *i64
3532 let aznd2: i64 = of_my_docs(azp, azal, azmd2, 128)
3533 of_ck("AZ21c reverse-index: alice's docs include her owned secret" as *u8, rb_in_list(azmd2, aznd2, "doc:secret" as *u8), pass, fail)
3534 let azfrank: *u8 = sys_mmap(16); of_meref(azfrank, "frank" as *u8)
3535 of_ck("AZ22 frank (not in team) DENIED" as *u8, 1 - of_read_ok(azp, azfrank, 1, "secret" as *u8), pass, fail)
3536 let azgrem: *u8 = "group=team&who=rose" as *u8
3537 of_do_group("/office" as *u8, azp, azal, "alice" as *u8, 1, azgrem, of_slen(azgrem), azdob, 0)
3538 of_ck("AZ23 remove rose from team -> loses secret (userset re-eval)" as *u8, 1 - of_read_ok(azp, azrose, 1, "secret" as *u8), pass, fail)
3539 let azbob2: *u8 = "group=team&who=x" as *u8
3540 let azgb: i64 = of_do_group("/office" as *u8, azp, azbo, "bob" as *u8, 1, azbob2, of_slen(azbob2), azdob, 1)
3541 of_ck("AZ24 non-owner bob cannot add to team = 403 (no group hijack)" as *u8, of_memhas(azdob, azgb, "403" as *u8), pass, fail)
3542
3543 // ---- AI CONTINUE (in-app AI over our own 0.5B seat): offline gate proves the button + graceful 503 ----
3544 // T-AI-a: the doc editor page offers the "Continue with AI" form (doc kind).
3545 n = of_handle(root, base, "GET /doc/family-letter HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 56, out, 1048576)
3546 var tai_a: i64 = 0
3547 if of_memhas(out, n, "Continue with AI" as *u8) == 1 { if of_memhas(out, n, "/ai'><input type='hidden' name='name' value='family-letter'" as *u8) == 1 { tai_a = 1 } }
3548 of_ck("T-AI-a doc page offers the AI-continue form (our own 0.5B model)" as *u8, tai_a, pass, fail)
3549 // T-AI-b: POST /office/ai with the LLM seat DOWN (offline gate) -> graceful 503, no version created, no crash.
3550 let aicnt0: *u8 = sys_mmap(64)
3551 let aiv0: i64 = of_manifest_count(root, "family-letter" as *u8, aicnt0, 64)
3552 bo = of_cat(bod, 0, "name=family-letter" as *u8); bod[bo] = 0 as u8
3553 ro = of_cat(req, 0, "POST /office/ai HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3554 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3555 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3556 let aicnt1: *u8 = sys_mmap(64)
3557 let aiv1: i64 = of_manifest_count(root, "family-letter" as *u8, aicnt1, 64)
3558 // A FIXTURE MUST ASSERT ITS OWN PRECONDITION (measured 2026-09-02): this tooth ASSUMED the seat at
3559 // 127.0.0.1:11434 was DOWN, and the day the estate's sovereign LLM seat came up on the NAS the
3560 // capability WORKED (200, one new version) and the gate read the working feature as a failure --
3561 // office went RED on 93/94 with nothing wrong. The seat's state is PROBED, and each state carries its
3562 // own contract: DOWN -> graceful 503 and NO version; UP -> a completion and EXACTLY ONE new version.
3563 // Neither arm is vacuous: the probe result is the fixture reaching its condition, printed by name.
3564 let seat_addr: *u8 = sys_mmap(16)
3565 nx_http_client_sockaddr_ipv4(seat_addr, 127, 0, 0, 1, 11434)
3566 var seat_up: i64 = 0
3567 let seat_fd: i64 = sys_socket(2, 1, 0)
3568 if seat_fd >= 0 { if sys_connect(seat_fd, seat_addr, 16) >= 0 { seat_up = 1 } sys_close(seat_fd) }
3569 var tai_b: i64 = 0
3570 if seat_up == 0 {
3571 if of_memhas(out, n, "503" as *u8) == 1 { if aiv1 == aiv0 { tai_b = 1 } }
3572 of_ck("T-AI-b POST /ai with seat DOWN (probed: refused) -> graceful 503 (framed) + NO version created" as *u8, tai_b, pass, fail)
3573 } else {
3574 // the seat answered the connect; whether it answered the PROMPT inside the handler's budget is the seat's
3575 // load, not the office's contract (measured 2026-09-02: the same binary passed under the ship's prove and
3576 // failed under the referee a minute later, the seat busy). The office's contract is: a completion becomes
3577 // EXACTLY ONE version, and a missing completion becomes a framed 503 with NO version -- never a half-write,
3578 // never a lost answer. Both outcomes are named so the referee row carries the state it measured.
3579 if of_memhas(out, n, "503" as *u8) == 0 {
3580 if aiv1 == aiv0 + 1 { tai_b = 1 }
3581 of_ck("T-AI-b POST /ai with seat UP (probed: connected, answered) -> the completion landed as EXACTLY ONE new version" as *u8, tai_b, pass, fail)
3582 } else {
3583 if aiv1 == aiv0 { tai_b = 1 }
3584 of_ck("T-AI-b POST /ai with seat UP (probed: connected, NO completion inside the handler budget) -> framed 503 + NO version created" as *u8, tai_b, pass, fail)
3585 }
3586 }
3587 // ---- U4 OFFLINE/PWA + SKELETONS + A11Y ----
3588 // T-U4-a: the web app manifest is served and installable (name + start_url).
3589 n = of_handle(root, base, "GET /manifest.webmanifest HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 59, out, 1048576)
3590 var tu4_a: i64 = 0
3591 if of_memhas(out, n, "200 OK" as *u8) == 1 { if of_memhas(out, n, "Nishi Office" as *u8) == 1 { if of_memhas(out, n, "standalone" as *u8) == 1 { tu4_a = 1 } } }
3592 of_ck("T-U4-a /manifest.webmanifest serves an installable PWA manifest" as *u8, tu4_a, pass, fail)
3593 // T-U4-b: the service worker is served AT THE MOUNT with Service-Worker-Allowed, else its scope cannot
3594 // cover the app it is meant to make offline-capable.
3595 n = of_handle(root, base, "GET /sw.js HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 44, out, 1048576)
3596 var tu4_b: i64 = 0
3597 if of_memhas(out, n, "200 OK" as *u8) == 1 { if of_memhas(out, n, "Service-Worker-Allowed" as *u8) == 1 { tu4_b = 1 } }
3598 of_ck("T-U4-b /sw.js serves the worker with Service-Worker-Allowed" as *u8, tu4_b, pass, fail)
3599 // T-U4-c: the worker must NEVER cache document content -- a never-lose-versions app showing a stale doc
3600 // would be the one lie its whole design forbids. Assert the exclusion is actually in the shipped worker.
3601 let swb: *u8 = sys_mmap(65536)
3602 let swl: i64 = of_read_asset("office_sw.js" as *u8, swb, 65535)
3603 var tu4_c: i64 = 0
3604 if swl > 0 { if of_memhas(swb, swl, "/doc/" as *u8) == 1 { if of_memhas(swb, swl, ".method !== 'GET'" as *u8) == 1 { tu4_c = 1 } } }
3605 of_ck("T-U4-c the worker EXCLUDES /doc/ content and never touches a write" as *u8, tu4_c, pass, fail)
3606 // T-U4-d: shell head advertises the manifest + theme colour, and the skeleton style exists.
3607 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 39, out, 1048576)
3608 var tu4_d: i64 = 0
3609 if of_memhas(out, n, "rel='manifest'" as *u8) == 1 { if of_memhas(out, n, "theme-color" as *u8) == 1 { if of_memhas(out, n, ".skel{" as *u8) == 1 { tu4_d = 1 } } }
3610 of_ck("T-U4-d shell advertises the manifest + theme-color and ships skeleton styles" as *u8, tu4_d, pass, fail)
3611 // ---- U3 LIBRARY ORGANISATION: starred + folders + shared-with-me ----
3612 // T-U3-a: star toggles ON, is visible in the library under ?filter=starred, and toggles back OFF.
3613 bo = of_cat(bod, 0, "name=family-letter" as *u8); bod[bo] = 0 as u8
3614 ro = of_cat(req, 0, "POST /office/star HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3615 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3616 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3617 var tu3_a: i64 = 0
3618 if of_starred(root, "family-letter" as *u8) == 1 {
3619 n = of_handle(root, base, "GET /?filter=starred HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 53, out, 1048576)
3620 if of_memhas(out, n, "family-letter" as *u8) == 1 { tu3_a = 1 }
3621 }
3622 of_ck("T-U3-a star ON and the starred filter shows the file" as *u8, tu3_a, pass, fail)
3623 // T-U3-b: the starred filter must EXCLUDE an unstarred file -- a filter that shows everything is not a filter.
3624 var tu3_b: i64 = 0
3625 if of_memhas(out, n, "family-budget" as *u8) == 0 { tu3_b = 1 }
3626 of_ck("T-U3-b starred filter EXCLUDES unstarred files (non-vacuous)" as *u8, tu3_b, pass, fail)
3627 // T-U3-c: folder set, then the folder filter selects it and rejects a different folder.
3628 bo = of_cat(bod, 0, "name=family-letter&folder=reunion" as *u8); bod[bo] = 0 as u8
3629 ro = of_cat(req, 0, "POST /office/folder HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3630 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3631 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3632 let fchk: *u8 = sys_mmap(64)
3633 of_folder_get(root, "family-letter" as *u8, fchk, 64)
3634 var tu3_c: i64 = 0
3635 if of_seq(fchk, "reunion" as *u8) == 1 {
3636 n = of_handle(root, base, "GET /?folder=reunion HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 53, out, 1048576)
3637 if of_memhas(out, n, "family-letter" as *u8) == 1 { if of_memhas(out, n, "family-budget" as *u8) == 0 { tu3_c = 1 } }
3638 }
3639 of_ck("T-U3-c folder set + folder filter selects only that folder" as *u8, tu3_c, pass, fail)
3640 // T-U3-d: a folder label carrying separators or markup is REFUSED (it becomes a URL filter value).
3641 bo = of_cat(bod, 0, "name=family-letter&folder=a/b" as *u8); bod[bo] = 0 as u8
3642 ro = of_cat(req, 0, "POST /office/folder HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3643 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3644 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3645 of_ck("T-U3-d a folder label with a separator is LOUDLY refused" as *u8, of_memhas(out, n, "400" as *u8), pass, fail)
3646 // T-U3-e: the doc page offers both controls.
3647 n = of_handle(root, base, "GET /doc/family-letter HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 56, out, 1048576)
3648 var tu3_e: i64 = 0
3649 if of_memhas(out, n, "Organise" as *u8) == 1 { if of_memhas(out, n, "/star'" as *u8) == 1 { if of_memhas(out, n, "/folder'" as *u8) == 1 { tu3_e = 1 } } }
3650 of_ck("T-U3-e doc page offers star + folder controls" as *u8, tu3_e, pass, fail)
3651 // ---- TEMPLATES GALLERY (U3): real starter content, not an empty page ----
3652 // T-TM-a: the home page offers the gallery and its templates carry WORKING content, not lorem text -- the
3653 // budget must ship a live =SUM and a #CF rule, else it demonstrates nothing about the engine underneath.
3654 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
3655 var ttm_a: i64 = 0
3656 if of_memhas(out, n, "<h2>Templates</h2>" as *u8) == 1 {
3657 if of_memhas(out, n, "Meeting agenda" as *u8) == 1 {
3658 if of_memhas(out, n, "Monthly budget" as *u8) == 1 {
3659 if of_memhas(out, n, "=SUM(B2:B3)" as *u8) == 1 { if of_memhas(out, n, "#CF B2:B3 greaterThan 300" as *u8) == 1 { ttm_a = 1 } }
3660 }
3661 }
3662 }
3663 of_ck("T-TM-a home offers Templates and the budget carries a REAL formula + CF rule" as *u8, ttm_a, pass, fail)
3664 // T-TM-b: a template POSTs to the SAME /save contract, so it becomes an ORDINARY versioned file.
3665 bo = of_cat(bod, 0, "name=tmpl-check&kind=doc&spec=H+Letter%0AP+Dear+friend%2C" as *u8); bod[bo] = 0 as u8
3666 ro = of_cat(req, 0, "POST /office/save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3667 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3668 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3669 let tmk: *u8 = sys_mmap(64)
3670 let tmv: i64 = of_manifest_count(root, "tmpl-check" as *u8, tmk, 64)
3671 var ttm_b: i64 = 0
3672 if of_memhas(out, n, "303" as *u8) == 1 { if tmv == 1 { ttm_b = 1 } }
3673 of_ck("T-TM-b a template lands as an ORDINARY v1 file (same /save contract)" as *u8, ttm_b, pass, fail)
3674 // ---- OF-A2 (sheet insight) + OF-A3 (deck slide): the AI reaches EVERY kind, in that kind's own grammar ----
3675 // T-AI-c: the SHEET page offers the insight card (not the doc wording) -- proves the kind branch renders.
3676 n = of_handle(root, base, "GET /doc/family-budget HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 56, out, 1048576)
3677 var tai_c: i64 = 0
3678 if of_memhas(out, n, "Add an AI insight" as *u8) == 1 { if of_memhas(out, n, "Continue with AI" as *u8) == 0 { tai_c = 1 } }
3679 of_ck("T-AI-c SHEET page offers the AI-insight card (and NOT the doc wording)" as *u8, tai_c, pass, fail)
3680 // T-AI-d: the DECK page offers the slide card.
3681 n = of_handle(root, base, "GET /doc/reunion-deck HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 55, out, 1048576)
3682 var tai_d: i64 = 0
3683 if of_memhas(out, n, "Draft the next slide" as *u8) == 1 { if of_memhas(out, n, "Add an AI insight" as *u8) == 0 { tai_d = 1 } }
3684 of_ck("T-AI-d DECK page offers the AI-slide card (and NOT the sheet wording)" as *u8, tai_d, pass, fail)
3685 // T-AI-e: POST /ai on a SHEET is now a REAL route (no longer the old doc-only 400) and degrades gracefully.
3686 let aik0: *u8 = sys_mmap(64)
3687 let aic0: i64 = of_manifest_count(root, "family-budget" as *u8, aik0, 64)
3688 bo = of_cat(bod, 0, "name=family-budget" as *u8); bod[bo] = 0 as u8
3689 ro = of_cat(req, 0, "POST /office/ai HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3690 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3691 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3692 let aik1: *u8 = sys_mmap(64)
3693 let aic1: i64 = of_manifest_count(root, "family-budget" as *u8, aik1, 64)
3694 var tai_e: i64 = 0
3695 if of_memhas(out, n, "503" as *u8) == 1 { if of_memhas(out, n, "400" as *u8) == 0 { if aic1 == aic0 { tai_e = 1 } } }
3696 of_ck("T-AI-e POST /ai on a SHEET -> 503 not 400 (kind is wired), NO version created" as *u8, tai_e, pass, fail)
3697 // ---- OF-A4 AGENT MODE (offline gate) -- the state machine + plan parser are fully provable with the seat
3698 // DOWN, so these teeth run everywhere. Only the model's WORDS need a live seat; the agency does not.
3699 // T-AG-a: the doc page offers agent mode with a goal input.
3700 n = of_handle(root, base, "GET /doc/family-letter HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 56, out, 1048576)
3701 var tag_a: i64 = 0
3702 if of_memhas(out, n, "Agent mode" as *u8) == 1 { if of_memhas(out, n, "/agent'><input type='hidden' name='name' value='family-letter'" as *u8) == 1 { tag_a = 1 } }
3703 of_ck("T-AG-a doc page offers agent mode with a goal input" as *u8, tag_a, pass, fail)
3704 // T-AG-b: POST /agent with a goal + seat DOWN -> graceful 503, NO version, NO agent state written.
3705 let agk0: *u8 = sys_mmap(64)
3706 let agc0: i64 = of_manifest_count(root, "family-letter" as *u8, agk0, 64)
3707 bo = of_cat(bod, 0, "name=family-letter&goal=add+a+closing" as *u8); bod[bo] = 0 as u8
3708 ro = of_cat(req, 0, "POST /office/agent HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3709 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3710 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3711 let agk1: *u8 = sys_mmap(64)
3712 let agc1: i64 = of_manifest_count(root, "family-letter" as *u8, agk1, 64)
3713 let agchk: *u8 = sys_mmap(8192)
3714 let agchkn: i64 = of_agent_read(root, "family-letter" as *u8, agchk, 8000)
3715 var tag_b: i64 = 0
3716 if of_memhas(out, n, "503" as *u8) == 1 { if agc1 == agc0 { if agchkn <= 0 { tag_b = 1 } } }
3717 of_ck("T-AG-b POST /agent seat DOWN -> 503, NO version, NO agent state (retry-safe)" as *u8, tag_b, pass, fail)
3718 // T-AG-c: no goal and no plan yet -> LOUD 400, never a silent no-op.
3719 bo = of_cat(bod, 0, "name=family-letter" as *u8); bod[bo] = 0 as u8
3720 ro = of_cat(req, 0, "POST /office/agent HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3721 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3722 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3723 of_ck("T-AG-c POST /agent with no goal -> LOUD 400" as *u8, of_memhas(out, n, "400" as *u8), pass, fail)
3724 // T-AG-d: agent mode is doc-only -> a SHEET is refused loudly (the kind guard actually bites).
3725 bo = of_cat(bod, 0, "name=family-budget&goal=summarise" as *u8); bod[bo] = 0 as u8
3726 ro = of_cat(req, 0, "POST /office/agent HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3727 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3728 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3729 of_ck("T-AG-d POST /agent on a SHEET -> LOUD 400 (doc-kind guard bites)" as *u8, of_memhas(out, n, "400" as *u8), pass, fail)
3730 // T-AG-e: the plan parser turns a real multi-line model reply into ordered steps, list punctuation stripped.
3731 let agpl: *u8 = sys_mmap(4096)
3732 let agsrc: *u8 = "1. Draft the summer plans section\n2) Add a warm closing paragraph\n- Check the tone\n" as *u8
3733 let agns: i64 = of_agent_plan_parse(agsrc, of_slen(agsrc), agpl, 4000)
3734 var tag_e: i64 = 0
3735 if agns == 3 { if of_memhas(agpl, of_slen(agpl), "S Draft the summer plans section" as *u8) == 1 { if of_memhas(agpl, of_slen(agpl), "S Add a warm closing paragraph" as *u8) == 1 { tag_e = 1 } } }
3736 of_ck("T-AG-e plan parser -> 3 ordered steps, list punctuation stripped" as *u8, tag_e, pass, fail)
3737 // T-AG-f: a SINGLE-LINE reply still becomes a real plan (sentence-split fallback), not a 1-step degenerate.
3738 let agpl2: *u8 = sys_mmap(4096)
3739 let agsrc2: *u8 = "Write the intro. Then add the plans. Finally close it." as *u8
3740 let agns2: i64 = of_agent_plan_parse(agsrc2, of_slen(agsrc2), agpl2, 4000)
3741 var tag_f: i64 = 0
3742 if agns2 >= 3 { tag_f = 1 }
3743 of_ck("T-AG-f single-line reply -> sentence-split into a multi-step plan" as *u8, tag_f, pass, fail)
3744 // T-AG-g: garbage in -> NO plan (the parser refuses rather than inventing a step) = the liar-kill tooth.
3745 let agpl3: *u8 = sys_mmap(4096)
3746 let agns3: i64 = of_agent_plan_parse("..\n-\n" as *u8, 5, agpl3, 4000)
3747 var tag_g: i64 = 0
3748 if agns3 == 0 { tag_g = 1 }
3749 of_ck("T-AG-g unusable model reply -> 0 steps (refuses, never invents)" as *u8, tag_g, pass, fail)
3750 // T-AG-h: state accessors round-trip (goal, ordered steps, done cursor) through the sidecar format.
3751 let agst: *u8 = "G ship it\nS one\nS two\nD 1\n" as *u8
3752 let agstn: i64 = of_slen(agst)
3753 let agtmp: *u8 = sys_mmap(256)
3754 var tag_h: i64 = 0
3755 if of_agent_tagcount(agst, agstn, 83) == 2 {
3756 if of_agent_done(agst, agstn) == 1 {
3757 of_agent_tagline(agst, agstn, 83, 1, agtmp, 256)
3758 if of_seq(agtmp, "two" as *u8) == 1 { tag_h = 1 }
3759 }
3760 }
3761 of_ck("T-AG-h agent state round-trips (2 steps, cursor=1, step[1]='two')" as *u8, tag_h, pass, fail)
3762 // under the gate (g_of_gv armed) the caller's gv_verdict is the ONE tally and the LAST line -- two verdict
3763 // lines would be two rulers, and the referee anchors on the last one.
3764 if g_of_gv != 0 { if fail[0] == 0 { return 0 } return 1 }
3765 p("NX-OFFICE SELFTEST pass=" as *u8); pn(pass[0]); p(" fail=" as *u8); pn(fail[0])
3766 if fail[0] == 0 { p(" verdict=GREEN (the office round-trips: create/edit/version/preview/download, additive by construction)\n" as *u8); return 0 }
3767 p(" verdict=RED\n" as *u8)
3768 return 1
3769}