Database: 427GB → 305GB
The production database crossed 427GB, with sailing_prices alone at 378GB. A full footprint analysis produced a tiered roadmap; Tier 1 landed today:
- Dropped an 82GB index with zero lifetime scans -- built long ago for a trends query that never shipped in that form.
- Stopped storing raw API responses on personalized package prices -- 39GB of compressed JSON nobody ever read back, and the raw-response observatory already logs the same responses independently. The column was nulled in batches and kept for rollback safety.
Post-VACUUM actuals: 305GB, a 122GB reclaim. Tier 2 (a change-only price ledger -- 98.7% of hourly rows are unchanged from the previous hour) remains on the roadmap.
Disk: Three Compounding Leaks
- The Silversea day-dir leak. The cache archiver only removed an expired day directory once it was empty, but Silversea writes sitemap and marker files the archiver didn't handle -- so its day dirs never emptied and ~4 months of them piled up while every other line self-pruned. Sitemaps are now archived as real data and leftover marker files are cleaned before the prune (guarded so a failed upload never deletes un-archived data).
- MSC's cache appetite. Once the Akamai bypass made MSC scrapes actually succeed, its cache started growing ~6GB/day. MSC now keeps zero days of cache with intra-day cleanup -- safe because cache lookups are hour-prefixed, so files older than two hours can never be hits again.
- The no-op archive loop. With baseline disk usage stuck above the 70% emergency threshold, the scheduler spawned an emergency archive every minute for 21 hours, each run freeing zero bytes because everything remaining was within retention. Emergency archives now carry a 30-minute cooldown.