feat(benchmark): leak-proof frozen-repo snapshot builder (#9259) - #9605
Conversation
An agent must see EXACTLY the repository state a maintainer saw at commit T and nothing after it. A future-information leak inflates every score built on top, and it does so invisibly -- a leaked snapshot still produces perfectly well-formed numbers. That makes leak-proofing the deliverable rather than a property, which is why all filtering lives in a pure, exhaustively tested core instead of inline in the CLI. What a snapshot carries: open PRs and issues as of T, with labels filtered to those applied at or before T, plus gate decisions recorded at or before T. What it never carries: anything created after T (never admitted, so a downstream bug cannot reintroduce it), and the OUTCOME of any included unit -- an open PR's eventual merge/close is precisely what the agent is asked to predict, so carrying it would make the snapshot an answer key rather than a benchmark. The frozen type has no outcome field at all. The T boundary is inclusive and defined ONCE, in atOrBefore, so no field can quietly disagree with another. An unreadable timestamp is treated as not-visible: a date nobody can parse might be from after T, and the cost of excluding it is lost context rather than an inflated score. Two real defects were found and fixed while testing, both of which would have broken reproducibility silently: - checksumSnapshot spread its argument, so handing it a whole snapshot (the natural re-verification call) folded the existing checksum into its own preimage and returned a wrong digest with no error. The committed fields are now listed explicitly, making the function total over both shapes and making an added field a compile error at the commitment. - The decision sort tied on (workUnitId, decidedAt, action), so two decisions differing only in reasonCode ordered by input order and the checksum moved when the CLI read them the other way round. The chain now ends in a canonical-serialization comparison, total by construction. The CLI refuses to write a snapshot that fails an independent leak audit: an inflated benchmark is worse than no benchmark, because its numbers look fine. Closes #9259
|
Warning ⏸️ LoopOver review result - manual review recommendedReview updated: 2026-07-29 04:25:43 UTC
Review summary Blockers
Nits — 5 non-blocking
Concerns raised — review before merging
📋 Copy for AI agents — paste into your coding agentDecision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Decision record
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9605 +/- ##
==========================================
- Coverage 90.24% 89.96% -0.28%
==========================================
Files 900 900
Lines 112914 112245 -669
Branches 26776 26685 -91
==========================================
- Hits 101896 100981 -915
- Misses 9687 9932 +245
- Partials 1331 1332 +1
Flags with carried forward coverage won't be shown. Click here to find out more. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| 🔵 In progress View logs |
loopover-ui | 4cdb151 | Jul 29 2026, 04:02 AM |
…a truncated snapshot Review caught both list reads stopping at page one. The consequence is worse than incompleteness: the snapshot's whole value is that two runs over the same (repo, T) produce the same checksum, and a truncated read makes that checksum a function of how many records the repo happened to have -- so the same T could yield two different "authoritative" snapshots. And it is silent, because the output is a perfectly well-formed snapshot that is simply missing history. - fetchAllPages reads to exhaustion, stopping at the first short page. - Both call sites use it: the issue/PR list, and per-issue label history. The second is the sharper of the two -- dropping early `labeled` events omits labels that were genuinely applied before T, which makes the snapshot WRONG rather than merely thinner. - Hitting the page bound is REPORTED, not silently accepted, and the CLI refuses to write a truncated snapshot -- the same posture as the leak audit, for the same reason: a snapshot nobody can reproduce is not one worth publishing. - A read error propagates instead of being swallowed into a short list that looks complete. The gap survived because the pagination lived inline in an untested CLI, so fetchAllPages is now an injectable seam with five tests covering multi-page reads, the short-page stop, the exactly-full-last-page extra read, empty/single-page sources, the bound, and error propagation.
What
An agent must see exactly the repository state a maintainer saw at commit T and nothing after it. A future-information leak inflates every score built on top, and it does so invisibly — a leaked snapshot still produces perfectly well-formed numbers. That makes leak-proofing the deliverable rather than a property of the code, which is why all filtering lives in a pure, exhaustively tested core (
scripts/frozen-repo-snapshot-core.ts) instead of inline in the CLI where it would be untestable.Carried, each filtered to its state at T: open PRs and issues, with labels filtered to those applied at or before T (label application times come from the issue-events timeline — a label object alone carries no timestamp, so without that every label would be unfilterable), plus gate decisions recorded at or before T.
Never carried: anything created after T — never admitted, so a downstream bug can't reintroduce it — and the outcome of any included unit. An open PR's eventual merge/close is precisely what the agent is being asked to predict, so a snapshot carrying it would be an answer key rather than a benchmark. The
FrozenWorkUnittype has no outcome field at all.The T boundary is inclusive and defined once, in
atOrBefore, so no field can quietly disagree with another. An unreadable timestamp is treated as not-visible: a date nobody can parse might be from after T, and the cost of excluding it is lost context rather than an inflated score.Two real defects found while testing
Both would have broken reproducibility silently, and both are fixed in the source rather than worked around in the tests:
checksumSnapshotspread its argument, so handing it a wholeFrozenRepoSnapshot— the natural re-verification call — folded the existingsnapshotChecksuminto its own preimage and returned a different, wrong digest with no error. The committed fields are now listed explicitly, which makes the function total over both call shapes and makes an added field a compile error right at the commitment, which is where you want to notice it.(workUnitId, decidedAt, action), so two decisions differing only inreasonCodefell back to input order — and the snapshot checksum moved when the CLI happened to read them the other way round. That's the exact reproducibility property this module exists to guarantee. The chain now ends in a canonical-serialization comparison, total by construction, so adding a field toFrozenDecisioncan't reintroduce the hole.Also simplified
canonicalize's comparator from three arms to two: object keys are unique by definition, so the "equal keys" arm was dead code no test could reach.The CLI refuses to write a leak
auditSnapshotForLeaksre-derives the no-future-information property independently of the builder, and the CLI exits non-zero rather than writing a snapshot that fails it. An inflated benchmark is worse than no benchmark, because its numbers look fine.Tests (18, 100% of the core's branches)
The invariants the issue asks for, asserted directly: a fixture full of post-T records producing a snapshot that provably excludes them (checked by scanning the serialized snapshot for every future marker, so a leak by any route fails); identical checksums from differently-ordered inputs; a snapshot built at T that doesn't move when a year of post-T history is appended; the outcome-never-included regression; boundary behavior at exactly T in both directions; fail-safe handling of unreadable timestamps in both the visible and open-at-T decisions; both
checksumSnapshotcall shapes; every leak shape the audit catches; and the full comparator chain including a byte-for-byte duplicate.scripts/**isn't Codecov-measured, but the core carries the correctness here, so it's covered to the same bar the rest of the harness is.Closes #9259