feat(review-pr): auto-filter low-risk files before chunking#215
feat(review-pr): auto-filter low-risk files before chunking#215derekmisler wants to merge 2 commits into
Conversation
docker-agent
left a comment
There was a problem hiding this comment.
Assessment: 🟡 NEEDS ATTENTION
This PR correctly implements a two-phase auto-filter mechanism and moves risk scoring before diff chunking. The new TEST_FILE_RE additions for Rust/Ruby patterns look correct, and the tsup.config.ts entry is properly wired. One medium-severity logic issue was found in Phase 2 of autoFilterDiff.
derekmisler
left a comment
There was a problem hiding this comment.
Assessment: 🟡 NEEDS ATTENTION
No new findings from this review pass the quality gate. One confirmed bug is already flagged in an existing inline comment (line 164 of src/auto-filter-diff/auto-filter-diff.ts): the Phase 2 progressive cap uses slice(0, -1) to protect the last file in the ascending-risk sort, but when multiple unscored files exist they all sort to Infinity and only the very last is protected — the others remain removable, violating the "unknown = needs review" invariant.
All other items examined were verified clean: missing set -euo pipefail in the auto-filter step (single-command step, no functional impact), remainingLines preamble accounting (no production trigger path), TEST_FILE_RE regex (works correctly), step ordering (correct: filter → score → auto-filter → chunk), lock-check guard asymmetry (harmless: pr.diff is never created when skip=true), and extractFilePath edge cases (correct for normal paths).
77bdd24 to
0b9207e
Compare
docker-agent
left a comment
There was a problem hiding this comment.
Assessment: 🟢 APPROVE
The auto-filter-diff pipeline is well-structured and correct. The two-phase filtering logic in src/auto-filter-diff/auto-filter-diff.ts handles edge cases properly:
- Phase 1 (auto-exclude): Correctly removes score-0 known files while preserving unknown files for review.
- Phase 2 (progressive cap): Correctly sorts by risk score ascending and removes lowest-risk scored files first. Unknown files are intentionally exempt from removal (documented in code comments). The
slice(0, -1)guard ensures at least one file is always kept among scored files. remainingLinescalculation: Accurate —parseSectionspartitions thesplit('\n')array into non-overlapping slices, sosum(s.lines.length)equals the assembled diff's line count.TEST_FILE_REextension: Rust and Ruby test patterns are correctly scoped to file suffixes and directory components.review-pr/action.ymlwiring: Steps are correctly ordered (score → auto-filter → chunk),max-diff-linesinput is properly threaded through.tsup.config.tsentry map:auto-filter-diff/index.tsis correctly added since it backs a direct CLI step inaction.yml.
18 unit tests cover all phases and edge cases including empty diffs, single-file protection, and unknown-file preservation. No bugs found in the changed code.
Signed-off-by: Derek Misler <derek.misler@docker.com>
fbaf8f1 to
d246250
Compare
…events by structure GitHub Actions does not allow overriding GITHUB_* runner-injected variables via the env: block on a uses: composite action step. As a result, the test-mention-reply-toplevel and test-mention-reply-inline jobs were reading the real pull_request event file (which has no 'issue' field), causing parseEventContext() to throw 'Cannot read properties of undefined (reading number)'. Fix 1 — src/mention-reply/index.ts: Add a structural fallback in parseEventContext(): treat the event as a pull_request_review_comment if raw.pull_request exists AND comment.diff_hunk is present (a combination unique to inline review comment payloads). This makes the handler work correctly even when GITHUB_EVENT_NAME cannot be overridden and stays as 'pull_request'. Fix 2 — .github/workflows/test-e2e.yml: Write synthetic event payloads directly to $GITHUB_EVENT_PATH (the real runner-provided path, which is writable) instead of /tmp/test-event-*.json. Remove the non-working env: overrides for GITHUB_EVENT_PATH and GITHUB_EVENT_NAME from both 'Run mention-reply handler' steps — overriding GITHUB_* variables this way has no effect on composite actions.
Summary
Fixes the root cause of large-PR review timeouts by making the risk-scoring pipeline automatically filter out low-risk files before diff chunking, without requiring per-repo
exclude-pathsconfiguration.Root causes addressed
Risk scoring happened after chunking — scores were computed but never used to filter the diff. Every file (including test files, generated code, etc.) got chunked and processed by the full multi-agent pipeline.
TEST_FILE_REinscore-risk.tsmissed Rust/Ruby test files — Rust test/bench/spec files and Ruby spec files scored non-zero and were included in chunks unnecessarily.Changes
Change 1 — Extend
TEST_FILE_REinsrc/score-risk/score-risk.tsExtended the regex to also match:
_test.rs,_bench.rs,_spec.rs_spec.rbtests/,test/,benches/,__tests__/, orspecs/directory componentAdded 9 new Vitest tests covering these new patterns.
Change 2 — New module
src/auto-filter-diff/Pure TypeScript module with two-phase filtering:
maxDiffLines(default 3000), removes lowest-risk files first until it fits. Always keeps at least 1 file.Includes 18 Vitest unit tests covering all phases and edge cases.
Change 3 — Wire up in
review-pr/action.ymlmax-diff-linesinput (default"3000", set"0"to disable)New step order: Filter excluded paths → Score file risk → Auto-filter → Split into chunks → Generate file history
Change 4 — Propagate through
.github/workflows/review-pr.ymlAdded
max-diff-linesas a workflow-levelnumberinput (default3000) and passed it through to thereview-praction call.Change 5 —
tsup.config.tsAdded
'src/auto-filter-diff/index.ts'to theentrymap so tsup bundles it asdist/auto-filter-diff.js.Test results
Biome formatting and TypeScript type-check pass cleanly. The pre-existing
actionlintwarning about thenode24runner intest-e2e.ymlis unrelated to this PR (present onmainbefore these changes).