code wiki / (root) / nx_behaveprobe_evidence_candidate_t297.nx

nx_behaveprobe_evidence_candidate_t297.nx source

↩ module page · 241 lines · 13796 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_evidence_candidate_t297.nx" 7import "json_emit.nx" 8import "nx_itoa_candidate_t297.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} 77func bp_run_result(q:*NxBehaviorRequest,r:*NxBehaviorResult)->i64{ 78 bp_result_init(r) 79 if q.arg_count<0||q.arg_count>NX_BO_I64_MAX/__size_of(i64)-2{return 2} 80 if q.timeout_ms<0||q.max_capture_bytes<0{return 2} 81 if (q.live as i64)<=0||(q.other as i64)<=0{return 2} 82 if q.arg_count>0{if (q.args as i64)<=0{return 2}} 83 let extent:i64=(q.arg_count+2)*__size_of(i64) 84 let av1:*i64=sys_mmap_try(extent) as *i64;let av2:*i64=sys_mmap_try(extent) as *i64 85 if (av1 as i64)<=0||(av2 as i64)<=0{ 86 if (av1 as i64)>0{sys_munmap_direct(av1 as *u8,extent)} 87 if (av2 as i64)>0{sys_munmap_direct(av2 as *u8,extent)} 88 r.state=NX_BO_ALLOCATION;return 2 89 } 90 av1[0]=q.live as i64;av2[0]=q.other as i64 91 var i:i64=0;var valid:i64=1 92 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} 93 av1[q.arg_count+1]=0;av2[q.arg_count+1]=0 94 if valid==0{sys_munmap_direct(av1 as *u8,extent);sys_munmap_direct(av2 as *u8,extent);return 2} 95 var a:NxBufOwned;var b:NxBufOwned 96 a.buf=0 as *u8;a.len=0;a.cap=0;b.buf=0 as *u8;b.len=0;b.cap=0 97 var x:NxRunEvidence;var y:NxRunEvidence 98 r.live_rc=tr_run_capture_owned_result(q.live,av1,&a,q.timeout_ms,q.max_capture_bytes,q.cwd,&x) 99 r.other_rc=tr_run_capture_owned_result(q.other,av2,&b,q.timeout_ms,q.max_capture_bytes,q.cwd,&y) 100 sys_munmap_direct(av1 as *u8,extent);sys_munmap_direct(av2 as *u8,extent) 101 r.live_bytes=a.len;r.other_bytes=b.len;r.live_capacity=a.cap;r.other_capacity=b.cap 102 r.live_wait=x.raw_wait;r.other_wait=y.raw_wait;r.live_exit=x.exit_code;r.other_exit=y.exit_code 103 r.live_signal=x.signal;r.other_signal=y.signal;r.live_setup=x.setup_error;r.other_setup=y.setup_error 104 r.live_exec=x.exec_error;r.other_exec=y.exec_error;r.live_reaped=x.reaped;r.other_reaped=y.reaped 105 r.live_timeout=x.timed_out;r.other_timeout=y.timed_out 106 r.state=0 107 if r.live_rc<0{r.state=r.live_rc} 108 if r.other_rc<0{r.state=r.other_rc} 109 if x.setup_error<0||y.setup_error<0||x.exec_error<0||y.exec_error<0{r.state=BP_UNQUALIFIED} 110 if x.reaped!=1||y.reaped!=1{r.state=BP_UNQUALIFIED} 111 if r.state==0{ 112 r.same_output=1;if a.len!=b.len{r.same_output=0} 113 var lim:i64=a.len;if b.len<lim{lim=b.len} 114 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}} 115 if r.same_output==0{if r.first_diff<0{r.first_diff=lim}} 116 if x.exited==y.exited&&x.exit_code==y.exit_code&&x.signal==y.signal{r.same_exit=1} 117 if r.same_output==1&&r.same_exit==1{r.matched=1} 118 r.grade=BP_G_STRONG 119 if a.len==0||b.len==0{r.grade=BP_G_WEAK} 120 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} 121 if x.exit_code!=0||y.exit_code!=0{if r.grade!=BP_G_WEAK{r.grade=BP_G_GRADED}} 122 if x.signal!=0||y.signal!=0{r.grade=BP_G_SIGNALLED;r.state=BP_UNQUALIFIED} 123 } 124 let ar:i64=nx_bo_release(&a);let br:i64=nx_bo_release(&b) 125 if ar<0{r.state=ar;r.grade=BP_G_HARNESS};if br<0{r.state=br;r.grade=BP_G_HARNESS} 126 if r.state!=0{return 2} 127 if r.matched==1{return 0};return 1 128} 129 130func bp_len(s:*u8)->i64{var n:i64=0;while s[n]!=(0 as u8){n=n+1};return n} 131 132struct BpRecordWriter { owned:*NxBufOwned,number:*u8,max_bytes:i64,error:i64 } 133func bp_record_bytes(w:*BpRecordWriter,s:*u8,n:i64)->i64{ 134 if w.error!=0{return w.error} 135 w.error=nx_bo_append(w.owned,s,n,w.max_bytes);return w.error 136} 137func bp_record_literal(w:*BpRecordWriter,s:*u8)->i64{return bp_record_bytes(w,s,bp_len(s))} 138func bp_record_string(w:*BpRecordWriter,s:*u8)->i64{ 139 if w.error!=0{return w.error} 140 let n:i64=bp_len(s) 141 if n>(NX_BO_I64_MAX-2)/6{w.error=NX_BO_RANGE;return w.error} 142 let cap:i64=n*6+2 143 let tmp:*u8=sys_mmap_try(cap) 144 if (tmp as i64)<=0{w.error=NX_BO_ALLOCATION;return w.error} 145 var j:JsonWriter;j.buf=tmp;j.pos=0;j.cap=cap;j.depth=0;j.prior=0 as *u8 146 let rc:i64=je_emit_string_raw(&j,s,n) 147 if rc==0{bp_record_bytes(w,tmp,j.pos)}else{w.error=rc} 148 let freed:i64=sys_munmap_direct(tmp,cap) 149 if freed<0{w.error=NX_BO_RELEASE};return w.error 150} 151func bp_record_number(w:*BpRecordWriter,name:*u8,value:i64)->i64{ 152 if w.error!=0{return w.error} 153 bp_record_literal(w,",");bp_record_string(w,name);bp_record_literal(w,":") 154 if w.error!=0{return w.error} 155 // All signed values use the same shared integer emitter. 156 let n:i64=nxi_buf(w.number,0,value) 157 return bp_record_bytes(w,w.number,n) 158} 159func bp_grade_text(grade:i64)->*u8{ 160 if grade==BP_G_HARNESS{return "HARNESS: execution or complete capture unqualified"} 161 if grade==BP_G_SIGNALLED{return "SIGNALLED: actual terminating signal observed; no behavioral acceptance"} 162 if grade==BP_G_WEAK{return "WEAK: empty capture or usage-pattern observation; workload coverage unverified"} 163 if grade==BP_G_GRADED{return "GRADED: normal nonzero exit observed; caller must verify its workload contract"} 164 return "STRONG: legacy label for normal zero exits and nonempty non-usage capture; quality and coverage unverified" 165} 166func bp_build_result(target:*u8,mode:*u8,r:*NxBehaviorResult,owned:*NxBufOwned,max_bytes:i64)->i64{ 167 if nx_bo_state(owned)!=0{return NX_BO_INVALID} 168 if owned.len!=0||owned.cap!=0{return NX_BO_INVALID} 169 if max_bytes<0{return NX_BO_INVALID} 170 if r.grade<BP_G_WEAK||r.grade>BP_G_STRONG{return BP_INVALID} 171 let number:*u8=sys_mmap_try(NXI_BUF) 172 if (number as i64)<=0{return NX_BO_ALLOCATION} 173 var w:BpRecordWriter;w.owned=owned;w.number=number;w.max_bytes=max_bytes;w.error=0 174 bp_record_literal(&w,"{\"organ\":\"nx_behaveprobe\",\"target\":") 175 bp_record_string(&w,target);bp_record_literal(&w,",\"mode\":");bp_record_string(&w,mode) 176 bp_record_number(&w,"live_rc",r.live_rc);bp_record_number(&w,"other_rc",r.other_rc) 177 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) 178 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) 179 bp_record_number(&w,"live_raw_wait",r.live_wait);bp_record_number(&w,"other_raw_wait",r.other_wait) 180 bp_record_number(&w,"live_exit_code",r.live_exit);bp_record_number(&w,"other_exit_code",r.other_exit) 181 bp_record_number(&w,"live_signal",r.live_signal);bp_record_number(&w,"other_signal",r.other_signal) 182 bp_record_number(&w,"live_setup_error",r.live_setup);bp_record_number(&w,"other_setup_error",r.other_setup) 183 bp_record_number(&w,"live_exec_error",r.live_exec);bp_record_number(&w,"other_exec_error",r.other_exec) 184 bp_record_number(&w,"live_reaped",r.live_reaped);bp_record_number(&w,"other_reaped",r.other_reaped) 185 bp_record_number(&w,"live_capture_capacity",r.live_capacity);bp_record_number(&w,"other_capture_capacity",r.other_capacity) 186 bp_record_number(&w,"live_timeout",r.live_timeout);bp_record_number(&w,"other_timeout",r.other_timeout) 187 bp_record_number(&w,"coverage_verified",r.coverage_verified) 188 bp_record_literal(&w,",\"verdict\":") 189 var verdict:*u8="DIFFERS" 190 if r.state!=0{verdict="UNQUALIFIED"}else{if r.matched==1{verdict="IDENTICAL"}} 191 bp_record_string(&w,verdict);bp_record_literal(&w,",\"evidence\":");bp_record_string(&w,bp_grade_text(r.grade)) 192 bp_record_literal(&w,"}\n") 193 let freed:i64=sys_munmap_direct(number,NXI_BUF) 194 if freed<0{w.error=NX_BO_RELEASE} 195 return w.error 196} 197func bp_write_record(fd:i64,b:*NxBufOwned)->i64{ 198 let state:i64=nx_bo_state(b);if state!=0{return state} 199 var off:i64=0 200 while off<b.len{ 201 let n:i64=sys_write(fd,b.buf+off,b.len-off) 202 if n==TR_EINTR{continue} 203 if n<=0{return TR_ERR_DRAIN} 204 off=off+n 205 } 206 return 0 207} 208func bp_emit_result_fd(fd:i64,target:*u8,mode:*u8,r:*NxBehaviorResult)->i64{ 209 var b:NxBufOwned;b.buf=0 as *u8;b.len=0;b.cap=0 210 var rc:i64=bp_build_result(target,mode,r,&b,0) 211 if rc==0{rc=bp_write_record(fd,&b)} 212 let freed:i64=nx_bo_release(&b);if freed<0{rc=freed} 213 if rc!=0{return 2};return 0 214} 215func bp_emit_result(target:*u8,mode:*u8,r:*NxBehaviorResult)->i64{return bp_emit_result_fd(1,target,mode,r)} 216 217func main(argc:i64,argv:*i64)->i64{ 218 if argc<2{be("usage: nx_behaveprobe <target> [args...] | prev <target> [args...] | self <target> [args...]\n");return 3} 219 var ai:i64=1;var suffix:*u8=".sov.elf.new";var mode:*u8="live-vs-staged" 220 if bp_eq(argv[1] as *u8,"prev")==1{ai=2;suffix=".elf.prev";mode="live-vs-prev"} 221 if bp_eq(argv[1] as *u8,"self")==1{ai=2;suffix=".elf";mode="live-vs-self"} 222 if ai>=argc{be("nx_behaveprobe: missing target\n");return 3} 223 let target:*u8=argv[ai] as *u8 224 let hn:i64=bp_len(BP_HOST);let tn:i64=bp_len(target);let sn:i64=bp_len(suffix) 225 if hn>NX_BO_I64_MAX-tn-2{return 2};let base:i64=hn+tn+2 226 if base>NX_BO_I64_MAX-sn-4{return 2} 227 let ln:i64=base+4;let on:i64=base+sn 228 let lp:*u8=sys_mmap_try(ln);let op:*u8=sys_mmap_try(on) 229 if (lp as i64)<=0||(op as i64)<=0{ 230 if (lp as i64)>0{sys_munmap_direct(lp,ln)} 231 if (op as i64)>0{sys_munmap_direct(op,on)};return 2 232 } 233 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 234 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 235 var q:NxBehaviorRequest 236 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 237 var r:NxBehaviorResult;let rc:i64=bp_run_result(&q,&r) 238 let emitted:i64=bp_emit_result(target,mode,&r) 239 sys_munmap_direct(lp,ln);sys_munmap_direct(op,on) 240 if emitted!=0{return emitted};return rc 241}