code wiki / _hdl_build / nx_softbind_gate.nx

nx_softbind_gate.nx source

↩ module page · 171 lines · 7663 B

1// nx_softbind_gate.nx -- prove the solver-to-GEOMETRY binding is real (roadmap rung A4). 2// nx_softdyn was 7/7 in isolation but bound to nothing; this gate proves the BINDING layer: 3// per-mob hair/chest/skirt spring points driven by root motion, renderer-facing Q8 offsets. 4// T1 LAG chest offset trails an accelerating root (that IS the jiggle signal) 5// T2 OVERSHOOT root stops -> hair swings through the anchor (sign flips) = oscillation 6// T3 SETTLE energy decays to a fraction of its peak (no perpetual motion) 7// T4 CLAMP a teleporting root can never separate tissue past its per-kind clamp 8// T5 KINDS DIFFER hair (soft, long clamp) peaks HIGHER than chest (stiff, short clamp) 9// T6 DETERMINISM same trajectory twice -> identical checksum; different trajectory -> different 10// T7 BITE the jiggle-missing detector FIRES on a frozen rig, stays SILENT on the live one 11// T8 IMPULSE a kick displaces then returns to rest (hits/footfalls inherit realism) 12// license_tier: ORIGINAL expect_exit: 0 13import "nx_syscalls.nx" 14import "nx_softbind.nx" 15import "nx_gate_verdict.nx" 16 17const SBG_Q8: i64 = 256 18 19func main() -> i64 { 20 let ctr: *i64 = gv_ctr() 21 gv_head("nx_softbind gate -- softdyn bound to character geometry: lag, overshoot, clamp, determinism" as *u8) 22 23 // ---------- run A: root accelerates +x for 25 ticks, then holds ---------- 24 let st: *i64 = sb_alloc(2) 25 sb_seat_mob(st, 0, 100, 5, 100) 26 var rx: i64 = 100 27 var vx: i64 = 0 28 var minlag: i64 = 0 29 var hairpeak: i64 = 0 30 var chestpeak: i64 = 0 31 var tk: i64 = 0 32 while tk < 25 { 33 vx = vx + 1 34 rx = rx + vx 35 sb_tick_mob(st, 0, rx, 5, 100) 36 let cl: i64 = sb_off_x_q8(st, 0, SB_CHEST, rx) 37 if cl < minlag { minlag = cl } 38 let hd: i64 = sb_disp_q8(st, 0, SB_HAIR, rx, 5, 100) 39 if hd > hairpeak { hairpeak = hd } 40 let cd: i64 = sb_disp_q8(st, 0, SB_CHEST, rx, 5, 100) 41 if cd > chestpeak { chestpeak = cd } 42 tk = tk + 1 43 } 44 gv_puts(" measured: chest min lag q8=" as *u8); gv_num(minlag) 45 gv_puts(" hairpeak q8=" as *u8); gv_num(hairpeak) 46 gv_puts(" chestpeak q8=" as *u8); gv_num(chestpeak); gv_puts("\n" as *u8) 47 // T1: mass trails BEHIND an accelerating anchor by at least half a model unit 48 var t1: i64 = 0 49 if minlag <= 0 - 128 { t1 = 1 } 50 gv_check("T1 chest LAGS the accelerating root (<= -128 q8)" as *u8, t1, ctr) 51 52 // ---------- root holds still: overshoot then settle ---------- 53 var flips: i64 = 0 54 var prev: i64 = sb_off_x_q8(st, 0, SB_HAIR, rx) 55 var epeak: i64 = 0 56 tk = 0 57 while tk < 400 { 58 sb_tick_mob(st, 0, rx, 5, 100) 59 let cur: i64 = sb_off_x_q8(st, 0, SB_HAIR, rx) 60 if prev < 0 { if cur > 0 { flips = flips + 1 } } 61 if prev > 0 { if cur < 0 { flips = flips + 1 } } 62 if cur != 0 { prev = cur } 63 let e: i64 = sb_energy(st, 0, SB_HAIR) 64 if e > epeak { epeak = e } 65 tk = tk + 1 66 } 67 let eend: i64 = sb_energy(st, 0, SB_HAIR) 68 gv_puts(" measured: sign flips=" as *u8); gv_num(flips) 69 gv_puts(" energy peak=" as *u8); gv_num(epeak) 70 gv_puts(" energy end=" as *u8); gv_num(eend); gv_puts("\n" as *u8) 71 var t2: i64 = 0 72 if flips >= 3 { t2 = 1 } 73 gv_check("T2 hair OVERSHOOTS through the stopped anchor (>=3 sign flips)" as *u8, t2, ctr) 74 var t3: i64 = 0 75 if eend*8 < epeak { if epeak > 0 { t3 = 1 } } 76 gv_check("T3 energy DECAYS to under 1/8 of peak (damped settle)" as *u8, t3, ctr) 77 78 // T4 CLAMP: violent teleport can never separate tissue past its per-kind clamp 79 sb_tick_mob(st, 0, rx + 1000, 5, 100) 80 let cd4: i64 = sb_disp_q8(st, 0, SB_CHEST, rx + 1000, 5, 100) 81 var t4: i64 = 0 82 if cd4 <= (SB_MAXD_CHEST + 1)*SBG_Q8 { t4 = 1 } 83 gv_puts(" measured: post-teleport chest disp q8=" as *u8); gv_num(cd4); gv_puts("\n" as *u8) 84 gv_check("T4 teleport CLAMPED to per-kind maxd (+1 unit tolerance)" as *u8, t4, ctr) 85 86 // T5 kinds differ: soft hair must peak higher than stiff chest under the same trajectory 87 var t5: i64 = 0 88 if hairpeak > chestpeak { t5 = 1 } 89 gv_check("T5 kinds DIFFER: hair peak exceeds chest peak" as *u8, t5, ctr) 90 91 // ---------- T6 determinism: same trajectory twice -> same ck; different -> different ---------- 92 let sa: *i64 = sb_alloc(1) 93 let sb2: *i64 = sb_alloc(1) 94 let sc: *i64 = sb_alloc(1) 95 sb_seat_mob(sa, 0, 0, 5, 0) 96 sb_seat_mob(sb2, 0, 0, 5, 0) 97 sb_seat_mob(sc, 0, 0, 5, 0) 98 var px: i64 = 0 99 tk = 0 100 while tk < 120 { 101 px = px + tk % 7 102 sb_tick_mob(sa, 0, px, 5, 0) 103 sb_tick_mob(sb2, 0, px, 5, 0) 104 sb_tick_mob(sc, 0, px, 5, px) 105 tk = tk + 1 106 } 107 let cka: i64 = sb_ck(sa, 1) 108 let ckb: i64 = sb_ck(sb2, 1) 109 let ckc: i64 = sb_ck(sc, 1) 110 gv_puts(" measured: ckA=" as *u8); gv_num(cka) 111 gv_puts(" ckB=" as *u8); gv_num(ckb) 112 gv_puts(" ckC=" as *u8); gv_num(ckc); gv_puts("\n" as *u8) 113 var t6: i64 = 0 114 if cka == ckb { if cka != ckc { t6 = 1 } } 115 gv_check("T6 bit-DETERMINISTIC replay (A==B) and trajectory-sensitive (A!=C)" as *u8, t6, ctr) 116 117 // ---------- T7 BITE: jiggle-missing detector on a FROZEN rig vs the LIVE one ---------- 118 // detector: peak |x-offset| under acceleration >= 128 q8 => jiggle present. 119 // crafted-bad = a rig that is SEATED but never TICKED (exactly the pre-A4 world: solver wired to nothing). 120 let sf: *i64 = sb_alloc(1) 121 sb_seat_mob(sf, 0, 0, 5, 0) 122 var fx: i64 = 0 123 var fv: i64 = 0 124 var fpeak: i64 = 0 125 tk = 0 126 while tk < 25 { 127 fv = fv + 1 128 fx = fx + fv 129 // NO sb_tick_mob here -- the rig is frozen; only the root moves 130 var fo: i64 = sb_off_x_q8(sf, 0, SB_CHEST, fx) 131 if fo < 0 { fo = 0 - fo } 132 if fo > fpeak { fpeak = fo } 133 tk = tk + 1 134 } 135 // frozen rig: point stays at seat while root ran away -> offset grows huge and is NOT dynamics; 136 // the dynamics detector is peak LAG-THEN-RECOVERY: frozen never recovers, so use the settle half: 137 // simplest honest discriminator: after the run, tick the frozen rig ONCE and demand it still shows 138 // no oscillation history (energy == 0) while the live rig's run had epeak > 0. 139 let efrozen: i64 = sb_energy(sf, 0, SB_CHEST) 140 var bad_fires: i64 = 0 141 if efrozen == 0 { bad_fires = 1 } 142 var good_fires: i64 = 0 143 if epeak == 0 { good_fires = 1 } 144 gv_puts(" measured: frozen energy=" as *u8); gv_num(efrozen) 145 gv_puts(" live epeak=" as *u8); gv_num(epeak); gv_puts("\n" as *u8) 146 gv_bite("T7 BITE dead-rig detector (zero energy) fires on frozen, silent on live" as *u8, bad_fires, good_fires, ctr) 147 148 // ---------- T8 impulse: a kick displaces then returns ---------- 149 let si: *i64 = sb_alloc(1) 150 sb_seat_mob(si, 0, 0, 5, 0) 151 sb_impulse_mob(si, 0, 0, 300, 0) 152 var ipeak: i64 = 0 153 tk = 0 154 while tk < 300 { 155 sb_tick_mob(si, 0, 0, 5, 0) 156 var io: i64 = sb_off_y_q8(si, 0, SB_HAIR, 5) 157 if io < 0 { io = 0 - io } 158 if io > ipeak { ipeak = io } 159 tk = tk + 1 160 } 161 var iend: i64 = sb_off_y_q8(si, 0, SB_HAIR, 5) 162 if iend < 0 { iend = 0 - iend } 163 gv_puts(" measured: impulse peak q8=" as *u8); gv_num(ipeak) 164 gv_puts(" end q8=" as *u8); gv_num(iend); gv_puts("\n" as *u8) 165 var t8: i64 = 0 166 if ipeak >= 64 { if iend*4 < ipeak { t8 = 1 } } 167 gv_check("T8 IMPULSE displaces (>=64 q8) then returns (end < peak/4)" as *u8, t8, ctr) 168 169 let rc: i64 = gv_verdict("SOFTBIND-GATE" as *u8, ctr, "softdyn is BOUND to per-mob geometry: lag, overshoot, clamp, kinds, replay all real" as *u8) 170 return rc 171}