Refs #1. Blocks #5, #7. Do this first.
Status: diagnosed 2026-08-20, not started.
Verified: all 42 released files contain CRLF in the working tree; git config core.autocrlf is true; the repo ships no .gitattributes.
Also verified: all 42 README byte metrics match exactly once line endings are normalized to LF (42/42), as do all 42 line counts and all 42 rule counts.
Not verified: behavior on a macOS checkout, and whether adding .gitattributes produces a whitespace-only diff against the upstream remote — run git add --renormalize . && git diff --stat and inspect before committing.
The central fact
The README is correct. There is no content drift.
A naive byte comparison reports 42/42 mismatches. Every one of them is the CR bytes. actual - claim equals the file's line count in all 42 cases:
clean-code/clean-code.md claim=13851 raw=14148 delta=297 lines=297
refactoring/refactoring.md claim=17866 raw=18299 delta=433 lines=433
This is a trap, not a defect in the data. Any lint that computes byte metrics without normalizing will emit 42 false failures on every Windows checkout, and an agent trusting that output will "fix" a README that was never wrong.
This is the third instance of this defect class in the operator's estate — see the open launchpad cards hub-gitattributes-crlf and gitattributes-crlf-blob-mismatch. Consider batching the diagnosis.
Goal
Make line endings deterministic in the repo, and make every downstream tool normalize before measuring.
Decisions (settled 2026-08-20)
| # |
Decision |
Rationale |
| 1 |
Add .gitattributes with *.md text eol=lf |
The corpus is text consumed by agents and by wc; LF is the canonical form the published metrics were computed in. |
| 2 |
Do not rewrite history |
The blobs are already LF in git; only the working tree is CRLF. This is a checkout-filter problem, not a content problem. |
| 3 |
Every metric tool normalizes \r\n to \n before counting bytes |
Belt and braces: .gitattributes fixes new clones, normalization fixes existing ones. A tool that is correct only on a correctly-configured clone is not correct. |
| 4 |
Lint asserts absence of CR in released files |
Turns the invariant into a control that can fail. |
Acceptance
Verification
Re-run the diagnostic sweep. Expect 42/42 passing on all three metric families with normalization applied, and the CR check (lint check 8) flipping from FAIL to PASS.
Refs #1. Blocks #5, #7. Do this first.
The central fact
The README is correct. There is no content drift.
A naive byte comparison reports 42/42 mismatches. Every one of them is the CR bytes.
actual - claimequals the file's line count in all 42 cases:This is a trap, not a defect in the data. Any lint that computes byte metrics without normalizing will emit 42 false failures on every Windows checkout, and an agent trusting that output will "fix" a README that was never wrong.
This is the third instance of this defect class in the operator's estate — see the open launchpad cards
hub-gitattributes-crlfandgitattributes-crlf-blob-mismatch. Consider batching the diagnosis.Goal
Make line endings deterministic in the repo, and make every downstream tool normalize before measuring.
Decisions (settled 2026-08-20)
.gitattributeswith*.md text eol=lfwc; LF is the canonical form the published metrics were computed in.\r\nto\nbefore counting bytes.gitattributesfixes new clones, normalization fixes existing ones. A tool that is correct only on a correctly-configured clone is not correct.Acceptance
.gitattributespresent with*.md text eol=lfgit add --renormalize .produces no content change to any book file — verify withgit diff --statand attach the outputrules_lint.pybyte check passes on both a CRLF and an LF working tree0002 — Line endings are LF, and every metric tool normalizes before countingVerification
Re-run the diagnostic sweep. Expect 42/42 passing on all three metric families with normalization applied, and the CR check (lint check 8) flipping from FAIL to PASS.