Version 2.0.0

July 9, 2026

Breaking change: Watson 2.0 changes how violations are stored. The upgrade migration collapses existing rows into one aggregated row per unique violation and cannot be reverted — back up your database before updating. Raw payloads no longer include the full CSP policy, and the default retention drops from 90 to 30 days.

Watson now stores one row per unique violation instead of one row per report, and purges itself. This release exists because v1.0.0 could fill a database on a high-traffic site with a repeating violation and no purge cron.

Added

  • Violations are aggregated by signature (kind + directive + blocked URI + document URI, query strings stripped): recurrences bump a hits counter and lastSeen timestamp instead of inserting new rows.
  • Automatic purging: a purge queue job is scheduled as reports come in, at most once per autoPurgeIntervalHours (default: 24). Controlled by the new autoPurge setting (default: on).
  • New storeRawPayload setting (default: on) to skip raw payload storage entirely.
  • Violations index now shows and sorts by Hits, First seen, and Last seen.
  • A resolved violation that recurs automatically flips back to new; ignored violations keep counting silently.
  • Install-time JSONL import now aggregates reports and warns on files over 10 MB.

Changed

  • The full CSP policy (originalPolicy) is no longer stored — it was the biggest row-size driver, repeated in every report.
  • Database write failures during report collection are caught and logged as warnings; the endpoint always answers 204 and no longer floods error monitoring (e.g. Sentry) at report volume.
  • Retention is now measured against lastSeen (last occurrence), not dateCreated.
  • Default retentionDays lowered from 90 to 30.
  • watson/violations/purge --days now defaults to the retentionDays setting instead of a hardcoded 90.
  • Unparseable request bodies are truncated to 4 KB before storage.

Upgrade notes

  • The upgrade migration collapses existing duplicate rows into aggregated rows (summing occurrence counts, keeping first/last seen). Per-report rows, IPs, and user agents of collapsed duplicates are discarded. If any collapsed row was still new, the surviving row is marked new.
  • The migration cannot be reverted.

Version 1.0.0

June 15, 2026
  • Initial release