Skip to content

fix(lock): disambiguate idiomatic lock target#10319

Merged
jdx merged 2 commits into
mainfrom
codex/fix-idiomatic-lockfile
Jun 11, 2026
Merged

fix(lock): disambiguate idiomatic lock target#10319
jdx merged 2 commits into
mainfrom
codex/fix-idiomatic-lockfile

Conversation

@jdx

@jdx jdx commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • prefer the highest-precedence mise config when idiomatic version files map to multiple configs with the same project root
  • add e2e coverage for root mise.toml vs .mise/config.toml lockfile targeting

Validation

  • cargo fmt --check
  • mise run test:e2e e2e/lockfile/test_lockfile_idiomatic_version_file
  • cargo clippy --all-features -- -D warnings

Follow-up to #10309.


Note

Medium Risk
Changes which lockfile path is used for idiomatic version sources in multi-config repos; behavior is more deterministic but may differ from the previous ambiguous choice for edge cases.

Overview
Fixes ambiguous lockfile targeting when an idiomatic version file (e.g. .dummy-version) is covered by more than one base mise.toml at the same project root.

lockfile_path_for_tool_source still picks the deepest matching config root and prefers base configs, but when several configs tie on those criteria it now breaks ties using config_files order (later entry wins). That makes colocated mise.toml and .mise/config.toml consistently map the idiomatic file to .mise/mise.lock instead of the root mise.lock.

E2e coverage runs mise lock --dry-run with both configs present and asserts the lock output targets .mise/mise.lock, not the root lockfile.

Reviewed by Cursor Bugbot for commit be58caf. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Tests

    • Added an end-to-end test covering an idiomatic version-file lockfile scenario and cleanup behavior.
  • Bug Fixes

    • Made lockfile selection deterministic when multiple configurations coexist, and ensured dry-run output references the local lockfile path rather than a hardcoded location.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2e095a89-1c91-4d1b-ac5d-58ea867bf930

📥 Commits

Reviewing files that changed from the base of the PR and between 8f2eab2 and be58caf.

📒 Files selected for processing (2)
  • e2e/lockfile/test_lockfile_idiomatic_version_file
  • src/lockfile.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • e2e/lockfile/test_lockfile_idiomatic_version_file
  • src/lockfile.rs

📝 Walkthrough

Walkthrough

This PR adds precedence tie-breaking to idiomatic version-file lockfile selection in src/lockfile.rs and validates the behavior with a new e2e test. When multiple configs share the same project root, the selection now includes iteration index as a tie-breaker alongside existing root-depth and base-config criteria.

Changes

Idiomatic version-file lockfile precedence

Layer / File(s) Summary
Lockfile precedence tie-breaking logic
src/lockfile.rs
lockfile_path_for_tool_source enumerates candidate configs and adds iteration index as a tie-breaker in max_by_key selection, alongside root depth and base-config status.
Idiomatic version file e2e test
e2e/lockfile/test_lockfile_idiomatic_version_file
New test scenario creates .mise/config.toml, runs mise lock --dry-run, and asserts the lockfile resolves to .mise/mise.lock and not a hardcoded workdir path.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • jdx/mise#10309: Overlapping idiomatic version-file lockfile precedence changes and lockfile path resolution.

Poem

A tie-break by index, neat and bright, 🐰
Co-located configs now pick just right,
The test writes .mise and checks the lock's call,
No hardcoded path — the selection stands tall,
Hooray, small changes that make resolve small!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(lock): disambiguate idiomatic lock target' directly describes the main change—resolving ambiguity in lockfile target selection when multiple configs share the same project root.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
e2e/lockfile/test_lockfile_idiomatic_version_file (1)

51-64: 💤 Low value

Consider adding a comment to clarify the test scenario.

The test correctly validates that when both mise.toml and .mise/config.toml exist in the same directory, .mise/config.toml wins the precedence tie-breaker for idiomatic version file lockfile selection. However, the intentional coexistence of both configs (created on lines 45-49 and 52-56) might not be immediately obvious to future maintainers.

Consider adding a comment before line 51 to make the test intent explicit:

# Test precedence when both mise.toml and .mise/config.toml exist at same root.
# .mise/config.toml should win and idiomatic .dummy-version should map to .mise/mise.lock.

This would make the test scenario clearer and help prevent confusion about why the previous mise.toml isn't cleaned up before creating .mise/config.toml.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/lockfile/test_lockfile_idiomatic_version_file` around lines 51 - 64, Add
an inline comment in the test_lockfile_idiomatic_version_file before the block
that creates .mise/config.toml to document the intent: explain that mise.toml
and .mise/config.toml are intentionally created together to verify precedence
(that .mise/config.toml wins and .dummy-version maps to .mise/mise.lock).
Reference the created artifacts (.mise/config.toml, mise.toml, .dummy-version,
and the expected .mise/mise.lock) in the comment so future maintainers
understand why mise.toml is not removed prior to creating .mise/config.toml.
src/lockfile.rs (1)

901-901: ⚡ Quick win

Document the precedence ordering assumption.

The comment on line 901 states that "the highest-precedence config wins" when multiple configs share a root, and the implementation uses iteration index (idx) as the tie-breaker. However, the code doesn't document a critical assumption: that config.config_files is ordered such that higher indices correspond to higher precedence configs.

Without this documentation, future maintainers might not understand:

  1. Why the enumeration index is used as a tie-breaker
  2. That the ordering of config.config_files is part of the contract
  3. Whether changes to config loading order could break this logic

Consider adding a comment explaining this assumption, for example:

/// If multiple configs share that root, the highest-precedence config wins.
/// Config precedence is determined by:
/// 1. Root depth (deeper roots override shallower ones)
/// 2. Base vs. local/env-specific (base configs preferred for idiomatic files)  
/// 3. Iteration order in config.config_files (higher index = higher precedence;
///    e.g., .mise/config.toml typically has higher precedence than mise.toml)

Also applies to: 911-927

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lockfile.rs` at line 901, Update the comment around the logic that picks
the "highest-precedence config" (the code that iterates config.config_files and
uses idx as a tie-breaker) to explicitly document the precedence contract: that
config.config_files is ordered with higher indices meaning higher precedence,
that tie-breaking uses the enumeration index (idx), and the effective precedence
rules (e.g., deeper root overrides shallower, base vs local/env rules, then
iteration order where higher index wins — e.g., .mise/config.toml > mise.toml).
Mention this assumption wherever the idx tie-break is used (the block around the
"highest-precedence config wins" comment and the related code at lines ~911-927)
so future maintainers know changing config loading order can break the logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@e2e/lockfile/test_lockfile_idiomatic_version_file`:
- Around line 51-64: Add an inline comment in the
test_lockfile_idiomatic_version_file before the block that creates
.mise/config.toml to document the intent: explain that mise.toml and
.mise/config.toml are intentionally created together to verify precedence (that
.mise/config.toml wins and .dummy-version maps to .mise/mise.lock). Reference
the created artifacts (.mise/config.toml, mise.toml, .dummy-version, and the
expected .mise/mise.lock) in the comment so future maintainers understand why
mise.toml is not removed prior to creating .mise/config.toml.

In `@src/lockfile.rs`:
- Line 901: Update the comment around the logic that picks the
"highest-precedence config" (the code that iterates config.config_files and uses
idx as a tie-breaker) to explicitly document the precedence contract: that
config.config_files is ordered with higher indices meaning higher precedence,
that tie-breaking uses the enumeration index (idx), and the effective precedence
rules (e.g., deeper root overrides shallower, base vs local/env rules, then
iteration order where higher index wins — e.g., .mise/config.toml > mise.toml).
Mention this assumption wherever the idx tie-break is used (the block around the
"highest-precedence config wins" comment and the related code at lines ~911-927)
so future maintainers know changing config loading order can break the logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6c7ac3b9-667d-4fce-9f40-8bb62fd069e5

📥 Commits

Reviewing files that changed from the base of the PR and between 90582ff and 8f2eab2.

📒 Files selected for processing (2)
  • e2e/lockfile/test_lockfile_idiomatic_version_file
  • src/lockfile.rs

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes ambiguous lockfile targeting when an idiomatic version file (e.g. .dummy-version) is covered by multiple base configs sharing the same project root. The fix adds a position-index tiebreaker to lockfile_path_for_tool_source so the later entry in config_files wins, making .mise/config.toml consistently map to .mise/mise.lock over the root mise.lock.

  • src/lockfile.rs: Adds .enumerate() to the config_files iterator and includes the index as a third key in max_by_key, breaking ties among same-root-depth base configs by insertion order.
  • e2e/lockfile/test_lockfile_idiomatic_version_file: New test scenario creates colocated mise.toml and .mise/config.toml, runs mise lock --dry-run, and asserts the output targets .mise/mise.lock (not the root mise.lock).

Confidence Score: 5/5

Safe to merge — the change is minimal, targeted, and validated end-to-end.

The logic change is a single additional tiebreaker key in one max_by_key call; it only activates when two base configs share the same root depth, and the e2e test directly exercises that exact scenario. Cleanup, teardown, and the surrounding test flow are all correct.

No files require special attention.

Important Files Changed

Filename Overview
src/lockfile.rs Adds an enumerate()-based index tiebreaker to lockfile_path_for_tool_source so that when multiple base configs share the same root depth, the later entry in config_files wins, making .mise/config.toml deterministically map to .mise/mise.lock.
e2e/lockfile/test_lockfile_idiomatic_version_file Adds a new e2e scenario that creates both mise.toml and .mise/config.toml, runs mise lock --dry-run, and asserts the output targets .mise/mise.lock rather than the root mise.lock. Cleans up correctly before the subsequent existing test block.

Reviews (2): Last reviewed commit: "docs(lock): clarify idiomatic lock targe..." | Re-trigger Greptile

Comment thread src/lockfile.rs Outdated
@github-actions

Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.2 x -- echo 23.2 ± 2.5 20.2 35.1 1.00
mise x -- echo 23.6 ± 1.7 21.3 47.5 1.02 ± 0.13

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.2 env 21.7 ± 1.1 19.5 27.6 1.00
mise env 22.3 ± 1.2 20.1 28.7 1.03 ± 0.08

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.2 hook-env 22.2 ± 1.1 19.9 27.5 1.00
mise hook-env 23.1 ± 1.1 20.5 28.6 1.04 ± 0.07

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.2 ls 17.4 ± 1.2 14.7 23.7 1.00
mise ls 17.8 ± 1.4 15.3 23.2 1.03 ± 0.11

xtasks/test/perf

Command mise-2026.6.2 mise Variance
install (cached) 135ms 134ms +0%
ls (cached) 58ms 61ms -4%
bin-paths (cached) 71ms 70ms +1%
task-ls (cached) 134ms 132ms +1%

@jdx jdx merged commit e9a9e67 into main Jun 11, 2026
34 checks passed
@jdx jdx deleted the codex/fix-idiomatic-lockfile branch June 11, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant