GENERATED VIEW · PRIVATE ARCHIVE · DO NOT SERVE
RobCo Industries · Archive Museum

record.md



BUGS

bugs/crlf-page-rename/record.md

sha256 c2c988ebbe5dc2f3 · 3104 bytes · original held in the private archive

--- title: The Carriage-Return Rename status: SEALED repo: archive observed: 2026-07-20 caught_by: fresh-clone regeneration churning pages on a machine with autocrlf=true one_line: The generator content-hashes raw bytes, so a CRLF checkout didn't just add \r — it renamed every generated page and re-churned the whole museum. guard_location: .gitattributes (eol=lf, deliberately not -text); sync.ps1 writes LF, not CRLF verified: with LF pinned, a fresh clone regenerates without churn; proven from a clone, not a local re-run exhibited: true lesson: When addresses are derived from bytes, line endings are load-bearing; pin them at the source and on checkout, and prove it from a fresh clone. provenance: - commits 2f4848c (.gitattributes) and 5bc7137 (sync.ps1) - Claude memory record museum-lf-normalization - root CLAUDE.md "Archive-specific invariants" table --- ## What happened The machine's system-level gitconfig sets `core.autocrlf=true`. Because `museum/generate.mjs` names each doc page `docs/<sha256(rawBytes)[:12]>.html` — hashing its **inputs** — a CRLF checkout does not merely add `\r` characters: it **renames every generated page** and re-churns the entire museum. Separately, `sync.ps1` had been writing its generated manifests with PowerShell's default CRLF (`WriteAllLines` uses `Environment.NewLine`), which baked CRLF hashes for `_CAPTURE_MANIFEST.txt`, `_CAPTURED_STORES.txt`, `ARCHIVE_RETAINED.md`, and `AUDIT.md` into the committed museum. This is the same failure family as [[vanishing-addresses]]: an address that moves for a reason unrelated to the content's meaning. ## How it was caught A fresh clone on the autocrlf machine regenerated with the whole museum churning — addresses moving with no content change. ## The guard Repo-root `.gitattributes` forces `* text=auto eol=lf` (with `*.png`/`*.zip binary`), overriding the system `autocrlf`. It is deliberately `eol=lf` (text) and **not** `-text`: `-text` would break the line-readable publication diff the archive depends on. `sync.ps1` was rewritten to emit LF at the source, so the same rename bug cannot be reintroduced upstream of checkout. ## What the guard costs Every text file in the repo is pinned to one line ending regardless of platform convention, and both surfaces (`.gitattributes` on checkout, `sync.ps1` on write) must stay correct — two places that must agree forever. ## Containment Proven from a **fresh clone**, not a local re-run: a local working copy is already LF, so a local regen would hide the bug entirely (the same trap as [[untracked-stowaway]]). With LF pinned, a fresh clone regenerates without churn. This invariant is listed in the root `CLAUDE.md` "do not revert" table. ## Provenance Commits `2f4848c` (`.gitattributes`) and `5bc7137` (`sync.ps1`). Full account in the Claude memory record `museum-lf-normalization`. Not among the eight approved wall specimens, but recorded because it is a real, richly-documented archive defect that formalised a standing invariant; whether it joins the wall is a curation/ordering call for the generator and the owner.
STAMP · generated for RELEASE v2.8.5 commit 06e5180 (06e51801b38a) · archive input-tree hash c07fbfbdd2e1ddeb · 754 files · no wall-clock timestamp (regenerates identically when nothing changed).