revert: remove the placement reconciler — it manufactured the problem it solved
CI / lint (push) Successful in 2s
CI / extension-version (push) Successful in 3s
Build images / sign-extension (push) Successful in 3s
Build images / build-agent (push) Successful in 6s
CI / frontend-build (push) Successful in 26s
CI / backend-lint-and-test (push) Successful in 33s
Build images / build-web (push) Successful in 59s
Build images / smoke-web (push) Skipped
Build images / build-ml (push) Successful in 1m55s
Build images / promote (push) Skipped
CI / integration (push) Successful in 2m22s
CI / lint (push) Successful in 2s
CI / extension-version (push) Successful in 3s
Build images / sign-extension (push) Successful in 3s
Build images / build-agent (push) Successful in 6s
CI / frontend-build (push) Successful in 26s
CI / backend-lint-and-test (push) Successful in 33s
Build images / build-web (push) Successful in 59s
Build images / smoke-web (push) Skipped
Build images / build-ml (push) Successful in 1m55s
Build images / promote (push) Skipped
CI / integration (push) Successful in 2m22s
Milestone #421 built a sweep that compared each image's `artist_id` to the name of the directory holding its file, and called every mismatch a misplaced image. It reported 33,789 of 63,605 as wrongly filed. That number described the comparison, not the library. What it actually was: 32,475 (97.1%) one artist's own folder, spelled differently — Telepurte/ vs telepurte/. Same artist, same art. 657 ( 2.0%) loose at the images root 328 ( 1.0%) in a folder named after a different artist And the 1% did not mean what the tool assumed either. `ImageProvenance` records the post and source every file was downloaded from — the authoritative answer, which the tool never consulted. Querying it for all 328: 144 provenance agrees with the record (move would be right) 87 provenance agrees with the FOLDER (the record is wrong; move wrong) 53 provenance names SEVERAL artists (no single correct folder) 41 no provenance at all 3 agrees with neither So the sweep would have misfiled or arbitrarily picked for ~41% of the only set it was really needed for. The system already knew where each file came from; the tool inferred it from a column and a directory name instead. Operator, 2026-09-21: *"the current system consistently records where items are and where they came from this is just complicating something works and doesn't need fixing."* Correct on both counts. Removed: the service, the tasks, the model and migration 0099's table, the /api/cleanup/layout and /placement/* endpoints, the Maintenance card and its store actions, and the tests. 0100 drops the table (rule #22 — no legacy). KEPT deliberately, per the operator: - `utils.paths.canonical_subdir` — new filesystem imports derive their directory from the artist's slug, matching what the downloader always did. Not part of this tool; removing it would be churn that fixes nothing. - The 327 files run 1 moved (InsoUwu/ -> insouwu/). Same artist either way, and the gallery renders them correctly. - Everything from #4223 (three-gate dedup, 256-bit pHash) and #4234 (backup credential exclusion). Those fixed problems that were actually reported. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
This commit is contained in:
@@ -71,66 +71,10 @@ export const useCleanupStore = defineStore('cleanup', () => {
|
||||
return await api.post(`/api/cleanup/audit/${id}/cancel`)
|
||||
}
|
||||
|
||||
// --- placement reconciler (milestone #421) --------------------------------
|
||||
//
|
||||
// Runs are server-side rows, so the DATABASE is the durable state here —
|
||||
// no localStorage resurfacing (useMaintenanceTask) is needed. Reload the
|
||||
// page, open it on another machine, and the run and its status are simply
|
||||
// there. That also means a plan survives being walked away from for a day.
|
||||
|
||||
const placementRuns = ref([])
|
||||
const layout = ref(null)
|
||||
|
||||
// The survey: which rows sit outside their artist's directory. check_disk
|
||||
// additionally stats every destination (collisions, missing sources) and
|
||||
// costs one stat per misplaced row over NFS, so it is opt-in.
|
||||
async function loadLayout(checkDisk = false) {
|
||||
layout.value = await api.get('/api/cleanup/layout', {
|
||||
params: checkDisk ? { check_disk: 1 } : {},
|
||||
})
|
||||
return layout.value
|
||||
}
|
||||
|
||||
// id -> name, so a run row can say "Conto" instead of "#47". The runs
|
||||
// endpoint carries artist_id alone: the name belongs to the artist, and
|
||||
// denormalising it into every run would go stale the moment one is renamed.
|
||||
async function loadArtistNames() {
|
||||
const rows = await api.get('/api/artists/names')
|
||||
return Object.fromEntries((rows || []).map(a => [a.id, a.name]))
|
||||
}
|
||||
|
||||
async function loadPlacementRuns(limit = 25) {
|
||||
const body = await api.get('/api/cleanup/placement/runs', { params: { limit } })
|
||||
placementRuns.value = body.runs || []
|
||||
return placementRuns.value
|
||||
}
|
||||
|
||||
// Detail carries `moves` — the plan the operator reads before agreeing.
|
||||
async function getPlacementRun(id) {
|
||||
return await api.get(`/api/cleanup/placement/runs/${id}`)
|
||||
}
|
||||
|
||||
async function planPlacement(artistId = null) {
|
||||
return await api.post('/api/cleanup/placement/plan', {
|
||||
body: artistId === null ? {} : { artist_id: artistId },
|
||||
})
|
||||
}
|
||||
|
||||
async function applyPlacement(id) {
|
||||
return await api.post(`/api/cleanup/placement/runs/${id}/apply`)
|
||||
}
|
||||
|
||||
async function revertPlacement(id) {
|
||||
return await api.post(`/api/cleanup/placement/runs/${id}/revert`)
|
||||
}
|
||||
|
||||
return {
|
||||
defaults, recentRuns,
|
||||
loadDefaults,
|
||||
previewMinDim, deleteMinDim,
|
||||
startAudit, getAudit, loadHistory, latestAuditForRule, applyAudit, cancelAudit,
|
||||
placementRuns, layout,
|
||||
loadLayout, loadArtistNames, loadPlacementRuns, getPlacementRun,
|
||||
planPlacement, applyPlacement, revertPlacement,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user