Expire unapplied workspace cleanup plans - #1277
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every cleanup plan and dry run persists a run row so an operator can review it and apply it later. Nothing ever removed the rows that were never applied, so they accumulate for the life of the install.
On this workspace:
completed_atrequested_by_user_id,requested_by_agent_id,parent_job_id, orbatch_job_id, so they come from plan and dry-run invocations rather than a scheduled jobThe rate follows agent activity rather than a fixed cadence: 3,559 on 2026-08-21 and 3,219 on 2026-08-24 during heavy automation, then 8 and 2 on quiet days.
workspace hygieneperforms an inventory-only cleanup classification on every call, so routine inspection persists plans too.These runs also fan out into
worktree_cleanup_chunkjobs and Action Scheduler actions, which is whyactionscheduler_actionsreached 436,869 rows on this install. Data Machine retention was deleting 58,533 of those rows in a single pass, so the exhaust was being handled correctly while its source kept growing.Fix
CleanupRunRepository::expire_runs()deletes runs in a given status that were created before a cutoff, removing each run's items first and bounding the work per pass.WorkspaceRetentionCleanupTaskcalls it on the daily retention pass that already exists.Only the unapplied planning state expires. Applied, completed, and in-flight runs are untouched, and a dry-run retention pass reports the cutoff without deleting.
Two filters cover tuning:
datamachine_code_cleanup_plan_max_age_days(7) anddatamachine_code_cleanup_plan_expiry_limit(2000).expire_runs()is deliberately not added toCleanupRunRepositoryInterface, which is the narrow progress-writing contract implemented by orchestrator test fakes.Verification
php tests/cleanup-plan-expiry.php— 7 checks covering the empty candidate set, reported counts, status/age/bound selection, item-before-run ordering, run-id scoping, and clamping of the per-pass boundtests/worktree-add-lifecycle.phptimes out on this branch and on an unmodified checkout, so it is pre-existing.Note
The cleanup system itself is working: 593 worktrees removed and 5.94 TB of artifacts reclaimed to date. This closes the one record type that had no retention.
AI assistance
OpenAI GPT-5.6-Sol via OpenCode was used to trace the Action Scheduler growth to its source, verify the retention chain, implement the expiry, and run the suite. I directed and reviewed the investigation.