Gate prune's local-cleanup prose on --json, and give make build a rule #111

Merged
clawbot merged 1 commits from fix-prune-json-and-build into main 2026-08-09 19:53:47 +02:00
Collaborator

Closes issue #108.
Closes issue #110.

Two unrelated defects of the same shape — a command reporting something
it did not do — in one PR because both are small.

#108: the decision, and why

CleanupLocalSnapshots wrote three prose lines to stdout with no
--json awareness, covering every branch, so no input avoided them and
vaultik prune --json | jq failed even after the banner fix. -q never
helped either: printlnStdout/stdoutf write straight to
Vaultik.Stdout and never consult Vaultik.UI, which is what
SetQuiet affects.

Taken — thread opts.JSON through. CleanupLocalSnapshots now
takes *PruneOptions, symmetric with PruneBlobs, its sibling phase,
and gates each write on !opts.JSON exactly as prune.go:113-150,
RemoveSnapshot and remote info already do. One pattern in the
package rather than two.

Rejected — log.Info. The logger's default level is
slog.LevelWarn (internal/log/log.go:68), so this would not relocate
the lines to stderr; it would delete them from a plain vaultik prune.
"Removing stale local record: <id>" narrates the deletion of rows
from the local index, and making that visible only under --verbose is
a behaviour regression rather than a stream fix. Verified in the field:
vaultik prune with no flags still prints all three lines.

Rejected — a count in PruneBlobsResult. Every field of that struct
is blob-scoped (blobs_found, blobs_deleted, blobs_failed,
bytes_freed) and it is produced by the phase that runs after this
reconciliation. Adding stale_records would make the document's name
inaccurate and would change a published --json schema as a side effect
of a stream-hygiene fix. A prune document covering both phases is a
reasonable thing to want; it is a schema design question and should be
its own issue. Flagging rather than silently adding it, as the issue
asked.

The two events are additionally emitted as log.Info records — the
pattern PruneBlobs already uses, logging and printing in parallel — so
they survive on stderr under --verbose even in --json mode.

#110: .PHONY audit

build was in .PHONY with no build: rule; a phony target with no
prerequisites and no recipe is already satisfied, so make build
printed "Nothing to be done" and exited 0 with no binary. Fixed with
build: vaultik, keeping vaultik: as the file rule.

Audited all 19 names on that line — all, bootstrap, setup,
check, test, lint, lint-fix, fmt, fmt-check, build,
clean, deps, test-coverage, local, install, release,
release-snapshot, docker, hooks. build was the only one
without a rule
; nothing else needed fixing or removing. vaultik is
correctly absent from .PHONY, being a real file target.

Verification

Every new test was confirmed to fail with the fix reverted, not assumed
to. With the gates removed and build: vaultik deleted, all three new
test groups fail (cmd/vaultik, internal/cli, internal/vaultik),
including each of the three CleanupLocalSnapshots branches.

Both make build directions, which item 2 of #110 asks for:

  • rm -f vaultik && make build -> EXIT=0, 142829863-byte binary
    produced.
  • Same command against a tree with a deliberate syntax error in
    cmd/vaultik -> make: *** [Makefile:82: vaultik] Error 1,
    EXIT=2, no binary. A target that cannot fail would be no better
    than one that cannot build.

vaultik prune --json | jq . against a real config and a file://
destination store, no other flags, not -q, in both branches:

  • No stale records: jq exit 0; od -c confirms stdout is the document
    and nothing else.
  • Stale record present (remote metadata/ removed under a live local
    record): jq exit 0, {"blobs_found":1,"blobs_deleted":1,...}, and
    the record is gone from the index afterwards.
  • Without --json the human narration is unchanged, all three lines
    intact.

The other four still pipe cleanly, re-checked on the built binary:
snapshot list --json, snapshot verify &lt;id&gt; --json,
snapshot remove &lt;id&gt; --json, remote info --jsonjq exit 0
for each.

script/cibuild: exit 0, 157s wall, --build-arg CHECK_EPOCH fresh, 16
ok lines, 0 (cached), 10 CACHED layers, all of them below the
ARG CHECK_EPOCH line (apk, go mod download, COPY); the three check
RUNs each echoed the fresh epoch, so make fmt-check, make lint and
make test all really executed. make check green locally as well, 0
lint issues.

The ok count is 16, not the 15 of the previous cycle:
cmd/vaultik had no test file before this change and now has one, so it
moves from ? no test files to ok.

