From d23bc1970ff6d2e33498029cb4f7f67e73785664 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sat, 29 Aug 2026 21:11:26 -0700 Subject: [PATCH 01/12] Add a Local Review Engine That Records What a Review Covered The fleet's rule that PR-bound work gets a local adversarial review before every push is already written in three Skills, including the fix-push moment, and is still not followed (#1104). It is not a wording gap, so this adds the capability a capture point can actually check: a review pass records a receipt keyed on the content it reviewed, and a later caller asks whether that receipt still covers what is about to be pushed. The key is over the net content the branch introduces against its target, never over diff text or HEAD, which is what lets a review run before the commit while the check runs at the push. Reviewing untracked work and committing it unchanged leaves the key identical; changing one byte moves it. Every identity in the key is computed by git rather than reconstructed. That is the load-bearing detail: a blob id built by hashing raw working-tree bytes cannot equal the one git stores wherever a text attribute or clean filter sits between them, and this repository applies one to every text file, so `git add` moved the key on any CRLF file. So the working tree's side is read by staging it into a throwaway index that git builds, with object writes redirected into a throwaway object directory and the real one attached as an alternate. Without that redirection a read would deposit the content of every unignored untracked file into the repository permanently. The engine holds no review logic. It drives backends: agent-skill is the local-strict-review subagent pass, which only a live session can run, so the engine records it; coderabbit-cli is headless and is the one backend a git hook can execute by itself. A pass records that a review ran over this content, never that the content is clean. Exit codes are three-valued, so an execution boundary is never reported as a verdict. The capture points that will call this, a git pre-push hook and the Skill steps, are a separate change. Part of #1104 and #1083. The capture points that close them come next. --- scripts/README.md | 27 +- scripts/local_review.py | 724 +++++++++++++++++++++++++++++ scripts/tests/test_local_review.py | 688 +++++++++++++++++++++++++++ 3 files changed, 1437 insertions(+), 2 deletions(-) create mode 100755 scripts/local_review.py create mode 100755 scripts/tests/test_local_review.py diff --git a/scripts/README.md b/scripts/README.md index 3941be23..56f2b4cf 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -4,14 +4,15 @@ The fleet's checks and review tooling, run by hand, with the deterministic ones **Hosted here and reached, never carried.** These are not declared in [`spec/files.json`][files], so the audit does not expect a downstream repo to ship them, the same footing as `spec/audit.py`. That is the fleet model rather than an omission: a gate holding no per-repo content has one canonical implementation for the fleet. The prose and repository gate implementations live beside their composite actions under `.github/actions/`, which lets reusable workflows reach the implementation at their pinned hub commit through `$/.github/actions/` without checking out the hub. The same-named files in `scripts/` are thin local entry points that call those action-owned implementations, so maintainers and hooks retain the established commands from a hub checkout without creating a second copy of either gate. A repository that cannot reach the hub reports a local check as not run rather than reconstructing it, since a rebuilt gate encodes its author's reading of the rule and agrees with no other repository. -Python only, standard library only, no third-party packages. Every check script is read-only and exits non-zero on a finding. `build_dist.py` and `skills_install.py` below are the two exceptions, since a generator and an installer both exist to write, and each still offers a read-only mode (`--check`, `--report`) for CI and for asking without changing anything. +Python only, standard library only, no third-party packages. Every check script is read-only and exits non-zero on a finding. `build_dist.py`, `local_review.py`, and `skills_install.py` below are the exceptions, since a generator, a recorder, and an installer all exist to write, and each still offers a read-only mode (`--check`, `status`, `--report`) for CI and for asking without changing anything. -The directory separates its kinds by name and by tree. A gate checks and exits non-zero on a finding, and its name carries a `_lint` or `_gate` suffix saying what it gates. The `prose_lint.py` and `repo_gate.py` entry points delegate to the action-owned implementations that gate this tree in CI, and `host_gate.py` gates the machine it runs on. A utility does work rather than gating and carries no suffix: `build_dist.py`, `pr_review.py`, `skills_install.py`. The unit tests live apart under [`scripts/tests/`][tests], one `test_