# Prison approach reliability audit Read-only comparison of three immutable ordinary-game captures. No retries, input, engine launches, gameplay changes or relaxed limits were used for this audit. The approach policy hash recorded in all three input reports matches the current `tools/prison_approach_proof.py`. The 19:39 and 19:41 captures also share the exact input-helper hash; 19:17 used an earlier helper. This is a small diagnostic sample, not a reliability rate or performance benchmark. | Archive | Approach outcome | W pulses / yaw requests | Native observed duration | Recorded W hold min / median / max | Largest stopped displacement | Final target error | | --- | --- | --- | --- | --- | --- | --- | | [19:39:24](evidence/game-2026-09-19-193924-approach-stopping-reserve/input-proof.json.txt) | Stopping-reserve refusal | 8 / 14 | 25.899 s | 241.581 / 247.062 / 313.187 ms | 0.906973 m | 0.982344 m | | [19:41:28](evidence/game-2026-09-19-194128-gate-context-unselected/input-proof.json.txt) | Approach completed; later alignment refused | 10 / 14 | 28.456 s | 240.434 / 247.307 / 261.644 ms | 0.572014 m | 0.475079 m | | [19:17:50](evidence/game-2026-09-19-191750-prison-approach/input-proof.json.txt) | Approach completed | 9 / 14 | 27.199 s | 244.823 / 247.146 / 264.882 ms | 0.585235 m | 0.490408 m | Durations use the first and last native samples retained by the approach report; key holds use the actual helper key-down/up event timestamps. Paths were 4.246073, 4.760125 and 4.741409 m respectively. The failed approach still had 6.164 s of its original 35-second approach allowance: it did not time out. The successful approaches left 3.633 and 4.734 s. None proves gate operation. ## What caused the refusal The policy ends only at target error `r <= 0.75 m`, but permits another pulse only when `r > largest_stop + 0.25 m` (`perform_approach`, lines 255–268). Therefore any `largest_stop > 0.50 m` creates an unreachable decision interval: `0.75 < r <= largest_stop + 0.25`. For 19:39 the interval was `(0.75, 1.156973] m`, width 0.406973 m. Pulse 7 moved 0.906973 m, leaving 1.420035 m. Pulse 8 was correctly permitted at that point, moved 0.438292 m and left 0.982344 m: outside the completion radius but inside the refusal interval. Waiting cannot change this while fully stopped. The earlier large stop is correctly retained; dropping it merely to allow another pulse would remove evidence from the safety decision. Both successful runs also had a smaller decision interval, but their final pulses crossed it: 19:41 moved from 1.046375 to 0.475079 m; 19:17 moved from 1.062121 to 0.490408 m. Their success does not prove the policy can always finish. ## Input timing versus native movement The policy currently sleeps 50 ms after W-down, **then runs the complete private ownership/focus guard while W remains held**, and finally sends W-up (`perform_approach` lines 229–245, 276–281). The helper's `Guard.check()` validates display binding, window/process identity, native arguments, focus/mapping and a second display binding. Those checks must remain intact. Measured down-to-up durations were approximately 240–265 ms in both successful runs. Thus the nominal 50 ms sleep is not the actual pulse duration: roughly 190–215 ms was spent in the release path and scheduling. The largest failed-run pulse lasted 313.187 ms, leaving 263.187 ms beyond the requested sleep. This is consistent with extra guard/IPC or OS scheduling latency. The archives do not contain guard start/end or XTest timing breakdowns, so they cannot identify which operation caused that excess. All recorded holds remain below the 400 ms cap. The large stop is physical, not just a helper distance calculation. In the [19:39 console](evidence/game-2026-09-19-193924-approach-stopping-reserve/console.log.txt), pulse 7 spans samples 240–252. Sample 240 at 57,156 ms is stopped at `6090.89,211.331,7156.87`. Native forward is positive at samples 241–243; movement input is positive at 242–243. At sample 244 (57,653 ms), forward and movement input are already zero, but velocity is approximately 2.149 m/s and the body is at `6091.44,211.323,7156.50`. It travels another **0.244 m** before the stopped position `6091.64,211.319,7156.36`, first zero-velocity sample 247. Thus native momentum after observed release contributes materially. Sparse 100–138 ms samples cannot locate the exact engine receipt of W-up. Comparable holds also produce different stops: 19:41's 240.434 ms pulse moved 0.568595 m, while its 261.644 ms pulse moved 0.432666 m. A linear duration-to-distance model is not justified. Every accepted pulse retained both positive native input acknowledgement and at least 0.05 m physical movement/progress; full-stop observation was required afterward. ## Smallest next improvement, still unqualified First record bounded monotonic guard-entry/return, W-up request and final native stop timestamps in a future experiment. This isolates release latency without changing input or authority. A small subsequent algorithm candidate is to perform the **same full release guard during the initial 50 ms hold interval**, rather than always adding it afterward. If that guard returns before 50 ms, wait the remainder and recheck it immediately before W-up. If it already consumed 50 ms, release immediately after its successful return. Keep emergency cleanup and the 1.5-second hard key lease unchanged; never release from a stale cached guard. This could remove the unconditional extra 50 ms when validation already takes ~200 ms, without weakening the 0.75 m target, 0.25 m reserve, 400 ms actual-hold cap, positive native input/0.05 m movement acknowledgement, full stop, original 35-second approach allowance or 45-second native lifetime. It is only a bounded candidate: shorter pulses may be missed by native sampling and must then refuse; extra pulses could exhaust the existing count or time budget. A slow guard can still dominate the hold. Tests must cover fast/slow/refused guards, real elapsed hold, release cleanup, missing native acknowledgement and unchanged reserve. There is **no source-proven safe completion fix for an already reached deadzone** under the current maximum-stop rule. Do not substitute the latest smaller stop, ignore the outlier, silently reset the maximum for a shorter pulse, cross the reserve, enlarge the target or extend the lifetime. Any future shorter-pulse strategy needs its own measured conservative stopping bound before it can safely address that remaining limitation. No such bound or improved runtime outcome is claimed here.