Plan O5 / spec §20.3 / §21.3.2.
apps/daemon/src/plugins/atoms/diff-review.ts ships the daemon-side
impl behind the SKILL.md fragment landed in §3.M4. The runner walks
plan/receipts/ + plan/steps.json and emits the four files the
SKILL.md fragment promises:
<cwd>/review/diff.patch receipt-derived patch concat
<cwd>/review/summary.md per-step walkthrough w/ +/- stats
<cwd>/review/decision.json accept / reject / partial
<cwd>/review/meta.json generatedAt + atomDigest +
planRevision
Public surface:
runDiffReview({ cwd, decision? }) → DiffReviewReport
{ files[], added, removed, receipts[], decision?, meta }
Decision composition rules (spec §20.3):
- 'accept' → accepted_files defaults to every touched file;
rejected_files defaults to [].
- 'reject' → rejected_files defaults to every touched file;
accepted_files defaults to [].
- 'partial' → MUST cover every touched file via the union of
accepted_files + rejected_files; otherwise the
runner throws 'missing <file>' so the GenUI surface
can re-prompt.
Round trip semantics: when decision is omitted, the runner reads
review/decision.json from disk if it exists and returns it on the
report so a subsequent stage can inspect the user's prior choice
without re-prompting.
The diff.patch artefact is intentionally a receipt-derived summary
(file list + added/removed counts + rationale comments). Precise
hunks live in plan/receipts/<id>.json — the SKILL.md fragment
spells this contract out so the agent doesn't claim diff.patch is
git-apply-shaped.
Daemon tests: 1581 → 1588 (+7 cases on plugins-diff-review:
artefact emission from receipts, aggregation + dedupe across multi-
file receipts, accept default-fills-all, reject default-fills-all,
partial requires full coverage, decision round-trip from disk,
empty-receipts dir non-crash).
Co-authored-by: Tom Huang <1043269994@qq.com>