code wiki / _hdl_build / nx_doctor_serve.nx
nx_doctor_serve.nx source
↩ module page · 59 lines · 4210 B
1// nx_doctor_serve.nx -- SERVE-WRAPPER making the DOCTOR role's capability MCP-callable (operator 2026-07-10: "each role
2// owns its raci capabilities and gets them to be mcp apis"). 6th wrapper. nx_doctor_apply's main() needs argv files (usage
3// exit 2 on no-arg dispatch), but its CORE doc_apply_mem(target, old, oldlen, new, newlen) is importable -- the graceful
4// conflict-safe atomic apply (lock + exact-once match + tmp+rename). Self-test on /tmp (idempotent: equal-length rewrite
5// each run): (1) HEAL -- apply BROKEN->HEALED, then BYTE-VERIFY the file really says HEALED (never claimed, read back);
6// (2) CONFLICT -- a non-matching oldstr is REFUSED (DA_CONFLICT) and the file is UNTOUCHED (never clobber);
7// (3) AMBIG -- an oldstr matching twice is REFUSED (DA_AMBIG, will not guess). Clean exit 0 + JSON so nishi_crew
8// dispatches `doctor fix`. Import ONLY nx_doctor_apply.nx (brings nx_syscalls + nx_arbiter; the flock dir
9// /home/elderwesto/.nishi/locks already exists on the NAS from the arbiter rung). license_tier: ORIGINAL expect_exit: 0
10import "nx_doctor_apply.nx"
11const K_MAGIC_4096: i64 = 4096
12
13func dsv_w2(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){ if s[n]==(39 as u8) { let q: *u8=sys_mmap(1); q[0]=34 as u8; sys_write(1,q,1) } else { sys_write(1,(s as i64+n) as *u8,1) } n=n+1 } return 0 }
14func dsv_bit(b: i64) -> i64 { let d: *u8=sys_mmap(1); d[0]=(48+b) as u8; sys_write(1,d,1); return 0 }
15func dsv_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
16func dsv_put(path: *u8, s: *u8) -> i64 {
17 let fd: i64 = sys_openat_wr(path, 0x1a4); if fd < 0 { return 0 - 1 }
18 sys_write(fd, s, dsv_slen(s)); sys_close(fd); return 0
19}
20func dsv_contains(hay: *u8, hn: i64, needle: *u8) -> i64 {
21 let nn: i64 = dsv_slen(needle)
22 if nn == 0 { return 1 }
23 var i: i64 = 0
24 while i + nn <= hn { var j: i64=0; var mt: i64=1; while j < nn { if hay[i+j]!=needle[j] { mt=0; j=nn } else { j=j+1 } } if mt==1 { return 1 } i=i+1 }
25 return 0
26}
27
28func main() -> i64 {
29 let t1: *u8 = "/tmp/nishi_doctor_selftest.txt" as *u8
30 let t2: *u8 = "/tmp/nishi_doctor_ambig.txt" as *u8
31 // fresh state each run; HEALED and BROKEN are equal length so the rewrite fully overwrites any prior run's bytes.
32 dsv_put(t1, "status=BROKEN;\n" as *u8)
33 dsv_put(t2, "dup dup\n" as *u8)
34 // (1) HEAL: exactly-once match -> APPLIED (0), then byte-verify the heal by reading the file back.
35 let rc_heal: i64 = doc_apply_mem(t1, "BROKEN" as *u8, 6, "HEALED" as *u8, 6)
36 let buf: *u8 = sys_mmap(K_MAGIC_4096)
37 let n1: i64 = da_read(t1, buf, K_MAGIC_4096)
38 var healed: i64 = 0
39 if rc_heal == 0 { if n1 > 0 { if dsv_contains(buf, n1, "status=HEALED;" as *u8) == 1 { healed = 1 } } }
40 // (2) CONFLICT: oldstr not in the current file -> REFUSED (1) and the file is untouched (still HEALED).
41 let rc_conf: i64 = doc_apply_mem(t1, "MISSING" as *u8, 7, "X" as *u8, 1)
42 let n2: i64 = da_read(t1, buf, K_MAGIC_4096)
43 var refused_conflict: i64 = 0
44 if rc_conf == 1 { if n2 > 0 { if dsv_contains(buf, n2, "status=HEALED;" as *u8) == 1 { refused_conflict = 1 } } }
45 // (3) AMBIG: oldstr matches twice -> REFUSED (2), will not guess which occurrence.
46 let rc_amb: i64 = doc_apply_mem(t2, "dup" as *u8, 3, "xxx" as *u8, 3)
47 var refused_ambig: i64 = 0
48 if rc_amb == 2 { refused_ambig = 1 }
49 var ok: i64 = 0
50 if healed == 1 { if refused_conflict == 1 { if refused_ambig == 1 { ok = 1 } } }
51 dsv_w2("{'v':1,'api':'nishi-crew-doctor/v1','role':'doctor','activity':'fix','capability':'graceful conflict-safe APPLY -- lock + exact-once context match + atomic tmp-rename; heals verified by readback; a changed or ambiguous region is REFUSED, never clobbered','selftest':{'heal_applied_and_byte_verified':" as *u8); dsv_bit(healed)
52 dsv_w2(",'nonmatch_refused_file_untouched':" as *u8); dsv_bit(refused_conflict)
53 dsv_w2(",'ambiguous_match_refused':" as *u8); dsv_bit(refused_ambig)
54 dsv_w2("},'verdict':'" as *u8)
55 if ok==1 { dsv_w2("GREEN (heal + never-clobber + never-guess proven)'}" as *u8) } else { dsv_w2("RED'}" as *u8) }
56 dsv_w2("\n" as *u8)
57 if ok==1 { sys_exit(0); return 0 }
58 sys_exit(1); return 1
59}