8000 T63 — Preview a prune with the disk each box holds, and report a stopped box's disk · Issue #3076 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

T63 — Preview a prune with the disk each box holds, and report a stopped box's disk #3076

Closed

Description

@agent-137

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_bytes measures 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_matches plus the older_than check) moves into one candidate step that the prune and the new preview both use. preview_prune returns the candidates with their disk and reaps none. show_box adds the disk for a stopped or exited box. Both measure off the manager loop, after the record read
    • crates/minimald/src/rpc.rs: the PreviewPrune handler, 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_frees
    • cargo nextest run -p minimald prune_dry_run_lists_matches_with_disk
    • cargo nextest run -p minimald prune_dry_run_reaps_none
    • cargo nextest run -p minimald prune_dry_run_matches_what_prune_reaps
    • cargo nextest run -p minimald show_reports_disk_a_reap_frees
  • wire:
    • crates/minimald-rpc/src/lib.rs: a new PreviewPrune RPC that takes the PruneBoxesRequest selectors and answers matched, one { record: BoxListingEntry, disk_bytes: Option<u64> } per box in box id order. ShowBoxResponse gains disk_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
  • 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

  1. minimal-foundry commented on Nov 5, 2026

    @minimal-foundry
    Contributor

    Done. #3078 merged.

    branch agent/3076-preview-a-prune-with-the-disk-each-box-holds-and · epic #2236 · PR #3078

    Updated 2026-11-06T06:17:06.471Z.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0