- Shipped
- August 27, 2026 at 8:34 PM UTC
- Author
- kamo
- Commit
- c780f8c
THE BADGE IS ABOUT YOU NOW, NOT ABOUT THE QUEUE. It counted every NEW report platform-wide, so it only ever fell when somebody moved a status — reading the queue did nothing to it. It counts what is still untriaged AND unread by you. ONE PREDICATE, THREE SURFACES. isNewToViewer() in systemBugCounts.ts is status === 'NEW' && !viewed, and the nav badge, the card's glow and the "Viewed" tick are all drawn from it — MediaService computes the number from the same two facts. A badge saying 3 above five glowing cards is a bug report, not a queue. Status is checked as well as viewed on purpose: reading is not triage, so a report a colleague has already picked up stops glowing at everybody, including the people who never opened it. LIVE OVER THE SHARED CHAT STOMP CLIENT, NOT A NEW SOCKET. NavCountsContext subscribes to /topic/system-bugs/changed, whose frame deliberately carries NO count — see systemBugCounts.ts for why this one topic is a contentless broadcast rather than the per-member subject the legal and training badges use — so the handler re-seeds and every session gets its own number back from an authenticated request. The subscription is gated on canManage from that seed, so the great majority of sessions, whose count is zero by construction, never subscribe at all. The seed on mount, on reconnect and the 60s tick stay load-bearing: the subject is core NATS with no stream. THE GLIMMER animates box-shadow and nothing else. opacity on a Paper fades the title along with the glow, and transform: scale silently defeats the hover lift, because a running animation's transform beats a rule's. The sweep is a separate ::after at a deliberately different period so the two drift rather than blink in lockstep, its white stop is kept under 60% so the title stays readable, and it is pointerEvents: none — without that it would eat clicks for a third of every cycle and present as a card that "sometimes doesn't open". Under prefers-reduced-motion both animations stop and the static ring remains, so the card still says what it was saying. MARKING READ LIVES IN THE DRAWER, not the card's onClick: every route into a report ends there — a card, a ?bug= deep link out of a status email, whatever comes next — and marking on the click would have covered only the first. Somebody arriving from an email would read the report and watch it keep glowing. The click does an optimistic local flip so the glimmer stops instantly; the drawer owns the write, and only after the detail actually loads, so a 404 never records that somebody read a report they were never shown. The status filter now carries a count per status, from a request that applies every filter EXCEPT the status — the number beside an entry is a promise about what picking it will show. Needs the MediaService and shared-library changes, and KamoInitializer's system_bug_view migration, to have landed first.