Skip to content

review: enforce the change-provenance gate in code; stage generated-stripped diffs - #227

Merged
jwbron merged 4 commits into
mainfrom
review-provenance-gate
Jul 9, 2026
Merged

review: enforce the change-provenance gate in code; stage generated-stripped diffs#227
jwbron merged 4 commits into
mainfrom
review-provenance-gate

Conversation

@jwbron

@jwbron jwbron commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Second of three PRs split out of #224; stacked on #226 (retarget to main when it merges). The follow-up prompt-disciplines PR stacks on this one.

Change-provenance gate, enforced in code. New lib/diff.ts (unified-diff parsing) and lib/provenance.ts (gate + CLI) compute a per-file changed-line map (provenance.json). A finding whose anchor is not an added or modified line of the diff cannot carry a blocking label, and pre-existing observations collapse into at most one non-blocking collapsed note (renderPreExistingNote). Deletion findings pass via removedAdjacent lines. The gate fails open (gates nothing, with a review-body note) whenever the parsed map cannot be trusted: an unparseable diff, hunk headers not attributable to any file section, or a changed file whose patch is missing from the parse (files.json now carries a hasPatch flag so binary/too-large files do not false-positive the check). Wired through the no-post eval runner and covered by unit tests plus a new smoke corpus case (provenance-pre-existing-note).

Generated-stripped whole-change diffs (measured cost fix). The provenance CLI also stages full-stripped.diff (the full diff minus files the router classifies linguist-generated; routing.json now exposes generatedFiles). Every whole-change reviewer and specialist lens reads it instead of the full diff; pattern-triage keeps the full diff since classification is its job. These ship together because the same CLI writes both artifacts.

No trigger config or consumer files touched.

cc @jeresig

Testing

  • npx vitest run workflows/review: 452 tests green, including the new end-to-end smoke case for the provenance gate.
  • New unit suites: lib/diff.test.ts, lib/provenance.test.ts, plus renderPreExistingNote rendering tests and router generatedFiles coverage.
  • npx tsc --noEmit clean under the repo's strict compiler options.

jwbron added 2 commits July 8, 2026 20:19
Every finding (not just blocking ones) now carries a failure_scenario:
the specific inputs or state and the wrong outcome they produce. The
field is required in the structured finding schema
(FINDING_SCHEMA_VERSION bumped to 2), emitted by every producer
(label-shape reviewers and all 11 specialist lenses), and carried
verbatim into claims.json. The claim-validator attacks exactly that
stated scenario: confirmed means the named scenario occurs on the cited
lines, and a scenario too vague to check caps at plausible.

Every corpus fixture is migrated with a hand-written failure scenario,
per the schema module's rule that a required field invalidates
previously serialized findings.
…tripped diffs

New lib/diff.ts (unified-diff parsing) and lib/provenance.ts (gate +
CLI) compute a per-file changed-line map (provenance.json). A finding
whose anchor is not an added or modified line of the diff cannot carry
a blocking label, and pre-existing observations collapse into at most
one non-blocking collapsed note (renderPreExistingNote). Deletion
findings pass via removedAdjacent lines. The gate fails open (gates
nothing, with a review-body note) whenever the parsed map cannot be
trusted: an unparseable diff, hunk headers not attributable to any file
section, or a changed file whose patch is missing from the parse
(files.json now carries a hasPatch flag so binary/too-large files do
not false-positive the check).

The provenance CLI also stages full-stripped.diff (the full diff minus
files the router classifies linguist-generated; routing.json now
exposes generatedFiles). Every whole-change reviewer and specialist
lens reads it instead of the full diff; pattern-triage keeps the full
diff since classifying every changed file is its job.

