docs(config): state the layer-vs-specificity precedence rule - #3789
docs(config): state the layer-vs-specificity precedence rule#3789worktrunk-bot wants to merge 2 commits into
Conversation
`WORKTRUNK_WORKTREE_PATH` and `--config-set worktree-path` set the global key; a `[projects."<id>"]` entry beats the global key whichever layer set it. The docs promised env vars override "all user config options" without naming the specificity axis, so a project entry silently winning read as a bug. Documents the rule under a new Precedence heading, cross-references it from the `--config-set` section, and pins all three behaviors with an integration test. Refs #3788
worktrunk-bot
left a comment
There was a problem hiding this comment.
Checked the documented rule against the code: layer order matches UserConfig::load_with_warnings (system → user → env → --config-set), specificity matches worktree_path_for_project / project_field, and the exact-key --config-set advice holds even against a [projects."host/*"] pattern entry because project_match::matching_keys orders least- to most-specific. wt config show does print Identifier: …, and #precedence is a unique heading so both @/config.md#precedence links resolve.
One gap in the test, inline: it pins the specificity half of the rule but not the layer half.
|
Superseded by #3790: @max-sixty called for the behavior change instead, so this page now documents a rule that no longer holds. #3790 carries the corrected precedence section (plus the test, with its expectations inverted). Closing — happy to reopen if the docs-only framing is wanted back. |
Problem
#3788 reports that
WORKTRUNK_WORKTREE_PATHdoes not override a[projects."<id>"].worktree-path, contradicting the config docs' claim that "All user config options can be overridden with environment variables using theWORKTRUNK_prefix."Verified against
main, and it is not an env-layer bug — the env var reachesworktree-pathcorrectly. All three invocation-level layers set the global key, and any matching[projects."…"]entry beats the global key regardless of which layer supplied it, because layer merging (UserConfig::load_with_warnings) and specificity resolution (worktree_path_for_project) are separate steps:WORKTRUNK_WORKTREE_PATH=$tmp/from-environment$tmp/from-project--config-set 'worktree-path = "…/from-config-set"'$tmp/from-project--config-set 'projects."github.com/acme/demo".worktree-path = "…"'--config-setvalueSo
--config-set's "higher priority than both config files andWORKTRUNK_env vars" is also imprecise for a key that has a project counterpart — it is the highest layer, not the most specific key.Solution
Documents the actual rule rather than changing it. A new "Precedence" section under Environment variables names the two axes — layer (system config → user config → env vars →
--config-set) and specificity (global key →[projects."…"]entry, applied to the merged result) — and gives the--config-set 'projects."<id>".…'form as the way to override a project entry for one invocation. The--config-setsection cross-references it.Whether an invocation-level layer should outrank a project entry is a separate design question, left open in the issue thread: making
WORKTRUNK_WORKTREE_PATHwin would mean a shell-rcexportsilently clobbering every per-project layout, so it is a maintainer call rather than a docs fix. This change is accurate for the current behavior either way and is a two-paragraph amend if the precedence later changes.Primary source is
after_long_helpinsrc/cli/mod.rs;docs/content/config.md, both skill reference mirrors, and thewt config --helpsnapshot are regenerated.Testing
test_switch_create_project_worktree_path_outranks_invocation_layersintests/integration_tests/switch.rspins all three rows of the table above end-to-end throughwt switch --create --format=json. It caught a wrong project identifier in its own first draft, so the assertions do discriminate. Each invocation layer additionally runs once with no[projects."…"]entry present, so a layer that stopped reachingworktree-pathfails a control rather than passing the specificity assertion for the wrong reason.cargo test --test integration integration_tests::switch::(209 passed), plustest_docs_are_in_sync,test_help,cargo clippy --all-targets, andcargo fmt.The one unrelated line in the help snapshot (
WORKTRUNK_TEST_PROBE_TIMEOUT_MSin the non-assertedinfo:block) is insta refreshing metadata that predates that env var; the committed snapshots are stale on it across the board.Refs #3788 — automated triage