Repository navigation
research: corpus-wide runs of every scheme, SonarQube branch mode, and the paper kit - #59
Merged
Merged
Conversation
`batch --analyzer bandit|semgrep` passes the analyzer to each replay, so the shipped tools' identity methods can be measured on their own tools' findings across the whole corpus, not only on Flask and DefectDojo. Bandit reads Python only, so its batch leaves out the JavaScript repositories. Results go to results/corpus-<analyzer>/ unless --out is given. A result directory now counts as done only for the analyzer named in its analyzer.json (CodeGuard when the file is missing, as in replays from before it existed), so runs of different analyzers never satisfy each other's resume check. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
`transform <local repository> --ref <commit>` exports the Python files of that commit to a temporary directory and records the commit as `head` in summary.json. Corpus clones made by `batch` have no working tree, so this is what lets the controlled experiment (RQ2) run on the same pinned commits as the replay (RQ1). Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
The `sonar` scheme tracks a renamed file's findings against the old file, as a SonarQube pull-request analysis does with SCM renames. A branch analysis, which is what compares a long-lived baseline, first runs FileMoveDetectionStep: an added file is the removed one only if their line counts are within (0.84x, 1.18x) and the similarity of their line hashes (100 x (1 - edit distance / longer length)) is at least 85. Otherwise every finding in it is new. Add `sonar_branch`, the same tracker behind a port of that decision (FileMoveDetectionStep and SourceSimilarityImpl, SonarQube 26.10.0.133078). The harness pairs files by git's rename detection, so only SonarQube's decision for that pair is ported. Replay and drift pass `renamed` down to scheme_pairs, where schemes listed in trackers.RENAME_CHECKS may refuse a rename. In the corpus run, renamed files hold 287 of 23,237 persisting findings. Every key scheme includes the path and loses all of them; `sonar` loses 2.8%. The new scheme shows how much of that depends on the analysis mode. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
paper_kit.py reads one corpus batch per analyzer and writes rq1.csv, Table II as LaTeX (booktabs) and numbers.md, which lists every RQ1 number with its interval, median and counts. It adds a split of the false-new rate by whether the file was renamed, read from each replay's findings.jsonl, and reuses the cluster bootstrap of stats.py with one set of draws per analyzer. paper/outline.md plans the six-page paper: page budget, research questions, what each section and table holds, threats, and candidate related work to verify. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
paper_kit --transform reads each repository's transform-<label>/matrix.csv, pools the false-new and hidden counts per transformation and scheme with cluster-bootstrap intervals (rq2.csv), and draws the matrix as one heatmap (fig_rq2.pdf): false-new rates, then hidden rates for the two duplicating transformations, on a single-hue sequential ramp with every value printed. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
Bandit's B101 (assert used) is 91% of its persisting and 92% of its introduced findings in the corpus, 98% of them in test code, and its message never varies. --bandit-exclude leaves such rules out of the table: false-new, hidden and mispair counts are then taken from findings.jsonl, and the collision rate, which needs every file version, is not computed. All rules stay in numbers.md as bandit_all_rules. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
gt_sample.py draws a seeded, stratified sample of findings from the replays (edited lines; persisting findings that SonarQube or CodeGuard report as new; introduced findings a content scheme matched; and two control strata where every scheme agrees with the truth) and writes sample.md, with the code before and after each commit and a link to it, and sample.csv with an empty verdict column. paper/claims.md lists every RQ1 number the paper can cite, with its interval, counts and source file. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
Replays of the pinned corpus with every scheme, including both SonarQube modes: CodeGuard findings in 35 repositories and Bandit findings in the 25 Python ones, and the transformation experiment on the 25 Python repositories at their pinned commits. paper/ now holds Table II (table_rq1.tex), Fig. 1 (fig_rq2.pdf), the numbers behind them (numbers.md, rq1.csv, rq2.csv), the stats tables of the CodeGuard replays, claims.md with every citable number and its source, the outline with the commands that regenerate all of it, and a seeded sample of 100 ground-truth decisions to check by hand. Fig. 1 leaves out sonar_branch, which equals sonar when no file is renamed, and the ground-truth sample clips each diff to the two hunks nearest the finding. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
Quoted source lines can end in spaces, which the repository's pre-commit hooks strip; write sample.md the way the hooks leave it, so regenerating it reproduces the committed file. Signed-off-by: Vichitra Attri <mevichitra@gmail.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.
Summary
Turns the finding-identity harness into the material for a 6-page IEEE paper. It re-runs the 35-repository corpus with every identity scheme, adds the shipped tools' analyzers and SonarQube's branch-analysis behaviour, runs the controlled experiment (RQ2) on the corpus, and generates the paper's table, figure and numbers into
research/finding_identity/paper/. Every generated file there reproduces byte for byte from the commands inpaper/outline.md.Type of change
research/, not part of the released package)Checklist
git commit -s— DCO sign-off on all commitspytestpasses locallyruff check research/andruff format --check research/cleanMYPYPATH=src mypy --strict research/finding_identitycleanresearch/What changed
Harness
batch --analyzer bandit|semgrepreplays the corpus with that analyzer's findings. Bandit skips the JavaScript repositories. A result directory counts as done only for the analyzer named in itsanalyzer.json.transform <local repository> --ref <commit>exports that commit's Python files, so RQ2 runs on the same pinned commits as RQ1. Corpus clones have no working tree.sonar_branch: SonarQube's tracker as a branch analysis runs it. A renamed file keeps its findings only if SonarQube's file move detection accepts the pair: line counts within (0.84×, 1.18×) and line-hash similarity ≥ 85. This portsFileMoveDetectionStepandSourceSimilarityImplfrom 26.10.0.133078.sonarstays the pull-request mode, which takes renames from the SCM. Replay and drift passrenameddown to the matchers.Paper kit
paper_kit.pywrites Table II (table_rq1.tex),numbers.md,rq1.csv, the pooled RQ2 matrix (rq2.csv) and Fig. 1 (fig_rq2.pdf). It uses cluster-bootstrap intervals over repositories, splits the false-new rate by renamed files, and can leave rules out (Bandit's B101).gt_sample.pydraws a seeded, stratified sample of 100 ground-truth decisions for a manual check (paper/ground_truth_check/).paper/outline.md(page budget, section contents, reproduction commands) andpaper/claims.md(every citable number with its interval and source).Results
CodeGuard findings in 35 repositories (23,237 persisting / 1,974 introduced); Bandit findings in 25 Python repositories. Rates in %, with cluster-bootstrap 95% intervals.
linegithubcodeguardsonarsonar_branchbanditcodeguard's false-new reports.githubloses 77.5% on edits below the line;codeguardloses 100% on function renames and extraction;sonarsurvives most edits through its fallback passes.line,line_text,githubandcodeguard-family results are identical to the first corpus run (2026-10-14).Test evidence
New tests cover the analyzer resume check and an end-to-end Bandit batch,
transform --refon a bare repository, and SonarQube's similarity score. That last one includes a seeded comparison with the textbook edit distance and the exact line-count bounds (ceil(100 × 1.18) = 119). They also cover rename gating, the rename split, rule exclusion, and RQ2 pooling.Notes for reviewer
sonar_branchmodels SonarQube's decision only for file pairs that git already detects as renames (git diff -M, 50%). A move SonarQube would find but git would not is not modelled. This is documented in the README.insert_toprow forbandit.paper/holds only aggregates and the 100-finding sample.Generated by Claude Code