From b5237659445ebecd913fe006d7171480add2eefc Mon Sep 17 00:00:00 2001 From: LinuxDev9002 Date: Sat, 18 Jul 2026 20:13:43 -0700 Subject: [PATCH] Keep complete-source synchronization byte exact --- .../references/drafting-process.md | 2 + .../scripts/sync-source-blocks.py | 12 +++-- .../scripts/test_sync_source_blocks.py | 44 +++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/.agents/skills/write-bpf-production-tutorial/references/drafting-process.md b/.agents/skills/write-bpf-production-tutorial/references/drafting-process.md index 9feef1a..97c8767 100644 --- a/.agents/skills/write-bpf-production-tutorial/references/drafting-process.md +++ b/.agents/skills/write-bpf-production-tutorial/references/drafting-process.md @@ -10,6 +10,8 @@ Add a source-fidelity ledger. Inventory every supplied fact, number, command, co Add a code inventory that identifies the complete core files to reproduce in the tutorial. Include the kernel-mode eBPF source, user-space source, and any shared header needed to understand their contract. Keep tests, generated skeletons, vendored code, and build boilerplate as links unless the teaching mechanism depends on them. +Every inventoried source must be non-empty UTF-8 text with LF line endings and a final LF byte. A fenced Markdown block cannot represent the absence of the final newline without changing the payload, so the synchronizer rejects an empty source or a source without the final LF instead of silently changing it. Do not normalize or edit an implementation file merely to make documentation synchronization pass without explicit authorization. + ## Establish the teaching path Write one sentence for the tutorial's promise and one sentence for its reader. Map each planned section to a distinct reader question. Confirm that the path covers the problem, relevant background, whole-system flow, complete code, focused kernel explanation, brief user-space explanation, deeper concepts, compilation and execution, real output, requirements, failure and cleanup behavior, limitations, summary, and references. diff --git a/.agents/skills/write-bpf-production-tutorial/scripts/sync-source-blocks.py b/.agents/skills/write-bpf-production-tutorial/scripts/sync-source-blocks.py index 79ae677..69441c6 100755 --- a/.agents/skills/write-bpf-production-tutorial/scripts/sync-source-blocks.py +++ b/.agents/skills/write-bpf-production-tutorial/scripts/sync-source-blocks.py @@ -78,13 +78,19 @@ def render( raise ValueError(f"missing matching generated fence and {END!r} after {source_name}") language = LANGUAGES[source.suffix] - source_text = source.read_bytes().decode("utf-8") + source_bytes = source.read_bytes() + if not source_bytes: + raise ValueError(f"complete source cannot be empty: {source_name}") + if not source_bytes.endswith(b"\n"): + raise ValueError( + f"complete source must end with an LF byte for exact fenced inclusion: {source_name}" + ) + source_text = source_bytes.decode("utf-8") if "\r" in source_text: raise ValueError(f"complete source must use LF line endings: {source_name}") max_backticks = max((len(run) for run in re.findall(r"`+", source_text)), default=0) generated_fence = "`" * max(3, max_backticks + 1) - if source_text.endswith("\n"): - source_text = source_text[:-1] + source_text = source_text[:-1] rendered.extend( [ lines[index], diff --git a/.agents/skills/write-bpf-production-tutorial/scripts/test_sync_source_blocks.py b/.agents/skills/write-bpf-production-tutorial/scripts/test_sync_source_blocks.py index 8158f16..73ffb8a 100755 --- a/.agents/skills/write-bpf-production-tutorial/scripts/test_sync_source_blocks.py +++ b/.agents/skills/write-bpf-production-tutorial/scripts/test_sync_source_blocks.py @@ -214,6 +214,50 @@ class SyncSourceBlocksTest(unittest.TestCase): self.assertEqual(first_english, english.read_bytes()) self.assertEqual(first_chinese, chinese.read_bytes()) + def test_rejects_empty_source_without_changing_either_readme(self) -> None: + source = self.root / "src/lesson/tool.c" + source.write_bytes(b"") + english = self.write_readme("src/lesson/README.md") + chinese = self.write_readme("src/lesson/README.zh.md") + before = (english.read_bytes(), chinese.read_bytes()) + + result = self.run_script( + "--readme", "src/lesson/README.md", + "--readme", "src/lesson/README.zh.md", + "--write", + ) + self.assertEqual(1, result.returncode) + self.assertIn("complete source cannot be empty", result.stderr) + self.assertEqual(before, (english.read_bytes(), chinese.read_bytes())) + + def test_rejects_source_without_final_lf(self) -> None: + source = self.root / "src/lesson/tool.c" + source.write_bytes(b"int value = 1;") + self.write_readme("src/lesson/README.md") + self.write_readme("src/lesson/README.zh.md") + + result = self.run_script( + "--readme", "src/lesson/README.md", + "--readme", "src/lesson/README.zh.md", + "--write", + ) + self.assertEqual(1, result.returncode) + self.assertIn("must end with an LF byte", result.stderr) + + def test_preserves_multiple_trailing_lfs(self) -> None: + source = self.root / "src/lesson/tool.c" + source.write_bytes(b"int value = 1;\n\n\n") + english = self.write_readme("src/lesson/README.md") + self.write_readme("src/lesson/README.zh.md") + + result = self.run_script( + "--readme", "src/lesson/README.md", + "--readme", "src/lesson/README.zh.md", + "--write", + ) + self.assertEqual(0, result.returncode, result.stderr) + self.assertIn("int value = 1;\n\n\n```", english.read_text(encoding="utf-8")) + def test_requires_bilingual_pair(self) -> None: self.write_readme("src/lesson/README.md") result = self.run_script(