Safety:
- `destroy`'s rollback-pin arm took a tag over IPC and interpolated it
straight into an image reference it then removed. `tag: "latest"` named
the project's live snapshot, deleted under a dialog saying "rollback
pin". It is the one destructive variant carrying a free-form string, so
it now goes through `parse_rollback_tag`.
- The compaction's scratch container was named `triple-c-scrub-*`, which
is what the scrub reclaim bucket hunts and force-removes. A reclaim from
a second window would have destroyed the container a running compaction
was about to commit. It gets `triple-c-compact-*`, swept at the start of
the next compaction rather than from a bucket anything else can fire.
- Deleting a home or config volume only refused a *running* container, but
a stopped one still pins its volumes — the resting state of every
project ever started — so the user typed the project name and met a raw
409. The container is now removed first and `loses` says so.
Correctness:
- The compaction Dockerfile emitted no `LABEL`, so the flattened
intermediate could never match the sweep's `dangling` + `triple-c.managed`
filter that three cleanup paths rely on. Verified on Docker 29.7.2 that
the label lands on the final stage, the build still yields one layer, and
untagging the staging tag after the commit leaves the committed snapshot
intact and startable.
- `snapshot_commit_layers` silently meant something else when
`triple-c.base-image-id` was absent — the normal case for a pre-label
project — counting the base's own layers and letting a never-recreated
project qualify for compaction. `base_lineage_known` now carries that,
the column says "unknown", and the plan does not offer the rewrite.
- `destroy` returned a `ReclaimResult` wearing a `ReclaimTarget` that named
work it had not done (a home-volume deletion came back as
`OrphanVolume`). Split into `target` / `destroyed`, exactly one set.
- `formatBytes` ran `toFixed` after the divide loop, so 999,999 rendered as
"1000.0 KB" — in the app's only byte formatter, in a panel full of
near-boundary sizes.
- `is_base_image_reference` split on the first colon, so a registry port
ate the repo name.
UI:
- `snapshot_above_base_bytes: null` — deliberately unmeasurable — rendered
as "0 B", the one guessed number in the table.
- Layer count was flagged by colour alone; it now says "stacked".
- The tick list survived a reclaim, so the same call could be re-fired at
objects that no longer existed. The plan is dropped after any action and
the panel says the totals predate it.
- `setReport` landed before the plan call was awaited, so a plan failure
rendered fresh totals above the previous scan's rows.
- Both confirmation modals unmounted before awaiting, making the entire
busy path dead code during multi-second work.
- `buildx du` failures silently showed `docker system df`'s under-reported
build-cache figure with no explanation.
- Tooltip text reached no assistive tech, so two headers announced as
"Help"; hardcoded input id; error-toned glyph in warning-toned panels;
`sweepOrphanedSnapshots` and `clearOutcome` had no callers.
- Four docstrings claimed things the code did not do, and two tests were
named for behaviour they did not assert.
Tests: 513 frontend (was 502), 370 Rust (was 365).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBq2rGum6GX7xXgsas1fDc