Skip to content
Merged
2 changes: 1 addition & 1 deletion plugins/disk-hygiene/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "disk-hygiene",
"version": "0.15.0",
"version": "0.16.0",
"description": "Context-aware disk hygiene for arbitrary directory trees: inventories orphaned and temporary artifacts, classifies evidence into review tiers, and offers exact-path cleanup only after a fresh safety preview and explicit per-tier approval. The target is read-only by default; OS-managed paths, links and mount points, VCS-tracked content, changed entries, and live-handle uncertainty fail closed.",
"author": {
"name": "Melodic Software",
Expand Down
35 changes: 32 additions & 3 deletions plugins/disk-hygiene/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,39 @@
All notable changes to the `disk-hygiene` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.15.0]
## [0.16.0]

> Version note: `0.14.0` is never published. This entry claimed it while open, and 0.15.0 shipped
> first with a note pointing here; taking the next free number on merge is what keeps both entries
> truthful about the order they actually landed in.

### Fixed

- **Byte accounting can say "unknown" and "not reclaimable local bytes" (#1806).** Finding 2 of
the live audit: a truncated subtree emitted `logical_size: 0`, byte-identical to a genuinely empty
directory, while hard-linked names each contributed their full `st_size` to every total. PR #1818
landed the `size_qualifiers` / `file_attributes` mechanism for cloud placeholders and deliberately
left aggregates alone so this change could own the rest.

Every entry now records `nlink` and `allocated_size` (cheap `st_blocks * 512` on POSIX; null on
Windows where that field is absent). A truncated directory — max-depth, protected name, or VCS
boundary — carries `logical_size: null` and `not-walked` rather than pretending to be empty. Files
with `st_nlink > 1` carry `hardlinked`; sparse files carry `sparse` when the platform exposes the
signal. Snapshot, preview, apply, and the scan-complete summary each report
`reclaimable_local_bytes` (or `target_reclaimable_local_bytes` /
`reclaimable_local_bytes_removed`) as a figure distinct from the walked logical roll-up: every
qualified entry is excluded, so a report can no longer honestly claim gigabytes removed when the
observed free-space delta is ~0 because the bytes were shared, remote, or never inventoried.

### Follow-ups left open on #1806

Findings 3 (a `summarize` surface), 4 (Stop-detector marker amortisation), 6 (probe path
provenance vs the guard's trusted settings channel), and 7 (run-state retention / snapshot path
containment) stay out of this PR — each needs a design or coupled-grammar call rather than a
mechanical completion of the byte-qualification vertical slice. Findings 1 and 5 already shipped in
0.13.0.

> Version note: `0.14.0` is claimed by PR #1870, open against this manifest. This entry takes the
> next number so the two do not collide.
## [0.15.0]

### Fixed

Expand Down
9 changes: 7 additions & 2 deletions plugins/disk-hygiene/skills/clean/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,13 @@ coverage-gap entries. Empty directories are not inherently junk.
An entry's `logical_size` is reclaimable local bytes only when its `size_qualifiers` is empty.
Exclude every qualified entry from any reclaimable-bytes total and state the qualified bytes
separately with their reasons — a `cloud-placeholder` carries its REMOTE size while occupying
roughly nothing locally, so folding it into a total claims space that deleting it would never
return.
roughly nothing locally; a `hardlinked` name shares one object with other names; a `sparse` file's
logical size overstates local allocation; and `not-walked` means the subtree was never inventoried,
so `logical_size` is `null` rather than `0` — except on the target's own record, which keeps its
partial walked sum alongside a `not-walked` qualifier, so read that number as a floor. Prefer the
snapshot's `target_reclaimable_local_bytes` (and preview/apply `reclaimable_local_bytes*`) over summing
`logical_size` yourself — folding qualified or unknown sizes into a total claims space that
deleting the path would never return.

## 4. Build one exact-tier plan

Expand Down
Loading