From bbabdd0448a6f2c46415745b1683262f37a353f4 Mon Sep 17 00:00:00 2001 From: Guillaume Tauzin <4648633+gtauzin@users.noreply.github.com> Date: Sun, 26 Jul 2026 17:20:22 +0200 Subject: [PATCH] docs(skill): record the conflicted-.gitignore hazard from the v0.38.0 fan-out yohou's .gitignore came out unmerged because the project had added reviews/ to the same block the template removed. Three independent signals reported the repo clean and all three were wrong: copier exited 0, the .rej sweep found nothing, and git status did not list the newly-delivered CLAUDE.md -- because the unresolved .gitignore still contained CLAUDE.md, so git treated the delivered file as ignored. The file was on disk throughout. .gitignore is the one file whose own conflicted content changes what git status reports, so it can conceal the delivery being verified. The skill now says to sweep for conflict markers as a first-class check rather than a follow-up, and not to treat git status as evidence when .gitignore is among the changed files. Also corrects the _skip_if_exists list, which had not been updated for CLAUDE.md. --- .claude/skills/fan-out-to-packages/SKILL.md | 26 ++++++++++++++++++++- .github/skills/fan-out-to-packages/SKILL.md | 26 ++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/.claude/skills/fan-out-to-packages/SKILL.md b/.claude/skills/fan-out-to-packages/SKILL.md index d6a0358..010f793 100644 --- a/.claude/skills/fan-out-to-packages/SKILL.md +++ b/.claude/skills/fan-out-to-packages/SKILL.md @@ -147,7 +147,31 @@ Group a section index under `##` headings only when it is big enough to need it stub, content surviving only in a `.rej` nobody reads. A **whitespace-only** template change replaced a 244-line curated tutorial with a 74-line placeholder in one release. - `_skip_if_exists` now covers the 4 logos, `docs/index.md`, - `docs/pages/tutorials/getting-started.md` and `docs/pages/examples/index.md`. + `docs/pages/tutorials/getting-started.md`, `docs/pages/examples/index.md` and `CLAUDE.md`. + +**A conflicted `.gitignore` hides the delivery you are verifying.** Fired on yohou in the +v0.38.0 fan-out. The project had added `reviews/` to the same block the template removed, +so `.gitignore` came out unmerged. Three independent signals said the repo was clean: + +```text +copier update -> exit 0 +.rej sweep -> no files +git status -> the newly-delivered CLAUDE.md not listed +``` + +All three wrong. The unresolved `.gitignore` still contained `CLAUDE.md`, so git treated +the delivered file as **ignored** and omitted it from `status` -- while the file sat on disk +the whole time. Copier writes markers in place and leaves the file `UU`; it does not exit +non-zero and produces no `.rej` for that path. `.gitignore` is the one file whose own +conflicted content changes what `git status` reports, so it can conceal the delivery being +checked. + +- Sweep for conflict markers as a **first-class check**, equal to the `.rej` sweep, not as + a follow-up. `grep -rlE '^(<<<<<<<|>>>>>>>)' --exclude-dir=.git .` +- When `.gitignore` is among the changed files, **`git status` is not evidence of what was + delivered.** Verify by path on disk and `git ls-files --error-unmatch `. +- Resolve by keeping **both** intents. Here: the template's removal of its block, and the + project's own `reviews/` entry moved to a section of its own with a comment saying why. - **`mkdocs.yml` is NOT protected, and a nav-touching release clobbers it every time.** Not a risk — a certainty. v0.26.0 removed one nav line and the clobber fired in **7 of 7** repos: 227 curated nav leaves collapsed to 87. Once a repo's nav has diverged, the hunk diff --git a/.github/skills/fan-out-to-packages/SKILL.md b/.github/skills/fan-out-to-packages/SKILL.md index d6a0358..010f793 100644 --- a/.github/skills/fan-out-to-packages/SKILL.md +++ b/.github/skills/fan-out-to-packages/SKILL.md @@ -147,7 +147,31 @@ Group a section index under `##` headings only when it is big enough to need it stub, content surviving only in a `.rej` nobody reads. A **whitespace-only** template change replaced a 244-line curated tutorial with a 74-line placeholder in one release. - `_skip_if_exists` now covers the 4 logos, `docs/index.md`, - `docs/pages/tutorials/getting-started.md` and `docs/pages/examples/index.md`. + `docs/pages/tutorials/getting-started.md`, `docs/pages/examples/index.md` and `CLAUDE.md`. + +**A conflicted `.gitignore` hides the delivery you are verifying.** Fired on yohou in the +v0.38.0 fan-out. The project had added `reviews/` to the same block the template removed, +so `.gitignore` came out unmerged. Three independent signals said the repo was clean: + +```text +copier update -> exit 0 +.rej sweep -> no files +git status -> the newly-delivered CLAUDE.md not listed +``` + +All three wrong. The unresolved `.gitignore` still contained `CLAUDE.md`, so git treated +the delivered file as **ignored** and omitted it from `status` -- while the file sat on disk +the whole time. Copier writes markers in place and leaves the file `UU`; it does not exit +non-zero and produces no `.rej` for that path. `.gitignore` is the one file whose own +conflicted content changes what `git status` reports, so it can conceal the delivery being +checked. + +- Sweep for conflict markers as a **first-class check**, equal to the `.rej` sweep, not as + a follow-up. `grep -rlE '^(<<<<<<<|>>>>>>>)' --exclude-dir=.git .` +- When `.gitignore` is among the changed files, **`git status` is not evidence of what was + delivered.** Verify by path on disk and `git ls-files --error-unmatch `. +- Resolve by keeping **both** intents. Here: the template's removal of its block, and the + project's own `reviews/` entry moved to a section of its own with a comment saying why. - **`mkdocs.yml` is NOT protected, and a nav-touching release clobbers it every time.** Not a risk — a certainty. v0.26.0 removed one nav line and the clobber fired in **7 of 7** repos: 227 curated nav leaves collapsed to 87. Once a repo's nav has diverged, the hunk