--- name: dotfiles-deployment-truth-audit description: "Answer \"is my X config actually tracked and deployed?\" per package: classify every file by readlink, expose tracked-then-ignored debt, and re-derive census numbers from the command printed on the page." --- Answer to "does this repo still track my settings?" must be a measurement, never a remembered count. The tracked unit is the **file**, not the directory: a live directory can be a real directory and still be fully tracked, because every file inside it is a symlink into the repo. Run in the deployment checkout (the checkout IS the deployment). ## 1. Tracked set, per package, both tiers ```bash cd ~/.omp # or the repo that owns dotfiles/ git ls-files dotfiles/ # base tier git ls-files dotfiles/zz-$(hostname) | grep # host override tier — counted separately ``` The `zz-*` tier overrides base files by the same relative path, so a per-package count that ignores it under-reports what a machine actually runs. ## 2. Live wiring — classify every tracked file (never by directory) ```bash for f in $(git ls-files dotfiles/); do rel=${f#dotfiles//}; live="$HOME/$rel" if [ -L "$live" ]; then printf 'link %-50s -> %s\n' "$rel" "$(readlink "$live")" elif [ -e "$live" ]; then printf 'REAL %-50s (NOT a link)\n' "$rel" else printf 'absent %s\n' "$rel"; fi done ``` - `REAL` = the repo copy is a fiction: live state diverged, deployment never reached it. - `absent` = tracked relic, nothing consumes it (candidate for `git rm --cached`). - Spaces in filenames break the `for` loop (`palettes/Gruber Red.json` splits into two rows). Use `git ls-files -z | tr '\0' '\n'` + `while read -r` when names can hold spaces. - Reverse direction finds untracked-but-load-bearing files: `find ~/.config/ -maxdepth 2 \( -type f -o -type l \) | while read -r p; do case "$(realpath "$p")" in $PWD/dotfiles/*) ;; *) echo "not from repo: $p";; esac; done` ## 3. Live state that must stay untracked Generated palette output and app state are expansion, not authorship. Distinguish by mtime cluster, not by name: `find ~/.local/state/ -type f -printf '%TY-%Tm-%Td %p\n'` — a same-second mass write is a generator; single later re-stamps are re-runs. Pointers a switcher script writes (e.g. `cfg/display.kdl -> desk-1-home.kdl`) are machine state too. Then check the hazard this creates: grep the entrypoint for includes of those generated files. A **non-optional** include of a correctly-untracked generated file bricks a fresh box (`include "noctalia.kdl"` with no `optional=true` = niri cannot start until the theme pipeline has run once). Report it as a fresh-box failure, not a style note. ## 4. Tracked-then-ignored debt (invisible to every normal check) ```bash git ls-files dotfiles | grep AGENTTRASH # trash committed inside the tree git check-ignore --no-index -v # does an ignore rule match it? ``` `.gitignore` patterns without an interior slash (`.AGENTTRASH/`) match at **any depth**, so the rule was fine all along — the file simply entered history *before* the rule existed, and an ignore rule never reaches an already-tracked path. Only repair: `git rm --cached ` plus moving the working copy to the root `.AGENTTRASH/` (never `rm`). `git check-ignore` without `--no-index` prints nothing for tracked paths and reads as "not ignored" — that false negative is the trap. ## 5. A census number is only valid with its command If a page prints a classifier command, every number on it must be reproducible by running that command. A row that the command does not reproduce was written from memory — wrong, not merely stale. Fix the row, and state the correction in the commit message rather than silently editing the number. ## Verification before landing `bats tests/`, `scripts/kb-lint.sh omp-docs`, `scripts/kb-coverage.py omp-docs`, and `scripts/deploy.sh --check` **from the worktree** — `--check` is read-only; never run the real deploy from a worktree, it repoints live symlinks into the worktree the heartbeat reaps.