Skip to content

Delete finished takes automatically: Recycle Bin or permanent, optionally only when space is needed (part of #644) - #716

Merged
ccoventry merged 27 commits into
devfrom
feat/auto-delete-takes-644
Oct 28, 2026
Merged

ccoventry merged 27 commits into
devfrom
feat/auto-delete-takes-644

Conversation

@ccoventry

@ccoventry ccoventry commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Release note: New: finished takes can be deleted automatically when their clips are done, to the Recycle Bin or permanently, or only when the capture drive runs low on space.

The automatic half of #644. It was stacked on #712, which has merged; the base is dev now and CI runs here.

Decisions

  • Each drive is checked on its own (the user's decision, 2026-10-25). A render job or a capture block is written whole to one drive, so "Only when space is needed" no longer adds free space up across drives. Two drives with 60% of a job free each used to count as enough: nothing was deleted, and the render then stopped for lack of room. Now each job or block needs its own size free on one drive, and the cleanup deletes finished takes on the drive that can be made to fit for the fewest bytes, or says that no one drive can (5fa2f81).
  • A take with a stream that was never rendered is never deleted (the user's decision). Anyone who doesn't want the HUD stream turns it off before capturing, so it's rare, and the frames are kept.

The setting

Configuration → Render Output → "After a clip is finished" has three choices:

  • Keep the take (the default).
  • Move the take to the Recycle Bin.
  • Delete the take permanently. Choosing it asks to confirm; Cancel puts the old choice back.

"Only when space is needed" only works with permanent deletion; its tooltip explains that the Recycle Bin frees no space until it's emptied. A line under the setting says what the current choice does. Both values are saved in settings.json and default to keep and off, including for older settings files.

What gets deleted, and when

  • Which takes can go (native/src/hlcr/take_cleanup.rs):
    • Every stream of the take (both halves of a HUD pair), as found in the take folder, has a last render attempt in dodstudio_take.json that finished, and that clip file is still on disk.
    • Failed, cancelled, interrupted, never-rendered, queued or rendering takes never go, and neither does a take whose clip file is gone.
    • Every delete runs Render tab: Delete Take sends a take folder to the Recycle Bin (part of #644) #712's own safety check. The new delete_take_permanently sits next to recycle_take, uses the same guard and keeps the history file.
  • After a clip is finished: takes whose jobs all finished are deleted when the render batch ends, after its summary and Finish clips automatically at the end of a capture batch (one video with audio per clip, no Render tab visit) #440's finish step have counted them. This also applies to render batches started by hand.
  • Only when space is needed:
    • Before a capture: each recording block needs its estimated size on one capture drive, keeping 15 GiB free on each drive (estimate_batch_capture_blocks; highlights that will merge into one recording count as one block).
    • Before a render batch or Finish clips automatically at the end of a capture batch (one video with audio per clip, no Render tab visit) #440's finish step: each job that starts together needs its estimate on one export drive, plus 1 GiB (first_wave_pieces).
    • Blocks and jobs are placed largest first on the first drive with room, the rule build_batch_queue uses for capture blocks.
    • Only takes on the drives the job writes to count. Oldest finished first, on the one drive that fits the job for the fewest bytes; takes on the other drives stay. Two drives are used only when several blocks need room on both.
    • If deleting every finished take still leaves a block or job with no drive, nothing is deleted and a warning toast says how much it needs on one drive and the most any one drive would have.
    • If a drive's free space can't be read, nothing is deleted.
  • Activity log: every deletion writes a [take-cleanup] line with the path, size, Recycle Bin or permanent, and why.

Test done

  • 5242365 (the two follow-ups from the 2026-10-28 live test), local:
    • The "Making room" warning (activity log and toast) now counts finished takes kept because their clip isn't where it was rendered. New tests: clip_moved cases, and plan_room reporting 1 moved take on a short drive; the toast's wording for 1 and 2.
    • "Capture Output Free" and the launch guard refresh on take_cleanup_done. New Playwright check in app-boot.spec.js (fails without the fix, passes with it).
    • cargo test -p native take_cleanup 25 passed, -p desktop-studio take_cleanup 5 passed; take_cleanup.test.js 14 passed; Playwright app-boot + take-cleanup 10 passed; clippy 1.98.1 on both crates and cargo fmt clean.
  • 2026-10-28 live test of "Only when space is needed" on a nearly full real drive: PASS after b360b7f and 0d0a7d6 (results comment below).
  • 5fa2f81 (per-drive check, merged with dev at 6fdb773), local:
    • cargo test -p native -p desktop-studio: native 793 passed, studio 239 passed. New tests: two drives with 60% of a job free each don't hold it; cleanup deletes on the one drive that fits for the fewest bytes, or reports it can't (90 at most on one drive, with 180 in all); a job that fits on one drive needs nothing while the other is full; several blocks placed across drives; blocks that need room on two drives; the capture block estimate merges highlights that merge.
    • Clippy 1.98.1 --workspace --all-targets -D warnings and cargo fmt --all --check are clean.
    • npm run test:unit: 867 passed. Playwright app-boot.spec.js and take-cleanup.spec.js: 9 passed.
  • Earlier (see comments): live test of the setting, Recycle Bin and permanent paths in the real Studio, 2026-10-14.
  • Several nearly full drives at once: unit tests only.

Worth knowing

To check by hand (Studio only)

  1. Settings:
    • The checkbox stays disabled until permanent is chosen.
    • Cancel on the confirm reverts.
    • The choice survives a restart.
  2. Recycle Bin: render a take. When the batch ends:
    • its rows go;
    • the folder is in the Recycle Bin;
    • dodstudio_take.json stays;
    • the activity log has the line.
  3. Permanent: the same, and the folder is really gone.
  4. A batch with one failed or cancelled job (or one half of a HUD pair failed): that take stays.
  5. Space needed: on a nearly full drive, start a capture.
    • The footer shows "Making room: …", the oldest finished takes on that drive go, then the capture runs.
    • Try Cancel during it.
    • With two export drives, neither with room for a job: the takes go from one drive only, and the render then starts on it.

Part of #644

🤖 Generated with Claude Code

…644)

The automatic half of #644. A new setting under Render Settings,
"After a clip is finished", keeps the take (default), moves it to the
Recycle Bin, or deletes it permanently. "Only when space is needed"
(permanent only, since the Recycle Bin frees nothing until emptied)
waits until a capture or render batch is short of room on its drives,
then deletes the oldest finished takes there until it fits. Turning
permanent deletion on asks first.

- native::hlcr::take_cleanup decides which takes may go: every stream's
  last render finished (#438) with the clip file still on disk, nothing
  queued or rendering. It plans room oldest first and deletes nothing
  when every finished take together still would not be enough.
- take_delete::delete_take_permanently removes the same file list as
  recycle_take, after the same check, keeping dodstudio_take.json.
- Hooks: the render scheduler's end (after render_batch_finished, so
  the finish step and the batch summary count the rows first), the
  capture start before build_batch_queue (estimate_batch_capture_bytes
  plus 15 GiB headroom per drive), and start_queued_render (the first
  wave's reservations plus the 1 GiB export margin).
- Every take that goes is logged ([take-cleanup]) with its size, where
  it went and why; progress shows in the Render tab's take-delete bar
  and the Capture footer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ccoventry and others added 2 commits October 11, 2026 23:02
…/auto-delete-takes-644

# Conflicts:
#	native/src/patch/builder/mod.rs
#	studio/src-tauri/src/capture_manager.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

Test pass 2026-10-13: stacked on #712, so no CI. Merged the updated feat/delete-takes-644 in (conflict in native/src/patch/builder/mod.rs: kept this PR's estimate_batch_capture_bytes and dev's STAY_BEHIND constant).
Local: fmt + workspace clippy clean; native 649, desktop-studio 122, npm unit 396 passed.
Live test still needed: Studio only, no game.

Base automatically changed from feat/delete-takes-644 to dev October 14, 2026 05:29
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

Updated with dev (#712 and #755 are merged; three small conflicts: docs line, an import, and start_queued_render's log line; the make-room step kept). Now targets dev with CI. Local: fmt + clippy 1.98.1 clean; native 661, desktop-studio 124, unit 415, Playwright 249.

Live test by Claude, 2026-10-14 night, real Studio over CDP, on three scratch copies of a 898 MB take (session_20991231_000000, history removed, deleted afterwards):

  • Setting (Configuration → Render Output, not "Render Settings" as the body said): "Only when space is needed" stays disabled for Keep and Recycle Bin and unlocks with permanent; choosing permanent asks "Delete takes permanently?"; Cancel put Recycle Bin back; the choice is in settings.json. Hint line follows the choice.
  • Permanent: one batch with take 90 rendered fully, take 91 both rows cancelled before Start, take 92 only its HUD row cancelled. After the batch: 90's take0000 was gone for good, its dodstudio_take.json kept, its rows removed, toast "Deleted a finished take for good (898 MB).", log [take-cleanup] Deleted ... for good (0.9 GB): its clip finished. 91 and 92 stayed on disk. Takes that scanned in as Finished from earlier renders (Render tab: tick the takes to render, bulk Cancel/Retry/Remove/Delete, Clear Queue (#70) #755) were not touched.
  • Recycle Bin: Retry on take 91 (it waited for Start, per Render tab: tick the takes to render, bulk Cancel/Retry/Remove/Delete, Clear Queue (#70) #755), Start: take0000 went to the Recycle Bin, json kept, toast and [take-cleanup] Moved ... to the Recycle Bin line.
  • Not tested: "Only when space is needed" (needs a nearly full drive). The setting is back on Keep.

…-644

# Conflicts:
#	studio/src/settings_sync.js
@ccoventry

Copy link
Copy Markdown
Owner Author

Merged dev in (874d69f); conflict in studio/src/settings_sync.js, resolved by saving both dev's setup_dismissed and this PR's take-cleanup settings; also added dev's new steam_id/recorded_this_demo fields to this PR's CaptureStreak test initializer, which no longer compiled. Local tests/clippy/fmt/npm unit pass, CI green; no DLL (no goldsrc-hooks changes)

ccoventry and others added 3 commits October 19, 2026 11:12
…-644

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dev renamed RenderOutcome::Interrupted to Started (an interrupted render is one that started and never ended).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
features.md: dev's rows with this branch's After a clip is finished; builder: this branch's estimate fns with dev's ds_capture_stay_behind comment; settings_sync: both spreads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ccoventry added a commit that referenced this pull request Oct 22, 2026
…use ds_capture_batch

hold_command sent the old dodstudio_batch name, which the hook no longer registers since #719, so hold and go did nothing; it now uses runtime_batch::BATCH_COMMAND (with a test). Commands.txt: dev's file with this branch's hold|go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
features.md: dev's Render Settings row (Presets, Clip Name Template) with this branch's After a clip is finished.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

Brought up to date with dev (unattended pass). Head 8e325f75.

🤖 Generated with Claude Code

ccoventry and others added 5 commits October 22, 2026 19:09
…-644

# Conflicts:
#	studio/src/settings_sync.js
…-queued take (part of #644)

- After a render batch, whether a take's clip is finished was asked of the
  Render tab's rows, so a take whose HUD row had been removed went with its
  HUD frames never rendered. The streams now come from the take folder.
- The cleanup took a take's rows out with Delete Take's check, which drops
  queued rows. A take queued again (Retry) after the cleanup looked was
  taken off the queue and deleted. It now stays while any row is queued or
  rendering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

Correctness review (unattended pass). Head 07225c69. I read the whole diff against dev. Two real bugs are fixed in that one commit. #885 still merges cleanly on top (checked with git merge-tree).

What I checked: which takes can go (every stream's last attempt Finished, clip file on disk), takes still queued, rendering or being written, the Recycle Bin vs permanent paths, the delete guard (relative paths, .., links, session/block/drive roots, folders outside Destinations, folders holding other takes), "only when space is needed" across several folders on one drive, cancelling mid-delete, defaults and older settings files (keep and off), the JS setting and confirm, progress events, blocking threads, and .display() in error text.

Bugs fixed (07225c6):

  1. A take could go with a stream that was never rendered. After a render batch, "is every stream finished?" was checked against the Render tab's rows, not against what's in the folder. If you removed a take's HUD row and rendered only the main row, the take was deleted, and its HUD frames with it, never rendered. The streams now come from the take folder itself (take_cleanup::streams_on_disk, the same scan the space-needed path already used). Test: a_takes_streams_are_read_from_its_folder.
  2. A take you had just queued again could be taken off the queue and deleted. The cleanup took a take's rows out with Delete Take's check, and that check lets queued rows go with the rest. If you clicked Retry on a finished take while the cleanup was scanning or sizing takes (a capture's make-room step can take a while), its queued row was silently dropped and the folder deleted. Now the cleanup uses remove_idle_take_rows: while any row of the take is queued or rendering, the take stays. Test: a_queued_or_rendering_row_keeps_its_take.

Open questions / notes (no change made):

  • Space counts every drive's free space together, but each render job, and each capture block, has to fit on a single drive. Say the export space is split over two drives with 60% of a job's size free on each: it counts as enough, nothing is deleted, and the render then stops with "every export folder has less than X GB free". Nothing is lost; it just doesn't make room. Worth fixing (needs a per-drive check), or fine as it is?
  • With fix 1, a take whose capture has a stream you never render (you always remove the HUD row) is never deleted automatically. That's the safe side; say if you'd rather a removed row count as "not wanted".
  • There's still a tiny window: a Render-tab rescan that re-adds a take's rows, followed by Start, in the moment between the cleanup removing those rows and deleting the folder. It needs a rescan at exactly that moment; not fixed.

Tests (local): cargo test -p native -p desktop-studio passes (native 792, studio 207). Clippy 1.98.1 --workspace --all-targets -D warnings and fmt are clean. JS unchanged. Nothing was run in the real app.

🤖 Generated with Claude Code

@ccoventry

Copy link
Copy Markdown
Owner Author

Decisions from the user (2026-10-25):

ccoventry and others added 2 commits October 25, 2026 01:20
Free space was added up across the export or capture drives, so two drives
with 60% of a job free each counted as enough, nothing was deleted, and the
render then stopped for lack of room. The check now places each piece (a
render job, a capture block) whole on one drive, and cleanup deletes the
oldest finished takes on the drive that fits the job for the fewest bytes,
or reports that no one drive can be made to fit.

- take_cleanup: RoomLedger keeps drives apart; choose_deletions picks the
  drive; SpaceNeed takes pieces instead of one total.
- estimate_batch_capture_blocks: one figure per block (highlights that merge
  count as one); estimate_batch_capture_bytes is now its sum.
- first_wave_pieces: one figure per render job of the first wave.
- Short log line and toast say "free on one drive".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
renderer.rs: keeps dev's try_reserve with this branch's public
EXPORT_SAFETY_MARGIN_BYTES as the margin. settings_manager tests: keep
both the #644 take defaults and dev's render_codec default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ccoventry and others added 3 commits October 27, 2026 16:30
…o longer stops the batch before finished takes can be deleted

The Capture tab's own free-space check ran before the backend's make_room,
so a capture short of room was refused even when deleting finished takes
would have made it fit. With the permanent choice and "Only when space is
needed" on, the shortfall is now an orange note and the backend decides:
it deletes finished takes first, or stops the batch with its own message.

Found in the live test of "Only when space is needed" on a nearly full F:.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…freed

make_room deleted a finished take, then build_batch_queue read the drive's
free space from get_available_bytes' 2 s cache, which still counted the
deleted take, and refused the batch ("Insufficient space across all mapped
drives"). forget_free_space() drops the cached answers and the disk list;
make_room calls it after deleting.

Found in the live test of "Only when space is needed" on a nearly full F:.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

Live test: "Only when space is needed" before a capture (2026-10-28, PRE/POST n/a, Studio only)

Setup: Destinations = one folder on F:, F:'s free space set with a placeholder file, one highlight (railroad2, row 1: Studio budgets 30.9 GB, the real utvideo take was 12.1 GB), "Delete the take permanently" + "Only when space is needed".

Run F: free Result
No finished takes, 45 GB 30 GB room < 30.9 refused, nothing deleted, warning toast (correct)
Finished take, 25 GB bug 1: the Capture tab's own space check stopped the batch before the cleanup ran
After b360b7f, clip moved by the user after rendering refused: the take's clip isn't where it was rendered, so it isn't a finished take (correct, safe)
Clip back, 25 GB 22.1 GB room even after deleting refused (my setup; correct)
40 GB 25 room, 37 after deleting bug 2: take deleted (12.1 GB), then build_batch_queue refused: it read free space from the 2 s cache, before the delete
After 0d0a7d6, 40 GB pass: "Making room", take deleted (12.1 GB), capture ran and finished; activity log [take-cleanup] Deleted ... take0000 for good (12.1 GB): space needed for a capture.; the take's dodstudio_take.json stays

Fixed on this branch

  • b360b7f: with permanent + "Only when space is needed", a capture short of room is an orange note under Start, not a block; the backend decides.
  • 0d0a7d6: sys::disk::forget_free_space() drops the free-space cache; make_room calls it after deleting, so the capture sees the room it just made. No unit test (it would race other disk writers); the live run above covers it.

Seen, not fixed here

  • The space-needed warning reads "would leave at most 10.0 GB" when the only finished takes were kept because their clip moved; it should say takes were found and why they stay (moving clips into an editing folder is normal).
  • The utvideo budget is ~2.5x the real take (30.9 vs 12.1 GB), so space-needed mode deletes more than it needs to.
  • After a delete the footer's "Capture Output Free" keeps the old figure until something refreshes it.
  • A refused batch shows "Batch capture queued successfully!" before its error toast, and the warning toast twice.
  • The setting lives under Render Output but acts before captures too: Move "After a clip is finished" out of Render Output: it also deletes takes before captures #1094.

Not run: Cancel during "Making room" (one delete takes under a second), the two-drive render case (unit tests only).

…clip moved; Capture Output Free updates after the cleanup

When every finished take still isn't enough, the activity-log line and the
toast now count the takes kept because their clip isn't where it was
rendered (moved or renamed), so a short warning with takes on the drive
explains itself. The Capture footer's free-space figure and the launch guard
read the drives again on take_cleanup_done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant