The problem
When the daemon announces an arrival and the cockpit stands its own bell down for it, one PR can end up announced by nobody.
web/src/notify.ts advances seen before it returns early on machineHasIt. If the status read the browser deferred to was optimistic — the daemon had written the stub but its notify() call had not come back yet — and that call then fails, the arrival is gone: the daemon did not tap, and the browser has already recorded the key as announced.
The window is narrow. It needs a machine with no notifier at all (so notifierWorks is still null and status.notify is optimistically true — i.e. the first PR after serve starts), a permitted cockpit tab polling inside a window that is milliseconds wide, and the notify attempt to fail. On any machine with a working notifier nothing is lost, and the machine that has none hands the bell back permanently on the very next poll (that part shipped in #31, commit 4db709c).
Found by the reviewer on #31: #31 (comment).
Why it wasn't fixed on #31
Both obvious fixes trade this rare silence for a certain cost, and picking between them is a product call:
- Require a proven notifier (
notifierWorks === true rather than !== false behind status.notify). Closes it, but every machine, every serve process, gets two popups for the first PR — against the stated "one PR, one popup" goal. It also leaves the working-then-broken transition, which has the same shape.
- A fallback buffer — hold deferred-but-unconfirmed keys and flush them if the machine tap turns out not to have happened. Right shape, but it needs a policy: what happens when the machine bell is switched off deliberately? Flushing then announces a backlog of still-open PRs, which is exactly what
seen exists to prevent.
Done when
A PR that arrives is announced exactly once by someone — including on a machine whose notifier is missing or wedged — without introducing a duplicate popup on the healthy path or a backlog flush when the machine bell is turned off on purpose.
The problem
When the daemon announces an arrival and the cockpit stands its own bell down for it, one PR can end up announced by nobody.
web/src/notify.tsadvancesseenbefore it returns early onmachineHasIt. If the status read the browser deferred to was optimistic — the daemon had written the stub but itsnotify()call had not come back yet — and that call then fails, the arrival is gone: the daemon did not tap, and the browser has already recorded the key as announced.The window is narrow. It needs a machine with no notifier at all (so
notifierWorksis stillnullandstatus.notifyis optimistically true — i.e. the first PR afterservestarts), a permitted cockpit tab polling inside a window that is milliseconds wide, and the notify attempt to fail. On any machine with a working notifier nothing is lost, and the machine that has none hands the bell back permanently on the very next poll (that part shipped in #31, commit 4db709c).Found by the reviewer on #31: #31 (comment).
Why it wasn't fixed on #31
Both obvious fixes trade this rare silence for a certain cost, and picking between them is a product call:
notifierWorks === truerather than!== falsebehindstatus.notify). Closes it, but every machine, everyserveprocess, gets two popups for the first PR — against the stated "one PR, one popup" goal. It also leaves the working-then-broken transition, which has the same shape.seenexists to prevent.Done when
A PR that arrives is announced exactly once by someone — including on a machine whose notifier is missing or wedged — without introducing a duplicate popup on the healthy path or a backlog flush when the machine bell is turned off on purpose.