Wired through the no-post eval runner and covered by unit tests plus a
new smoke corpus case (provenance-pre-existing-note).
@changeset-bot

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 756ea71

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
review Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Cherry-picked from the standalone fix (PR #229) so this stacked PR's
own push-event CI can resolve its associated PRs: a stacked head commit
belongs to two open PRs, which is exactly the path that crashed. The
changeset stays with #229; this copy merges cleanly as the same patch.
@khan-actions-bot
khan-actions-bot requested a review from a team July 9, 2026 03:32
@jwbron jwbron self-assigned this Jul 9, 2026
@jwbron
jwbron requested a review from jeresig July 9, 2026 04:28

@jeresig jeresig left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great - hope this helps to clean up some of the extraneous comments!

Comment thread workflows/review/lib/render-comment.ts Outdated
* Returns `null` when there is nothing to note; the caller then posts no
* note at all.
*/
export const renderPreExistingNote = (

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if we want to render this at all?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. By the time a finding lands in this bucket it has already slipped past two layers of instruction telling the model not to produce it, so what collects here is mostly drift, and a comment whose body says "no action required in this PR" is exactly the extraneous-comment problem. It would also repeat on re-reviews (the gate runs before the new-scope dedup).

Updated: the note is gone entirely. The gate still sets these findings aside, but they now go to the run artifact (out/pre-existing.json) instead of the PR, so we can still inspect what the gate is catching while posting nothing. A genuinely important pre-existing issue still has a path in: the materially-amplifies rule anchors it on changed lines and it passes the gate as a normal finding.

jwbron added a commit that referenced this pull request Jul 9, 2026
## Summary

`actions/get-changed-files` crashes with `core.warn is not a function` on push events when the pushed commit is associated with more than one open PR. The github-script `core` API method is `core.warning`; `core.warn` does not exist, and the test mock stubbed `warn` so the suite never caught it. The path fires exactly for stacked PRs (a commit that is the head of one PR and part of another), which is how #227 surfaced it: its "Testing with 'push' events" check dies on this line instead of warning and proceeding with the first associated PR.

One-line fix plus the matching test-mock rename.

cc @jeresig

## Testing

- `npx vitest run actions/get-changed-files`: 40 tests green, including the multi-PR warn path.
- `pnpm build` (tsc) compiles clean.

Author: jwbron

Reviewers: jeresig, somewhatabstract, kevinb-khan

Required Reviewers:

Approved By: jeresig

Checks: ✅ 3 checks were successful

Pull Request URL: #229
…ote; set-asides are artifact-only

Review feedback from jeresig: don't render the collapsed pre-existing
observations note at all. Anything the change-provenance gate sets aside now
posts nothing to the PR; the collected observations are written to the run
artifact (out/pre-existing.json) instead, so the gate stays inspectable for
tuning without adding a comment whose body says no action is required.

A pre-existing issue important enough to surface still has its path: the
materially-amplifies rule anchors it on changed lines and it passes the gate
as a normal finding.

Removes renderPreExistingNote and its tests, simplifies the eval runner and
gates (postedCommentCount is now exactly the posted candidates), updates the
prompt and README, and reworks the smoke case to pin that the set-aside
finding is absent from the planned review rather than present in a note.
jwbron added a commit that referenced this pull request Jul 9, 2026
## Summary

First of three PRs split out of #224 (stack: this PR, then #227 provenance gate, then #228 prompt disciplines). Each lands independently revertable; the three together are byte-identical to #224.

Every finding (not just blocking ones) now carries a concrete `failure_scenario`: the specific inputs or state and the wrong outcome they produce. The field is required in the structured finding schema (`FINDING_SCHEMA_VERSION` bumped to 2), emitted by every producer (label-shape reviewers and all 11 specialist lenses), and carried verbatim into `claims.json`. The claim-validator now attacks exactly that stated scenario: confirmed means the named scenario occurs on the cited lines, and a scenario too vague to check caps at plausible.

`FINDING_SCHEMA_VERSION` is now 2 (a required field invalidates previously serialized findings, per the schema module's own rule); every corpus fixture is migrated with a hand-written failure scenario.

cc @jeresig

## Testing

- `npx vitest run workflows/review`: 410 tests green, including the smoke set.
- `npx tsc --noEmit` clean.

Author: jwbron

Reviewers: jeresig, jaredly

Required Reviewers:

Approved By: jeresig

Checks: ✅ 3 checks were successful

Pull Request URL: #226
Base automatically changed from review-failure-scenario to main July 9, 2026 18:06
@jwbron
jwbron merged commit 0892c8d into main Jul 9, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants