Repository navigation
research: land the drift mode and the 35-repository corpus on main - #58
Merged
Merged
Conversation
Consecutive commit pairs are too easy a test: almost every persisting finding has only moved. Baselines are created once and compared with much later versions, so add a "drift" mode that picks an anchor commit c0 and scores every identity scheme between c0 and c_k for each span k. The ground truth is chained: each anchor finding's line is followed through every intermediate first-parent commit with map_lines on that step's diff, following renames per step, and records whether any step edited it. Only c0 and each c_k are scanned; intermediate commits are read only as blobs of files that hold tracked findings. - drift.py: trace_files, chain_lines, per-span comparison, CLI arguments - summarize.py: per-span tables, scheme x span pivots, pooled "ALL" runs and a long-format CSV (label, span, scheme, rates) for plotting - matching.py: split the scoring out of evaluate() as score(), unchanged behaviour, so both modes share the outcome taxonomy - gitrepo.py: files() lists a commit's tree - cli.py: "drift" and "drift-summary" subcommands - tests: synthetic repository with insertion, line edit, file rename and function rename; chaining and lineage unit tests Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
Each replay now also scores the findings of every rule category (security, performance, quality) on their own and writes the results to summary.json under by_category, with the same totals and collisions blocks as the summary itself. Scheme keys include the rule ID and the ground truth only pairs findings of the same rule, so the categories add up exactly to the overall totals; a test checks this. The change is additive: existing keys and outputs are unchanged. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
…dentity corpus.csv lists 36 open-source web applications (26 Python, 10 JavaScript/TypeScript), each pinned to a commit, with its licence, framework and why it qualifies. corpus.py pins rows to their branch head and re-checks the measurable selection criteria at the pinned commit from git alone: at least 200 first-parent commits in the two years before it, a recent pinned commit, a single OSI-approved root licence, and the declared back-end language as the majority of analysable files. The README records the criteria and the 24 rejected candidates with their reasons. `batch` replays every corpus repository at its pinned SHA in parallel, one replay process per repository. It resumes by skipping repositories whose summary already covers the pinned SHA and commit count, and logs failures to batch.jsonl and per-repository logs without stopping. `stats` reports, for all findings and for security findings, pooled rates with Wilson intervals, cluster-bootstrap intervals over repositories, macro-averaged rates, and the median and interquartile range of per-repository rates, as CSV and Markdown tables, with an optional box plot (matplotlib, listed in requirements.txt). Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
The single wide Markdown table dropped the separator after the median column. Each scope now gets a false-new table with all its intervals and a second table for the other metrics. The box plot uses a symmetric log axis so rates of a few percent stay visible next to the line scheme. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
…rpus Adds paper/ with the aggregated outputs of the 35-repository run: pooled rates with Wilson and cluster-bootstrap intervals, macro rates, per-repository rates and spread, a per-repository Markdown table (new per_repo.md output of stats) and the box plot of per-repository false-new rates. CTFd commits Vite build output under CTFd/themes/*/static/assets/ that the harness does not skip, so its replay was dominated by generated bundles (12,944 findings compared in its first 75 commit pairs). It is excluded under a new, documented "no committed build output" criterion. The README records the run's runtime and notes that renamed files make every scheme lose its findings, the main source of the residual false-new rate. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
…d rates Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
Add long-span drift mode with chained ground truth to the finding-identity harness
Brings in the long-span drift mode (PR #53). The conflicts were in the command line and the README, where both sides only added: cli.py registers the drift, drift-summary, batch, corpus and stats commands, and the README keeps both the corpus sections and the drift-mode limitations. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
Finding identity: 35-repository corpus, batch runner and statistics
PRs #53 (long-span drift mode) and #55 (corpus, batch runner, statistics and the paper/ tables) were merged into the branch of #51 after #51 itself had been merged, so they never reached main. Conflicts, all resolved by keeping both sides: - cli.py: register the transform subcommand (main) next to drift, drift-summary and the corpus commands; replay keeps main's --analyzer and per-analyzer schemes. - scan.py: the Scanner keeps main's pluggable analyzer and gains the per-category totals. - requirements.txt: main's pinned research dependencies; matplotlib now also serves `stats --plot`. - .gitignore: ignore tables/ as well as fidelity/.build/ and .cache/. - README.md: keep both the Fidelity/RQ2 sections and the Corpus/Batch/Statistics sections; note that the committed paper/ tables predate the sonar and bandit schemes. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
Drift mode pooled the findings of every compared file into one list before scoring. That was harmless for the key-based schemes, whose keys include the path, but the SonarQube tracker (merged into main alongside) compares one file's findings and lines, so pooled input let it pair findings across files: in the drift test it "mispaired" the finding of a renamed file with one in another file. Score each file pair on its own, as the consecutive mode does, and sum the counts. The chained ground truth is unchanged. The drift tests looped over every scheme but `line` with outcomes written for key-based schemes. Restrict those loops to the key-based schemes and check the sonar and bandit outcomes explicitly: SonarQube keeps the renamed file's finding but loses the edited one; Bandit, which ignores location and code, keeps the edited one but loses the renamed file's; both take the new copy of the old line for the old finding. Signed-off-by: Vichitra Attri <mevichitra@gmail.com>
mevichitra
force-pushed
the
claude/land-research-corpus
branch
from
October 17, 2026 05:12
1912a1f to
6bfe1d3
Compare
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
#53 (long-span drift mode) and #55 (35-repository corpus, batch runner, statistics and the committed
paper/tables) were merged intoclaude/nice-allen-ptg63r, the branch of #51, after #51 had already been merged intomain. About 6,000 lines of research code and results never reachedmain. This PR merges that branch intomain, resolves the conflicts with #54 (RQ2 transformations) and #56 (SonarQube, Bandit and Semgrep schemes), and fixes a bug in drift mode that only appears once the two are combined.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
Merge commit, conflicts resolved by keeping both sides:
cli.py: thetransformsubcommand (Add controlled transformation experiment for finding identity (RQ2) #54) is registered next todrift,drift-summaryand the corpus commands (batch,corpus,stats).replaykeeps--analyzerand the per-analyzer schemes (research: compare the identity methods of SonarQube, Bandit and Semgrep #56).scan.py:Scannerkeeps the pluggable analyzer (research: compare the identity methods of SonarQube, Bandit and Semgrep #56) and gains the per-category totals (Finding identity: 35-repository corpus, batch runner and statistics #55).requirements.txt: keeps research: compare the identity methods of SonarQube, Bandit and Semgrep #56's pinned research dependencies;matplotlibnow also servesstats --plot..gitignore: ignorestables/as well asfidelity/.build/and.cache/.README.md: keeps the Fidelity and RQ2 sections and the Corpus, Batch and Statistics sections. It now notes that the committedpaper/tables predate thesonarandbanditschemes and the line-separator fix, and thatbatch --forcere-scores every scheme.research: score drift spans file by file: drift mode pooled every compared file's findings into one list before scoring. That was harmless for the key-based schemes, whose keys include the path. The SonarQube tracker from #56, though, compares one file's findings and lines, so the pooled input let it pair findings across files. In the drift test it "mispaired" the finding of a renamed file with one from another file. Each file pair is now scored on its own, as the consecutive mode does, and the counts are summed. The chained ground truth is unchanged.The drift tests looped over every scheme except
line, with outcomes written for key-based schemes. Those loops now cover the key-based schemes, andsonarandbanditget explicit checks:sonarbanditTest evidence
Before the drift fix, the merged tree failed
test_span_2_edit_loses_the_edited_finding(bandit) andtest_span_3_file_rename_breaks_every_path_based_key(sonar:{'known_ok': 1, 'mispaired': 1, 'false_new': 1}).Notes for reviewer
paper/tables are out of date. They come from the corpus run of 2026-10-14, which scored onlyline,line_text,githuband thecodeguardfamily. The paper needs a re-run withbatch --forceto add thesonarandbanditcolumns.--analyzer banditorsemgrep, the per-category totals put every finding underunknown, because the categories come from CodeGuard's rule registry. Sostatshas no security-only table for those runs.claude/nice-allen-ptg63rcan be deleted.