Expand description
The disk janitor: finished runs get their worktrees folded, worktrees whose run record is already gone get reclaimed too, and the shared build cache is pruned to its cap.
A run’s state being written by an older schema is not the same thing as it
being unreadable, and this module used to conflate the two: fold_due
treated any run.json its version check rejected exactly like one that
failed to parse at all, so a single schema bump silently stopped every
automatic fold in the fleet the moment it shipped, and did so with no
counter and no log line to say so. A record magi genuinely cannot parse —
missing fields, broken JSON, a schema newer than this build has ever heard
of — is still left alone here, still counted in
Housekeeping::unreadable, and still only ever removed by an explicit
operator action (magi fold, or the equivalent phone route). One written
by a schema this build merely disagrees with the meaning of is not that:
as long as it still parses, folding proceeds regardless of the number in
its schema field.
Everything policy-shaped — which statuses are foldable, how long a finished run is left alone, whether the cache is over its limit — is a pure function injected with numbers, so nothing here has to ask the operating system to be testable. The only I/O is the removal itself.
Structs§
- Housekeeping
- What one janitor pass did, for the caller’s log line.
Functions§
- abandon_
settled_ questions - Abandon every open question whose run has already settled into a status
nothing comes back from, worded with what the run became - the same
cleanup
graph::Runner::settle_questionsruns the momentstatuslands there, for questions that missed it. - cache_
report - The cache’s path, size and cap, for
magi cache showand the health view.Nonewhen the config declares noCARGO_TARGET_DIRto aggregate. - cache_
size - Size in bytes of the shared build cache.
- clear_
abandoned_ active magi fold’s recovery path for a run whose worktrees are already gone — socrate::graph::fold_runremoved nothing — but whoserun.jsonstill lists active seats nobody is left to answer for: no live daemon claims the run, and every one of those seats has overrun its own timeout (seeRunState::active_all_overrun). Clearing them and failing the run is what lets it be deleted afterward —RunState::ensure_can_deleteonly ever checks whether a live daemon is working on the run and whether its candidates are folded, notstatus, but a run stuckimplementingforever with an empty worktree still reads as unresolved everywhere else (magi show, the deck, the phone) until this runs.- due
- Is
updatedold enough, measured againstnow, that the run may fold? - fold_
due - Fold every run that is finished, older than the grace period, and not being
worked on; return
(folded, unreadable). - fold_
orphaned_ worktrees - Reclaim worktrees under
worktrees_rootthat no run record inrunsclaims anymore, and return how many were removed. - fold_
unreadable - Remove a run that cannot be read: its state directory under
runsand its worktree directory underworktrees_root. - housekeep
- Run the janitor: fold due runs, reclaim orphaned worktrees, prune stale worktree registrations, then prune the cache if it is over its cap.
- prune_
cache - Delete files from the shared build cache until it fits its cap.
- prune_
cache_ if_ over_ limit prune_cache, but resolving the operator’s opt-out and missingCARGO_TARGET_DIRfirst — the same two checkshousekeep’s idle pass makes before ever measuring the cache, factored out socrate::daemon’s between-runs check (see the module’s own doc for why congestion can make “idle” arrive too rarely to matter) makes them identically rather than growing its own copy that could drift.Ok(None)covers both a cap of0(see the module docs oncache_limit_bytes) and a config that renders noCARGO_TARGET_DIRto aggregate at all.