GetExitCodeProcess versus OpenProcess for live process check
A process object outlives the process. OpenProcess keeps succeeding on a terminated process for as long as anyone holds a handle, so a successful handle is not proof the process runs. A hard-killed wake session reported wedged for a process that no longer existed.
The fix
GetExitCodeProcess against STILL_ACTIVE is the question actually being asked. That went into the health report.
What did not change
foreman._pid_alive was deliberately left unchanged. For a mutex, treating a not-yet-reaped process as live is the safe direction. Same Win32 API, two different questions, correctly kept apart rather than unified.
Second piece of work
tools/gate_log.py records what was asked, the confirmation sentence verbatim, the outcome and when. New GET /api/gate, new HUD panel, 50-check test suite.
Six outcomes are recorded: pending, confirmed, denied, refused, unresolved, and expired.
The record went in a sibling, not in gate.py. That module promises no imports at all, so the gate has nothing that can fail underneath it. Adding json/os/datetime would have destroyed the exact property that makes it worth trusting.
Expiry is derived at read time, never written. No timeout was added to do_write. A pending entry past its TTL reads as expired because the reader computes it, so a process that dies between question and answer still produces a fail-closed reading with no writer involved.
Problems
antecedent_test started writing to the real memory/gate.json. It drives the real run_voice with "force push the foreman repo" and redirects nothing. Fixed with a FOREMAN_GATE_PATH redirect.
The saved HUD layout overrode the new default. assistant_settings.json holds a hand-edited hud list, so changing DEFAULT_HUD_PANELS did nothing and the panel would never have appeared. Added gate to the desk list there.
The gate panel is in the desk default only. At the wall's 460px the sentence list overflowed 45px horizontally and 188px vertically. The wall gets two counts and the last outcome instead.