Repository navigation
Description
Task
| slice | size | difficulty | model | who | estimated lines |
|---|---|---|---|---|---|
| Reclaim on purpose | M | needs care | strongest | an agent | 480 (230 code, 250 tests) |
A prune preview lists every stopped or exited box the selectors match, with the disk each holds, and reaps none. Reading a stopped or exited box's record returns the same disk figure.
Covers:
- BOX-021
- BOX-159
Layers:
- daemon:
- crates/boxes/src/store.rs:
BoxDir::disk_bytesmeasures the box's directory, which is what a reap deletes: the retained filesystem (tree,home,cache,patches,hooks; BOX-017),output.log(BOX-155),events.jsonl(BOX-045),execs/and the record and spec files. It sums allocated bytes (st_blocks * 512), follows no symlink, stays on the directory's own device, and counts a hard-linked inode once - crates/minimald/src/box_manager.rs: the matching in
prune_boxes_at(prune_matchesplus theolder_thancheck) moves into one candidate step that the prune and the new preview both use.preview_prunereturns the candidates with their disk and reaps none.show_boxadds the disk for astoppedorexitedbox. Both measure off the manager loop, after the record read - crates/minimald/src/rpc.rs: the
PreviewPrunehandler, and its name in the dispatch allow-list - crates/minimald/src/box_manager/tests.rs: tests
cargo nextest run -p boxes box_dir_disk_counts_what_a_reap_freescargo nextest run -p minimald prune_dry_run_lists_matches_with_diskcargo nextest run -p minimald prune_dry_run_reaps_nonecargo nextest run -p minimald prune_dry_run_matches_what_prune_reapscargo nextest run -p minimald show_reports_disk_a_reap_frees
- crates/boxes/src/store.rs:
- wire:
- crates/minimald-rpc/src/lib.rs: a new
PreviewPruneRPC that takes thePruneBoxesRequestselectors and answersmatched, one{ record: BoxListingEntry, disk_bytes: Option<u64> }per box in box id order.ShowBoxResponsegainsdisk_bytes: Option<u64>(serde(default, skip_serializing_if = "Option::is_none")) - crates/minimald-rpc/src/tests.rs: tests
cargo nextest run -p minimald-rpc preview_prune_and_show_disk_round_trip
- crates/minimald-rpc/src/lib.rs: a new
- docs:
- docs/specs/29-spec-box-local-first/29-spec-box-local-first.md: the BOX-021 and BOX-159 sub-bullets below, and one Design reasoning paragraph for the preview
The rest of #2834, split out after T2 (BCLI, #2890, PR #2961) and T22 (BCLI, #2907, PR #3008) shipped min box rm and min box prune. T8 (#2395, PR #2833) gave the daemon ReapBox and PruneBoxes. This task adds the daemon's dry run
8000
and the disk figure that BCLI-006 renders. BCLI T23 (#2915) then adds min box prune --dry-run and the min box show disk line over them. It is blocked by this task.
The dry run is a separate RPC, not a dry_run field on PruneBoxesRequest. The request has no deny_unknown_fields, so a daemon older than this task drops the field and reaps every match. MINIMAL_ALLOW_VERSION_SKEW turns the client's version gate (prune_hosts is gated) into a warning, so the gate cannot keep a dry run off an old daemon. The dispatch in crates/minimald/src/rpc.rs answers an RPC name it does not know with channel_failure, so an old daemon refuses PreviewPrune and reaps nothing. PruneBoxesResponse keeps deny_unknown_fields and gains no field.
disk_bytes is None for a box in any state but stopped or exited. It is also None when the walk fails (a file vanishes, a permission error). The daemon log names the box and the error. The figure is never 0 in place of an unknown. The walk can cover a large tree, so it never runs inside the manager's message loop. delete_box's comment records how a stalled step in that loop parks min ls. Run it on a blocking task after the Records/Listing reply. Today no box has a Box Volume (box_actor.rs notes BVOL-013's hold check has none to find). So the exclusion holds because the walk stays inside the box's directory and on its device. The test pins it with a bind mount or a second device under tree, where the harness allows one.
prune_dry_run_matches_what_prune_reaps runs the preview and then the prune with the same selectors over a mix of running, stopped and exited boxes with and without a parent and an exited event. It checks that the preview's ids are the prune's reaped ids. prune_dry_run_reaps_none checks that every matched record, its events.jsonl and its tree remain after the preview, and that the preview appends no event.
This task prints nothing a person reads. The daemon adds only log records and wire fields. The text min box show and min box prune --dry-run print is BCLI T23's ("Disk: " and "Total: ", pinned by show_and_prune_dry_run_report_disk).
Proposed spec text (a proposal for the maintainer to accept or correct, drafted with the foundry spec-ears skill; the existing sentences of BOX-021 and BOX-159 stay as they are):
- **BOX-021** WHEN boxes are pruned, optionally narrowed by the `older-than <d>` and `parent <box>` selectors, THE SYSTEM SHALL reap every box in the `stopped` or `exited` state that matches all the given selectors, never a box in any other state, and print what it reaped.
tier: T0
verify: cargo nextest run -p minimald prune_selectors_reap_and_print
- WHERE a prune is requested as a `dry-run` THE SYSTEM SHALL return every box the given selectors match, each with the disk it holds as BOX-159 returns it.
tier: T0
verify: cargo nextest run -p minimald prune_dry_run_lists_matches_with_disk
- WHERE a prune is requested as a `dry-run` THE SYSTEM SHALL reap no box and leave each matched record, its events and its filesystem in place.
tier: T0
verify: cargo nextest run -p minimald prune_dry_run_reaps_none
- **BOX-159** WHEN one box record is read THE SYSTEM SHALL return its `box_id`, name, `box_type`, `parent`, project root, state with the `reason`, `exit_code` and `signal` BOX-011 defines, its identity as BOX-140 reports it, and the exec id of each live exec in it (BOX-149).
tier: T0
verify: cargo nextest run -p minimald show_returns_record_state_identity_and_live_execs
- WHEN the record of a `stopped` or `exited` box is read THE SYSTEM SHALL also return the disk the box holds: the bytes a reap of the box frees (BOX-019), counting its retained filesystem (BOX-017), its log (BOX-155) and its events (BOX-045), and not counting any Box Volume, which a reap leaves in place (BVOL-008).
tier: T0
verify: cargo nextest run -p minimald show_reports_disk_a_reap_frees
| Source (#2834) | Pattern | Requirement |
|---|---|---|
| "lists the boxes the selectors match and the disk each holds" | optional-feature (exists only when a dry run is asked for) | BOX-021, first sub-bullet |
| "and reaps none" | optional-feature | BOX-021, second sub-bullet (split: a separate observable and test) |
"min box show <box> reports the disk that a stopped or exited box holds ... counts only what a reap frees ... excludes Box Volumes" |
event-driven (a record read) | BOX-159 sub-bullet |
Waits on:
Plan block
### T63 — Preview a prune with the disk each box holds, and report a stopped box's disk
slice: S1
kind: task
covers: BOX-021, BOX-159
size: M
est: 230 code, 250 tests
executor: agent
difficulty: needs care
model: strongest
diagnostics: daemon log names each box whose disk it could not measure, with the error; the figure is then absent, never 0
observability: box.prune_preview span records the selectors, matched and unmeasured counts; box.show span records whether a disk figure was returned
layers:
- daemon:
- crates/boxes/src/store.rs: BoxDir::disk_bytes, the allocated bytes a reap of the box directory frees
- crates/minimald/src/box_manager.rs: one candidate step for prune and preview, preview_prune, show_box disk, measured off the manager loop
- crates/minimald/src/rpc.rs: PreviewPrune handler and dispatch name
- crates/minimald/src/box_manager/tests.rs: tests
test: cargo nextest run -p boxes box_dir_disk_counts_what_a_reap_frees
test: cargo nextest run -p minimald prune_dry_run_lists_matches_with_disk
test: cargo nextest run -p minimald prune_dry_run_reaps_none
test: cargo nextest run -p minimald prune_dry_run_matches_what_prune_reaps
test: cargo nextest run -p minimald show_reports_disk_a_reap_frees
- wire:
- crates/minimald-rpc/src/lib.rs: PreviewPrune RPC, ShowBoxResponse disk_bytes
- crates/minimald-rpc/src/tests.rs: tests
test: cargo nextest run -p minimald-rpc preview_prune_and_show_disk_round_trip
- docs:
- docs/specs/29-spec-box-local-first/29-spec-box-local-first.md: BOX-021 dry-run and BOX-159 disk sub-bullets, and the preview's Design reasoning paragraph
produces: none
consumes: none
proof: A prune preview lists every stopped or exited box the selectors match, with the disk each holds, and reaps none; reading a stopped or exited box's record returns the same disk figure.
depends on:
Activity
minimal-foundry commentedon Nov 5, 2026
Done. #3078 merged.
branch
agent/3076-preview-a-prune-with-the-disk-each-box-holds-and· epic #2236 · PR #3078Updated 2026-11-06T06:17:06.471Z.