diff --git a/CLAUDE.md b/CLAUDE.md index 193d311..621dd25 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,7 +24,7 @@ go test ./internal/ -run TestGolden -update # regenerate golden files after | `docs/SPEC.md` | behavior the user approved: commands, flags, JSON, safety levels, ecosystem catalog, config | behavior changes | | `docs/ARCHITECTURE.md` | module boundaries, cross-module contracts, adding an ecosystem | a boundary or contract changes | | `plugins/devclean/skills/devclean/SKILL.md` | the Claude Code skill that runs the binary for the user | commands, flags, JSON fields or safety gates change | -| `docs/decisions/` | one costly-to-reverse choice per file: decision, verification, rationale, rejected alternatives | such a choice is made or reversed | +| `docs/decisions/` | one costly-to-reverse choice per file: decision, rationale, rejected alternatives | such a choice is made or reversed | | `CHANGELOG.md` | release sections written by release-please from PR titles | never by hand (`docs/decisions/release-please.md`) | - Update docs in the same commit as the code. diff --git a/docs/decisions/clone-aware-size.md b/docs/decisions/clone-aware-size.md index da02b19..5a079da 100644 --- a/docs/decisions/clone-aware-size.md +++ b/docs/decisions/clone-aware-size.md @@ -9,15 +9,6 @@ The per-file block sum is kept as `allocated_size` when larger. -## Verification - -```bash -go test ./internal/scanner/ -run 'Clone|Pnpm' -v -go test ./internal/output/ -run SharedBlocks -v -``` - -Measured 2026-10-02: Chrome copies 11.3 GB → 0.76 GB; a pnpm `node_modules` 448 MB → 3.9 MB; home scan time unchanged (~60 s). - ## Rationale - Sizes that are mostly shared blocks (Chrome copies ~15×) lead users to delete for space that never comes back. diff --git a/docs/decisions/hf-shared-blobs.md b/docs/decisions/hf-shared-blobs.md index 8181312..a0d919c 100644 --- a/docs/decisions/hf-shared-blobs.md +++ b/docs/decisions/hf-shared-blobs.md @@ -4,13 +4,6 @@ Shared blobs are sized and deleted by their `.refs` manifests with huggingface_hub's rules (`utils/_shared_blobs.py`): a reference counts only while its symlink still points at the blob, and a blob whose manifest is unreadable or whose `.lock` is held is never deleted. -## Verification - -```bash -go test ./internal/scanner/ -run 'TestLLMScanner_HF' -v -go test ./internal/cleaner/ -run 'Release' -v -``` - ## Rationale - Model directories hold only symlinks, so without the store GB of weights went unreported and deleting a model freed nothing. diff --git a/docs/decisions/one-filesystem.md b/docs/decisions/one-filesystem.md index 5d61f35..45b22ef 100644 --- a/docs/decisions/one-filesystem.md +++ b/docs/decisions/one-filesystem.md @@ -4,13 +4,6 @@ Finding, sizing and the pre-delete check walk through `fstree`, which stays on the root's filesystem (like `du -x`). A directory on another device, of unknown device, or unreadable is not entered and is returned as skipped. Path removal (including dry-run) is refused when `fstree` skipped any directory inside the item. To scan a mount, pass it as `--path`. -## Verification - -```bash -go test ./internal/fstree/ -run 'OtherFilesystem|WithoutDevice|CheckOneFilesystem' -v -go test ./internal/cleaner/ -run 'TestRefusesUncheckedTree' -v -``` - ## Rationale - Mounts under the root are not this machine's reclaimable disk. Example: Xcode CoreDevice's `~/Library/Developer/CoreDevice/DeviceFS`, measured at ~4 s per directory read. diff --git a/docs/decisions/prune-non-project-trees.md b/docs/decisions/prune-non-project-trees.md index ff99fca..d473924 100644 --- a/docs/decisions/prune-non-project-trees.md +++ b/docs/decisions/prune-non-project-trees.md @@ -11,12 +11,6 @@ The walk engine skips these trees whole — no artifact matching, no project con When adding an ecosystem or rule, scan that tool's real SDK/toolchain checkout and verify what gets flagged. A scanner's own false positive is fixed in that scanner's PR. -## Verification - -```bash -go test ./internal/scanner/ -run 'TestWalkExcludesInstalledPackageTrees|TestFlutterWalk' -v -``` - ## Rationale - Each package in an installed-package tree, including the runtime an app ships inside its bundle, carries its own marker (`package.json`, `setup.py`, `go.mod`). Without pruning it roots a project, and its shipped `dist/`, `__pycache__` or `vendor/` matches as `safe` output — deleting the `dist/` of the npm bundled in a GitHub Actions runner breaks the runner. A project's own `node_modules` matches as an artifact before the name check, so it is still reported. diff --git a/docs/decisions/release-please.md b/docs/decisions/release-please.md index 4955f76..2e00858 100644 --- a/docs/decisions/release-please.md +++ b/docs/decisions/release-please.md @@ -6,18 +6,9 @@ release-please keeps a release PR open on `main`. Merging it bumps the version, - Version: Conventional Commits, `feat` bumps minor, `fix`/`perf` bump patch; below 1.0 a breaking change bumps minor (`bump-minor-pre-major`). - Sections: `feat` → Added, `fix` → Fixed, `perf`/`revert` → Changed; other types are hidden. +- The repository squash-merges only, with the PR title as the commit title, so the PR title is what release-please reads. - Token: the default `GITHUB_TOKEN`. Its tag does not trigger other workflows, so GoReleaser runs as a job of the release-please workflow. CI on the release PR waits for a manual approval because `GITHUB_TOKEN` opened it. -## Verification - -```bash -goreleaser check -``` - -CI runs the same check on every PR. The first release PR shows the generated version and section; its merge run shows the Release with assets. - -The repository squash-merges only, with the PR title as the commit title, so the PR title is what release-please reads. - ## Rationale - Releases stalled for five months when version, changelog cut and tag were manual steps; an always-open release PR makes a release one merge. diff --git a/docs/decisions/symlink-no-follow.md b/docs/decisions/symlink-no-follow.md index 7f13902..7ae21c6 100644 --- a/docs/decisions/symlink-no-follow.md +++ b/docs/decisions/symlink-no-follow.md @@ -4,14 +4,6 @@ `fstree` never descends into a symlink and never matches one as an artifact, even when it is named like one (a symlinked `node_modules`, as pnpm and some monorepos produce). Only the scan root is read through, and only for `--path`. Deleting a symlink removes only the link; the cleaner's cross-filesystem trash copy recreates symlinks as links. -## Verification - -```bash -go test ./internal/fstree/ -run 'Symlink' -v -go test ./internal/scanner/ -run 'Symlink' -v -go test ./internal/cleaner/ -run 'TestCopyTree_PreservesSymlinkAsLink' -v -``` - ## Rationale - A symlink's target is real content that lives on disk elsewhere, so following it would double-count that space and inflate the reported reclaimable total.