code wiki / (root) / nx_behaveprobe_review_candidate_t371.nx

nx_behaveprobe_review_candidate_t371.nx source

↩ module page · 251 lines · 14297 B

1// nx_behaveprobe.nx -- paired workload observations for reviewed promotion evidence. 2// Complete capture and matching outputs/exits are observations, not sufficient proof of behavior, 3// workload coverage, or deployment quality. The caller must qualify the workload and exit contract. 4// Running a supplied workload executes it twice; the caller owns its side-effect authorization. 5// Existing CLI directions and helper entrypoints remain available. 6import "nx_tool_run.nx" 7import "json_emit.nx" 8import "nx_itoa_lib.nx" 9 10const BP_HOST: *u8 = "/volume1/homes/elderwesto/nishihost" 11const BP_CAP: i64 = 262144 12const BP_TMO: i64 = 120000 13// THIRD DIRECTION (2026-09-05): `self` compares LIVE against ITSELF. It needs no staged twin and no .prev, so 14// a referee can ask the live ruler how it reads a subject (its rc, its evidence grade) and whether the 15// subject's output is deterministic across two runs -- the question that surfaced today when the served 16// probe, older than the estate's own wait-status rule, reported rc=0 for a gate the crash guard had killed. 17// A signal death reads 128+signal from wait_status_rc (SIGTERM 143; SIGSEGV surfaces as 139 through the 18// crash guard); BP_SIGNAL_RC_BASE is that base, named once, so the grader can SAY signalled instead of 19// leaving a caller to notice that a rc above 128 is not a verdict. 20const BP_SIGNAL_RC_BASE: i64 = 128 21func bp_eq(a: *u8, b: *u8) -> i64 { 22 var i: i64 = 0 23 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 24 if b[i] != (0 as u8) { return 0 } 25 return 1 26} 27 28func bp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 29func be(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(2,s,n); return 0 } 30func bn(v:i64)->i64{return nxi_out(v)} 31func bcat(d: *u8, o: i64, s: *u8) -> i64 { var x: i64=o; var i: i64=0; while s[i]!=(0 as u8){d[x]=s[i];x=x+1;i=i+1} return x } 32func bexists(p: *u8) -> i64 { let fd: i64 = sys_openat_rd(p); if fd < 0 { return 0 } sys_close(fd); return 1 } 33 34// TEST THE HYPOTHESIS, NOT A PROXY FOR IT (2026-08-07). The 200-byte floor below existed to catch "both 35// sides printed the same USAGE LINE". Size is only a PROXY for that, and it is wrong in both directions: 36// MEASURED -- nx_fsops size <file> answered 70 B of correct output on a real argv, rc=0 both sides, 37// verdict IDENTICAL, and was graded WEAK. A byte-identical response to a real workload is the STRONGEST 38// signal this probe can produce, and a threshold on length threw it away. 39// So ask the real question: does the captured output actually CONTAIN a usage banner? 40// * WHEN YOU CAN TEST THE HYPOTHESIS DIRECTLY, A THRESHOLD ON A CORRELATE IS A WORSE INSTRUMENT, NOT A 41// CHEAPER ONE -- and it fails silently on every organ whose correct answer is short. 42func bp_has(buf: *u8, n: i64, needle: *u8) -> i64 { 43 var m: i64 = 0 44 while needle[m] != (0 as u8) { m = m + 1 } 45 if m == 0 { return 0 } 46 var i: i64 = 0 47 while i + m <= n { 48 var k: i64 = 0 49 var ok: i64 = 1 50 while k < m { 51 if buf[i + k] != needle[k] { ok = 0; k = m } 52 else { k = k + 1 } 53 } 54 if ok == 1 { return 1 } 55 i = i + 1 56 } 57 return 0 58} 59 60 61const BP_UNQUALIFIED:i64=-301 62const BP_INVALID:i64=-302 63const BP_G_WEAK:i64=1 64const BP_G_HARNESS:i64=2 65const BP_G_SIGNALLED:i64=3 66const BP_G_GRADED:i64=4 67const BP_G_STRONG:i64=5 68struct NxBehaviorRequest { live:*u8,other:*u8,cwd:*u8,args:*i64,arg_count:i64,timeout_ms:i64,max_capture_bytes:i64 } 69struct NxBehaviorResult { state:i64,matched:i64,same_output:i64,same_exit:i64,grade:i64,live_rc:i64,other_rc:i64,live_bytes:i64,other_bytes:i64,first_diff:i64,live_wait:i64,other_wait:i64,live_exit:i64,other_exit:i64,live_signal:i64,other_signal:i64,live_setup:i64,other_setup:i64,live_exec:i64,other_exec:i64,live_reaped:i64,other_reaped:i64,live_capacity:i64,other_capacity:i64,live_timeout:i64,other_timeout:i64,coverage_verified:i64 } 70func bp_result_init(r:*NxBehaviorResult)->i64{ 71 r.state=BP_INVALID;r.matched=0;r.same_output=0;r.same_exit=0;r.grade=BP_G_HARNESS 72 r.live_rc=BP_INVALID;r.other_rc=BP_INVALID;r.live_bytes=0;r.other_bytes=0;r.first_diff=-1 73 r.live_wait=-1;r.other_wait=-1;r.live_exit=-1;r.other_exit=-1;r.live_signal=0;r.other_signal=0 74 r.live_setup=0;r.other_setup=0;r.live_exec=0;r.other_exec=0;r.live_reaped=0;r.other_reaped=0 75 r.live_capacity=0;r.other_capacity=0;r.live_timeout=0;r.other_timeout=0;r.coverage_verified=0;return 0 76} 77// Retained-output variant executes each authorized workload once; never reruns for review. 78func bp_run_owned_result(q:*NxBehaviorRequest,r:*NxBehaviorResult,a:*NxBufOwned,b:*NxBufOwned)->i64{ 79 bp_result_init(r) 80 if nx_bo_state(a)!=0||nx_bo_state(b)!=0{return 2} 81 if a.len!=0||a.cap!=0||b.len!=0||b.cap!=0{return 2} 82 if q.arg_count<0||q.arg_count>NX_BO_I64_MAX/__size_of(i64)-2{return 2} 83 if q.timeout_ms<0||q.max_capture_bytes<0{return 2} 84 if (q.live as i64)<=0||(q.other as i64)<=0{return 2} 85 if q.arg_count>0{if (q.args as i64)<=0{return 2}} 86 let extent:i64=(q.arg_count+2)*__size_of(i64) 87 let av1:*i64=sys_mmap_try(extent) as *i64;let av2:*i64=sys_mmap_try(extent) as *i64 88 if (av1 as i64)<=0||(av2 as i64)<=0{ 89 if (av1 as i64)>0{sys_munmap_direct(av1 as *u8,extent)} 90 if (av2 as i64)>0{sys_munmap_direct(av2 as *u8,extent)} 91 r.state=NX_BO_ALLOCATION;return 2 92 } 93 av1[0]=q.live as i64;av2[0]=q.other as i64 94 var i:i64=0;var valid:i64=1 95 while i<q.arg_count{if q.args[i]<=0{valid=0};av1[i+1]=q.args[i];av2[i+1]=q.args[i];i=i+1} 96 av1[q.arg_count+1]=0;av2[q.arg_count+1]=0 97 if valid==0{sys_munmap_direct(av1 as *u8,extent);sys_munmap_direct(av2 as *u8,extent);return 2} 98 var x:NxRunEvidence;var y:NxRunEvidence 99 r.live_rc=tr_run_capture_owned_result(q.live,av1,a,q.timeout_ms,q.max_capture_bytes,q.cwd,&x) 100 r.other_rc=tr_run_capture_owned_result(q.other,av2,b,q.timeout_ms,q.max_capture_bytes,q.cwd,&y) 101 sys_munmap_direct(av1 as *u8,extent);sys_munmap_direct(av2 as *u8,extent) 102 r.live_bytes=a.len;r.other_bytes=b.len;r.live_capacity=a.cap;r.other_capacity=b.cap 103 r.live_wait=x.raw_wait;r.other_wait=y.raw_wait;r.live_exit=x.exit_code;r.other_exit=y.exit_code 104 r.live_signal=x.signal;r.other_signal=y.signal;r.live_setup=x.setup_error;r.other_setup=y.setup_error 105 r.live_exec=x.exec_error;r.other_exec=y.exec_error;r.live_reaped=x.reaped;r.other_reaped=y.reaped 106 r.live_timeout=x.timed_out;r.other_timeout=y.timed_out 107 r.state=0 108 if r.live_rc<0{r.state=r.live_rc} 109 if r.other_rc<0{r.state=r.other_rc} 110 if x.setup_error<0||y.setup_error<0||x.exec_error<0||y.exec_error<0{r.state=BP_UNQUALIFIED} 111 if x.reaped!=1||y.reaped!=1{r.state=BP_UNQUALIFIED} 112 if r.state==0{ 113 r.same_output=1;if a.len!=b.len{r.same_output=0} 114 var lim:i64=a.len;if b.len<lim{lim=b.len} 115 i=0;while i<lim{if a.buf[i]!=b.buf[i]{r.first_diff=i;r.same_output=0;i=lim}else{i=i+1}} 116 if r.same_output==0{if r.first_diff<0{r.first_diff=lim}} 117 if x.exited==y.exited&&x.exit_code==y.exit_code&&x.signal==y.signal{r.same_exit=1} 118 if r.same_output==1&&r.same_exit==1{r.matched=1} 119 r.grade=BP_G_STRONG 120 if a.len==0||b.len==0{r.grade=BP_G_WEAK} 121 if bp_has(a.buf,a.len,"usage:")==1||bp_has(b.buf,b.len,"usage:")==1||bp_has(a.buf,a.len,"Usage:")==1||bp_has(b.buf,b.len,"Usage:")==1{r.grade=BP_G_WEAK} 122 if x.exit_code!=0||y.exit_code!=0{if r.grade!=BP_G_WEAK{r.grade=BP_G_GRADED}} 123 if x.signal!=0||y.signal!=0{r.grade=BP_G_SIGNALLED;r.state=BP_UNQUALIFIED} 124 } 125 if r.state!=0{return 2} 126 if r.matched==1{return 0};return 1 127} 128 129// The caller owns both captures, including partial bytes on unqualified execution. 130// Compatibility entrypoint preserves the prior release-on-return contract. 131func bp_run_result(q:*NxBehaviorRequest,r:*NxBehaviorResult)->i64{ 132 var a:NxBufOwned;var b:NxBufOwned 133 a.buf=0 as *u8;a.len=0;a.cap=0;b.buf=0 as *u8;b.len=0;b.cap=0 134 let rc:i64=bp_run_owned_result(q,r,&a,&b) 135 let ar:i64=nx_bo_release(&a);let br:i64=nx_bo_release(&b) 136 if ar<0{r.state=ar;r.grade=BP_G_HARNESS};if br<0{r.state=br;r.grade=BP_G_HARNESS} 137 if ar<0||br<0{return 2};return rc 138} 139 140func bp_len(s:*u8)->i64{var n:i64=0;while s[n]!=(0 as u8){n=n+1};return n} 141 142struct BpRecordWriter { owned:*NxBufOwned,number:*u8,max_bytes:i64,error:i64 } 143func bp_record_bytes(w:*BpRecordWriter,s:*u8,n:i64)->i64{ 144 if w.error!=0{return w.error} 145 w.error=nx_bo_append(w.owned,s,n,w.max_bytes);return w.error 146} 147func bp_record_literal(w:*BpRecordWriter,s:*u8)->i64{return bp_record_bytes(w,s,bp_len(s))} 148func bp_record_string(w:*BpRecordWriter,s:*u8)->i64{ 149 if w.error!=0{return w.error} 150 let n:i64=bp_len(s) 151 if n>(NX_BO_I64_MAX-2)/6{w.error=NX_BO_RANGE;return w.error} 152 let cap:i64=n*6+2 153 let tmp:*u8=sys_mmap_try(cap) 154 if (tmp as i64)<=0{w.error=NX_BO_ALLOCATION;return w.error} 155 var j:JsonWriter;j.buf=tmp;j.pos=0;j.cap=cap;j.depth=0;j.prior=0 as *u8 156 let rc:i64=je_emit_string_raw(&j,s,n) 157 if rc==0{bp_record_bytes(w,tmp,j.pos)}else{w.error=rc} 158 let freed:i64=sys_munmap_direct(tmp,cap) 159 if freed<0{w.error=NX_BO_RELEASE};return w.error 160} 161func bp_record_number(w:*BpRecordWriter,name:*u8,value:i64)->i64{ 162 if w.error!=0{return w.error} 163 bp_record_literal(w,",");bp_record_string(w,name);bp_record_literal(w,":") 164 if w.error!=0{return w.error} 165 // All signed values use the same shared integer emitter. 166 let n:i64=nxi_buf(w.number,0,value) 167 return bp_record_bytes(w,w.number,n) 168} 169func bp_grade_text(grade:i64)->*u8{ 170 if grade==BP_G_HARNESS{return "HARNESS: execution or complete capture unqualified"} 171 if grade==BP_G_SIGNALLED{return "SIGNALLED: actual terminating signal observed; no behavioral acceptance"} 172 if grade==BP_G_WEAK{return "WEAK: empty capture or usage-pattern observation; workload coverage unverified"} 173 if grade==BP_G_GRADED{return "GRADED: normal nonzero exit observed; caller must verify its workload contract"} 174 return "STRONG: legacy label for normal zero exits and nonempty non-usage capture; quality and coverage unverified" 175} 176func bp_build_result(target:*u8,mode:*u8,r:*NxBehaviorResult,owned:*NxBufOwned,max_bytes:i64)->i64{ 177 if nx_bo_state(owned)!=0{return NX_BO_INVALID} 178 if owned.len!=0||owned.cap!=0{return NX_BO_INVALID} 179 if max_bytes<0{return NX_BO_INVALID} 180 if r.grade<BP_G_WEAK||r.grade>BP_G_STRONG{return BP_INVALID} 181 let number:*u8=sys_mmap_try(NXI_BUF) 182 if (number as i64)<=0{return NX_BO_ALLOCATION} 183 var w:BpRecordWriter;w.owned=owned;w.number=number;w.max_bytes=max_bytes;w.error=0 184 bp_record_literal(&w,"{\"organ\":\"nx_behaveprobe\",\"target\":") 185 bp_record_string(&w,target);bp_record_literal(&w,",\"mode\":");bp_record_string(&w,mode) 186 bp_record_number(&w,"live_rc",r.live_rc);bp_record_number(&w,"other_rc",r.other_rc) 187 bp_record_number(&w,"live_bytes",r.live_bytes);bp_record_number(&w,"other_bytes",r.other_bytes);bp_record_number(&w,"first_diff_off",r.first_diff) 188 bp_record_number(&w,"state",r.state);bp_record_number(&w,"same_output",r.same_output);bp_record_number(&w,"same_exit",r.same_exit) 189 bp_record_number(&w,"live_raw_wait",r.live_wait);bp_record_number(&w,"other_raw_wait",r.other_wait) 190 bp_record_number(&w,"live_exit_code",r.live_exit);bp_record_number(&w,"other_exit_code",r.other_exit) 191 bp_record_number(&w,"live_signal",r.live_signal);bp_record_number(&w,"other_signal",r.other_signal) 192 bp_record_number(&w,"live_setup_error",r.live_setup);bp_record_number(&w,"other_setup_error",r.other_setup) 193 bp_record_number(&w,"live_exec_error",r.live_exec);bp_record_number(&w,"other_exec_error",r.other_exec) 194 bp_record_number(&w,"live_reaped",r.live_reaped);bp_record_number(&w,"other_reaped",r.other_reaped) 195 bp_record_number(&w,"live_capture_capacity",r.live_capacity);bp_record_number(&w,"other_capture_capacity",r.other_capacity) 196 bp_record_number(&w,"live_timeout",r.live_timeout);bp_record_number(&w,"other_timeout",r.other_timeout) 197 bp_record_number(&w,"coverage_verified",r.coverage_verified) 198 bp_record_literal(&w,",\"verdict\":") 199 var verdict:*u8="DIFFERS" 200 if r.state!=0{verdict="UNQUALIFIED"}else{if r.matched==1{verdict="IDENTICAL"}} 201 bp_record_string(&w,verdict);bp_record_literal(&w,",\"evidence\":");bp_record_string(&w,bp_grade_text(r.grade)) 202 bp_record_literal(&w,"}\n") 203 let freed:i64=sys_munmap_direct(number,NXI_BUF) 204 if freed<0{w.error=NX_BO_RELEASE} 205 return w.error 206} 207func bp_write_record(fd:i64,b:*NxBufOwned)->i64{ 208 let state:i64=nx_bo_state(b);if state!=0{return state} 209 var off:i64=0 210 while off<b.len{ 211 let n:i64=sys_write(fd,b.buf+off,b.len-off) 212 if n==TR_EINTR{continue} 213 if n<=0{return TR_ERR_DRAIN} 214 off=off+n 215 } 216 return 0 217} 218func bp_emit_result_fd(fd:i64,target:*u8,mode:*u8,r:*NxBehaviorResult)->i64{ 219 var b:NxBufOwned;b.buf=0 as *u8;b.len=0;b.cap=0 220 var rc:i64=bp_build_result(target,mode,r,&b,0) 221 if rc==0{rc=bp_write_record(fd,&b)} 222 let freed:i64=nx_bo_release(&b);if freed<0{rc=freed} 223 if rc!=0{return 2};return 0 224} 225func bp_emit_result(target:*u8,mode:*u8,r:*NxBehaviorResult)->i64{return bp_emit_result_fd(1,target,mode,r)} 226 227func main(argc:i64,argv:*i64)->i64{ 228 if argc<2{be("usage: nx_behaveprobe <target> [args...] | prev <target> [args...] | self <target> [args...]\n");return 3} 229 var ai:i64=1;var suffix:*u8=".sov.elf.new";var mode:*u8="live-vs-staged" 230 if bp_eq(argv[1] as *u8,"prev")==1{ai=2;suffix=".elf.prev";mode="live-vs-prev"} 231 if bp_eq(argv[1] as *u8,"self")==1{ai=2;suffix=".elf";mode="live-vs-self"} 232 if ai>=argc{be("nx_behaveprobe: missing target\n");return 3} 233 let target:*u8=argv[ai] as *u8 234 let hn:i64=bp_len(BP_HOST);let tn:i64=bp_len(target);let sn:i64=bp_len(suffix) 235 if hn>NX_BO_I64_MAX-tn-2{return 2};let base:i64=hn+tn+2 236 if base>NX_BO_I64_MAX-sn-4{return 2} 237 let ln:i64=base+4;let on:i64=base+sn 238 let lp:*u8=sys_mmap_try(ln);let op:*u8=sys_mmap_try(on) 239 if (lp as i64)<=0||(op as i64)<=0{ 240 if (lp as i64)>0{sys_munmap_direct(lp,ln)} 241 if (op as i64)>0{sys_munmap_direct(op,on)};return 2 242 } 243 var z:i64=bcat(lp,0,BP_HOST);z=bcat(lp,z,"/");z=bcat(lp,z,target);z=bcat(lp,z,".elf");lp[z]=0 as u8 244 z=bcat(op,0,BP_HOST);z=bcat(op,z,"/");z=bcat(op,z,target);z=bcat(op,z,suffix);op[z]=0 as u8 245 var q:NxBehaviorRequest 246 q.live=lp;q.other=op;q.cwd=BP_HOST;q.args=((argv as i64)+(ai+1)*__size_of(i64)) as *i64;q.arg_count=argc-ai-1;q.timeout_ms=BP_TMO;q.max_capture_bytes=0 247 var r:NxBehaviorResult;let rc:i64=bp_run_result(&q,&r) 248 let emitted:i64=bp_emit_result(target,mode,&r) 249 sys_munmap_direct(lp,ln);sys_munmap_direct(op,on) 250 if emitted!=0{return emitted};return rc 251}