Problem
Two PRs in one day burned a red CI round on the same undocumented Windows trap:
Mechanism, verified empirically on a Windows/Git Bash box:
- An NTFS clone gets
core.filemode=false set automatically at init/clone.
- Under
core.filemode=false, chmod +x never reaches the index: git add stages every newly added file as 100644 regardless of the worktree bit, and git status / git diff show nothing wrong afterward — the author cannot see the defect locally.
- The
hygiene lane's exec-bit action (ci-workflows .github/actions/exec-bit) fails any tracked file whose first two bytes are #! (extension-agnostic, not just .sh) with staged mode 100644, so the defect first surfaces as exec-bit=failure in the aggregate — after a full CI round.
- The fix is
git update-index --chmod=+x -- <path> (plus chmod +x to keep the worktree in agreement), which writes the index entry directly and works regardless of core.filemode. Verified: once the entry is 100755, a later git add of content edits preserves it under filemode=false.
Why documentation, not another gate
The trap is already enforced twice:
- CI-side: the
hygiene lane's exec-bit check is fail-closed and whole-repo, and its per-file ::error annotation already prints the exact git update-index --chmod=+x command.
- Commit-time: the source-control plugin's commit skill runs
exec-bit-check.sh --fix on every commit it makes (plugins/source-control/skills/commit/scripts/exec-bit-check.sh, rationale in plugins/source-control/skills/commit/reference/exec-bit.md).
Both red PRs were commits made without the commit skill. A third gate would either duplicate the hygiene lane inside the same CI round (no earlier feedback) or introduce local git hooks — a mechanism this repo does not use (no core.hooksPath, no husky; the enforcement idiom is CI lanes plus session-side plugin guards). Unlike #2569 / #2571, which gated a defect CI could not otherwise see, CI already catches this one; the gap is that nothing repo-level explains the symptom, the one-line fix, or why it is invisible on Windows — grep -ri "update-index" AGENTS.md CLAUDE.md docs/ .github/ returns nothing.
Proposal
Add a section to AGENTS.md (the agent-facing orientation surface, next to the existing commit-mechanics rule "Stage explicit paths") that leads with the literal symptom string exec-bit=failure so a search from the red lane lands on it, gives the two-line fix, explains the core.filemode=false invisibility, and points at the commit skill's existing check and reference doc for depth.
Problem
Two PRs in one day burned a red CI round on the same undocumented Windows trap:
100644; thehygienelane failedexec-bit=failure, andci-statusfailed with it.Mechanism, verified empirically on a Windows/Git Bash box:
core.filemode=falseset automatically at init/clone.core.filemode=false,chmod +xnever reaches the index:git addstages every newly added file as100644regardless of the worktree bit, andgit status/git diffshow nothing wrong afterward — the author cannot see the defect locally.hygienelane's exec-bit action (ci-workflows.github/actions/exec-bit) fails any tracked file whose first two bytes are#!(extension-agnostic, not just.sh) with staged mode100644, so the defect first surfaces asexec-bit=failurein the aggregate — after a full CI round.git update-index --chmod=+x -- <path>(pluschmod +xto keep the worktree in agreement), which writes the index entry directly and works regardless ofcore.filemode. Verified: once the entry is100755, a latergit addof content edits preserves it underfilemode=false.Why documentation, not another gate
The trap is already enforced twice:
hygienelane's exec-bit check is fail-closed and whole-repo, and its per-file::errorannotation already prints the exactgit update-index --chmod=+xcommand.exec-bit-check.sh --fixon every commit it makes (plugins/source-control/skills/commit/scripts/exec-bit-check.sh, rationale inplugins/source-control/skills/commit/reference/exec-bit.md).Both red PRs were commits made without the commit skill. A third gate would either duplicate the hygiene lane inside the same CI round (no earlier feedback) or introduce local git hooks — a mechanism this repo does not use (no
core.hooksPath, no husky; the enforcement idiom is CI lanes plus session-side plugin guards). Unlike #2569 / #2571, which gated a defect CI could not otherwise see, CI already catches this one; the gap is that nothing repo-level explains the symptom, the one-line fix, or why it is invisible on Windows —grep -ri "update-index" AGENTS.md CLAUDE.md docs/ .github/returns nothing.Proposal
Add a section to
AGENTS.md(the agent-facing orientation surface, next to the existing commit-mechanics rule "Stage explicit paths") that leads with the literal symptom stringexec-bit=failureso a search from the red lane lands on it, gives the two-line fix, explains thecore.filemode=falseinvisibility, and points at the commit skill's existing check and reference doc for depth.