Under --json, prune deletes local index rows with no signal in either stream #112

Open
opened 2026-08-09 19:54:26 +02:00 by clawbot · 0 comments
Collaborator

Split out of PR #111, which
gated CleanupLocalSnapshots' stdout writes on --json. The gating is
correct; this is what it exposes.

Under --json, removing a stale local snapshot record produces no
signal anywhere
:

  • stdout — correctly gated by #108, so nothing.
  • stderrinternal/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 the log.Info records are unreachable. Measured:
    --verbose prune emits them; --verbose prune --json and
    --debug prune --json emit neither.
  • the document — the stale-record count is deliberately not in
    PruneBlobsResult, since every field there is blob-scoped.

So a machine consumer sees blobs_found/blobs_deleted/bytes_freed
and has no way to learn that local index rows were also deleted.

Inherited, not introduced. PruneBlobs' own log.Info calls are
equally invisible under --json on main today. #111 made the gap
visible by closing the stdout leak that was accidentally covering it.

Why it is worth deciding

vaultik prune is a destructive operation and --json is the mode a
scheduler or wrapper runs it in. "What did you delete?" currently has no
machine-readable answer for half the work the command does. That is a
weaker contract than the human path, which narrates every removal.

There is also a design question underneath: should --json imply
Quiet?
Now that #82 put diagnostics on stderr and #106 removed the
banner from stdout, the original reason for coupling them — keeping
stdout clean — no longer applies. --json pinning the log level to WARN
is now suppressing stderr output that could not corrupt anything.

Options

  1. Decouple --json from Quiet. --json gates stdout; --verbose
    continues to control stderr independently. Restores the audit trail
    under --verbose --json and is the smallest conceptual change.
  2. Put the count in the document as a two-phase prune result
    (stale_records_removed alongside the blob fields). Machine-readable,
    but changes a published schema and needs the shape agreed.
  3. Accept it and document that --json reports blob-phase results
    only.

Recommendation: option 1, and consider 2 separately. 1 is a
correctness fix to a coupling that outlived its reason; 2 is a schema
decision that deserves its own discussion.

Definition of done

  1. A decision recorded here with reasoning.
  2. If option 1: --verbose prune --json emits the local-cleanup records
    on stderr while stdout stays exactly one document. Test both halves.
  3. Whatever is chosen, prune --json | jq must keep working — that is
    #108 and must not regress.
  4. Check whether any other command couples --json to Quiet for the
    same outdated reason, and treat them consistently.
  5. script/cibuild exits 0.
Split out of [PR #111](https://git.eeqj.de/sneak/vaultik/pulls/111), which gated `CleanupLocalSnapshots`' stdout writes on `--json`. The gating is correct; this is what it exposes. Under `--json`, removing a stale local snapshot record produces **no signal anywhere**: - **stdout** — correctly gated by #108, so nothing. - **stderr** — `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 the `log.Info` records are unreachable. Measured: `--verbose prune` emits them; `--verbose prune --json` and `--debug prune --json` emit neither. - **the document** — the stale-record count is deliberately not in `PruneBlobsResult`, since every field there is blob-scoped. So a machine consumer sees `blobs_found`/`blobs_deleted`/`bytes_freed` and has no way to learn that local index rows were also deleted. **Inherited, not introduced.** `PruneBlobs`' own `log.Info` calls are equally invisible under `--json` on `main` today. #111 made the gap visible by closing the stdout leak that was accidentally covering it. ## Why it is worth deciding `vaultik prune` is a destructive operation and `--json` is the mode a scheduler or wrapper runs it in. "What did you delete?" currently has no machine-readable answer for half the work the command does. That is a weaker contract than the human path, which narrates every removal. There is also a design question underneath: **should `--json` imply `Quiet`?** Now that #82 put diagnostics on stderr and #106 removed the banner from stdout, the original reason for coupling them — keeping stdout clean — no longer applies. `--json` pinning the log level to WARN is now suppressing stderr output that could not corrupt anything. ## Options 1. **Decouple `--json` from `Quiet`.** `--json` gates stdout; `--verbose` continues to control stderr independently. Restores the audit trail under `--verbose --json` and is the smallest conceptual change. 2. **Put the count in the document** as a two-phase prune result (`stale_records_removed` alongside the blob fields). Machine-readable, but changes a published schema and needs the shape agreed. 3. **Accept it and document** that `--json` reports blob-phase results only. Recommendation: **option 1**, and consider 2 separately. 1 is a correctness fix to a coupling that outlived its reason; 2 is a schema decision that deserves its own discussion. ## Definition of done 1. A decision recorded here with reasoning. 2. If option 1: `--verbose prune --json` emits the local-cleanup records on stderr while stdout stays exactly one document. Test both halves. 3. Whatever is chosen, `prune --json | jq` must keep working — that is #108 and must not regress. 4. Check whether any other command couples `--json` to `Quiet` for the same outdated reason, and treat them consistently. 5. `script/cibuild` exits 0.
clawbot added this to the 1.0.0 milestone 2026-08-09 19:54:26 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/vaultik#112