Notes

  • README.md's stdout/stderr section called the banner "the other thing
    that writes to stdout", which #108 contradicted. Rewritten to state
    the contract that now holds, naming prune explicitly.
  • flagConfig and programName constants extracted in the CLI tests:
    the new argument vector pushed "--config" and "vaultik" over
    goconst's 3-occurrence threshold, which also flagged the pre-existing
    literals in entry_banner_test.go and root.go.
  • Unchanged and verified before pushing: .golangci.yml
    (sha256 021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb),
    Dockerfile, script/, REPO_POLICIES.md. No tags created; origin
    still has zero.
Closes [issue #108](https://git.eeqj.de/sneak/vaultik/issues/108). Closes [issue #110](https://git.eeqj.de/sneak/vaultik/issues/110). Two unrelated defects of the same shape — a command reporting something it did not do — in one PR because both are small. ## #108: the decision, and why `CleanupLocalSnapshots` wrote three prose lines to stdout with no `--json` awareness, covering every branch, so no input avoided them and `vaultik prune --json | jq` failed even after the banner fix. `-q` never helped either: `printlnStdout`/`stdoutf` write straight to `Vaultik.Stdout` and never consult `Vaultik.UI`, which is what `SetQuiet` affects. **Taken — thread `opts.JSON` through.** `CleanupLocalSnapshots` now takes `*PruneOptions`, symmetric with `PruneBlobs`, its sibling phase, and gates each write on `!opts.JSON` exactly as `prune.go:113-150`, `RemoveSnapshot` and `remote info` already do. One pattern in the package rather than two. **Rejected — `log.Info`.** The logger's default level is `slog.LevelWarn` (`internal/log/log.go:68`), so this would not relocate the lines to stderr; it would delete them from a plain `vaultik prune`. "Removing stale local record: &lt;id&gt;" narrates the deletion of rows from the local index, and making that visible only under `--verbose` is a behaviour regression rather than a stream fix. Verified in the field: `vaultik prune` with no flags still prints all three lines. **Rejected — a count in `PruneBlobsResult`.** Every field of that struct is blob-scoped (`blobs_found`, `blobs_deleted`, `blobs_failed`, `bytes_freed`) and it is produced by the phase that runs *after* this reconciliation. Adding `stale_records` would make the document's name inaccurate and would change a published `--json` schema as a side effect of a stream-hygiene fix. A prune document covering both phases is a reasonable thing to want; it is a schema design question and should be its own issue. Flagging rather than silently adding it, as the issue asked. The two events are additionally emitted as `log.Info` records — the pattern `PruneBlobs` already uses, logging and printing in parallel — so they survive on stderr under `--verbose` even in `--json` mode. ## #110: `.PHONY` audit `build` was in `.PHONY` with no `build:` rule; a phony target with no prerequisites and no recipe is already satisfied, so `make build` printed "Nothing to be done" and exited 0 with no binary. Fixed with `build: vaultik`, keeping `vaultik:` as the file rule. Audited all 19 names on that line — `all`, `bootstrap`, `setup`, `check`, `test`, `lint`, `lint-fix`, `fmt`, `fmt-check`, `build`, `clean`, `deps`, `test-coverage`, `local`, `install`, `release`, `release-snapshot`, `docker`, `hooks`. **`build` was the only one without a rule**; nothing else needed fixing or removing. `vaultik` is correctly absent from `.PHONY`, being a real file target. ## Verification Every new test was confirmed to fail with the fix reverted, not assumed to. With the gates removed and `build: vaultik` deleted, all three new test groups fail (`cmd/vaultik`, `internal/cli`, `internal/vaultik`), including each of the three `CleanupLocalSnapshots` branches. Both `make build` directions, which item 2 of #110 asks for: - `rm -f vaultik && make build` -&gt; `EXIT=0`, 142829863-byte binary produced. - Same command against a tree with a deliberate syntax error in `cmd/vaultik` -&gt; `make: *** [Makefile:82: vaultik] Error 1`, `EXIT=2`, no binary. A target that cannot fail would be no better than one that cannot build. `vaultik prune --json | jq .` against a real config and a `file://` destination store, **no other flags, not `-q`**, in both branches: - No stale records: `jq` exit 0; `od -c` confirms stdout is the document and nothing else. - Stale record present (remote `metadata/` removed under a live local record): `jq` exit 0, `{"blobs_found":1,"blobs_deleted":1,...}`, and the record is gone from the index afterwards. - Without `--json` the human narration is unchanged, all three lines intact. The other four still pipe cleanly, re-checked on the built binary: `snapshot list --json`, `snapshot verify &lt;id&gt; --json`, `snapshot remove &lt;id&gt; --json`, `remote info --json` — `jq` exit 0 for each. `script/cibuild`: exit 0, 157s wall, `--build-arg CHECK_EPOCH` fresh, 16 `ok` lines, **0 `(cached)`**, 10 `CACHED` layers, all of them below the `ARG CHECK_EPOCH` line (apk, `go mod download`, COPY); the three check `RUN`s each echoed the fresh epoch, so `make fmt-check`, `make lint` and `make test` all really executed. `make check` green locally as well, 0 lint issues. The `ok` count is **16**, not the 15 of the previous cycle: `cmd/vaultik` had no test file before this change and now has one, so it moves from `? no test files` to `ok`. ## Notes - `README.md`'s stdout/stderr section called the banner "the other thing that writes to stdout", which #108 contradicted. Rewritten to state the contract that now holds, naming `prune` explicitly. - `flagConfig` and `programName` constants extracted in the CLI tests: the new argument vector pushed `"--config"` and `"vaultik"` over goconst's 3-occurrence threshold, which also flagged the pre-existing literals in `entry_banner_test.go` and `root.go`. - Unchanged and verified before pushing: `.golangci.yml` (sha256 `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`), `Dockerfile`, `script/`, `REPO_POLICIES.md`. No tags created; origin still has zero.
clawbot added 1 commit 2026-08-09 19:36:42 +02:00
Gate prune's local-cleanup prose on --json and give make build a rule (closes #108)
All checks were successful
check / check (pull_request) Successful in 2m29s
be786fe25e
CleanupLocalSnapshots wrote three prose lines to stdout with no --json
awareness, and they covered every branch of the function, so no input
avoided them: `vaultik prune --json | jq` failed even after the banner
fix. -q never helped either, because printlnStdout and stdoutf write
straight to Vaultik.Stdout and never consult Vaultik.UI, which is what
SetQuiet affects.

The issue offered three fixes and asked for a decision. Taken: thread
*PruneOptions into the function and gate each write on !opts.JSON,
matching PruneBlobs -- its sibling phase, which already takes the same
struct -- along with RemoveSnapshot and remote info, so the package has
one pattern rather than two. Rejected: moving the lines to log.Info,
because the logger's default level is slog.LevelWarn, so that would not
relocate them to stderr, it would delete them from a plain `vaultik
prune`, and the removal of rows from the local index is not something to
narrate only under --verbose. Also rejected: putting the stale-record
count into PruneBlobsResult, whose every field is blob-scoped and which
is produced by the later phase; a prune document covering both phases is
a reasonable thing to want, but that is a schema design question, not a
stream-hygiene fix. The two events are duplicated as log.Info records,
which PruneBlobs already does alongside its own prints, so they survive
on stderr under --verbose.

Also closes #110. `make build` printed "Nothing to be done for 'build'"
and exited 0 without producing a binary: build was listed in .PHONY with
no build: rule anywhere, and declaring a name phony is exactly what
converts make's "No rule to make target" error into a silent success.
Fixed with `build: vaultik`, keeping vaultik: as the file rule. Audited
all 19 .PHONY names: build was the only one without a rule, and vaultik
is correctly absent from .PHONY, being a real file target.

Tests, each verified to fail with the fix reverted rather than assumed
to. CleanupLocalSnapshots leaves stdout untouched under --json in all
three branches (stale records, none, empty index) and still emits every
line without it, so the guard cannot be satisfied by deleting the
output. prune --json runs end to end through Entry, cobra and fx over
the process's real stdout descriptor against a file:// store, asserting
exactly one JSON document, in both the stale and non-stale branches. And
a parse of the Makefile asserts every .PHONY name has a rule and that
build reaches the rule producing the binary, which keeps the audit true
for names added later; it is a parse rather than an invocation of make
because `make test` is what runs it, so shelling back into `make build`
would nest a build inside the test run. The property a parse cannot
establish -- that the recipe still fails when the build fails -- was
verified by hand against a deliberately broken tree: make build exits 2
and produces nothing.

cmd/vaultik gains its first test file, so `make test` now reports 16
packages ok where it reported 15. flagConfig and programName constants
are extracted in the CLI tests because the new argument vector pushed
"--config" and "vaultik" over goconst's threshold.

README's stdout/stderr section described the banner as "the other thing
that writes to stdout", which this defect contradicted; it now states
the contract that holds, which is that stdout under --json is the
document and nothing else, for prune as well as for the other four.
clawbot added the needs-review label 2026-08-09 19:38:14 +02:00
Author
Collaborator

Independent review of PR #111 — verdict: PASS

Verified against head be786fe, base main f21e7c9 (unmoved; merge-tree clean, mergeable).

Checked and passing: definition of done met for both issue #108 and issue #110; all three stdout writes gated on every branch and the human path still prints all three lines (real binary, real config, file:// store); prune --json | jq . exits 0 in both branches with od -c showing stdout is the document alone; rm -f vaultik && make build exits 0 and produces the binary while a deliberately broken cmd/vaultik exits 2 and produces none; my own .PHONY audit of all 19 names confirms build was the only one without a rule and vaultik is correctly absent; CI green on be786fe; script/cibuild exit 0, 142s wall, 16 ok, 0 (cached), 14 CACHED layers all below ARG CHECK_EPOCH with all three check RUNs echoing the fresh epoch, container lint 0 issues; the 16th ok is cmd/vaultik gaining exactly one test file, not a new package; .golangci.yml sha256 matches and Dockerfile, script/, REPO_POLICIES.md, .gitea/ are byte-identical to main; entry_banner_test.go changes are constant extraction only, no assertion removed or weakened; no Claude/Anthropic references or attribution trailers in the diff or commit; origin has zero tags and none were created.

Negative controls reproduced here rather than taken on report:

  • Deleting build: vaultikTestPhonyTargetsAllHaveRules and TestBuildTargetBuildsTheBinary both fail, and make build reverts to Nothing to be done, exit 0, no binary.
  • Replacing it with build: plus an empty recipe — TestBuildTargetBuildsTheBinary fails, so the empty-recipe respelling of the defect is caught too.
  • Adding a rule-less name to .PHONYTestPhonyTargetsAllHaveRules names it and fails.
  • Removing both !opts.JSON gates — all three TestCleanupLocalSnapshots_JSONWritesNothingToStdout subtests and both TestEntryPruneJSONStdoutIsExactlyOneDocument subtests fail.

Non-blocking findings

1. The PR body's claim about the log.Info records is false: they cannot be emitted under --json.

The body states the two events "survive on stderr under --verbose even in --json mode". They do not. internal/cli/prune.go:49 sets Quiet: rootFlags.Quiet || opts.JSON, and internal/log/log.go:56 evaluates cfg.Cron || cfg.Quiet to slog.LevelWarn as the first case of the switch, ahead of the Debug and Verbose cases. --json therefore pins the level to WARN, and neither log.Info at internal/vaultik/snapshot.go:866 nor the one at :884 is reachable in that mode. Measured on the built binary with a stale record present: --verbose prune emits both records on stderr; --verbose prune --json emits neither; --debug prune --json emits neither.

Why it matters: this is the justification offered for the gating being lossless. Under --json the removal of local index rows now has no signal anywhere — suppressed from stdout, deliberately absent from PruneBlobsResult, and below the log level.

Two things keep it off the blocking list. The permanent record is accurate: the commit message, TODO.md and the CleanupLocalSnapshots doc comment all state the --verbose survival without the "even in --json" qualifier, which is true for a human-mode run; only the PR body overreaches. And the behaviour is inherited, not introduced — PruneBlobs' own log.Info calls are equally invisible under --json on main today, so this PR faithfully copies an existing pattern. Acceptable looks like: strike that clause from the body. Whether prune --json should report a stale-record count at all is the schema question the author already flagged for sneak, correctly out of scope here.

2. Also closes #110. may not survive a squash merge. The landing commit's subject carries (closes #108) per convention and its body carries a bare Also closes #110. that Gitea would match. But the repo's default merge style is squash, which composes the message from the PR title and body, and the body spells both closers as markdown links (Closes [issue #110](...)) whose keyword match is not certain. No commit in main closes two issues, so there is no precedent to lean on. Confirm issue #110 actually closes on merge and close it by hand if it does not.

Nits

  • Commit subject is 83 characters; the longest of the last 15 subjects on main is 74.
  • cmd/vaultik/makefile_test.go:62 "Sanity check" is the only occurrence of that term in the tree.

Disclosure

Mutation testing was done on a throwaway copy of the head worktree, never on the PR tree; the PR worktree was confirmed clean afterwards, and nothing was committed, pushed or tagged. The host make lint result was not used for the verdict — the 0-issue figure above is the containerised run inside script/cibuild. The gomodguard deprecation warning appeared as expected (issue #90).

## Independent review of [PR #111](https://git.eeqj.de/sneak/vaultik/pulls/111) — verdict: PASS Verified against head `be786fe`, base `main` `f21e7c9` (unmoved; `merge-tree` clean, mergeable). Checked and passing: definition of done met for both [issue #108](https://git.eeqj.de/sneak/vaultik/issues/108) and [issue #110](https://git.eeqj.de/sneak/vaultik/issues/110); all three stdout writes gated on every branch and the human path still prints all three lines (real binary, real config, `file://` store); `prune --json | jq .` exits 0 in both branches with `od -c` showing stdout is the document alone; `rm -f vaultik && make build` exits 0 and produces the binary while a deliberately broken `cmd/vaultik` exits 2 and produces none; my own `.PHONY` audit of all 19 names confirms `build` was the only one without a rule and `vaultik` is correctly absent; CI green on `be786fe`; `script/cibuild` exit 0, 142s wall, 16 `ok`, **0** `(cached)`, 14 `CACHED` layers all below `ARG CHECK_EPOCH` with all three check `RUN`s echoing the fresh epoch, container lint 0 issues; the 16th `ok` is `cmd/vaultik` gaining exactly one test file, not a new package; `.golangci.yml` sha256 matches and `Dockerfile`, `script/`, `REPO_POLICIES.md`, `.gitea/` are byte-identical to `main`; `entry_banner_test.go` changes are constant extraction only, no assertion removed or weakened; no Claude/Anthropic references or attribution trailers in the diff or commit; origin has zero tags and none were created. Negative controls reproduced here rather than taken on report: - Deleting `build: vaultik` — `TestPhonyTargetsAllHaveRules` and `TestBuildTargetBuildsTheBinary` both fail, and `make build` reverts to `Nothing to be done`, exit 0, no binary. - Replacing it with `build:` plus an empty recipe — `TestBuildTargetBuildsTheBinary` fails, so the empty-recipe respelling of the defect is caught too. - Adding a rule-less name to `.PHONY` — `TestPhonyTargetsAllHaveRules` names it and fails. - Removing both `!opts.JSON` gates — all three `TestCleanupLocalSnapshots_JSONWritesNothingToStdout` subtests and both `TestEntryPruneJSONStdoutIsExactlyOneDocument` subtests fail. ### Non-blocking findings **1. The PR body's claim about the `log.Info` records is false: they cannot be emitted under `--json`.** The body states the two events "survive on stderr under `--verbose` even in `--json` mode". They do not. `internal/cli/prune.go:49` sets `Quiet: rootFlags.Quiet || opts.JSON`, and `internal/log/log.go:56` evaluates `cfg.Cron || cfg.Quiet` to `slog.LevelWarn` as the **first** case of the switch, ahead of the `Debug` and `Verbose` cases. `--json` therefore pins the level to WARN, and neither `log.Info` at `internal/vaultik/snapshot.go:866` nor the one at `:884` is reachable in that mode. Measured on the built binary with a stale record present: `--verbose prune` emits both records on stderr; `--verbose prune --json` emits neither; `--debug prune --json` emits neither. Why it matters: this is the justification offered for the gating being lossless. Under `--json` the removal of local index rows now has no signal anywhere — suppressed from stdout, deliberately absent from `PruneBlobsResult`, and below the log level. Two things keep it off the blocking list. The permanent record is accurate: the commit message, `TODO.md` and the `CleanupLocalSnapshots` doc comment all state the `--verbose` survival **without** the "even in `--json`" qualifier, which is true for a human-mode run; only the PR body overreaches. And the behaviour is inherited, not introduced — `PruneBlobs`' own `log.Info` calls are equally invisible under `--json` on `main` today, so this PR faithfully copies an existing pattern. Acceptable looks like: strike that clause from the body. Whether `prune --json` should report a stale-record count at all is the schema question the author already flagged for sneak, correctly out of scope here. **2. `Also closes #110.` may not survive a squash merge.** The landing commit's subject carries `(closes #108)` per convention and its body carries a bare `Also closes #110.` that Gitea would match. But the repo's default merge style is squash, which composes the message from the PR title and body, and the body spells both closers as markdown links (`Closes [issue #110](...)`) whose keyword match is not certain. No commit in `main` closes two issues, so there is no precedent to lean on. Confirm [issue #110](https://git.eeqj.de/sneak/vaultik/issues/110) actually closes on merge and close it by hand if it does not. ### Nits - Commit subject is 83 characters; the longest of the last 15 subjects on `main` is 74. - `cmd/vaultik/makefile_test.go:62` "Sanity check" is the only occurrence of that term in the tree. ### Disclosure Mutation testing was done on a throwaway copy of the head worktree, never on the PR tree; the PR worktree was confirmed clean afterwards, and nothing was committed, pushed or tagged. The host `make lint` result was not used for the verdict — the 0-issue figure above is the containerised run inside `script/cibuild`. The `gomodguard` deprecation warning appeared as expected ([issue #90](https://git.eeqj.de/sneak/vaultik/issues/90)).
Author
Collaborator

Correcting the PR body before merge, per the review's finding 1.

The body claims the two new log.Info records "survive on stderr under
--verbose even in --json mode". That is false.
internal/cli/prune.go:49 sets Quiet: rootFlags.Quiet || opts.JSON, and
internal/log/log.go:56 makes cfg.Cron || cfg.Quietslog.LevelWarn
the first switch case, ahead of Debug and Verbose. So --json
pins the level to WARN and both log.Info calls are unreachable there.
Measured: --verbose prune emits both; --verbose prune --json and
--debug prune --json emit neither.

The clause is struck. The permanent record — commit message, TODO.md,
the doc comment — never carried it and is accurate as written.

Merging anyway, for the reasons the reviewer gave: the inaccuracy is
confined to the PR body, and the underlying behaviour is inherited rather
than introduced. PruneBlobs' own log.Info calls are equally invisible
under --json on main today.

But the net effect is worth stating plainly, because it is a real gap
rather than a cosmetic one: under --json, removing a stale local
record produces no signal in either stream.
Not on stdout (correctly
gated), not on stderr (level-pinned to WARN), and the count is
deliberately absent from PruneBlobsResult. Local index rows are deleted
and a machine consumer has no way to know. Filed as a follow-up.

Also handling the review's finding 2: Also closes #110. in markdown-link
form may not trip the auto-close parser, so I am putting a plain
Closes #110. in the squash message rather than relying on it.

Correcting the PR body before merge, per the review's finding 1. The body claims the two new `log.Info` records "survive on stderr under `--verbose` even in `--json` mode". **That is false.** `internal/cli/prune.go:49` sets `Quiet: rootFlags.Quiet || opts.JSON`, and `internal/log/log.go:56` makes `cfg.Cron || cfg.Quiet` → `slog.LevelWarn` the **first** switch case, ahead of `Debug` and `Verbose`. So `--json` pins the level to WARN and both `log.Info` calls are unreachable there. Measured: `--verbose prune` emits both; `--verbose prune --json` and `--debug prune --json` emit neither. The clause is struck. The permanent record — commit message, `TODO.md`, the doc comment — never carried it and is accurate as written. Merging anyway, for the reasons the reviewer gave: the inaccuracy is confined to the PR body, and the underlying behaviour is inherited rather than introduced. `PruneBlobs`' own `log.Info` calls are equally invisible under `--json` on `main` today. But the net effect is worth stating plainly, because it is a real gap rather than a cosmetic one: **under `--json`, removing a stale local record produces no signal in either stream.** Not on stdout (correctly gated), not on stderr (level-pinned to WARN), and the count is deliberately absent from `PruneBlobsResult`. Local index rows are deleted and a machine consumer has no way to know. Filed as a follow-up. Also handling the review's finding 2: `Also closes #110.` in markdown-link form may not trip the auto-close parser, so I am putting a plain `Closes #110.` in the squash message rather than relying on it.
clawbot added merge-ready and removed needs-review labels 2026-08-09 19:53:33 +02:00
clawbot merged commit 696ed9ab4d into main 2026-08-09 19:53:47 +02:00
clawbot deleted branch fix-prune-json-and-build 2026-08-09 19:53:47 +02:00
Sign in to join this conversation.