From 64c191b1d7398869ce12b603ef07d161220bcc69 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 1 Aug 2026 08:33:09 +0800 Subject: [PATCH] fix(build): force LF for Markdown too (frontmatter parsers anchor on LF) (#3517) Co-Authored-By: Diego --- .gitattributes | 13 +++++++++++++ CONTRIBUTING.md | 14 ++++++++++---- docs/TESTING.md | 9 ++++++--- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/.gitattributes b/.gitattributes index 8be1189ba..0f1c53fab 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14,3 +14,16 @@ # through bash. `eol=lf` pins the checkout regardless of the user's # core.autocrlf setting. *.sh text eol=lf + +# Markdown gets the same pin, for a different failure mode: the frontmatter +# parsers anchor on LF. Under a CRLF checkout the opening fence becomes +# "---\r\n", which an LF-only /^---\n/ (or a startsWith("---\n")) does not +# match, so a well-formed document silently parses as having no frontmatter. +# There is no error -- the field just comes back empty. That has surfaced as +# blank skill descriptions, a fixer inserting its banner above the +# frontmatter instead of below it, resolver trigger extraction dropping +# entries, and a generated-doc freshness check reporting every line as +# drifted. The parsers stay CR-tolerant on their own merits (gbrain reads +# Markdown it does not own), but pinning this repo's own .md checkout to LF +# removes the whole class for anyone working here. +*.md text eol=lf diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49e289808..d6408cd20 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,14 +19,20 @@ The root `.gitattributes` pins `*.sh text eol=lf`, which overrides the `core.autocrlf=true` that Git for Windows installs by default. A fresh clone is correct with no extra steps. -If you cloned before that pin existed, your working copy still has the old -Windows line endings and bash will fail with `$'\r': command not found`. Refresh -it once, from the repository root: +`.gitattributes` pins `*.md text eol=lf` for the same reason. The frontmatter +readers anchor on a `---` fence followed by a Unix line ending, so a CRLF +checkout makes a well-formed document parse as having no frontmatter. That +failure is silent: no error, the field just comes back empty. + +If you cloned before either pin existed, your working copy still has the old +Windows line endings. Bash will fail with `$'\r': command not found`, and +frontmatter will read as absent. Refresh it once, from the repository root: ```bash git rm --cached -r . -q git reset --hard -bash -n scripts/run-unit-parallel.sh # silence means bash can read the scripts +bash -n scripts/run-unit-parallel.sh # silence means bash can read the scripts +git ls-files --eol -- '*.md' | grep -c w/crlf # 0 means Markdown is clean ``` Every `check:*` entry in `package.json` invokes its script as `bash scripts/.sh` diff --git a/docs/TESTING.md b/docs/TESTING.md index c908eec24..a4e3434f2 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -32,9 +32,12 @@ CI, macOS) rejects CRLF and dies on the script's first meaningful line; the Cygw bash that ships with Git for Windows tolerates it, so a green local run is not by itself evidence that a script is CRLF-clean. The root `.gitattributes` pins `*.sh text eol=lf`, which overrides the -`core.autocrlf=true` default that Git for Windows installs. Working copies cloned -before that pin need a one-time `git rm --cached -r . -q && git reset --hard` to -pick it up; see the Windows section of `CONTRIBUTING.md`. +`core.autocrlf=true` default that Git for Windows installs. It pins `*.md` the +same way, because the frontmatter readers anchor on a `---` fence followed by a +Unix line ending and a CRLF checkout makes a document parse as having no +frontmatter, silently. Working copies cloned +before those pins need a one-time `git rm --cached -r . -q && git reset --hard` to +pick them up; see the Windows section of `CONTRIBUTING.md`. Wallclock figures in the table above are from a Mac dev box. Windows is substantially slower because each check pays full process-creation cost, and three