Check complete tutorial source blocks

This commit is contained in:
LinuxDev9002
2026-07-18 19:10:07 -07:00
parent f865650c54
commit c266234034
6 changed files with 137 additions and 3 deletions

View File

@@ -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
<!-- BEGIN FULL SOURCE: src/<lesson>/<tool>.bpf.c -->
```c
placeholder replaced by the script
```
<!-- END FULL SOURCE -->
````
Run the script with `--write` after drafting and `--check` before acceptance. Never hand-edit content between these markers.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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"^<!-- BEGIN FULL SOURCE: ([^ ]+) -->$")
END = "<!-- END FULL SOURCE -->"
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())

View File

@@ -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.

View File

@@ -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