From c266234034e6e10ad70d567306db7ce488f7f67b Mon Sep 17 00:00:00 2001 From: LinuxDev9002 Date: Sat, 18 Jul 2026 19:10:07 -0700 Subject: [PATCH] Check complete tutorial source blocks --- .../bpf-tutorial-writing-style/SKILL.md | 14 +++ .../prose-and-bilingual-checklist.md | 2 +- .../references/repository-house-style.md | 4 + .../scripts/sync-source-blocks.py | 116 ++++++++++++++++++ .../references/drafting-process.md | 2 +- .../references/repository-precedents.md | 2 +- 6 files changed, 137 insertions(+), 3 deletions(-) create mode 100755 .agents/skills/bpf-tutorial-writing-style/scripts/sync-source-blocks.py diff --git a/.agents/skills/bpf-tutorial-writing-style/SKILL.md b/.agents/skills/bpf-tutorial-writing-style/SKILL.md index 21205da..d0883d7 100644 --- a/.agents/skills/bpf-tutorial-writing-style/SKILL.md +++ b/.agents/skills/bpf-tutorial-writing-style/SKILL.md @@ -15,6 +15,8 @@ Read all three references before drafting or reviewing an advanced lesson: 2. [Repository house style](references/repository-house-style.md) defines how new lessons should match `47-cuda-events` and `49-hid` while avoiding their legacy defects. 3. [Prose and bilingual checklist](references/prose-and-bilingual-checklist.md) carries the applicable eunomia.dev prose discipline into this repository. +Use existing tutorials as living examples, not as a fixed template. Always read the `47-cuda-events` and `49-hid` English/Chinese pairs, then let the agent select one to three additional completed tutorial pairs whose subsystem, attachment type, tool shape, or target reader matches the new lesson. Read every selected file in full and record why it was chosen. Never infer house style from headings alone. + Treat verified implementation facts, real runtime evidence, and the user's current requirements as authoritative. Never change code, commands, output, versions, claims, qualifiers, failure behavior, or limitations to make prose smoother. When an older precedent conflicts with verified facts or the current rulebooks, preserve the facts and use only the precedent's useful teaching style. ## Apply the final gate @@ -22,3 +24,15 @@ Treat verified implementation facts, real runtime evidence, and the user's curre Reject a draft until it satisfies every non-diagnostic rule in the three references. Report each failure with the file, heading, smallest useful excerpt, reason, and a targeted correction. Never rewrite a whole section during review when a paragraph-level fix is enough. Paragraph length ranges are diagnostics, not quotas. A rule marked **Must fix** blocks acceptance. Preserve English and Chinese macro structure, facts, code, commands, output, examples, limitations, and references, but compose each language naturally rather than translating line by line. + +Use `scripts/sync-source-blocks.py` for every complete-source block. Mark each block with a repository-relative source path: + +````markdown + +```c +placeholder replaced by the script +``` + +```` + +Run the script with `--write` after drafting and `--check` before acceptance. Never hand-edit content between these markers. diff --git a/.agents/skills/bpf-tutorial-writing-style/references/prose-and-bilingual-checklist.md b/.agents/skills/bpf-tutorial-writing-style/references/prose-and-bilingual-checklist.md index ebe7f32..84e9fd5 100644 --- a/.agents/skills/bpf-tutorial-writing-style/references/prose-and-bilingual-checklist.md +++ b/.agents/skills/bpf-tutorial-writing-style/references/prose-and-bilingual-checklist.md @@ -37,7 +37,7 @@ This checklist carries the relevant eunomia.dev writing discipline into advanced ## Code and evidence presentation -- Present full core source exactly as it exists before excerpting it again for explanation. Never silently shorten functions, replace blocks with ellipses, translate comments, or “clean up” commands. +- Present full core source exactly as it exists before excerpting it again for explanation. Mark complete-source blocks for `scripts/sync-source-blocks.py`, then require its `--check` mode to pass. Never silently shorten functions, replace blocks with ellipses, translate comments, or “clean up” commands. - Introduce each complete file with its role in the kernel/user-space flow. After the file, select only the parts that need deeper explanation. - Explain what advanced developers need to know: program type, attach point, context restrictions, helper or kfunc semantics, map ownership, state lifetime, concurrency, verifier constraints, event/control path, error handling, and cleanup. - Keep build and run commands copyable. Explain prerequisites before the command and interpret real output after it. diff --git a/.agents/skills/bpf-tutorial-writing-style/references/repository-house-style.md b/.agents/skills/bpf-tutorial-writing-style/references/repository-house-style.md index eb7c34e..ac7b5a1 100644 --- a/.agents/skills/bpf-tutorial-writing-style/references/repository-house-style.md +++ b/.agents/skills/bpf-tutorial-writing-style/references/repository-house-style.md @@ -2,6 +2,10 @@ New advanced lessons must feel like they belong beside `src/47-cuda-events/` and `src/49-hid/`. Read both English/Chinese README pairs in full before drafting. Use `47-cuda-events` as the depth baseline for an end-to-end tool and `49-hid` as the voice and code-first teaching baseline. +After those two anchors, inspect the repository index and nearby lesson directories. Select one to three additional finished bilingual tutorials when they offer a closer domain pattern. Networking work may use `20-tc`, `41-xdp-tcpdump`, `42-xdp-loadbalancer`, or `50-tcx`. Process and security work may use `7-execsnoop`, `19-lsm-connect`, `26-sudo`, or `34-syscall`. Tracing work may use `9-runqlat`, `17-biopattern`, or `33-funclatency`. Accelerator work may use `47-cuda-events` and the closest lesson under `src/xpu/`. A reusable primitive may use the closest `src/features/` pair plus one numbered end-to-end lesson. + +These examples are routing guidance, not an allowlist. The agent may choose another completed lesson when it is a better match. It must read each selected English/Chinese pair in full, name the concrete pattern being reused, and explain why that pattern fits. Do not copy a section skeleton simply because another lesson has it. + ## Match the useful patterns - Start with a concrete situation the reader can picture. Address the reader directly when it sounds natural, then name the tool and what the reader will learn. diff --git a/.agents/skills/bpf-tutorial-writing-style/scripts/sync-source-blocks.py b/.agents/skills/bpf-tutorial-writing-style/scripts/sync-source-blocks.py new file mode 100755 index 0000000..2478f6b --- /dev/null +++ b/.agents/skills/bpf-tutorial-writing-style/scripts/sync-source-blocks.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +"""Synchronize complete-source code blocks in tutorial READMEs.""" + +from __future__ import annotations + +import argparse +import pathlib +import re +import sys + + +BEGIN_RE = re.compile(r"^$") +END = "" +LANGUAGES = { + ".c": "c", + ".h": "c", + ".py": "python", + ".rs": "rust", + ".sh": "bash", +} + + +def contained_path(root: pathlib.Path, value: str, label: str) -> pathlib.Path: + path = (root / value).resolve() + try: + path.relative_to(root) + except ValueError as error: + raise ValueError(f"{label} escapes repository root: {value}") from error + return path + + +def render(readme: pathlib.Path, root: pathlib.Path) -> tuple[str, int]: + lines = readme.read_text(encoding="utf-8").splitlines() + rendered: list[str] = [] + blocks = 0 + index = 0 + + while index < len(lines): + match = BEGIN_RE.match(lines[index]) + if not match: + rendered.append(lines[index]) + index += 1 + continue + + source_name = match.group(1) + source = contained_path(root, source_name, "source path") + if not source.is_file(): + raise ValueError(f"source file does not exist: {source_name}") + + end = index + 1 + while end < len(lines) and lines[end] != END: + end += 1 + if end == len(lines): + raise ValueError(f"missing {END!r} after {source_name}") + + language = LANGUAGES.get(source.suffix, "text") + source_text = source.read_text(encoding="utf-8").rstrip("\n") + rendered.extend( + [ + lines[index], + f"```{language}", + source_text, + "```", + END, + ] + ) + blocks += 1 + index = end + 1 + + return "\n".join(rendered) + "\n", blocks + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--repo", required=True, help="absolute repository root") + parser.add_argument( + "--readme", action="append", required=True, help="repository-relative README" + ) + mode = parser.add_mutually_exclusive_group(required=True) + mode.add_argument("--write", action="store_true", help="replace marked blocks") + mode.add_argument("--check", action="store_true", help="fail when blocks differ") + args = parser.parse_args() + + root = pathlib.Path(args.repo).resolve() + if not (root / ".git").exists() and not (root / ".git").is_file(): + print(f"not a Git worktree: {root}", file=sys.stderr) + return 2 + + failed = False + for value in args.readme: + try: + readme = contained_path(root, value, "README path") + if not readme.is_file(): + raise ValueError(f"README does not exist: {value}") + before = readme.read_text(encoding="utf-8") + after, blocks = render(readme, root) + if blocks == 0: + raise ValueError(f"no complete-source markers in {value}") + if args.write: + if before != after: + readme.write_text(after, encoding="utf-8") + print(f"synced {blocks} source blocks in {value}") + elif before != after: + print(f"stale complete-source block in {value}", file=sys.stderr) + failed = True + else: + print(f"checked {blocks} source blocks in {value}") + except (OSError, ValueError) as error: + print(error, file=sys.stderr) + failed = True + + return 1 if failed else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) 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 5f63dec..6253017 100644 --- a/.agents/skills/write-bpf-production-tutorial/references/drafting-process.md +++ b/.agents/skills/write-bpf-production-tutorial/references/drafting-process.md @@ -22,4 +22,4 @@ Draft English and Chinese from the same evidence ledger. Keep code, commands, an After the rewrite, compare each README with its entry version from the end backwards. Mark every removed paragraph as moved, rephrased with all facts intact, or intentionally excluded for a reason already authorized by the task. Restore any unaccounted technical content. -Verify that every complete-source code block matches its repository file exactly. Then run the repository documentation generators, link checks, tests, and external review workflow. +Run `$bpf-tutorial-writing-style/scripts/sync-source-blocks.py --check` to verify that every complete-source block matches its repository file exactly. Then run the repository documentation generators, link checks, tests, and external review workflow. diff --git a/.agents/skills/write-bpf-production-tutorial/references/repository-precedents.md b/.agents/skills/write-bpf-production-tutorial/references/repository-precedents.md index b8152c1..123544b 100644 --- a/.agents/skills/write-bpf-production-tutorial/references/repository-precedents.md +++ b/.agents/skills/write-bpf-production-tutorial/references/repository-precedents.md @@ -5,7 +5,7 @@ Read both required English/Chinese README pairs in full before drafting: - `src/47-cuda-events/README.md` and `src/47-cuda-events/README.zh.md` - `src/49-hid/README.md` and `src/49-hid/README.zh.md` -Select one additional lesson with the same operational shape or eBPF attachment when it adds a useful domain pattern. Record every exact path in a precedent brief. +Select one to three additional completed lesson pairs with the same operational shape, subsystem, attachment type, or reader task when they add a useful domain pattern. The lists below route common topics, but they are not an allowlist. An agent may select any better-matched finished tutorial after inspecting the repository index. Read every selected English/Chinese pair in full and record every exact path in the precedent brief. ## Required advanced-tool precedents