code wiki / (root) / nx_elara_state.nx

nx_elara_state.nx source

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