reload: fix infinite reload loop and spurious rebuilds from .devenv/#2806
Open
ndam-hexagon wants to merge 1 commit into
Open
reload: fix infinite reload loop and spurious rebuilds from .devenv/#2806ndam-hexagon wants to merge 1 commit into
ndam-hexagon wants to merge 1 commit into
Conversation
Member
|
Maybe we should skip individual devenv files? I'm worried that someone might store something into DEVENV_STATE and expect the reload to work. |
6048614 to
63a79f8
Compare
63a79f8 to
9bb171b
Compare
domenkozar
approved these changes
May 28, 2026
`lib.fileset.fromSource ./.` (and any other `readDir` on a parent of `.devenv/`) was dragging devenv's own churn into the Nix tracked-input set: the eval-cache SQLite db + WAL/SHM are rewritten on every evaluation, the tasks db on every task run, and shell-env.sh / imports.txt / generated bootstrap files on every build. Tracked inputs that change every run mean cache validity is poisoned and the reload watcher self-triggers in an infinite loop after the first reload. Exclude the whole devenv dotfile from both the eval cache's tracked inputs (CachingConfig.excluded_paths) and the reload watcher (is_watchable_input in reload::owner). To preserve the documented $DEVENV_STATE contract, carve out `<dotfile>/state/` via CachingConfig.excluded_path_exceptions and the equivalent predicate in the watcher: files users persist there still trigger reload and cache invalidation. The carve-out would otherwise re-admit devenv-managed leaves under `state/` — the tasks-cache sqlite db (rewritten on every task run) and the git-hooks state dir (rewritten on every reload) — and reintroduce the same loop scoped to state/. Switch `ops_to_inputs` to longest-prefix-match between `excluded_paths` and `excluded_path_exceptions`: the most specific rule wins, ties favor the exception. Callers can then list `<dotfile>/state/tasks.db`, `tasks.db-wal`, `tasks.db-shm`, and `git-hooks` back in `excluded_paths` and have them override the broader state exception. `is_watchable_input` mirrors the same leaf list as defense in depth in case a stale eval-cache row predates the filter. `Path::starts_with` matches on components, so each sqlite sibling (`-wal`, `-shm`) is its own component and is listed explicitly — a `tasks.db` prefix would not cover them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9bb171b to
be168ec
Compare
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
devenv shellself-triggered hot-reload in an infinite loop after the first reload, andlib.fileset.fromSource ./.(or any otherreadDiron a parent of.devenv/) caused spurious cache invalidations and rebuilds.Both came from the same root cause: devenv's own dotfile churn was leaking into Nix's tracked-input set, so every evaluation invalidated the previous one's cache.
Fix
Exclude
.devenv/from the reload watch set and the eval cache's tracked inputs, keeping.devenv/state/($DEVENV_STATE) so files users persist there still trigger reload.