mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-10-29 19:58:08 +08:00
Add cross-model tutorial writing review
This commit is contained in:
@@ -1,20 +1,22 @@
|
||||
---
|
||||
name: write-bpf-production-tutorial
|
||||
description: Create or revise bilingual bpf-developer-tutorial lessons as small, production-realistic eBPF tools with host builds, benchmark-kernel KVM tests, reproducible evidence, and prose authored only by the exact Claude model claude-opus-4-6[1m]. Use when proposing, implementing, documenting, reviewing, or preparing a PR for a new eBPF tutorial, especially when deciding between numbered lessons, features, networking, security, or xpu/gpu placement.
|
||||
description: Create or revise bilingual bpf-developer-tutorial lessons as small, production-realistic eBPF tools with host builds, benchmark-kernel KVM tests, reproducible evidence, and mandatory independent cross-model prose review. Use when proposing, implementing, documenting, reviewing, or preparing a PR for a new eBPF tutorial, especially when deciding between numbered lessons, features, networking, security, or xpu/gpu placement.
|
||||
---
|
||||
|
||||
# Write BPF Production Tutorials
|
||||
|
||||
Build a useful tool around a kernel capability. Do not publish a wrapper around an upstream selftest or a feature-only API tour.
|
||||
|
||||
## Enforce the author boundary
|
||||
## Separate authorship from acceptance
|
||||
|
||||
- Let the implementation agent design, code, test, and collect technical evidence.
|
||||
- Require Claude Code with the exact model string `claude-opus-4-6[1m]` to author or revise `README.md` and `README.zh.md`.
|
||||
- Invoke Claude only through `scripts/run-claude-writer.sh`. Do not expose a model override and do not configure a fallback model.
|
||||
- Do not write tutorial prose with Codex or another model. Send factual corrections back through the same wrapper instead of rewriting paragraphs manually.
|
||||
- Permit other models to review code or prose, but never to author replacement tutorial text.
|
||||
- Preserve every wrapper trace and manifest under `~/.local/state/bpf-tutorial-writer/runs/`. Never delete, truncate, rewrite, or clean that directory.
|
||||
- Let Codex, a human, or another capable model author and revise the lesson. Treat model identity as provenance, not proof of quality.
|
||||
- Require a read-only review by a different model family after every completed writing or substantial editing pass.
|
||||
- Give the reviewer the finished English and Chinese files, implementation, tests, real output, primary sources, and the repository rulebooks. Do not give it the author's diagnosis or a list of expected defects.
|
||||
- Resolve every valid **Must fix** finding. Record a concrete disposition for every **Should fix** and **Consider** finding, then run an external re-review of the final diff.
|
||||
- Do not call the prose finished while any valid Must-fix remains. If no different model family is available, report `cross-model review unavailable`.
|
||||
- Use `scripts/run-external-review.sh` for Grok 4.5 or OpenCode GLM 5.2 reviews. Choose one reviewer for a normal pass and at most two when the first review finds factual uncertainty or substantial bilingual problems. Do not run every available model by default. The wrapper is read-only and preserves the complete prompt, trace, and manifest under `~/.local/state/bpf-tutorial-reviews/runs/`.
|
||||
- Keep `scripts/run-claude-writer.sh` only as an optional, trace-verified `claude-opus-4-6[1m]` authoring channel.
|
||||
- Never delete, truncate, rewrite, or clean any writer or reviewer trace directory. Preserve failed and partial runs too.
|
||||
|
||||
## Establish the tutorial contract
|
||||
|
||||
@@ -27,7 +29,7 @@ Before coding, write one sentence naming:
|
||||
|
||||
Reject proposals whose only result is “the program loaded,” “the helper returned success,” or “the upstream selftest passed.”
|
||||
|
||||
Read [references/tutorial-acceptance.md](references/tutorial-acceptance.md) before selecting scope or placement. Read [references/writing-guide.md](references/writing-guide.md) before invoking the writer.
|
||||
Read [references/tutorial-acceptance.md](references/tutorial-acceptance.md) before selecting scope or placement. Read [references/repository-precedents.md](references/repository-precedents.md) and the selected precedent lessons in full before drafting. Read [references/writing-guide.md](references/writing-guide.md) before drafting. Read [references/review-checklist.md](references/review-checklist.md) before external review.
|
||||
|
||||
## Implement and verify
|
||||
|
||||
@@ -39,20 +41,23 @@ Read [references/tutorial-acceptance.md](references/tutorial-acceptance.md) befo
|
||||
6. Add a compile CI step. Add a runtime feature probe or an explicit skip when ordinary CI lacks the required kernel.
|
||||
7. Run documentation generators and link/unit tests.
|
||||
|
||||
## Delegate the prose
|
||||
## Draft from evidence
|
||||
|
||||
First write a precedent brief that names two or three existing bilingual lessons read in full, including one with the same operational shape. Use `src/47-cuda-events/README.md` and `README.zh.md` as a default precedent for a production tracer or accelerator tool. State which structural patterns to reuse, which legacy weaknesses to avoid, and why the new lesson has a distinct operational job. Do not draft until this brief exists.
|
||||
|
||||
Create a task file outside the lesson with:
|
||||
|
||||
- the exact README paths Claude may edit;
|
||||
- the exact README paths the author may edit;
|
||||
- the production scenario and intended audience;
|
||||
- the final code paths and CLI;
|
||||
- verified build and guest commands;
|
||||
- real captured output with private paths and identities removed;
|
||||
- minimum kernel, libbpf, config, privilege, and hardware requirements;
|
||||
- primary upstream references;
|
||||
- facts or claims Claude must not add.
|
||||
- the precedent brief and exact sibling README paths;
|
||||
- facts or claims the author must not add.
|
||||
|
||||
Then run:
|
||||
Draft or revise both README files from that evidence. The optional exact-Claude authoring path is:
|
||||
|
||||
```bash
|
||||
TUTORIAL_ROOT="$(git rev-parse --show-toplevel)"
|
||||
@@ -63,11 +68,32 @@ TUTORIAL_ROOT="$(git rev-parse --show-toplevel)"
|
||||
--readme "$TUTORIAL_ROOT/src/<lesson>/README.zh.md"
|
||||
```
|
||||
|
||||
The wrapper must finish with a verified exact-model trace. Inspect both READMEs for matching structure and technical meaning, then rerun build and documentation commands exactly as written.
|
||||
The wrapper must finish with a verified exact-model trace. When another author writes the files, record the author identity in the PR evidence instead.
|
||||
|
||||
## Run independent prose review
|
||||
|
||||
Run a different model family read-only over the final files, implementation evidence, and the precedent READMEs named in the brief. Pass repository-relative paths with repeated `--file` arguments:
|
||||
|
||||
```bash
|
||||
TUTORIAL_ROOT="$(git rev-parse --show-toplevel)"
|
||||
"$TUTORIAL_ROOT/.agents/skills/write-bpf-production-tutorial/scripts/run-external-review.sh" \
|
||||
--reviewer grok \
|
||||
--repo "$TUTORIAL_ROOT" \
|
||||
--task /absolute/path/to/review-task.md \
|
||||
--file src/<lesson>/README.md \
|
||||
--file src/<lesson>/README.zh.md \
|
||||
--file src/<lesson>/<tool>.bpf.c \
|
||||
--file src/<lesson>/<tool>.c \
|
||||
--file src/<lesson>/tests/<test>.py \
|
||||
--file src/47-cuda-events/README.md \
|
||||
--file src/47-cuda-events/README.zh.md
|
||||
```
|
||||
|
||||
Use `--reviewer glm` for the fixed OpenCode model `zai-coding-plan/glm-5.2`. Apply valid findings with targeted edits, diff-check both languages, rerun documented commands, and invoke an external reviewer again. The gate passes only when the final trace reports no valid Must-fix item.
|
||||
|
||||
## Prepare the PR
|
||||
|
||||
- Include only one lesson and the minimal generated index/compatibility changes.
|
||||
- Explain the production problem before the kernel feature in the PR body.
|
||||
- Report the host build, KVM positive test, negative/cleanup test, guest kernel provenance, documentation tests, and model-trace manifest.
|
||||
- Report the host build, KVM positive test, negative/cleanup test, guest kernel provenance, documentation tests, author identity, review manifests, and finding dispositions.
|
||||
- Follow the repository's review, Copilot, and monitored CI gates. Do not merge unless the user asks.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
interface:
|
||||
display_name: "BPF Production Tutorial Writer"
|
||||
short_description: "Build tested eBPF lessons with Claude Opus prose"
|
||||
short_description: "Build and cross-review tested eBPF lessons"
|
||||
default_prompt: "Use $write-bpf-production-tutorial to turn this production eBPF scenario into a tested bilingual tutorial."
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Repository tutorial precedents
|
||||
|
||||
Read two or three existing English/Chinese README pairs in full before drafting. Select one lesson with the same operational shape and one with the same eBPF attachment or subsystem. Record the exact paths in a precedent brief.
|
||||
|
||||
## Default production-tool precedent
|
||||
|
||||
Use `src/47-cuda-events/README.md` and `src/47-cuda-events/README.zh.md` as a default precedent for tracers and accelerator-facing tools. Reuse its useful scope:
|
||||
|
||||
- identify a real workload and the operator-visible events;
|
||||
- connect the BPF hooks, shared event structure, ring buffer, user-space formatter, CLI, and fixture end to end;
|
||||
- include build and run commands, representative output, limitations, extension points, and primary references;
|
||||
- keep the complete source easy to find while explaining only the important excerpts.
|
||||
|
||||
Do not inherit its legacy weaknesses. New lessons must show commands and verified evidence early, avoid generic eBPF or subsystem introductions, use only captured output, qualify volatile IDs and addresses, source every benchmark claim, keep English and Chinese macro structure aligned, and state requirements, negative behavior, and cleanup explicitly.
|
||||
|
||||
## Domain selection
|
||||
|
||||
- For networking, also read the closest of `src/20-tc/`, `src/41-xdp-tcpdump/`, `src/42-xdp-loadbalancer/`, or `src/50-tcx/`.
|
||||
- For security and process lifecycle, also read the closest of `src/7-execsnoop/`, `src/19-lsm-connect/`, `src/26-sudo/`, or `src/34-syscall/`.
|
||||
- For latency and operations, also read the closest of `src/9-runqlat/`, `src/17-biopattern/`, `src/33-funclatency/`, or `src/48-energy/`.
|
||||
- For GPU, NPU, or DMA-BUF work, read `src/47-cuda-events/` plus the closest lesson under `src/xpu/`.
|
||||
- For a reusable kernel primitive, read the closest pair under `src/features/` and one numbered lesson that uses a similar end-to-end flow.
|
||||
|
||||
## Required precedent brief
|
||||
|
||||
Before prose, record:
|
||||
|
||||
1. the exact README pairs read in full;
|
||||
2. two to four structural patterns to reuse;
|
||||
3. old weaknesses or irrelevant sections to avoid;
|
||||
4. the new lesson's distinct operational question;
|
||||
5. why the chosen depth fits this tool rather than copying a fixed template.
|
||||
|
||||
Give this brief to both the author and external reviewer. Repository continuity is a requirement, but an older lesson never overrides verified code, runtime evidence, or the current writing rules.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Independent tutorial review checklist
|
||||
|
||||
Review the supplied snapshot without editing files or running commands. The author and reviewer must belong to different model families. The snapshot must include the precedent lessons named by the author; fail the process as incomplete if they are absent.
|
||||
|
||||
Classify every finding as **Must fix**, **Should fix**, or **Consider**. For each finding, name the file and line or heading, quote the smallest useful fragment, explain the problem, and propose a concrete correction. Do not rewrite entire sections.
|
||||
|
||||
Give explicit verdicts for:
|
||||
|
||||
1. production realism and whether the lesson is a useful small tool rather than a feature tour or upstream selftest wrapper;
|
||||
2. factual faithfulness to the implementation, KVM evidence, minimum versions, configs, privileges, limitations, and cleanup behavior;
|
||||
3. architecture, including the thesis, running scenario, section progression, and ending;
|
||||
4. reproducibility of every build, run, failure, and cleanup command;
|
||||
5. paragraph density, note-like prose, vague claims, invented output, and unsupported production claims;
|
||||
6. overlap with nearby lessons and whether the new lesson has a distinct operational job;
|
||||
7. English and Chinese agreement on headings, commands, examples, numbers, claims, and caveats;
|
||||
8. natural Chinese composition, terminology consistency, punctuation, and avoidance of line-locked translation.
|
||||
|
||||
For the precedent verdict, distinguish legitimate repository continuity from copying. Confirm that the new lesson matches the selected examples' useful depth and end-to-end explanation while rejecting legacy weaknesses such as generic introductions, late commands, invented volatile output, unsupported benchmark claims, exhaustive feature inventories, or bilingual structure drift.
|
||||
|
||||
Finish with a count by severity and exactly one final gate result:
|
||||
|
||||
- `GATE: PASS` when no valid Must-fix item remains.
|
||||
- `GATE: FAIL` when one or more Must-fix items remain.
|
||||
|
||||
Model identity documents review independence. It is not evidence that the prose is correct.
|
||||
@@ -1,6 +1,8 @@
|
||||
# BPF tutorial writing guide
|
||||
|
||||
Write for developers who want to reproduce a small, useful eBPF tool. Use oral, direct English and natural Chinese. Prefer short, connected sentences over academic prose or marketing claims.
|
||||
Write for developers who want to reproduce a small, useful eBPF tool. Use direct English and natural Chinese. Prefer short, connected sentences over academic prose, release-note inventories, or marketing claims.
|
||||
|
||||
Before prose, write a private architecture brief with one thesis, the reader's operational goal, the unique angle relative to nearby lessons, non-goals, a running scenario, and the role of each section. Also write the precedent brief required by `repository-precedents.md`. Build a progression from the operational problem through the mechanism and measured evidence to a practical boundary. Do not mirror an upstream selftest or kernel merge note.
|
||||
|
||||
## Required narrative
|
||||
|
||||
@@ -17,8 +19,13 @@ Write for developers who want to reproduce a small, useful eBPF tool. Use oral,
|
||||
|
||||
- Use a specific title such as `# eBPF Tutorial by Example: Quarantine an Established TCP Connection`.
|
||||
- Build a progressive explanation around one running example instead of listing features.
|
||||
- Match the repository's established depth: explain the workload, BPF hook and state, event/control path, user-space behavior, CLI, verified run, failure path, cleanup, limits, and primary references. Omit any section the actual tool does not need.
|
||||
- Borrow organization and voice from the selected precedents, never their scenario-specific facts, output, claims, or defects. The current rulebook overrides a weaker pattern in an older lesson.
|
||||
- Use active voice and define technical terms through the example.
|
||||
- Avoid throat clearing, repeated summaries, vague claims, paper-like language, em dashes, and stacked one-line paragraphs.
|
||||
- Give each paragraph one job. Inspect English paragraphs above 110 words, Chinese paragraphs above 320 characters, and any run of three dense paragraphs.
|
||||
- Avoid throat clearing, repeated summaries, vague claims, paper-like language, em dashes, semicolons joining independent clauses, and stacked one-line paragraphs.
|
||||
- Use a colon only for a real list, code block, or table. Rewrite claim-colon-evidence and noun-phrase-colon openings as sentences.
|
||||
- Keep subjects near their verbs, use concrete actors, and replace spec-sheet paragraphs with an argument that explains why each mechanism or number matters.
|
||||
- Do not describe a demo as production-ready. State scope and missing hardening plainly.
|
||||
- Preserve exact code, command, version, and output facts supplied in the task file.
|
||||
- Link kernel claims to primary sources such as kernel commits, documentation, or selftests.
|
||||
@@ -26,7 +33,9 @@ Write for developers who want to reproduce a small, useful eBPF tool. Use oral,
|
||||
## Bilingual rules
|
||||
|
||||
- Keep English and Chinese headings, examples, commands, limitations, and claims aligned.
|
||||
- Translate naturally rather than sentence by sentence.
|
||||
- Compose Chinese from the source facts and paragraph role rather than translating English sentence by sentence. Sentence and paragraph boundaries should differ when natural Chinese requires it.
|
||||
- Keep product names, code, commands, file names, functions, and genuine terms of art in English. Translate ordinary concept nouns consistently, with a first-use English gloss only when useful.
|
||||
- Do not start Chinese prose sentences with an English common noun. Use full-width Chinese punctuation and spaces between CJK text and Latin letters or digits.
|
||||
- Keep code and verified console output identical.
|
||||
- Do not use Chinese em dashes (`——`) or spaced English em dashes (` — `).
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ readonly MODEL='claude-opus-4-6[1m]'
|
||||
readonly SKILL_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
readonly VERIFY="$SKILL_DIR/scripts/verify_claude_trace.py"
|
||||
readonly GUIDE="$SKILL_DIR/references/writing-guide.md"
|
||||
readonly PRECEDENTS="$SKILL_DIR/references/repository-precedents.md"
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 --repo ABSOLUTE_REPO_PATH --task ABSOLUTE_TASK_FILE --readme ABSOLUTE_README_PATH --readme ABSOLUTE_README_PATH" >&2
|
||||
@@ -94,10 +95,11 @@ status_before=$(git -C "$repo" status --porcelain=v1)
|
||||
task_sha=$(sha256sum "$task" | awk '{print $1}')
|
||||
printf -v allowed_paths 'Allowed README path: %s\n' "${allowed_readmes[@]}"
|
||||
|
||||
prompt=$(printf '%s\n\n%s\n%s\n%s\n' \
|
||||
'You are the sole prose author for an eBPF production tutorial. Read the repository code and evidence named in the task. Edit only the README.md and README.zh.md paths explicitly allowed by the task. Do not edit code, build files, generated indexes, or tests. Do not invent output or claims. Finish by stating which README files you edited.' \
|
||||
prompt=$(printf '%s\n\n%s\n%s\n%s\n%s\n' \
|
||||
'You are the prose author for this eBPF production tutorial pass. Read the repository code and evidence named in the task. Edit only the README.md and README.zh.md paths explicitly allowed by the task. Do not edit code, build files, generated indexes, or tests. Do not invent output or claims. Finish by stating which README files you edited.' \
|
||||
"$allowed_paths" \
|
||||
"$(<"$GUIDE")" \
|
||||
"$(<"$PRECEDENTS")" \
|
||||
"$(<"$task")")
|
||||
|
||||
set +e
|
||||
|
||||
209
.agents/skills/write-bpf-production-tutorial/scripts/run-external-review.sh
Executable file
209
.agents/skills/write-bpf-production-tutorial/scripts/run-external-review.sh
Executable file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
readonly SKILL_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
readonly WRITING_GUIDE="$SKILL_DIR/references/writing-guide.md"
|
||||
readonly REVIEW_GUIDE="$SKILL_DIR/references/review-checklist.md"
|
||||
readonly PRECEDENT_GUIDE="$SKILL_DIR/references/repository-precedents.md"
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 --reviewer grok|glm --repo ABSOLUTE_REPO_PATH --task ABSOLUTE_TASK_FILE --file REPO_RELATIVE_PATH [--file ...]" >&2
|
||||
}
|
||||
|
||||
reviewer=
|
||||
repo=
|
||||
task=
|
||||
files=()
|
||||
while (($#)); do
|
||||
case "$1" in
|
||||
--reviewer)
|
||||
reviewer=${2:-}
|
||||
shift 2
|
||||
;;
|
||||
--repo)
|
||||
repo=${2:-}
|
||||
shift 2
|
||||
;;
|
||||
--task)
|
||||
task=${2:-}
|
||||
shift 2
|
||||
;;
|
||||
--file)
|
||||
files+=("${2:-}")
|
||||
shift 2
|
||||
;;
|
||||
--model|--fallback-model)
|
||||
echo "model overrides and fallbacks are forbidden" >&2
|
||||
exit 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ $reviewer == grok || $reviewer == glm ]] || { usage; exit 2; }
|
||||
[[ $repo = /* && -d $repo ]] || { echo "--repo must be an absolute Git checkout" >&2; exit 2; }
|
||||
git -C "$repo" rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "--repo must be an absolute Git checkout" >&2; exit 2; }
|
||||
[[ $task = /* && -f $task ]] || { echo "--task must be an absolute readable file" >&2; exit 2; }
|
||||
((${#files[@]} >= 2)) || { echo "pass at least the English and Chinese README with --file" >&2; exit 2; }
|
||||
command -v git >/dev/null || { echo "git is required" >&2; exit 127; }
|
||||
command -v python3 >/dev/null || { echo "python3 is required" >&2; exit 127; }
|
||||
|
||||
case "$reviewer" in
|
||||
grok)
|
||||
readonly model='grok-4.5'
|
||||
command -v grok >/dev/null || { echo "Grok CLI is required" >&2; exit 127; }
|
||||
;;
|
||||
glm)
|
||||
readonly model='zai-coding-plan/glm-5.2'
|
||||
command -v opencode >/dev/null || { echo "OpenCode is required" >&2; exit 127; }
|
||||
;;
|
||||
esac
|
||||
|
||||
repo_real=$(realpath "$repo")
|
||||
for file in "${files[@]}"; do
|
||||
[[ $file && $file != /* ]] || { echo "--file paths must be repository-relative: $file" >&2; exit 2; }
|
||||
file_real=$(realpath "$repo/$file")
|
||||
[[ $file_real == "$repo_real"/* && -f $file_real ]] || { echo "invalid review file: $file" >&2; exit 2; }
|
||||
done
|
||||
|
||||
state_root=${XDG_STATE_HOME:-$HOME/.local/state}/bpf-tutorial-reviews/runs
|
||||
mkdir -p "$state_root"
|
||||
chmod 700 "$state_root"
|
||||
run_id="$(date -u +%Y%m%dT%H%M%SZ)-$$-$reviewer"
|
||||
run_dir="$state_root/$run_id"
|
||||
mkdir -m 700 "$run_dir"
|
||||
prompt="$run_dir/review-prompt.md"
|
||||
trace="$run_dir/review-trace.jsonl"
|
||||
manifest="$run_dir/manifest.json"
|
||||
|
||||
{
|
||||
printf '# Independent eBPF tutorial review\n\n'
|
||||
printf 'Review this immutable snapshot. Do not edit files, run commands, use network sources, or infer facts absent from the snapshot. Do not assume the author\x27s intended diagnosis.\n\n'
|
||||
printf '## Writing rulebook\n\n'
|
||||
sed -n '1,$p' "$WRITING_GUIDE"
|
||||
printf '\n## Review rulebook\n\n'
|
||||
sed -n '1,$p' "$REVIEW_GUIDE"
|
||||
printf '\n## Repository precedent rulebook\n\n'
|
||||
sed -n '1,$p' "$PRECEDENT_GUIDE"
|
||||
printf '\n## Review task and evidence\n\n'
|
||||
sed -n '1,$p' "$task"
|
||||
for file in "${files[@]}"; do
|
||||
printf '\n## Snapshot: `%s`\n\n```text\n' "$file"
|
||||
sed -n '1,$p' "$repo/$file"
|
||||
printf '\n```\n'
|
||||
done
|
||||
} >"$prompt"
|
||||
chmod 600 "$prompt"
|
||||
|
||||
head_before=$(git -C "$repo" rev-parse HEAD)
|
||||
status_before=$(git -C "$repo" status --porcelain=v1)
|
||||
files_before=$(
|
||||
for file in "${files[@]}"; do
|
||||
sha256sum "$repo/$file"
|
||||
done
|
||||
)
|
||||
prompt_sha=$(sha256sum "$prompt" | awk '{print $1}')
|
||||
|
||||
set +e
|
||||
case "$reviewer" in
|
||||
grok)
|
||||
(
|
||||
cd "$run_dir"
|
||||
grok --prompt-file "$prompt" \
|
||||
--model "$model" \
|
||||
--permission-mode plan \
|
||||
--no-subagents \
|
||||
--disable-web-search \
|
||||
--output-format streaming-json
|
||||
) >"$trace" 2>&1
|
||||
review_status=$?
|
||||
;;
|
||||
glm)
|
||||
(
|
||||
cd "$run_dir"
|
||||
opencode run \
|
||||
'Review the complete attached snapshot and return only the requested independent review.' \
|
||||
--dir "$run_dir" \
|
||||
--model "$model" \
|
||||
--agent plan \
|
||||
--format json \
|
||||
--title "bpf-tutorial-review-$run_id" \
|
||||
--file "$prompt"
|
||||
) >"$trace" 2>&1
|
||||
review_status=$?
|
||||
;;
|
||||
esac
|
||||
set -e
|
||||
|
||||
trace_sha=$(sha256sum "$trace" | awk '{print $1}')
|
||||
head_after=$(git -C "$repo" rev-parse HEAD)
|
||||
status_after=$(git -C "$repo" status --porcelain=v1)
|
||||
files_after=$(
|
||||
for file in "${files[@]}"; do
|
||||
sha256sum "$repo/$file"
|
||||
done
|
||||
)
|
||||
|
||||
REVIEWER_VALUE="$reviewer" \
|
||||
MODEL_VALUE="$model" \
|
||||
REPO_VALUE="$repo" \
|
||||
TASK_VALUE="$task" \
|
||||
PROMPT_VALUE="$prompt" \
|
||||
PROMPT_SHA_VALUE="$prompt_sha" \
|
||||
TRACE_VALUE="$trace" \
|
||||
TRACE_SHA_VALUE="$trace_sha" \
|
||||
REVIEW_STATUS_VALUE="$review_status" \
|
||||
HEAD_BEFORE_VALUE="$head_before" \
|
||||
HEAD_AFTER_VALUE="$head_after" \
|
||||
STATUS_BEFORE_VALUE="$status_before" \
|
||||
STATUS_AFTER_VALUE="$status_after" \
|
||||
FILES_BEFORE_VALUE="$files_before" \
|
||||
FILES_AFTER_VALUE="$files_after" \
|
||||
python3 - "$manifest" <<'PY'
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
path = pathlib.Path(__import__("sys").argv[1])
|
||||
path.write_text(json.dumps({
|
||||
"reviewer": os.environ["REVIEWER_VALUE"],
|
||||
"model": os.environ["MODEL_VALUE"],
|
||||
"repo": os.environ["REPO_VALUE"],
|
||||
"task": os.environ["TASK_VALUE"],
|
||||
"prompt": os.environ["PROMPT_VALUE"],
|
||||
"prompt_sha256": os.environ["PROMPT_SHA_VALUE"],
|
||||
"trace": os.environ["TRACE_VALUE"],
|
||||
"trace_sha256": os.environ["TRACE_SHA_VALUE"],
|
||||
"review_exit_status": int(os.environ["REVIEW_STATUS_VALUE"]),
|
||||
"head_before": os.environ["HEAD_BEFORE_VALUE"],
|
||||
"head_after": os.environ["HEAD_AFTER_VALUE"],
|
||||
"status_before": os.environ["STATUS_BEFORE_VALUE"],
|
||||
"status_after": os.environ["STATUS_AFTER_VALUE"],
|
||||
"repository_status_changed": os.environ["STATUS_BEFORE_VALUE"] != os.environ["STATUS_AFTER_VALUE"],
|
||||
"review_files_sha256_before": os.environ["FILES_BEFORE_VALUE"].splitlines(),
|
||||
"review_files_sha256_after": os.environ["FILES_AFTER_VALUE"].splitlines(),
|
||||
}, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
PY
|
||||
chmod 600 "$trace" "$manifest"
|
||||
|
||||
if ((review_status != 0)); then
|
||||
echo "$reviewer exited with status $review_status; preserved trace: $trace" >&2
|
||||
exit "$review_status"
|
||||
fi
|
||||
[[ -s $trace ]] || { echo "review trace is empty: $trace" >&2; exit 1; }
|
||||
if [[ $head_before != "$head_after" || $files_before != "$files_after" ]]; then
|
||||
echo "read-only review changed Git HEAD or a reviewed file; preserved trace: $trace" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ $status_before != "$status_after" ]]; then
|
||||
echo "warning: unrelated repository status changed during review; recorded in manifest" >&2
|
||||
fi
|
||||
|
||||
echo "manifest=$manifest"
|
||||
Reference in New Issue
Block a user