Skip to main content

Module cache

Module cache 

Source
Expand description

Durable ownership of the shared Cargo build cache (CARGO_TARGET_DIR).

One cache, many borrowers: an implement wave’s candidates, a review round’s E2E, the final gate, a human’s magi review invoked by hand — all of them may point CARGO_TARGET_DIR at the same directory, sometimes from different worktrees, sometimes from a different magi run entirely. Two failures came out of sharing it with no ownership record at all:

  • A read-only reviewer seat that inherited CARGO_TARGET_DIR tried to write into it, was refused by its own sandbox, and reported the refusal as a defect in the code under review rather than a property of its own seat. See graph::wave, which now only hands the variable to a seat that crate::agent::Invocation::allow_write actually permits to use.
  • Two source trees building the same package name/version into one CARGO_TARGET_DIR in sequence can leave a stale artifact from the older worktree looking fresh to Cargo, and a later cargo test runs binaries compiled from source nobody is looking at. ensure_fresh selectively cargo clean -ps the workspace’s own packages — never the downloaded dependency graph — the moment the recorded source identity for a cache directory changes.

Both are consequences of one missing fact: who is using this cache right now, and against which source. This module is that fact, made durable (a JSON file per cache directory, surviving a process restart) and cheap to ask (classify, in_use, inventory).

§Reclaiming a dead owner

Liveness is crate::proc::pid_alive — the same conservative check crate::daemon::sweep_stale_claims uses for the queue’s own claim locks: every uncertain outcome reads as alive, and a lease whose file cannot even be parsed is never reclaimed automatically (Status::Unknown). This is deliberately the same policy as the queue’s .lock files, not a new one — a bare lock file was never trusted alone there either; it is always paired with a liveness check.

Process cleanup additionally holds an OS output lease through termination of managed tool descendants. Admission and destructive maintenance check that lease too: reclaiming a dead JSON owner alone does not permit deleting or reusing outputs still owned by cleanup.

Structs§

Entry
One cache directory’s state, for a0fc’s capacity/cleanup inventory (and magi cache show, eventually). Every lease file on disk is reported — including ones this process itself does not want to touch — because the question this answers is “what is registered right now”, not “what can I safely act on”.
Guard
A held lease. Releases on drop, so a panicking or early-returning caller never leaves the cache permanently marked busy — the same guarantee crate::queue::Claim gives the task queue’s own lock file.
Identity
The source a build against a cache directory was last known to come from. Compared by needs_refresh on every acquire, so a cache directory that only ever sees one worktree/head pair never pays a clean it does not need.
Owner
Who is holding, or wants, a cache directory.

Enums§

AcquireOutcome
What try_acquire returned.
Busy
Why try_acquire did not hand back a Guard.
EntryStatus
Entry::status’s possible values.
Status
Where a cache directory’s classification lands.
Target
Where cargo is asked about the workspace’s own packages.

Constants§

RESOURCE_HOLD
Prefix of the machine hold a task gets when its run stopped because this lease stayed busy past [graph] timeout_resource_wait. triage reads it to release the task once the lease is free; keep both in sync.

Functions§

ensure_fresh
Guarantee that a build against cache_dir from (worktree, head) never silently reuses another source’s compiled output: clean the workspace’s own packages out of the cache when the recorded identity disagrees, then record the new one. A no-op — no subprocess spawned — when the identity already matches, which is the common case once a cache directory settles on one worktree for a while.
extract_manifest_paths
Every --manifest-path the given verify commands pass, in order of first appearance, without duplicates. Understands --manifest-path X and --manifest-path=X, with ' / " quoting. Pure.
in_use
Is cache_dir in use right now — held by a live owner, or in a state nobody can vouch for? The conservative half of the janitor’s prune guard: Status::Unknown refuses exactly like Status::Active, because a lease this process cannot read is not evidence the directory is free.
invalidate_identity
Forget the recorded source identity for cache_dir, so the next ensure_fresh call cannot skip its clean on the strength of a stale match.
inventory
Every cache directory magi knows about under home, whether or not anything holds it right now. A lease file reports the current borrower; once released it is gone (by design — see Guard::release), so a directory nobody is borrowing is reported from the catalog instead, carrying its last known owner rather than nothing at all. There is nothing here for a directory this process has never leased: inventory answers “what has magi registered”, not “what looks like a build cache”.
maintenance_prune
Prune cache_dir to limit, but only while holding the lease — a prune that raced a live build would delete files a compile in flight still needs, on top of confusing whatever built them about why its own output vanished. Ok(None) when the cache is in use right now; that is not an error, it is the janitor’s next pass catching it once the borrower is done. Never touches a lease file itself — they live outside cache_dir (see [leases_dir]), so crate::disk::prune_dir’s own sweep can never reach one.
needs_refresh
Has the source building against cache_dir changed since the last record? True (needs a refresh) whenever nothing was ever recorded — the conservative default for a cache directory this process has not tracked before.
parse_workspace_package_names
Parse cargo metadata --no-deps’s JSON for the names of packages defined in the workspace itself — never a dependency, which is exactly the distinction that keeps a freshness fix from also discarding a downloaded crate’s compiled artifacts on every worktree switch. Pure, so the parse is tested against fixture text without a cargo on the test machine.
record_identity
Persist identity as the last known source for cache_dir.
try_acquire
Take the lease for cache_dir if nobody live holds it, reclaiming a stale one first. One attempt — a caller that wants to wait uses wait_for, which is this in a loop bounded by a budget.
try_acquire_maintenance
Take both cache ownership and exclusive output ownership for a destructive maintenance operation. Refuses while process cleanup still owns descendants.
wait_for
Acquire the lease for cache_dir, waiting out contention rather than failing on the first busy owner — but never past budget, and the wait comes out of that same budget rather than a second, unbounded one. A caller already has a node timeout; this is that timeout, not a new clock next to it, which is what keeps a wait from becoming the “無期限待機” AGENTS.md’s own build-cache section warns is never acceptable. The error on timeout names who is still holding it, for the event this gets logged into.
wait_for_unless
wait_for that also gives up, with Ok(None), as soon as cancel returns true. cancel is looked at once per poll, so a park request is honoured within a poll interval instead of after the whole budget. The lease is never held on that path: nothing was acquired.