diff --git a/CHANGELOG.md b/CHANGELOG.md
index 479ca92cc..dc0ee9b2e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,8 @@ All notable changes to Bambuddy will be documented in this file.
- **Slice modal: pick the build plate (#1337, reported by @digitalskies)** — Slicing a plain STL through the integrated slicer always defaulted to whatever `curr_bed_type` lived in the chosen process preset (typically `Cool Plate`), which the slicer CLI then rejected for high-temp filaments with `Plate 1: Cool Plate does not support filament 1`. The user had no way to switch plates short of cloning the process preset in BambuStudio, which defeats the point of the in-app slicer. The Slice modal now exposes a `Build plate` dropdown with the six canonical BambuStudio / OrcaSlicer plates (Cool Plate, Cool Plate SuperTack, Engineering Plate, High Temp Plate, Textured PEI Plate, Smooth PEI Plate) plus an explicit `Auto (use process preset)` option that preserves the previous behavior. The dropdown sits between Process profile and Filament rows so it stays visible regardless of how many filament slots the picked plate uses (a long filament list would otherwise push it off the modal's `max-h-[85vh]` scroll viewport) and is **always enabled** — including when the user picks a Printer Preset Bundle from the top BundlePicker. When the user picks a specific plate, the new `bed_type` field on `SliceRequest` ([`backend/app/schemas/slicer.py`](backend/app/schemas/slicer.py)) flows through the dispatcher via two paths: (1) **resolved-preset path** — the route helper `_patch_process_bed_type` in [`backend/app/api/routes/library.py`](backend/app/api/routes/library.py) overwrites `curr_bed_type` on the resolved process JSON before forwarding to the sidecar (no preset cloning required); (2) **bundle dispatch path** — `slice_with_bundle` in [`backend/app/services/slicer_api.py`](backend/app/services/slicer_api.py) adds a `bedType` form field to the sidecar multipart so the sidecar can pass `--curr_bed_type` through to the CLI, which lets the override take effect even though Bambuddy can't patch the bundle's process JSON locally (the sidecar materialises it from the stored .bbscfg). Sidecar versions that don't recognise the field silently no-op — the slice still runs, just with the bundle's default plate; the slicer-API fork at maziggy/orca-slicer-api will need the matching change for the bundle path to take full effect. **i18n parity:** 8 new keys (`slice.bedType.{label,auto,coolPlate,coolPlateSuperTack,engineering,highTemp,texturedPEI,smoothPEI}`) added to all 8 locales — full German translation, English fallbacks elsewhere per project convention. **Regression tests:** 4 in [`test_slice_request_bed_type.py`](backend/tests/unit/test_slice_request_bed_type.py) (`bed_type` defaults to None, accepts the six canonical strings, rejects overlong input via the schema's `max_length=64`; `_patch_process_bed_type` overwrites an existing value, adds the field when missing, and returns the input unchanged for malformed JSON or non-dict roots), 4 in [`test_library_slice_api.py`](backend/tests/integration/test_library_slice_api.py) (resolved-preset path: with `bed_type` set, the sidecar receives `"curr_bed_type": "Textured PEI Plate"` in the presetProfile multipart part; without it, `curr_bed_type` stays out of the body entirely. bundle dispatch path: `bedType` form field carries the override through to the sidecar; omitting `bed_type` keeps the form field out of the request so the bundle's own `curr_bed_type` is preserved), 2 in [`SliceModal.test.tsx`](frontend/src/__tests__/components/SliceModal.test.tsx) (dropdown selection puts `bed_type` on the request; leaving it on Auto omits the field). 59 backend slice tests + 34 SliceModal tests pass; build and i18n parity script clean.
### Fixed
+- **In-app updater no longer fails with "Failed to fetch updates" when a tag on the remote was re-pointed** — Symptom on native installs upgrading from 0.2.4: clicking *Settings → System → Updates → Apply Update* aborted with `Git fetch failed: From https://github.com/maziggy/bambuddy ... ! [rejected] v0.2.1 -> v0.2.1 (would clobber existing tag)` even though `origin/main` and the target release tag fetched cleanly. `_perform_update` in [`backend/app/api/routes/updates.py:526`](backend/app/api/routes/updates.py) ran `git fetch --prune --tags origin`, which returns a non-zero exit if even one local tag would be overwritten by a moved upstream tag — and any non-zero exit was surfaced to the user as a hard failure, leaving them stuck on the previous release. **Fix:** added `--force` to the fetch invocation so a re-pointed tag on the remote overwrites the local stale copy cleanly; matches the in-app updater's contract ("sync me to the remote"). The native `update.sh` doesn't hit this bug because it fetches without `--tags` at all, but the in-app path can't drop `--tags` — release-tag refs (`v0.2.4b1`, `v0.2.4.1`, …) need to be locally resolvable for the subsequent `git reset --hard`. **Note for users on 0.2.4 upgrading to 0.2.4.1:** the fix is *in* 0.2.4.1, which 0.2.4's updater can't reach. Use the CLI path documented in the release notes for this one upgrade; from 0.2.4.1 onward the in-app button works again. Docker installs are unaffected — they don't go through git. Regression test in [`backend/tests/integration/test_updates_api.py`](backend/tests/integration/test_updates_api.py) asserts `--force` is in the fetch args alongside the existing `--tags` assertion so a future refactor can't quietly drop it.
+
- **Print Queue page no longer 404-storms thumbnail / plates / plate-thumbnail when an item points at a soft-deleted archive, and pending queue items for a soft-deleted archive are now cancelled with a clear reason instead of silently stuck-pending forever** ([#1348](https://github.com/maziggy/bambuddy/issues/1348) follow-up) — Symptom: opening the Queue page or any of its sub-views fired `GET /archives/{id}/thumbnail`, `GET /archives/{id}/plates`, and `GET /archives/{id}/plate-thumbnail/{n}` for queue rows pointing at archives that had been soft-deleted (#1343 leaves the row but removes files from disk), all returning 404. Frontend's `onError` handler hid the broken `
` so it was visually clean, but the network tab and any pending-print logic still saw three 404s per affected row. Two underlying problems wearing one mask: cosmetic 404 storm, AND functional — a queue item whose 3MF was removed from disk can never actually dispatch, so it sits in `pending` forever with no clue to the user about why. **Two-part fix in the same shape as the print-log followup above:** (1) New helper `_cancel_pending_queue_items(db, archive_id)` in [`backend/app/services/archive.py`](backend/app/services/archive.py) sets `status='cancelled'` + `waiting_reason='Source archive deleted'` on every pending queue item linked to the archive; called from `soft_delete_archive` alongside the existing `_null_print_log_thumbnail_paths` cleanup. Only `pending` is touched — `printing` is a rare race that the printer-side fail-path catches anyway, and completed / failed / cancelled rows are historical audit-trail. Hard-delete is already covered by `ON DELETE CASCADE` on `print_queue.archive_id`. (2) Queue API serializer in [`backend/app/api/routes/print_queue.py:224`](backend/app/api/routes/print_queue.py) now checks `item.archive.deleted_at` before populating any archive-derived field — when soft-deleted, the whole block (`archive_name`, `archive_thumbnail`, `print_time_seconds`, `filament_used_grams`, plate-specific re-reads, …) is skipped and the new `archive_deleted: bool = True` flag on [`PrintQueueItemResponse`](backend/app/schemas/print_queue.py) signals the soft-deleted state. The `archive_thumbnail` suppression alone covers the thumbnail render in [`QueuePage.tsx:434`](frontend/src/pages/QueuePage.tsx), [`CompactHistoryRow.tsx:45`](frontend/src/components/CompactHistoryRow.tsx), and [`QueueTimelineView.tsx:72`](frontend/src/components/QueueTimelineView.tsx) because they all gate on it. The `/plates` query at [`QueuePage.tsx:329`](frontend/src/pages/QueuePage.tsx) was gated on `archive_id` only — `archive_id` is the real FK and stays exposed in the response (the queue scheduler still needs it for audit / dispatch checks), so the query was added a new `&& !item.archive_deleted` clause to respect the new flag. **Regression tests** in [`backend/tests/integration/test_print_queue_api.py`](backend/tests/integration/test_print_queue_api.py): `test_soft_delete_archive_cancels_pending_queue_items` pins the cancel-only-pending behavior (completed rows untouched), `test_queue_api_hides_archive_surface_when_soft_deleted` pins the suppression + `archive_deleted=True` for soft-deleted archives, `test_queue_api_still_exposes_archive_surface_when_live` pins the sanity guard that live archives' fields keep flowing through. All 3 new tests + 146 in the queue/archives/obico sweep pass; ruff clean.
- **Print log no longer 404-storms on the thumbnail endpoint for entries whose archive was deleted or whose print failed before a thumbnail was extracted** ([#1348](https://github.com/maziggy/bambuddy/issues/1348) follow-up) — Symptom in DevTools when opening Archives → Print Log: a 404 per orphaned entry per render. Visually clean (the `
` handler in [`frontend/src/pages/ArchivesPage.tsx:3763`](frontend/src/pages/ArchivesPage.tsx) hides the broken image), but noisy and wasteful. **Root cause** in [`backend/app/api/routes/print_log.py:91-113`](backend/app/api/routes/print_log.py): `PrintLogEntry.thumbnail_path` is copied by value from `archive.thumbnail_path` at write-time ([`main.py:3615`](backend/app/main.py)) but the FK on `archive_id` is `ON DELETE SET NULL` (#1378) — so log entries survive archive deletion to preserve stats history, but the cached thumbnail_path string keeps pointing at a file that was removed when the archive's directory was deleted. Same shape for failed prints that recorded an expected thumbnail path before the extractor wrote (or skipped writing) the file. **Two-part fix:** (1) `get_print_log_thumbnail` self-heals when the file is missing — it NULLs `thumbnail_path` on the entry and commits before returning 404, so the frontend's `entry.thumbnail_path &&
` gate keeps the next page render from re-requesting. (2) New helper `_null_print_log_thumbnail_paths(db, archive_id)` in [`backend/app/services/archive.py`](backend/app/services/archive.py) is called from `soft_delete_archive` and `delete_archive` before the on-disk files are removed — eager clear so future deletes don't cause the one-time storm at all. The route handler covers stragglers (failed prints, files manually moved, etc.). **Regression tests** in [`backend/tests/integration/test_archives_api.py`](backend/tests/integration/test_archives_api.py): `test_soft_delete_clears_thumbnail_path_on_linked_log_entries` pins the eager clear on the soft-delete route, `test_hard_delete_clears_thumbnail_path_before_fk_cascade` pins it on `ArchiveService.delete_archive` (used by the auto-purge sweeper), `test_print_log_thumbnail_route_lazy_nulls_missing_file` pins the route's self-heal for failed-print orphans where the file was never written. All 4 new tests + 61 in the archives/print-log sweep pass; ruff clean.