# Release: Time's Up v2.5.1

**Release Date:** 2026-04-19
**Status:** Draft
**Manifest Version:** 3

## Release Summary

v2.5.1 is a patch release fixing a race condition in doomscroll content-script registration that was causing silent failures of the feature on some service worker lifecycles. The bug was surfaced by the v2.5.0 diagnostics panel and had been logged invisibly to `chrome://extensions/errors` for weeks.

## Bug Fixes

### Doomscroll Duplicate Script ID Race (BUG-008)
**Requirement doc:** [requirements/bugs/BUG-008-doomscroll-duplicate-id.md](../bugs/BUG-008-doomscroll-duplicate-id.md)

`updateDoomscrollScripts()` used an unregister-then-register sequence that was not atomic. When `init()` (called on SW startup) ran concurrently with `handleSetConfig()` (called on every config save), the two calls could interleave such that both passed the unregister step and both attempted to register with the same id, producing `Duplicate script ID 'timesup-doomscroll'`. The second register call failed, leaving doomscroll detection silently uninstalled for that SW lifecycle.

- **Root cause:** Non-atomic unregister-then-register sequence with no serialization between concurrent callers.
- **Fix:**
  - Extracted pure `computeDoomscrollAction(existing, ds)` that decides `register | update | unregister | noop` from current state. This replaces the always-unregister-first approach with an MV3-idiomatic upsert — if a registration exists, use `updateContentScripts` (idempotent) instead of register.
  - Added a module-level promise chain (`doomscrollChain`) so concurrent callers of `updateDoomscrollScripts()` serialize instead of racing.
- **Impact:** Doomscroll detection installs reliably across SW restarts and config saves. The "Duplicate script ID" error stops appearing in `chrome://extensions/errors` and in the v2.5.0 diagnostics export.

## Test Coverage Added

- 11 new unit tests in `tests/unit/background/doomscrollAction.test.js`:
  - All four decision branches of `computeDoomscrollAction` (register, update, unregister, noop)
  - Match-pattern construction (www + bare domain, multiple sites)
  - Invariant: with an existing registration, never return `register` (core BUG-008 guarantee)
  - Serialization chain: two concurrent callers execute in strict sequence, and the chain continues after a caller rejects.

## Migration Notes

No user migration needed. Existing doomscroll registrations from v2.5.0 are transparently picked up by `updateContentScripts` on next config save or SW startup.
