code wiki / (root) / nx_elara_state.nx

nx_elara_state.nx source

↩ module page · 740 lines · 38466 B

1// nx_elara_state.nx -- F975 rung 1: the COMPANION STATE-COHERENCE ENGINE. 2// 3// THE KEYSTONE (operator charter 2026-07-23): "she DRESSES HERSELF UP and KEEPS herself dressed ... a 4// synthetic human ... with LOGICAL CONSISTENCY based on her INTERNAL THOUGHT PROCESS ... who FLOWS 5// THROUGH THE DAY, not scene to scene or clip to clip." That is only possible if ONE state store holds 6// her wardrobe/mood/location/arousal/energy/arc/dynamic and the chat persona + the gen prompt composer + 7// the wardrobe logic ALL read AND write it. Without it, "she stays dressed" is per-image luck; with it, 8// consistency is BY CONSTRUCTION -- what she SAYS == what she WEARS == where she IS, across turns. 9// 10// This is rung 1: PERSISTENT, AGENT-WRITABLE current state on the sovereign seg-store, MCP-exposed. 11// Each `set` also appends to a per-session TIMELINE (append-only, real-clock stamped) so rung 2 (F920 12// idle day-arcs / dream-cycle advancing state between interactions) has the substrate to flow over. 13// NOT gen: no image is produced here -- this is the mind's state, which the (GPU-gated) gen path reads. 14// 15// OO/SCALE: state is CID-keyed NXR1 records on nx_seg_store via nx_registry (last-write-wins per key, 16// O(log) get, additive history). Composes proven organs; introduces no new storage format. 17// 18// VERBS 19// get <session> -> JSON of every state field (charter defaults for unset ones) 20// set <session> <field> <value> -> update one field (validated field name) + timeline append 21// dress <session> <outfit_key> [loc] -> set outfit (+ location) THROUGH the elaragram- rules: refuses 22// an unknown outfit, and (if loc given) flags an exposure-ceiling 23// conflict -- the "keep herself dressed appropriately" primitive 24// timeline <session> [max] -> the flowing-day log, newest last 25// selftest -> gate, verdict=GREEN|RED 26// 27// FIELDS (charter-derived, the only settable names): outfit location mood arousal energy activity 28// arc_stage dynamic. `dynamic` = the reversible relational stance (e.g. submissive|dominant|switch) so a 29// companion can act sub while the operator acts domme, or the reverse, per companion. 30// license_tier: ORIGINAL No hw writes (Rule 26). 31import "nx_syscalls.nx" 32import "nx_canon_cid.nx" 33import "nx_seg_store.nx" 34import "nx_registry.nx" 35const ES_MAGIC_4096: i64 = 4096 36const ES_MAGIC_8192: i64 = 8192 37const ES_MAGIC_1024: i64 = 1024 38const ES_MAGIC_16384: i64 = 16384 39const ES_MAGIC_3600: i64 = 3600 40 41const ES_STORE: *u8 = "knowledge/store/elarastate-" as *u8 42const ES_GRAM: *u8 = "knowledge/store/elaragram-" as *u8 // the wardrobe grammar plane (nx_sqlite_rows) 43const ES_NFIELD: i64 = 8 44 45func es_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 46func es_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 47func es_eq(a: *u8, b: *u8) -> i64 { 48 var i: i64 = 0 49 while 1 == 1 { 50 if a[i] != b[i] { return 0 } 51 if a[i] == (0 as u8) { return 1 } 52 i = i + 1 53 } 54 return 0 55} 56func es_cat(d: *u8, o: i64, s: *u8) -> i64 { var p: i64 = o; var i: i64 = 0; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } return p } 57func es_ch(d: *u8, o: i64, c: i64) -> i64 { d[o] = c as u8; return o + 1 } 58func es_udec(d: *u8, o: i64, v: i64) -> i64 { 59 if v == 0 { d[o] = 48 as u8; return o + 1 } 60 var div: i64 = 1 61 var m: i64 = v 62 while m >= 10 { div = div * 10; m = m / 10 } 63 var p: i64 = o 64 var rest: i64 = v 65 while div > 0 { let dg: i64 = rest / div; d[p] = (48 + dg) as u8; rest = rest - dg * div; div = div / 10; p = p + 1 } 66 return p 67} 68// JSON-escape a value into d (quotes/backslash/control) -- state values are agent-supplied = a boundary. 69func es_jesc(d: *u8, o: i64, s: *u8, n: i64) -> i64 { 70 var p: i64 = o 71 var i: i64 = 0 72 while i < n { 73 let c: i64 = s[i] as i64 74 if c == 34 { d[p] = 92 as u8; d[p+1] = 34 as u8; p = p + 2 } else { 75 if c == 92 { d[p] = 92 as u8; d[p+1] = 92 as u8; p = p + 2 } else { 76 if c == 10 { d[p] = 92 as u8; d[p+1] = 110 as u8; p = p + 2 } else { 77 if c == 9 { d[p] = 92 as u8; d[p+1] = 116 as u8; p = p + 2 } else { 78 if c < 32 { d[p] = 32 as u8; p = p + 1 } else { d[p] = c as u8; p = p + 1 } 79 } 80 } 81 } 82 } 83 i = i + 1 84 } 85 return p 86} 87 88// the settable field names (index-aligned with defaults) 89func es_field_name(i: i64) -> *u8 { 90 if i == 0 { return "outfit" as *u8 } 91 if i == 1 { return "location" as *u8 } 92 if i == 2 { return "mood" as *u8 } 93 if i == 3 { return "arousal" as *u8 } 94 if i == 4 { return "energy" as *u8 } 95 if i == 5 { return "activity" as *u8 } 96 if i == 6 { return "arc_stage" as *u8 } 97 if i == 7 { return "dynamic" as *u8 } 98 return "" as *u8 99} 100func es_field_default(i: i64) -> *u8 { 101 if i == 0 { return "unset" as *u8 } 102 if i == 1 { return "bedroom" as *u8 } 103 if i == 2 { return "content" as *u8 } 104 if i == 3 { return "0" as *u8 } 105 if i == 4 { return "rested" as *u8 } 106 if i == 5 { return "idle" as *u8 } 107 if i == 6 { return "day" as *u8 } 108 if i == 7 { return "switch" as *u8 } 109 return "" as *u8 110} 111func es_field_index(name: *u8) -> i64 { 112 var i: i64 = 0 113 while i < ES_NFIELD { if es_eq(name, es_field_name(i)) == 1 { return i } i = i + 1 } 114 return 0 - 1 115} 116 117// key "<session>|<field>" into kb 118func es_key(kb: *u8, session: *u8, field: *u8) -> i64 { 119 var o: i64 = es_cat(kb, 0, session) 120 o = es_ch(kb, o, 124) 121 o = es_cat(kb, o, field) 122 kb[o] = 0 as u8 123 return o 124} 125 126// append to the per-session timeline (append-only history for the flowing day). Key is uniquified with a 127// monotonic-microsecond suffix so multiple sets in the SAME wall-clock second do NOT collide (last- 128// write-wins would otherwise erase all but one) -- the flowing day must record every transition. 129func es_timeline_append(session: *u8, field: *u8, value: *u8) -> i64 { 130 let now: i64 = sys_now_realtime_sec() 131 let kb: *u8 = sys_mmap(512) 132 var o: i64 = es_cat(kb, 0, session) 133 o = es_cat(kb, o, "|_tl:" as *u8) 134 o = es_udec(kb, o, now) 135 o = es_ch(kb, o, 46) // '.' 136 o = es_udec(kb, o, sys_now_us()) 137 kb[o] = 0 as u8 138 let rec: *u8 = sys_mmap(ES_MAGIC_4096) 139 var ro: i64 = es_cat(rec, 0, field) 140 rec[ro] = 9 as u8; ro = ro + 1 141 ro = es_cat(rec, ro, value) 142 rec[ro] = 9 as u8; ro = ro + 1 143 ro = es_udec(rec, ro, now) 144 return reg_put(ES_STORE, "tl:" as *u8, "tl:ids" as *u8, kb, rec, ro) 145} 146 147// write one field: update CURRENT state (last-write-wins per key) AND journal the transition to the 148// timeline -- a set is ATOMIC "change now + record it happened", so history can never drift from state. 149func es_set_field(session: *u8, field: *u8, value: *u8) -> i64 { 150 let kb: *u8 = sys_mmap(512) 151 es_key(kb, session, field) 152 let rec: *u8 = sys_mmap(ES_MAGIC_4096) 153 var ro: i64 = es_cat(rec, 0, value) 154 rec[ro] = 9 as u8; ro = ro + 1 155 // MILLISECOND stamp (not seconds): tick's drift-vs-agent-override comparison must distinguish two 156 // writes in the SAME wall-clock second (a set right after a tick), or drift clobbers intent. 157 ro = es_udec(rec, ro, sys_now_realtime_ms()) 158 let rc: i64 = reg_put(ES_STORE, "es:" as *u8, "es:ids" as *u8, kb, rec, ro) 159 if rc == 0 { es_timeline_append(session, field, value) } 160 return rc 161} 162 163// read one field's value (strips the \t<epoch>) into out; returns 1 found, 0 default-used. 164func es_get_field(session: *u8, field: *u8, out: *u8) -> i64 { 165 let kb: *u8 = sys_mmap(512) 166 es_key(kb, session, field) 167 let po: *i64 = sys_mmap(16) as *i64 168 let lo: *i64 = sys_mmap(16) as *i64 169 if reg_get(ES_STORE, "es:" as *u8, kb, po, lo) == 1 { 170 let src: *u8 = po[0] as *u8 171 // copy value bytes up to the first tab (the \t<epoch> suffix is metadata, not the value) 172 var i: i64 = 0 173 var done: i64 = 0 174 while done == 0 { 175 if i >= lo[0] { done = 1 } else { 176 if src[i] == (9 as u8) { done = 1 } else { out[i] = src[i]; i = i + 1 } 177 } 178 } 179 out[i] = 0 as u8 180 return 1 181 } 182 let df: *u8 = es_field_default(es_field_index(field)) 183 var d: i64 = 0 184 while df[d] != (0 as u8) { out[d] = df[d]; d = d + 1 } 185 out[d] = 0 as u8 186 return 0 187} 188 189// read the per-session timeline: scan tl:ids for keys "<session>|_tl:*" and print each record 190// (field\tvalue\tepoch), newest last (append order preserved by the index). max=0 = all. 191func es_timeline_emit(session: *u8, max: i64) -> i64 { 192 // SIZE-TO-NEED: buffer derived from the index itself. The pair this replaces 193 // returned -1 once the timeline index passed 4 MiB, and -1 skips the walk 194 // below -- a session's timeline would have rendered EMPTY once it got long. 195 let idxbox: *i64 = sys_mmap(16) as *i64 196 let ilen: i64 = reg_index_read(ES_STORE, "tl:ids" as *u8, idxbox) 197 let idx: *u8 = idxbox[0] as *u8 198 let pfx: *u8 = sys_mmap(256) 199 var po: i64 = es_cat(pfx, 0, session) 200 po = es_cat(pfx, po, "|_tl:" as *u8) 201 pfx[po] = 0 as u8 202 let plen: i64 = po 203 let key: *u8 = sys_mmap(512) 204 let vp: *i64 = sys_mmap(16) as *i64 205 let vl: *i64 = sys_mmap(16) as *i64 206 let line: *u8 = sys_mmap(ES_MAGIC_8192) 207 var count: i64 = 0 208 var ls: i64 = 0 209 var i: i64 = 0 210 while i <= ilen { 211 var eol: i64 = 0 212 if i == ilen { eol = 1 } else { if idx[i] == (10 as u8) { eol = 1 } } 213 if eol == 1 { 214 let klen: i64 = i - ls 215 if klen > plen { 216 var hit: i64 = 1 217 var c: i64 = 0 218 while c < plen { if idx[ls + c] != pfx[c] { hit = 0 } c = c + 1 } 219 if hit == 1 { 220 var k: i64 = 0 221 while k < klen { key[k] = idx[ls + k]; k = k + 1 } 222 key[klen] = 0 as u8 223 if reg_get(ES_STORE, "tl:" as *u8, key, vp, vl) == 1 { 224 let src: *u8 = vp[0] as *u8 225 var o: i64 = 0 226 var b: i64 = 0 227 while b < vl[0] { line[o] = src[b]; o = o + 1; b = b + 1 } 228 line[o] = 10 as u8; o = o + 1 229 sys_write(1, line, o) 230 count = count + 1 231 } 232 } 233 } 234 ls = i + 1 235 if max > 0 { if count >= max { i = ilen + 1 } } 236 } 237 i = i + 1 238 } 239 return count 240} 241 242func es_emit_state(session: *u8) -> i64 { 243 let out: *u8 = sys_mmap(ES_MAGIC_8192) 244 let val: *u8 = sys_mmap(ES_MAGIC_4096) 245 var o: i64 = 0 246 o = es_ch(out, o, 123) 247 o = es_cat(out, o, "\"session\":\"" as *u8) 248 o = es_jesc(out, o, session, es_len(session)) 249 o = es_ch(out, o, 34) 250 var i: i64 = 0 251 while i < ES_NFIELD { 252 o = es_ch(out, o, 44) 253 o = es_ch(out, o, 34) 254 o = es_cat(out, o, es_field_name(i)) 255 o = es_cat(out, o, "\":\"" as *u8) 256 es_get_field(session, es_field_name(i), val) 257 o = es_jesc(out, o, val, es_len(val)) 258 o = es_ch(out, o, 34) 259 i = i + 1 260 } 261 o = es_ch(out, o, 125) 262 o = es_ch(out, o, 10) 263 sys_write(1, out, o) 264 return 0 265} 266 267// ---- NXR1 record field reader (for reading the elaragram- grammar plane records) ---- 268// DRY NOTE: this is the 3rd copy of the NXR1 field walk (mv_rec_field, sqr_rec_field, here) -> the shared 269// nx_nxr1 lib is now warranted (filed as debt). Kept local so rung 2 ships without a 3-file refactor. 270func es_r32(p: *u8, o: i64) -> i64 { let a: i64=p[o]; let b: i64=p[o+1]; let c: i64=p[o+2]; let d: i64=p[o+3]; return (((((a<<8)|b)<<8)|c)<<8)|d } 271// BOUNDED to reclen at EVERY step: a scan over hundreds of records must never walk past ONE of them 272// (an out-of-bounds read segfaulted the whole scan -- hit live 2026-07-24 on the T8 phantom scan). Any 273// malformed/misread length aborts the field with -1 instead of dereferencing garbage. `maxout` caps the 274// value copy so a large field (e.g. body_coverage) can never overflow a small caller buffer. 275func es_nxr1_field_cap(rec: *u8, reclen: i64, key: *u8, out: *u8, maxout: i64) -> i64 { 276 if reclen < 8 { return 0 - 1 } 277 if rec[0] != (78 as u8) { return 0 - 1 } // 'N' of NXR1 278 let klen: i64 = es_len(key) 279 let n: i64 = es_r32(rec, 4) 280 if n < 0 { return 0 - 1 } 281 if n > ES_MAGIC_1024 { return 0 - 1 } 282 var off: i64 = 8 283 var i: i64 = 0 284 while i < n { 285 if off + 4 > reclen { return 0 - 1 } 286 let kl: i64 = es_r32(rec, off); off = off + 4 287 if kl < 0 { return 0 - 1 } 288 if off + kl > reclen { return 0 - 1 } 289 let kp: i64 = off; off = off + kl 290 if off + 4 > reclen { return 0 - 1 } 291 let vl: i64 = es_r32(rec, off); off = off + 4 292 if vl < 0 { return 0 - 1 } 293 if off + vl > reclen { return 0 - 1 } 294 let vp: i64 = off; off = off + vl 295 if kl == klen { 296 var m: i64 = 1 297 var c: i64 = 0 298 while c < kl { if rec[kp + c] != key[c] { m = 0 } c = c + 1 } 299 if m == 1 { 300 var cap: i64 = vl 301 if cap > maxout - 1 { cap = maxout - 1 } 302 var w: i64 = 0 303 while w < cap { out[w] = rec[vp + w]; w = w + 1 } 304 out[cap] = 0 as u8 305 return cap 306 } 307 } 308 i = i + 1 309 } 310 return 0 - 1 311} 312func es_nxr1_field(rec: *u8, reclen: i64, key: *u8, out: *u8) -> i64 { 313 return es_nxr1_field_cap(rec, reclen, key, out, ES_MAGIC_4096) 314} 315func es_atoi(s: *u8) -> i64 { 316 var v: i64 = 0 317 var i: i64 = 0 318 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 } 319 return v 320} 321// is the null-terminated `needle` a comma-or-exact element of csv? (location_tags = "costume,home,nightlife") 322func es_csv_has(csv: *u8, needle: *u8) -> i64 { 323 let nl: i64 = es_len(needle) 324 var i: i64 = 0 325 var start: i64 = 0 326 while 1 == 1 { 327 let c: i64 = csv[i] as i64 328 if c == 44 { if i - start == nl { var m: i64=1; var k: i64=0; while k<nl { if csv[start+k]!=needle[k] { m=0 } k=k+1 } if m==1 { return 1 } } start = i + 1 } 329 if c == 0 { if i - start == nl { var m2: i64=1; var k2: i64=0; while k2<nl { if csv[start+k2]!=needle[k2] { m2=0 } k2=k2+1 } if m2==1 { return 1 } } return 0 } 330 i = i + 1 331 } 332 return 0 333} 334 335// SCALABLE outfit lookup: read the manifest, map EACH segment .docs ONCE (munmap after), scan its records 336// for a live "outfits:*" key whose outfit_key field == target. This is O(total-bytes) with only ~1 mmap 337// PER SEGMENT -- vs the naive 905x ss_get which leaked ~96 mmaps EACH (3 ver-bufs + one per segment via 338// ss_readall, none freed) and blew past vm.max_map_count -> SILENT CRASH (hit live 2026-07-24; ss_get 339// mmap-leak filed as a seg-store debt). Record framing = [kind:u8][klen:u32be][key][vlen:u32be][val], 340// big-endian (ss_w32); every offset is bounded to the mapped size. Returns 1 found (+ fills buffers), 0 not. 341func es_find_outfit(target: *u8, loctags: *u8, nsfw: *u8, name: *u8, desc: *u8) -> i64 { 342 let mp: *u8 = sys_mmap(512) 343 var mo: i64 = es_cat(mp, 0, ES_GRAM) 344 mo = es_cat(mp, mo, "manifest.txt" as *u8) 345 mp[mo] = 0 as u8 346 let szp: *i64 = sys_mmap(16) as *i64 347 let man: *u8 = sys_read_file(mp, szp) 348 if (man as i64) == 0 { return 0 } 349 let mlen: i64 = szp[0] 350 let pfx: *u8 = "outfits:" as *u8 351 let tmp: *u8 = sys_mmap(ES_MAGIC_4096) 352 var found: i64 = 0 353 var ls: i64 = 0 354 var mi: i64 = 0 355 while mi <= mlen { 356 var eol: i64 = 0 357 if mi == mlen { eol = 1 } else { if man[mi] == (10 as u8) { eol = 1 } } 358 if eol == 1 { 359 if found == 0 { if mi > ls { 360 let sp: *u8 = sys_mmap(512) 361 var so: i64 = es_cat(sp, 0, ES_GRAM) 362 var kk: i64 = ls 363 while kk < mi { sp[so] = man[kk]; so = so + 1; kk = kk + 1 } 364 so = es_cat(sp, so, ".docs" as *u8) 365 sp[so] = 0 as u8 366 let dszp: *i64 = sys_mmap(16) as *i64 367 let b: *u8 = sys_map_file(sp, dszp) 368 if (b as i64) != 0 { 369 let sz: i64 = dszp[0] 370 var j: i64 = 0 371 while j + 9 <= sz { 372 if found == 1 { j = sz } else { 373 let kind: i64 = b[j] 374 let kl: i64 = es_r32(b, j + 1) 375 let koff: i64 = j + 5 376 if kl < 0 { j = sz } else { 377 if koff + kl + 4 > sz { j = sz } else { 378 let vl: i64 = es_r32(b, koff + kl) 379 let voff: i64 = koff + kl + 4 380 if vl < 0 { j = sz } else { 381 if voff + vl > sz { j = sz } else { 382 if kind == 1 { if kl > 8 { 383 var pm: i64 = 1 384 var p: i64 = 0 385 while p < 8 { if b[koff + p] != pfx[p] { pm = 0 } p = p + 1 } 386 if pm == 1 { 387 let okl: i64 = es_nxr1_field_cap((b as i64 + voff) as *u8, vl, "outfit_key" as *u8, tmp, ES_MAGIC_4096) 388 if okl >= 0 { if es_eq(tmp, target) == 1 { 389 found = 1 390 es_nxr1_field_cap((b as i64 + voff) as *u8, vl, "location_tags" as *u8, loctags, ES_MAGIC_4096) 391 es_nxr1_field_cap((b as i64 + voff) as *u8, vl, "nsfw_level" as *u8, nsfw, ES_MAGIC_4096) 392 es_nxr1_field_cap((b as i64 + voff) as *u8, vl, "name" as *u8, name, ES_MAGIC_4096) 393 // prompt_fragment = the rich render description (context/persona use); fall back to zimage_sentence 394 if es_nxr1_field_cap((b as i64 + voff) as *u8, vl, "prompt_fragment" as *u8, desc, ES_MAGIC_4096) < 0 { es_nxr1_field_cap((b as i64 + voff) as *u8, vl, "zimage_sentence" as *u8, desc, ES_MAGIC_4096) } 395 } } 396 } 397 } } 398 j = voff + vl 399 }} 400 }} 401 } 402 } 403 sys_munmap(b, sz) 404 } 405 } } 406 ls = mi + 1 407 } 408 mi = mi + 1 409 } 410 return found 411} 412 413// dress <session> <outfit_key> [location]: VALIDATE the outfit against the elaragram- grammar (she can only 414// wear an outfit that EXISTS), commit it to state, and flag whether it fits the location (the outfit's 415// location_tags). Returns 0 dressed, 3 unknown-outfit (refused). 416// ENVELOPE: bounded scan of outfits:minrow..maxrow (from outfits:meta) -- O(rows) per call; the O(log) 417// outfit_key->rowid index is a rung-2b optimization (filed). Refuses loudly, never dresses in a phantom outfit. 418func es_dress(session: *u8, outfit_key: *u8, location: *u8, has_loc: i64) -> i64 { 419 let loctags: *u8 = sys_mmap(ES_MAGIC_4096) 420 let nsfw: *u8 = sys_mmap(ES_MAGIC_4096) 421 let name: *u8 = sys_mmap(ES_MAGIC_4096) 422 let desc: *u8 = sys_mmap(ES_MAGIC_4096) 423 loctags[0] = 0 as u8; nsfw[0] = 0 as u8; name[0] = 0 as u8; desc[0] = 0 as u8 424 // SCALABLE lookup (one mmap per segment, munmap'd) -- replaces the 905x ss_get that crashed 425 let found: i64 = es_find_outfit(outfit_key, loctags, nsfw, name, desc) 426 if found == 0 { 427 let eb: *u8 = sys_mmap(512) 428 var xo: i64 = es_cat(eb, 0, "{\"error\":\"unknown outfit_key: " as *u8) 429 xo = es_jesc(eb, xo, outfit_key, es_len(outfit_key)) 430 xo = es_cat(eb, xo, "\",\"detail\":\"she can only wear an outfit that exists in the grammar; nothing changed\"}" as *u8) 431 eb[xo] = 0 as u8 432 es_puts(eb); es_puts("\n" as *u8) 433 return 3 434 } 435 // commit: outfit (+ location) to state 436 es_set_field(session, "outfit" as *u8, outfit_key) 437 var appropriate: i64 = 1 438 if has_loc == 1 { 439 es_set_field(session, "location" as *u8, location) 440 if es_len(loctags) > 0 { if es_csv_has(loctags, location) == 0 { appropriate = 0 } } 441 } 442 // dress verdict + full state 443 let vb: *u8 = sys_mmap(ES_MAGIC_1024) 444 var vo: i64 = es_cat(vb, 0, "{\"dressed\":\"" as *u8) 445 vo = es_jesc(vb, vo, outfit_key, es_len(outfit_key)) 446 vo = es_cat(vb, vo, "\",\"name\":\"" as *u8); vo = es_jesc(vb, vo, name, es_len(name)) 447 vo = es_cat(vb, vo, "\",\"nsfw_level\":\"" as *u8); vo = es_jesc(vb, vo, nsfw, es_len(nsfw)) 448 vo = es_cat(vb, vo, "\",\"location_tags\":\"" as *u8); vo = es_jesc(vb, vo, loctags, es_len(loctags)) 449 vo = es_cat(vb, vo, "\",\"location_appropriate\":" as *u8) 450 if appropriate == 1 { vo = es_cat(vb, vo, "true" as *u8) } else { vo = es_cat(vb, vo, "false" as *u8) } 451 vo = es_cat(vb, vo, "}" as *u8) 452 vb[vo] = 0 as u8 453 es_puts(vb); es_puts("\n" as *u8) 454 es_emit_state(session) 455 return 0 456} 457 458func es_selftest() -> i64 { 459 let pass: *i64 = sys_mmap(16) as *i64 460 pass[0] = 0 461 // RUN-UNIQUE session id: the store is ADDITIVE, so a fixed id would make "defaults before any set" 462 // (T0) see the PRIOR run's writes and fail on the 2nd run. A per-run id (monotonic-us suffix) keeps 463 // every run's slice fresh + isolated -> deterministic re-runs, and the timeline count is exactly this 464 // run's sets. (This is throwaway state; production sessions use a real stable id.) 465 let S: *u8 = sys_mmap(64) 466 var so: i64 = es_cat(S, 0, "st_" as *u8) 467 so = es_udec(S, so, sys_now_us()) 468 S[so] = 0 as u8 469 let val: *u8 = sys_mmap(ES_MAGIC_4096) 470 // T0 defaults before any set 471 es_get_field(S, "outfit" as *u8, val) 472 var t0: i64 = 0 473 if es_eq(val, "unset" as *u8) == 1 { t0 = 1 } 474 es_get_field(S, "dynamic" as *u8, val) 475 if es_eq(val, "switch" as *u8) == 0 { t0 = 0 } 476 if t0 == 1 { pass[0] = pass[0] + 1; es_puts("T0 charter defaults: PASS\n" as *u8) } else { es_puts("T0 charter defaults: FAIL\n" as *u8) } 477 // T1 set + get round-trip 478 es_set_field(S, "outfit" as *u8, "sundress" as *u8) 479 es_get_field(S, "outfit" as *u8, val) 480 var t1: i64 = 0 481 if es_eq(val, "sundress" as *u8) == 1 { t1 = 1 } 482 if t1 == 1 { pass[0] = pass[0] + 1; es_puts("T1 set/get round-trip: PASS\n" as *u8) } else { es_puts("T1 set/get round-trip: FAIL\n" as *u8) } 483 // T2 last-write-wins (change persists over the old value) 484 es_set_field(S, "outfit" as *u8, "witch_costume" as *u8) 485 es_get_field(S, "outfit" as *u8, val) 486 var t2: i64 = 0 487 if es_eq(val, "witch_costume" as *u8) == 1 { t2 = 1 } 488 if t2 == 1 { pass[0] = pass[0] + 1; es_puts("T2 last-write-wins: PASS\n" as *u8) } else { es_puts("T2 last-write-wins: FAIL\n" as *u8) } 489 // T3 fields are independent (setting outfit did not disturb location default) 490 es_set_field(S, "location" as *u8, "garden" as *u8) 491 es_get_field(S, "outfit" as *u8, val) 492 var t3: i64 = 0 493 if es_eq(val, "witch_costume" as *u8) == 1 { 494 es_get_field(S, "location" as *u8, val) 495 if es_eq(val, "garden" as *u8) == 1 { t3 = 1 } 496 } 497 if t3 == 1 { pass[0] = pass[0] + 1; es_puts("T3 fields independent: PASS\n" as *u8) } else { es_puts("T3 fields independent: FAIL\n" as *u8) } 498 // T4 unknown field name refused by es_field_index 499 var t4: i64 = 0 500 if es_field_index("outfit" as *u8) == 0 { if es_field_index("bogus" as *u8) == (0 - 1) { t4 = 1 } } 501 if t4 == 1 { pass[0] = pass[0] + 1; es_puts("T4 unknown-field refused: PASS\n" as *u8) } else { es_puts("T4 unknown-field refused: FAIL\n" as *u8) } 502 // T5 JSON escape of a hostile value 503 let jb: *u8 = sys_mmap(256) 504 let jo: i64 = es_jesc(jb, 0, "a\"b\\c" as *u8, 5) 505 var t5: i64 = 0 506 if jo == 7 { if jb[1] == (92 as u8) { if jb[2] == (34 as u8) { t5 = 1 } } } 507 if t5 == 1 { pass[0] = pass[0] + 1; es_puts("T5 json-escape hostile value: PASS\n" as *u8) } else { es_puts("T5 json-escape hostile value: FAIL\n" as *u8) } 508 // T6 the flowing-day timeline recorded the sets above (>=4 entries for this session: outfit x2, 509 // location, plus any prior run) -- the substrate for rung-2 idle day-arcs is real, not aspirational. 510 let tln: i64 = es_timeline_emit(S, 0) 511 var t6: i64 = 0 512 if tln >= 3 { t6 = 1 } // T1/T2/T3 each set a field -> >=3 timeline entries (additive: re-runs add more) 513 if t6 == 1 { pass[0] = pass[0] + 1; es_puts("T6 timeline records the flowing day: PASS\n" as *u8) } else { es_puts("T6 timeline records the flowing day: FAIL\n" as *u8) } 514 // T7 DRESS a REAL outfit from the elaragram- grammar (sexy_witch, rowid 258) -> found + committed. 515 // (Requires the grammar plane; if absent, es_dress returns 4 and this tooth honestly fails.) 516 let dv: i64 = es_dress(S, "sexy_witch" as *u8, "" as *u8, 0) 517 es_get_field(S, "outfit" as *u8, val) 518 var t7: i64 = 0 519 if dv == 0 { if es_eq(val, "sexy_witch" as *u8) == 1 { t7 = 1 } } 520 if t7 == 1 { pass[0] = pass[0] + 1; es_puts("T7 dress real outfit (grammar-validated): PASS\n" as *u8) } else { es_puts("T7 dress real outfit (grammar-validated): FAIL\n" as *u8) } 521 // T8 DRESS a PHANTOM outfit -> REFUSED (exit 3) AND state UNCHANGED (she never wears what does not exist) 522 let dv2: i64 = es_dress(S, "totally_not_a_real_outfit_zzz" as *u8, "" as *u8, 0) 523 es_get_field(S, "outfit" as *u8, val) 524 var t8: i64 = 0 525 if dv2 == 3 { if es_eq(val, "sexy_witch" as *u8) == 1 { t8 = 1 } } 526 if t8 == 1 { pass[0] = pass[0] + 1; es_puts("T8 phantom outfit refused, state intact: PASS\n" as *u8) } else { es_puts("T8 phantom outfit refused, state intact: FAIL\n" as *u8) } 527 // T9 CONTEXT JOIN: the outfit_key resolves to its display NAME + rich DESCRIPTION from the grammar 528 // (what makes `context` a persona-ready block, not just a key). 529 let d9loc: *u8 = sys_mmap(ES_MAGIC_4096) 530 let d9nsfw: *u8 = sys_mmap(ES_MAGIC_4096) 531 let d9name: *u8 = sys_mmap(ES_MAGIC_4096) 532 let d9desc: *u8 = sys_mmap(ES_MAGIC_4096) 533 d9desc[0] = 0 as u8; d9name[0] = 0 as u8 534 let f9: i64 = es_find_outfit("sexy_witch" as *u8, d9loc, d9nsfw, d9name, d9desc) 535 var t9: i64 = 0 536 if f9 == 1 { if es_len(d9name) > 0 { if es_len(d9desc) > 0 { t9 = 1 } } } 537 if t9 == 1 { pass[0] = pass[0] + 1; es_puts("T9 context join: outfit name+description resolved: PASS\n" as *u8) } else { es_puts("T9 context join: outfit name+description resolved: FAIL\n" as *u8) } 538 // T10 TICK advances ambient state to the real clock: arc_stage lands on one of the 4 time-of-day periods. 539 es_tick(S) 540 es_get_field(S, "arc_stage" as *u8, val) 541 var t10: i64 = 0 542 if es_eq(val, "morning" as *u8) == 1 { t10 = 1 } 543 if es_eq(val, "afternoon" as *u8) == 1 { t10 = 1 } 544 if es_eq(val, "evening" as *u8) == 1 { t10 = 1 } 545 if es_eq(val, "night" as *u8) == 1 { t10 = 1 } 546 if t10 == 1 { pass[0] = pass[0] + 1; es_puts("T10 tick advances ambient state to real clock: PASS\n" as *u8) } else { es_puts("T10 tick advances ambient state to real clock: FAIL\n" as *u8) } 547 // T11 CONFLICT-RESOLUTION: an agent-set field survives a tick (your interaction sticks; drift does not 548 // clobber intent). Fresh session -> last_tick=0, so activity set now (epoch>0) is NOT re-drifted. 549 let S3: *u8 = sys_mmap(64) 550 let s3o: i64 = es_cpz(S3, S) 551 S3[s3o] = 98 as u8; S3[s3o + 1] = 0 as u8 // S + 'b' = a distinct fresh session 552 es_set_field(S3, "activity" as *u8, "reading_a_book" as *u8) 553 es_tick(S3) 554 es_get_field(S3, "activity" as *u8, val) 555 var t11: i64 = 0 556 if es_eq(val, "reading_a_book" as *u8) == 1 { t11 = 1 } 557 if t11 == 1 { pass[0] = pass[0] + 1; es_puts("T11 agent override survives tick (drift respects intent): PASS\n" as *u8) } else { es_puts("T11 agent override survives tick (drift respects intent): FAIL\n" as *u8) } 558 let vb: *u8 = sys_mmap(128) 559 var vo: i64 = es_cat(vb, 0, "nx_elara_state selftest T=12 PASS=" as *u8) 560 vo = es_udec(vb, vo, pass[0]) 561 if pass[0] == 12 { vo = es_cat(vb, vo, " verdict=GREEN" as *u8) } else { vo = es_cat(vb, vo, " verdict=RED" as *u8) } 562 vo = es_ch(vb, vo, 10) 563 sys_write(1, vb, vo) 564 if pass[0] == 12 { return 0 } 565 return 1 566} 567 568// context <session>: the INTEGRATION KEYSTONE -- join her live state with the grammar's RICH outfit 569// description into a persona-ready block, so the chat persona (F917) and gen composer read ONE call and 570// know exactly what she is wearing, where, and how she feels. Emits structured fields + a `narrative` 571// string ready to inject into a prompt. This is "what she SAYS == what she WEARS == where she IS" made queryable. 572func es_context(session: *u8) -> i64 { 573 let outfit: *u8 = sys_mmap(ES_MAGIC_4096) 574 let location: *u8 = sys_mmap(ES_MAGIC_4096) 575 let mood: *u8 = sys_mmap(ES_MAGIC_4096) 576 let activity: *u8 = sys_mmap(ES_MAGIC_4096) 577 let dynamic: *u8 = sys_mmap(ES_MAGIC_4096) 578 let energy: *u8 = sys_mmap(ES_MAGIC_4096) 579 let arousal: *u8 = sys_mmap(ES_MAGIC_4096) 580 es_get_field(session, "outfit" as *u8, outfit) 581 es_get_field(session, "location" as *u8, location) 582 es_get_field(session, "mood" as *u8, mood) 583 es_get_field(session, "activity" as *u8, activity) 584 es_get_field(session, "dynamic" as *u8, dynamic) 585 es_get_field(session, "energy" as *u8, energy) 586 es_get_field(session, "arousal" as *u8, arousal) 587 // join the outfit_key -> its rich render description + display name 588 let oname: *u8 = sys_mmap(ES_MAGIC_4096) 589 let odesc: *u8 = sys_mmap(ES_MAGIC_4096) 590 let loctags: *u8 = sys_mmap(ES_MAGIC_4096) 591 let nsfw: *u8 = sys_mmap(ES_MAGIC_4096) 592 oname[0] = 0 as u8; odesc[0] = 0 as u8 593 if es_eq(outfit, "unset" as *u8) == 0 { es_find_outfit(outfit, loctags, nsfw, oname, odesc) } 594 let out: *u8 = sys_mmap(ES_MAGIC_16384) 595 var o: i64 = 0 596 o = es_ch(out, o, 123) 597 o = es_cat(out, o, "\"session\":\"" as *u8); o = es_jesc(out, o, session, es_len(session)); o = es_ch(out, o, 34) 598 o = es_cat(out, o, ",\"outfit_key\":\"" as *u8); o = es_jesc(out, o, outfit, es_len(outfit)); o = es_ch(out, o, 34) 599 o = es_cat(out, o, ",\"outfit_name\":\"" as *u8); o = es_jesc(out, o, oname, es_len(oname)); o = es_ch(out, o, 34) 600 o = es_cat(out, o, ",\"outfit_description\":\"" as *u8); o = es_jesc(out, o, odesc, es_len(odesc)); o = es_ch(out, o, 34) 601 o = es_cat(out, o, ",\"location\":\"" as *u8); o = es_jesc(out, o, location, es_len(location)); o = es_ch(out, o, 34) 602 o = es_cat(out, o, ",\"mood\":\"" as *u8); o = es_jesc(out, o, mood, es_len(mood)); o = es_ch(out, o, 34) 603 o = es_cat(out, o, ",\"activity\":\"" as *u8); o = es_jesc(out, o, activity, es_len(activity)); o = es_ch(out, o, 34) 604 o = es_cat(out, o, ",\"dynamic\":\"" as *u8); o = es_jesc(out, o, dynamic, es_len(dynamic)); o = es_ch(out, o, 34) 605 // the persona-ready narrative line 606 o = es_cat(out, o, ",\"narrative\":\"" as *u8) 607 // pick the wearing CLAUSE so it never doubles "wearing" (prompt_fragment already starts with it): 608 // rich description reads "wearing a ..." -> use as-is after "You are"; else "wearing the <Name>"; else the key. 609 o = es_cat(out, o, "You are " as *u8) 610 if es_len(odesc) > 0 { o = es_jesc(out, o, odesc, es_len(odesc)) } else { 611 if es_len(oname) > 0 { o = es_cat(out, o, "wearing the " as *u8); o = es_jesc(out, o, oname, es_len(oname)) } else { 612 o = es_cat(out, o, "wearing " as *u8); o = es_jesc(out, o, outfit, es_len(outfit)) 613 } 614 } 615 o = es_cat(out, o, ", in the " as *u8); o = es_jesc(out, o, location, es_len(location)) 616 o = es_cat(out, o, ", feeling " as *u8); o = es_jesc(out, o, mood, es_len(mood)) 617 o = es_cat(out, o, " while " as *u8); o = es_jesc(out, o, activity, es_len(activity)) 618 o = es_cat(out, o, ". Your relational dynamic is " as *u8); o = es_jesc(out, o, dynamic, es_len(dynamic)) 619 o = es_cat(out, o, ".\"" as *u8) 620 o = es_ch(out, o, 125) 621 o = es_ch(out, o, 10) 622 sys_write(1, out, o) 623 return 0 624} 625 626// her timezone offset from UTC (operator is US Central; CDT = UTC-5 in summer). A named default, not a 627// buried magic number -- a real deployment would read this from her card. -18000s = -5h. 628const ES_TZ_OFFSET_SEC: i64 = 0 - 18000 629 630func es_cpz(dst: *u8, src: *u8) -> i64 { var i: i64=0; while src[i]!=(0 as u8){ dst[i]=src[i]; i=i+1 } dst[i]=0 as u8; return i } 631 632// map a real-clock epoch to her whole AMBIENT day-state: time-of-day arc_stage, energy, a routine activity, 633// and a mood baseline. GROUNDED IN REAL TIME, not an invented decay curve -- she is sleepy at night and 634// having coffee in the morning because it IS that hour. Returns the local hour. 635func es_daystate(epoch: i64, stage_out: *u8, energy_out: *u8, act_out: *u8, mood_out: *u8) -> i64 { 636 let local: i64 = epoch + ES_TZ_OFFSET_SEC 637 var h: i64 = (local / ES_MAGIC_3600) % 24 638 if h < 0 { h = h + 24 } 639 var stage: *u8 = "night" as *u8; var energy: *u8 = "sleepy" as *u8 640 var act: *u8 = "getting sleepy" as *u8; var mood: *u8 = "drowsy" as *u8 641 if h >= 5 { if h <= 11 { stage="morning" as *u8; energy="rested" as *u8; act="having her morning coffee" as *u8; mood="bright" as *u8 } } 642 if h >= 12 { if h <= 17 { stage="afternoon" as *u8; energy="energetic" as *u8; act="busy with her day" as *u8; mood="content" as *u8 } } 643 if h >= 18 { if h <= 22 { stage="evening" as *u8; energy="relaxed" as *u8; act="unwinding for the evening" as *u8; mood="relaxed" as *u8 } } 644 es_cpz(stage_out, stage); es_cpz(energy_out, energy); es_cpz(act_out, act); es_cpz(mood_out, mood) 645 return h 646} 647 648// the stored epoch of a field's last write (es_set_field records value\t<epoch>). 0 if never set. 649// Lets tick tell an AGENT override (recent) from an ambient value it may re-drift. 650func es_field_epoch(session: *u8, field: *u8) -> i64 { 651 let kb: *u8 = sys_mmap(512) 652 es_key(kb, session, field) 653 let po: *i64 = sys_mmap(16) as *i64 654 let lo: *i64 = sys_mmap(16) as *i64 655 if reg_get(ES_STORE, "es:" as *u8, kb, po, lo) == 1 { 656 let src: *u8 = po[0] as *u8 657 let n: i64 = lo[0] 658 var ti: i64 = 0 - 1 659 var i: i64 = 0 660 while i < n { if src[i] == (9 as u8) { if ti < 0 { ti = i } } i = i + 1 } 661 if ti < 0 { return 0 } 662 var e: i64 = 0 663 var j: i64 = ti + 1 664 while j < n { let c: i64 = src[j] as i64; if c >= 48 { if c <= 57 { e = e * 10 + (c - 48) } } j = j + 1 } 665 return e 666 } 667 return 0 668} 669 670// tick <session>: advance her AMBIENT state (time-of-day arc_stage + energy) to the real clock -- the 671// "flows through the day" updater (F920 rung 1). Meant to run periodically (cron) so she keeps existing 672// between interactions; intentional agent overrides win via last-write-wins. Does NOT touch 673// outfit/location/mood/activity/dynamic (those are user/agent-driven). 674func es_tick(session: *u8) -> i64 { 675 let now: i64 = sys_now_realtime_sec() 676 let stage: *u8 = sys_mmap(64) 677 let energy: *u8 = sys_mmap(64) 678 let ract: *u8 = sys_mmap(128) 679 let rmood: *u8 = sys_mmap(64) 680 es_daystate(now, stage, energy, ract, rmood) 681 // last_tick = the epoch of the previous tick; a field touched AFTER it was an intentional override. 682 let lt: i64 = es_field_epoch(session, "_last_tick" as *u8) 683 // arc_stage + energy ARE the clock -> always advance them. 684 es_set_field(session, "arc_stage" as *u8, stage) 685 es_set_field(session, "energy" as *u8, energy) 686 // activity + mood DRIFT with the day, but only if you have not set them since the last tick 687 // ("influenced by our interactions": an intentional override sticks until the next natural drift). 688 if es_field_epoch(session, "activity" as *u8) <= lt { es_set_field(session, "activity" as *u8, ract) } 689 if es_field_epoch(session, "mood" as *u8) <= lt { es_set_field(session, "mood" as *u8, rmood) } 690 es_set_field(session, "_last_tick" as *u8, "t" as *u8) 691 es_emit_state(session) 692 return 0 693} 694 695func main(argc: i64, argv: *i64) -> i64 { 696 sys_mkdir("knowledge" as *u8, 511) 697 sys_mkdir("knowledge/store" as *u8, 511) 698 if argc >= 2 { if es_eq((argv[1]) as *u8, "selftest" as *u8) == 1 { return es_selftest() } } 699 if argc < 3 { 700 es_puts("usage: nx_elara_state get <session> | set <session> <field> <value> | timeline <session> [max] | selftest\n" as *u8) 701 return 2 702 } 703 let verb: *u8 = (argv[1]) as *u8 704 let session: *u8 = (argv[2]) as *u8 705 if es_eq(verb, "get" as *u8) == 1 { return es_emit_state(session) } 706 if es_eq(verb, "context" as *u8) == 1 { return es_context(session) } 707 if es_eq(verb, "tick" as *u8) == 1 { return es_tick(session) } 708 if es_eq(verb, "timeline" as *u8) == 1 { 709 var mx: i64 = 0 710 if argc >= 4 { 711 let a3: *u8 = (argv[3]) as *u8 712 var k: i64 = 0 713 while a3[k] != (0 as u8) { let c: i64 = a3[k] as i64; if c >= 48 { if c <= 57 { mx = mx * 10 + (c - 48) } } k = k + 1 } 714 } 715 es_timeline_emit(session, mx) 716 return 0 717 } 718 if es_eq(verb, "set" as *u8) == 1 { 719 if argc < 5 { es_puts("{\"error\":\"set needs <field> <value>\"}\n" as *u8); return 2 } 720 let field: *u8 = (argv[3]) as *u8 721 let value: *u8 = (argv[4]) as *u8 722 if es_field_index(field) < 0 { 723 es_puts("{\"error\":\"unknown field; settable = outfit location mood arousal energy activity arc_stage dynamic\"}\n" as *u8) 724 return 3 725 } 726 if es_set_field(session, field, value) != 0 { es_puts("{\"error\":\"state write failed\"}\n" as *u8); return 4 } 727 es_emit_state(session) 728 return 0 729 } 730 if es_eq(verb, "dress" as *u8) == 1 { 731 if argc < 4 { es_puts("{\"error\":\"dress needs <outfit_key> [location]\"}\n" as *u8); return 2 } 732 let ok: *u8 = (argv[3]) as *u8 733 var loc: *u8 = "" as *u8 734 var hl: i64 = 0 735 if argc >= 5 { loc = (argv[4]) as *u8; hl = 1 } 736 return es_dress(session, ok, loc, hl) 737 } 738 es_puts("{\"error\":\"unknown verb\"}\n" as *u8) 739 return 2 740}