Diff the working tree when it is dirty, instead of scanning everything - #170
Draft
Ibrahimrahhal wants to merge 2 commits into
Draft
Diff the working tree when it is dirty, instead of scanning everything#170Ibrahimrahhal wants to merge 2 commits into
Ibrahimrahhal wants to merge 2 commits into
Conversation
A dirty worktree took incremental scanning off the table unless the run passed --ignore-dirty-worktree, and that is what almost every CLI scan is: across 14 days of production traffic, 3,466 of 4,539 CLI scans arrived flagged dirty and not one of them scanned incrementally. Only 17 reached the gates that pick a baseline. CI dirties a worktree as a matter of course by installing dependencies or building before it scans. The refusal was never needed. The flag did not paper over a dirty tree; it moved the far side of the diff to the working tree, which is what the run uploads, so edited and untracked files are named and rescanned like any other change. Gitignored files are absent from both the diff and the archive, so no unnamed file is left to carry stale findings forward. That makes the worktree diff the accurate choice for a dirty upload rather than a concession, and the server already accepts one: its dirty gate passes a diff that claims to cover the worktree. So incremental no longer consults the flag. --ignore-dirty-worktree keeps its other, genuinely lossy meaning for --skip-if-commit-scanned-recently, where it reuses a scan that does not cover the uncommitted changes. --disable-incremental is still the way to opt out. Co-authored-by: ibrahim <ibrahim@corgea.com>
1.11.1 gave the flag `requires = skip_if_commit_scanned_recently`, so passing it alone was an error. 1.12.0 dropped that clause to let the flag also put incremental back on the table for a dirty tree, and the previous commit means nothing needs it for that any more. That leaves a flag a run can pass alone, where it governs nothing at all. Pipelines do pass it that way, to get the incremental scan of a dirty tree it used to enable, and would otherwise get full scans with no indication why. Re-adding the `requires` clause would break those pipelines on upgrade, so warn instead and say where the behaviour went. Co-authored-by: ibrahim <ibrahim@corgea.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Incremental scans are effectively not happening for CLI users. Over 14 days of production traffic (
trigger_source = 'cli',engine = 'corgea-blast', non-prework):76% of CLI scans arrive flagged dirty, and before this change every one of them refused incremental unless the run passed
--ignore-dirty-worktree. Only 17 scans in two weeks got as far as looking for a baseline. That is expected rather than surprising: CI dirties a worktree as a matter of course by installing dependencies or building before it scans, and the flag is opt-in.What changed
resolve_incremental_planno longer consultsignore_dirty_worktree. A dirty tree now diffs the working tree, which is what the flag already did.The refusal was never needed for correctness. The flag did not paper over a dirty tree — it moved the far side of the diff from
HEADto the index and working tree, so files edited but not committed are named in the changed-file list and rescanned like any other change. The concern the gate existed for (a commit-to-commit diff leaves a modified file off the list, so its old findings are copied forward over content nothing analyzed) is exactly what the worktree diff avoids. Since the archive is the working tree, it is the accurate diff for a dirty upload rather than a concession.Two things make it safe end to end:
WalkBuilder::standard_filters(true)), so no unnamed file is left to carry stale findings forward. Covered by a new test._try_incremental_scan's dirty gate passes when the client diff claims to cover the worktree, and the CLI sendsincremental_covers_worktree=true. The plan is built from the same reconciledRepoInfothe upload'sdirtyfield comes from, so the two cannot disagree.--ignore-dirty-worktreekeeps its other, genuinely lossy meaning for--skip-if-commit-scanned-recently, where it reuses a prior scan that does not cover the uncommitted changes. Its help text now covers only that, and--disable-incrementalis still the way to opt out of incremental entirely.The flag now warns when it governs nothing
1.11.1 defined the flag with
requires = "skip_if_commit_scanned_recently", so passing it alone was a hard argument error. 1.12.0 dropped that clause precisely so the flag could also put incremental back on the table for a dirty tree — which is no longer needed.That leaves a flag a run can pass alone, where it now governs nothing. Pipelines do pass it that way, to get the incremental scan of a dirty tree it used to enable, and would otherwise get full scans with no indication why. Re-adding
requireswould break those pipelines on upgrade, so the second commit warns instead and says where the behavior went.Notes for review
ignore_dirty_worktree_for_runparameter threaded throughblast::run→start_new_scanexisted only to feed this refusal, so it is gone.main.rswas passing the same value twice.blast_upload_planencoded "a dirty tree never asks" for a baseline; it now always expects the lookup.narrowed_blast_upload_plancovers the one case that still skips it,--target/--exclude, where carrying findings forward for files the archive no longer holds would be wrong.a_dirty_worktree_skips_the_baseline_lookup_and_scans_everythingasserted behavior that no longer exists and is redundant with the worktree-diff test plusa_project_with_no_baseline_scan_uploads_without_a_diff, so it is deleted.Testing
./harness check— 814 tests pass, strict clippy and format clean.The two existing tests for the worktree diff (
a_worktree_diff_names_edited_and_untracked_files,a_worktree_diff_still_spans_the_commits_behind_it) already covered the path this promotes to the default. Addeda_worktree_diff_leaves_gitignored_files_outfor the gitignore claim above. The end-to-enda_dirty_worktree_diffs_the_working_tree_rather_than_scanning_everythingnow runs without the flag, asserting the upload carriesdirty=truealongsideincremental_base_sha,incremental_changed_filesandincremental_covers_worktree=true;ignore_dirty_worktree_alone_warns_and_scans_incrementally_anywayshares that setup and asserts the same scan plus the warning.What this does not fix
This clears the gate that 76% of CLI scans stop at. It does not, on its own, guarantee they go incremental, because a dirty scan can never become a baseline (
base_filterrequiresworktree_dirty=False, correctly — a dirty scan's contents are not reproducible from its commit). A project whose every CLI scan is dirty has no baseline to diff against and needs one from a clean run, CI, or an SCM integration. Separately,baseline_branchesonly ever asks aboutorigin/HEAD(usually absent in CI checkouts) plusmainandmaster, so a project whose trunk is named anything else finds no baseline either. Both are being measured before any change is proposed.The other two buckets are untouched: 854 scans with no branch or sha (detached HEAD, which is what PR pipelines check out) and 210 on a CLI too old to report the flag at all.