mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-10-30 20:25:50 +08:00
Check complete tutorial source blocks
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
116
.agents/skills/bpf-tutorial-writing-style/scripts/sync-source-blocks.py
Executable file
116
.agents/skills/bpf-tutorial-writing-style/scripts/sync-source-blocks.py
Executable 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())
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user