What
#982 renamed the ratified Bitwarden folder taxonomy from Dotfiles/apps / Dotfiles/infra to apps / infra, updating both secrets/registry.yaml and validBWFolders, the parser's allow-list. Both halves are correct. What is missing is that the deployed copy of the registry is a separate artifact with its own lifecycle (ADR-030): ~/.dotfiles/secrets/registry.yaml is refreshed by setup-linux.sh, not by merging a PR.
So a binary built from current main rejects the registry that is currently deployed on every machine:
$ cd ~/.dotfiles && dotf secrets ls
Error: secret "GITHUB_PERSONAL_ACCESS_TOKEN": bw.folder "Dotfiles/apps" is not in the ratified taxonomy (apps, infra)
$ grep -o 'folder: [A-Za-z/]*' ~/.dotfiles/secrets/registry.yaml | sort | uniq -c
21 folder: Dotfiles/apps
5 folder: Dotfiles/infra
Not currently broken, and that is the trap
The installed binary is 0.40.0, which predates #982, so today everything works. The failure is armed, not firing: it lands the moment anyone installs a build from main — the next release, or a scripts/install-dotf.sh run — and it lands on every machine simultaneously, before any of them has re-run setup.
Blast radius when it fires: ParseRegistry is the entry point for the whole dotf secrets surface, so ls, run, show, verify, render and two dotf doctor sections all fail at once. Reproduced here with a main-based build:
[Secrets integrity]
[FAIL] secrets/registry.yaml not found or invalid
Note the message says "not found or invalid" for what is actually a validation failure on a file that is present and readable — so the first person to hit this will go looking for a missing file.
Why the guard did not catch it
The pattern is the dormant-value one this repo already has a lesson about, inverted: OPS-028 learned to validate bw.folder at write time rather than at activation time. This is the same field failing the other way — a value that was valid when written and was invalidated later by a change to the validator, in an artifact the validator's PR did not and could not update.
dotf doctor's deploy-drift check knows the deployed copy can lag the checkout; nothing checks that the lagging copy is still parseable by the current binary.
Options
- Accept both spellings for a deprecation window —
validBWFolders takes the old values too, WARNing on them, removed after a release. Cheapest, and it makes the change survivable in any install order.
- Make the deploy a precondition of the parse tightening — ship the registry change, require setup, then tighten. Correct but needs coordination the release process does not currently have.
- Have
dotf doctor --fix redeploy the registry when the deployed copy fails to parse but the checkout's parses. Fixes this instance and the next one of the same shape.
Recommend 1 now (it is what makes the already-merged change safe), plus 3 as the durable guard.
Acceptance criteria
Evidence
What
#982 renamed the ratified Bitwarden folder taxonomy from
Dotfiles/apps/Dotfiles/infratoapps/infra, updating bothsecrets/registry.yamlandvalidBWFolders, the parser's allow-list. Both halves are correct. What is missing is that the deployed copy of the registry is a separate artifact with its own lifecycle (ADR-030):~/.dotfiles/secrets/registry.yamlis refreshed bysetup-linux.sh, not by merging a PR.So a binary built from current
mainrejects the registry that is currently deployed on every machine:Not currently broken, and that is the trap
The installed binary is 0.40.0, which predates #982, so today everything works. The failure is armed, not firing: it lands the moment anyone installs a build from
main— the next release, or ascripts/install-dotf.shrun — and it lands on every machine simultaneously, before any of them has re-run setup.Blast radius when it fires:
ParseRegistryis the entry point for the wholedotf secretssurface, sols,run,show,verify,renderand twodotf doctorsections all fail at once. Reproduced here with amain-based build:Note the message says "not found or invalid" for what is actually a validation failure on a file that is present and readable — so the first person to hit this will go looking for a missing file.
Why the guard did not catch it
The pattern is the dormant-value one this repo already has a lesson about, inverted: OPS-028 learned to validate
bw.folderat write time rather than at activation time. This is the same field failing the other way — a value that was valid when written and was invalidated later by a change to the validator, in an artifact the validator's PR did not and could not update.dotf doctor's deploy-drift check knows the deployed copy can lag the checkout; nothing checks that the lagging copy is still parseable by the current binary.Options
validBWFolderstakes the old values too, WARNing on them, removed after a release. Cheapest, and it makes the change survivable in any install order.dotf doctor --fixredeploy the registry when the deployed copy fails to parse but the checkout's parses. Fixes this instance and the next one of the same shape.Recommend 1 now (it is what makes the already-merged change safe), plus 3 as the durable guard.
Acceptance criteria
mainparses the currently-deployed registry, or a documented, enforced ordering makes that impossible to hit.ParseRegistry's failure is reported as a validation error naming the file and the rule, never as "not found or invalid".Evidence
cli/internal/secrets/registry.go—validBWFolders,planeFolderdocs/adr/adr-030-*— checkout vs deployed copy, the two-artifact lifecycledocs/lessons.md— the OPS-028 dormant-field lesson, the same field failing the other way