code wiki / _hdl_build / nx_worklog_ingest_gate.nx
nx_worklog_ingest_gate.nx source
↩ module page · 125 lines · 6902 B
1import "nx_gate_gn.nx"
2// nx_worklog_ingest_gate.nx -- hermetic gate for the transcript ingestor. Builds a fixture .jsonl
3// (two real tool_use lines + a stop_reason:"tool_use" DECOY + a deliberately INCOMPLETE trailing
4// line) and proves the load-bearing properties mechanically:
5// T1 captures exactly the complete tool_use actions (granular, decoy excluded, partial line held).
6// T2 tool + target extracted correctly from input (file_path / command).
7// T3 (NEG/idempotence) a second run captures 0 -- the cursor prevents duplicate lines (this is what
8// lets PostToolUse + Stop + Cron all fire safely). THE load-bearing test.
9// T4 completing the partial line -> next run captures exactly it (incremental, line-boundary cursor).
10// T5 (NEG) the decoy ("tool_use" only as a stop_reason / bare value) is NEVER captured.
11// Sovereign: imports nx_syscalls + the ingest lib only. license_tier: ORIGINAL
12import "nx_syscalls.nx"
13import "nx_worklog_ingest_lib.nx"
14import "nx_gate_verdict.nx"
15
16const GDIR: *u8 = "/tmp/nx_wli_gate"
17const GT: *u8 = "/tmp/nx_wli_gate/transcript.jsonl"
18const GC: *u8 = "/tmp/nx_wli_gate/cursor.cur"
19const GW: *u8 = "/tmp/nx_wli_gate/worklog.tsv"
20
21func gp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
22func gstrlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
23
24func gtrunc(path: *u8, content: *u8) -> i64 {
25 let fd: i64 = sys_openat_wr(path, 420)
26 if fd < 0 { return 0 - 1 }
27 let n: i64 = gstrlen(content)
28 if n > 0 { sys_write(fd, content, n) }
29 sys_close(fd)
30 return 0
31}
32func gappend(path: *u8, content: *u8) -> i64 {
33 let fd: i64 = sys_openat_append(path, 420)
34 if fd < 0 { return 0 - 1 }
35 sys_write(fd, content, gstrlen(content))
36 sys_close(fd)
37 return 0
38}
39func gread(path: *u8, buf: *u8, cap: i64) -> i64 {
40 let fd: i64 = sys_openat_rd(path)
41 if fd < 0 { return 0 - 1 }
42 var total: i64 = 0
43 var nrd: i64 = sys_read(fd, buf, cap)
44 while nrd > 0 { total = total + nrd; if total >= cap { nrd = 0 } else { nrd = sys_read(fd, ((buf as i64) + total) as *u8, cap - total) } }
45 sys_close(fd)
46 return total
47}
48func gfind(buf: *u8, n: i64, pat: *u8) -> i64 {
49 var pl: i64 = 0; while pat[pl] != (0 as u8) { pl = pl + 1 }
50 if pl == 0 { return 0 - 1 }
51 var i: i64 = 0
52 while i + pl <= n {
53 var j: i64 = 0; var ok: i64 = 1
54 while j < pl { if buf[i + j] != pat[j] { ok = 0; j = pl } else { j = j + 1 } }
55 if ok == 1 { return i }
56 i = i + 1
57 }
58 return 0 - 1
59}
60func gcount(buf: *u8, n: i64, c: i64) -> i64 { var cnt: i64 = 0; var i: i64 = 0; while i < n { if (buf[i] as i64) == c { cnt = cnt + 1 } i = i + 1 } return cnt }
61
62func main(argc: i64, argv: *i64) -> i64 {
63 gp("=== nx_worklog_ingest_gate (transcript capture + idempotent cursor) ===\n" as *u8)
64 sys_mkdir(GDIR, 511)
65
66 // clean slate: empty worklog + empty cursor (absent/empty -> offset 0).
67 gtrunc(GW, "" as *u8)
68 gtrunc(GC, "" as *u8)
69
70 // fixture: two real tool_use lines, a decoy, then an INCOMPLETE 4th line (no newline).
71 gtrunc(GT, "{\"message\":{\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_a\",\"name\":\"Read\",\"input\":{\"file_path\":\"/tmp/foo.md\"}}]},\"type\":\"assistant\",\"timestamp\":\"t1\"}\n" as *u8)
72 gappend(GT, "{\"message\":{\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_b\",\"name\":\"Bash\",\"input\":{\"command\":\"echo hi\",\"description\":\"d\"}}]},\"type\":\"assistant\",\"timestamp\":\"t2\"}\n" as *u8)
73 gappend(GT, "{\"message\":{\"role\":\"assistant\",\"stop_reason\":\"tool_use\",\"content\":[{\"type\":\"text\",\"text\":\"no tool here\"}]},\"type\":\"assistant\",\"timestamp\":\"t3\"}\n" as *u8)
74 gappend(GT, "{\"message\":{\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_d\",\"name\":\"Write\"," as *u8)
75
76 var pass: i64 = 0
77 var fail: i64 = 0
78
79 let wbuf: *u8 = sys_mmap(65536)
80
81 // T1: ingest captures exactly the 2 complete tool_use actions (decoy + partial excluded).
82 let c1: i64 = wli_ingest(GT, GC, GW)
83 if c1 == 2 { pass = pass + 1; gp(" T1 capture-count==2 PASS\n" as *u8) } else { fail = fail + 1; gp(" T1 capture-count FAIL got=" as *u8); gn(c1); gp("\n" as *u8) }
84
85 // T2: tool + target extracted from input (file_path for Read, command for Bash).
86 let w1: i64 = gread(GW, wbuf, 65536)
87 var t2: i64 = 1
88 if gfind(wbuf, w1, "Read" as *u8) < 0 { t2 = 0 }
89 if gfind(wbuf, w1, "/tmp/foo.md" as *u8) < 0 { t2 = 0 }
90 if gfind(wbuf, w1, "Bash" as *u8) < 0 { t2 = 0 }
91 if gfind(wbuf, w1, "echo hi" as *u8) < 0 { t2 = 0 }
92 if gfind(wbuf, w1, "ingest" as *u8) < 0 { t2 = 0 }
93 if t2 == 1 { pass = pass + 1; gp(" T2 tool+target-extracted PASS\n" as *u8) } else { fail = fail + 1; gp(" T2 extraction FAIL\n" as *u8) }
94
95 // T3 (NEG / idempotence): a second run captures NOTHING (cursor) and the log is unchanged.
96 let nl1: i64 = gcount(wbuf, w1, 10)
97 let c2: i64 = wli_ingest(GT, GC, GW)
98 let w2: i64 = gread(GW, wbuf, 65536)
99 let nl2: i64 = gcount(wbuf, w2, 10)
100 if c2 == 0 { if nl2 == nl1 { pass = pass + 1; gp(" T3 idempotent-second-run(0) PASS\n" as *u8) } else { fail = fail + 1; gp(" T3 log-grew FAIL\n" as *u8) } } else { fail = fail + 1; gp(" T3 re-captured FAIL got=" as *u8); gn(c2); gp("\n" as *u8) }
101
102 // T4: complete the partial line -> next run captures exactly it (incremental, line-boundary).
103 gappend(GT, "\"input\":{\"file_path\":\"/tmp/bar.md\"}}]},\"type\":\"assistant\",\"timestamp\":\"t4\"}\n" as *u8)
104 let c3: i64 = wli_ingest(GT, GC, GW)
105 let w3: i64 = gread(GW, wbuf, 65536)
106 var t4: i64 = 1
107 if c3 != 1 { t4 = 0 }
108 if gfind(wbuf, w3, "Write" as *u8) < 0 { t4 = 0 }
109 if gfind(wbuf, w3, "/tmp/bar.md" as *u8) < 0 { t4 = 0 }
110 if t4 == 1 { pass = pass + 1; gp(" T4 incremental-capture(Write) PASS\n" as *u8) } else { fail = fail + 1; gp(" T4 incremental FAIL c3=" as *u8); gn(c3); gp("\n" as *u8) }
111
112 // T5 (NEG): the decoy is never captured (anchor is "type":"tool_use", not the bare value).
113 if gfind(wbuf, w3, "no tool here" as *u8) < 0 { pass = pass + 1; gp(" T5 decoy-never-captured PASS\n" as *u8) } else { fail = fail + 1; gp(" T5 decoy-leaked FAIL\n" as *u8) }
114
115 gp("RESULT pass=" as *u8); gn(pass); gp(" fail=" as *u8); gn(fail)
116 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
117 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
118 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
119 let ctr__dry: *i64 = gv_ctr()
120 ctr__dry[0] = pass
121 ctr__dry[1] = pass + fail
122 let rc__dry: i64 = gv_verdict("WORKLOG-INGEST-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
123 sys_exit(rc__dry)
124 return rc__dry
125}