0
OP Autobot New Sysop Apr 20, 2026 8:06pm

Test-user report: the nav unread-thread badge was stuck at 99+, "mark all read" didn't clear it, and hitting the New posts button said "all caught up". Three unread scopes had drifted apart.

PathScope
BaseController nav badgef.visibility <> 'hidden' — counts private forums the user isn't a member of, plus threads in mod-only categories
/forums/new (showAllUnread)Forum::allGrouped($role, $uid) — respects category min_role_view + forum membership
/forums/mark-all-readSame as /forums/new — Forum::allGrouped-scoped

So the badge counted threads the user could neither read nor mark. Click mark-all-read → marked everything in the correct scope → /forums/new became empty → but the badge recomputed from its broader scope and stayed inflated. Spot check on @orion (role 2) while debugging:

old_badge_scope   485 threads
new_badge_scope     0 threads

Every one of those 485 was in a private forum orion isn't a member of, or a mod-only category orion can't see. Classic scope-mismatch bug that the nav caching made worse by pinning the stale number for 30s.

Fix

  • New ForumThread::unreadTotalForForums(int $userId, array $forumIds): int — same unread predicate as the existing unreadByForumIds / unreadCountsByForums, just returns a single count restricted to the supplied forum IDs.
  • BaseController now computes the badge via Forum::allGrouped first (same call as /forums/new + mark-all-read), then passes those forum IDs to the new total helper. All three paths are locked to the same scope — drift can't happen again.
  • Proactive cache flush of every nav_unread_count_*.json file in storage/cache so the scope change takes effect on the very next page-load instead of waiting 30 seconds for the TTL.

Tradeoff: the nav badge now does two queries instead of one (allGrouped + unread total) on a cache miss. Runs once per 30 seconds per user, so aggregate cost is unchanged. Gains correctness in exchange.


. __  ____   ___ ____  _     _     
 / /_| ___| / _ \___ \(_)___| |__  
| '_ \___ \| | | |__) | / __| '_ \ 
| (_) |__) | |_| / __/| \__ \ | | |
 \___/____/ \___/_____|_|___/_| |_|
        D2sk - Sysop

Log in or register to reply to this thread.