A badge count that drifts from reality undermines the entire notification contract. When bulk-delete actions, crash-interrupted decrements, or missed code paths leave the counter stale, users open the popup expecting unread items and find none — or worse, miss real items because the badge showed zero. ISO 25010:2011 functional-suitability.functional-correctness applies directly: the badge's job is accurate representation of state, and independent increment/decrement counters are structurally incapable of guaranteeing that.
Medium because stale badge counts cause user confusion and erode trust in the extension's reliability, but do not expose security risk or block core functionality.
Derive the badge count from a single source of truth on every update rather than maintaining a separate counter. Tie badge updates to chrome.storage.onChanged so any write to the underlying data automatically recalculates the displayed count.
async function updateBadge() {
const { items } = await chrome.storage.local.get(['items']);
const unread = (items ?? []).filter(item => !item.read).length;
chrome.action.setBadgeText({
text: unread > 0 ? String(unread) : ''
});
}
chrome.storage.onChanged.addListener(() => updateBadge());
Never increment or decrement a counter variable directly — every code path that modifies items must go through storage, and onChanged handles the badge automatically.
ID: extension-ux-performance.badge-notifications.badge-count-accurate
Severity: medium
What to look for: Examine the logic that sets the badge text via chrome.action.setBadgeText. Check whether the badge count is updated when items are marked read, dismissed, or acted upon. Look for whether the count is recalculated from a source of truth (e.g., counting unread items in storage) or tracked independently (incrementing or decrementing a counter variable, which can drift out of sync). Before evaluating, extract and quote the badge update calls (e.g., chrome.action.setBadgeText) to verify the count logic. Count all instances found and enumerate each.
Pass criteria: The badge count is derived from a consistent source of truth — e.g., recomputed by counting qualifying items in chrome.storage.local each time it updates. Decrement or increment based counters are only used if they are reset from source of truth periodically as a check. At least 1 implementation must be confirmed.
Fail criteria: Badge count is maintained as an independent counter that is incremented on new items and decremented on dismissal, with no reconciliation against actual data. If increment or decrement operations miss a path (e.g., bulk delete not reflected, crash during update), the counter drifts and misrepresents the true count.
Skip (N/A) when: The extension does not use the badge API or the badge does not display a count.
Cross-reference: The badge-cleared-on-view check verifies the badge count is reset when the user opens the popup.
Detail on fail: Describe the accuracy issue. Example: "Badge count incremented on new notification but not decremented when items dismissed via bulk action — count drifts over time" or "Badge not updated when user marks items read from the popup — count remains stale until browser restart."
Remediation: Derive badge count from source of truth rather than maintaining a separate counter:
async function updateBadge() {
const { items } = await chrome.storage.local.get(['items']);
const unread = (items ?? []).filter(item => !item.read).length;
chrome.action.setBadgeText({
text: unread > 0 ? String(unread) : ''
});
}
// Call updateBadge() wherever items change:
chrome.storage.onChanged.addListener(() => updateBadge());