chore(tooling): exclude nested Claude Code worktrees from local quality gates - #262
Open
Dmitrii Ostasevich (kwinto) wants to merge 1 commit into
Open
Dmitrii Ostasevich (kwinto) wants to merge 1 commit into
Dmitrii Ostasevich (kwinto) wants to merge 1 commit into
Conversation
…ty gates Nested git worktrees under .claude/worktrees/<name> are full checkouts of this repo, each with its own src/, test/ and node_modules. The local gates have no way to know they are not part of the tree under inspection, so with stray worktrees on disk: - `npm run lint:a11y` reported 42 errors / 10 warnings, every one of them from a file inside a nested worktree and none from src/ or test/. - `npm test` collected the nested specs on top of the real suite. Those worktrees' node_modules supply a second React copy, so every collected rendering spec died with "Cannot read properties of null (reading 'useContext')". The root-anchored `test/dom-compat.spec.tsx` exclude also misses the nested copies, so dom-compat leaked into the default run. CI never sees any of this — it does a fresh checkout with no nested worktrees — so the failures were pure local noise that buries real findings. Git already skips these paths via .git/info/exclude, but that file is local to one clone and no linter reads it. Ignore .claude/worktrees/ in both ESLint configs, both Vitest configs and .prettierignore, and commit the .gitignore entry so the exclusion travels with the repo instead of living in one developer's .git/info/exclude. Scoped to worktrees/ rather than all of .claude/ so the tracked agents/commands/skills content stays in scope exactly as it is on CI. Verified with two real nested worktrees on disk (89 extra lintable files, 16 extra specs): lint:a11y, test:a11y and `prettier --check .` all exit 0 and Vitest collects exactly the 17 real test files. Coverage is unchanged on a CI-shaped tree — the linted file list is byte-identical to before (97 files: 66 src/, 24 test/, 7 root). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Contributor
There was a problem hiding this comment.
Pull request overview
Adjusts local lint/test/format file-selection to ignore nested Claude Code git worktrees under .claude/worktrees/**, preventing local quality gates from picking up duplicate repo checkouts (and their node_modules) while keeping CI coverage unchanged.
Changes:
- Exclude
.claude/worktrees/**from Vitest default runs (and dom-compat config) to prevent duplicate test collection. - Add
.claude/worktrees/**to ESLint flat-config ignores (both main + a11y gate) to avoid stray-worktree lint noise. - Ignore
.claude/worktrees/for Prettier and git status via.prettierignoreand.gitignore.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
vitest.dom-compat.config.ts |
Extends Vitest default excludes to also skip nested .claude/worktrees/** during dom-compat runs. |
vite.config.ts |
Adds **/.claude/worktrees/** to test.exclude (and refactors exclude array for commented entries). |
eslint.config.js |
Adds .claude/worktrees/** to flat-config ignore patterns for standard linting. |
eslint.a11y.config.js |
Adds .claude/worktrees/** to ignore list for the a11y-only ESLint gate. |
.prettierignore |
Ignores .claude/worktrees/ to prevent formatting checks from traversing nested worktrees. |
.gitignore |
Ignores .claude/worktrees/ so nested worktrees don’t appear as untracked files. |
Open
10 tasks
Sushmitha Sekar (sushmi21)
approved these changes
Sep 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nested git worktrees under
.claude/worktrees/<name>are full checkouts of this repo, each with its ownsrc/,test/andnode_modules. The local quality gates have no way to know they aren't part of the tree under inspection, so with stray worktrees on disk they produce large numbers of failures that CI never sees (CI does a fresh checkout with no nested worktrees).Observed with three stray worktrees present:
npm run lint:a11y→ 42 errors, 10 warnings, every one of them from a file inside a nested worktree. Zero fromsrc/ortest/.npm test→ collected the nested specs on top of the real suite. Those worktrees'node_modulessupply a second React copy, so every collected rendering spec died withCannot read properties of null (reading 'useContext')(Audio, Avatar, Datepicker, DatepickerA11y, Gallery, List, Text, Video,a11y.spec× N worktrees). Zero real failures.Git already skips these paths, but only via
.git/info/exclude— local to one clone, and no linter reads it. This PR moves the exclusion into the repo's own config so it travels with the checkout.What changed
eslint.a11y.config.js".claude/worktrees/**"added toignoreseslint.config.jsignoresvite.config.ts"**/.claude/worktrees/**"added totest.exclude; array reflowed so each pattern carries its own commentvitest.dom-compat.config.tsexcludechanged fromconfigDefaults.excludeto[...configDefaults.exclude, "**/.claude/worktrees/**"].prettierignore.claude/worktrees/added.gitignore.claude/worktrees/added under the existing "Claude Code worktrees" blockTwo deliberate choices worth a reviewer's attention:
worktrees/, not all of.claude/**. The tracked.claude/content (agents/,commands/,skills/wcag-component/) stays in scope exactly as it is on CI, so a future.ts/.tsxadded under a skill is still linted locally and on CI alike. Ignoring all of.claude/would have created the same local↔CI divergence this PR is fixing, just in the other direction..gitignoreline is included even though.git/info/excludealready covers it locally. Without it, a teammate who creates a nested worktree sees it as untracked ingit status, andprettier --check .picks it up (Prettier 3 reads.gitignoreby default). One-line addition in the block that already says "Claude Code worktrees".The dom-compat side is worth calling out: the existing
test/dom-compat.spec.tsxexclude is root-anchored, so it does not match a nested worktree's copy —dom-compat.spec.tsxwas leaking into the defaultnpm testrun and failing on an unresolvable../dist/chat-components.jsimport. The new pattern closes that too.Success criteria
npm run lint:a11yreports only findings fromsrc/,test/and root config files, never from.claude/worktrees/, even with nested worktrees on disknpm testcollects only the repo's own 17 test files, never a nested worktree's copies, and nevertest/dom-compat.spec.tsxnpm run test:dom-compatstill collects exactlytest/dom-compat.spec.tsxnpx prettier --check .ignores nested worktreesgit statusstays clean when a nested worktree exists, for any clone (not just ones with a hand-edited.git/info/exclude)src/andtest/still checkedHow to test
git worktree add --detach .claude/worktrees/verify-a HEADandgit worktree add --detach .claude/worktrees/verify-b HEAD~1. That adds 89 lintable files and 16 spec files that don't belong to the tree under test.npm run lint:a11y→ exits 0.npm run test:a11y→ exits 0, 44/44.npx prettier --check .→ exits 0.npx vitest list --filesOnly→ exactly the 17 real files undertest/, nothing under.claude/, nodom-compat.npx vitest list --filesOnly --config vitest.dom-compat.config.ts→ exactlytest/dom-compat.spec.tsx.git stashthe config changes and repeat step 3 — collection jumps to 31 files andvitest listerrors out on the nested copies.git worktree remove --force .claude/worktrees/verify-a && git worktree remove --force .claude/worktrees/verify-b && git worktree prune.Coverage-parity check (this is the one that matters for CI): with no nested worktrees present, dump the file list ESLint actually reports under the old config and the new one and diff them. I ran this and the lists are byte-identical — 97 files (66
src/, 24test/, 7 root). Vitest collects the same 17 files either way.Security
Config-only change to lint/test/format file-selection globs. No runtime, library or rendered-output code is touched, and the checks' rule sets are unchanged — only which paths they walk.
Accessibility (WCAG 2.2 AA)
test/fixtures/message-cases.ts— n/a, no new message types<Component>A11y.spec.tsx) added/updated — n/a, no component or interaction changesNo change to rendered DOM, so the DOM-compat contract is untouched and no release-notes "Accessibility changes" entry is needed. The a11y gates keep their exact coverage (verified above): the point of the change is that
lint:a11yfailures now mean something again instead of being buried under 42 findings from other branches.Additional considerations
Local runs get faster as a side effect —
npm testno longer transforms and collects a duplicate copy of the suite per stray worktree. CI timing is unaffected.Documentation Considerations
Nothing for the docs team — internal tooling only. The rationale lives in comments next to each ignore entry, and the
.gitignoreblock cross-references the four gate configs so the set stays discoverable if one is ever edited in isolation.Reviewer note: a Node-version-dependent test failure (not caused by this PR)
npm testexits 1 locally on Node 26, on one failure unrelated to this change:test/sanitize.spec.ts›sanitizeHTMLWithConfig > iframe srcdoc XSS Prevention (Zendesk Infosec Report) > preserves valid content while stripping dangerous parts in mixed srcdoc.It fails identically with the pristine
vite.config.ts, and it fails onmain/release/0.78.0in every worktree, so it is not attributable to this PR. CI is green on this branch (build (22.x)passes), which confirms it is environment-dependent, not repo debt:package.jsondeclaresengines: >=22.1.0but CI only tests22.x, so a developer on Node 24/26 hits a rednpm teston a clean checkout ofmain. Worth its own ticket — either pin the supported range or fix the srcdoc expectation for newer jsdom/DOMPurify. Out of scope here.🤖 Generated with Claude Code