code wiki / (root) / nx_chat_swipe_gate.nx

nx_chat_swipe_gate.nx source

↩ module page · 166 lines · 10054 B

1// nx_chat_swipe_gate.nx -- the REFEREE for companionchat CC4 (the swipe loop in nx_companion_persona.nx): the chat log stays 2// append-only and branch-aware -- a swipe is a SIBLING reply (never an overwrite) and shows by default, a select picks a 3// sibling and persists, an edit overrides the displayed text while the original row remains, the regenerate path loads 4// history WITHOUT the turn being re-answered, the partition (rows = users+assistants+swipes+selects+edits+other) sums and 5// is printed, and a plain user/assistant log loads to the byte-identical legacy shape. GPU-free, in-process; the fixture 6// log lives under /tmp/<gate>/ (the lib reads elara_mem.log from the cwd, so the gate chdirs into its scratch dir). 7// license_tier: ORIGINAL expect_exit: 0 8import "nx_syscalls.nx" 9import "nx_gate_verdict.nx" 10import "nx_companion_persona.nx" 11 12const SG_DIR: *u8 = "/tmp/nx_chat_swipe_gate" as *u8 13const SG_LOG: *u8 = "/tmp/nx_chat_swipe_gate/elara_mem.log" as *u8 14const SG_MODE_DIR: i64 = 511 15const SG_MODE_FILE: i64 = 420 16const SG_OUT_CAP: i64 = 65536 17const SG_INFO_CAP: i64 = 64 18const SG_MAXLINES: i64 = 32 19const SG_PLAIN: *u8 = "user\thi elara\nassistant\they you, missed you\nuser\thow was the beach\nassistant\tgolden and warm, wish you were there\n" as *u8 20const SG_PLAIN_JSON: *u8 = ",{\"role\":\"user\",\"content\":\"hi elara\"},{\"role\":\"assistant\",\"content\":\"hey you, missed you\"},{\"role\":\"user\",\"content\":\"how was the beach\"},{\"role\":\"assistant\",\"content\":\"golden and warm, wish you were there\"}" as *u8 21const SG_T2_ORIG: *u8 = "golden and warm, wish you were there" as *u8 22const SG_T2_SWIPE: *u8 = "quiet today, I found a shell for you" as *u8 23const SG_T2_EDIT: *u8 = "golden and warm -- next time you come with me" as *u8 24const SG_T1_REPLY: *u8 = "hey you, missed you" as *u8 25const SG_T1_USER: *u8 = "hi elara" as *u8 26const SG_T2_USER: *u8 = "how was the beach" as *u8 27const SG_ORPHAN_LOG: *u8 = "assistant\ta reply with no turn\nuser\thello\nassistant\thi\n" as *u8 28const SG_OUT_OF_RANGE: *u8 = "7" as *u8 29const SG_SELECT_FIRST: *u8 = "0" as *u8 30 31func sg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 32func sg_eqn(a: *u8, an: i64, b: *u8) -> i64 { 33 if sg_len(b) != an { return 0 } 34 var i: i64 = 0 35 while i < an { if a[i] != b[i] { return 0 } i = i + 1 } 36 return 1 37} 38func sg_find(buf: *u8, n: i64, needle: *u8) -> i64 { 39 let nl: i64 = sg_len(needle) 40 if nl <= 0 { return 0 - 1 } 41 var i: i64 = 0 42 while i + nl <= n { 43 var j: i64 = 0 44 var same: i64 = 1 45 var scan: i64 = 1 46 while scan == 1 { if j >= nl { scan = 0 } else { if buf[i + j] != needle[j] { same = 0; scan = 0 } else { j = j + 1 } } } 47 if same == 1 { return i } 48 i = i + 1 49 } 50 return 0 - 1 51} 52func sg_write(path: *u8, body: *u8) -> i64 { 53 let fd: i64 = sys_openat_wr(path, SG_MODE_FILE) 54 if fd < 0 { return 0 - 1 } 55 sys_write(fd, body, sg_len(body)) 56 sys_close(fd) 57 return 0 58} 59// whole log as bytes (for the never-overwrites tooth): returns size, buffer in bp[0] 60func sg_log_bytes(bp: *i64) -> i64 { 61 let lp: *i64 = sys_mmap(16) as *i64 62 lp[0] = 0 63 let b: *u8 = sys_read_file(SG_LOG, lp) 64 bp[0] = b as i64 65 if (b as i64) == 0 { return 0 } 66 return lp[0] 67} 68// is a[0..an) a byte-prefix of b[0..bn)? 69func sg_is_prefix(a: *u8, an: i64, b: *u8, bn: i64) -> i64 { 70 if an > bn { return 0 } 71 var i: i64 = 0 72 while i < an { if a[i] != b[i] { return 0 } i = i + 1 } 73 return 1 74} 75// the partition field `"<key>":<n>` -- returns n, or -1 when absent 76func sg_field(buf: *u8, n: i64, key: *u8) -> i64 { 77 let p: i64 = sg_find(buf, n, key) 78 if p < 0 { return 0 - 1 } 79 var i: i64 = p + sg_len(key) 80 var v: i64 = 0 81 var seen: i64 = 0 82 var scan: i64 = 1 83 while scan == 1 { 84 if i >= n { scan = 0 } else { 85 let d: i64 = buf[i] & 0xff 86 if d >= 48 { if d <= 57 { v = v * 10 + (d - 48); seen = 1; i = i + 1 } else { scan = 0 } } else { scan = 0 } 87 } 88 } 89 if seen == 0 { return 0 - 1 } 90 return v 91} 92 93func main() -> i64 { 94 gv_head("nx_chat_swipe_gate -- CC4: a swipe is a sibling never an overwrite, select and edit persist additively, regen loads history without the re-answered turn, the partition sums" as *u8) 95 let ctr: *i64 = gv_ctr() 96 sys_mkdir(SG_DIR, SG_MODE_DIR) 97 let cd: i64 = sys_chdir(SG_DIR) 98 gv_check("setup-scratch-cwd-entered" as *u8, cd == 0, ctr) 99 let out: *u8 = sys_mmap(SG_OUT_CAP) 100 let info: *i64 = sys_mmap(SG_INFO_CAP) as *i64 101 let bp: *i64 = sys_mmap(16) as *i64 102 103 // T1 the plain two-turn log: parsed as two turns, loaded as the legacy byte shape 104 sg_write(SG_LOG, SG_PLAIN) 105 var pn: i64 = go_mem_partition(out, 0) 106 gv_check("fixture-reached-condition-plain-log-two-turns-two-replies-sum-ok" as *u8, (sg_field(out, pn, "\"users\":" as *u8) == 2) & (sg_field(out, pn, "\"assistants\":" as *u8) == 2) & (sg_field(out, pn, "\"turns\":" as *u8) == 2) & (sg_field(out, pn, "\"sum_ok\":" as *u8) == 1), ctr) 107 var ln: i64 = go_mem_load_json(out, 0, SG_MAXLINES) 108 gv_check("plain-log-loads-to-the-byte-identical-legacy-shape" as *u8, sg_eqn(out, ln, SG_PLAIN_JSON) == 1, ctr) 109 110 // T2 a swipe is appended as a SIBLING, shows by default, and rewrites nothing that was there before 111 let before: i64 = sg_log_bytes(bp) 112 let bbuf: *u8 = bp[0] as *u8 113 go_mem_append("swipe" as *u8, SG_T2_SWIPE) 114 let after: i64 = sg_log_bytes(bp) 115 let abuf: *u8 = bp[0] as *u8 116 gv_check("neg-control-swipe-never-rewrites-existing-rows" as *u8, (after > before) & (sg_is_prefix(bbuf, before, abuf, after) == 1), ctr) 117 ln = go_mem_load_json(out, 0, SG_MAXLINES) 118 gv_check("fresh-swipe-is-the-displayed-reply-by-default" as *u8, (sg_find(out, ln, SG_T2_SWIPE) >= 0) & (sg_find(out, ln, SG_T2_ORIG) < 0), ctr) 119 go_mem_last_turn(info) 120 gv_check("last-turn-reports-two-siblings-displaying-the-swipe" as *u8, (info[0] == 2) & (info[1] == 1) & (info[2] == 0), ctr) 121 122 // T3 select picks the earlier sibling and persists in the log; an out-of-range select is ignored and counted 123 go_mem_append("select" as *u8, SG_SELECT_FIRST) 124 ln = go_mem_load_json(out, 0, SG_MAXLINES) 125 gv_check("select-picks-an-earlier-sibling-and-persists" as *u8, (sg_find(out, ln, SG_T2_ORIG) >= 0) & (sg_find(out, ln, SG_T2_SWIPE) < 0), ctr) 126 go_mem_append("select" as *u8, SG_OUT_OF_RANGE) 127 ln = go_mem_load_json(out, 0, SG_MAXLINES) 128 pn = go_mem_partition(out, ln) 129 gv_check("neg-control-out-of-range-select-is-ignored-never-guessed" as *u8, (sg_find(out, ln, SG_T2_ORIG) >= 0) & (sg_field(((out as i64) + ln) as *u8, pn - ln, "\"select_ignored\":" as *u8) == 1), ctr) 130 131 // T4 edit overrides the displayed text; the original rows stay in the log 132 go_mem_append("edit" as *u8, SG_T2_EDIT) 133 ln = go_mem_load_json(out, 0, SG_MAXLINES) 134 let logn: i64 = sg_log_bytes(bp) 135 let lbuf: *u8 = bp[0] as *u8 136 gv_check("edit-overrides-the-displayed-reply" as *u8, (sg_find(out, ln, SG_T2_EDIT) >= 0) & (sg_find(out, ln, SG_T2_ORIG) < 0) & (sg_find(out, ln, SG_T2_SWIPE) < 0), ctr) 137 gv_check("edit-is-additive-the-original-and-the-swipe-remain-in-the-log" as *u8, (sg_find(lbuf, logn, SG_T2_ORIG) >= 0) & (sg_find(lbuf, logn, SG_T2_SWIPE) >= 0), ctr) 138 go_mem_last_turn(info) 139 gv_check("last-turn-reports-edited-with-the-selected-index" as *u8, (info[0] == 2) & (info[1] == 0) & (info[2] == 1), ctr) 140 141 // T5 the regenerate load skips the turn being re-answered and keeps the earlier turn 142 ln = go_mem_load_json_ex(out, 0, SG_MAXLINES, 1) 143 gv_check("regen-load-excludes-the-current-turn-and-keeps-the-earlier-one" as *u8, (sg_find(out, ln, SG_T1_REPLY) >= 0) & (sg_find(out, ln, SG_T2_USER) < 0) & (sg_find(out, ln, SG_T2_EDIT) < 0) & (sg_find(out, ln, SG_T2_ORIG) < 0), ctr) 144 let lu: *u8 = sys_mmap(SG_INFO_CAP * 8) 145 let lun: i64 = go_mem_last_user(lu, SG_INFO_CAP * 8) 146 gv_check("last-user-returns-the-latest-user-text" as *u8, sg_eqn(lu, lun, SG_T2_USER) == 1, ctr) 147 148 // T6 the partition sums over every kind, and the last-turn JSON carries every sibling 149 pn = go_mem_partition(out, 0) 150 gv_check("partition-sums-rows-over-every-kind" as *u8, (sg_field(out, pn, "\"rows\":" as *u8) == 8) & (sg_field(out, pn, "\"swipes\":" as *u8) == 1) & (sg_field(out, pn, "\"selects\":" as *u8) == 2) & (sg_field(out, pn, "\"edits\":" as *u8) == 1) & (sg_field(out, pn, "\"sum_ok\":" as *u8) == 1) & (sg_field(out, pn, "\"branches\":" as *u8) == 1), ctr) 151 let jn: i64 = go_mem_last_turn_json(out, 0) 152 gv_check("last-turn-json-lists-both-siblings-and-the-edited-display" as *u8, (sg_find(out, jn, SG_T2_ORIG) >= 0) & (sg_find(out, jn, SG_T2_SWIPE) >= 0) & (sg_find(out, jn, SG_T2_EDIT) >= 0) & (sg_find(out, jn, "\"edited\":1" as *u8) >= 0) & (sg_find(out, jn, "\"selected\":0" as *u8) >= 0), ctr) 153 154 // T7 NEG-CONTROLS: an empty log loads nothing and partitions to zero; a reply before any user row is an orphan, not a turn 155 sys_unlinkat(SG_LOG) 156 ln = go_mem_load_json(out, 0, SG_MAXLINES) 157 pn = go_mem_partition(out, ln) 158 gv_check("neg-control-absent-log-loads-nothing-and-reads-zero-rows" as *u8, (ln == 0) & (sg_field(((out as i64) + ln) as *u8, pn - ln, "\"rows\":" as *u8) == 0) & (go_mem_last_turn(info) == 0), ctr) 159 sg_write(SG_LOG, SG_ORPHAN_LOG) 160 pn = go_mem_partition(out, 0) 161 ln = go_mem_load_json(out, pn, SG_MAXLINES) 162 gv_check("neg-control-reply-before-any-user-row-is-an-orphan-not-a-turn" as *u8, (sg_field(out, pn, "\"orphans\":" as *u8) == 1) & (sg_field(out, pn, "\"turns\":" as *u8) == 1) & (sg_field(out, pn, "\"sum_ok\":" as *u8) == 1) & (sg_find(((out as i64) + pn) as *u8, ln - pn, "no turn" as *u8) < 0), ctr) 163 sys_unlinkat(SG_LOG) 164 165 return gv_verdict("CHAT-SWIPE-GATE" as *u8, ctr, "CC4 done-rule: regenerate produces a sibling row never an overwrite, branch selection persists in history, edit is additive with the original retained, the mainline-plus-branches partition sums and is printed" as *u8) 166}