diff --git a/.agents/skills/comment-and-doc-style/references/line-endings.md b/.agents/skills/comment-and-doc-style/references/line-endings.md index 7726adede..ec32e16a0 100644 --- a/.agents/skills/comment-and-doc-style/references/line-endings.md +++ b/.agents/skills/comment-and-doc-style/references/line-endings.md @@ -113,8 +113,10 @@ JSONC (it has `//` comments), so strip them before JSON-parsing it. Editing CRLF files programmatically with a regex has a sharper trap: `.` matches `\r`, so a captured line keeps its carriage return and rejoining with `\r\n` yields `CRCRLF`. A text-mode -rewrite has the mirror failure, silently flattening CRLF to LF. Prefer line-based edits -(`splitlines(keepends=True)`) or literal replacement over regex reassembly. In Python the -text-mode failure is the default: `Path.read_text()` decodes through universal newlines and -`write_text()` writes `\n` back, so a read-edit-write round trip flattens the whole file while the -edit itself looks correct. Pass `newline=''` to both, or work in bytes. +rewrite has the mirror failure, silently rewriting every line ending to the host's own. Prefer +line-based edits (`splitlines(keepends=True)`) or literal replacement over regex reassembly. In +Python the text-mode failure is the default. `Path.read_text()` decodes through universal +newlines, and `write_text()` translates each `\n` to `os.linesep`. A read-edit-write round trip +therefore rewrites every ending in the file while the edit itself looks correct. Work in bytes, or +use `open()` with `newline=''` on both the read and the write. `Path.read_text()` is no substitute, +since it accepts `newline` only on Python 3.13 and newer and raises `TypeError` below it. diff --git a/.claude-plugin/fleet-skills/.source-digests/comment-and-doc-style b/.claude-plugin/fleet-skills/.source-digests/comment-and-doc-style index 6e093d6ee..316a04ef8 100644 --- a/.claude-plugin/fleet-skills/.source-digests/comment-and-doc-style +++ b/.claude-plugin/fleet-skills/.source-digests/comment-and-doc-style @@ -1 +1 @@ -db8fb1a840099988 +d0cc83be0784f597 diff --git a/.claude-plugin/fleet-skills/skills/comment-and-doc-style/references/line-endings.md b/.claude-plugin/fleet-skills/skills/comment-and-doc-style/references/line-endings.md index 7726adede..ec32e16a0 100644 --- a/.claude-plugin/fleet-skills/skills/comment-and-doc-style/references/line-endings.md +++ b/.claude-plugin/fleet-skills/skills/comment-and-doc-style/references/line-endings.md @@ -113,8 +113,10 @@ JSONC (it has `//` comments), so strip them before JSON-parsing it. Editing CRLF files programmatically with a regex has a sharper trap: `.` matches `\r`, so a captured line keeps its carriage return and rejoining with `\r\n` yields `CRCRLF`. A text-mode -rewrite has the mirror failure, silently flattening CRLF to LF. Prefer line-based edits -(`splitlines(keepends=True)`) or literal replacement over regex reassembly. In Python the -text-mode failure is the default: `Path.read_text()` decodes through universal newlines and -`write_text()` writes `\n` back, so a read-edit-write round trip flattens the whole file while the -edit itself looks correct. Pass `newline=''` to both, or work in bytes. +rewrite has the mirror failure, silently rewriting every line ending to the host's own. Prefer +line-based edits (`splitlines(keepends=True)`) or literal replacement over regex reassembly. In +Python the text-mode failure is the default. `Path.read_text()` decodes through universal +newlines, and `write_text()` translates each `\n` to `os.linesep`. A read-edit-write round trip +therefore rewrites every ending in the file while the edit itself looks correct. Work in bytes, or +use `open()` with `newline=''` on both the read and the write. `Path.read_text()` is no substitute, +since it accepts `newline` only on Python 3.13 and newer and raises `TypeError` below it. diff --git a/.github/skills/comment-and-doc-style/references/line-endings.md b/.github/skills/comment-and-doc-style/references/line-endings.md index 7726adede..ec32e16a0 100644 --- a/.github/skills/comment-and-doc-style/references/line-endings.md +++ b/.github/skills/comment-and-doc-style/references/line-endings.md @@ -113,8 +113,10 @@ JSONC (it has `//` comments), so strip them before JSON-parsing it. Editing CRLF files programmatically with a regex has a sharper trap: `.` matches `\r`, so a captured line keeps its carriage return and rejoining with `\r\n` yields `CRCRLF`. A text-mode -rewrite has the mirror failure, silently flattening CRLF to LF. Prefer line-based edits -(`splitlines(keepends=True)`) or literal replacement over regex reassembly. In Python the -text-mode failure is the default: `Path.read_text()` decodes through universal newlines and -`write_text()` writes `\n` back, so a read-edit-write round trip flattens the whole file while the -edit itself looks correct. Pass `newline=''` to both, or work in bytes. +rewrite has the mirror failure, silently rewriting every line ending to the host's own. Prefer +line-based edits (`splitlines(keepends=True)`) or literal replacement over regex reassembly. In +Python the text-mode failure is the default. `Path.read_text()` decodes through universal +newlines, and `write_text()` translates each `\n` to `os.linesep`. A read-edit-write round trip +therefore rewrites every ending in the file while the edit itself looks correct. Work in bytes, or +use `open()` with `newline=''` on both the read and the write. `Path.read_text()` is no substitute, +since it accepts `newline` only on Python 3.13 and newer and raises `TypeError` below it. diff --git a/tests/test_repo_gate.py b/tests/test_repo_gate.py index 3421e9bf8..c3547f869 100755 --- a/tests/test_repo_gate.py +++ b/tests/test_repo_gate.py @@ -66,10 +66,12 @@ def test_the_table_holds_every_check_the_cli_offers(self) -> None: self.assertGreaterEqual(len(repo_gate.CHECKS), 3) def test_the_patterns_compile_and_carry_no_invisible_characters(self) -> None: - """A shell heredoc turns a backslash escape into a control character no diff shows.""" + """printf, echo -e, and $'...' turn an escape into a control character no diff shows.""" for name in ("USES", "PIN", "WORKFLOW", "HTTP_STATUS"): with self.subTest(pattern=name): - self.assertTrue(re.compile(getattr(repo_gate, name).pattern)) + pattern = getattr(repo_gate, name).pattern + self.assertTrue(re.compile(pattern)) + self.assertTrue(pattern.isascii() and pattern.isprintable()) for action in repo_gate.SHA_EXCEPTIONS: with self.subTest(exception=action): self.assertTrue(action.isascii() and action.isprintable())