refactor(deps): store deps state under $MISE_STATE_DIR#9301
Conversation
Store per-project deps freshness state in `$MISE_STATE_DIR/deps/<hash>.toml` (hashed by project root, mirroring the `tracked-configs` pattern) instead of `<project>/.mise/deps-state.toml`. Keeps mise from writing inside the project tree, where the file could easily end up committed or conflated with project config. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR moves the Confidence Score: 5/5Safe to merge — core change is a correct path relocation with no migration required, and all ancillary refactors are semantically equivalent. No P0/P1 issues found. The state-path relocation is clean and mirrors existing patterns. All match-guard refactors preserve the original semantics because each affected arm matches a distinct enum variant, so a failed guard cannot accidentally match an unrelated sibling arm. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["mise deps / task run"] --> B["DepsState::load(project_root)"]
B --> C["state_path(project_root)"]
C --> D["hash_to_str(&project_root)\n(SipHash 64-bit)"]
D --> E["$MISE_STATE_DIR/deps/<hash>.toml"]
E -->|"file exists"| F["Parse TOML → DepsState"]
E -->|"file missing"| G["DepsState::default()"]
F --> H["Check freshness\n(blake3 hashes)"]
G --> H
H -->|"stale / first run"| I["Re-hash sources\nDepsState::save(project_root)"]
H -->|"fresh"| J["Skip provider"]
I --> E
style E fill:#d4edda,stroke:#28a745
style D fill:#fff3cd,stroke:#856404
Reviews (3): Last reviewed commit: "[autofix.ci] apply automated fixes (atte..." | Re-trigger Greptile |
| project_root.join(".mise").join("deps-state.toml") | ||
| dirs::STATE | ||
| .join("deps") | ||
| .join(format!("{}.toml", hash_to_str(&project_root))) |
There was a problem hiding this comment.
Unnecessary double-reference in
hash_to_str call
project_root is already &Path, so &project_root produces &&Path. While the Hash blanket impl for &T delegates to T::hash, so the output is identical to passing project_root directly, this is a needless borrow that clippy::needless_borrow would flag. Every other callsite in the codebase (e.g. tracking.rs, hook_env.rs) passes &owned_value, not a double-ref.
| .join(format!("{}.toml", hash_to_str(&project_root))) | |
| .join(format!("{}.toml", hash_to_str(project_root))) |
There was a problem hiding this comment.
Code Review
This pull request moves the dependency freshness state storage from a local .mise/deps-state.toml file to a centralized location in $MISE_STATE_DIR/deps/, using a hash of the project root for the filename. This change ensures that no state files are written inside the project directory. I have no feedback to provide as there were no review comments.
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.18 x -- echo |
22.3 ± 0.6 | 21.2 | 24.9 | 1.00 |
mise x -- echo |
22.5 ± 0.5 | 21.6 | 24.4 | 1.01 ± 0.03 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.18 env |
21.8 ± 0.7 | 20.8 | 28.1 | 1.00 |
mise env |
22.8 ± 0.7 | 21.4 | 24.8 | 1.04 ± 0.05 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.18 hook-env |
22.6 ± 0.6 | 21.6 | 26.3 | 1.00 |
mise hook-env |
23.1 ± 0.7 | 21.9 | 27.1 | 1.02 ± 0.04 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.18 ls |
19.8 ± 0.6 | 18.8 | 22.5 | 1.00 |
mise ls |
20.6 ± 0.5 | 19.2 | 22.4 | 1.04 ± 0.04 |
xtasks/test/perf
| Command | mise-2026.4.18 | mise | Variance |
|---|---|---|---|
| install (cached) | 144ms | -14% | |
| ls (cached) | 76ms | 79ms | -3% |
| bin-paths (cached) | 80ms | 83ms | -3% |
| task-ls (cached) | 807ms | 809ms | +0% |
Summary
<project>/.mise/deps-state.tomlto$MISE_STATE_DIR/deps/<hash>.toml, keyed by a SipHash of the project root — same pattern used fortracked-configs.docs/dev-tools/deps.md.Why
depsis brand new (landed in #9056, 2026.4.18) and the state file currently sits inside the project directory. That's awkward — it's per-machine state, but it lives where users keep versioned config. Moving it under$MISE_STATE_DIRmatches how other per-project state (tracked/trusted/ignored configs, env cache, hook-env checks) is stored.Notes for reviewer
main(docs/backend-plugin-development.md,docs/url-replacements.md) where prettier wants to collapse GitHub's> [!WARNING]callout syntax onto a single line — that would actually break the GitHub alert rendering, so I left them alone. I usedHK_SKIP_STEPS=prettierfor this commit; all other lint steps (cargo-check, cargo-fmt, markdownlint, shellcheck, taplo, shfmt, schema, etc.) passed.Test plan
mise depsin a project; confirm$MISE_STATE_DIR/deps/<hash>.tomlis created and.mise/deps-state.tomlis not.mise deps; confirm providers report fresh (hashes matched from state dir).This PR was generated by an AI coding assistant.
Note
Medium Risk
Changes where deps freshness state is read/written, which can cause all providers to appear stale once after upgrade or create unexpected state collisions if hashing/scoping is wrong; otherwise it’s cache-only state with limited blast radius.
Overview
Deps freshness state is no longer written to
<project>/.mise/deps-state.toml; it is now persisted under$MISE_STATE_DIR/deps/<hash>.toml, where<hash>is derived from the project root path.DepsStatenow computes its storage path viadirs::STATEandhash_to_str(project_root), keeping state per-project without touching the repo tree, and the docs are updated to reflect the new location.Reviewed by Cursor Bugbot for commit e007c55. Bugbot is set up for automated code reviews on this repo. Configure here.