Re-evaluate when a cached eval's drvs are missing from the cache (SPEC §6.1) #17

Manually merged
krisbuild merged 4 commits from eval-drv-verify into main 2026-09-27 19:57:32 +02:00
Owner

When a cached eval/expand result is about to be reused, the control plane now checks that the .drv files it emitted are actually in the cache (SPEC §6.1, §7.3). Until now a cached eval whose drvs never reached the cache (for example because attic watch-store was backlogged) was replayed forever, and every dependent failed with "derivation not present locally and not fetchable". Retrying couldn't recover (seen on graphs 573, 575 and 580).

  • Stale-eval check: missing_drv() probes the narinfo of every emitted NixDrv .drv on the configured substituters, up to 16 at a time. If every substituter answers 404, the hit is stale and the eval runs again.
  • Fail open: on substituter errors, after 15 s, or with no substituters configured, the cached result is used as before.
  • Probe cache: positive answers are kept in memory for 1 h, so a warm cache costs one probe per drv per hour.
  • Reruns: a rerun no longer carries over unfinished tasks emitted by a pure expander. The expander emits them again, so they are ordered after the (re-)evaluation.
  • Tests: new tests/stale_eval.rs covers the 404 re-eval, 200 replay with one probe in total, 503 fail-open, and a failed_only rerun that recovers.

🤖 Generated with Claude Code

When a cached eval/expand result is about to be reused, the control plane now checks that the `.drv` files it emitted are actually in the cache (SPEC §6.1, §7.3). Until now a cached eval whose drvs never reached the cache (for example because `attic watch-store` was backlogged) was replayed forever, and every dependent failed with "derivation not present locally and not fetchable". Retrying couldn't recover (seen on graphs 573, 575 and 580). - **Stale-eval check:** `missing_drv()` probes the narinfo of every emitted `NixDrv` `.drv` on the configured substituters, up to 16 at a time. If every substituter answers 404, the hit is stale and the eval runs again. - **Fail open:** on substituter errors, after 15 s, or with no substituters configured, the cached result is used as before. - **Probe cache:** positive answers are kept in memory for 1 h, so a warm cache costs one probe per drv per hour. - **Reruns:** a rerun no longer carries over unfinished tasks emitted by a pure expander. The expander emits them again, so they are ordered after the (re-)evaluation. - **Tests:** new `tests/stale_eval.rs` covers the 404 re-eval, 200 replay with one probe in total, 503 fail-open, and a `failed_only` rerun that recovers. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Stale cached eval: re-evaluate when its .drv files are not in the cache
Some checks failed
krisbuild/kris/krisbuild/nix/hello cached
krisbuild/kris/krisbuild/nix/workspace-deps cached
krisbuild/kris/krisbuild/nix/world cached
krisbuild/kris/krisbuild/nix/clippy failed on ares (exit-code)
krisbuild/kris/krisbuild/nix/build succeeded
krisbuild/kris/krisbuild/nix/kb-check failed on nuxbox (exit-code)
krisbuild/kris/krisbuild/nix/test succeeded
krisbuild/kris/krisbuild krisbuild kris/krisbuild: one or more tasks failed
871c098a18
A cached eval/expand result is replayed only after a narinfo HEAD for each
emitted NixDrv's .drv. An authoritative 404 from every substituter makes the
hit stale (SPEC §6.1) and the eval runs again; an unreachable or slow cache
keeps the hit (fail open, 15s bound), and positive answers are remembered for
an hour so a warm cache costs one probe per derivation, not per graph.

Reruns no longer carry tasks a pure expander emitted that did not complete in
the source: the expander (replayed or re-run) emits them again, so a
re-evaluation precedes the tasks it repairs instead of racing them. Without
this a failed_only rerun of a graph whose drvs never reached attic could
never recover.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
substitution: collapse the stale-eval check into a let-chain (clippy)
All checks were successful
krisbuild/kris/krisbuild/nix/workspace-deps cached
krisbuild/kris/krisbuild/nix/hello cached
krisbuild/kris/krisbuild/nix/world cached
krisbuild/kris/krisbuild/nix/clippy succeeded
krisbuild/kris/krisbuild/nix/build succeeded
krisbuild/kris/krisbuild/nix/kb-check succeeded
krisbuild/kris/krisbuild/nix/test succeeded
krisbuild/kris/krisbuild krisbuild kris/krisbuild: all tasks succeeded
17a94bdcb4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tests: fold stale_eval into the control plane's single test binary
All checks were successful
krisbuild/kris/krisbuild/nix/hello cached
krisbuild/kris/krisbuild/nix/test-deps cached
krisbuild/kris/krisbuild/nix/workspace-deps cached
krisbuild/kris/krisbuild/nix/world cached
krisbuild/kris/krisbuild/nix/clippy succeeded
krisbuild/kris/krisbuild/nix/test succeeded
krisbuild/kris/krisbuild/nix/build succeeded
krisbuild/kris/krisbuild/nix/kb-check succeeded
krisbuild/kris/krisbuild krisbuild kris/krisbuild: all tasks succeeded
krisbuild/queue merged
4923aacb1e
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Author
Owner

Merged main (#18) and moved stale_eval into tests/it/. Previous head was fully green (graph 588).

@krisbuild r+ p=5

Merged main (#18) and moved `stale_eval` into `tests/it/`. Previous head was fully green (graph 588). @krisbuild r+ p=5
krisbuild manually merged commit 5fcfc8d3fb into main 2026-09-27 19:57:32 +02:00
Collaborator

Merged as 5fcfc8d3fb.

Merged as 5fcfc8d3fb15.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kris/krisbuild!17
No description provided.