Skip to content

Stop yamllint and markdownlint linting other sessions' worktrees - #316

Merged
Gerrrt merged 1 commit into
mainfrom
gerrrt/lint-ignore-claude-worktrees
Sep 4, 2026
Merged

Stop yamllint and markdownlint linting other sessions' worktrees#316
Gerrrt merged 1 commit into
mainfrom
gerrrt/lint-ignore-claude-worktrees

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Sep 4, 2026

Copy link
Copy Markdown
Owner

make validate ended in validation failed on the deploy host for a completely clean change. Every finding was inside .claude/worktrees/<branch>/ — another Claude Code session's git worktree, which is an entire second checkout of this repository. That path is gitignored (.gitignore:72) and neither linter reads .gitignore, so CI never reproduces it.

Green where nothing runs and red where everything does is the wrong way round. It is the failure mode this repo already names twice — the deleted .gitleaksignore "was an acknowledgement, not a fix, and it existed because a CI job that is permanently red for a known reason gets ignored", and lint.sh's editorconfig-checker comment records the same shape when the checker walked the tree and found rendered secrets.

Why the existing ignore entries did not already cover it

Worth being precise about, because it looks like they should. Patterns containing a slash are anchored to the repository root the way .gitignore anchors them, so secrets/*.sops.yaml does not match .claude/worktrees/<branch>/secrets/observability.sops.yaml. Measured: 22 of the 23 findings were that one file's copy.

markdownlint-cli2 was exposed too

This was not obvious and I had it wrong at first. **/*.md does match dot directories, so it linted 114 files against 57 tracked. It passed only because a worktree holds a copy of this repository's own markdown — a branch under review carrying one lint error would have failed make validate on main, pointing at a file main does not have.

The other three are clear — checked, not assumed

Linter What it looks at Exposed?
yamllint walks . yes — fixed here
markdownlint-cli2 globs **/*.md, matches dot dirs yes — fixed here
shellcheck handed scripts/*.sh, one literal glob no
actionlint only <repo root>/.github/workflows-verbose shows 2 files linted with a worktree present, not 4 no
editorconfig-checker handed a git ls-files list built on the host no — this exact fix was already made for it

lint.sh's header now records all five, because "which files does this linter actually look at" is the question behind both incidents and it had no written answer. The editorconfig-checker row is called out as the shape to copy: a list built from git cannot drift, whereas these two carry an exclusion list that has to be extended by hand.

Verification

Planted a file that genuinely fails both linters under this repo's own configs, then:

  • outside .claude/fails both (so it is a valid control)
  • under .claude/worktrees/ with these entries — passes both
  • same tree with the two configs stashed — red again for both, reproducing the bug

./scripts/lint.sh passes all six checks with two worktrees checked out, and ./scripts/validate.sh ends in all checks passed with zero skips.

These entries are no-ops in CI, which has no .claude/worktrees/.

🤖 Generated with Claude Code

…ktrees

`make validate` ended in `validation failed` on the deploy host for a
completely clean change. Every finding was inside
.claude/worktrees/<branch>/ — another Claude Code session's git worktree,
which is an entire second checkout of this repository. That path is
gitignored (.gitignore:72) and neither linter reads .gitignore, so CI
never reproduces it.

Green where nothing runs and red where everything does is the wrong way
round. It is also the failure mode this repository already names twice:
the deleted .gitleaksignore "was an acknowledgement, not a fix, and it
existed because a CI job that is permanently red for a known reason gets
ignored", and lint.sh's editorconfig-checker comment records the same
shape when the checker walked the tree and found rendered secrets. An
operator who learns to dismiss a red validate has stopped reading the one
command that gates a deploy.

The existing ignore entries do not cover it, and it is worth being precise
about why: patterns containing a slash are anchored to the repository root
the way .gitignore anchors them, so `secrets/*.sops.yaml` does not match
`.claude/worktrees/<branch>/secrets/observability.sops.yaml`. Measured —
22 of the 23 findings were that one file's copy.

markdownlint-cli2 had the same exposure and was not obviously going to:
`**/*.md` matches dot directories, so it linted 114 files against 57
tracked. It passed only because a worktree holds a copy of this
repository's own markdown. A branch under review carrying one lint error
would have failed `make validate` on main, pointing at a file main does
not have.

The other three are clear, checked rather than assumed: shellcheck is
handed one literal glob, editorconfig-checker is handed a `git ls-files`
list built on the host (the fix already made for this exact class), and
actionlint reads only <repo root>/.github/workflows — `-verbose` confirms
2 files linted with a worktree present, not 4. lint.sh's header now
records all five, because "which files does this linter actually look at"
is the question behind both incidents and it had no written answer.

Verified by planting a file that fails both linters: it fails outside
.claude/, passes under .claude/worktrees/ with these entries, and the
whole tree goes red again with the two configs stashed. `make validate`
now ends in `all checks passed` with zero skips on a host with two
worktrees checked out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Gerrrt
Gerrrt merged commit be79fee into main Sep 4, 2026
3 checks passed
@Gerrrt
Gerrrt deleted the gerrrt/lint-ignore-claude-worktrees branch September 4, 2026 23:15
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