nx_office_serve.nx source
↩ module page · 3109 lines · 197925 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_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
17import "nx_itoa_lib.nx" // shared integer emitter: nxi_out (fd) and nxi_buf (NUL-free buffer form)
18import "nx_rebac.nx" // the shared ReBAC plane: doc ownership + sharing are rb_ tuples (doc:<name> owner|viewer|editor)
19import "nx_http_client.nx" // loopback POST to our own sovereign LLM seat (:11434) for in-app AI drafting
20
21// office authz store. The office daemon runs as ELDERWESTO (its reconcile cron), NOT root -- so the store must be
22// in the elderwesto-writable cwd (nishihost/officeauthz_*), NOT the root-owned knowledge/status/ (which relate,
23// running as root, created). Tuples live OUTSIDE office/ so they never render as documents. A doc with NO owner
24// tuple stays PUBLIC (legacy/demo -> non-breaking).
25const OF_AUTHZ: *u8 = "officeauthz_"
26const OF_RELATE: *u8 = "knowledge/status/relate_"
27
28func p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
29// MIGRATED to the shared emitter (debt 1785557603): the old body mmapped TWO buffers per call
30// (LSB-first digits + a reverse buffer) and freed neither. nxi_out is the ONE shim, always balanced.
31func pn(v: i64) -> i64 { nxi_out(v); return 0 }
32func of_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
33func 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 }
34func of_catc(dst: *u8, off: i64, code: i64) -> i64 { dst[off] = code as u8; return off + 1 }
35// MIGRATED to nxi_buf, the NUL-FREE shared form. The old body mmapped a reverse buffer per call and
36// never freed it -- and this function has 60 CALL SITES, so the leak was per-call in a long-lived
37// server. nxi_buf is MSB-first (allocates nothing) and, unlike ccz_cat_num, writes NO byte past the
38// returned offset -- gate tooth T15 proves that difference by biting.
39func of_catn(dst: *u8, off: i64, v: i64) -> i64 { return nxi_buf(dst, off, v) }
40func of_seq(a: *u8, b: *u8) -> i64 {
41 var i: i64 = 0
42 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
43 if b[i] != (0 as u8) { return 0 }
44 return 1
45}
46func 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 }
47func of_memhas(buf: *u8, n: i64, needle: *u8) -> i64 {
48 let nl: i64 = of_slen(needle)
49 if nl == 0 { return 0 }
50 var i: i64 = 0
51 while i + nl <= n {
52 var k: i64 = 0; var hit: i64 = 1
53 while k < nl { if buf[i+k] != needle[k] { hit = 0; k = nl } else { k = k + 1 } }
54 if hit == 1 { return 1 }
55 i = i + 1
56 }
57 return 0
58}
59// escape & < > while appending a NUL-terminated string (safe for html text and textarea content)
60func of_esc(dst: *u8, off: i64, s: *u8) -> i64 {
61 var o: i64 = off; var i: i64 = 0
62 while s[i] != (0 as u8) {
63 let c: i64 = s[i] as i64
64 if c == 38 { o = of_cat(dst, o, "&" as *u8) } else {
65 if c == 60 { o = of_cat(dst, o, "<" as *u8) } else {
66 if c == 62 { o = of_cat(dst, o, ">" as *u8) } else { dst[o] = s[i]; o = o + 1 } } }
67 i = i + 1
68 }
69 return o
70}
71func of_hexval(c: i64) -> i64 {
72 if c >= 48 { if c <= 57 { return c - 48 } }
73 if c >= 65 { if c <= 70 { return c - 55 } }
74 if c >= 97 { if c <= 102 { return c - 87 } }
75 return 0
76}
77// urldecode form value for key from body (handles + and %XX). proven pattern (nx_relate_serve).
78func of_form_get(body: *u8, blen: i64, key: *u8, out: *u8, cap: i64) -> i64 {
79 let kl: i64 = of_slen(key)
80 var i: i64 = 0
81 while i < blen {
82 var atk: i64 = 0
83 if i == 0 { atk = 1 } else { if body[i-1] == (38 as u8) { atk = 1 } }
84 if atk == 1 {
85 var m: i64 = 1; var j: i64 = 0
86 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 } } }
87 if m == 1 { if i + kl < blen { if body[i+kl] == (61 as u8) {
88 var q: i64 = i + kl + 1; var t: i64 = 0
89 var go: i64 = 1
90 while go == 1 {
91 if q >= blen { go = 0 } else {
92 let c: i64 = body[q] as i64
93 if c == 38 { go = 0 } else {
94 var ch: i64 = c
95 if c == 43 { ch = 32 }
96 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 } }
97 if t < cap - 1 { out[t] = ch as u8; t = t + 1 }
98 q = q + 1
99 }
100 }
101 }
102 out[t] = 0 as u8; return t
103 } } }
104 }
105 i = i + 1
106 }
107 out[0] = 0 as u8; return 0
108}
109func of_write_all(fd: i64, buf: *u8, n: i64) -> i64 {
110 var w: i64 = 0
111 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 }
112 return 0
113}
114// read ONE full HTTP request: headers until CRLFCRLF plus Content-Length body. proven pattern.
115func of_read_req(fd: i64, buf: *u8, cap: i64) -> i64 {
116 var n: i64 = 0
117 var hdr_end: i64 = 0 - 1
118 var want: i64 = 0 - 1
119 var go: i64 = 1
120 while go == 1 {
121 if n >= cap - 1 { go = 0 } else {
122 let r: i64 = sys_read(fd, (buf as i64 + n) as *u8, cap - 1 - n)
123 if r <= 0 { go = 0 } else {
124 n = n + r
125 if hdr_end < 0 {
126 var i: i64 = 0
127 while i + 3 < n {
128 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 } } } }
129 i = i + 1
130 }
131 if hdr_end >= 0 {
132 var cl: i64 = 0 - 1
133 let key: *u8 = "Content-Length:" as *u8
134 let kl: i64 = 15
135 var j: i64 = 0
136 while j + kl < hdr_end {
137 var m: i64 = 1
138 var q: i64 = 0
139 while q < kl { if buf[j+q] != key[q] { m = 0; q = kl } else { q = q + 1 } }
140 if m == 1 {
141 var v: i64 = 0
142 var t: i64 = j + kl
143 while t < hdr_end {
144 let c: i64 = buf[t] as i64
145 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } }
146 if c == 13 { t = hdr_end }
147 t = t + 1
148 }
149 cl = v
150 j = hdr_end
151 }
152 j = j + 1
153 }
154 if cl < 0 { want = hdr_end } else { want = hdr_end + cl }
155 }
156 }
157 if want >= 0 { if n >= want { go = 0 } }
158 }
159 }
160 }
161 return n
162}
163func of_read_file(path: *u8, buf: *u8, cap: i64) -> i64 {
164 let fd: i64 = sys_openat_rd(path)
165 if fd < 0 { return 0 - 1 }
166 var tot: i64 = 0
167 while tot < cap { let r: i64 = sys_read(fd, (buf as i64 + tot) as *u8, cap - tot); if r <= 0 { break } tot = tot + r }
168 sys_close(fd)
169 return tot
170}
171func of_write_file(path: *u8, buf: *u8, n: i64) -> i64 {
172 let fd: i64 = sys_openat_wr(path, 420)
173 if fd < 0 { return 0 - 1 }
174 let rc: i64 = of_write_all(fd, buf, n)
175 sys_close(fd)
176 return rc
177}
178// extract a header value (key like "Origin:") from the header region; trims one leading space; stops at CR.
179func of_hdr_get(req: *u8, reqlen: i64, key: *u8, out: *u8, cap: i64) -> i64 {
180 out[0] = 0 as u8
181 var he: i64 = reqlen
182 var i: i64 = 0
183 while i + 3 < reqlen {
184 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 } } } }
185 i = i + 1
186 }
187 let kl: i64 = of_slen(key)
188 var j: i64 = 0
189 while j + kl < he {
190 var m: i64 = 1
191 var q: i64 = 0
192 while q < kl { if req[j+q] != key[q] { m = 0; q = kl } else { q = q + 1 } }
193 if m == 1 {
194 var t: i64 = j + kl
195 if req[t] == (32 as u8) { t = t + 1 }
196 var o: i64 = 0
197 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 } }
198 out[o] = 0 as u8
199 return o
200 }
201 j = j + 1
202 }
203 return 0
204}
205func of_atoi(s: *u8) -> i64 {
206 var v: i64 = 0
207 var i: i64 = 0
208 while s[i] != (0 as u8) {
209 let d: i64 = (s[i] as i64) - 48
210 if d >= 0 { if d <= 9 { v = v * 10 + d } }
211 i = i + 1
212 }
213 return v
214}
215
216// ---- domain: names, kinds, layout ----
217func of_name_ok(name: *u8) -> i64 {
218 var i: i64 = 0
219 while name[i] != (0 as u8) {
220 let c: i64 = name[i] as i64
221 var ok: i64 = 0
222 if c >= 97 { if c <= 122 { ok = 1 } }
223 if c >= 48 { if c <= 57 { ok = 1 } }
224 if c == 45 { ok = 1 }
225 if ok == 0 { return 0 }
226 i = i + 1
227 }
228 if i < 1 { return 0 }
229 if i > 40 { return 0 }
230 return 1
231}
232func of_kind_idx(kind: *u8) -> i64 {
233 if of_seq(kind, "doc" as *u8) == 1 { return 0 }
234 if of_seq(kind, "sheet" as *u8) == 1 { return 1 }
235 if of_seq(kind, "deck" as *u8) == 1 { return 2 }
236 return 0 - 1
237}
238func of_ext(k: i64) -> *u8 {
239 if k == 0 { return "docx" as *u8 }
240 if k == 1 { return "xlsx" as *u8 }
241 return "pptx" as *u8
242}
243func of_elf(k: i64) -> *u8 {
244 if k == 0 { return "_offc/nx_docx.elf" as *u8 }
245 if k == 1 { return "_offc/nx_xlsx.elf" as *u8 }
246 return "_offc/nx_pptx.elf" as *u8
247}
248func of_ct(k: i64) -> *u8 {
249 if k == 0 { return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" as *u8 }
250 if k == 1 { return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" as *u8 }
251 return "application/vnd.openxmlformats-officedocument.presentationml.presentation" as *u8
252}
253func of_kind_name(k: i64) -> *u8 {
254 if k == 0 { return "doc" as *u8 }
255 if k == 1 { return "sheet" as *u8 }
256 return "deck" as *u8
257}
258// versions so far for <name> (0 = does not exist); kind of the file copied into kindout.
259func of_manifest_count(root: *u8, name: *u8, kindout: *u8, kcap: i64) -> i64 {
260 kindout[0] = 0 as u8
261 let mp: *u8 = sys_mmap(512)
262 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
263 let buf: *u8 = sys_mmap(65536)
264 let n: i64 = of_read_file(mp, buf, 65536)
265 if n <= 0 { return 0 }
266 var lines: i64 = 0
267 var i: i64 = 0
268 while i < n { if buf[i] == (10 as u8) { lines = lines + 1 } i = i + 1 }
269 // kind = field 2 of the FIRST line (v<N> \t kind \t usec)
270 var t: i64 = 0
271 while t < n { if buf[t] == (9 as u8) { break } t = t + 1 }
272 t = t + 1
273 var ko: i64 = 0
274 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 } } }
275 kindout[ko] = 0 as u8
276 return lines
277}
278// build "<root>/<name>/v<N>" into out, return offset
279func of_vdir(root: *u8, name: *u8, vn: i64, out: *u8) -> i64 {
280 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)
281 out[o] = 0 as u8
282 return o
283}
284// append one line to an append-only file (creates if missing)
285func of_append_line(path: *u8, line: *u8, n: i64) -> i64 {
286 let fd: i64 = sys_openat_append(path, 420)
287 if fd < 0 { return 0 - 1 }
288 let rc: i64 = of_write_all(fd, line, n)
289 sys_close(fd)
290 return rc
291}
292// SAVE: validate -> new version dir -> spec -> fork the format organ (artifact) -> fork html (preview) ->
293// register in manifest (+ index on v1). auto=1 (background autosave) tags the manifest line with an ADDITIVE
294// 4th field "auto" -- older parsers read fields 1-3 unchanged. Returns the new version N, or a LOUD negative:
295// -1 invalid name/kind/spec -2 kind mismatch with existing file -3 organ build failed -4 preview failed
296func of_save(root: *u8, base: *u8, name: *u8, kind: *u8, spec: *u8, sl: i64, auto: i64) -> i64 {
297 if of_name_ok(name) == 0 { return 0 - 1 }
298 let k: i64 = of_kind_idx(kind)
299 if k < 0 { return 0 - 1 }
300 if sl <= 0 { return 0 - 1 }
301 if sl > 131072 { return 0 - 1 }
302 sys_mkdir(root, 493)
303 let nd: *u8 = sys_mmap(512)
304 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
305 sys_mkdir(nd, 493)
306 let kbuf: *u8 = sys_mmap(64)
307 let cur: i64 = of_manifest_count(root, name, kbuf, 64)
308 if cur > 0 { if of_seq(kbuf, kind) == 0 { return 0 - 2 } }
309 let vn: i64 = cur + 1
310 let vd: *u8 = sys_mmap(512)
311 of_vdir(root, name, vn, vd)
312 sys_mkdir(vd, 493)
313 let specp: *u8 = sys_mmap(600)
314 var so: i64 = of_cat(specp, 0, vd); so = of_cat(specp, so, "/spec.txt" as *u8); specp[so] = 0 as u8
315 if of_write_file(specp, spec, sl) != 0 { return 0 - 3 }
316 let artp: *u8 = sys_mmap(600)
317 let ext: *u8 = of_ext(k)
318 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
319 let prevp: *u8 = sys_mmap(600)
320 var po: i64 = of_cat(prevp, 0, vd); po = of_cat(prevp, po, "/preview.html" as *u8); prevp[po] = 0 as u8
321 let dlu: *u8 = sys_mmap(600)
322 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
323 let elf: *u8 = of_elf(k)
324 let av: *i64 = sys_mmap(8 * 8) as *i64
325 av[0] = elf as i64
326 if k == 0 { av[1] = "writerich" as *u8 as i64; av[2] = artp as i64; av[3] = specp as i64 } else {
327 if k == 1 { av[1] = "fromtsv" as *u8 as i64; av[2] = specp as i64; av[3] = artp as i64 } else {
328 av[1] = "fromspec" as *u8 as i64; av[2] = specp as i64; av[3] = artp as i64 } }
329 av[4] = 0
330 let capbuf: *u8 = sys_mmap(65536)
331 let ol: *i64 = sys_mmap(16) as *i64
332 let rc: i64 = tr_run_capture(elf, av, capbuf, 65536, ol)
333 if rc != 0 { return 0 - 3 }
334 let av2: *i64 = sys_mmap(8 * 8) as *i64
335 av2[0] = elf as i64
336 av2[1] = "html" as *u8 as i64
337 av2[2] = artp as i64
338 av2[3] = prevp as i64
339 av2[4] = dlu as i64
340 av2[5] = 0
341 let rc2: i64 = tr_run_capture(elf, av2, capbuf, 65536, ol)
342 if rc2 != 0 { return 0 - 4 }
343 let mp: *u8 = sys_mmap(600)
344 var mo: i64 = of_cat(mp, 0, nd); mo = of_cat(mp, mo, "/manifest.txt" as *u8); mp[mo] = 0 as u8
345 let line: *u8 = sys_mmap(256)
346 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())
347 if auto == 1 { lo = of_catc(line, lo, 9); lo = of_cat(line, lo, "auto" as *u8) }
348 lo = of_catc(line, lo, 10)
349 if of_append_line(mp, line, lo) != 0 { return 0 - 3 }
350 if vn == 1 {
351 let ip: *u8 = sys_mmap(600)
352 var io: i64 = of_cat(ip, 0, root); io = of_cat(ip, io, "/index.txt" as *u8); ip[io] = 0 as u8
353 let il: *u8 = sys_mmap(256)
354 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)
355 of_append_line(ip, il, ilo)
356 }
357 return vn
358}
359
360// ---- pages (zero-JS, sovereign styling, no hash-colors) ----
361func of_css(out: *u8, off: i64) -> i64 {
362 // CSS custom properties drive light/dark so the JS theme toggle is one class flip (:root.dark / :root.light);
363 // system preference wins unless the user chose. U-axes rung: app shell, card grid, thumbnails, transitions.
364 var o: i64 = off
365 // canonical --nx-color tokens (fleet bar / ui_rubric) with local shorthand ALIASES so every existing
366 // var(--bg)-style usage keeps working; dark redefines only the canon and the aliases follow.
367 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)
368 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)
369 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)
370 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)
371 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)
372 // fleet-bar accessibility + motion: skip-link, visible keyboard focus, entrance rise (stagger via
373 // nth-child), and a reduced-motion kill-switch.
374 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)
375 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)
376 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)
377 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)
378 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)
379 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)
380 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)
381 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)
382 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)
383 o = of_cat(out, o, ".wrap{max-width:1200px;margin:0 auto;padding:16px 20px 44px}\n" as *u8)
384 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)
385 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)
386 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)
387 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)
388 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)
389 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)
390 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)
391 // ---- home: create tiles, files header (chips + sort), card grid with REAL thumbnails, empty states
392 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)
393 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)
394 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)
395 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)
396 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)
397 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)
398 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)
399 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)
400 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)
401 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)
402 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)
403 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)
404 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)
405 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)
406 // ---- editor page: crumb, saved stamp, find highlights
407 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)
408 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)
409 // ---- visual editor (WYSIWYG surfaces; hidden until app.js flips html.js -> progressive enhancement)
410 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)
411 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)
412 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)
413 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)
414 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)
415 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)
416 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)
417 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)
418 // wide tables never sideways-scroll the page on a phone -- they scroll inside their own wrapper
419 o = of_cat(out, o, ".tablewrap{overflow-x:auto}
420/* U4 loading skeletons: a shimmer placeholder honestly says work-in-progress, where a blank pane reads as broken.
421 Held to prefers-reduced-motion like every other animation here. */
422.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}
423.skel *{visibility:hidden}
424@keyframes shim{0%{background-position:100% 50%}100%{background-position:0 50%}}
425@media(prefers-reduced-motion:reduce){.skel{animation:none}}
426.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n" as *u8)
427 // ---- version diff (sibling lane; rgba overlays read on BOTH themes so no dark block needed)
428 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)
429 // ---- responsive: the shell collapses gracefully on phones
430 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)
431 o = of_cat(out, o, "</style>" as *u8)
432 return o
433}
434// escape src[a,b) (XML & < >) while appending -> for emitting substrings without a NUL terminator
435func of_esc_n(out: *u8, off: i64, src: *u8, a: i64, b: i64) -> i64 {
436 var o: i64 = off
437 var i: i64 = a
438 while i < b {
439 let c: i64 = src[i] as i64
440 if c == 38 { o = of_cat(out, o, "&" as *u8) } else {
441 if c == 60 { o = of_cat(out, o, "<" as *u8) } else {
442 if c == 62 { o = of_cat(out, o, ">" as *u8) } else { out[o] = src[i]; o = o + 1 } } }
443 i = i + 1
444 }
445 return o
446}
447// render a doc spec (H/B/I/P/T lines) as an editable block tree (#ed). Consecutive T lines = one table.
448func of_render_doc(out: *u8, off: i64, spec: *u8, sl: i64) -> i64 {
449 var o: i64 = of_cat(out, off, "<div id='ed' class='visual doc' contenteditable='true'>" as *u8)
450 var i: i64 = 0
451 var intable: i64 = 0
452 while i < sl {
453 var e: i64 = i
454 while e < sl { if spec[e] == (10 as u8) { break } e = e + 1 }
455 let c0: i64 = spec[i] as i64
456 var cs: i64 = i
457 if e >= i + 2 { if spec[i+1] == (32 as u8) { cs = i + 2 } }
458 if c0 == 84 { // 'T' table row
459 if intable == 0 { o = of_cat(out, o, "<table class='edt'><tbody>" as *u8); intable = 1 }
460 o = of_cat(out, o, "<tr>" as *u8)
461 var cstart: i64 = cs
462 var k: i64 = cs
463 while k <= e {
464 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 }
465 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 } }
466 }
467 o = of_cat(out, o, "</tr>" as *u8)
468 } else {
469 if intable == 1 { o = of_cat(out, o, "</tbody></table>" as *u8); intable = 0 }
470 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) }
471 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) }
472 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) }
473 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) } } }
474 }
475 i = e + 1
476 }
477 if intable == 1 { o = of_cat(out, o, "</tbody></table>" as *u8) }
478 o = of_cat(out, o, "</div>" as *u8)
479 return o
480}
481// render a sheet spec (TSV) as an editable grid (#grid).
482func of_render_sheet(out: *u8, off: i64, spec: *u8, sl: i64) -> i64 {
483 var o: i64 = of_cat(out, off, "<table id='grid' class='visual sheet'><tbody>" as *u8)
484 var i: i64 = 0
485 while i < sl {
486 var e: i64 = i
487 while e < sl { if spec[e] == (10 as u8) { break } e = e + 1 }
488 o = of_cat(out, o, "<tr>" as *u8)
489 var cstart: i64 = i
490 var k: i64 = i
491 while k <= e {
492 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 }
493 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 } }
494 }
495 o = of_cat(out, o, "</tr>" as *u8)
496 i = e + 1
497 }
498 o = of_cat(out, o, "</tbody></table>" as *u8)
499 return o
500}
501// render a deck spec (S title / B bullet) as editable slide cards (#deck).
502func of_render_deck(out: *u8, off: i64, spec: *u8, sl: i64) -> i64 {
503 var o: i64 = of_cat(out, off, "<div id='deck' class='visual deck'>" as *u8)
504 var i: i64 = 0
505 var inslide: i64 = 0
506 while i < sl {
507 var e: i64 = i
508 while e < sl { if spec[e] == (10 as u8) { break } e = e + 1 }
509 let c0: i64 = spec[i] as i64
510 var cs: i64 = i
511 if e >= i + 2 { if spec[i+1] == (32 as u8) { cs = i + 2 } }
512 if c0 == 83 { // 'S' new slide
513 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) }
514 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)
515 inslide = 1
516 } else { if c0 == 66 { // 'B' bullet
517 if inslide == 0 { o = of_cat(out, o, "<div class='slide'><h3 contenteditable='true'>Slide</h3><ul>" as *u8); inslide = 1 }
518 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)
519 } }
520 i = e + 1
521 }
522 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) }
523 o = of_cat(out, o, "</div>" as *u8)
524 return o
525}
526// kind-specific editing toolbar (buttons carry data-act -> app.js) + shared undo/redo/find controls.
527func of_toolbar(out: *u8, off: i64, ks: i64) -> i64 {
528 var o: i64 = of_cat(out, off, "<div class='toolbar'>" as *u8)
529 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) }
530 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) }
531 if ks == 2 { o = of_cat(out, o, "<button type='button' data-act='slide'>+ slide</button>" as *u8) }
532 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)
533 o = of_cat(out, o, "</div>" as *u8)
534 return o
535}
536// serve the client at /app.js (read from CWD; NishiLang literal traps -> JS MUST live in a file, never inlined).
537// Static client assets (office_app.js, office_sw.js) live beside the SERVICE root, but a gate runs
538// from buildroot/. A bare cwd-relative read therefore resolves for the daemon and 404s for the gate,
539// which is how five teeth (T3c, T12i, T13d, T-U4-b, T-U4-c) failed while the server itself was fine.
540// Resolve through an ORDERED ROOT LIST so the answer does not depend on where the process happened
541// to be launched -- the build-cwd-is-not-run-cwd law, and rule 17's configuration hierarchy applied
542// to a file path. A symlink would have hidden this; it is the consumer that has to resolve.
543// Returns bytes read, or <=0 if no root has the asset. Frees what it takes.
544func of_read_asset(name: *u8, buf: *u8, cap: i64) -> i64 {
545 var n: i64 = of_read_file(name, buf, cap)
546 if n > 0 { return n }
547 let p: *u8 = sys_mmap(1024)
548 var o: i64 = of_cat(p, 0, "../" as *u8)
549 o = of_cat(p, o, name)
550 p[o] = 0 as u8
551 n = of_read_file(p, buf, cap)
552 sys_munmap(p, 1024)
553 return n
554}
555
556func of_serve_js(out: *u8, cap: i64) -> i64 {
557 let fb: *u8 = sys_mmap(131072)
558 let fl: i64 = of_read_asset("office_app.js" as *u8, fb, 131071)
559 if fl <= 0 { return of_err(out, "404 Not Found" as *u8, "app.js missing" as *u8) }
560 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)
561 o = of_catn(out, o, fl)
562 o = of_cat(out, o, "\r\nCache-Control: max-age=300\r\n\r\n" as *u8)
563 var i: i64 = 0
564 while i < fl { if o + i < cap { out[o + i] = fb[i] } i = i + 1 }
565 return o + fl
566}
567// U4 OFFLINE/PWA. The service worker lives in a FILE for the same reason app.js does -- NishiLang literal
568// traps make inlining JS a hazard. It is served at /sw.js so its scope covers the whole office mount; a worker
569// served from a deeper path could not control the app it is meant to make offline-capable.
570func of_serve_sw(out: *u8, cap: i64) -> i64 {
571 let fb: *u8 = sys_mmap(65536)
572 let fl: i64 = of_read_asset("office_sw.js" as *u8, fb, 65535)
573 if fl <= 0 { return of_err(out, "404 Not Found" as *u8, "sw.js missing" as *u8) }
574 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK
575
576Content-Type: application/javascript; charset=utf-8
577
578Service-Worker-Allowed: /
579
580Content-Length: " as *u8)
581 o = of_catn(out, o, fl)
582 o = of_cat(out, o, "
583
584Cache-Control: max-age=60
585
586
587
588" as *u8)
589 var i: i64 = 0
590 while i < fl { if o + i < cap { out[o + i] = fb[i] } i = i + 1 }
591 return o + fl
592}
593// Web app manifest -- installable to a home screen, which is what "offline" means to a family on a phone.
594func of_serve_manifest(out: *u8, base: *u8, cap: i64) -> i64 {
595 let b: *u8 = sys_mmap(4096)
596 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)
597 m = of_cat(b, m, base)
598 m = of_cat(b, m, "/\"}" as *u8)
599 b[m] = 0 as u8
600 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK
601
602Content-Type: application/manifest+json
603
604Content-Length: " as *u8)
605 o = of_catn(out, o, m)
606 o = of_cat(out, o, "
607
608
609
610" as *u8)
611 o = of_cat(out, o, b)
612 return o
613}
614func of_page_top(out: *u8, off: i64, title: *u8) -> i64 {
615 var o: i64 = off
616 o = of_cat(out, o, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<" as *u8)
617 o = of_catc(out, o, 33)
618 o = of_cat(out, o, "DOCTYPE html>\n<html lang=" as *u8)
619 o = of_catc(out, o, 34)
620 o = of_cat(out, o, "en" as *u8)
621 o = of_catc(out, o, 34)
622 o = of_cat(out, o, "><head><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>" as *u8)
623 o = of_esc(out, o, title)
624 // favicon: inline SVG data URI, percent-encoded (no raw hash/bang -- nx_cc literal law)
625 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)
626 o = of_css(out, o)
627 o = of_cat(out, o, "</head><body>\n" as *u8)
628 return o
629}
630func of_page_foot(out: *u8, off: i64) -> i64 {
631 var o: i64 = off
632 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)
633 return o
634}
635// the app shell: sticky top bar with brand, live search (GET <base>/?q=) and a JS-only theme toggle.
636// q = the current search text (prefilled so the state is visible); pass an empty buffer elsewhere.
637func of_shell_top(out: *u8, off: i64, title: *u8, base: *u8, q: *u8) -> i64 {
638 var o: i64 = of_page_top(out, off, title)
639 // U4 PWA: installable + a theme colour so the OS chrome matches the app instead of flashing white.
640 // Emitted HERE, not in of_page_top: only the APP SHELL is installable. The bare share/error pages have no
641 // base mount and are not an app -- advertising a manifest from them would install a broken scope.
642 o = of_cat(out, o, "<meta name='theme-color' content='rgb(41,84,164)'><link rel='manifest' href='" as *u8)
643 o = of_cat(out, o, base)
644 o = of_cat(out, o, "/manifest.webmanifest'>" as *u8)
645 // skip-to-content for keyboard/screen-reader users (href='#main'; hash composed via catc)
646 o = of_cat(out, o, "<a class='skip-link' href='" as *u8)
647 o = of_catc(out, o, 35)
648 o = of_cat(out, o, "main'>Skip to content</a><header class='top'><nav><a class='bname' href='" as *u8)
649 o = of_cat(out, o, base)
650 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)
651 o = of_cat(out, o, base)
652 o = of_cat(out, o, "/'><input type='text' name='q' placeholder='Search files' value='" as *u8)
653 o = of_esc(out, o, q)
654 o = of_cat(out, o, "'></form><button type='button' class='thm' data-act='theme'>Theme</button></nav></header>\n" as *u8)
655 return o
656}
657// human "edited ago" from a usec timestamp (0 = unknown)
658func of_ago(out: *u8, off: i64, us: i64) -> i64 {
659 if us <= 0 { return of_cat(out, off, "—" as *u8) }
660 var d: i64 = (sys_now_us() - us) / 1000000
661 if d < 0 { d = 0 }
662 if d < 90 { return of_cat(out, off, "just now" as *u8) }
663 if d < 5400 { var o: i64 = of_catn(out, off, d / 60); return of_cat(out, o, "m ago" as *u8) }
664 if d < 129600 { var o2: i64 = of_catn(out, off, d / 3600); return of_cat(out, o2, "h ago" as *u8) }
665 var o3: i64 = of_catn(out, off, d / 86400)
666 return of_cat(out, o3, "d ago" as *u8)
667}
668// usec of the LATEST save = field 3 of the last non-empty manifest line (0 if missing) -> recency sort + stamps
669func of_manifest_last_us(root: *u8, name: *u8) -> i64 {
670 let mp: *u8 = sys_mmap(512)
671 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
672 let buf: *u8 = sys_mmap(65536)
673 let n: i64 = of_read_file(mp, buf, 65536)
674 if n <= 0 { return 0 }
675 var e: i64 = n
676 while e > 0 { if buf[e-1] == (10 as u8) { e = e - 1 } else { break } }
677 if e <= 0 { return 0 }
678 var s: i64 = e
679 while s > 0 { if buf[s-1] == (10 as u8) { break } s = s - 1 }
680 var tabs: i64 = 0
681 var i: i64 = s
682 while i < e { if buf[i] == (9 as u8) { tabs = tabs + 1; i = i + 1; if tabs == 2 { break } } else { i = i + 1 } }
683 if tabs < 2 { return 0 }
684 var v: i64 = 0
685 while i < e { let c: i64 = buf[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 }
686 return v
687}
688// 1 if the manifest line for v<N> carries the additive 4th field "auto" (a background autosave), else 0
689func of_manifest_is_auto(root: *u8, name: *u8, vn: i64) -> i64 {
690 let mp: *u8 = sys_mmap(512)
691 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
692 let buf: *u8 = sys_mmap(65536)
693 let n: i64 = of_read_file(mp, buf, 65536)
694 if n <= 0 { return 0 }
695 let pfx: *u8 = sys_mmap(32)
696 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
697 var i: i64 = 0
698 while i < n {
699 var m: i64 = 1
700 var k: i64 = 0
701 while pfx[k] != (0 as u8) {
702 if i + k >= n { m = 0; break }
703 if buf[i+k] != pfx[k] { m = 0; break }
704 k = k + 1
705 }
706 var e: i64 = i
707 while e < n { if buf[e] == (10 as u8) { break } e = e + 1 }
708 if m == 1 {
709 var tabs: i64 = 0
710 var j: i64 = i
711 while j < e {
712 if buf[j] == (9 as u8) {
713 tabs = tabs + 1
714 if tabs == 3 {
715 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 } } } } }
716 return 0
717 }
718 }
719 j = j + 1
720 }
721 return 0
722 }
723 i = e + 1
724 }
725 return 0
726}
727// server-rendered mini preview of the LATEST spec -> the home card thumbnail (real content, zero JS)
728func of_thumb(out: *u8, off: i64, root: *u8, name: *u8, ks: i64, vc: i64) -> i64 {
729 var o: i64 = of_cat(out, off, "<div class='thumb'>" as *u8)
730 let vd: *u8 = sys_mmap(512)
731 of_vdir(root, name, vc, vd)
732 let sp: *u8 = sys_mmap(600)
733 var so: i64 = of_cat(sp, 0, vd); so = of_cat(sp, so, "/spec.txt" as *u8); sp[so] = 0 as u8
734 let buf: *u8 = sys_mmap(600)
735 let sl: i64 = of_read_file(sp, buf, 520)
736 if sl <= 0 { return of_cat(out, o, "<div class='tdoc'>…</div></div>" as *u8) }
737 if ks == 0 {
738 o = of_cat(out, o, "<div class='tdoc'>" as *u8)
739 var i: i64 = 0
740 var lines: i64 = 0
741 while i < sl {
742 if lines >= 7 { break }
743 var e: i64 = i
744 while e < sl { if buf[e] == (10 as u8) { break } e = e + 1 }
745 let c0: i64 = buf[i] as i64
746 var cs: i64 = i
747 if e >= i + 2 { if buf[i+1] == (32 as u8) { cs = i + 2 } }
748 var ce: i64 = e
749 if ce > cs + 64 { ce = cs + 64 }
750 if c0 == 72 { o = of_cat(out, o, "<div class='th'>" as *u8) } else {
751 if c0 == 66 { o = of_cat(out, o, "<div class='tb'>" as *u8) } else {
752 if c0 == 73 { o = of_cat(out, o, "<div class='ti'>" as *u8) } else { o = of_cat(out, o, "<div>" as *u8) } } }
753 o = of_esc_n(out, o, buf, cs, ce)
754 o = of_cat(out, o, "</div>" as *u8)
755 lines = lines + 1
756 i = e + 1
757 }
758 o = of_cat(out, o, "</div>" as *u8)
759 }
760 if ks == 1 {
761 o = of_cat(out, o, "<table class='tsheet'><tbody>" as *u8)
762 var i2: i64 = 0
763 var rows: i64 = 0
764 while i2 < sl {
765 if rows >= 5 { break }
766 var e2: i64 = i2
767 while e2 < sl { if buf[e2] == (10 as u8) { break } e2 = e2 + 1 }
768 o = of_cat(out, o, "<tr>" as *u8)
769 var cstart: i64 = i2
770 var k: i64 = i2
771 var cells: i64 = 0
772 while k <= e2 {
773 if cells >= 4 { break }
774 var hit: i64 = 0
775 if k == e2 { hit = 1 } else { if buf[k] == (9 as u8) { hit = 1 } }
776 if hit == 1 {
777 var ce2: i64 = k
778 if ce2 > cstart + 14 { ce2 = cstart + 14 }
779 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)
780 cstart = k + 1
781 cells = cells + 1
782 }
783 k = k + 1
784 }
785 o = of_cat(out, o, "</tr>" as *u8)
786 rows = rows + 1
787 i2 = e2 + 1
788 }
789 o = of_cat(out, o, "</tbody></table>" as *u8)
790 }
791 if ks == 2 {
792 o = of_cat(out, o, "<div class='tslide'>" as *u8)
793 var i3: i64 = 0
794 var started: i64 = 0
795 var bl: i64 = 0
796 while i3 < sl {
797 var e3: i64 = i3
798 while e3 < sl { if buf[e3] == (10 as u8) { break } e3 = e3 + 1 }
799 let c3: i64 = buf[i3] as i64
800 var cs3: i64 = i3
801 if e3 >= i3 + 2 { if buf[i3+1] == (32 as u8) { cs3 = i3 + 2 } }
802 var ce3: i64 = e3
803 if ce3 > cs3 + 56 { ce3 = cs3 + 56 }
804 if c3 == 83 {
805 if started == 1 { break }
806 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)
807 started = 1
808 } else { if c3 == 66 { if bl < 3 {
809 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)
810 bl = bl + 1
811 } } }
812 i3 = e3 + 1
813 }
814 o = of_cat(out, o, "</div>" as *u8)
815 }
816 o = of_cat(out, o, "</div>" as *u8)
817 return o
818}
819// lowercase in place (search is case-insensitive; stored names are already lowercase by of_name_ok)
820func of_lower(s: *u8) -> i64 {
821 var i: i64 = 0
822 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 }
823 return 0
824}
825// one filter/sort pill: preserves q, sets type (tv, empty = All) and sort (sv) explicitly
826func of_chip(out: *u8, off: i64, base: *u8, q: *u8, tv: *u8, sv: *u8, label: *u8, on: i64) -> i64 {
827 var o: i64 = of_cat(out, off, "<a class='" as *u8)
828 if on == 1 { o = of_cat(out, o, "on" as *u8) }
829 o = of_cat(out, o, "' href='" as *u8)
830 o = of_cat(out, o, base)
831 o = of_cat(out, o, "/?" as *u8)
832 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) }
833 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) }
834 o = of_cat(out, o, "sort=" as *u8)
835 o = of_cat(out, o, sv)
836 o = of_cat(out, o, "'>" as *u8)
837 o = of_cat(out, o, label)
838 o = of_cat(out, o, "</a>" as *u8)
839 return o
840}
841// first byte offset of needle in buf[0,n), or -1 -- lets the gate assert ORDERING, not just presence
842func of_findpos(buf: *u8, n: i64, needle: *u8) -> i64 {
843 let nl: i64 = of_slen(needle)
844 if nl == 0 { return 0 - 1 }
845 var i: i64 = 0
846 while i + nl <= n {
847 var k: i64 = 0
848 var hit: i64 = 1
849 while k < nl { if buf[i+k] != needle[k] { hit = 0; k = nl } else { k = k + 1 } }
850 if hit == 1 { return i }
851 i = i + 1
852 }
853 return 0 - 1
854}
855// one Start-new tile: pick a name, Create -> lands on the visual editor. The starter spec rides a HIDDEN INPUT
856// (a hidden default value is what type=hidden is FOR -- and unlike a display:none <textarea> it renders NOTHING
857// in every engine incl. Nishi Browser, so the tile shows no leaked spec text; newlines/tabs survive the POST via
858// URL-encoding, which of_form_get decodes). Submitted as-is, works with NO JS; the editor is where you compose.
859// ---- U3 LIBRARY ORGANISATION: starred + folders ------------------------------------------------------
860// Both are SIDECAR files next to the manifest, exactly like agent.txt: the document spec stays pure content,
861// nothing about the file format changes, and a missing sidecar simply means "not starred / no folder". No
862// migration, no schema version, and an older daemon reading a newer tree just ignores them.
863func of_side_path(root: *u8, name: *u8, leaf: *u8, out: *u8) -> i64 {
864 var o: i64 = of_cat(out, 0, root); o = of_cat(out, o, "/" as *u8); o = of_cat(out, o, name)
865 o = of_cat(out, o, "/" as *u8); o = of_cat(out, o, leaf); out[o] = 0 as u8
866 return o
867}
868func of_starred(root: *u8, name: *u8) -> i64 {
869 let p: *u8 = sys_mmap(512)
870 of_side_path(root, name, "starred" as *u8, p)
871 let b: *u8 = sys_mmap(8)
872 if of_read_file(p, b, 4) > 0 { return 1 }
873 return 0
874}
875// toggle and return the NEW state. Unstar writes "0" rather than deleting: a retired star is still history,
876// and a write we can read back beats a delete we cannot audit.
877// Toggle and return the NEW state. Unstar writes a zeroed byte rather than deleting: a retired star is still
878// history, and a write we can read back beats a delete we cannot audit.
879// NOTE: never pass the "" literal here -- the nx_cc constant pool ALIASES an empty literal onto the NEXT
880// literal in the pool, so the "empty" write would emit someone else's bytes. Use a real zeroed buffer.
881func of_star_toggle(root: *u8, name: *u8) -> i64 {
882 let p: *u8 = sys_mmap(512)
883 of_side_path(root, name, "starred" as *u8, p)
884 if of_starred(root, name) == 1 {
885 let z: *u8 = sys_mmap(8); z[0] = 0 as u8
886 of_write_file(p, z, 0)
887 return 0
888 }
889 of_write_file(p, "1" as *u8, 1)
890 return 1
891}
892func of_folder_get(root: *u8, name: *u8, out: *u8, cap: i64) -> i64 {
893 let p: *u8 = sys_mmap(512)
894 of_side_path(root, name, "folder" as *u8, p)
895 let n: i64 = of_read_file(p, out, cap - 1)
896 if n <= 0 { out[0] = 0 as u8; return 0 }
897 var e: i64 = n
898 var trim: i64 = 1
899 while trim == 1 {
900 if e <= 0 { trim = 0 } else {
901 let c: i64 = out[e-1] as i64
902 if c == 10 { e = e - 1 } else { if c == 13 { e = e - 1 } else { trim = 0 } }
903 }
904 }
905 out[e] = 0 as u8
906 return e
907}
908func of_folder_set(root: *u8, name: *u8, val: *u8) -> i64 {
909 let p: *u8 = sys_mmap(512)
910 of_side_path(root, name, "folder" as *u8, p)
911 return of_write_file(p, val, of_slen(val))
912}
913// One template card. Same POST /save contract as of_form, so a template is not a special kind of file --
914// it is an ordinary document that happens to start with useful content, and every downstream feature
915// (versioning, diff, AI, agent, sharing) works on it unchanged.
916func of_tmpl(out: *u8, off: i64, base: *u8, k: i64, icon: *u8, title: *u8, blurb: *u8, spec: *u8) -> i64 {
917 var o: i64 = of_cat(out, off, "<div class='newt'><h3><div class='fico k" as *u8)
918 o = of_catn(out, o, k)
919 o = of_cat(out, o, "'>" as *u8)
920 o = of_cat(out, o, icon)
921 o = of_cat(out, o, "</div>" as *u8)
922 o = of_cat(out, o, title)
923 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)
924 o = of_cat(out, o, base)
925 o = of_cat(out, o, "/save'><input type='hidden' name='kind' value='" as *u8)
926 o = of_cat(out, o, of_kind_name(k))
927 o = of_cat(out, o, "'><input type='hidden' name='spec' value='" as *u8)
928 o = of_esc(out, o, spec)
929 o = of_cat(out, o, "'><p class='hint' style='margin:0'>" as *u8)
930 o = of_cat(out, o, blurb)
931 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)
932 return o
933}
934func of_form(out: *u8, off: i64, base: *u8, k: i64) -> i64 {
935 var o: i64 = off
936 o = of_cat(out, o, "<div class='newt'><h3><div class='fico k" as *u8)
937 o = of_catn(out, o, k)
938 o = of_cat(out, o, "'>" as *u8)
939 if k == 0 { o = of_cat(out, o, "W" as *u8) }
940 if k == 1 { o = of_cat(out, o, "S" as *u8) }
941 if k == 2 { o = of_cat(out, o, "P" as *u8) }
942 o = of_cat(out, o, "</div>New " as *u8)
943 o = of_cat(out, o, of_kind_name(k))
944 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)
945 o = of_cat(out, o, base)
946 o = of_cat(out, o, "/save'><input type='hidden' name='kind' value='" as *u8)
947 o = of_cat(out, o, of_kind_name(k))
948 o = of_cat(out, o, "'><input type='hidden' name='spec' value='" as *u8)
949 if k == 0 { o = of_cat(out, o, "H Untitled document\nP Start writing here." as *u8) }
950 if k == 1 { o = of_cat(out, o, "Item\tAmount\nExample\t1" as *u8) }
951 if k == 2 { o = of_cat(out, o, "S Untitled deck\nB First point" as *u8) }
952 o = of_cat(out, o, "'>" as *u8)
953 if k == 0 { o = of_cat(out, o, "<p class='hint' style='margin:0'>Headings, bold, tables. Opens in Word.</p>" as *u8) }
954 if k == 1 { o = of_cat(out, o, "<p class='hint' style='margin:0'>Real formulas (=SUM, =AVERAGE…). Opens in Excel.</p>" as *u8) }
955 if k == 2 { o = of_cat(out, o, "<p class='hint' style='margin:0'>Titles and bullets. Opens in PowerPoint.</p>" as *u8) }
956 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)
957 return o
958}
959// the home APP SHELL (U-axes rung): search + type chips + recency/name sort + card grid with REAL content
960// thumbnails + onboarding/no-match empty states. All server-rendered -- works with ZERO JS.
961// qs = the raw query string (q=&type=&sort=), form-urlencoded exactly like a POST body.
962func of_home(root: *u8, base: *u8, qs: *u8, out: *u8, cap: i64, azprefix: *u8, me: *u8, authed: i64) -> i64 {
963 let ql: i64 = of_slen(qs)
964 let q: *u8 = sys_mmap(96)
965 let srt: *u8 = sys_mmap(24)
966 let tf: *u8 = sys_mmap(24)
967 of_form_get(qs, ql, "q" as *u8, q, 80)
968 of_form_get(qs, ql, "sort" as *u8, srt, 24)
969 of_form_get(qs, ql, "type" as *u8, tf, 24)
970 let flt: *u8 = sys_mmap(24)
971 let fld: *u8 = sys_mmap(64)
972 of_form_get(qs, ql, "filter" as *u8, flt, 24)
973 of_form_get(qs, ql, "folder" as *u8, fld, 48)
974 // "shared with me" = docs the ReBAC reverse index grants me that I do NOT own. Answered from the existing
975 // index rather than a second store, so sharing and the library view can never disagree.
976 let shd: *i64 = sys_mmap(8 * 64) as *i64
977 let own: *i64 = sys_mmap(8 * 64) as *i64
978 var nshd: i64 = 0
979 var nown: i64 = 0
980 if of_seq(flt, "shared" as *u8) == 1 { if authed == 1 {
981 nshd = of_my_docs(azprefix, me, shd, 64)
982 nown = of_collect_docs(azprefix, me, "owner" as *u8, own, 0, 64)
983 } }
984 of_lower(q)
985 var o: i64 = of_shell_top(out, 0, "Nishi Office" as *u8, base, q)
986 o = of_cat(out, o, "<main id='main' class='wrap'>" as *u8)
987 // collect entries from the append-only registry, filtered by type chip + search text
988 let idx: *u8 = sys_mmap(512)
989 var io: i64 = of_cat(idx, 0, root); io = of_cat(idx, io, "/index.txt" as *u8); idx[io] = 0 as u8
990 let ib: *u8 = sys_mmap(65536)
991 let n: i64 = of_read_file(idx, ib, 65536)
992 let names: *u8 = sys_mmap(256 * 64)
993 let kidx: *i64 = sys_mmap(256 * 8) as *i64
994 let vcs: *i64 = sys_mmap(256 * 8) as *i64
995 let uss: *i64 = sys_mmap(256 * 8) as *i64
996 let ord: *i64 = sys_mmap(256 * 8) as *i64
997 var total: i64 = 0
998 var ne: i64 = 0
999 let nm: *u8 = sys_mmap(64)
1000 let kd: *u8 = sys_mmap(32)
1001 let kb: *u8 = sys_mmap(64)
1002 var i: i64 = 0
1003 while i < n {
1004 var t: i64 = 0
1005 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 }
1006 nm[t] = 0 as u8
1007 var t2: i64 = 0
1008 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 }
1009 kd[t2] = 0 as u8
1010 if t > 0 {
1011 total = total + 1
1012 var keep: i64 = 1
1013 if tf[0] != (0 as u8) { if of_seq(tf, kd) == 0 { keep = 0 } }
1014 if keep == 1 { if q[0] != (0 as u8) { if of_memhas(nm, of_slen(nm), q) == 0 { keep = 0 } } }
1015 if keep == 1 { if of_seq(flt, "starred" as *u8) == 1 { if of_starred(root, nm) == 0 { keep = 0 } } }
1016 if keep == 1 { if fld[0] != (0 as u8) {
1017 let fbuf: *u8 = sys_mmap(64)
1018 of_folder_get(root, nm, fbuf, 64)
1019 if of_seq(fbuf, fld) == 0 { keep = 0 }
1020 } }
1021 if keep == 1 { if of_seq(flt, "shared" as *u8) == 1 {
1022 var mine: i64 = 0
1023 var si: i64 = 0
1024 while si < nshd { if of_seq(shd[si] as *u8, nm) == 1 { mine = 1; si = nshd } else { si = si + 1 } }
1025 if mine == 0 { keep = 0 }
1026 if mine == 1 {
1027 var owned: i64 = 0
1028 var oi: i64 = 0
1029 while oi < nown { if of_seq(own[oi] as *u8, nm) == 1 { owned = 1; oi = nown } else { oi = oi + 1 } }
1030 if owned == 1 { keep = 0 }
1031 }
1032 } }
1033 if keep == 1 { if ne < 256 {
1034 let ki: i64 = of_kind_idx(kd)
1035 var ks: i64 = ki
1036 if ks < 0 { ks = 0 }
1037 var w: i64 = 0
1038 while nm[w] != (0 as u8) { names[ne * 64 + w] = nm[w]; w = w + 1 }
1039 names[ne * 64 + w] = 0 as u8
1040 kidx[ne] = ks
1041 vcs[ne] = of_manifest_count(root, nm, kb, 64)
1042 uss[ne] = of_manifest_last_us(root, nm)
1043 ord[ne] = ne
1044 ne = ne + 1
1045 } }
1046 }
1047 }
1048 // order: default = most recently edited first (Docs-style); sort=name = alphabetical
1049 var by_name: i64 = 0
1050 if of_seq(srt, "name" as *u8) == 1 { by_name = 1 }
1051 var a: i64 = 0
1052 while a < ne {
1053 var b: i64 = a + 1
1054 while b < ne {
1055 var sw: i64 = 0
1056 if by_name == 1 {
1057 let pa: *u8 = (names as i64 + ord[a] * 64) as *u8
1058 let pb: *u8 = (names as i64 + ord[b] * 64) as *u8
1059 var ci: i64 = 0
1060 var cmp: i64 = 0
1061 while cmp == 0 {
1062 let ca: i64 = pa[ci] as i64
1063 let cb: i64 = pb[ci] as i64
1064 if ca < cb { cmp = 0 - 1 } else { if ca > cb { cmp = 1 } else { if ca == 0 { cmp = 2 } else { ci = ci + 1 } } }
1065 }
1066 if cmp == 1 { sw = 1 }
1067 } else {
1068 if uss[ord[b]] > uss[ord[a]] { sw = 1 }
1069 }
1070 if sw == 1 { let tmp: i64 = ord[a]; ord[a] = ord[b]; ord[b] = tmp }
1071 b = b + 1
1072 }
1073 a = a + 1
1074 }
1075 // first-run onboarding: nothing exists yet
1076 if total == 0 {
1077 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)
1078 o = of_form(out, o, base, 0)
1079 o = of_form(out, o, base, 1)
1080 o = of_form(out, o, base, 2)
1081 o = of_cat(out, o, "</div></main>" as *u8)
1082 o = of_page_foot(out, o)
1083 return o
1084 }
1085 o = of_cat(out, o, "<h2>Start new</h2><div class='newrow'>" as *u8)
1086 o = of_form(out, o, base, 0)
1087 o = of_form(out, o, base, 1)
1088 o = of_form(out, o, base, 2)
1089 o = of_cat(out, o, "</div>" as *u8)
1090 // ---- TEMPLATES GALLERY (U3): a blank page is the worst onboarding a suite can offer. Every template is a
1091 // REAL working spec -- the budget carries live =SUM and a #CF rule, the agenda a real table -- so opening one
1092 // demonstrates the engine instead of describing it. Zero JS: each card is a plain POST to the same /save.
1093 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)
1094 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")
1095 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.")
1096 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")
1097 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")
1098 o = of_cat(out, o, "</div>" as *u8)
1099 // files header: count + type chips + sort links (every control is a plain link -- zero JS)
1100 o = of_cat(out, o, "<div class='fhead'><h1>Files</h1><span class='cnt'>" as *u8)
1101 o = of_catn(out, o, ne)
1102 if ne != total { o = of_cat(out, o, " of " as *u8); o = of_catn(out, o, total) }
1103 o = of_cat(out, o, "</span><span class='chips'>" as *u8)
1104 // U3 chips: Starred and Shared-with-me sit alongside the type chips. Shared is shown only when a caller is
1105 // actually signed in -- an always-visible control that can only ever be empty is a lie about the product.
1106 o = of_cat(out, o, "<a class='" as *u8)
1107 if of_seq(flt, "starred" as *u8) == 1 { o = of_cat(out, o, "on" as *u8) }
1108 o = of_cat(out, o, "' href='" as *u8); o = of_cat(out, o, base)
1109 o = of_cat(out, o, "/?filter=starred'>★ Starred</a>" as *u8)
1110 if authed == 1 {
1111 o = of_cat(out, o, "<a class='" as *u8)
1112 if of_seq(flt, "shared" as *u8) == 1 { o = of_cat(out, o, "on" as *u8) }
1113 o = of_cat(out, o, "' href='" as *u8); o = of_cat(out, o, base)
1114 o = of_cat(out, o, "/?filter=shared'>Shared with me</a>" as *u8)
1115 }
1116 let e0: *u8 = sys_mmap(4)
1117 e0[0] = 0 as u8
1118 var srtv: *u8 = "recent" as *u8
1119 if by_name == 1 { srtv = "name" as *u8 }
1120 var all_on: i64 = 0
1121 if tf[0] == (0 as u8) { all_on = 1 }
1122 o = of_chip(out, o, base, q, e0, srtv, "All" as *u8, all_on)
1123 o = of_chip(out, o, base, q, "doc" as *u8, srtv, "Docs" as *u8, of_seq(tf, "doc" as *u8))
1124 o = of_chip(out, o, base, q, "sheet" as *u8, srtv, "Sheets" as *u8, of_seq(tf, "sheet" as *u8))
1125 o = of_chip(out, o, base, q, "deck" as *u8, srtv, "Decks" as *u8, of_seq(tf, "deck" as *u8))
1126 o = of_cat(out, o, "</span><span class='sortl'>Sort:" as *u8)
1127 o = of_chip(out, o, base, q, tf, "recent" as *u8, "Recent" as *u8, 1 - by_name)
1128 o = of_chip(out, o, base, q, tf, "name" as *u8, "Name" as *u8, by_name)
1129 o = of_cat(out, o, "</span></div>" as *u8)
1130 if ne == 0 {
1131 // no-match empty state (search/filter found nothing)
1132 o = of_cat(out, o, "<div class='empty'><h2>No files match</h2><p>" as *u8)
1133 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) }
1134 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)
1135 } else {
1136 o = of_cat(out, o, "<div class='fgrid'>" as *u8)
1137 var r: i64 = 0
1138 while r < ne {
1139 let ei: i64 = ord[r]
1140 let pnm: *u8 = (names as i64 + ei * 64) as *u8
1141 o = of_cat(out, o, "<a class='fcard' href='" as *u8)
1142 o = of_cat(out, o, base); o = of_cat(out, o, "/doc/" as *u8); o = of_cat(out, o, pnm)
1143 o = of_cat(out, o, "'>" as *u8)
1144 // thumbnails for the first 60 cards keep the page bounded; the rest stay plain cards
1145 if r < 60 { o = of_thumb(out, o, root, pnm, kidx[ei], vcs[ei]) }
1146 o = of_cat(out, o, "<div class='fmeta'><div class='fico k" as *u8)
1147 o = of_catn(out, o, kidx[ei])
1148 o = of_cat(out, o, "'>" as *u8)
1149 if kidx[ei] == 0 { o = of_cat(out, o, "W" as *u8) }
1150 if kidx[ei] == 1 { o = of_cat(out, o, "S" as *u8) }
1151 if kidx[ei] == 2 { o = of_cat(out, o, "P" as *u8) }
1152 o = of_cat(out, o, "</div><span class='nm'><b>" as *u8)
1153 o = of_esc(out, o, pnm)
1154 o = of_cat(out, o, "</b><span>v" as *u8)
1155 o = of_catn(out, o, vcs[ei])
1156 o = of_cat(out, o, " · " as *u8)
1157 o = of_ago(out, o, uss[ei])
1158 o = of_cat(out, o, "</span></span></div></a>" as *u8)
1159 r = r + 1
1160 }
1161 o = of_cat(out, o, "</div>" as *u8)
1162 if ne == 256 { o = of_cat(out, o, "<p class='hint'>Showing the first 256 files.</p>" as *u8) }
1163 }
1164 o = of_cat(out, o, "</main>" as *u8)
1165 o = of_page_foot(out, o)
1166 return o
1167}
1168// ---- version DIFF (leverages the never-lose store: every version's spec.txt is on disk) ----
1169func of_lineeq(a: *u8, b: *u8) -> i64 {
1170 var i: i64 = 0
1171 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
1172 if b[i] != (0 as u8) { return 0 }
1173 return 1
1174}
1175// split buf[0,n) into NUL-terminated lines in place; store start pointers in lp[]; return count (<=maxl). Caller sets buf[n]=0.
1176func of_split_lines(buf: *u8, n: i64, lp: *i64, maxl: i64) -> i64 {
1177 var c: i64 = 0
1178 var i: i64 = 0
1179 while i < n {
1180 if c >= maxl { return c }
1181 lp[c] = (buf as i64) + i
1182 c = c + 1
1183 while i < n { if buf[i] == (10 as u8) { break } i = i + 1 }
1184 if i < n { buf[i] = 0 as u8; i = i + 1 }
1185 }
1186 return c
1187}
1188func of_read_version_spec(root: *u8, name: *u8, vn: i64, buf: *u8, cap: i64) -> i64 {
1189 let vd: *u8 = sys_mmap(512)
1190 of_vdir(root, name, vn, vd)
1191 let sp: *u8 = sys_mmap(600)
1192 var so: i64 = of_cat(sp, 0, vd); so = of_cat(sp, so, "/spec.txt" as *u8); sp[so] = 0 as u8
1193 let n: i64 = of_read_file(sp, buf, cap)
1194 if n > 0 { buf[n] = 0 as u8; return n }
1195 buf[0] = 0 as u8; return 0
1196}
1197// render an LCS line-diff of specA vs specB into out. added=in B not A (green), removed=in A not B (red).
1198func of_render_diff(out: *u8, off: i64, bufa: *u8, na_bytes: i64, bufb: *u8, nb_bytes: i64) -> i64 {
1199 let MAXL: i64 = 400
1200 let la: *i64 = sys_mmap(MAXL * 8) as *i64
1201 let lb: *i64 = sys_mmap(MAXL * 8) as *i64
1202 let na: i64 = of_split_lines(bufa, na_bytes, la, MAXL)
1203 let nb: i64 = of_split_lines(bufb, nb_bytes, lb, MAXL)
1204 let W: i64 = nb + 1
1205 let dp: *i64 = sys_mmap((na + 1) * (nb + 1) * 8) as *i64
1206 var i: i64 = na
1207 while i >= 0 {
1208 var j: i64 = nb
1209 while j >= 0 {
1210 if i == na { dp[i*W + j] = 0 } else { if j == nb { dp[i*W + j] = 0 } else {
1211 if of_lineeq(la[i] as *u8, lb[j] as *u8) == 1 { dp[i*W + j] = dp[(i+1)*W + (j+1)] + 1 }
1212 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 } }
1213 } }
1214 j = j - 1
1215 }
1216 i = i - 1
1217 }
1218 var o: i64 = of_cat(out, off, "<div class='diff'>" as *u8)
1219 var add: i64 = 0; var del: i64 = 0
1220 var a: i64 = 0; var b: i64 = 0
1221 var go: i64 = 1
1222 while go == 1 {
1223 if a < na { if b < nb {
1224 if of_lineeq(la[a] as *u8, lb[b] as *u8) == 1 {
1225 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
1226 } else { if dp[(a+1)*W + b] >= dp[a*W + (b+1)] {
1227 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
1228 } else {
1229 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
1230 } }
1231 } else {
1232 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
1233 } } else { if b < nb {
1234 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
1235 } else { go = 0 } }
1236 }
1237 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)
1238 return o
1239}
1240func of_diffpage(root: *u8, base: *u8, name: *u8, va: i64, vb: i64, out: *u8, cap: i64) -> i64 {
1241 let kb: *u8 = sys_mmap(64)
1242 let vc: i64 = of_manifest_count(root, name, kb, 64)
1243 if vc <= 0 { return 0 - 1 }
1244 if va < 1 { return 0 - 1 }
1245 if vb < 1 { return 0 - 1 }
1246 if va > vc { return 0 - 1 }
1247 if vb > vc { return 0 - 1 }
1248 let ba: *u8 = sys_mmap(131072)
1249 let bb: *u8 = sys_mmap(131072)
1250 let nab: i64 = of_read_version_spec(root, name, va, ba, 131071)
1251 let nbb: i64 = of_read_version_spec(root, name, vb, bb, 131071)
1252 let eqd: *u8 = sys_mmap(4)
1253 eqd[0] = 0 as u8
1254 var o: i64 = of_shell_top(out, 0, name, base, eqd)
1255 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)
1256 o = of_catn(out, o, va); o = of_cat(out, o, " → v" as *u8); o = of_catn(out, o, vb)
1257 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)
1258 o = of_render_diff(out, o, ba, nab, bb, nbb)
1259 o = of_cat(out, o, "</div></main>\n" as *u8)
1260 o = of_page_foot(out, o)
1261 return o
1262}
1263func of_docpage(root: *u8, base: *u8, name: *u8, out: *u8, cap: i64) -> i64 {
1264 let kb: *u8 = sys_mmap(64)
1265 let vc: i64 = of_manifest_count(root, name, kb, 64)
1266 if vc <= 0 { return 0 - 1 }
1267 let ki: i64 = of_kind_idx(kb)
1268 var ks: i64 = ki
1269 if ks < 0 { ks = 0 }
1270 let eq: *u8 = sys_mmap(4)
1271 eq[0] = 0 as u8
1272 var o: i64 = of_shell_top(out, 0, name, base, eq)
1273 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)
1274 o = of_esc(out, o, name)
1275 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)
1276 o = of_cat(out, o, "</span> <span class='stamp'>Saved v" as *u8)
1277 o = of_catn(out, o, vc)
1278 o = of_cat(out, o, " · " as *u8)
1279 o = of_ago(out, o, of_manifest_last_us(root, name))
1280 o = of_cat(out, o, "</span></h1><p class='sub'>" as *u8)
1281 o = of_catn(out, o, vc)
1282 o = of_cat(out, o, " version(s), additive — saving creates v" as *u8)
1283 o = of_catn(out, o, vc + 1)
1284 o = of_cat(out, o, ", earlier versions stay forever.</p>\n" as *u8)
1285 let vd: *u8 = sys_mmap(512)
1286 of_vdir(root, name, vc, vd)
1287 let sp: *u8 = sys_mmap(600)
1288 var so: i64 = of_cat(sp, 0, vd); so = of_cat(sp, so, "/spec.txt" as *u8); sp[so] = 0 as u8
1289 let spec: *u8 = sys_mmap(131072)
1290 let sl: i64 = of_read_file(sp, spec, 131071)
1291 if sl > 0 { spec[sl] = 0 as u8 }
1292 // ---- the visual editor card: toolbar + WYSIWYG surface + raw-spec fallback, all in one form ----
1293 o = of_cat(out, o, "<div class='card'>" as *u8)
1294 o = of_toolbar(out, o, ks)
1295 o = of_cat(out, o, "<form id='savef' method='post' action='" as *u8)
1296 o = of_cat(out, o, base)
1297 o = of_cat(out, o, "/save'><input type='hidden' name='kind' value='" as *u8)
1298 o = of_cat(out, o, kb)
1299 o = of_cat(out, o, "'><input type='hidden' name='name' value='" as *u8)
1300 o = of_cat(out, o, name)
1301 o = of_cat(out, o, "'>" as *u8)
1302 if ks == 0 { o = of_render_doc(out, o, spec, sl) }
1303 if ks == 1 { o = of_render_sheet(out, o, spec, sl) }
1304 if ks == 2 { o = of_render_deck(out, o, spec, sl) }
1305 o = of_cat(out, o, "<details id='rawd' class='rawwrap' open><summary>Edit raw spec</summary><textarea id='specta' name='spec'>" as *u8)
1306 if sl > 0 { o = of_esc(out, o, spec) }
1307 o = of_cat(out, o, "</textarea></details>" as *u8)
1308 o = of_cat(out, o, "<p><button type='submit' class='save'>Save as v" as *u8)
1309 o = of_catn(out, o, vc + 1)
1310 o = of_cat(out, o, "</button> <span id='savest' class='hint'></span></p></form></div>\n" as *u8)
1311 if ks == 0 {
1312 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)
1313 o = of_cat(out, o, base)
1314 o = of_cat(out, o, "/ai'><input type='hidden' name='name' value='" as *u8)
1315 o = of_cat(out, o, name)
1316 o = of_cat(out, o, "'><button type='submit' class='ghost'>✨ Continue with AI</button></form></div>\n" as *u8)
1317 // ---- OF-A4 AGENT MODE card: plan -> execute -> refine, one turn per click ----
1318 let agb: *u8 = sys_mmap(8192)
1319 let agn: i64 = of_agent_read(root, name, agb, 8000)
1320 let agsteps: i64 = of_agent_tagcount(agb, agn, 83)
1321 let agdone: i64 = of_agent_done(agb, agn)
1322 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)
1323 if agn <= 0 {
1324 o = of_cat(out, o, "<form method='post' action='" as *u8)
1325 o = of_cat(out, o, base)
1326 o = of_cat(out, o, "/agent'><input type='hidden' name='name' value='" as *u8)
1327 o = of_cat(out, o, name)
1328 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)
1329 } else {
1330 let agg: *u8 = sys_mmap(512)
1331 of_agent_tagline(agb, agn, 71, 0, agg, 512)
1332 o = of_cat(out, o, "<p style='margin:0 0 6px'><b>Goal:</b> " as *u8)
1333 o = of_esc(out, o, agg)
1334 o = of_cat(out, o, "</p><ol class='agentplan' style='margin:0 0 10px 18px'>" as *u8)
1335 let agsb: *u8 = sys_mmap(256)
1336 var agi: i64 = 0
1337 while agi < agsteps {
1338 of_agent_tagline(agb, agn, 83, agi, agsb, 256)
1339 o = of_cat(out, o, "<li>" as *u8)
1340 if agi < agdone { o = of_cat(out, o, "<span class='cnt'>✓</span> " as *u8) }
1341 o = of_esc(out, o, agsb)
1342 o = of_cat(out, o, "</li>" as *u8)
1343 agi = agi + 1
1344 }
1345 o = of_cat(out, o, "</ol>" as *u8)
1346 if agdone > agsteps {
1347 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)
1348 o = of_cat(out, o, base)
1349 o = of_cat(out, o, "/agent'><input type='hidden' name='name' value='" as *u8)
1350 o = of_cat(out, o, name)
1351 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)
1352 } else {
1353 o = of_cat(out, o, "<p class='hint' style='margin:0 0 10px'>Turn " as *u8)
1354 o = of_catn(out, o, agdone + 1)
1355 o = of_cat(out, o, " of " as *u8)
1356 o = of_catn(out, o, agsteps + 1)
1357 o = of_cat(out, o, " (the last turn is the refine pass).</p><form method='post' action='" as *u8)
1358 o = of_cat(out, o, base)
1359 o = of_cat(out, o, "/agent'><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'>▶ " as *u8)
1362 if agdone < agsteps { o = of_cat(out, o, "Run next step" as *u8) } else { o = of_cat(out, o, "Run final refine" as *u8) }
1363 o = of_cat(out, o, "</button></form>" as *u8)
1364 }
1365 }
1366 o = of_cat(out, o, "</div>\n" as *u8)
1367 }
1368 // OF-A2 (sheets) / OF-A3 (decks): the same sovereign seat, in each artifact's own grammar. Agent mode stays
1369 // doc-only for now (it appends prose), so these get the single-turn card, not the plan/execute/refine loop.
1370 if ks != 0 {
1371 o = of_cat(out, o, "<div class='card'><h2 style='margin:0 0 8px'>✨ " as *u8)
1372 if ks == 1 { o = of_cat(out, o, "AI insight" as *u8) } else { o = of_cat(out, o, "AI slide" as *u8) }
1373 o = of_cat(out, o, "</h2><p class='hint' style='margin:0 0 10px'>" as *u8)
1374 if ks == 1 {
1375 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)
1376 } else {
1377 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)
1378 }
1379 o = of_cat(out, o, " <b>Experimental</b> (0.5B is small — quality is rough).</p><form method='post' action='" as *u8)
1380 o = of_cat(out, o, base)
1381 o = of_cat(out, o, "/ai'><input type='hidden' name='name' value='" as *u8)
1382 o = of_cat(out, o, name)
1383 o = of_cat(out, o, "'><button type='submit' class='ghost'>✨ " as *u8)
1384 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) }
1385 o = of_cat(out, o, "</button></form></div>\n" as *u8)
1386 }
1387 // U3: star + folder controls. Zero-JS forms, same additive spirit as everything else -- neither touches
1388 // the spec or the version chain, so organising a file can never damage its content.
1389 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)
1390 o = of_cat(out, o, base)
1391 o = of_cat(out, o, "/star' style='display:inline'><input type='hidden' name='name' value='" as *u8)
1392 o = of_cat(out, o, name)
1393 o = of_cat(out, o, "'><button type='submit' class='ghost'>" as *u8)
1394 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) }
1395 o = of_cat(out, o, "</button></form> <form method='post' action='" as *u8)
1396 o = of_cat(out, o, base)
1397 o = of_cat(out, o, "/folder' style='display:inline'><input type='hidden' name='name' value='" as *u8)
1398 o = of_cat(out, o, name)
1399 o = of_cat(out, o, "'><input type='text' name='folder' placeholder='folder' value='" as *u8)
1400 let fcur: *u8 = sys_mmap(64)
1401 of_folder_get(root, name, fcur, 64)
1402 o = of_esc(out, o, fcur)
1403 o = of_cat(out, o, "'><button type='submit' class='ghost'>File it</button></form></div>
1404" as *u8)
1405 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></tr></thead><tbody>" as *u8)
1406 var v: i64 = vc
1407 while v >= 1 {
1408 o = of_cat(out, o, "<tr><td><b>v" as *u8); o = of_catn(out, o, v)
1409 o = of_cat(out, o, "</b>" as *u8)
1410 if of_manifest_is_auto(root, name, v) == 1 { o = of_cat(out, o, " <span class='cnt'>(auto)</span>" as *u8) }
1411 o = of_cat(out, o, "</td><td>" as *u8)
1412 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) }
1413 else { o = of_cat(out, o, "—" as *u8) }
1414 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)
1415 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)
1416 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)
1417 if v < vc {
1418 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)
1419 } else { o = of_cat(out, o, "<span class='cnt'>current</span>" as *u8) }
1420 o = of_cat(out, o, "</td></tr>" as *u8)
1421 v = v - 1
1422 }
1423 o = of_cat(out, o, "</tbody></table></div></div></main>\n<script src='" as *u8)
1424 o = of_cat(out, o, base)
1425 o = of_cat(out, o, "/app.js'></script>\n" as *u8)
1426 o = of_page_foot(out, o)
1427 return o
1428}
1429func of_err(out: *u8, status: *u8, msg: *u8) -> i64 {
1430 // body = "LOUD: " + msg + "\n" (6 + len(msg) + 1). Emit Content-Length + Connection: close so a STRICT
1431 // CL-stop client (our own nx_https TLS stack / nx_office_live_verify) can frame the error without hanging.
1432 let bl: i64 = 6 + of_slen(msg) + 1
1433 var o: i64 = of_cat(out, 0, "HTTP/1.1 " as *u8)
1434 o = of_cat(out, o, status)
1435 o = of_cat(out, o, "\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: " as *u8)
1436 o = of_catn(out, o, bl)
1437 o = of_cat(out, o, "\r\nConnection: close\r\n\r\nLOUD: " as *u8)
1438 o = of_cat(out, o, msg)
1439 o = of_catc(out, o, 10)
1440 return o
1441}
1442// ---- IN-APP AI (the marquee): draft with OUR OWN sovereign no-float 0.5B LLM served on loopback :11434 ----
1443// HONEST: it is a 0.5B integer model -- draft quality is EXPERIMENTAL, not GPT/Copilot-class. The point is
1444// sovereign convergence: our office drafting off our own model on our own hardware, zero OpenAI. Graceful:
1445// if the seat is down, the caller returns a LOUD 503 (never an office error).
1446// extract the FIRST "content":"..." value (JSON-unescaped) from buf into out; returns length or -1 if absent.
1447func of_extract_json_content(buf: *u8, n: i64, out: *u8, cap: i64) -> i64 {
1448 let key: *u8 = "\"content\":\"" as *u8
1449 var i: i64 = 0
1450 var found: i64 = 0 - 1
1451 while i + 11 <= n {
1452 var m: i64 = 1; var j: i64 = 0
1453 while j < 11 { if buf[i+j] != key[j] { m = 0; j = 11 } else { j = j + 1 } }
1454 if m == 1 { found = i + 11; i = n } else { i = i + 1 }
1455 }
1456 if found < 0 { return 0 - 1 }
1457 var o: i64 = 0
1458 var k: i64 = found
1459 var go: i64 = 1
1460 while go == 1 {
1461 if k >= n { go = 0 } else {
1462 let c: i64 = buf[k] as i64
1463 if c == 34 { go = 0 } else {
1464 if c == 92 {
1465 k = k + 1
1466 if k < n {
1467 let e: i64 = buf[k] as i64
1468 if e == 110 { if o < cap-1 { out[o] = 10 as u8; o = o + 1 } } else {
1469 if e == 116 { if o < cap-1 { out[o] = 9 as u8; o = o + 1 } } else {
1470 if e == 34 { if o < cap-1 { out[o] = 34 as u8; o = o + 1 } } else {
1471 if e == 92 { if o < cap-1 { out[o] = 92 as u8; o = o + 1 } } else {
1472 if o < cap-1 { out[o] = buf[k]; o = o + 1 } } } } }
1473 }
1474 k = k + 1
1475 } else {
1476 if o < cap-1 { out[o] = buf[k]; o = o + 1 }
1477 k = k + 1
1478 } }
1479 }
1480 }
1481 out[o] = 0 as u8
1482 return o
1483}
1484// flatten a doc spec (H/B/I/P lines; T table rows) into plain running text for the LLM prompt (strip the 2-char
1485// kind prefix, '|' table cells -> spaces). Keeps only the tail (last ~cap chars) since the 0.5B context is small.
1486func of_spec_to_text(spec: *u8, sl: i64, out: *u8, cap: i64) -> i64 {
1487 let tmp: *u8 = sys_mmap(sl + 16)
1488 var to: i64 = 0
1489 var i: i64 = 0
1490 while i < sl {
1491 var e: i64 = i
1492 while e < sl { if spec[e] == (10 as u8) { break } e = e + 1 }
1493 var cs: i64 = i
1494 if e >= i + 2 { if spec[i+1] == (32 as u8) { cs = i + 2 } }
1495 var k: i64 = cs
1496 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 }
1497 tmp[to] = 32 as u8; to = to + 1
1498 i = e + 1
1499 }
1500 // keep the tail
1501 var start: i64 = 0
1502 if to > cap { start = to - cap }
1503 var oo: i64 = 0
1504 var t: i64 = start
1505 while t < to { if oo < cap - 1 { out[oo] = tmp[t]; oo = oo + 1 } t = t + 1 }
1506 out[oo] = 0 as u8
1507 return oo
1508}
1509// call our sovereign LLM seat (POST /complete on 127.0.0.1:11434) to continue `prompt`. Fills out with the
1510// completion (JSON-unescaped); returns length, or <0 on conn-fail / non-200 / empty (caller -> graceful 503).
1511// max_tokens is a PARAMETER (of_llm_complete keeps the proven 24 default) because agent mode needs a longer
1512// budget for its PLAN turn than for a step turn. Keep every value small enough that ONE call finishes well
1513// under the edge's ~15s proxy timeout -- measured ~0.29s/token, so 32 tokens ~= 9.3s is the safe ceiling.
1514func of_llm_complete_n(prompt: *u8, plen: i64, out: *u8, cap: i64, maxtok: i64) -> i64 {
1515 let bcap: i64 = plen * 2 + 256
1516 let jb: *u8 = sys_mmap(bcap)
1517 var bo: i64 = of_cat(jb, 0, "{\"content\":\"" as *u8)
1518 var i: i64 = 0
1519 while i < plen {
1520 let c: i64 = prompt[i] as i64
1521 if c == 34 { jb[bo] = 92 as u8; bo = bo + 1; jb[bo] = 34 as u8; bo = bo + 1 } else {
1522 if c == 92 { jb[bo] = 92 as u8; bo = bo + 1; jb[bo] = 92 as u8; bo = bo + 1 } else {
1523 if c == 10 { jb[bo] = 92 as u8; bo = bo + 1; jb[bo] = 110 as u8; bo = bo + 1 } else {
1524 if c == 9 { jb[bo] = 32 as u8; bo = bo + 1 } else {
1525 if c == 13 { } else {
1526 if c < 32 { jb[bo] = 32 as u8; bo = bo + 1 } else { jb[bo] = prompt[i]; bo = bo + 1 } } } } } }
1527 i = i + 1
1528 }
1529 bo = of_cat(jb, bo, "\",\"max_tokens\":" as *u8)
1530 bo = of_catn(jb, bo, maxtok)
1531 bo = of_catc(jb, bo, 125)
1532 jb[bo] = 0 as u8
1533 let addr: *u8 = sys_mmap(16)
1534 nx_http_client_sockaddr_ipv4(addr, 127, 0, 0, 1, 11434)
1535 let fd: i64 = sys_socket(2, 1, 0)
1536 if fd < 0 { return 0 - 1 }
1537 if nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { sys_close(fd); return 0 - 2 }
1538 sys_set_socket_timeout(fd, 14)
1539 let ct: *u8 = "application/json" as *u8
1540 let req: *u8 = sys_mmap(8192 + bo)
1541 let reqlen: i64 = nx_http_client_build_request_post("/complete" as *u8, 9, "localhost" as *u8, 9, ct, 16, jb, bo, req)
1542 sys_write(fd, req, reqlen)
1543 let resp: *u8 = sys_mmap(262144)
1544 var rn: i64 = 0
1545 var go: i64 = 1
1546 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 } } }
1547 sys_close(fd)
1548 if rn < 15 { return 0 - 3 }
1549 if (resp[9] as i64) != 50 { return 0 - 4 }
1550 if (resp[10] as i64) != 48 { return 0 - 4 }
1551 if (resp[11] as i64) != 48 { return 0 - 4 }
1552 resp[rn] = 0 as u8
1553 let cl: i64 = of_extract_json_content(resp, rn, out, cap)
1554 if cl <= 0 { return 0 - 5 }
1555 return cl
1556}
1557func of_llm_complete(prompt: *u8, plen: i64, out: *u8, cap: i64) -> i64 {
1558 return of_llm_complete_n(prompt, plen, out, cap, 24)
1559}
1560// OF-A2 / OF-A3: each kind gets its OWN prompt builder rather than one function with a kind flag, so the
1561// census can needle a DEFINITION per axis (its own anti-faking law: a comment mentioning a bare name must
1562// never flip an axis) and each stays independently editable.
1563func of_ai_prompt_sheet(ptext: *u8, out: *u8) -> i64 {
1564 var o: i64 = of_cat(out, 0, "This is a spreadsheet, tab separated. Data: " as *u8)
1565 o = of_cat(out, o, ptext)
1566 o = of_cat(out, o, " . State one short insight about this data:" as *u8)
1567 out[o] = 0 as u8
1568 return o
1569}
1570func of_ai_prompt_deck(ptext: *u8, out: *u8) -> i64 {
1571 var o: i64 = of_cat(out, 0, "Slides so far: " as *u8)
1572 o = of_cat(out, o, ptext)
1573 o = of_cat(out, o, " . Write the next slide as a title, then one bullet:" as *u8)
1574 out[o] = 0 as u8
1575 return o
1576}
1577
1578// ================= OF-A4 AGENT MODE -- multi-step PLAN -> EXECUTE -> REFINE =========================
1579// The 2025/2026 headline differentiator the SOTA bar names (M365 Copilot "Agent Mode" GA 2026-04-22:
1580// Copilot plans, executes and refines MULTI-STEP work in the app). Ours runs on OUR OWN sovereign seat.
1581//
1582// WHY IT IS STEP-DRIVEN, NOT A SINGLE LONG CALL: one LLM turn costs ~7-10s and the edge proxy times out at
1583// ~15s. A 4-step agent in one request would ALWAYS exceed it. So each POST /office/agent advances EXACTLY
1584// ONE turn and persists its state; the loop is driven by repeated POSTs. That is a real constraint honestly
1585// handled, not a reduced capability -- the agent is still multi-step, state-carrying and resumable.
1586//
1587// WHERE THE EXCEEDS IS: every executed step lands as a NEW ADDITIVE VERSION through of_save, so the entire
1588// agent trajectory is diffable and restorable. The cloud leaders' agent steps are ephemeral -- you get the
1589// final artifact and the reasoning is gone. Ours is content-addressed history you can walk backwards.
1590//
1591// State lives in a SIDECAR <root>/<name>/agent.txt so the document spec stays PURE CONTENT (no new spec line
1592// kinds = no renderer risk, no format migration). Line-based, same idiom as the spec:
1593// G <goal> one line, the operator's goal
1594// S <step> one line per planned step, in order
1595// D <n> how many turns are DONE. n in 0..steps = executing; n > steps = refined + complete.
1596func of_agent_path(root: *u8, name: *u8, out: *u8) -> i64 {
1597 var o: i64 = of_cat(out, 0, root); o = of_cat(out, o, "/" as *u8); o = of_cat(out, o, name)
1598 o = of_cat(out, o, "/agent.txt" as *u8); out[o] = 0 as u8
1599 return o
1600}
1601func of_agent_read(root: *u8, name: *u8, buf: *u8, cap: i64) -> i64 {
1602 let p: *u8 = sys_mmap(512)
1603 of_agent_path(root, name, p)
1604 return of_read_file(p, buf, cap)
1605}
1606func of_agent_write(root: *u8, name: *u8, buf: *u8, n: i64) -> i64 {
1607 let p: *u8 = sys_mmap(512)
1608 of_agent_path(root, name, p)
1609 return of_write_file(p, buf, n)
1610}
1611// count the lines whose FIRST byte is `tag` (tags: 71='G' 83='S' 68='D')
1612func of_agent_tagcount(buf: *u8, n: i64, tag: i64) -> i64 {
1613 var c: i64 = 0
1614 var i: i64 = 0
1615 var bol: i64 = 1
1616 while i < n {
1617 if bol == 1 { if (buf[i] as i64) == tag { c = c + 1 } }
1618 if buf[i] == (10 as u8) { bol = 1 } else { bol = 0 }
1619 i = i + 1
1620 }
1621 return c
1622}
1623// copy the body of the idx-th (0-based) line carrying `tag` into out; returns its length (0 = no such line)
1624func of_agent_tagline(buf: *u8, n: i64, tag: i64, idx: i64, out: *u8, cap: i64) -> i64 {
1625 var seen: i64 = 0
1626 var i: i64 = 0
1627 var bol: i64 = 1
1628 while i < n {
1629 if bol == 1 {
1630 if (buf[i] as i64) == tag {
1631 if seen == idx {
1632 var s: i64 = i + 1
1633 if s < n { if buf[s] == (32 as u8) { s = s + 1 } }
1634 var o: i64 = 0
1635 while s < n {
1636 if buf[s] == (10 as u8) { s = n } else {
1637 if o < cap - 1 { out[o] = buf[s]; o = o + 1 }
1638 s = s + 1 }
1639 }
1640 out[o] = 0 as u8
1641 return o
1642 }
1643 seen = seen + 1
1644 }
1645 }
1646 if buf[i] == (10 as u8) { bol = 1 } else { bol = 0 }
1647 i = i + 1
1648 }
1649 out[0] = 0 as u8
1650 return 0
1651}
1652func of_agent_done(buf: *u8, n: i64) -> i64 {
1653 let t: *u8 = sys_mmap(32)
1654 if of_agent_tagline(buf, n, 68, 0, t, 32) <= 0 { return 0 }
1655 return of_atoi(t)
1656}
1657// Turn ONE free-text LLM completion into at most 4 plan steps. Splits on newlines first; if that yields
1658// fewer than 2 steps, falls back to splitting on ". " so a single-line reply still becomes a real plan.
1659// Leading list punctuation (digits, '.', ')', '-', '*', spaces) is stripped so "1. Draft intro" -> "Draft intro".
1660// Emits "S <step>\n" lines into out. Returns how many steps were written (0 = the model gave us nothing usable).
1661func of_agent_plan_parse(comp: *u8, cl: i64, out: *u8, cap: i64) -> i64 {
1662 var steps: i64 = 0
1663 var o: i64 = 0
1664 var ph: i64 = 0
1665 while ph < 2 {
1666 steps = 0
1667 o = 0
1668 var i: i64 = 0
1669 while i < cl {
1670 if steps >= 4 { i = cl } else {
1671 // find the end of this chunk: newline always ends it; in phase 1 ". " ends it too
1672 var e: i64 = i
1673 var scan: i64 = 1
1674 while scan == 1 {
1675 if e >= cl { scan = 0 } else {
1676 if comp[e] == (10 as u8) { scan = 0 } else {
1677 var brk: i64 = 0
1678 if ph == 1 {
1679 if comp[e] == (46 as u8) {
1680 if e + 1 < cl { if comp[e+1] == (32 as u8) { brk = 1 } }
1681 }
1682 }
1683 if brk == 1 { scan = 0 } else { e = e + 1 }
1684 }
1685 }
1686 }
1687 // strip leading list punctuation + spaces: "1. Draft intro" -> "Draft intro"
1688 var s: i64 = i
1689 var strip: i64 = 1
1690 while strip == 1 {
1691 if s >= e { strip = 0 } else {
1692 let c: i64 = comp[s] as i64
1693 if c == 32 { s = s + 1 } else {
1694 if c == 46 { s = s + 1 } else {
1695 if c == 41 { s = s + 1 } else {
1696 if c == 45 { s = s + 1 } else {
1697 if c == 42 { s = s + 1 } else {
1698 if c >= 48 { if c <= 57 { s = s + 1 } else { strip = 0 } } else { strip = 0 } } } } } }
1699 }
1700 }
1701 // keep it only if real text survives (>= 4 chars) and it fits the buffer
1702 if e - s >= 4 {
1703 if o + (e - s) + 8 < cap {
1704 o = of_cat(out, o, "S " as *u8)
1705 var k: i64 = s
1706 var w: i64 = 0
1707 while k < e {
1708 if w < 120 {
1709 let c2: i64 = comp[k] as i64
1710 if c2 == 9 { out[o] = 32 as u8 } else { if c2 == 13 { out[o] = 32 as u8 } else { out[o] = comp[k] } }
1711 o = o + 1; w = w + 1
1712 }
1713 k = k + 1
1714 }
1715 o = of_catc(out, o, 10)
1716 steps = steps + 1
1717 }
1718 }
1719 i = e + 1
1720 }
1721 }
1722 // phase 0 (newline split) wins if it found a real multi-step plan; else retry splitting sentences
1723 if steps >= 2 { ph = 2 } else { ph = ph + 1 }
1724 }
1725 out[o] = 0 as u8
1726 return steps
1727}
1728// Insert Content-Length before the header terminator so a STRICT HTTP client (the sovereign Nishi Browser)
1729// can frame the body. Static docroot files send it; our HTML pages (of_page_top) did NOT, so the in-browser
1730// GET of /office failed to frame after a clean TLS handshake (Waterfox tolerates it by reading until close).
1731// out holds a full "HTTP/.. \r\n<headers>\r\n\r\n<body>" of length n; returns the new length. Idempotent
1732// (skips if Content-Length already present, e.g. of_serve downloads) and fail-safe (no room -> unchanged).
1733func of_cl_frame(out: *u8, n: i64, cap: i64) -> i64 {
1734 if n <= 0 { return n }
1735 var p: i64 = 0 - 1
1736 var i: i64 = 0
1737 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 }
1738 if p < 0 { return n }
1739 if of_memhas(out, p, "Content-Length:" as *u8) == 1 { return n }
1740 let bodylen: i64 = n - (p + 4)
1741 let ins: *u8 = sys_mmap(48)
1742 var io: i64 = of_cat(ins, 0, "Content-Length: " as *u8)
1743 io = of_catn(ins, io, bodylen)
1744 io = of_catc(ins, io, 13); io = of_catc(ins, io, 10)
1745 if n + io >= cap { return n }
1746 var s: i64 = n - 1
1747 while s >= p + 2 { out[s + io] = out[s]; s = s - 1 }
1748 var k: i64 = 0
1749 while k < io { out[p + 2 + k] = ins[k]; k = k + 1 }
1750 return n + io
1751}
1752// serve <root>/<name>/v<N>/{file.<ext>|preview.html}. mode 0 = artifact download, 1 = preview html.
1753func of_serve(root: *u8, name: *u8, vn: i64, mode: i64, out: *u8, cap: i64) -> i64 {
1754 let kb: *u8 = sys_mmap(64)
1755 let vc: i64 = of_manifest_count(root, name, kb, 64)
1756 if vc <= 0 { return 0 - 1 }
1757 if vn < 1 { return 0 - 1 }
1758 if vn > vc { return 0 - 1 }
1759 let ki: i64 = of_kind_idx(kb)
1760 var ks: i64 = ki
1761 if ks < 0 { ks = 0 }
1762 let vd: *u8 = sys_mmap(512)
1763 of_vdir(root, name, vn, vd)
1764 let fp: *u8 = sys_mmap(600)
1765 var fo: i64 = of_cat(fp, 0, vd)
1766 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)) }
1767 fp[fo] = 0 as u8
1768 let fb: *u8 = sys_mmap(1048576)
1769 let fl: i64 = of_read_file(fp, fb, 1048576)
1770 if fl < 0 { return 0 - 1 }
1771 var o: i64 = of_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8)
1772 if mode == 1 { o = of_cat(out, o, "text/html; charset=utf-8" as *u8) } else { o = of_cat(out, o, of_ct(ks)) }
1773 o = of_cat(out, o, "\r\nContent-Length: " as *u8)
1774 o = of_catn(out, o, fl)
1775 if mode == 0 {
1776 o = of_cat(out, o, "\r\nContent-Disposition: attachment; filename=" as *u8)
1777 o = of_cat(out, o, name)
1778 o = of_cat(out, o, "." as *u8)
1779 o = of_cat(out, o, of_ext(ks))
1780 }
1781 o = of_cat(out, o, "\r\n\r\n" as *u8)
1782 var i: i64 = 0
1783 while i < fl { if o + i < cap { out[o + i] = fb[i] } i = i + 1 }
1784 return o + fl
1785}
1786// parse "/<pfx>/<name>/v<N>" -> name + N. returns N (>=1) or -1.
1787func of_parse_nv(path: *u8, pfxlen: i64, name: *u8, ncap: i64) -> i64 {
1788 var i: i64 = pfxlen
1789 var t: i64 = 0
1790 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 }
1791 name[t] = 0 as u8
1792 if t == 0 { return 0 - 1 }
1793 if path[i] != (47 as u8) { return 0 - 1 }
1794 i = i + 1
1795 if path[i] != (118 as u8) { return 0 - 1 }
1796 i = i + 1
1797 var v: i64 = 0
1798 var d: i64 = 0
1799 while path[i] != (0 as u8) {
1800 let c: i64 = path[i] as i64
1801 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 }
1802 }
1803 if d == 0 { return 0 - 1 }
1804 return v
1805}
1806
1807// the app: request bytes -> response bytes. returns response length.
1808// base = the URL mount prefix (e.g. "/office" when reverse-proxied at nishifamily.com/office, "" for the raw
1809// daemon). The edge forwards the FULL path verbatim, so we STRIP base off the incoming path before routing while
1810// build "doc:<name>" / "user:<handle>" refs for the ReBAC plane.
1811func 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 }
1812func 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 }
1813func 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 }
1814// the userset "group:<g>#member" -- sharing a doc with THIS grants every member of the group (Zanzibar userset).
1815func 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 }
1816// a share target handle must be [a-zA-Z0-9_-] 1..64 -- so ':' or '#' can never forge a type/userset in a tuple ref.
1817func of_tok_ok(s: *u8) -> i64 {
1818 if s[0] == (0 as u8) { return 0 }
1819 var i: i64 = 0
1820 while s[i] != (0 as u8) {
1821 let c: i64 = s[i] as i64
1822 var ok: i64 = 0
1823 if c >= 97 { if c <= 122 { ok = 1 } }
1824 if c >= 65 { if c <= 90 { ok = 1 } }
1825 if c >= 48 { if c <= 57 { ok = 1 } }
1826 if c == 95 { ok = 1 }
1827 if c == 45 { ok = 1 }
1828 if ok == 0 { return 0 }
1829 if i >= 64 { return 0 }
1830 i = i + 1
1831 }
1832 return 1
1833}
1834func of_sess_field(dst: *u8, off: i64, tok: *u8) -> i64 {
1835 var o: i64 = off
1836 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) }
1837 return o
1838}
1839// authz refusal (fail-closed: owned doc, caller not allowed).
1840func of_deny_read(out: *u8) -> i64 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
1841func 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) }
1842func 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 }
1843// read/write authorization for a doc by name. UNOWNED = PUBLIC (1). OWNED = the caller needs the relation.
1844func of_read_ok(azprefix: *u8, me: *u8, authed: i64, nm: *u8) -> i64 {
1845 let dref: *u8 = sys_mmap(320); of_docref(dref, nm)
1846 if rb_obj_has_owner(azprefix, dref) == 0 { return 1 }
1847 if authed == 0 { return 0 }
1848 return rb_check2(azprefix, OF_RELATE, me, "read" as *u8, dref, 0)
1849}
1850func of_write_ok(azprefix: *u8, me: *u8, authed: i64, nm: *u8) -> i64 {
1851 let dref: *u8 = sys_mmap(320); of_docref(dref, nm)
1852 if rb_obj_has_owner(azprefix, dref) == 0 { return 1 }
1853 if authed == 0 { return 0 }
1854 return rb_check2(azprefix, OF_RELATE, me, "write" as *u8, dref, 0)
1855}
1856// SHARE(grant=1)/UNSHARE(grant=0) an OWNED doc -- owner-only. doc:<name> viewer|editor user:<who>.
1857func of_do_share(base: *u8, azprefix: *u8, me: *u8, handle: *u8, authed: i64, body: *u8, blen: i64, out: *u8, grant: i64) -> i64 {
1858 if authed == 0 { return of_deny_write(out) }
1859 let nm: *u8 = sys_mmap(64); let who: *u8 = sys_mmap(64); let lv: *u8 = sys_mmap(16)
1860 of_form_get(body, blen, "name" as *u8, nm, 64)
1861 of_form_get(body, blen, "who" as *u8, who, 64)
1862 of_form_get(body, blen, "level" as *u8, lv, 16)
1863 if of_name_ok(nm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
1864 if of_tok_ok(who) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad handle" as *u8) }
1865 let dref: *u8 = sys_mmap(320); of_docref(dref, nm)
1866 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) }
1867 if rb_check(azprefix, me, "manage" as *u8, dref, 0) == 0 { return of_deny_write(out) }
1868 var rel: *u8 = "viewer" as *u8
1869 if of_seq(lv, "editor" as *u8) == 1 { rel = "editor" as *u8 }
1870 // target=group -> share with the userset group:<who>#member (every group member gets access); else a person.
1871 let tgt: *u8 = sys_mmap(16); of_form_get(body, blen, "target" as *u8, tgt, 16)
1872 let wref: *u8 = sys_mmap(320)
1873 if of_seq(tgt, "group" as *u8) == 1 { of_grpmemberref(wref, who) } else { of_meref(wref, who) }
1874 rb_put(azprefix, dref, rel, wref, handle, grant)
1875 var o: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
1876 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)
1877 return o
1878}
1879// copy s into dst up to a '#' (or end), NUL-term. "elders#member" -> "elders".
1880func 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 }
1881// render one shared-with row + its unshare button. subref = "user:<h>" (a person) OR "group:<g>#member" (a group).
1882func of_share_row(out: *u8, off: i64, base: *u8, nm: *u8, subref: *u8, rel: *u8, tok: *u8) -> i64 {
1883 var target: *u8 = "user" as *u8
1884 let who: *u8 = sys_mmap(96)
1885 let label: *u8 = sys_mmap(128)
1886 if of_starts(subref, "group:" as *u8) == 1 {
1887 target = "group" as *u8
1888 of_before_hash(who, of_after_colon(subref))
1889 var lo: i64 = of_cat(label, 0, "group " as *u8); lo = of_cat(label, lo, who); label[lo] = 0 as u8
1890 } else {
1891 var wo: i64 = of_cat(who, 0, of_after_colon(subref)); who[wo] = 0 as u8
1892 var lo: i64 = of_cat(label, 0, who); label[lo] = 0 as u8
1893 }
1894 var o: i64 = of_cat(out, off, "<div class='row'>" as *u8)
1895 o = of_cat(out, o, label); o = of_cat(out, o, " <span class='mut'>" as *u8); o = of_cat(out, o, rel)
1896 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)
1897 o = of_sess_field(out, o, tok)
1898 o = of_cat(out, o, "<input type='hidden' name='name' value='" as *u8); o = of_cat(out, o, nm)
1899 o = of_cat(out, o, "'><input type='hidden' name='who' value='" as *u8); o = of_cat(out, o, who)
1900 o = of_cat(out, o, "'><input type='hidden' name='target' value='" as *u8); o = of_cat(out, o, target)
1901 o = of_cat(out, o, "'><input type='hidden' name='level' value='" as *u8); o = of_cat(out, o, rel)
1902 o = of_cat(out, o, "'><button class='ghost'>unshare</button></form></div>" as *u8)
1903 return o
1904}
1905// the owner's Sharing panel for a doc. returns inner-HTML length, or negative (=-1 unauth / -2 not-owned / -3 not-owner).
1906func of_managepage(base: *u8, azprefix: *u8, me: *u8, authed: i64, nm: *u8, tok: *u8, out: *u8, cap: i64) -> i64 {
1907 let dref: *u8 = sys_mmap(320); of_docref(dref, nm)
1908 if authed == 0 { return 0 - 1 }
1909 if rb_obj_has_owner(azprefix, dref) == 0 { return 0 - 2 }
1910 if rb_check(azprefix, me, "manage" as *u8, dref, 0) == 0 { return 0 - 3 }
1911 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)
1912 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)
1913 let vv: *i64 = sys_mmap(8 * 64) as *i64
1914 let nv: i64 = rb_list_subjects(azprefix, dref, "viewer" as *u8, vv, 64)
1915 let ee: *i64 = sys_mmap(8 * 64) as *i64
1916 let ne: i64 = rb_list_subjects(azprefix, dref, "editor" as *u8, ee, 64)
1917 if nv == 0 { if ne == 0 { o = of_cat(out, o, "<div class='mut'>(not shared with anyone yet)</div>" as *u8) } }
1918 var qi: i64 = 0
1919 while qi < ne { o = of_share_row(out, o, base, nm, ee[qi] as *u8, "editor" as *u8, tok); qi = qi + 1 }
1920 qi = 0
1921 while qi < nv { o = of_share_row(out, o, base, nm, vv[qi] as *u8, "viewer" as *u8, tok); qi = qi + 1 }
1922 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)
1923 o = of_sess_field(out, o, tok)
1924 o = of_cat(out, o, "<input type='hidden' name='name' value='" as *u8); o = of_cat(out, o, nm)
1925 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)
1926 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)
1927 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)
1928 return o
1929}
1930
1931// GROUP membership handler: add(1)/remove(0) a member. The caller bootstraps/owns the group. 303 -> /groups.
1932func of_do_group(base: *u8, azprefix: *u8, me: *u8, handle: *u8, authed: i64, body: *u8, blen: i64, out: *u8, add: i64) -> i64 {
1933 if authed == 0 { return of_deny_write(out) }
1934 let gn: *u8 = sys_mmap(64); let who: *u8 = sys_mmap(64)
1935 of_form_get(body, blen, "group" as *u8, gn, 64)
1936 of_form_get(body, blen, "who" as *u8, who, 64)
1937 if of_tok_ok(gn) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad group name" as *u8) }
1938 if of_tok_ok(who) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad handle" as *u8) }
1939 let gref: *u8 = sys_mmap(320); of_grpref(gref, gn)
1940 if rb_may_grant(azprefix, me, gref) == 0 { return of_deny_write(out) }
1941 if rb_obj_has_owner(azprefix, gref) == 0 {
1942 rb_put(azprefix, gref, "owner" as *u8, me, handle, 1)
1943 rb_put(azprefix, gref, "member" as *u8, me, handle, 1)
1944 }
1945 let wref: *u8 = sys_mmap(320); of_meref(wref, who)
1946 rb_put(azprefix, gref, "member" as *u8, wref, handle, add)
1947 var o: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
1948 o = of_cat(out, o, base); o = of_cat(out, o, "/groups\r\n\r\n" as *u8)
1949 return o
1950}
1951// the caller's GROUPS page (owned groups + members + management forms). returns a FULL HTTP response.
1952func of_groupspage(base: *u8, azprefix: *u8, me: *u8, authed: i64, tok: *u8, out: *u8, cap: i64) -> i64 {
1953 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)
1954 if authed == 0 { o = of_cat(out, o, "<p>Sign in to manage groups.</p></body></html>" as *u8); return o }
1955 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)
1956 let gg: *i64 = sys_mmap(8 * 64) as *i64
1957 let ng: i64 = rb_list_objects_for_sub(azprefix, me, "owner" as *u8, gg, 64)
1958 if ng == 0 { o = of_cat(out, o, "<div class='mut'>(no groups yet -- create one below)</div>" as *u8) }
1959 var gi: i64 = 0
1960 while gi < ng {
1961 let gref: *u8 = gg[gi] as *u8
1962 let gbare: *u8 = of_after_colon(gref)
1963 o = of_cat(out, o, "<h3>" as *u8); o = of_cat(out, o, gbare); o = of_cat(out, o, "</h3>" as *u8)
1964 let mm: *i64 = sys_mmap(8 * 64) as *i64
1965 let nm2: i64 = rb_list_subjects(azprefix, gref, "member" as *u8, mm, 64)
1966 var mi: i64 = 0
1967 while mi < nm2 {
1968 let mbare: *u8 = of_after_colon(mm[mi] as *u8)
1969 o = of_cat(out, o, "<div class='row'>" as *u8); o = of_cat(out, o, mbare)
1970 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)
1971 o = of_sess_field(out, o, tok)
1972 o = of_cat(out, o, "<input type='hidden' name='group' value='" as *u8); o = of_cat(out, o, gbare)
1973 o = of_cat(out, o, "'><input type='hidden' name='who' value='" as *u8); o = of_cat(out, o, mbare)
1974 o = of_cat(out, o, "'><button class='ghost'>remove</button></form></div>" as *u8)
1975 mi = mi + 1
1976 }
1977 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)
1978 o = of_sess_field(out, o, tok)
1979 o = of_cat(out, o, "<input type='hidden' name='group' value='" as *u8); o = of_cat(out, o, gbare)
1980 o = of_cat(out, o, "'><input name='who' placeholder='handle to add'><button>Add member</button></form>" as *u8)
1981 gi = gi + 1
1982 }
1983 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)
1984 o = of_sess_field(out, o, tok)
1985 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)
1986 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)
1987 return o
1988}
1989
1990// REVERSE INDEX: append the doc: objects where (obj, rel, sub) is current into out[] (deduped). returns new count.
1991func of_collect_docs(azprefix: *u8, sub: *u8, rel: *u8, out: *i64, n: i64, cap: i64) -> i64 {
1992 let tmp: *i64 = sys_mmap(8 * 64) as *i64
1993 let k: i64 = rb_list_objects_for_sub(azprefix, sub, rel, tmp, 64)
1994 var i: i64 = 0; var nn: i64 = n
1995 while i < k {
1996 let o: *u8 = tmp[i] as *u8
1997 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 } } }
1998 i = i + 1
1999 }
2000 return nn
2001}
2002// "what documents can I access?" -- the reverse-index query: docs I own/view/edit DIRECTLY, plus docs shared with
2003// any GROUP I'm a member of (userset expansion on the read side). Deduped. This is the SOTA list-objects primitive.
2004func of_my_docs(azprefix: *u8, me: *u8, out: *i64, cap: i64) -> i64 {
2005 var n: i64 = 0
2006 n = of_collect_docs(azprefix, me, "owner" as *u8, out, n, cap)
2007 n = of_collect_docs(azprefix, me, "viewer" as *u8, out, n, cap)
2008 n = of_collect_docs(azprefix, me, "editor" as *u8, out, n, cap)
2009 let grps: *i64 = sys_mmap(8 * 64) as *i64
2010 let ng: i64 = rb_list_objects_for_sub(azprefix, me, "member" as *u8, grps, 64)
2011 var gi: i64 = 0
2012 while gi < ng {
2013 let g: *u8 = grps[gi] as *u8
2014 if of_starts(g, "group:" as *u8) == 1 {
2015 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
2016 n = of_collect_docs(azprefix, gm, "viewer" as *u8, out, n, cap)
2017 n = of_collect_docs(azprefix, gm, "editor" as *u8, out, n, cap)
2018 }
2019 gi = gi + 1
2020 }
2021 return n
2022}
2023// the "Shared with me" page: every doc the caller can reach (direct or via a group). FULL HTTP response.
2024func of_sharedpage(base: *u8, azprefix: *u8, me: *u8, authed: i64, out: *u8, cap: i64) -> i64 {
2025 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)
2026 if authed == 0 { o = of_cat(out, o, "<p>Sign in to see documents shared with you.</p></body></html>" as *u8); return o }
2027 let docs: *i64 = sys_mmap(8 * 128) as *i64
2028 let nd: i64 = of_my_docs(azprefix, me, docs, 128)
2029 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)
2030 if nd == 0 { o = of_cat(out, o, "<div class='mut'>(nothing yet)</div>" as *u8) }
2031 var di: i64 = 0
2032 while di < nd {
2033 let dbare: *u8 = of_after_colon(docs[di] as *u8)
2034 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)
2035 di = di + 1
2036 }
2037 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)
2038 return o
2039}
2040
2041// generated links KEEP base -> the app is mount-point agnostic (works at :8030/ and at nishifamily.com/office/).
2042// OPEN-MODE wrapper: no handle -> no authz gating (current PUBLIC behavior; the 34-test offline gate runs here).
2043func of_handle(root: *u8, base: *u8, req: *u8, reqlen: i64, out: *u8, cap: i64) -> i64 {
2044 let mt: *u8 = sys_mmap(8); mt[0] = 0 as u8
2045 return of_handle_auth(root, base, req, reqlen, out, cap, mt, OF_AUTHZ, mt)
2046}
2047// AUTH-AWARE handler. handle = resolved caller ("" = unauthed/open). azprefix = ReBAC tuple store. tok = session
2048// token embedded in owner forms (zero-JS). A doc with NO owner tuple is PUBLIC; an OWNED doc: read needs
2049// rb_check(user:me, read, doc), a new version needs write, only the owner may share/unshare/manage.
2050func of_handle_auth(root: *u8, base: *u8, req: *u8, reqlen: i64, out: *u8, cap: i64, handle: *u8, azprefix: *u8, tok: *u8) -> i64 {
2051 var authed: i64 = 0; let me: *u8 = sys_mmap(320); me[0] = 0 as u8
2052 if handle[0] != (0 as u8) { authed = 1; of_meref(me, handle) }
2053 // fullpath = token between the first two spaces
2054 let fullpath: *u8 = sys_mmap(300)
2055 var i: i64 = 0
2056 while i < reqlen { if req[i] == (32 as u8) { i = i + 1; break } i = i + 1 }
2057 var t: i64 = 0
2058 while i < reqlen { if req[i] == (32 as u8) { break } if t < 299 { fullpath[t] = req[i]; t = t + 1 } i = i + 1 }
2059 fullpath[t] = 0 as u8
2060 // split off the query string (home search/sort/filter reads it) so routing sees a clean path
2061 let qs: *u8 = sys_mmap(300)
2062 qs[0] = 0 as u8
2063 var qi: i64 = 0
2064 while fullpath[qi] != (0 as u8) {
2065 if fullpath[qi] == (63 as u8) {
2066 var qq: i64 = qi + 1
2067 var qt: i64 = 0
2068 while fullpath[qq] != (0 as u8) { if qt < 299 { qs[qt] = fullpath[qq]; qt = qt + 1 } qq = qq + 1 }
2069 qs[qt] = 0 as u8
2070 fullpath[qi] = 0 as u8
2071 } else { qi = qi + 1 }
2072 }
2073 // strip the mount prefix -> path is relative to the app root ("/office/doc/x" -> "/doc/x", "/office" -> "")
2074 var path: *u8 = fullpath
2075 if base[0] != (0 as u8) {
2076 var bm: i64 = 1
2077 var bi: i64 = 0
2078 while base[bi] != (0 as u8) { if fullpath[bi] != base[bi] { bm = 0; bi = of_slen(base) } else { bi = bi + 1 } }
2079 if bm == 1 { path = (fullpath as i64 + of_slen(base)) as *u8 }
2080 }
2081 var is_post: i64 = 0
2082 if req[0] == (80 as u8) { if req[1] == (79 as u8) { is_post = 1 } }
2083 if is_post == 1 {
2084 var is_save: i64 = of_seq(path, "/save" as *u8)
2085 var is_restore: i64 = of_seq(path, "/restore" as *u8)
2086 var is_share: i64 = of_seq(path, "/share" as *u8)
2087 var is_unshare: i64 = of_seq(path, "/unshare" as *u8)
2088 var is_gadd: i64 = of_seq(path, "/group-add" as *u8)
2089 var is_gremove: i64 = of_seq(path, "/group-remove" as *u8)
2090 var is_ai: i64 = of_seq(path, "/ai" as *u8)
2091 var is_agent: i64 = of_seq(path, "/agent" as *u8)
2092 var is_star: i64 = of_seq(path, "/star" as *u8)
2093 var is_folder: i64 = of_seq(path, "/folder" as *u8)
2094 if (is_save + is_restore + is_share + is_unshare + is_gadd + is_gremove + is_ai + is_agent + is_star + is_folder) == 0 { return of_err(out, "404 Not Found" as *u8, "no such POST route" as *u8) }
2095 // same-origin guard: if Origin present it must contain our Host
2096 let ob: *u8 = sys_mmap(300)
2097 let hb: *u8 = sys_mmap(300)
2098 of_hdr_get(req, reqlen, "Origin:" as *u8, ob, 300)
2099 of_hdr_get(req, reqlen, "Host:" as *u8, hb, 300)
2100 if ob[0] != (0 as u8) { if hb[0] != (0 as u8) {
2101 if of_memhas(ob, of_slen(ob), hb) == 0 { return of_err(out, "403 Forbidden" as *u8, "cross-origin POST refused" as *u8) }
2102 } }
2103 var bs: i64 = 0 - 1
2104 var j: i64 = 0
2105 while j + 3 < reqlen {
2106 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 } } } }
2107 j = j + 1
2108 }
2109 if bs < 0 { return of_err(out, "400 Bad Request" as *u8, "no body" as *u8) }
2110 let body: *u8 = (req as i64 + bs) as *u8
2111 let blen: i64 = reqlen - bs
2112 // SHARE / UNSHARE an owned doc (owner-only; additive grant / tombstone revoke). GROUP add/remove members.
2113 if is_share == 1 { return of_do_share(base, azprefix, me, handle, authed, body, blen, out, 1) }
2114 if is_unshare == 1 { return of_do_share(base, azprefix, me, handle, authed, body, blen, out, 0) }
2115 if is_gadd == 1 { return of_do_group(base, azprefix, me, handle, authed, body, blen, out, 1) }
2116 if is_gremove == 1 { return of_do_group(base, azprefix, me, handle, authed, body, blen, out, 0) }
2117 // AI CONTINUE: draft a continuation with OUR OWN sovereign 0.5B model (:11434) + append it as a NEW
2118 // version (additive -- the AI draft is a version you can diff/restore). Doc kind only. Graceful 503 if
2119 // the seat is down. Write-gated like a save (owned docs need edit access).
2120 if is_ai == 1 {
2121 let anm: *u8 = sys_mmap(64)
2122 of_form_get(body, blen, "name" as *u8, anm, 64)
2123 if of_name_ok(anm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2124 if of_write_ok(azprefix, me, authed, anm) == 0 { return of_deny_write(out) }
2125 let akb: *u8 = sys_mmap(64)
2126 let avc: i64 = of_manifest_count(root, anm, akb, 64)
2127 if avc <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2128 // ONE sovereign seat, THREE kinds. The prompt AND the append are kind-specific so the model edits each
2129 // artifact in ITS OWN grammar: prose for a doc, an insight ROW for a sheet (OF-A2, the "Fill with
2130 // Gemini" class), a whole new SLIDE for a deck (OF-A3, prompt-to-slide). Every kind stays additive.
2131 let akind: i64 = of_kind_idx(akb)
2132 let aspec: *u8 = sys_mmap(131073)
2133 let asl: i64 = of_read_version_spec(root, anm, avc, aspec, 131072)
2134 let ptext: *u8 = sys_mmap(2048)
2135 let ptl: i64 = of_spec_to_text(aspec, asl, ptext, 1200)
2136 let aprompt: *u8 = sys_mmap(4096)
2137 var api: i64 = 0
2138 if akind == 1 { api = of_ai_prompt_sheet(ptext, aprompt) } else {
2139 if akind == 2 { api = of_ai_prompt_deck(ptext, aprompt) } else { api = of_cat(aprompt, 0, ptext) }
2140 }
2141 aprompt[api] = 0 as u8
2142 let comp: *u8 = sys_mmap(8192)
2143 let cl: i64 = of_llm_complete(aprompt, api, comp, 8000)
2144 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) }
2145 let nspec: *u8 = sys_mmap(140000)
2146 var no: i64 = 0
2147 var ci: i64 = 0
2148 while ci < asl { nspec[no] = aspec[ci]; no = no + 1; ci = ci + 1 }
2149 if no > 0 { if nspec[no-1] != (10 as u8) { nspec[no] = 10 as u8; no = no + 1 } }
2150 if akind == 2 {
2151 // deck: everything up to the first sentence end becomes the TITLE, the remainder the BULLET
2152 var dsp: i64 = 0 - 1
2153 var dfi: i64 = 0
2154 while dfi < cl { if comp[dfi] == (46 as u8) { dsp = dfi; dfi = cl } else { dfi = dfi + 1 } }
2155 var tend: i64 = cl
2156 if dsp > 3 { tend = dsp }
2157 no = of_cat(nspec, no, "S " as *u8)
2158 var dti: i64 = 0
2159 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 }
2160 if dsp > 3 { if dsp + 2 < cl {
2161 no = of_catc(nspec, no, 10)
2162 no = of_cat(nspec, no, "B " as *u8)
2163 var dbi: i64 = dsp + 1
2164 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 }
2165 } }
2166 } else {
2167 // sheet -> a REAL two-cell TSV row so the insight lands IN the grid; doc -> a P paragraph
2168 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) }
2169 var di: i64 = 0
2170 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 }
2171 }
2172 nspec[no] = 0 as u8
2173 let nvn: i64 = of_save(root, base, anm, akb, nspec, no, 0)
2174 if nvn > 0 {
2175 var ao: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2176 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)
2177 return ao
2178 }
2179 return of_err(out, "500 Internal Server Error" as *u8, "AI draft save failed" as *u8)
2180 }
2181 // AGENT MODE (OF-A4, the 2026 marquee): ONE POST = ONE agent turn. PLAN when there is no plan yet (or
2182 // a fresh goal arrives), otherwise EXECUTE the next step, and once every step is drafted run one final
2183 // REFINE turn. Each executed turn lands as a NEW VERSION, so the whole trajectory is diffable/restorable.
2184 // D is bumped ONLY AFTER its version lands, so a 503 mid-run is safely retryable (no step is skipped).
2185 if is_agent == 1 {
2186 let gnm: *u8 = sys_mmap(64)
2187 of_form_get(body, blen, "name" as *u8, gnm, 64)
2188 if of_name_ok(gnm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2189 if of_write_ok(azprefix, me, authed, gnm) == 0 { return of_deny_write(out) }
2190 let gkb: *u8 = sys_mmap(64)
2191 let gvc: i64 = of_manifest_count(root, gnm, gkb, 64)
2192 if gvc <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2193 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) }
2194 let goal: *u8 = sys_mmap(512)
2195 of_form_get(body, blen, "goal" as *u8, goal, 512)
2196 let ast: *u8 = sys_mmap(8192)
2197 let an: i64 = of_agent_read(root, gnm, ast, 8000)
2198 // ground EVERY turn in the CURRENT document, not the one the plan was written against
2199 let gspec: *u8 = sys_mmap(131073)
2200 let gsl: i64 = of_read_version_spec(root, gnm, gvc, gspec, 131072)
2201 let gtext: *u8 = sys_mmap(2048)
2202 let gtl: i64 = of_spec_to_text(gspec, gsl, gtext, 1100)
2203 let agloc: *u8 = sys_mmap(512)
2204
2205 // ---- PLAN turn ----
2206 var want_plan: i64 = 0
2207 if an <= 0 { want_plan = 1 }
2208 if of_slen(goal) > 0 { want_plan = 1 }
2209 if want_plan == 1 {
2210 if of_slen(goal) == 0 { return of_err(out, "400 Bad Request" as *u8, "agent mode needs a goal to plan against" as *u8) }
2211 let pp: *u8 = sys_mmap(4096)
2212 var po2: i64 = of_cat(pp, 0, "You are planning edits to a document. Goal: " as *u8)
2213 po2 = of_cat(pp, po2, goal)
2214 po2 = of_cat(pp, po2, ". Document so far: " as *u8)
2215 po2 = of_cat(pp, po2, gtext)
2216 po2 = of_cat(pp, po2, " . List the steps, one per line:" as *u8)
2217 pp[po2] = 0 as u8
2218 let pcomp: *u8 = sys_mmap(8192)
2219 let pcl: i64 = of_llm_complete_n(pp, po2, pcomp, 8000, 32)
2220 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) }
2221 let plan: *u8 = sys_mmap(4096)
2222 let nst: i64 = of_agent_plan_parse(pcomp, pcl, plan, 4000)
2223 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) }
2224 let nstate: *u8 = sys_mmap(8192)
2225 var so2: i64 = of_cat(nstate, 0, "G " as *u8)
2226 so2 = of_cat(nstate, so2, goal)
2227 so2 = of_catc(nstate, so2, 10)
2228 so2 = of_cat(nstate, so2, plan)
2229 so2 = of_cat(nstate, so2, "D 0\n" as *u8)
2230 nstate[so2] = 0 as u8
2231 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) }
2232 var pl: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2233 pl = of_cat(out, pl, base); pl = of_cat(out, pl, "/doc/" as *u8); pl = of_cat(out, pl, gnm)
2234 pl = of_cat(out, pl, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2235 return pl
2236 }
2237
2238 // ---- EXECUTE / REFINE turn ----
2239 let nsteps: i64 = of_agent_tagcount(ast, an, 83)
2240 let dn: i64 = of_agent_done(ast, an)
2241 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) }
2242 let gg: *u8 = sys_mmap(512)
2243 of_agent_tagline(ast, an, 71, 0, gg, 512)
2244 let sp: *u8 = sys_mmap(4096)
2245 var qo: i64 = 0
2246 if dn < nsteps {
2247 let stx: *u8 = sys_mmap(256)
2248 of_agent_tagline(ast, an, 83, dn, stx, 256)
2249 qo = of_cat(sp, 0, "Goal: " as *u8)
2250 qo = of_cat(sp, qo, gg)
2251 qo = of_cat(sp, qo, ". Now do step " as *u8)
2252 qo = of_catn(sp, qo, dn + 1)
2253 qo = of_cat(sp, qo, ": " as *u8)
2254 qo = of_cat(sp, qo, stx)
2255 qo = of_cat(sp, qo, ". Document so far: " as *u8)
2256 qo = of_cat(sp, qo, gtext)
2257 qo = of_cat(sp, qo, " . Write that section:" as *u8)
2258 } else {
2259 qo = of_cat(sp, 0, "Goal: " as *u8)
2260 qo = of_cat(sp, qo, gg)
2261 qo = of_cat(sp, qo, ". Every step is drafted. Document: " as *u8)
2262 qo = of_cat(sp, qo, gtext)
2263 qo = of_cat(sp, qo, " . Write a short closing paragraph that ties it together:" as *u8)
2264 }
2265 sp[qo] = 0 as u8
2266 let scomp: *u8 = sys_mmap(8192)
2267 let scl: i64 = of_llm_complete(sp, qo, scomp, 8000)
2268 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) }
2269 let gnspec: *u8 = sys_mmap(140000)
2270 var gno: i64 = 0
2271 var gci: i64 = 0
2272 while gci < gsl { gnspec[gno] = gspec[gci]; gno = gno + 1; gci = gci + 1 }
2273 if gno > 0 { if gnspec[gno-1] != (10 as u8) { gnspec[gno] = 10 as u8; gno = gno + 1 } }
2274 gno = of_cat(gnspec, gno, "P " as *u8)
2275 var gdi: i64 = 0
2276 while gdi < scl {
2277 let gc: i64 = scomp[gdi] as i64
2278 if gc == 10 { gnspec[gno] = 32 as u8 } else { if gc == 9 { gnspec[gno] = 32 as u8 } else { gnspec[gno] = scomp[gdi] } }
2279 gno = gno + 1; gdi = gdi + 1
2280 }
2281 gnspec[gno] = 0 as u8
2282 let gvn: i64 = of_save(root, base, gnm, gkb, gnspec, gno, 0)
2283 if gvn <= 0 { return of_err(out, "500 Internal Server Error" as *u8, "agent step save failed" as *u8) }
2284 // the version landed -- NOW advance the cursor
2285 let ns2: *u8 = sys_mmap(8192)
2286 let sbuf: *u8 = sys_mmap(256)
2287 var xo: i64 = of_cat(ns2, 0, "G " as *u8)
2288 xo = of_cat(ns2, xo, gg)
2289 xo = of_catc(ns2, xo, 10)
2290 var si: i64 = 0
2291 while si < nsteps {
2292 of_agent_tagline(ast, an, 83, si, sbuf, 256)
2293 xo = of_cat(ns2, xo, "S " as *u8)
2294 xo = of_cat(ns2, xo, sbuf)
2295 xo = of_catc(ns2, xo, 10)
2296 si = si + 1
2297 }
2298 xo = of_cat(ns2, xo, "D " as *u8)
2299 xo = of_catn(ns2, xo, dn + 1)
2300 xo = of_catc(ns2, xo, 10)
2301 ns2[xo] = 0 as u8
2302 of_agent_write(root, gnm, ns2, xo)
2303 var al: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2304 al = of_cat(out, al, base); al = of_cat(out, al, "/doc/" as *u8); al = of_cat(out, al, gnm)
2305 al = of_cat(out, al, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2306 return al
2307 }
2308 // U3 STAR / FOLDER: library organisation, write-gated exactly like a save so a reader cannot reorganise
2309 // someone else's library. Neither touches the document spec or its versions.
2310 if is_star == 1 {
2311 let snm: *u8 = sys_mmap(64)
2312 of_form_get(body, blen, "name" as *u8, snm, 64)
2313 if of_name_ok(snm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2314 if of_write_ok(azprefix, me, authed, snm) == 0 { return of_deny_write(out) }
2315 let skb: *u8 = sys_mmap(64)
2316 if of_manifest_count(root, snm, skb, 64) <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2317 of_star_toggle(root, snm)
2318 var so: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other
2319
2320Location: " as *u8)
2321 so = of_cat(out, so, base); so = of_cat(out, so, "/" as *u8)
2322 so = of_cat(out, so, "
2323
2324Content-Length: 0
2325
2326Connection: close
2327
2328
2329
2330" as *u8)
2331 return so
2332 }
2333 if is_folder == 1 {
2334 let fnm: *u8 = sys_mmap(64)
2335 let fvl: *u8 = sys_mmap(64)
2336 of_form_get(body, blen, "name" as *u8, fnm, 64)
2337 of_form_get(body, blen, "folder" as *u8, fvl, 48)
2338 if of_name_ok(fnm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2339 if of_write_ok(azprefix, me, authed, fnm) == 0 { return of_deny_write(out) }
2340 let fkb: *u8 = sys_mmap(64)
2341 if of_manifest_count(root, fnm, fkb, 64) <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2342 // a folder is a plain label; reuse the handle validator so it cannot carry separators or markup
2343 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) } }
2344 of_folder_set(root, fnm, fvl)
2345 var fo: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other
2346
2347Location: " as *u8)
2348 fo = of_cat(out, fo, base); fo = of_cat(out, fo, "/doc/" as *u8); fo = of_cat(out, fo, fnm)
2349 fo = of_cat(out, fo, "
2350
2351Content-Length: 0
2352
2353Connection: close
2354
2355
2356
2357" as *u8)
2358 return fo
2359 }
2360 // RESTORE: put an old version back by SAVING its spec as a NEW version (additive -- never destroys history).
2361 if is_restore == 1 {
2362 let rnm: *u8 = sys_mmap(64)
2363 let rvs: *u8 = sys_mmap(16)
2364 of_form_get(body, blen, "name" as *u8, rnm, 64)
2365 of_form_get(body, blen, "version" as *u8, rvs, 16)
2366 if of_name_ok(rnm) == 0 { return of_err(out, "400 Bad Request" as *u8, "bad name" as *u8) }
2367 if of_write_ok(azprefix, me, authed, rnm) == 0 { return of_deny_write(out) }
2368 let rkb: *u8 = sys_mmap(64)
2369 let rvc: i64 = of_manifest_count(root, rnm, rkb, 64)
2370 if rvc <= 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2371 let rv: i64 = of_atoi(rvs)
2372 if rv < 1 { return of_err(out, "400 Bad Request" as *u8, "bad version" as *u8) }
2373 if rv > rvc { return of_err(out, "400 Bad Request" as *u8, "bad version" as *u8) }
2374 let rspec: *u8 = sys_mmap(131073)
2375 let rsl: i64 = of_read_version_spec(root, rnm, rv, rspec, 131072)
2376 let rnew: i64 = of_save(root, base, rnm, rkb, rspec, rsl, 0)
2377 if rnew > 0 {
2378 var ro2: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2379 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)
2380 return ro2
2381 }
2382 return of_err(out, "500 Internal Server Error" as *u8, "restore failed (organ rejected the spec)" as *u8)
2383 }
2384 let nm: *u8 = sys_mmap(64)
2385 let kd: *u8 = sys_mmap(32)
2386 let spec: *u8 = sys_mmap(131073)
2387 of_form_get(body, blen, "name" as *u8, nm, 64)
2388 of_form_get(body, blen, "kind" as *u8, kd, 32)
2389 let sl: i64 = of_form_get(body, blen, "spec" as *u8, spec, 131073)
2390 // AUTHZ: an OWNED doc's new version needs write access; remember owned-ness to CLAIM on first save.
2391 var was_owned: i64 = 0
2392 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 } }
2393 if was_owned == 1 { if of_write_ok(azprefix, me, authed, nm) == 0 { return of_deny_write(out) } }
2394 // ajax=1 = background AUTOSAVE (fetch from office_app.js): answer 200 OK v<N> instead of the 303
2395 let ax: *u8 = sys_mmap(8)
2396 of_form_get(body, blen, "ajax" as *u8, ax, 8)
2397 var auto: i64 = 0
2398 if ax[0] == (49 as u8) { auto = 1 }
2399 let vn: i64 = of_save(root, base, nm, kd, spec, sl, auto)
2400 if vn > 0 {
2401 // CLAIM ownership on first save by an authed user: unowned doc -> owner tuple (now private + shareable).
2402 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) } }
2403 if auto == 1 {
2404 // body = "OK v" + vn + "\n" (4 + digits(vn) + 1) -> Content-Length so strict clients frame it.
2405 var nd: i64 = 1
2406 var tv: i64 = vn
2407 while tv >= 10 { nd = nd + 1; tv = tv / 10 }
2408 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)
2409 oa = of_catn(out, oa, 4 + nd + 1)
2410 oa = of_cat(out, oa, "\r\nConnection: close\r\n\r\nOK v" as *u8)
2411 oa = of_catn(out, oa, vn)
2412 oa = of_catc(out, oa, 10)
2413 return oa
2414 }
2415 var o: i64 = of_cat(out, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
2416 o = of_cat(out, o, base)
2417 o = of_cat(out, o, "/doc/" as *u8)
2418 o = of_cat(out, o, nm)
2419 o = of_cat(out, o, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8)
2420 return o
2421 }
2422 if vn == (0 - 2) { return of_err(out, "400 Bad Request" as *u8, "kind mismatch: that name already exists with a different kind" as *u8) }
2423 if vn == (0 - 3) { return of_err(out, "500 Internal Server Error" as *u8, "the format organ rejected the spec (build failed)" as *u8) }
2424 if vn == (0 - 4) { return of_err(out, "500 Internal Server Error" as *u8, "preview render failed" as *u8) }
2425 return of_err(out, "400 Bad Request" as *u8, "invalid name (a-z 0-9 dash, max 40), kind, or empty spec" as *u8)
2426 }
2427 // GET routes
2428 if of_seq(path, "/app.js" as *u8) == 1 { return of_serve_js(out, cap) }
2429 if of_seq(path, "/sw.js" as *u8) == 1 { return of_serve_sw(out, cap) }
2430 if of_seq(path, "/manifest.webmanifest" as *u8) == 1 { return of_serve_manifest(out, base, cap) }
2431 if of_seq(path, "/" as *u8) == 1 { return of_cl_frame(out, of_home(root, base, qs, out, cap, azprefix, me, authed), cap) }
2432 if path[0] == (0 as u8) { return of_cl_frame(out, of_home(root, base, qs, out, cap, azprefix, me, authed), cap) }
2433 if of_starts(path, "/doc/" as *u8) == 1 {
2434 let nm: *u8 = sys_mmap(64)
2435 var q: i64 = 5
2436 var t2: i64 = 0
2437 while path[q] != (0 as u8) { if t2 < 63 { nm[t2] = path[q]; t2 = t2 + 1 } q = q + 1 }
2438 nm[t2] = 0 as u8
2439 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
2440 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
2441 let n: i64 = of_docpage(root, base, nm, out, cap)
2442 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such file" as *u8) }
2443 return of_cl_frame(out, n, cap)
2444 }
2445 if of_starts(path, "/preview/" as *u8) == 1 {
2446 let nm: *u8 = sys_mmap(64)
2447 let vn: i64 = of_parse_nv(path, 9, nm, 64)
2448 if vn < 1 { return of_err(out, "404 Not Found" as *u8, "bad preview path" as *u8) }
2449 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
2450 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
2451 let n: i64 = of_serve(root, nm, vn, 1, out, cap)
2452 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such version" as *u8) }
2453 return n
2454 }
2455 if of_starts(path, "/file/" as *u8) == 1 {
2456 let nm: *u8 = sys_mmap(64)
2457 let vn: i64 = of_parse_nv(path, 6, nm, 64)
2458 if vn < 1 { return of_err(out, "404 Not Found" as *u8, "bad file path" as *u8) }
2459 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
2460 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
2461 let n: i64 = of_serve(root, nm, vn, 0, out, cap)
2462 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such version" as *u8) }
2463 return n
2464 }
2465 if of_starts(path, "/diff/" as *u8) == 1 {
2466 // /diff/<name>/<a>/<b>
2467 let nm: *u8 = sys_mmap(64)
2468 var q: i64 = 6
2469 var t: i64 = 0
2470 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 }
2471 nm[t] = 0 as u8
2472 if path[q] != (47 as u8) { return of_err(out, "404 Not Found" as *u8, "bad diff path" as *u8) }
2473 q = q + 1
2474 var va: i64 = 0; var da: i64 = 0
2475 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 } }
2476 if path[q] != (47 as u8) { return of_err(out, "404 Not Found" as *u8, "bad diff path" as *u8) }
2477 q = q + 1
2478 var vb: i64 = 0; var db: i64 = 0
2479 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 } }
2480 if da == 0 { return of_err(out, "404 Not Found" as *u8, "bad diff versions" as *u8) }
2481 if db == 0 { return of_err(out, "404 Not Found" as *u8, "bad diff versions" as *u8) }
2482 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
2483 if of_read_ok(azprefix, me, authed, nm) == 0 { return of_deny_read(out) }
2484 let n: i64 = of_diffpage(root, base, nm, va, vb, out, cap)
2485 if n < 0 { return of_err(out, "404 Not Found" as *u8, "no such file or version" as *u8) }
2486 return of_cl_frame(out, n, cap)
2487 }
2488 if of_seq(path, "/groups" as *u8) == 1 {
2489 let n: i64 = of_groupspage(base, azprefix, me, authed, tok, out, cap)
2490 return of_cl_frame(out, n, cap)
2491 }
2492 if of_seq(path, "/shared-with-me" as *u8) == 1 {
2493 let n: i64 = of_sharedpage(base, azprefix, me, authed, out, cap)
2494 return of_cl_frame(out, n, cap)
2495 }
2496 if of_starts(path, "/manage/" as *u8) == 1 {
2497 let nm: *u8 = sys_mmap(64)
2498 var q: i64 = 8
2499 var t2: i64 = 0
2500 while path[q] != (0 as u8) { if t2 < 63 { nm[t2] = path[q]; t2 = t2 + 1 } q = q + 1 }
2501 nm[t2] = 0 as u8
2502 if of_name_ok(nm) == 0 { return of_err(out, "404 Not Found" as *u8, "bad name" as *u8) }
2503 let n: i64 = of_managepage(base, azprefix, me, authed, nm, tok, out, cap)
2504 if n == (0 - 1) { return of_err(out, "401 Unauthorized" as *u8, "sign in to manage sharing" as *u8) }
2505 if n == (0 - 2) { return of_err(out, "404 Not Found" as *u8, "this document has no owner (it is public)" as *u8) }
2506 if n == (0 - 3) { return of_err(out, "403 Forbidden" as *u8, "only the owner can manage sharing" as *u8) }
2507 return of_cl_frame(out, n, cap)
2508 }
2509 return of_err(out, "404 Not Found" as *u8, "no such route" as *u8)
2510}
2511
2512// ---- the offline gate body (consumed by _hdl_build/nx_office_gate) ----
2513func of_ck(name: *u8, cond: i64, pass: *i64, fail: *i64) -> i64 {
2514 if cond == 1 { p(" PASS " as *u8); p(name); p("\n" as *u8); pass[0] = pass[0] + 1; return 1 }
2515 p(" FAIL " as *u8); p(name); p("\n" as *u8); fail[0] = fail[0] + 1
2516 return 0
2517}
2518func of_selftest(root: *u8) -> i64 {
2519 p("=== NX-OFFICE SELFTEST root=" as *u8); p(root); p(" (create/edit/version/preview/download, additive-proven, LOUD negatives) ===\n" as *u8)
2520 let base: *u8 = sys_mmap(4)
2521 base[0] = 0 as u8
2522 let pass: *i64 = sys_mmap(16) as *i64
2523 let fail: *i64 = sys_mmap(16) as *i64
2524 pass[0] = 0
2525 fail[0] = 0
2526 let out: *u8 = sys_mmap(1048576)
2527 let req: *u8 = sys_mmap(262144)
2528 let bod: *u8 = sys_mmap(131072)
2529 // T1 empty home
2530 var n: i64 = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
2531 of_ck("T1 home renders" as *u8, of_memhas(out, n, "Nishi Office" as *u8), pass, fail)
2532 // helper-free POST builder: body first, then request with exact Content-Length
2533 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)
2534 var ro: i64 = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2535 ro = of_catn(req, ro, bo)
2536 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
2537 ro = of_cat(req, ro, bod)
2538 n = of_handle(root, base, req, ro, out, 1048576)
2539 var t2ok: i64 = 0
2540 if of_memhas(out, n, "303 See Other" as *u8) == 1 { if of_memhas(out, n, "/doc/family-letter" as *u8) == 1 { t2ok = 1 } }
2541 of_ck("T2 create doc v1 (303 redirect)" as *u8, t2ok, pass, fail)
2542 let fb: *u8 = sys_mmap(1048576)
2543 let ap: *u8 = sys_mmap(600)
2544 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
2545 let fl1: i64 = of_read_file(ap, fb, 1048576)
2546 var t2b: i64 = 0
2547 if fl1 > 200 { t2b = 1 }
2548 of_ck("T2b v1 .docx built on disk" as *u8, t2b, pass, fail)
2549 let pp: *u8 = sys_mmap(600)
2550 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
2551 let pv: *u8 = sys_mmap(1048576)
2552 let pl: i64 = of_read_file(pp, pv, 1048576)
2553 var t2c: i64 = 0
2554 if pl > 0 { t2c = of_memhas(pv, pl, "Family Letter" as *u8) }
2555 of_ck("T2c v1 preview renders the heading" as *u8, t2c, pass, fail)
2556 // T3 doc page round-trips the spec into the editor
2557 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)
2558 var t3: i64 = 0
2559 if of_memhas(out, n, "H Family Letter" as *u8) == 1 { if of_memhas(out, n, "Save as v2" as *u8) == 1 { t3 = 1 } }
2560 of_ck("T3 editor page carries latest spec (raw fallback)" as *u8, t3, pass, fail)
2561 // T3b VISUAL editor: doc spec rendered as editable blocks (#ed, <h2>, <b>) + app.js wired
2562 var t3b: i64 = 0
2563 if of_memhas(out, n, "id='ed' class='visual doc' contenteditable" as *u8) == 1 {
2564 if of_memhas(out, n, "<h2>Family Letter</h2>" as *u8) == 1 {
2565 if of_memhas(out, n, "<p data-k='B'><b>Dear family</b></p>" as *u8) == 1 {
2566 if of_memhas(out, n, "/app.js'></script>" as *u8) == 1 { t3b = 1 } } } }
2567 of_ck("T3b doc renders editable blocks (#ed h2/b) + app.js" as *u8, t3b, pass, fail)
2568 // T3c the client is served at /app.js as javascript
2569 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)
2570 var t3c: i64 = 0
2571 if of_memhas(out, na, "Content-Type: application/javascript" as *u8) == 1 { if of_memhas(out, na, "getElementById" as *u8) == 1 { t3c = 1 } }
2572 of_ck("T3c /app.js serves the client as javascript" as *u8, t3c, pass, fail)
2573 // snapshot v1 spec bytes for the additive proof
2574 let s1p: *u8 = sys_mmap(600)
2575 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
2576 let s1a: *u8 = sys_mmap(131072)
2577 let s1n: i64 = of_read_file(s1p, s1a, 131072)
2578 // T4 save v2 (edited)
2579 bo = of_cat(bod, 0, "name=family-letter&kind=doc&spec=H+Family+Letter+EDITED%0AP+Now+with+a+second+version." as *u8)
2580 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2581 ro = of_catn(req, ro, bo)
2582 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
2583 ro = of_cat(req, ro, bod)
2584 n = of_handle(root, base, req, ro, out, 1048576)
2585 let s2p: *u8 = sys_mmap(600)
2586 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
2587 let s2a: *u8 = sys_mmap(131072)
2588 let s2n: i64 = of_read_file(s2p, s2a, 131072)
2589 var t4: i64 = 0
2590 if of_memhas(out, n, "303" as *u8) == 1 { if s2n > 0 { t4 = 1 } }
2591 of_ck("T4 save again creates v2" as *u8, t4, pass, fail)
2592 let s1b: *u8 = sys_mmap(131072)
2593 let s1n2: i64 = of_read_file(s1p, s1b, 131072)
2594 var addv: i64 = 0
2595 if s1n2 == s1n { if s1n > 0 {
2596 addv = 1
2597 var ci: i64 = 0
2598 while ci < s1n { if s1a[ci] != s1b[ci] { addv = 0; ci = s1n } ci = ci + 1 }
2599 } }
2600 of_ck("T4b ADDITIVE: v1 spec bytes unchanged after v2" as *u8, addv, pass, fail)
2601 // T5 artifact download: response body == on-disk v2 bytes
2602 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)
2603 var bs: i64 = 0 - 1
2604 var bi: i64 = 0
2605 while bi + 3 < n {
2606 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 } } } }
2607 bi = bi + 1
2608 }
2609 var a2o2: i64 = of_cat(ap, 0, root)
2610 a2o2 = of_cat(ap, a2o2, "/family-letter/v2/file.docx" as *u8)
2611 ap[a2o2] = 0 as u8
2612 let fl2: i64 = of_read_file(ap, fb, 1048576)
2613 var t5: i64 = 0
2614 if bs > 0 { if n - bs == fl2 { if fl2 > 0 {
2615 t5 = 1
2616 var di: i64 = 0
2617 while di < fl2 { if out[bs + di] != fb[di] { t5 = 0; di = fl2 } di = di + 1 }
2618 } } }
2619 var t5h: i64 = of_memhas(out, bs, "wordprocessingml" as *u8)
2620 var t5ok: i64 = 0
2621 if t5 == 1 { if t5h == 1 { t5ok = 1 } }
2622 of_ck("T5 download == on-disk bytes + docx content-type" as *u8, t5ok, pass, fail)
2623 // T6 sheet with a real formula: preview shows the COMPUTED 30
2624 bo = of_cat(bod, 0, "name=family-budget&kind=sheet&spec=Item%09Cost%0AApples%0910%0APears%0920%0ATotal%09=SUM(B2:B3)" as *u8)
2625 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2626 ro = of_catn(req, ro, bo)
2627 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
2628 ro = of_cat(req, ro, bod)
2629 n = of_handle(root, base, req, ro, out, 1048576)
2630 var t6r: i64 = of_memhas(out, n, "303" as *u8)
2631 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)
2632 var t6: i64 = 0
2633 if t6r == 1 { if of_memhas(out, n, "30" as *u8) == 1 { t6 = 1 } }
2634 of_ck("T6 sheet formula computed in preview (SUM=30)" as *u8, t6, pass, fail)
2635 // T7 deck
2636 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)
2637 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2638 ro = of_catn(req, ro, bo)
2639 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
2640 ro = of_cat(req, ro, bod)
2641 n = of_handle(root, base, req, ro, out, 1048576)
2642 var t7r: i64 = of_memhas(out, n, "303" as *u8)
2643 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)
2644 var t7: i64 = 0
2645 if t7r == 1 { if of_memhas(out, n, "Reunion 2026" as *u8) == 1 { t7 = 1 } }
2646 of_ck("T7 deck builds + preview shows slide title" as *u8, t7, pass, fail)
2647 // T7b VISUAL editors for sheet + deck (editable grid #grid, editable slides #deck)
2648 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)
2649 var t7b: i64 = 0
2650 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 } }
2651 of_ck("T7b sheet renders an editable grid (#grid cells)" as *u8, t7b, pass, fail)
2652 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)
2653 var t7c: i64 = 0
2654 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 } } }
2655 of_ck("T7c deck renders editable slides (#deck h3 + toolbar)" as *u8, t7c, pass, fail)
2656 // T8 LOUD negatives
2657 bo = of_cat(bod, 0, "name=Bad/Name&kind=doc&spec=P+x" as *u8)
2658 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2659 ro = of_catn(req, ro, bo)
2660 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
2661 ro = of_cat(req, ro, bod)
2662 n = of_handle(root, base, req, ro, out, 1048576)
2663 of_ck("T8a bad name refused 400" as *u8, of_memhas(out, n, "400" as *u8), pass, fail)
2664 bo = of_cat(bod, 0, "name=family-letter&kind=sheet&spec=A%09B" as *u8)
2665 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2666 ro = of_catn(req, ro, bo)
2667 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
2668 ro = of_cat(req, ro, bod)
2669 n = of_handle(root, base, req, ro, out, 1048576)
2670 of_ck("T8b kind flip on existing name refused 400" as *u8, of_memhas(out, n, "kind mismatch" as *u8), pass, fail)
2671 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)
2672 of_ck("T8c missing version 404" as *u8, of_memhas(out, n, "404" as *u8), pass, fail)
2673 bo = of_cat(bod, 0, "name=family-letter&kind=doc&spec=P+evil" as *u8)
2674 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nOrigin: http://evil.example\r\nContent-Length: " as *u8)
2675 ro = of_catn(req, ro, bo)
2676 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
2677 ro = of_cat(req, ro, bod)
2678 n = of_handle(root, base, req, ro, out, 1048576)
2679 of_ck("T8d cross-origin POST refused 403" as *u8, of_memhas(out, n, "403" as *u8), pass, fail)
2680 let kb: *u8 = sys_mmap(64)
2681 var t8e: i64 = 0
2682 if of_manifest_count(root, "family-letter" as *u8, kb, 64) == 2 { t8e = 1 }
2683 of_ck("T8e negatives left NO new versions (still 2)" as *u8, t8e, pass, fail)
2684 // T9 home lists all three
2685 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
2686 var t9: i64 = 0
2687 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 } } }
2688 of_ck("T9 home lists all three files" as *u8, t9, pass, fail)
2689 // T10 MOUNTED at /office: the edge forwards the full path; stripping routes it, links carry the prefix.
2690 let mbase: *u8 = "/office" as *u8
2691 n = of_handle(root, mbase, "GET /office HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8, 46, out, 1048576)
2692 var t10a: i64 = 0
2693 if of_memhas(out, n, "Nishi Office" as *u8) == 1 { if of_memhas(out, n, "/office/doc/family-letter" as *u8) == 1 { t10a = 1 } }
2694 of_ck("T10a /office home renders + links carry the mount prefix" as *u8, t10a, pass, fail)
2695 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)
2696 var t10b: i64 = 0
2697 if of_memhas(out, n, "200 OK" as *u8) == 1 { if of_memhas(out, n, "wordprocessingml" as *u8) == 1 { t10b = 1 } }
2698 of_ck("T10b /office/file/.../v2 downloads through the mount" as *u8, t10b, pass, fail)
2699 // T10c a query string (cache-bust, browser params) must not break routing -> home still renders
2700 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)
2701 of_ck("T10c /office?query still routes to home (no 404)" as *u8, of_memhas(out, n, "Nishi Office" as *u8), pass, fail)
2702 // T11 VERSION DIFF: controlled v1/v2 with a partial overlap -> LCS keeps 2, adds 1, removes 1.
2703 // NOTE: of_cat does NOT NUL-terminate -> terminate bod at bo so of_cat(req,ro,bod) copies EXACTLY the body
2704 // (else a shorter body trails leftover bytes from a longer prior test = spec contamination).
2705 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
2706 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2707 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
2708 n = of_handle(root, base, req, ro, out, 1048576)
2709 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
2710 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2711 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
2712 n = of_handle(root, base, req, ro, out, 1048576)
2713 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)
2714 var t11: i64 = 0
2715 if of_memhas(out, n, "Changes: v1 → v2" as *u8) == 1 {
2716 if of_memhas(out, n, "class='ddel'>− P Line A</div>" as *u8) == 1 {
2717 if of_memhas(out, n, "class='dadd'>+ P Line A CHANGED</div>" as *u8) == 1 {
2718 if of_memhas(out, n, "class='dkeep'> H Title</div>" as *u8) == 1 {
2719 if of_memhas(out, n, "<b>1</b> line(s) added, <b>1</b> removed" as *u8) == 1 { t11 = 1 } } } } }
2720 of_ck("T11 version diff: LCS keep/add/del + counts (1 added, 1 removed)" as *u8, t11, pass, fail)
2721 // T11b the doc page links the diff for v>=2
2722 n = of_handle(root, base, "GET /doc/diffdoc HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 50, out, 1048576)
2723 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)
2724 // T11c doc page offers a Restore button for the older version (v1), not for the current (v2)
2725 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)
2726 // T11d RESTORE: put diffdoc v1 back -> creates v3 == v1 spec, ADDITIVE (v1 + v2 untouched)
2727 bo = of_cat(bod, 0, "name=diffdoc&version=1" as *u8); bod[bo] = 0 as u8
2728 ro = of_cat(req, 0, "POST /restore HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2729 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
2730 n = of_handle(root, base, req, ro, out, 1048576)
2731 var t11d: i64 = of_memhas(out, n, "303" as *u8)
2732 // v3 spec must byte-equal v1 spec; manifest now has 3 versions
2733 let rkbx: *u8 = sys_mmap(64)
2734 let rvcx: i64 = of_manifest_count(root, "diffdoc" as *u8, rkbx, 64)
2735 let s1x: *u8 = sys_mmap(4096)
2736 let s3x: *u8 = sys_mmap(4096)
2737 let n1x: i64 = of_read_version_spec(root, "diffdoc" as *u8, 1, s1x, 4095)
2738 let n3x: i64 = of_read_version_spec(root, "diffdoc" as *u8, 3, s3x, 4095)
2739 var eqx: i64 = 0
2740 if rvcx == 3 { if n1x == n3x { if n1x > 0 {
2741 eqx = 1
2742 var ci: i64 = 0
2743 while ci < n1x { if s1x[ci] != s3x[ci] { eqx = 0; ci = n1x } ci = ci + 1 }
2744 } } }
2745 var t11dok: i64 = 0
2746 if t11d == 1 { if eqx == 1 { t11dok = 1 } }
2747 of_ck("T11d restore v1 -> v3==v1 spec, additive (now 3 versions)" as *u8, t11dok, pass, fail)
2748 // T12 the PRODUCT SHELL (U-axes rung): search / type chips / sort order / REAL thumbnails / empty states /
2749 // editor chrome. Ordering asserted with of_findpos, not just presence.
2750 n = of_handle(root, base, "GET /?q=budget HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 47, out, 1048576)
2751 var t12a: i64 = 0
2752 if of_memhas(out, n, "family-budget" as *u8) == 1 { if of_memhas(out, n, "/doc/family-letter" as *u8) == 0 { t12a = 1 } }
2753 of_ck("T12a search q=budget filters the card grid" as *u8, t12a, pass, fail)
2754 n = of_handle(root, base, "GET /?type=deck HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 48, out, 1048576)
2755 var t12b: i64 = 0
2756 if of_memhas(out, n, "reunion-deck" as *u8) == 1 { if of_memhas(out, n, "/doc/family-budget" as *u8) == 0 { t12b = 1 } }
2757 of_ck("T12b type=deck chip filters to decks only" as *u8, t12b, pass, fail)
2758 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
2759 var pd: i64 = of_findpos(out, n, "/doc/reunion-deck" as *u8)
2760 var plt: i64 = of_findpos(out, n, "/doc/family-letter" as *u8)
2761 var t12c: i64 = 0
2762 if pd >= 0 { if plt >= 0 { if pd < plt { t12c = 1 } } }
2763 of_ck("T12c default sort = recently edited first (deck before letter)" as *u8, t12c, pass, fail)
2764 n = of_handle(root, base, "GET /?sort=name HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 48, out, 1048576)
2765 var pb2: i64 = of_findpos(out, n, "/doc/family-budget" as *u8)
2766 var pl2: i64 = of_findpos(out, n, "/doc/family-letter" as *u8)
2767 var pd2: i64 = of_findpos(out, n, "/doc/reunion-deck" as *u8)
2768 var t12d: i64 = 0
2769 if pb2 >= 0 { if pl2 > pb2 { if pd2 > pl2 { t12d = 1 } } }
2770 of_ck("T12d sort=name orders the grid alphabetically" as *u8, t12d, pass, fail)
2771 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
2772 var t12e: i64 = 0
2773 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 } } } }
2774 of_ck("T12e home cards carry REAL content thumbnails (sheet cells + doc heading)" as *u8, t12e, pass, fail)
2775 n = of_handle(root, base, "GET /?q=zzzz HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 45, out, 1048576)
2776 of_ck("T12f no-match search shows an empty state" as *u8, of_memhas(out, n, "No files match" as *u8), pass, fail)
2777 let root2: *u8 = sys_mmap(600)
2778 var r2o: i64 = of_cat(root2, 0, root); r2o = of_cat(root2, r2o, "-fresh" as *u8); root2[r2o] = 0 as u8
2779 n = of_handle(root2, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
2780 of_ck("T12g first-run onboarding empty state" as *u8, of_memhas(out, n, "Create your first document" as *u8), pass, fail)
2781 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)
2782 var t12h: i64 = 0
2783 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 } } } }
2784 of_ck("T12h editor carries saved-stamp + undo/find controls + save-state slot" as *u8, t12h, pass, fail)
2785 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)
2786 var t12i: i64 = 0
2787 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 } } }
2788 of_ck("T12i app.js ships find/shortcuts/theme (ctrlKey+TreeWalker+localStorage)" as *u8, t12i, pass, fail)
2789 // T13 TRUE AUTOSAVE (U4 rung): ajax=1 -> 200 OK v<N> (no 303 navigation), manifest tags the version with
2790 // the additive 4th field "auto", and the Versions table labels it. The JS side (debounce + changed-only)
2791 // ships in app.js (T13d needles) -- browser timing itself is not headless-executed here (honest caveat).
2792 bo = of_cat(bod, 0, "name=family-letter&kind=doc&spec=H+Family+Letter+AUTO%0AP+Background+save.&ajax=1" as *u8)
2793 bod[bo] = 0 as u8
2794 ro = of_cat(req, 0, "POST /save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2795 ro = of_catn(req, ro, bo)
2796 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
2797 ro = of_cat(req, ro, bod)
2798 n = of_handle(root, base, req, ro, out, 1048576)
2799 var t13a: i64 = 0
2800 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 } } }
2801 of_ck("T13a ajax autosave answers 200 OK v3 (no 303)" as *u8, t13a, pass, fail)
2802 var t13b: i64 = 0
2803 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 } }
2804 of_ck("T13b manifest tags v3 auto, v2 not" as *u8, t13b, pass, fail)
2805 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)
2806 var t13c: i64 = 0
2807 if of_memhas(out, n, "(auto)" as *u8) == 1 { if of_memhas(out, n, "Save as v4" as *u8) == 1 { t13c = 1 } }
2808 of_ck("T13c versions table labels the autosave + next save renumbers v4" as *u8, t13c, pass, fail)
2809 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)
2810 var t13d: i64 = 0
2811 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 } } }
2812 of_ck("T13d app.js ships the autosave engine (ajax=1 + changed-only lastSpec)" as *u8, t13d, pass, fail)
2813 // T14 HTML pages carry Content-Length so the STRICT sovereign browser can frame them (the /office in-browser
2814 // fetch failed without it). Assert present on the home response AND that its value == the actual body length.
2815 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
2816 var t14: i64 = 0
2817 if of_memhas(out, n, "Content-Length: " as *u8) == 1 {
2818 var hp: i64 = 0 - 1
2819 var xi: i64 = 0
2820 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 }
2821 if hp >= 0 {
2822 let bodylen: i64 = n - (hp + 4)
2823 var cl: i64 = 0
2824 var found: i64 = 0
2825 var ci: i64 = 0
2826 let key: *u8 = "Content-Length: " as *u8
2827 while ci + 16 < hp {
2828 if of_starts((out as i64 + ci) as *u8, key) == 1 {
2829 var t: i64 = ci + 16
2830 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 } }
2831 ci = hp
2832 } else { ci = ci + 1 }
2833 }
2834 if found == 1 { if cl == bodylen { t14 = 1 } }
2835 }
2836 }
2837 of_ck("T14 home carries a CORRECT Content-Length (strict-client framable)" as *u8, t14, pass, fail)
2838
2839 // ---- AUTHZ (nx_rebac): owner-binding + read/write gating + share/unshare -- the office integration ----
2840 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
2841 let azal: *u8 = sys_mmap(24); of_meref(azal, "alice" as *u8)
2842 let azbo: *u8 = sys_mmap(24); of_meref(azbo, "bob" as *u8)
2843 let azca: *u8 = sys_mmap(24); of_meref(azca, "carol" as *u8)
2844 let azempty: *u8 = sys_mmap(4); azempty[0] = 0 as u8
2845 of_ck("AZ0a unowned doc PUBLIC to authed (non-breaking)" as *u8, of_read_ok(azp, azal, 1, "flyer" as *u8), pass, fail)
2846 of_ck("AZ0b unowned doc PUBLIC to anon (non-breaking)" as *u8, of_read_ok(azp, azempty, 0, "flyer" as *u8), pass, fail)
2847 let azsref: *u8 = sys_mmap(32); of_docref(azsref, "secret" as *u8)
2848 rb_put(azp, azsref, "owner" as *u8, azal, "alice" as *u8, 1)
2849 of_ck("AZ1 owner alice reads owned secret" as *u8, of_read_ok(azp, azal, 1, "secret" as *u8), pass, fail)
2850 of_ck("AZ2 anon DENIED on owned secret" as *u8, 1 - of_read_ok(azp, azempty, 0, "secret" as *u8), pass, fail)
2851 of_ck("AZ3 bob (no grant) DENIED read" as *u8, 1 - of_read_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
2852 of_ck("AZ4 bob DENIED write" as *u8, 1 - of_write_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
2853 rb_put(azp, azsref, "viewer" as *u8, azbo, "alice" as *u8, 1)
2854 of_ck("AZ5 bob now READS (shared viewer)" as *u8, of_read_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
2855 of_ck("AZ6 bob viewer still cannot WRITE" as *u8, 1 - of_write_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
2856 rb_put(azp, azsref, "editor" as *u8, azca, "alice" as *u8, 1)
2857 of_ck("AZ7 carol editor CAN write" as *u8, of_write_ok(azp, azca, 1, "secret" as *u8), pass, fail)
2858 rb_put(azp, azsref, "viewer" as *u8, azbo, "alice" as *u8, 0)
2859 of_ck("AZ8 bob REVOKED (unshare tombstone)" as *u8, 1 - of_read_ok(azp, azbo, 1, "secret" as *u8), pass, fail)
2860 of_ck("AZ9 alice may_grant (owner)" as *u8, rb_may_grant(azp, azal, azsref), pass, fail)
2861 of_ck("AZ10 bob may_grant DENIED (not owner)" as *u8, 1 - rb_may_grant(azp, azbo, azsref), pass, fail)
2862 let azdob: *u8 = sys_mmap(8192)
2863 let azsh1: *u8 = "name=secret&who=dan&level=viewer" as *u8
2864 let azr1: i64 = of_do_share("/office" as *u8, azp, azal, "alice" as *u8, 1, azsh1, of_slen(azsh1), azdob, 1)
2865 let azdan: *u8 = sys_mmap(16); of_meref(azdan, "dan" as *u8)
2866 of_ck("AZ11a of_do_share owner->dan = 303" as *u8, of_memhas(azdob, azr1, "303" as *u8), pass, fail)
2867 of_ck("AZ11b dan now reads secret" as *u8, of_read_ok(azp, azdan, 1, "secret" as *u8), pass, fail)
2868 let azr2: i64 = of_do_share("/office" as *u8, azp, azbo, "bob" as *u8, 1, azsh1, of_slen(azsh1), azdob, 1)
2869 of_ck("AZ12 of_do_share by non-owner bob = 403" as *u8, of_memhas(azdob, azr2, "403" as *u8), pass, fail)
2870 let azsh2: *u8 = "name=secret&who=ev:il&level=viewer" as *u8
2871 let azr3: i64 = of_do_share("/office" as *u8, azp, azal, "alice" as *u8, 1, azsh2, of_slen(azsh2), azdob, 1)
2872 of_ck("AZ13 of_do_share bad handle = 400 (no forge)" as *u8, of_memhas(azdob, azr3, "400" as *u8), pass, fail)
2873 let azmob: *u8 = sys_mmap(65536)
2874 let azm1: i64 = of_managepage("/office" as *u8, azp, azal, 1, "secret" as *u8, "TOK" as *u8, azmob, 65536)
2875 of_ck("AZ14 owner manage page renders" as *u8, of_memhas(azmob, azm1, "Sharing: secret" as *u8), pass, fail)
2876 let azm2: i64 = of_managepage("/office" as *u8, azp, azbo, 1, "secret" as *u8, "TOK" as *u8, azmob, 65536)
2877 var azm2ok: i64 = 0
2878 if azm2 == (0 - 3) { azm2ok = 1 }
2879 of_ck("AZ15 non-owner manage DENIED (-3)" as *u8, azm2ok, pass, fail)
2880 let azm3: i64 = of_managepage("/office" as *u8, azp, azal, 1, "flyer" as *u8, "TOK" as *u8, azmob, 65536)
2881 var azm3ok: i64 = 0
2882 if azm3 == (0 - 2) { azm3ok = 1 }
2883 of_ck("AZ16 manage unowned = not-owned (-2)" as *u8, azm3ok, pass, fail)
2884 of_ck("AZ17 handle validator rejects colon (no type forge)" as *u8, 1 - of_tok_ok("ev:il" as *u8), pass, fail)
2885 of_ck("AZ18 handle validator accepts ok_h-1" as *u8, of_tok_ok("ok_h-1" as *u8), pass, fail)
2886
2887 // ---- GROUP SHARING (the userset differentiator): share a doc with a GROUP, members inherit access ----
2888 let azgadd: *u8 = "group=team&who=rose" as *u8
2889 let azgr: i64 = of_do_group("/office" as *u8, azp, azal, "alice" as *u8, 1, azgadd, of_slen(azgadd), azdob, 1)
2890 of_ck("AZ19 alice creates group team + adds rose = 303" as *u8, of_memhas(azdob, azgr, "303" as *u8), pass, fail)
2891 let azgshare: *u8 = "name=secret&who=team&level=viewer&target=group" as *u8
2892 let azgs: i64 = of_do_share("/office" as *u8, azp, azal, "alice" as *u8, 1, azgshare, of_slen(azgshare), azdob, 1)
2893 of_ck("AZ20 share secret with GROUP team = 303" as *u8, of_memhas(azdob, azgs, "303" as *u8), pass, fail)
2894 let azrose: *u8 = sys_mmap(16); of_meref(azrose, "rose" as *u8)
2895 of_ck("AZ21 rose reads secret VIA GROUP membership (userset)" as *u8, of_read_ok(azp, azrose, 1, "secret" as *u8), pass, fail)
2896 // reverse index (list-objects): what docs can each subject reach?
2897 let azmd: *i64 = sys_mmap(8 * 128) as *i64
2898 let aznd: i64 = of_my_docs(azp, azrose, azmd, 128)
2899 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)
2900 let azmd2: *i64 = sys_mmap(8 * 128) as *i64
2901 let aznd2: i64 = of_my_docs(azp, azal, azmd2, 128)
2902 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)
2903 let azfrank: *u8 = sys_mmap(16); of_meref(azfrank, "frank" as *u8)
2904 of_ck("AZ22 frank (not in team) DENIED" as *u8, 1 - of_read_ok(azp, azfrank, 1, "secret" as *u8), pass, fail)
2905 let azgrem: *u8 = "group=team&who=rose" as *u8
2906 of_do_group("/office" as *u8, azp, azal, "alice" as *u8, 1, azgrem, of_slen(azgrem), azdob, 0)
2907 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)
2908 let azbob2: *u8 = "group=team&who=x" as *u8
2909 let azgb: i64 = of_do_group("/office" as *u8, azp, azbo, "bob" as *u8, 1, azbob2, of_slen(azbob2), azdob, 1)
2910 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)
2911
2912 // ---- AI CONTINUE (in-app AI over our own 0.5B seat): offline gate proves the button + graceful 503 ----
2913 // T-AI-a: the doc editor page offers the "Continue with AI" form (doc kind).
2914 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)
2915 var tai_a: i64 = 0
2916 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 } }
2917 of_ck("T-AI-a doc page offers the AI-continue form (our own 0.5B model)" as *u8, tai_a, pass, fail)
2918 // T-AI-b: POST /office/ai with the LLM seat DOWN (offline gate) -> graceful 503, no version created, no crash.
2919 let aicnt0: *u8 = sys_mmap(64)
2920 let aiv0: i64 = of_manifest_count(root, "family-letter" as *u8, aicnt0, 64)
2921 bo = of_cat(bod, 0, "name=family-letter" as *u8); bod[bo] = 0 as u8
2922 ro = of_cat(req, 0, "POST /office/ai HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2923 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
2924 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
2925 let aicnt1: *u8 = sys_mmap(64)
2926 let aiv1: i64 = of_manifest_count(root, "family-letter" as *u8, aicnt1, 64)
2927 var tai_b: i64 = 0
2928 if of_memhas(out, n, "503" as *u8) == 1 { if aiv1 == aiv0 { tai_b = 1 } }
2929 of_ck("T-AI-b POST /ai with seat DOWN -> graceful 503 (framed) + NO version created" as *u8, tai_b, pass, fail)
2930 // ---- U4 OFFLINE/PWA + SKELETONS + A11Y ----
2931 // T-U4-a: the web app manifest is served and installable (name + start_url).
2932 n = of_handle(root, base, "GET /manifest.webmanifest HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 59, out, 1048576)
2933 var tu4_a: i64 = 0
2934 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 } } }
2935 of_ck("T-U4-a /manifest.webmanifest serves an installable PWA manifest" as *u8, tu4_a, pass, fail)
2936 // T-U4-b: the service worker is served AT THE MOUNT with Service-Worker-Allowed, else its scope cannot
2937 // cover the app it is meant to make offline-capable.
2938 n = of_handle(root, base, "GET /sw.js HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 44, out, 1048576)
2939 var tu4_b: i64 = 0
2940 if of_memhas(out, n, "200 OK" as *u8) == 1 { if of_memhas(out, n, "Service-Worker-Allowed" as *u8) == 1 { tu4_b = 1 } }
2941 of_ck("T-U4-b /sw.js serves the worker with Service-Worker-Allowed" as *u8, tu4_b, pass, fail)
2942 // T-U4-c: the worker must NEVER cache document content -- a never-lose-versions app showing a stale doc
2943 // would be the one lie its whole design forbids. Assert the exclusion is actually in the shipped worker.
2944 let swb: *u8 = sys_mmap(65536)
2945 let swl: i64 = of_read_asset("office_sw.js" as *u8, swb, 65535)
2946 var tu4_c: i64 = 0
2947 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 } } }
2948 of_ck("T-U4-c the worker EXCLUDES /doc/ content and never touches a write" as *u8, tu4_c, pass, fail)
2949 // T-U4-d: shell head advertises the manifest + theme colour, and the skeleton style exists.
2950 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 39, out, 1048576)
2951 var tu4_d: i64 = 0
2952 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 } } }
2953 of_ck("T-U4-d shell advertises the manifest + theme-color and ships skeleton styles" as *u8, tu4_d, pass, fail)
2954 // ---- U3 LIBRARY ORGANISATION: starred + folders + shared-with-me ----
2955 // T-U3-a: star toggles ON, is visible in the library under ?filter=starred, and toggles back OFF.
2956 bo = of_cat(bod, 0, "name=family-letter" as *u8); bod[bo] = 0 as u8
2957 ro = of_cat(req, 0, "POST /office/star HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2958 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
2959 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
2960 var tu3_a: i64 = 0
2961 if of_starred(root, "family-letter" as *u8) == 1 {
2962 n = of_handle(root, base, "GET /?filter=starred HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 53, out, 1048576)
2963 if of_memhas(out, n, "family-letter" as *u8) == 1 { tu3_a = 1 }
2964 }
2965 of_ck("T-U3-a star ON and the starred filter shows the file" as *u8, tu3_a, pass, fail)
2966 // T-U3-b: the starred filter must EXCLUDE an unstarred file -- a filter that shows everything is not a filter.
2967 var tu3_b: i64 = 0
2968 if of_memhas(out, n, "family-budget" as *u8) == 0 { tu3_b = 1 }
2969 of_ck("T-U3-b starred filter EXCLUDES unstarred files (non-vacuous)" as *u8, tu3_b, pass, fail)
2970 // T-U3-c: folder set, then the folder filter selects it and rejects a different folder.
2971 bo = of_cat(bod, 0, "name=family-letter&folder=reunion" as *u8); bod[bo] = 0 as u8
2972 ro = of_cat(req, 0, "POST /office/folder HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2973 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
2974 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
2975 let fchk: *u8 = sys_mmap(64)
2976 of_folder_get(root, "family-letter" as *u8, fchk, 64)
2977 var tu3_c: i64 = 0
2978 if of_seq(fchk, "reunion" as *u8) == 1 {
2979 n = of_handle(root, base, "GET /?folder=reunion HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 53, out, 1048576)
2980 if of_memhas(out, n, "family-letter" as *u8) == 1 { if of_memhas(out, n, "family-budget" as *u8) == 0 { tu3_c = 1 } }
2981 }
2982 of_ck("T-U3-c folder set + folder filter selects only that folder" as *u8, tu3_c, pass, fail)
2983 // T-U3-d: a folder label carrying separators or markup is REFUSED (it becomes a URL filter value).
2984 bo = of_cat(bod, 0, "name=family-letter&folder=a/b" as *u8); bod[bo] = 0 as u8
2985 ro = of_cat(req, 0, "POST /office/folder HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
2986 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
2987 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
2988 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)
2989 // T-U3-e: the doc page offers both controls.
2990 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)
2991 var tu3_e: i64 = 0
2992 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 } } }
2993 of_ck("T-U3-e doc page offers star + folder controls" as *u8, tu3_e, pass, fail)
2994 // ---- TEMPLATES GALLERY (U3): real starter content, not an empty page ----
2995 // T-TM-a: the home page offers the gallery and its templates carry WORKING content, not lorem text -- the
2996 // budget must ship a live =SUM and a #CF rule, else it demonstrates nothing about the engine underneath.
2997 n = of_handle(root, base, "GET / HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8, 38, out, 1048576)
2998 var ttm_a: i64 = 0
2999 if of_memhas(out, n, "<h2>Templates</h2>" as *u8) == 1 {
3000 if of_memhas(out, n, "Meeting agenda" as *u8) == 1 {
3001 if of_memhas(out, n, "Monthly budget" as *u8) == 1 {
3002 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 } }
3003 }
3004 }
3005 }
3006 of_ck("T-TM-a home offers Templates and the budget carries a REAL formula + CF rule" as *u8, ttm_a, pass, fail)
3007 // T-TM-b: a template POSTs to the SAME /save contract, so it becomes an ORDINARY versioned file.
3008 bo = of_cat(bod, 0, "name=tmpl-check&kind=doc&spec=H+Letter%0AP+Dear+friend%2C" as *u8); bod[bo] = 0 as u8
3009 ro = of_cat(req, 0, "POST /office/save HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3010 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3011 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3012 let tmk: *u8 = sys_mmap(64)
3013 let tmv: i64 = of_manifest_count(root, "tmpl-check" as *u8, tmk, 64)
3014 var ttm_b: i64 = 0
3015 if of_memhas(out, n, "303" as *u8) == 1 { if tmv == 1 { ttm_b = 1 } }
3016 of_ck("T-TM-b a template lands as an ORDINARY v1 file (same /save contract)" as *u8, ttm_b, pass, fail)
3017 // ---- OF-A2 (sheet insight) + OF-A3 (deck slide): the AI reaches EVERY kind, in that kind's own grammar ----
3018 // T-AI-c: the SHEET page offers the insight card (not the doc wording) -- proves the kind branch renders.
3019 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)
3020 var tai_c: i64 = 0
3021 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 } }
3022 of_ck("T-AI-c SHEET page offers the AI-insight card (and NOT the doc wording)" as *u8, tai_c, pass, fail)
3023 // T-AI-d: the DECK page offers the slide card.
3024 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)
3025 var tai_d: i64 = 0
3026 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 } }
3027 of_ck("T-AI-d DECK page offers the AI-slide card (and NOT the sheet wording)" as *u8, tai_d, pass, fail)
3028 // T-AI-e: POST /ai on a SHEET is now a REAL route (no longer the old doc-only 400) and degrades gracefully.
3029 let aik0: *u8 = sys_mmap(64)
3030 let aic0: i64 = of_manifest_count(root, "family-budget" as *u8, aik0, 64)
3031 bo = of_cat(bod, 0, "name=family-budget" as *u8); bod[bo] = 0 as u8
3032 ro = of_cat(req, 0, "POST /office/ai HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3033 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3034 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3035 let aik1: *u8 = sys_mmap(64)
3036 let aic1: i64 = of_manifest_count(root, "family-budget" as *u8, aik1, 64)
3037 var tai_e: i64 = 0
3038 if of_memhas(out, n, "503" as *u8) == 1 { if of_memhas(out, n, "400" as *u8) == 0 { if aic1 == aic0 { tai_e = 1 } } }
3039 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)
3040 // ---- OF-A4 AGENT MODE (offline gate) -- the state machine + plan parser are fully provable with the seat
3041 // DOWN, so these teeth run everywhere. Only the model's WORDS need a live seat; the agency does not.
3042 // T-AG-a: the doc page offers agent mode with a goal input.
3043 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)
3044 var tag_a: i64 = 0
3045 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 } }
3046 of_ck("T-AG-a doc page offers agent mode with a goal input" as *u8, tag_a, pass, fail)
3047 // T-AG-b: POST /agent with a goal + seat DOWN -> graceful 503, NO version, NO agent state written.
3048 let agk0: *u8 = sys_mmap(64)
3049 let agc0: i64 = of_manifest_count(root, "family-letter" as *u8, agk0, 64)
3050 bo = of_cat(bod, 0, "name=family-letter&goal=add+a+closing" as *u8); bod[bo] = 0 as u8
3051 ro = of_cat(req, 0, "POST /office/agent HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3052 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3053 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3054 let agk1: *u8 = sys_mmap(64)
3055 let agc1: i64 = of_manifest_count(root, "family-letter" as *u8, agk1, 64)
3056 let agchk: *u8 = sys_mmap(8192)
3057 let agchkn: i64 = of_agent_read(root, "family-letter" as *u8, agchk, 8000)
3058 var tag_b: i64 = 0
3059 if of_memhas(out, n, "503" as *u8) == 1 { if agc1 == agc0 { if agchkn <= 0 { tag_b = 1 } } }
3060 of_ck("T-AG-b POST /agent seat DOWN -> 503, NO version, NO agent state (retry-safe)" as *u8, tag_b, pass, fail)
3061 // T-AG-c: no goal and no plan yet -> LOUD 400, never a silent no-op.
3062 bo = of_cat(bod, 0, "name=family-letter" as *u8); bod[bo] = 0 as u8
3063 ro = of_cat(req, 0, "POST /office/agent HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3064 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3065 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3066 of_ck("T-AG-c POST /agent with no goal -> LOUD 400" as *u8, of_memhas(out, n, "400" as *u8), pass, fail)
3067 // T-AG-d: agent mode is doc-only -> a SHEET is refused loudly (the kind guard actually bites).
3068 bo = of_cat(bod, 0, "name=family-budget&goal=summarise" as *u8); bod[bo] = 0 as u8
3069 ro = of_cat(req, 0, "POST /office/agent HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
3070 ro = of_catn(req, ro, bo); ro = of_cat(req, ro, "\r\n\r\n" as *u8); ro = of_cat(req, ro, bod)
3071 n = of_handle(root, "/office" as *u8, req, ro, out, 1048576)
3072 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)
3073 // T-AG-e: the plan parser turns a real multi-line model reply into ordered steps, list punctuation stripped.
3074 let agpl: *u8 = sys_mmap(4096)
3075 let agsrc: *u8 = "1. Draft the summer plans section\n2) Add a warm closing paragraph\n- Check the tone\n" as *u8
3076 let agns: i64 = of_agent_plan_parse(agsrc, of_slen(agsrc), agpl, 4000)
3077 var tag_e: i64 = 0
3078 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 } } }
3079 of_ck("T-AG-e plan parser -> 3 ordered steps, list punctuation stripped" as *u8, tag_e, pass, fail)
3080 // T-AG-f: a SINGLE-LINE reply still becomes a real plan (sentence-split fallback), not a 1-step degenerate.
3081 let agpl2: *u8 = sys_mmap(4096)
3082 let agsrc2: *u8 = "Write the intro. Then add the plans. Finally close it." as *u8
3083 let agns2: i64 = of_agent_plan_parse(agsrc2, of_slen(agsrc2), agpl2, 4000)
3084 var tag_f: i64 = 0
3085 if agns2 >= 3 { tag_f = 1 }
3086 of_ck("T-AG-f single-line reply -> sentence-split into a multi-step plan" as *u8, tag_f, pass, fail)
3087 // T-AG-g: garbage in -> NO plan (the parser refuses rather than inventing a step) = the liar-kill tooth.
3088 let agpl3: *u8 = sys_mmap(4096)
3089 let agns3: i64 = of_agent_plan_parse("..\n-\n" as *u8, 5, agpl3, 4000)
3090 var tag_g: i64 = 0
3091 if agns3 == 0 { tag_g = 1 }
3092 of_ck("T-AG-g unusable model reply -> 0 steps (refuses, never invents)" as *u8, tag_g, pass, fail)
3093 // T-AG-h: state accessors round-trip (goal, ordered steps, done cursor) through the sidecar format.
3094 let agst: *u8 = "G ship it\nS one\nS two\nD 1\n" as *u8
3095 let agstn: i64 = of_slen(agst)
3096 let agtmp: *u8 = sys_mmap(256)
3097 var tag_h: i64 = 0
3098 if of_agent_tagcount(agst, agstn, 83) == 2 {
3099 if of_agent_done(agst, agstn) == 1 {
3100 of_agent_tagline(agst, agstn, 83, 1, agtmp, 256)
3101 if of_seq(agtmp, "two" as *u8) == 1 { tag_h = 1 }
3102 }
3103 }
3104 of_ck("T-AG-h agent state round-trips (2 steps, cursor=1, step[1]='two')" as *u8, tag_h, pass, fail)
3105 p("NX-OFFICE SELFTEST pass=" as *u8); pn(pass[0]); p(" fail=" as *u8); pn(fail[0])
3106 if fail[0] == 0 { p(" verdict=GREEN (the office round-trips: create/edit/version/preview/download, additive by construction)\n" as *u8); return 0 }
3107 p(" verdict=RED\n" as *u8)
3108 return 1
3109}