nx_write_run.nx source
↩ module page · 238 lines · 10494 B
1// nx_write_run.nx -- WRITING arc: the FILE-DRIVEN RUNNER (the tool the operator
2// runs on a real story). It reads everything from knowledge/staging/write/:
3// story.txt the work (operator/lane content -- Claude never authors it)
4// roster.txt character bible, one name per line
5// descriptors.txt descriptor lexicon, one term per line (setting/outfit/mood/...)
6// register.txt "term weight" per line (intensity lexicon; optional)
7// gov.txt "threshold age consent locale" ints (optional; default 5 1 1 1)
8// and emits, per scene, the IMAGE-GEN prompt + COMPANION context, plus the register
9// route -> stdout AND knowledge/staging/write/out.txt.
10//
11// This keeps the seam intact: the operator drops their content + lexicons here and
12// runs the tool; the engine (all gated organs) does the structuring. Build+run:
13// ./_offc/nx_sov_build_run.elf nx_write_run
14//
15// license_tier: ORIGINAL
16// module: nishi-core.write.run
17// depends: nishi-core.write.parselex, nishi-core.write.emit, nishi-core.write.register
18// capability: WRITE_RUN_TOOL
19import "nx_syscalls_x86_64.nx"
20import "nx_parse_lex.nx"
21import "nx_emit.nx"
22import "nx_register.nx"
23import "nx_conflict.nx"
24
25const WR_MAXSC: i64 = 128
26
27// write a null-terminated string to stdout AND the out file
28func wstr(outfd: i64, s: *u8) -> i64 {
29 var n: i64 = 0
30 while s[n] != (0 as u8) { n = n + 1 }
31 sys_write(1, s, n)
32 if outfd > 0 { sys_write(outfd, s, n) }
33 return 0
34}
35// write a signed integer to stdout AND the out file
36func wnum(outfd: i64, v: i64) -> i64 {
37 var m: i64 = v
38 if m < 0 { wstr(outfd, "-\x00" as *u8); m = 0 - m }
39 let bb: *u8 = sys_mmap(32)
40 let t: *u8 = sys_mmap(32)
41 var k: i64 = 0
42 if m == 0 { t[0] = 48 as u8; k = 1 }
43 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
44 var i: i64 = 0
45 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
46 bb[k] = 0 as u8
47 wstr(outfd, bb)
48 return 0
49}
50// write a packed term (by index) to stdout + out file
51func wterm(outfd: i64, terms: *u8, idx: i64) -> i64 {
52 let off: i64 = ig_name_off(terms, idx)
53 var n: i64 = 0
54 while terms[off + n] != (0 as u8) { n = n + 1 }
55 sys_write(1, (terms as i64 + off) as *u8, n)
56 if outfd > 0 { sys_write(outfd, (terms as i64 + off) as *u8, n) }
57 return 0
58}
59// parse up to maxk whitespace-separated ints from raw[0..n) into out
60func parse_ints(raw: *u8, n: i64, out: *i64, maxk: i64) -> i64 {
61 var count: i64 = 0
62 var i: i64 = 0
63 while i < n {
64 var g: i64 = 1
65 while g == 1 {
66 if i < n { let c: i64 = raw[i] as i64; if c >= 48 { if c <= 57 { g = 0 } else { i = i + 1 } } else { i = i + 1 } } else { g = 0 }
67 }
68 if i < n {
69 var val: i64 = 0
70 var g2: i64 = 1
71 while g2 == 1 {
72 if i < n { let c: i64 = raw[i] as i64; if c >= 48 { if c <= 57 { val = val * 10 + (c - 48); i = i + 1 } else { g2 = 0 } } else { g2 = 0 } } else { g2 = 0 }
73 }
74 if count < maxk { out[count] = val; count = count + 1 }
75 }
76 }
77 return count
78}
79// null-terminate a buffer at the first newline; return the resulting length
80func first_line(buf: *u8, n: i64) -> i64 {
81 var i: i64 = 0
82 var done: i64 = 0
83 while i < n {
84 if done == 0 {
85 if buf[i] == (10 as u8) { buf[i] = 0 as u8; done = 1 }
86 else { if buf[i] == (13 as u8) { buf[i] = 0 as u8; done = 1 } else { i = i + 1 } }
87 } else { i = n }
88 }
89 if done == 0 { buf[n] = 0 as u8 }
90 var ln: i64 = 0
91 while buf[ln] != (0 as u8) { ln = ln + 1 }
92 return ln
93}
94
95func main() -> i64 {
96 let lenp: *i64 = sys_mmap(16) as *i64
97 let story: *u8 = sys_read_file_x86_64("knowledge/staging/write/story.txt\x00" as *u8, lenp)
98 if story == (0 as *u8) {
99 wstr(0, "no story.txt -- drop story.txt + roster.txt + descriptors.txt into knowledge/staging/write/\n\x00" as *u8)
100 sys_exit(0)
101 return 0
102 }
103 let n: i64 = lenp[0]
104
105 // roster (optional)
106 let roster: *u8 = sys_mmap(4096)
107 var nnames: i64 = 0
108 let rraw: *u8 = sys_read_file_x86_64("knowledge/staging/write/roster.txt\x00" as *u8, lenp)
109 if rraw != (0 as *u8) { nnames = px_pack_lines(rraw, lenp[0], roster, 4096) }
110
111 // descriptors (optional)
112 let dterms: *u8 = sys_mmap(8192)
113 var ndterms: i64 = 0
114 let draw: *u8 = sys_read_file_x86_64("knowledge/staging/write/descriptors.txt\x00" as *u8, lenp)
115 if draw != (0 as *u8) { ndterms = px_pack_lines(draw, lenp[0], dterms, 8192) }
116
117 // register lexicon (optional)
118 let rterms: *u8 = sys_mmap(8192)
119 let rweights: *i64 = sys_mmap(2048) as *i64
120 var nrt: i64 = 0
121 let rgraw: *u8 = sys_read_file_x86_64("knowledge/staging/write/register.txt\x00" as *u8, lenp)
122 if rgraw != (0 as *u8) { nrt = px_pack_weighted(rgraw, lenp[0], rterms, 8192, rweights) }
123
124 // conflict axes lexicon (optional): "term axis" per line (same axis = mutually exclusive)
125 let cfterms: *u8 = sys_mmap(8192)
126 let cfaxes: *i64 = sys_mmap(2048) as *i64
127 var ncf: i64 = 0
128 var naxes: i64 = 0
129 let craw: *u8 = sys_read_file_x86_64("knowledge/staging/write/conflicts.txt\x00" as *u8, lenp)
130 if craw != (0 as *u8) {
131 ncf = px_pack_weighted(craw, lenp[0], cfterms, 8192, cfaxes)
132 var ci0: i64 = 0
133 while ci0 < ncf { if cfaxes[ci0] + 1 > naxes { naxes = cfaxes[ci0] + 1 } ci0 = ci0 + 1 }
134 }
135 let cfout: *i64 = sys_mmap(8192) as *i64
136
137 // persistent attributes (cross-scene continuity): "term axis" per line
138 let pterms: *u8 = sys_mmap(8192)
139 let paxes: *i64 = sys_mmap(2048) as *i64
140 var npt: i64 = 0
141 var pnaxes: i64 = 0
142 let praw: *u8 = sys_read_file_x86_64("knowledge/staging/write/persistent.txt\x00" as *u8, lenp)
143 if praw != (0 as *u8) {
144 npt = px_pack_weighted(praw, lenp[0], pterms, 8192, paxes)
145 var pi0: i64 = 0
146 while pi0 < npt { if paxes[pi0] + 1 > pnaxes { pnaxes = paxes[pi0] + 1 } pi0 = pi0 + 1 }
147 }
148
149 // governance (optional): threshold age consent locale ; defaults 5 1 1 1
150 var thr: i64 = 5
151 var age: i64 = 1
152 var consent: i64 = 1
153 var locale: i64 = 1
154 let gv: *i64 = sys_mmap(64) as *i64
155 let graw: *u8 = sys_read_file_x86_64("knowledge/staging/write/gov.txt\x00" as *u8, lenp)
156 if graw != (0 as *u8) {
157 let gc: i64 = parse_ints(graw, lenp[0], gv, 4)
158 if gc >= 1 { thr = gv[0] }
159 if gc >= 2 { age = gv[1] }
160 if gc >= 3 { consent = gv[2] }
161 if gc >= 4 { locale = gv[3] }
162 }
163
164 // style suffix + negative prompt (optional, single line each, operator DATA)
165 let styleb: *u8 = sys_read_file_x86_64("knowledge/staging/write/style.txt\x00" as *u8, lenp)
166 var has_style: i64 = 0
167 if styleb != (0 as *u8) { if first_line(styleb, lenp[0]) > 0 { has_style = 1 } }
168 let negb: *u8 = sys_read_file_x86_64("knowledge/staging/write/negative.txt\x00" as *u8, lenp)
169 var has_neg: i64 = 0
170 if negb != (0 as *u8) { if first_line(negb, lenp[0]) > 0 { has_neg = 1 } }
171
172 let stride: i64 = 5 + nnames
173 let scenes: *i64 = sys_mmap(WR_MAXSC * stride * 8) as *i64
174 let nsc: i64 = ig_extract(story, n, roster, nnames, scenes, WR_MAXSC)
175
176 let outfd: i64 = sys_openat_wr("knowledge/staging/write/out.txt\x00" as *u8, 0x1a4)
177
178 wstr(outfd, "== nishi-write analysis ==\n\x00" as *u8)
179 wstr(outfd, "scenes: \x00" as *u8); wnum(outfd, nsc); wstr(outfd, "\n\x00" as *u8)
180 var rscore: i64 = 0
181 if nrt > 0 { rscore = rg_score(story, 0, n, rterms, rweights, nrt) }
182 let route: i64 = rg_decision(rscore, thr, age, consent, locale)
183 wstr(outfd, "register score: \x00" as *u8); wnum(outfd, rscore)
184 wstr(outfd, " threshold: \x00" as *u8); wnum(outfd, thr)
185 wstr(outfd, " route: \x00" as *u8); wnum(outfd, route)
186 wstr(outfd, " (0=SFW-lane 1=EXPLICIT-lane 2=REFUSE)\n\n\x00" as *u8)
187
188 let dst: *u8 = sys_mmap(2048)
189 var k: i64 = 0
190 while k < nsc {
191 let base: i64 = k * stride
192 let a: i64 = scenes[base]
193 let b: i64 = scenes[base + 1]
194 let focus: i64 = scenes[base + 3]
195 wstr(outfd, "SCENE \x00" as *u8); wnum(outfd, k); wstr(outfd, "\n\x00" as *u8)
196 em_image_prompt_focus(story, a, b, roster, nnames, focus, dterms, ndterms, dst)
197 wstr(outfd, " IMG: \x00" as *u8); wstr(outfd, dst)
198 if has_style == 1 { wstr(outfd, ", \x00" as *u8); wstr(outfd, styleb) }
199 wstr(outfd, "\n\x00" as *u8)
200 if has_neg == 1 { wstr(outfd, " NEG: \x00" as *u8); wstr(outfd, negb); wstr(outfd, "\n\x00" as *u8) }
201 em_companion_ctx(story, a, b, roster, nnames, dterms, ndterms, dst)
202 wstr(outfd, " CTX: \x00" as *u8); wstr(outfd, dst); wstr(outfd, "\n\x00" as *u8)
203 if naxes > 0 {
204 let nc: i64 = cf_detect_owned(story, scenes[base], scenes[base + 1], roster, nnames, cfterms, cfaxes, ncf, naxes, cfout)
205 var ci: i64 = 0
206 while ci < nc {
207 wstr(outfd, " CONFLICT [\x00" as *u8); wterm(outfd, roster, cfout[ci * 4 + 0])
208 wstr(outfd, ", axis \x00" as *u8); wnum(outfd, cfout[ci * 4 + 1]); wstr(outfd, "]: \x00" as *u8)
209 wterm(outfd, cfterms, cfout[ci * 4 + 2]); wstr(outfd, " <-> \x00" as *u8); wterm(outfd, cfterms, cfout[ci * 4 + 3])
210 wstr(outfd, "\n\x00" as *u8)
211 ci = ci + 1
212 }
213 if nc == 0 { wstr(outfd, " conflicts: none\n\x00" as *u8) }
214 }
215 wstr(outfd, "\n\x00" as *u8)
216 k = k + 1
217 }
218
219 if pnaxes > 0 {
220 wstr(outfd, "-- continuity (whole-story persistent attributes, per character) --\n\x00" as *u8)
221 let pc: i64 = cf_detect_owned(story, 0, n, roster, nnames, pterms, paxes, npt, pnaxes, cfout)
222 var pj: i64 = 0
223 while pj < pc {
224 wstr(outfd, " CONTINUITY [\x00" as *u8); wterm(outfd, roster, cfout[pj * 4 + 0])
225 wstr(outfd, ", axis \x00" as *u8); wnum(outfd, cfout[pj * 4 + 1]); wstr(outfd, "]: \x00" as *u8)
226 wterm(outfd, pterms, cfout[pj * 4 + 2]); wstr(outfd, " <-> \x00" as *u8); wterm(outfd, pterms, cfout[pj * 4 + 3])
227 wstr(outfd, " (changes across story)\n\x00" as *u8)
228 pj = pj + 1
229 }
230 if pc == 0 { wstr(outfd, " continuity: consistent\n\x00" as *u8) }
231 wstr(outfd, "\n\x00" as *u8)
232 }
233
234 wstr(outfd, "-- end (also written to knowledge/staging/write/out.txt) --\n\x00" as *u8)
235 if outfd > 0 { sys_close(outfd) }
236 sys_exit(0)
237 return 0
238}