feat: notifications say what changed and alert once: a grouped notice names the tracks, grows without re-alerting, and a phone pile lists its titles (M542 #6146-#6151)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m33s
release / android (push) Failing after 1m42s
release / integration (push) Failing after 4m42s
release / Build signed APK (releases and dev) (push) Successful in 4m55s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped

- An update to a grouped notice keeps its arrival time and email state, so the
  phone and the email no longer go off again each time it grows.
- Notices carry the names of what changed (newest ten), shown as three and
  "and N more": tracks still missing after the scan's move/replacement fold,
  duplicate groups new to a sweep, songs merged automatically, and the track
  and listener a playback error was for.
- Duplicates found counts only the groups new to that sweep; playback errors
  count reports, not the unresolved total.
- A scan failure says what stopped and links to Admin > Library.
- Android: a pile of more than three alerts lists the newest five titles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 22:44:19 -04:00
co-authored by Claude Opus 5.5
parent 2365514e5b
commit 854c307834
26 changed files with 486 additions and 190 deletions
+18 -8
View File
@@ -184,15 +184,25 @@ UPDATE duplicate_groups
SET status = 'dismissed', resolved_at = now()
WHERE id = sqlc.arg(id) AND status = 'pending';
-- name: CountDuplicateGroupsDetectedSince :one
-- name: ListDuplicateGroupsDetectedSince :many
-- Pending proposals first made at or after `since`: what a sweep that started
-- then found for the first time. A refreshed proposal keeps its detected_at,
-- so a sweep that only re-finds known groups counts none (M489: admins are
-- told about new duplicates, not reminded of the same ones every sweep).
SELECT count(*)::bigint
FROM duplicate_groups
WHERE status = 'pending'
AND detected_at >= sqlc.arg(since);
-- then found for the first time, each named by one of its songs, and `total`
-- of them however many are listed. A refreshed proposal keeps its detected_at,
-- so a sweep that only re-finds known groups lists none (M489: admins are told
-- about new duplicates, not reminded of the same ones every sweep).
SELECT ar.name AS artist_name, t.title, count(*) OVER ()::bigint AS total
FROM duplicate_groups g
JOIN LATERAL (SELECT m.track_id
FROM duplicate_group_members m
WHERE m.group_id = g.id
ORDER BY m.track_id
LIMIT 1) one ON true
JOIN tracks t ON t.id = one.track_id
JOIN artists ar ON ar.id = t.artist_id
WHERE g.status = 'pending'
AND g.detected_at >= sqlc.arg(since)
ORDER BY g.detected_at DESC, g.id
LIMIT sqlc.arg(n);
-- name: ListDuplicateGroupsForResolve :many
-- Every pending group's present copies, for the resolver (M498 #5435): what it