Final step of #768. Read cutover verified in prod (suggestions + allowlist read image_prediction; backfill complete at 908k rows / 51k images).
Change
Migration 0046 DROPs image_record.tagger_predictions. The model field is removed; tagger_model_version stays as the "tagged / current?" signal.
tag_and_embed no longer dual-writes the JSON — image_prediction is the only write path. The backfill needs-tagging check switched to tagger_model_version IS NULL.
Importer re-import reset and all tests updated to image_prediction.
Retired the one-time #768 backfill task + #764 prune task, both admin endpoints, and both Maintenance cards.
Deploy notes
Quiesce the ml-worker (docker service scale curator_ml-worker=0) during the migration — 0046's DROP COLUMN takes a brief ACCESS EXCLUSIVE on image_record, and an old ml-worker still writing the JSON column would error against the new schema.
Force a real :latest re-pull and roll all services; web runs 0046 on boot.
Backups (#739) are fixed by the DROP alone (pg_dump is logical). Optional, off-hours: VACUUM (FULL, ANALYZE) image_record to return the ~100 GB physical disk to the OS — it takes an ACCESS EXCLUSIVE lock for the duration (likely minutes; only live data is copied), so run it quiesced.
Dev CI green (run 895: lint, backend, integration incl. the 0046 migration, frontend-build).
Final step of #768. Read cutover verified in prod (suggestions + allowlist read `image_prediction`; backfill complete at 908k rows / 51k images).
## Change
- **Migration 0046 DROPs `image_record.tagger_predictions`.** The model field is removed; `tagger_model_version` stays as the "tagged / current?" signal.
- `tag_and_embed` no longer dual-writes the JSON — `image_prediction` is the only write path. The backfill needs-tagging check switched to `tagger_model_version IS NULL`.
- Importer re-import reset and all tests updated to `image_prediction`.
- Retired the one-time #768 backfill task + #764 prune task, both admin endpoints, and both Maintenance cards.
## Deploy notes
1. **Quiesce the ml-worker** (`docker service scale curator_ml-worker=0`) during the migration — `0046`'s `DROP COLUMN` takes a brief `ACCESS EXCLUSIVE` on `image_record`, and an old ml-worker still writing the JSON column would error against the new schema.
2. Force a real `:latest` re-pull and roll **all** services; web runs `0046` on boot.
3. Backups (#739) are fixed by the DROP alone (`pg_dump` is logical). Optional, off-hours: `VACUUM (FULL, ANALYZE) image_record` to return the ~100 GB physical disk to the OS — it takes an ACCESS EXCLUSIVE lock for the duration (likely minutes; only live data is copied), so run it quiesced.
Dev CI green (run 895: lint, backend, integration incl. the 0046 migration, frontend-build).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Read cutover verified in prod (suggestions + allowlist read image_prediction;
backfill complete at 908k rows / 51k images). Removes the old JSON column and
everything that fed it:
- ImageRecord.tagger_predictions column removed; migration 0046 DROPs it.
tagger_model_version kept as the "tagged / current?" signal the backfill
sweep reads (needs-tagging check switched to tagger_model_version IS NULL).
- tag_and_embed no longer dual-writes the JSON — image_prediction is the only
write path.
- importer re-import reset drops the JSON line (image_prediction rows are
already deleted on re-import).
- Retired the one-time #768 backfill task + the #764 prune task, their admin
endpoints, and their Maintenance cards (Backfill/PrunePredictionsCard).
- Tests seed/assert via image_prediction; stale column refs removed.
Disk reclaim is NOT automatic: DROP COLUMN is a catalog change. Run
`VACUUM FULL image_record` off-hours afterward to return the ~100 GB to the OS
so DB backups go small (#739). image_prediction (~90 MB) stays in pg_dump — it's
the source of truth now.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Final step of #768. Read cutover verified in prod (suggestions + allowlist read
image_prediction; backfill complete at 908k rows / 51k images).Change
image_record.tagger_predictions. The model field is removed;tagger_model_versionstays as the "tagged / current?" signal.tag_and_embedno longer dual-writes the JSON —image_predictionis the only write path. The backfill needs-tagging check switched totagger_model_version IS NULL.image_prediction.Deploy notes
docker service scale curator_ml-worker=0) during the migration —0046'sDROP COLUMNtakes a briefACCESS EXCLUSIVEonimage_record, and an old ml-worker still writing the JSON column would error against the new schema.:latestre-pull and roll all services; web runs0046on boot.pg_dumpis logical). Optional, off-hours:VACUUM (FULL, ANALYZE) image_recordto return the ~100 GB physical disk to the OS — it takes an ACCESS EXCLUSIVE lock for the duration (likely minutes; only live data is copied), so run it quiesced.Dev CI green (run 895: lint, backend, integration incl. the 0046 migration, frontend-build).
🤖 Generated with Claude Code