Skip to content

Ration the banners, and say nothing while nobody is looking - #66

Merged
mukes555 merged 1 commit into
mainfrom
fix/notification-storm
Sep 16, 2026
Merged

mukes555 merged 1 commit into
mainfrom
fix/notification-storm

Conversation

@mukes555

Copy link
Copy Markdown
Owner

Reported from a real session: an agent left running restarted a server over
and over, the display went to sleep, and at unlock every queued banner
arrived at once, each with the interrupt sound.

Three things were wrong.

  1. No rate limit. Each watched-port change posted a banner. A server
    flapping every two seconds meant a banner every two seconds.
  2. Every banner was new. Notifier.send used a fresh UUID as the
    identifier, so nothing ever replaced anything: forty changes left forty
    entries in Notification Center.
  3. PortNanny kept posting while nobody could see. macOS queues banners
    posted behind a locked screen and delivers the queue at unlock.

Now: one banner per port per minute, at most three in half a minute before
the rest become a summary, one sound per burst, and an identifier per port
and kind so a new banner replaces the last. While the screen is locked or
the display is asleep nothing is posted at all: changes are counted, and one
silent summary ("12 changes on :3000, :5173 and 2 more") arrives on return.
The guard still kills, still records History, still refuses agents while you
are away; only the telling waits.

Refusal banners use the same gate.

Testing

386 unit tests, 0 failures, including six for the gate: a port flapping every
two seconds for a minute yields one banner; only the first of a burst makes a
sound; "freed" and "taken" are separate news; nothing posts while away and
the summary counts what happened, in the order it happened, once.

One unrelated test fix: testFreePortSkipsOtherPeoplesLeases probed the
kernel, so it depended on what was listening on the machine running it (a dev
server on :3002 failed it). It now tests the choosing logic, as its
neighbours do.

🤖 Generated with Claude Code

A watched port an agent kept restarting produced a banner per change, each
with its own sound and its own entry in Notification Center, and macOS holds
everything posted while the screen is locked: an hour of restarts arrived in
one pile at unlock, with an alarm per banner.

Every banner now passes a gate: one per port per minute, at most three in
half a minute before the rest are counted instead, and only the first of a
burst makes a sound. Each carries an identifier for its port and kind, so a
new one replaces the last rather than joining it.

While the screen is locked or the display is asleep nothing is posted at
all. The changes are counted, and one silent summary follows when the screen
comes back. The guard keeps working throughout; only the telling waits.

Refusals go through the same gate: ten agents refused in a minute is one
story, not ten interruptions.

Also: a free-port test asked the kernel and so depended on what happened to
be listening on the machine running it, which a dev server on :3002 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mukes555
mukes555 merged commit e10c13d into main Sep 16, 2026
2 checks passed
@mukes555 mukes555 mentioned this pull request Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant