pbz: stop reading unidentifiable acks as evidence
A property fuzz over the whole failure space (2000 seeded runs, and it
proved itself by catching 10 planted mutants first, including the
historical one) found a defect the hand-written tests could not reach.
Acks carry no request id. The multi-chunk sendBytecode before the resume
is acked frame-by-frame, and the resume mark is taken 300ms later, so on
a board slow enough to matter those stragglers land after the mark and
get counted as the resume's. One unmatched ack bought running-unsaved
outright: the zero-frame error then answered its own "Is the pattern
rendering?" with "it was confirmed rendering" over a frozen wall — item
8's original bug, through a different door. run() was worse: it returned
SUCCESS and printed "ok (live, not saved)" at a dark room.
Neither method treats an ack it cannot identify as evidence now. save()
waits for the preview frames, which are unambiguous. run() has none, so
it asks the device for its own status frame: fps > 0 is rendering, fps 0
is positive evidence of a frozen wall, and the device broadcasts one
about once a second, so run() has usually already received it.
Live measurement then showed zero frames has two OPPOSITE causes: a
frozen wall, or a concurrent reader stealing the stream —
samplePreview()'s teardown sends {sendUpdates:false} and purges type-5
frames, reproduced against real hardware stopping a save's collection
while the wall rendered perfectly. The same fps signal distinguishes
them, and the message now names the likely cause instead of asking a
question the device could have answered.
Item 15 upgraded from a code-reading claim to a confirmed hardware
finding. ping()/getConfig() contention was not reproducible blind in 34
attempts, so that half stays unquantified rather than asserted.
242 tests, typecheck green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PZnUXRsLLnt2A7pR3X4Luj T
Tarek Rached committed
3d77d091f9b37c3ecdb345bed02bda6a1ad8aeb6
Parent: 70931e3