fix: address review — injective mirror roots, root relocation, full preview coverage, EXDEV-safe rollback

Codex review on #1124:

- P1: mirror layout root component is now <basename>-<roothash>
  (sha256 of the normalized root path), so two roots sharing a basename
  no longer map to the same mirror directory and overwrite each other's
  sidecars
- P1: changing sidecar_storage_path while centralized no longer strands
  assets in the old root — new relocate_root migration direction moves
  the whole mirror tree, rewrites preview_url prefixes inside sidecars,
  reconciles scanner caches, and prunes the emptied old tree; the
  settings UI detects the path change and offers the relocation
- P2: migration enumerates the same preview candidates as
  find_preview_file — case-insensitive variants (model.WEBP) and the
  legacy .example.0.jpeg suffix — instead of exact lowercase
  PREVIEW_EXTENSIONS only
- P2: _rollback_model_staging restores staged files with the
  EXDEV-tolerant mover, so a failed undoable-delete staging no longer
  strands a cross-filesystem centralized sidecar copy

Tests: same-basename root injectivity, mixed-case/example preview
migration, relocate_root happy path + guards + route 400, frontend
relocation prompt flow. Verified end-to-end in a sandboxed standalone
server: uppercase/legacy previews migrate, root relocation moves the
tree and the list API serves the new locations immediately without a
rescan.
This commit is contained in:
Will Miao
2026-09-26 12:24:17 +08:00
parent 16430aef21
commit a6fca8612f
22 changed files with 592 additions and 71 deletions
+4 -2
View File
@@ -809,7 +809,8 @@
"migrateFailed": "[TODO: Translate] Sidecar migration failed: {message}",
"migrationDeferred": "[TODO: Translate] Existing sidecars were not moved. You can migrate them later from Settings → Library → Sidecar Storage.",
"confirmToCentralized": "[TODO: Translate] The storage mode changed, but existing .metadata.json sidecars and preview images are not moved automatically. Move them into the centralized storage directory now? You can also do this later with the \"Migrate Sidecars Now\" button.",
"confirmToAlongside": "[TODO: Translate] The storage mode changed, but existing .metadata.json sidecars and preview images are not moved automatically. Move them back next to their model files now? You can also do this later with the \"Migrate Sidecars Now\" button."
"confirmToAlongside": "[TODO: Translate] The storage mode changed, but existing .metadata.json sidecars and preview images are not moved automatically. Move them back next to their model files now? You can also do this later with the \"Migrate Sidecars Now\" button.",
"confirmRelocateRoot": "[TODO: Translate] The centralized storage directory changed, but existing sidecars and preview images are still in the previous directory. Move them to the new directory now?"
},
"proxySettings": {
"enableProxy": "Habilitar proxy a nivel de aplicación",
@@ -1662,7 +1663,8 @@
"sidecarMigrationConfirm": {
"titleToCentralized": "[TODO: Translate] Move sidecars to centralized storage?",
"titleToAlongside": "[TODO: Translate] Move sidecars back next to model files?",
"confirmButton": "[TODO: Translate] Migrate Now"
"confirmButton": "[TODO: Translate] Migrate Now",
"titleRelocateRoot": "[TODO: Translate] Move sidecars to the new storage directory?"
},
"bulkAddTags": {
"title": "Añadir etiquetas a múltiples modelos",