fix(ci): root-cleanliness guards assumed .git is always a directory - #291
Merged
Conversation
…ectory
`git push` crashed inside the pre-push hook's repo-optimization step, in this
worktree specifically: `fs.mkdirSync ENOTDIR '.../recursing-carson-721318/.git/
evolith-quarantine/69e8ec9d'`. `.git` at a worktree's root is a plain text
redirect file (`gitdir: <real-gitdir>`), not a directory, and
02-optimize-repo.mjs assumed otherwise in two places:
1. `path.join(root, ".git", "evolith-quarantine")` assumed `.git` was always a
writable directory to build a subtree under. Fixed by resolving the real
git-dir via `git rev-parse --git-dir` -- which is `.git` in a normal
checkout and the per-worktree directory under `.git/worktrees/<name>` here
-- with `path.resolve`, not `path.join`: `--git-dir` prints a RELATIVE path
in a normal checkout but an ABSOLUTE one in a worktree, and `path.join`
would have mangled the absolute case by concatenating it onto `root`.
2. Fixing (1) surfaced a worse defect, verified live: once the crash stopped,
the quarantine loop saw `.git` itself as an unrecognised untracked FILE
(only `allowedDirectories` lists it, not `allowedFiles`) and moved it into
quarantine -- severing this worktree from git entirely. Recoverable, since
quarantine moves rather than deletes, but confirmed by reproducing it and
then restoring `.git` by hand before writing the real fix: exclude `.git`
unconditionally, by name, before the directory/file allowlist split.
The identical root cause was independently present in
03-validate-root-cleanliness.mjs, a separate script with its own duplicated
allowlist -- confirmed failing in this same worktree ("Unauthorized file
found in root: .git") before the same by-name exclusion fixed it too. Lower
blast radius than the pre-push script (CI always checks out fresh, never a
worktree, so this specific guard never hits it there), but the same class of
bug and already fully understood, so fixed alongside it.
Also added two legitimately-tracked root files the first script's allowlist
was missing (evolith.yaml, commitlint.config.mjs), clearing an unrelated
warning this same run surfaced.
Re-verified: both scripts pass clean in this worktree (0 quarantined, 32 root
entries inspected), 01-validate-docs (1491 files) and 08-validate-tracking
(635 gaps, 577 closure records) unaffected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📊 Bilingual Coverage ImpactPR Changes
Repository Coverage
To create skeletons: node .harness/scripts/generate-es-skeleton.mjs <file.md>Generated by GitHub Actions |
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.
Summary
.gitat a git-worktree root is a plain redirect file, not a directory — two guards assumed otherwise and broke in a worktree checkout:02-optimize-repo.mjs(the pre-push hook's cleanup step, which crashed withENOTDIR, and once patched past that, quarantined.gititself, severing the worktree from git) and03-validate-root-cleanliness.mjs(independently, same root cause, own duplicated allowlist)..gitunconditionally by name before the directory/file allowlist check.02-optimize-repo.mjsalso resolves the real writable git-dir viagit rev-parse --git-dir(path.resolve, notpath.join, since that command prints an absolute path in a worktree) instead of assuming.gititself is where the quarantine subtree lives.evolith.yaml,commitlint.config.mjs) that were missing from02-optimize-repo.mjs's allowlist, clearing an unrelated warning noticed along the way.actions/checkoutalways produces a normal (non-worktree) checkout, so neither guard has ever hit this there. This is a local-development-in-a-worktree fix.Test plan
node .harness/scripts/ci/02-optimize-repo.mjs— 0 quarantined,.gituntouched,git log/git statusstill functional afterwardnode .harness/scripts/ci/03-validate-root-cleanliness.mjs— passes (32 root entries inspected)node .harness/scripts/ci/01-validate-docs.mjs— 1491 files, unaffectednode .harness/scripts/ci/08-validate-tracking.mjs— 635 gaps, 577 closure records, unaffected🤖 Generated with Claude Code