pmacs/pmacs-gpu/src
Levi Neuwirth 9f08f5278c
fix(gpu): 1-pre round 2 --- a read ceiling, and the A4 consequence was wrong
Two review findings, one of them a real defect.

**THE SENTINEL READ COULD HANG FOREVER.** `read_until_sentinel` blocked
with no bound, so a writer or encoder that regressed after `enqueue`
would WEDGE THE GATE rather than redden it --- and a hang is the worst
failure shape there is, because it looks like slowness until the job is
killed. A 30 s `READ_CEILING` is armed on the daemon socket.

The distinction is kept explicit in the code, because collapsing it is
how this fix would undo the design it protects: **the sentinel remains
the success condition and the ceiling is only an error ceiling.**
Arrival is still decided by the sentinel, so the harness never infers
"nothing was sent" from a duration --- the core-count assumption behind
PR #235's CI red is not reintroduced. The ceiling sits far above any
plausible drain, so reaching it means broken, never busy.

M24 proves it fires rather than trusting it: drop the sentinel enqueue
entirely and the row fails in under a second with a diagnostic naming
both candidate causes and the partial transcript, instead of hanging.

**THE STAGE 1a CONSEQUENCE WAS WRONG IN FOUR PLACES.** Every record
claimed A4 would leave `EventOutcome` with one variant, so the type
should go with the Escape branch. It will not, and it should not.
`LifecycleRoute::Exit` --- a native window close --- returns
`EventOutcome::Exit` too. A4 removes the KEYBOARD producer only, leaving
one `Exit` producer.

And **one producer is not one variant**: the type survives because
`dispatch_window_event` must still distinguish `Continue` from `Exit` on
every event it handles --- nearly all must not exit, and the close must.
What A4 actually changes is `apply_keyboard`'s signature. Corrected in
the `EventOutcome` doc, the Escape-branch comment, the framing and the
ledger; the framing's superseded paragraph is deleted rather than
patched, since it also carried the stale "two `event_loop.exit()`
call sites" count. **There is exactly one executable
`event_loop.exit()`**, in `window_event`.

Also: the sentinel-tag comment claimed four modifier bits and used
three. It now says three, wrapping every eight steps, and why that
suffices --- each sentinel is read before the next is issued, so a tag
only has to differ from its immediate predecessor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-12 11:07:41 +02:00
..
attach.rs feat(gpu): 1-pre P2 --- the effect harness, outbound AND local 2026-08-12 10:36:12 +02:00
main.rs fix(gpu): 1-pre round 2 --- a read ceiling, and the A4 consequence was wrong 2026-08-12 11:07:41 +02:00
math_layout.rs feat(math): caret-driven suppression, the draw pass, and the slice acceptance 2026-07-24 22:04:35 -04:00
math_parse.rs feat(math): caret-driven suppression, the draw pass, and the slice acceptance 2026-07-24 22:04:35 -04:00
terminal.rs feat(bottom-panel): paint and drive the GPU panel band 2026-07-29 18:40:46 -04:00