Problem
#15300 did not finish the job, and I want that on the record before anyone relies on its claim. It made check-chore-sync.mjs merge-aware, and that guard now correctly passes a dev-merge — verified live on grace/15272-throttle-producer immediately after #15300 merged (38a7285973): the sync-data guard no longer appears in the failure set.
The merge is still refused. check-whitespace.mjs has the identical merge-blindness:
Trailing whitespace found in resources/content/discussions/chunk-1/discussion-15173.md:24
… (and :25 :26 :27 :28 :184 :185 :479)
That file is pipeline-authored and arrived with the merge. The branch never touched it. Trailing whitespace is normal in GitHub discussion bodies — it is how markdown encodes a hard line break — so the sync pipeline legitimately produces content this hook legitimately rejects.
The evidence is in the pipeline's own comment
.github/workflows/data-sync-pipeline.yml:69:
<h1 class="neo-h1" data-record-id="4">Commit (neo repo). --no-verify: generated data fails whitespace hooks. NEO_SKIP_TICKET_ARCHAEOLOGY:</h1>
<h1 class="neo-h1" data-record-id="5">the explicit archaeology-gate exemption for the generated-data class (declares intent + future-proofs;</h1>
<h1 class="neo-h1" data-record-id="6">co-exists with --no-verify, which these commits still need for whitespace).</h1>
NEO_SKIP_TICKET_ARCHAEOLOGY=1 git commit --no-verify -m "chore(data): Hourly data sync pipeline update [skip ci]"
The pipeline knows its data fails the whitespace hook and escapes with --no-verify. It can: it is a trusted CI job committing only generated data. A maintainer merging dev cannot — --no-verify is banned here and also skips the AiConfig test-mutation safety lint.
So the pipeline's escape hatch does not extend to anyone who later inherits its commits through a merge, which is everyone.
Scope: this is a hook-layer property, not two isolated bugs
package.json lint-staged runs check-whitespace.mjs on the * glob — every staged file, of every type. A merge stages everything it brings in. So any hook on a broad glob inherits the same defect; check-chore-sync and check-whitespace are the two that actually fire on resources/content/** today.
The *.mjs hooks (check-shorthand, check-jsdoc-types, check-ticket-archaeology, check-block-alignment, check-parse) are the same shape but currently latent for sync data — they don't match .md/.json. They are not latent for a dev-merge that carries someone else's .mjs drift, which is how I hit check-block-alignment on revalidationSweep.mjs earlier today (a file I never touched).
Acceptance Criteria
Out of scope
- The
*.mjs hooks — latent for sync data, and I'd rather fix them when a real merge trips one than speculatively. check-block-alignment on revalidationSweep.mjs is a live instance, but it arose from an entangled duplicate-SHA merge that no longer applies post-#15300; re-verify before widening.
- Loosening
check-whitespace for resources/content/** generally. That would stop catching drift a maintainer authors there. The merge-inheritance distinction is the correct axis, not the path.
Why this is filed rather than folded into #15300
#15300 is merged and its diff is correct as far as it goes. Re-opening it to widen scope would be worse than a narrow successor: its ACs and evidence are about the sync guard, and this is a different script with its own fixtures. The honest cost is that #15300's PR body claims it "unblocks dev-refresh for every feature branch" — that claim is wrong, and this ticket is the correction. #15281's roster join is still blocked behind it.
Evidence
- Live reproduction:
git merge origin/dev on grace/15272-throttle-producer post-#15300 → sync guard passes, check-whitespace fails on 8 lines of pipeline-authored discussion-15173.md.
.github/workflows/data-sync-pipeline.yml:69 — the pipeline's own --no-verify for exactly this hook.
package.json lint-staged — check-whitespace is on the * glob.
- #15300 (
38a7285973) — the discriminator to reuse.
Related: #15299 (the first half) · #15281 (still blocked)
Problem
#15300 did not finish the job, and I want that on the record before anyone relies on its claim. It made
check-chore-sync.mjsmerge-aware, and that guard now correctly passes a dev-merge — verified live ongrace/15272-throttle-producerimmediately after #15300 merged (38a7285973): the sync-data guard no longer appears in the failure set.The merge is still refused.
check-whitespace.mjshas the identical merge-blindness:That file is pipeline-authored and arrived with the merge. The branch never touched it. Trailing whitespace is normal in GitHub discussion bodies — it is how markdown encodes a hard line break — so the sync pipeline legitimately produces content this hook legitimately rejects.
The evidence is in the pipeline's own comment
.github/workflows/data-sync-pipeline.yml:69:<h1 class="neo-h1" data-record-id="4">Commit (neo repo). --no-verify: generated data fails whitespace hooks. NEO_SKIP_TICKET_ARCHAEOLOGY:</h1> <h1 class="neo-h1" data-record-id="5">the explicit archaeology-gate exemption for the generated-data class (declares intent + future-proofs;</h1> <h1 class="neo-h1" data-record-id="6">co-exists with --no-verify, which these commits still need for whitespace).</h1> NEO_SKIP_TICKET_ARCHAEOLOGY=1 git commit --no-verify -m "chore(data): Hourly data sync pipeline update [skip ci]"The pipeline knows its data fails the whitespace hook and escapes with
--no-verify. It can: it is a trusted CI job committing only generated data. A maintainer merging dev cannot —--no-verifyis banned here and also skips the AiConfig test-mutation safety lint.So the pipeline's escape hatch does not extend to anyone who later inherits its commits through a merge, which is everyone.
Scope: this is a hook-layer property, not two isolated bugs
package.jsonlint-staged runscheck-whitespace.mjson the*glob — every staged file, of every type. A merge stages everything it brings in. So any hook on a broad glob inherits the same defect;check-chore-syncandcheck-whitespaceare the two that actually fire onresources/content/**today.The
*.mjshooks (check-shorthand,check-jsdoc-types,check-ticket-archaeology,check-block-alignment,check-parse) are the same shape but currently latent for sync data — they don't match.md/.json. They are not latent for a dev-merge that carries someone else's.mjsdrift, which is how I hitcheck-block-alignmentonrevalidationSweep.mjsearlier today (a file I never touched).Acceptance Criteria
check-whitespace.mjsdoes not fail a file whose staged content is inherited fromMERGE_HEAD— reuse #15300's discriminator semantics (git diff --cached --name-only MERGE_HEAD⇒ diverged ⇒ authored ⇒ still checked). A file hand-edited during the merge is still authoring and still fails.MERGE_HEADor a failed diff ⇒ treat every staged file as authored.inheritedFromMerge()helper both consume, or state why two copies are correct.Out of scope
*.mjshooks — latent for sync data, and I'd rather fix them when a real merge trips one than speculatively.check-block-alignmentonrevalidationSweep.mjsis a live instance, but it arose from an entangled duplicate-SHA merge that no longer applies post-#15300; re-verify before widening.check-whitespaceforresources/content/**generally. That would stop catching drift a maintainer authors there. The merge-inheritance distinction is the correct axis, not the path.Why this is filed rather than folded into #15300
#15300 is merged and its diff is correct as far as it goes. Re-opening it to widen scope would be worse than a narrow successor: its ACs and evidence are about the sync guard, and this is a different script with its own fixtures. The honest cost is that #15300's PR body claims it "unblocks dev-refresh for every feature branch" — that claim is wrong, and this ticket is the correction. #15281's roster join is still blocked behind it.
Evidence
git merge origin/devongrace/15272-throttle-producerpost-#15300 → sync guard passes,check-whitespacefails on 8 lines of pipeline-authoreddiscussion-15173.md..github/workflows/data-sync-pipeline.yml:69— the pipeline's own--no-verifyfor exactly this hook.package.jsonlint-staged —check-whitespaceis on the*glob.38a7285973) — the discriminator to reuse.Related: #15299 (the first half) · #15281 (still blocked)