code wiki / _hdl_build / nx_claims.nx

nx_claims.nx source

↩ module page · 866 lines · 37392 B

1// nx_claims.nx -- SESSION-CLAIMS AS AN ECOSYSTEM CAPABILITY (ws=ws-intel2, 2026-07-20). 2// Eats debt 1784408445 (claims protocol shell-only via WSL) + feeds 1784408708 (claims hub 3// to NAS = standup claim-holder liveness): claim/beat/release/walk become MCP tools/call 4// verbs on an append-only NAS journal -- peers of nx_ws_sync (journal) / nx_ws_cycle (phase). 5// HOLDERSHIP IS DERIVED, NEVER STORED (evidence law): latest CLAIM not RELEASEd by its 6// holder = the claim; freshness = latest CLAIM/BEAT ts by that holder vs its TTL -> 7// HELD | EXPIRED (crash-expiry BY CONSTRUCTION -- a dead session's claim self-expires, 8// the F214 lease semantics) | FREE (released) | ABSENT. Claim on a contended resource is 9// REFUSED fail-closed (exit 3) -- never silently stolen; an EXPIRED claim is claimable. 10// Frame: <ts>\t<VERB>\t<resource>\t<actor>\t<ttl>\t<note> VERB in {CLAIM, BEAT, RELEASE} 11// SCALE LAW: windowed reads + declared envelope (window_bytes/truncated/claims_capped). 12// license_tier: ORIGINAL No hw writes (Rule 26). 13// claim <journal> <resource> <actor> <ttl_sec> <note> -> HELD | CONTENDED(3) 14// beat <journal> <resource> <actor> <note> -> BEAT | NOT-HOLDER(3) 15// release <journal> <resource> <actor> <note> -> RELEASED | NOT-HOLDER(3) 16// state <journal> <resource> -> ONE-LINE probe: state=HELD|EXPIRED|FREE|ABSENT holder=.. 17// (seq543/seq552: lets nx_seat checkout classify NOT-HOLDER honestly; exit 0 always) 18// walk <journal> -> JSON all resources 19// reap <journal> <reaper> <note> -> F214: release ONLY provably-EXPIRED claims 20// (age>ttl by the claim's OWN ttl field) + ORPHAN-REAPED audit note; idempotent; exit 0 21// selftest <scratch-journal> -> gate T1..T8 (caller pre-cleans) 22import "nx_syscalls.nx" 23import "nx_gate_verdict.nx" 24const CL_MAGIC_4096: i64 = 4096 25const CL_MAGIC_2000: i64 = 2000 26const CL_MAGIC_200000: i64 = 200000 27const CL_MAGIC_5000: i64 = 5000 28 29const CL_WIN: i64 = 4194304 30const CL_OUT: i64 = 262144 31const CL_SOFT: i64 = 49152 32const CL_NOTE_MAX: i64 = 200 33const CL_NAME_MAX: i64 = 120 34// THE LEASE CEILING (2026-08-09). MEASURED: `walk` showed held=2 expired=0, BOTH held by one dead seat 35// claude-76b93d3f at ttl_sec=7200000 (83.3 DAYS) against age 16.4 days -- so age < ttl, cl_state derived 36// HELD, and cl_reap (which acts ONLY on st==2) skipped them BY CONSTRUCTION. Two lanes were locked until 37// ~2026-10-14. Proven corpus_complete=1 over 22,811 files: the ONLY ttl validation in the estate was 38// `if ttl <= 0`, with NO UPPER BOUND ANYWHERE. Live journal TTLs are 3600/5400/7200/10800/14400/21600/ 39// 86400; 7200000 is exactly 1000x the modal 7200 -- a typo nothing said no to. 40// ***HOLDERSHIP IS DERIVED SO THE HOLDER CANNOT ASSERT ITS OWN LIVENESS -- BUT THE TTL IT IS DIVIDED BY 41// WAS A NUMBER THE HOLDER CHOSE, SO THE HOLDER DEFINED ITS OWN DEATH. A LEASE WHOSE EXPIRY THE LESSEE 42// SETS IS NOT A LEASE.*** The 2026 distributed-systems rule is the same: never trust a process to know 43// that its own lock has expired. 44// 86400 MATCHES THE INCUMBENT rather than inventing a number: nx_no_cookie_session.nx (`if ttl_s > 86400 45// -> BAD_INPUT`) and nx_modern_auth_flow.nx (NX_MAUTH_HARD_MAX_TTL_S = 86400) already bound session TTL 46// at 24h, and 86400 is also the largest legitimate TTL observed in the live journal. 47const CL_TTL_MAX: i64 = 86400 48 49func cl_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 } 50func cl_catn(d: *u8, o: i64, v: i64) -> i64 { 51 let t: *u8 = sys_mmap(28) 52 var m: i64 = v 53 var p: i64 = o 54 if m < 0 { d[p]=45 as u8; p=p+1; m=0-m } 55 var k: i64 = 0 56 if m == 0 { t[0]=48 as u8; k=1 } 57 while m > 0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 58 var i: i64 = 0 59 while i < k { d[p]=t[k-1-i]; p=p+1; i=i+1 } 60 return p 61} 62func cl_vlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 63func cl_atoi_z(s: *u8) -> i64 { var v: i64=0; var i: i64=0; 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 } return v } 64func cl_read(path: *u8, buf: *u8, cap: i64) -> i64 { 65 let fd: i64 = sys_openat_rd(path) 66 if fd < 0 { return 0 } 67 var n: i64 = 0 68 var go: i64 = 1 69 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64)+n) as *u8, cap-n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } } 70 sys_close(fd) 71 return n 72} 73// append one frame: <ts>\t<verb>\t<resource>\t<actor>\t<ttl>\t<note>\n (ts<0 => real clock; note flattened) 74func cl_append(journal: *u8, ts: i64, verb: *u8, res: *u8, actor: *u8, ttl: i64, note: *u8) -> i64 { 75 var t: i64 = ts 76 if t < 0 { t = sys_now_realtime_sec() } 77 let ln: *u8 = sys_mmap(CL_MAGIC_4096) 78 var o: i64 = 0 79 o = cl_catn(ln, o, t) 80 ln[o]=9 as u8; o=o+1 81 o = cl_cat(ln, o, verb) 82 ln[o]=9 as u8; o=o+1 83 o = cl_cat(ln, o, res) 84 ln[o]=9 as u8; o=o+1 85 o = cl_cat(ln, o, actor) 86 ln[o]=9 as u8; o=o+1 87 o = cl_catn(ln, o, ttl) 88 ln[o]=9 as u8; o=o+1 89 var i: i64 = 0 90 var used: i64 = 0 91 while note[i]!=(0 as u8) { 92 if used < CL_MAGIC_2000 { 93 let c: i64 = note[i] as i64 94 if c==9 { ln[o]=32 as u8; o=o+1 } else { if c==10 { ln[o]=32 as u8; o=o+1 } else { if c==13 { ln[o]=32 as u8; o=o+1 } else { ln[o]=c as u8; o=o+1 } } } 95 used = used + 1 96 } 97 i = i + 1 98 } 99 ln[o]=10 as u8; o=o+1 100 let fd: i64 = sys_openat_append(journal, 0x1a4) 101 if fd < 0 { return -1 } 102 sys_write(fd, ln, o) 103 sys_close(fd) 104 return 0 105} 106func cl_le(q: *u8, i: i64, n: i64) -> i64 { 107 var le: i64 = i 108 var s: i64 = 1 109 while s==1 { if le>=n { s=0 } else { if q[le]==(10 as u8){s=0} else {le=le+1} } } 110 return le 111} 112func cl_col(q: *u8, ls: i64, le: i64, c: i64, out: *i64) -> i64 { 113 var col: i64 = 0 114 var p: i64 = ls 115 while col < c { 116 var s: i64 = 1 117 while s == 1 { if p >= le { return 0 } if q[p]==(9 as u8) { s = 0 } else { p = p+1 } } 118 p = p + 1 119 col = col + 1 120 } 121 var e: i64 = p 122 var s2: i64 = 1 123 while s2 == 1 { if e >= le { s2 = 0 } else { if q[e]==(9 as u8) { s2 = 0 } else { e = e+1 } } } 124 out[0] = p 125 out[1] = e 126 return 1 127} 128func cl_lit_eq(q: *u8, s: i64, e: i64, lit: *u8) -> i64 { 129 var i: i64 = 0 130 while s+i < e { if lit[i]==(0 as u8) { return 0 } if q[s+i]!=lit[i] { return 0 } i=i+1 } 131 if lit[i]!=(0 as u8) { return 0 } 132 return 1 133} 134func cl_span_eq(q: *u8, s1: i64, e1: i64, s2: i64, e2: i64) -> i64 { 135 if e1-s1 != e2-s2 { return 0 } 136 var i: i64 = 0 137 while s1+i < e1 { if q[s1+i]!=q[s2+i] { return 0 } i=i+1 } 138 return 1 139} 140func cl_atoi(q: *u8, s: i64, e: i64) -> i64 { 141 var v: i64 = 0 142 var i: i64 = s 143 while i < e { let c: i64 = q[i] as i64; if c>=48 { if c<=57 { v = v*10 + (c-48) } } i=i+1 } 144 return v 145} 146// DERIVED claim state for a resource span. Returns -1 ABSENT / 1 HELD / 2 EXPIRED / 3 FREE. 147// out[0..1]=holder span, out[2]=ttl, out[3]=last_activity_ts (valid when state 1|2). 148func cl_state(q: *u8, cx: *i64, res_s: i64, res_e: i64, out: *i64) -> i64 { 149 let n: i64 = cx[0] 150 let cv: *i64 = sys_mmap(16) as *i64 151 let cr: *i64 = sys_mmap(16) as *i64 152 let ca: *i64 = sys_mmap(16) as *i64 153 let ct: *i64 = sys_mmap(16) as *i64 154 let c0: *i64 = sys_mmap(16) as *i64 155 var mode: i64 = 0 156 var ever: i64 = 0 157 var hs: i64 = -1 158 var he: i64 = -1 159 var ttl: i64 = 0 160 var last: i64 = 0 161 var i: i64 = 0 162 while i < n { 163 let le: i64 = cl_le(q,i,n) 164 if cl_col(q,i,le,2,cr)==1 { if cl_span_eq(q,cr[0],cr[1],res_s,res_e)==1 { 165 if cl_col(q,i,le,1,cv)==1 { if cl_col(q,i,le,0,c0)==1 { if cl_col(q,i,le,3,ca)==1 { 166 let ts: i64 = cl_atoi(q,c0[0],c0[1]) 167 if cl_lit_eq(q,cv[0],cv[1],"CLAIM" as *u8)==1 { 168 mode=1 169 ever=1 170 hs=ca[0] 171 he=ca[1] 172 last=ts 173 if cl_col(q,i,le,4,ct)==1 { ttl = cl_atoi(q,ct[0],ct[1]) } 174 } 175 if cl_lit_eq(q,cv[0],cv[1],"BEAT" as *u8)==1 { 176 if mode==1 { if cl_span_eq(q,ca[0],ca[1],hs,he)==1 { last=ts } } 177 } 178 if cl_lit_eq(q,cv[0],cv[1],"RELEASE" as *u8)==1 { 179 if mode==1 { if cl_span_eq(q,ca[0],ca[1],hs,he)==1 { mode=0 } } 180 } 181 } } } 182 } } 183 i = le + 1 184 } 185 if ever==0 { return -1 } 186 if mode==0 { return 3 } 187 out[0]=hs 188 out[1]=he 189 out[2]=ttl 190 out[3]=last 191 let age: i64 = cx[1] - last 192 // THE GUARD AND ITS PAIRED REPAIR IN ONE PLACE. Bounding only the CLAIM path would fix future claims 193 // and leave the two already-written immortals locked forever -- and the estate's own law is that a 194 // guard shipped without its paired repair is a permanent outage of the thing it guards. Capping HERE, 195 // in the single derivation every consumer (walk/state/beat/release/reap) already shares, retroactively 196 // corrects out-of-policy rows WITHOUT rewriting the append-only journal (additive-only holds). 197 // FAIL DIRECTION: this can only ever make a lease expire SOONER. It cannot manufacture a false HELD. 198 // out[2] deliberately still reports the RECORDED ttl, so `walk` shows state=EXPIRED beside 199 // ttl_sec=7200000 and the original defect stays VISIBLE rather than being silently normalised. 200 var eff: i64 = ttl 201 if eff > CL_TTL_MAX { eff = CL_TTL_MAX } 202 if age > eff { return 2 } 203 return 1 204} 205func cl_state_name(st: i64) -> *u8 { 206 if st==1 { return "HELD" as *u8 } 207 if st==2 { return "EXPIRED" as *u8 } 208 if st==3 { return "FREE" as *u8 } 209 return "ABSENT" as *u8 210} 211// resource span first occurrence? (walk dedupe) 212func cl_res_seen(q: *u8, upto: i64, r_s: i64, r_e: i64) -> i64 { 213 let cr: *i64 = sys_mmap(16) as *i64 214 var i: i64 = 0 215 while i < upto { 216 let le: i64 = cl_le(q,i,upto) 217 if cl_col(q,i,le,2,cr)==1 { if cl_span_eq(q,cr[0],cr[1],r_s,r_e)==1 { return 1 } } 218 i = le + 1 219 } 220 return 0 221} 222// find span of a resource by literal name; 1 if any frame carries it 223func cl_res_span_lit(q: *u8, cx: *i64, res: *u8, out: *i64) -> i64 { 224 let n: i64 = cx[0] 225 let cr: *i64 = sys_mmap(16) as *i64 226 var i: i64 = 0 227 while i < n { 228 let le: i64 = cl_le(q,i,n) 229 if cl_col(q,i,le,2,cr)==1 { if cl_lit_eq(q,cr[0],cr[1],res)==1 { out[0]=cr[0]; out[1]=cr[1]; return 1 } } 230 i = le + 1 231 } 232 return 0 233} 234// last note (col5) for a resource 235func cl_note_span(q: *u8, cx: *i64, res_s: i64, res_e: i64, out: *i64) -> i64 { 236 let n: i64 = cx[0] 237 let cr: *i64 = sys_mmap(16) as *i64 238 let cn: *i64 = sys_mmap(16) as *i64 239 var ns: i64 = -1 240 var ne: i64 = -1 241 var i: i64 = 0 242 while i < n { 243 let le: i64 = cl_le(q,i,n) 244 if cl_col(q,i,le,2,cr)==1 { if cl_span_eq(q,cr[0],cr[1],res_s,res_e)==1 { 245 if cl_col(q,i,le,5,cn)==1 { ns=cn[0]; ne=cn[1] } 246 } } 247 i = le + 1 248 } 249 if ns >= 0 { out[0]=ns; out[1]=ne; return 1 } 250 return 0 251} 252func cl_jesc(d: *u8, o: i64, q: *u8, s: i64, e: i64, maxb: i64) -> i64 { 253 var p: i64 = o 254 var i: i64 = s 255 var used: i64 = 0 256 while i < e { 257 if used >= maxb { i = e } else { 258 let c: i64 = q[i] as i64 259 if c == 34 { d[p]=92 as u8; p=p+1; d[p]=34 as u8; p=p+1 } else { if c == 92 { d[p]=92 as u8; p=p+1; d[p]=92 as u8; p=p+1 } else { if c < 32 { d[p]=32 as u8; p=p+1 } else { d[p]=c as u8; p=p+1 } } } 260 used = used + 2 261 i = i + 1 262 } 263 } 264 return p 265} 266func cl_key(d: *u8, o: i64, name: *u8) -> i64 { 267 d[o]=34 as u8 268 var p: i64 = o + 1 269 p = cl_cat(d,p,name) 270 d[p]=34 as u8 271 p = p + 1 272 d[p]=58 as u8 273 p = p + 1 274 return p 275} 276func cl_qlit(d: *u8, o: i64, s: *u8) -> i64 { 277 var p: i64 = o 278 d[p]=34 as u8; p=p+1 279 p = cl_cat(d,p,s) 280 d[p]=34 as u8; p=p+1 281 return p 282} 283func cl_emit_res(d: *u8, o: i64, q: *u8, cx: *i64, r_s: i64, r_e: i64) -> i64 { 284 var p: i64 = o 285 let st_out: *i64 = sys_mmap(32) as *i64 286 let no: *i64 = sys_mmap(16) as *i64 287 d[p]=123 as u8; p=p+1 288 p = cl_key(d,p,"resource" as *u8) 289 d[p]=34 as u8; p=p+1 290 p = cl_jesc(d,p,q,r_s,r_e,CL_NAME_MAX) 291 d[p]=34 as u8; p=p+1 292 d[p]=44 as u8; p=p+1 293 let st: i64 = cl_state(q,cx,r_s,r_e,st_out) 294 p = cl_key(d,p,"state" as *u8) 295 let sn: *u8 = cl_state_name(st) 296 p = cl_qlit(d,p,sn) 297 d[p]=44 as u8; p=p+1 298 p = cl_key(d,p,"holder" as *u8) 299 d[p]=34 as u8; p=p+1 300 if st==1 { p = cl_jesc(d,p,q,st_out[0],st_out[1],CL_NAME_MAX) } 301 if st==2 { p = cl_jesc(d,p,q,st_out[0],st_out[1],CL_NAME_MAX) } 302 d[p]=34 as u8; p=p+1 303 d[p]=44 as u8; p=p+1 304 p = cl_key(d,p,"ttl_sec" as *u8) 305 var tv: i64 = -1 306 if st==1 { tv = st_out[2] } 307 if st==2 { tv = st_out[2] } 308 p = cl_catn(d,p,tv) 309 d[p]=44 as u8; p=p+1 310 p = cl_key(d,p,"age_sec" as *u8) 311 var age: i64 = -1 312 if st==1 { age = cx[1] - st_out[3] } 313 if st==2 { age = cx[1] - st_out[3] } 314 p = cl_catn(d,p,age) 315 d[p]=44 as u8; p=p+1 316 p = cl_key(d,p,"last_note" as *u8) 317 d[p]=34 as u8; p=p+1 318 let hn: i64 = cl_note_span(q,cx,r_s,r_e,no) 319 if hn==1 { p = cl_jesc(d,p,q,no[0],no[1],CL_NOTE_MAX) } 320 d[p]=34 as u8; p=p+1 321 d[p]=125 as u8; p=p+1 322 return p 323} 324func cl_walk_json(q: *u8, cx: *i64, d: *u8) -> i64 { 325 let n: i64 = cx[0] 326 var p: i64 = 0 327 d[p]=123 as u8; p=p+1 328 p = cl_key(d,p,"v" as *u8) 329 p = cl_catn(d,p,1) 330 d[p]=44 as u8; p=p+1 331 p = cl_key(d,p,"tool" as *u8) 332 p = cl_qlit(d,p,"nx_claims" as *u8) 333 d[p]=44 as u8; p=p+1 334 p = cl_key(d,p,"journal" as *u8) 335 d[p]=34 as u8; p=p+1 336 let jp: *u8 = cx[5] as *u8 337 let jl: i64 = cl_vlen(jp) 338 p = cl_jesc(d,p,jp,0,jl,200) 339 d[p]=34 as u8; p=p+1 340 d[p]=44 as u8; p=p+1 341 p = cl_key(d,p,"journal_bytes" as *u8) 342 p = cl_catn(d,p,n) 343 d[p]=44 as u8; p=p+1 344 p = cl_key(d,p,"window_bytes" as *u8) 345 p = cl_catn(d,p,CL_WIN) 346 d[p]=44 as u8; p=p+1 347 p = cl_key(d,p,"truncated" as *u8) 348 p = cl_catn(d,p,cx[4]) 349 d[p]=44 as u8; p=p+1 350 p = cl_key(d,p,"now" as *u8) 351 p = cl_catn(d,p,cx[1]) 352 d[p]=44 as u8; p=p+1 353 // totals pass 354 let cr: *i64 = sys_mmap(16) as *i64 355 let st_out: *i64 = sys_mmap(32) as *i64 356 var theld: i64 = 0 357 var texp: i64 = 0 358 var tfree: i64 = 0 359 var i: i64 = 0 360 while i < n { 361 let le: i64 = cl_le(q,i,n) 362 if cl_col(q,i,le,2,cr)==1 { if cl_res_seen(q,i,cr[0],cr[1])==0 { 363 let st: i64 = cl_state(q,cx,cr[0],cr[1],st_out) 364 if st==1 { theld=theld+1 } 365 if st==2 { texp=texp+1 } 366 if st==3 { tfree=tfree+1 } 367 } } 368 i = le + 1 369 } 370 p = cl_key(d,p,"totals" as *u8) 371 d[p]=123 as u8; p=p+1 372 p = cl_key(d,p,"held" as *u8) 373 p = cl_catn(d,p,theld) 374 d[p]=44 as u8; p=p+1 375 p = cl_key(d,p,"expired" as *u8) 376 p = cl_catn(d,p,texp) 377 d[p]=44 as u8; p=p+1 378 p = cl_key(d,p,"free" as *u8) 379 p = cl_catn(d,p,tfree) 380 d[p]=125 as u8; p=p+1 381 d[p]=44 as u8; p=p+1 382 p = cl_key(d,p,"resources" as *u8) 383 d[p]=91 as u8; p=p+1 384 var capped: i64 = 0 385 var first: i64 = 1 386 var j: i64 = 0 387 while j < n { 388 let je: i64 = cl_le(q,j,n) 389 if cl_col(q,j,je,2,cr)==1 { if cl_res_seen(q,j,cr[0],cr[1])==0 { 390 if p > CL_SOFT { capped=1 } else { 391 if first==0 { d[p]=44 as u8; p=p+1 } 392 first=0 393 p = cl_emit_res(d,p,q,cx,cr[0],cr[1]) 394 } 395 } } 396 j = je + 1 397 } 398 d[p]=93 as u8; p=p+1 399 d[p]=44 as u8; p=p+1 400 p = cl_key(d,p,"claims_capped" as *u8) 401 p = cl_catn(d,p,capped) 402 d[p]=125 as u8; p=p+1 403 d[p]=10 as u8; p=p+1 404 return p 405} 406func cl_hesc(d: *u8, o: i64, q: *u8, s: i64, e: i64, maxb: i64) -> i64 { 407 var p: i64 = o 408 var i: i64 = s 409 var used: i64 = 0 410 while i < e { 411 if used >= maxb { i = e } else { 412 let c: i64 = q[i] as i64 413 if c == 60 { p = cl_cat(d,p,"&lt;" as *u8) } else { if c == 62 { p = cl_cat(d,p,"&gt;" as *u8) } else { if c == 38 { p = cl_cat(d,p,"&amp;" as *u8) } else { if c < 32 { d[p]=32 as u8; p=p+1 } else { d[p]=c as u8; p=p+1 } } } } 414 used = used + 5 415 i = i + 1 416 } 417 } 418 return p 419} 420func cl_page_html(q: *u8, cx: *i64, d: *u8) -> i64 { 421 let n: i64 = cx[0] 422 var p: i64 = 0 423 p = cl_cat(d,p,"<" as *u8) 424 d[p]=33 as u8 425 p = p + 1 426 p = cl_cat(d,p,"doctype html><html><head><meta charset=utf-8><title>Nishi Claims</title></head><body>" as *u8) 427 p = cl_cat(d,p,"<h1>Nishi Claims -- who holds what (TTL crash-expiry, derived never asserted)</h1>" as *u8) 428 let cr: *i64 = sys_mmap(16) as *i64 429 let st_out: *i64 = sys_mmap(32) as *i64 430 let no: *i64 = sys_mmap(16) as *i64 431 var theld: i64 = 0 432 var texp: i64 = 0 433 var tfree: i64 = 0 434 var i: i64 = 0 435 while i < n { 436 let le: i64 = cl_le(q,i,n) 437 if cl_col(q,i,le,2,cr)==1 { if cl_res_seen(q,i,cr[0],cr[1])==0 { 438 let st: i64 = cl_state(q,cx,cr[0],cr[1],st_out) 439 if st==1 { theld=theld+1 } 440 if st==2 { texp=texp+1 } 441 if st==3 { tfree=tfree+1 } 442 } } 443 i = le + 1 444 } 445 p = cl_cat(d,p,"<p>held=" as *u8) 446 p = cl_catn(d,p,theld) 447 p = cl_cat(d,p," expired=" as *u8) 448 p = cl_catn(d,p,texp) 449 p = cl_cat(d,p," free=" as *u8) 450 p = cl_catn(d,p,tfree) 451 p = cl_cat(d,p,"</p>" as *u8) 452 p = cl_cat(d,p,"<table border=1><tr><th>resource</th><th>state</th><th>holder</th><th>ttl-sec</th><th>age-sec</th><th>last note</th></tr>" as *u8) 453 var truncated_rows: i64 = 0 454 var j: i64 = 0 455 while j < n { 456 let je: i64 = cl_le(q,j,n) 457 if cl_col(q,j,je,2,cr)==1 { if cl_res_seen(q,j,cr[0],cr[1])==0 { 458 if p > CL_MAGIC_200000 { truncated_rows = truncated_rows + 1 } else { 459 p = cl_cat(d,p,"<tr><td>" as *u8) 460 p = cl_hesc(d,p,q,cr[0],cr[1],CL_NAME_MAX) 461 p = cl_cat(d,p,"</td><td>" as *u8) 462 let st2: i64 = cl_state(q,cx,cr[0],cr[1],st_out) 463 let sn: *u8 = cl_state_name(st2) 464 p = cl_cat(d,p,sn) 465 p = cl_cat(d,p,"</td><td>" as *u8) 466 if st2==1 { p = cl_hesc(d,p,q,st_out[0],st_out[1],CL_NAME_MAX) } 467 if st2==2 { p = cl_hesc(d,p,q,st_out[0],st_out[1],CL_NAME_MAX) } 468 p = cl_cat(d,p,"</td><td>" as *u8) 469 var tv: i64 = -1 470 if st2==1 { tv = st_out[2] } 471 if st2==2 { tv = st_out[2] } 472 p = cl_catn(d,p,tv) 473 p = cl_cat(d,p,"</td><td>" as *u8) 474 var age: i64 = -1 475 if st2==1 { age = cx[1] - st_out[3] } 476 if st2==2 { age = cx[1] - st_out[3] } 477 p = cl_catn(d,p,age) 478 p = cl_cat(d,p,"</td><td>" as *u8) 479 let hn: i64 = cl_note_span(q,cx,cr[0],cr[1],no) 480 if hn==1 { p = cl_hesc(d,p,q,no[0],no[1],CL_NOTE_MAX) } 481 p = cl_cat(d,p,"</td></tr>" as *u8) 482 } 483 } } 484 j = je + 1 485 } 486 p = cl_cat(d,p,"</table>" as *u8) 487 if truncated_rows > 0 { 488 p = cl_cat(d,p,"<p>ENVELOPE: rows_truncated=" as *u8) 489 p = cl_catn(d,p,truncated_rows) 490 p = cl_cat(d,p,"</p>" as *u8) 491 } 492 p = cl_cat(d,p,"<p>envelope window_bytes=" as *u8) 493 p = cl_catn(d,p,CL_WIN) 494 p = cl_cat(d,p," journal_bytes=" as *u8) 495 p = cl_catn(d,p,n) 496 p = cl_cat(d,p," generated=" as *u8) 497 p = cl_catn(d,p,cx[1]) 498 p = cl_cat(d,p," | source=knowledge/status/claims.jrnl | tool=nx_claims (MCP) | <a href=/standup>standup</a> <a href=/wsmine>wsmine</a> <a href=/frontier>frontier</a></p>" as *u8) 499 p = cl_cat(d,p,"</body></html>" as *u8) 500 d[p]=10 as u8 501 p = p + 1 502 return p 503} 504func cl_find(d: *u8, dn: i64, lit: *u8) -> i64 { 505 let ll: i64 = cl_vlen(lit) 506 if ll == 0 { return 0 } 507 var i: i64 = 0 508 while i + ll <= dn { 509 var k: i64 = 0 510 var ok: i64 = 1 511 while k < ll { if d[i+k]!=lit[k] { ok=0; k=ll } else { k=k+1 } } 512 if ok==1 { return 1 } 513 i = i + 1 514 } 515 return 0 516} 517 518// F214 ORPHAN REAP -- fail-safe BY CONSTRUCTION: derive+append on ONE snapshot; release ONLY 519// claims whose state derives EXPIRED (age>ttl by the claim's OWN ttl field). NEVER by name, 520// NEVER by looks-stale, no special cases. Additive-only (RELEASE frames appended, history kept). 521// Idempotent: post-reap state=FREE so a re-run appends NOTHING. Audit=who/when/why in the note. 522func cl_span_z(q: *u8, s: i64, e: i64, d: *u8, cap: i64) -> i64 { 523 if e - s >= cap { return 0 } 524 var i: i64 = 0 525 while s + i < e { d[i] = q[s+i]; i = i + 1 } 526 d[i] = 0 as u8 527 return 1 528} 529func cl_reap(journal: *u8, q: *u8, cx: *i64, reaper: *u8, note: *u8) -> i64 { 530 let n: i64 = cx[0] 531 let cr: *i64 = sys_mmap(16) as *i64 532 let so: *i64 = sys_mmap(32) as *i64 533 let rname: *u8 = sys_mmap(512) 534 let hname: *u8 = sys_mmap(512) 535 let rnote: *u8 = sys_mmap(CL_MAGIC_4096) 536 var reaped: i64 = 0 537 var scanned: i64 = 0 538 var i: i64 = 0 539 while i < n { 540 let le: i64 = cl_le(q,i,n) 541 if cl_col(q,i,le,2,cr)==1 { if cl_res_seen(q,i,cr[0],cr[1])==0 { 542 scanned = scanned + 1 543 let st: i64 = cl_state(q,cx,cr[0],cr[1],so) 544 if st==2 { 545 let okr: i64 = cl_span_z(q,cr[0],cr[1],rname,500) 546 let okh: i64 = cl_span_z(q,so[0],so[1],hname,500) 547 if okr==1 { if okh==1 { 548 let age: i64 = cx[1] - so[3] 549 var o: i64 = 0 550 o = cl_cat(rnote,0,"ORPHAN-REAPED by=" as *u8) 551 o = cl_cat(rnote,o,reaper) 552 o = cl_cat(rnote,o," expired age=" as *u8) 553 o = cl_catn(rnote,o,age) 554 o = cl_cat(rnote,o,"s ttl=" as *u8) 555 o = cl_catn(rnote,o,so[2]) 556 o = cl_cat(rnote,o,"s " as *u8) 557 o = cl_cat(rnote,o,note) 558 rnote[o] = 0 as u8 559 let arc: i64 = cl_append(journal,-1,"RELEASE" as *u8,rname,hname,0,rnote) 560 if arc==0 { 561 reaped = reaped + 1 562 gv_puts("NX-CLAIMS REAPED resource=" as *u8) 563 gv_puts(rname) 564 gv_puts(" holder=" as *u8) 565 gv_puts(hname) 566 gv_puts(" age=" as *u8) 567 gv_num(age) 568 gv_puts(" ttl=" as *u8) 569 gv_num(so[2]) 570 gv_puts("\n" as *u8) 571 } else { 572 gv_puts("NX-CLAIMS REAP-APPEND-FAIL resource=" as *u8) 573 gv_puts(rname) 574 gv_puts("\n" as *u8) 575 } 576 } } 577 if okr==0 { gv_puts("NX-CLAIMS REAP-SKIP resource-name-too-long\n" as *u8) } else { if okh==0 { gv_puts("NX-CLAIMS REAP-SKIP holder-too-long\n" as *u8) } } 578 } 579 } } 580 i = le + 1 581 } 582 gv_puts("NX-CLAIMS REAP-DONE reaped=" as *u8) 583 gv_num(reaped) 584 gv_puts(" scanned=" as *u8) 585 gv_num(scanned) 586 gv_puts(" now=" as *u8) 587 gv_num(cx[1]) 588 gv_puts("\n" as *u8) 589 return reaped 590} 591 592// ---------- selftest gate (T1..T13, deterministic via injected timestamps) ---------- 593func cl_selftest(journal: *u8) -> i64 { 594 let ctr: *i64 = gv_ctr() 595 gv_head("nx_claims selftest -- lease/claim teeth (caller pre-cleans journal)" as *u8) 596 let q: *u8 = sys_mmap(CL_WIN) 597 let cx: *i64 = sys_mmap(64) as *i64 598 let sp: *i64 = sys_mmap(16) as *i64 599 let st_out: *i64 = sys_mmap(32) as *i64 600 let now: i64 = sys_now_realtime_sec() 601 let rcap: i64 = CL_WIN - 8 602 // T1 empty journal -> absent resource honestly ABSENT 603 var n: i64 = cl_read(journal,q,rcap) 604 cx[0]=n; cx[1]=now; cx[2]=0; cx[3]=0; cx[4]=0; cx[5]=journal as i64 605 var ok1: i64 = 0 606 if n==0 { ok1=1 } 607 gv_check("T1 empty journal no fabricated claims" as *u8, ok1, ctr) 608 // T2 fresh claim -> HELD by claimer 609 let t2ts: i64 = now - 100 610 cl_append(journal, t2ts, "CLAIM" as *u8, "resA" as *u8, "sess1" as *u8, 1000, "claimA" as *u8) 611 n = cl_read(journal,q,rcap) 612 cx[0]=n 613 var ok2: i64 = 0 614 if cl_res_span_lit(q,cx,"resA" as *u8,sp)==1 { 615 let st2: i64 = cl_state(q,cx,sp[0],sp[1],st_out) 616 if st2==1 { if cl_lit_eq(q,st_out[0],st_out[1],"sess1" as *u8)==1 { ok2=1 } } 617 } 618 gv_check("T2 fresh claim derives HELD by claimer" as *u8, ok2, ctr) 619 // T3 contender predicate: HELD + holder != sess2 -> claim verb would refuse 620 var ok3: i64 = 0 621 if cl_res_span_lit(q,cx,"resA" as *u8,sp)==1 { 622 let st3: i64 = cl_state(q,cx,sp[0],sp[1],st_out) 623 if st3==1 { if cl_lit_eq(q,st_out[0],st_out[1],"sess2" as *u8)==0 { ok3=1 } } 624 } 625 gv_check("T3 contended claim predicate refuses other actor" as *u8, ok3, ctr) 626 // T4 beat by holder revives freshness: old claim + fresh beat -> HELD 627 let t4c: i64 = now - CL_MAGIC_5000 628 let t4b: i64 = now - 50 629 cl_append(journal, t4c, "CLAIM" as *u8, "resB" as *u8, "sess1" as *u8, 1000, "claimB" as *u8) 630 cl_append(journal, t4b, "BEAT" as *u8, "resB" as *u8, "sess1" as *u8, 0, "beatB" as *u8) 631 n = cl_read(journal,q,rcap) 632 cx[0]=n 633 var ok4: i64 = 0 634 if cl_res_span_lit(q,cx,"resB" as *u8,sp)==1 { let st4: i64 = cl_state(q,cx,sp[0],sp[1],st_out); if st4==1 { ok4=1 } } 635 gv_check("T4 holder beat revives freshness HELD" as *u8, ok4, ctr) 636 // T5 stale claim without beats -> EXPIRED (crash-expiry) 637 let t5c: i64 = now - CL_MAGIC_5000 638 cl_append(journal, t5c, "CLAIM" as *u8, "resC" as *u8, "sess3" as *u8, 1000, "claimC" as *u8) 639 n = cl_read(journal,q,rcap) 640 cx[0]=n 641 var ok5: i64 = 0 642 if cl_res_span_lit(q,cx,"resC" as *u8,sp)==1 { let st5: i64 = cl_state(q,cx,sp[0],sp[1],st_out); if st5==2 { ok5=1 } } 643 gv_check("T5 stale claim derives EXPIRED crash-expiry" as *u8, ok5, ctr) 644 // T6 release -> FREE, then re-claim by other -> HELD by new holder 645 let t6c: i64 = now - 300 646 let t6r: i64 = now - 200 647 let t6c2: i64 = now - 100 648 cl_append(journal, t6c, "CLAIM" as *u8, "resD" as *u8, "sess1" as *u8, 1000, "claimD" as *u8) 649 cl_append(journal, t6r, "RELEASE" as *u8, "resD" as *u8, "sess1" as *u8, 0, "releaseD" as *u8) 650 n = cl_read(journal,q,rcap) 651 cx[0]=n 652 var ok6a: i64 = 0 653 if cl_res_span_lit(q,cx,"resD" as *u8,sp)==1 { let st6: i64 = cl_state(q,cx,sp[0],sp[1],st_out); if st6==3 { ok6a=1 } } 654 cl_append(journal, t6c2, "CLAIM" as *u8, "resD" as *u8, "sess2" as *u8, 1000, "reclaimD" as *u8) 655 n = cl_read(journal,q,rcap) 656 cx[0]=n 657 var ok6: i64 = 0 658 if ok6a==1 { if cl_res_span_lit(q,cx,"resD" as *u8,sp)==1 { 659 let st6b: i64 = cl_state(q,cx,sp[0],sp[1],st_out) 660 if st6b==1 { if cl_lit_eq(q,st_out[0],st_out[1],"sess2" as *u8)==1 { ok6=1 } } 661 } } 662 gv_check("T6 release frees then other actor claims" as *u8, ok6, ctr) 663 // T7 neg-control: absent resource stays absent 664 var ok7: i64 = 0 665 if cl_res_span_lit(q,cx,"resNOPE" as *u8,sp)==0 { ok7=1 } 666 gv_check("T7 neg-control absent resource stays absent" as *u8, ok7, ctr) 667 // T8 walk JSON smoke: totals + states + envelope 668 let d: *u8 = sys_mmap(CL_OUT) 669 let dl: i64 = cl_walk_json(q,cx,d) 670 var ok8: i64 = 0 671 if dl > 0 { if d[0]==(123 as u8) { if cl_find(d,dl,"EXPIRED" as *u8)==1 { if cl_find(d,dl,"claims_capped" as *u8)==1 { if cl_find(d,dl,"held" as *u8)==1 { ok8=1 } } } } } 672 gv_check("T8 walk JSON carries totals plus declared envelope" as *u8, ok8, ctr) 673 // T9 page HTML smoke: table + states + envelope 674 let d2: *u8 = sys_mmap(CL_OUT) 675 let dl9: i64 = cl_page_html(q,cx,d2) 676 var ok9: i64 = 0 677 if dl9 > 0 { if cl_find(d2,dl9,"<table" as *u8)==1 { if cl_find(d2,dl9,"EXPIRED" as *u8)==1 { if cl_find(d2,dl9,"window_bytes" as *u8)==1 { ok9=1 } } } } 678 gv_check("T9 page HTML carries table states envelope" as *u8, ok9, ctr) 679 // T10 F214 reap: ONLY the provably-expired claim (resC age>ttl) is released; audit note lands 680 n = cl_read(journal,q,rcap) 681 cx[0]=n 682 let r10: i64 = cl_reap(journal,q,cx,"reaper1" as *u8,"t10-orphan-sweep" as *u8) 683 n = cl_read(journal,q,rcap) 684 cx[0]=n 685 var ok10: i64 = 0 686 if r10==1 { if cl_res_span_lit(q,cx,"resC" as *u8,sp)==1 { 687 let st10: i64 = cl_state(q,cx,sp[0],sp[1],st_out) 688 if st10==3 { if cl_find(q,n,"ORPHAN-REAPED by=reaper1" as *u8)==1 { ok10=1 } } 689 } } 690 gv_check("T10 reap releases only the expired claim with audit note" as *u8, ok10, ctr) 691 // T11 NEGATIVE: unexpired claims SURVIVE the reap untouched 692 var ok11: i64 = 0 693 if cl_res_span_lit(q,cx,"resA" as *u8,sp)==1 { 694 let st11a: i64 = cl_state(q,cx,sp[0],sp[1],st_out) 695 if st11a==1 { if cl_lit_eq(q,st_out[0],st_out[1],"sess1" as *u8)==1 { 696 if cl_res_span_lit(q,cx,"resD" as *u8,sp)==1 { 697 let st11d: i64 = cl_state(q,cx,sp[0],sp[1],st_out) 698 if st11d==1 { if cl_lit_eq(q,st_out[0],st_out[1],"sess2" as *u8)==1 { ok11=1 } } 699 } 700 } } 701 } 702 gv_check("T11 negative unexpired claims survive reap" as *u8, ok11, ctr) 703 // T12 idempotent: nothing expired -> reap changes NOTHING (0 reaped, journal byte-identical) 704 let nb12: i64 = n 705 let r12: i64 = cl_reap(journal,q,cx,"reaper1" as *u8,"t12-rerun" as *u8) 706 let n12: i64 = cl_read(journal,q,rcap) 707 cx[0]=n12 708 var ok12: i64 = 0 709 if r12==0 { if n12==nb12 { ok12=1 } } 710 gv_check("T12 reap idempotent when nothing expired" as *u8, ok12, ctr) 711 // T13 a reaped resource is claimable by a NEW actor (the unblocked-sibling tooth) 712 cl_append(journal, -1, "CLAIM" as *u8, "resC" as *u8, "sess9" as *u8, 1000, "post-reap-claim" as *u8) 713 let n13: i64 = cl_read(journal,q,rcap) 714 cx[0]=n13 715 var ok13: i64 = 0 716 if cl_res_span_lit(q,cx,"resC" as *u8,sp)==1 { 717 let st13: i64 = cl_state(q,cx,sp[0],sp[1],st_out) 718 if st13==1 { if cl_lit_eq(q,st_out[0],st_out[1],"sess9" as *u8)==1 { ok13=1 } } 719 } 720 gv_check("T13 reaped resource claimable by new actor" as *u8, ok13, ctr) 721 let rc: i64 = gv_verdict("CLAIMS-GATE" as *u8, ctr, "claim lease + F214 orphan-reap teeth green" as *u8) 722 return rc 723} 724 725func main(argc: i64, argv: *i64) -> i64 { 726 if argc < 3 { gv_puts("usage: nx_claims {claim <journal> <resource> <actor> <ttl_sec> <note> | beat <journal> <resource> <actor> <note> | release <journal> <resource> <actor> <note> | walk <journal> | state <journal> <resource> | reap <journal> <reaper> <note> | selftest <journal>}\n" as *u8); sys_exit(2); return 2 } 727 let verb: *u8 = argv[1] as *u8 728 let journal: *u8 = argv[2] as *u8 729 let vl: i64 = cl_vlen(verb) 730 if cl_lit_eq(verb,0,vl,"selftest" as *u8)==1 { let rc: i64 = cl_selftest(journal); sys_exit(rc); return rc } 731 let q: *u8 = sys_mmap(CL_WIN) 732 let rcap: i64 = CL_WIN - 8 733 let n: i64 = cl_read(journal,q,rcap) 734 let cx: *i64 = sys_mmap(64) as *i64 735 cx[0]=n 736 cx[1]=sys_now_realtime_sec() 737 cx[2]=0 738 cx[3]=0 739 cx[4]=0 740 if n >= rcap { cx[4]=1 } 741 cx[5]=journal as i64 742 if cl_lit_eq(verb,0,vl,"walk" as *u8)==1 { 743 let d: *u8 = sys_mmap(CL_OUT) 744 let dl: i64 = cl_walk_json(q,cx,d) 745 sys_write(1,d,dl) 746 sys_exit(0) 747 return 0 748 } 749 if cl_lit_eq(verb,0,vl,"page" as *u8)==1 { 750 if argc < 4 { gv_puts("page needs <journal> <outfile>\n" as *u8); sys_exit(2); return 2 } 751 let outfile: *u8 = argv[3] as *u8 752 let d: *u8 = sys_mmap(CL_OUT) 753 let dl: i64 = cl_page_html(q,cx,d) 754 let fd: i64 = sys_openat_wr(outfile, 0x1a4) 755 if fd < 0 { gv_puts("CLAIMS-PAGE OPEN-FAIL\n" as *u8); sys_exit(1); return 1 } 756 sys_write(fd,d,dl) 757 sys_close(fd) 758 gv_puts("CLAIMS-PAGE bytes=" as *u8) 759 gv_num(dl) 760 gv_puts("\n" as *u8) 761 sys_exit(0) 762 return 0 763 } 764 // seq543/seq552: single-resource STATE probe (additive, rule 19) -- the SAME derivation the 765 // beat/release path uses (cl_res_span_lit + cl_state), so holdership judgment stays one copy. 766 // Lets nx_seat checkout classify a NOT-HOLDER release honestly (already-free vs live-foreign) 767 // without a full walk. Read-only, exit 0 always. 768 if cl_lit_eq(verb,0,vl,"state" as *u8)==1 { 769 if argc < 4 { gv_puts("state needs <journal> <resource>\n" as *u8); sys_exit(2); return 2 } 770 let sres: *u8 = argv[3] as *u8 771 let ssp: *i64 = sys_mmap(16) as *i64 772 let sso: *i64 = sys_mmap(32) as *i64 773 var sv: i64 = -1 774 if cl_res_span_lit(q,cx,sres,ssp)==1 { sv = cl_state(q,cx,ssp[0],ssp[1],sso) } 775 gv_puts("NX-CLAIMS STATE resource=" as *u8) 776 gv_puts(sres) 777 gv_puts(" state=" as *u8) 778 gv_puts(cl_state_name(sv)) 779 gv_puts(" holder=" as *u8) 780 var svh: i64 = 0 781 if sv == 1 { svh = 1 } 782 if sv == 2 { svh = 1 } 783 if svh == 1 { sys_write(1,(q as i64 + sso[0]) as *u8, sso[1]-sso[0]) } 784 if svh == 0 { gv_puts("-" as *u8) } 785 gv_puts("\n" as *u8) 786 sys_exit(0) 787 return 0 788 } 789 if cl_lit_eq(verb,0,vl,"reap" as *u8)==1 { 790 if argc < 5 { gv_puts("reap needs <journal> <reaper> <note>\n" as *u8); sys_exit(2); return 2 } 791 let reaper: *u8 = argv[3] as *u8 792 let rpnote: *u8 = argv[4] as *u8 793 let rk: i64 = cl_reap(journal, q, cx, reaper, rpnote) 794 if rk >= 0 { sys_exit(0); return 0 } 795 sys_exit(1) 796 return 1 797 } 798 if argc < 5 { gv_puts("claim|beat|release need <journal> <resource> <actor> ...\n" as *u8); sys_exit(2); return 2 } 799 let res: *u8 = argv[3] as *u8 800 let actor: *u8 = argv[4] as *u8 801 let sp: *i64 = sys_mmap(16) as *i64 802 let st_out: *i64 = sys_mmap(32) as *i64 803 var st: i64 = -1 804 if cl_res_span_lit(q,cx,res,sp)==1 { st = cl_state(q,cx,sp[0],sp[1],st_out) } 805 if cl_lit_eq(verb,0,vl,"claim" as *u8)==1 { 806 if argc < 7 { gv_puts("claim needs <journal> <resource> <actor> <ttl_sec> <note>\n" as *u8); sys_exit(2); return 2 } 807 let ttlz: *u8 = argv[5] as *u8 808 let ttl: i64 = cl_atoi_z(ttlz) 809 let note: *u8 = argv[6] as *u8 810 // REFUSE, NEVER SILENTLY SHRINK. The estate banked that law in the memfloor incident, and the 811 // 2026-07 "ttl ceiling" recorded 86400 for a 7200000 request -- a SILENT clamp, in a CALLER. 812 // A ceiling that lives in one caller is bypassable by every other caller, so the bound belongs 813 // HERE, in the organ that owns holdership. Loud + exit 2 so a typo is a usage error a human sees, 814 // never a lease quietly rounded down and never an 83-day lock nobody notices for 16 days. 815 if ttl > CL_TTL_MAX { gv_puts("NX-CLAIMS BAD-TTL-CEILING requested=" as *u8); gv_num(ttl); gv_puts(" max=" as *u8); gv_num(CL_TTL_MAX); gv_puts(" seconds (a lease whose expiry the lessee sets is not a lease)\n" as *u8); sys_exit(2); return 2 } 816 if ttl <= 0 { gv_puts("NX-CLAIMS BAD-TTL (must be positive seconds)\n" as *u8); sys_exit(2); return 2 } 817 if st == 1 { 818 if cl_lit_eq(q,st_out[0],st_out[1],actor)==0 { 819 gv_puts("NX-CLAIMS CONTENDED resource=" as *u8) 820 gv_puts(res) 821 gv_puts(" holder=" as *u8) 822 sys_write(1,(q as i64 + st_out[0]) as *u8, st_out[1]-st_out[0]) 823 gv_puts("\n" as *u8) 824 sys_exit(3) 825 return 3 826 } 827 } 828 let rc: i64 = cl_append(journal, -1, "CLAIM" as *u8, res, actor, ttl, note) 829 if rc==0 { gv_puts("NX-CLAIMS HELD resource=" as *u8); gv_puts(res); gv_puts(" actor=" as *u8); gv_puts(actor); gv_puts(" ttl=" as *u8); gv_num(ttl); gv_puts("\n" as *u8); sys_exit(0); return 0 } 830 gv_puts("append FAILED\n" as *u8) 831 sys_exit(1) 832 return 1 833 } 834 // beat | release require an un-released claim whose holder == actor (EXPIRED still owned) 835 if argc < 6 { gv_puts("beat|release need <journal> <resource> <actor> <note>\n" as *u8); sys_exit(2); return 2 } 836 let note2: *u8 = argv[5] as *u8 837 var owner_ok: i64 = 0 838 if st == 1 { if cl_lit_eq(q,st_out[0],st_out[1],actor)==1 { owner_ok=1 } } 839 if st == 2 { if cl_lit_eq(q,st_out[0],st_out[1],actor)==1 { owner_ok=1 } } 840 if owner_ok == 0 { 841 gv_puts("NX-CLAIMS NOT-HOLDER resource=" as *u8) 842 gv_puts(res) 843 gv_puts(" actor=" as *u8) 844 gv_puts(actor) 845 gv_puts("\n" as *u8) 846 sys_exit(3) 847 return 3 848 } 849 if cl_lit_eq(verb,0,vl,"beat" as *u8)==1 { 850 let rc: i64 = cl_append(journal, -1, "BEAT" as *u8, res, actor, 0, note2) 851 if rc==0 { gv_puts("NX-CLAIMS BEAT resource=" as *u8); gv_puts(res); gv_puts("\n" as *u8); sys_exit(0); return 0 } 852 gv_puts("append FAILED\n" as *u8) 853 sys_exit(1) 854 return 1 855 } 856 if cl_lit_eq(verb,0,vl,"release" as *u8)==1 { 857 let rc: i64 = cl_append(journal, -1, "RELEASE" as *u8, res, actor, 0, note2) 858 if rc==0 { gv_puts("NX-CLAIMS RELEASED resource=" as *u8); gv_puts(res); gv_puts("\n" as *u8); sys_exit(0); return 0 } 859 gv_puts("append FAILED\n" as *u8) 860 sys_exit(1) 861 return 1 862 } 863 gv_puts("unknown verb\n" as *u8) 864 sys_exit(2) 865 return 2 866}