News that finds you, including when nothing of ours is open
The dots covered Reports and Messages from the day those sections existed. The announcement did not: only a chat reply produced an HX-Trigger, so a scheduled run that filed a report or posted into Messages lit a green dot in a corner and said nothing at all. That is precisely the arrival nobody is watching for -- a chat reply is one you asked for a moment ago and are probably looking at. So every kind announces, each with its own once-only flag, and the payload is a list of items rather than of titles, because a notification is a thing you click and a title cannot say where. One arrival, three channels, and they must not all fire. A toast for somebody looking at the page; a count in the tab title while it is hidden, cleared on focus; a system notification for somebody elsewhere entirely. The service worker is the only place that can tell them apart -- the server cannot see whether a window is focused and the page cannot see a push it did not receive -- so it stays quiet when one of its own windows has focus. And web push, hand-rolled against RFC 8291 and RFC 8292 with the cryptography already here for Fernet. It exists because everything else is polled by an open page, and the arrival worth interrupting somebody for is a schedule firing at seven in the morning with the laptop shut. The trade is real and is written down rather than glossed: the POST goes to Google's or Mozilla's push service, the payload is sealed end to end so they cannot read it, and what they do learn is that this server sent something and when. Opt-in per device, off until asked for, and the rest of the system works without it. Nothing else in LLeMbas contacts an outside service on its own. The encryption is tested by decrypting it back with an independent implementation of the specification's other half. There is no other way to know: a push service accepts the POST and forwards bytes it cannot read, so a wrong derivation is a notification that never appears, with a 201 in the log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -254,3 +254,47 @@ def test_the_file_picker_asks_for_files():
|
||||
# Directories stay a step in file mode, or a file two folders down is
|
||||
# unreachable.
|
||||
assert app.count("[data-dir-open]") >= 2
|
||||
|
||||
|
||||
def test_a_notification_is_never_shown_to_somebody_looking_at_the_page():
|
||||
"""Three channels carry one arrival and they must not all fire at once: the
|
||||
toast is for somebody watching, the tab-title count for somebody in another
|
||||
tab, and the system notification for somebody elsewhere entirely.
|
||||
|
||||
The service worker is the only place that can tell -- the server cannot see
|
||||
whether a window is focused, and the page cannot see a push it did not
|
||||
receive. Driven under a DOM stub; what is pinned here is that both halves
|
||||
of the decision exist.
|
||||
"""
|
||||
worker = (ROOT / "web/static/js/sw.js").read_text(encoding="utf-8")
|
||||
|
||||
# The page half: nothing but a toast while it is being looked at.
|
||||
assert "document.hidden" in SOURCE
|
||||
# The worker half: no notification when one of its own windows has focus.
|
||||
assert "clients[i].focused" in worker
|
||||
assert "showNotification" in worker
|
||||
|
||||
|
||||
def test_the_tab_title_count_re_reads_its_base():
|
||||
"""The title is rewritten by navigation and by a rename arriving out of
|
||||
band, so a base captured once would pin the old name until a reload."""
|
||||
assert "replace(/^\\(\\d+\\)\\s*/" in SOURCE
|
||||
|
||||
|
||||
def test_permission_is_only_ever_asked_from_a_gesture():
|
||||
"""`requestPermission` is refused outside one, silently. A checkbox restored
|
||||
on load and acted upon would look exactly like a switch that does nothing,
|
||||
which is the failure this codebase keeps cataloguing."""
|
||||
settings = (TEMPLATES / "settings.html").read_text(encoding="utf-8")
|
||||
|
||||
# A button, not an input whose `change` writes.
|
||||
assert "data-notify-toggle" in settings
|
||||
assert '<button class="btn" type="button" data-notify-toggle' in settings
|
||||
assert "requestPermission" in SOURCE
|
||||
|
||||
|
||||
def test_turning_notifications_off_also_drops_the_registration():
|
||||
"""Leaving it would mean this server going on POSTing to a third-party push
|
||||
service for something the reader has switched off."""
|
||||
assert "/api/push/unsubscribe" in SOURCE
|
||||
assert "pushManager" in SOURCE
|
||||
|
||||
Reference in New Issue
Block a user