CI / lint (push) Successful in 2s
CI / extension-version (push) Successful in 2s
Build images / sign-extension (push) Successful in 4s
Build images / build-ml (push) Successful in 6s
Build images / build-agent (push) Successful in 6s
CI / frontend-build (push) Successful in 22s
CI / backend-lint-and-test (push) Successful in 32s
Build images / build-web (push) Successful in 1m6s
Build images / smoke-web (push) Skipped
Build images / promote (push) Skipped
CI / integration (push) Successful in 2m17s
The UI half of the reconciler, in Maintenance. Survey shows how many images sit in the wrong artist's folder and which folders they are in; each artist gets its own Plan button; each run can be reviewed, applied, and put back. Deliberately NOT using useMaintenanceTask. That composable stashes a task id in localStorage so a result survives navigate-away, which is the right answer when the only record is a Celery result. Here the runs are database rows — so a reload, another machine, or coming back tomorrow simply shows the same state, because the state IS the row. The card polls the runs endpoint instead. Copy avoids the vocabulary this work has been tripping over: "folder", "put back", "in the wrong folder" rather than artist_id, revert and canonical. The one thing the operator most needs to know — nothing here changes who an image belongs to — is what the blurb says first. Three things I had assumed and checked instead: MaintenanceTile lives in common/ not settings/; there is no generic ConfirmDialog (BackupCard uses a purpose-built modal), so this uses a plain v-dialog; and `loadArtistNames` did not exist — it does now, mapping id to name so a run row reads "Conto" rather than "#47". The name deliberately is not denormalised into the run: it belongs to the artist and would go stale on a rename. Also extracted `stubFetch` to frontend/test/stubFetch.js. The shape ledger flagged it as a byte-identical duplicate across five specs and this would have been the sixth; the others keep their copies until each is next touched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR