aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_notification_dismissal.py
Commit message (Collapse)AuthorAgeFilesLines
* style: ruff's own fixes, mechanically appliedChristophe Besson6 days1-1/+0
| | | | | | | | | | | | | | | | | | | | `ruff check .` had gone unrun long enough to report 568 errors, which is the same as having no linter: the next real finding would have been invisible in the noise. This is the 521 it fixes by itself, in 173 files, and nothing else — the 98 it cannot fix are the next commit. What actually changed: import sorting (225), imports nobody used (87, none of them a re-export — no `__init__.py` is touched, which was the one way this could have broken an import elsewhere), `datetime.timezone.utc` to `datetime.UTC` (69) and `asyncio.TimeoutError` to `TimeoutError` (18), both plain aliases on the 3.12 this project requires, `Optional[X]` to `X | None` (24), and f-strings with nothing to interpolate (19). Checked rather than assumed: every module in the three packages still imports, and the suite is 2893 passed — the same count, test for test, as the merge before it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(hub): usernames are at least 8 characters at registrationChristophe Besson11 days1-5/+5
| | | | | | | Existing shorter accounts keep signing in. Test usernames padded to match. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
* fix(hub): dismissing a notification deletes itChristophe Besson2026-09-021-9/+39
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The previous commit filtered the list to unread, which corrected what the reader saw and left every dismissed row in the table, invisible for ever. That is a place to hide the disagreement rather than a resolution, and the operator said so: "elles s'accumulent pour rien." So dismissing drops the row. It is the reasoning `purge_notifications` has carried all along — "these are signals, not a record: the group is still there, the message is still in the chat, the invitation is still an invitation" — applied one at a time instead of only in bulk. - `DELETE /v1/notifications/{id}` is the honest name and what the SPA calls. - `POST /{id}/read` reaches the same handler and now deletes too. It has to keep working: the interface ships inside the desktop package, so a hub is always answering some client older than itself, and giving the old path the new behaviour means those clients stop hoarding as well rather than only the updated ones. - `read-all` deletes rather than marking, which makes it `DELETE ""` under an older name. Marking would have made it the one route still filling the table. Nothing in this repo calls it, but a reachable endpoint is one that can be called. `Notification.read` is now vestigial — nothing stored can be read, because reading it deletes it. It stays because dropping a column is a migration for no gain, and `unread_only` stays because a SPA newer than its hub still needs it to be right. Both are said in the module docstring rather than left to be worked out. Two existing tests encoded the old semantics and now assert the opposite; test_notification_dismissal.py gains one for the old `/read` path, because version skew is the normal case here and not the exception. 617 hub tests pass. docs/USERGUIDE.md's endpoint table updated in both places it lists them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014UtzVrzM7e2tG9fSpkR9ML
* fix(hub): a dismissed notification stays dismissed across a restartChristophe Besson2026-09-021-0/+144
Clicking a notification navigated to the group and the entry disappeared — the intended behaviour — and it was back on the next launch. Neither half was wrong on its own, which is why it survived. `markRead` drops the entry locally *and* marks it read on the hub, deliberately: "Reading it is the point of clicking it: it goes, here and in the count, rather than sitting there greyed out." The hub honoured that and persisted it. But the startup fetch asked for `/v1/notifications?limit=20` with no filter, and the endpoint returns read and unread alike, so every dismissed notification came straight back. It asks for `unread_only=true` now — a parameter the endpoint already had and already tested. The feed still carried the fossil of the older intent: `class="notif-item ${n.read ? '' : 'notif-unread'}"`, styling for a read entry rendered greyed out, from before clicking meant dismissing. Nothing read reaches the feed any more, so that branch was dead code describing behaviour the application had abandoned — and noticing it is what made the two halves' disagreement visible. Removed. `unread_count` is computed server-side over the whole table and is unaffected by the filter, so the bell is unchanged. test_notification_dismissal.py holds both halves: the API round trip that is the reported bug (list, read, list again), its mirror showing the unfiltered endpoint still returns it — so the fix cannot read as a coincidence — and a static check that the SPA asks for the filter, which is the only one of the three that catches the defect that actually happened. Verified by dropping the parameter again: that one fails, the API tests do not. Read notifications now accumulate unread in the table rather than being deleted. Purge removes them; the volume is small. Making dismissal a delete would suit `purge_notifications`' own docstring — "these are signals, not a record" — but it would leave `/read` a misnomer and `read-all` inconsistent, so it is a separate decision. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014UtzVrzM7e2tG9fSpkR9ML