feat(orb): randomized close-audit holdout — the selective-labels fix for close precision - #8841
Conversation
…judication rubric The gate's only confirmation signal is 'no human reversed it' -- a lower bound on error, not a label: humans reverse only what they notice, so a silently-wrong merge scores as correct and every accuracy figure inherits the bias. Closes #8830. Part of epic #8828 (Phase 2 -- labels). - decision_audit_labels (migration 0178): one label per PR ever, adjudications comparable only within a rubric version - pure stratified sampler: merges oversampled (the costly arm), a first-time-author stratum (weakest priors), deterministic under an injected rng, thin strata spill instead of shrinking the sample - weekly cron enqueue (Tuesday 08:00 UTC), flag-gated by LOOPOVER_DECISION_AUDIT (default OFF, byte-identical), self-host only; the dispatch re-checks the flag so a stale queued job after a flag flip does zero work - internal adjudication routes: list (filterable) + adjudicate; a second adjudication 409s -- labels are calibration data, rewrites must be deliberate via a rubric-version bump, never silent - docs/decision-audit-rubric.md v1: judge the decision at decision-time knowledge, not the outcome; 'uncertain' is a first-class label excluded from both sides and tracked as a rate
…pfront The randomized close-holdout (#8831) lands its adjudications in the same label store; widening the CHECK now spares that PR a SQLite table rebuild for one enum value.
A holdout_close row (#8831) is created while the PR is still held -- no realized outcome exists yet; the human adjudication is its ground truth. The weekly sampler always supplies an outcome.
…des the UPDATE Superagent P1 on this PR, and it is right: select-then-update lets two concurrent adjudications both pass the pending check and both write, silently violating the one-adjudication-per-label guarantee. The predicate now rides the UPDATE (WHERE status = 'pending'); zero changes disambiguates 404 vs 409 with a read that no longer guards anything. Regression test races two concurrent adjudications: exactly one 200, one 409, one surviving label. Also binds LOOPOVER_NATIVE_SOURCE instead of a hardcoded source literal (branding-drift check).
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Logic backtestReplayed 0 historical case(s) for Backtest comparison:
|
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
loopover-ui | 9c92c59 | Commit Preview URL Branch Preview URL |
Jul 26 2026, 11:51 AM |
❌ 2 Tests Failed:
View the top 2 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
|
Caution 🛑 LoopOver review result - fixes requiredReview updated: 2026-07-26 11:42:25 UTC
Review summary Nits — 6 non-blocking
CI checks failing
Decision 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. 🟩 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.
|
Review blocker on this PR, and it is right: the author count read every cached pull_requests row, so a newcomer with several open-but-undecided PRs and exactly one decided PR was wrongly marked veteran -- starving the stratum whose whole purpose is weak-prior newcomers. The count now requires a realized pr_outcome per counted PR, with a regression test seeding open PRs that must not inflate the total.
…for close precision When the bot closes a PR we never observe whether merging would have been fine: close-precision is estimated only on closes humans happened to contest, a biased sample (selective labels, Lakkaraju et al. KDD 2017). ORB is deterministic, so every off-policy estimator is undefined -- propensities are 0/1, no overlap. Randomization is the only fix. Closes #8831. Part of epic #8828 (Phase 2 -- labels). A configurable fraction epsilon (gate.closeAuditHoldoutPct, 0-20%, manifest-only, default 0 = byte-identical) of would-AUTO-close PRs is HELD for human adjudication instead, with epsilon and the draw logged -- the propensity record that makes counterfactual evaluation well-defined for the first time. Invariants, each pinned by a test: - the draw consumes the FINAL post-breaker plan: it can divert the decided close to a human but never influence the decision - heuristic closes only: policy closes are enforcement (#8827), and staged closes already get a human - HARD ordering rule: the plan is only diverted when the propensity record wrote -- an unlogged hold would silently bias every estimator, so on a write failure the close proceeds (the instrument degrades, never the gate) - held PRs land in decision_audit_labels as stratum holdout_close with a NULL outcome (the PR is still open; the adjudication IS the label)
…mas and preview The settings-parity gate requires every RepositorySettings field on RepositorySettingsSchema and the settings-preview shape; regenerated openapi.
1ec12ac to
9c92c59
Compare
- config/examples/loopover.full.yml gains the closeAuditHoldoutPct doc block its .loopover.yml.example twin gained in #8841 (the template parity test compares them from WHERE IT LIVES onward) - register loopover_close_audit_holdouts_total in DEFAULT_METRIC_META (the metrics drift guard requires every emitted literal)
What
A randomized ε-holdout on would-auto-close PRs — the only mechanism that can produce an unbiased close-precision estimate. Closes #8831 (epic #8828, Phase 2). Stacked on #8840 (uses its
decision_audit_labelstable); mergeable once that lands.Why
The selective-labels problem: when ORB closes a PR, we never observe whether merging would have been fine. Close-precision today is estimated only on the closes humans happened to contest — a biased sample. And because ORB is deterministic, every off-policy estimator (IPS, doubly-robust) is undefined: logged propensities are 0/1, there is no overlap. Randomization is not one option among several; it is the only fix (Lakkaraju et al., KDD 2017). This was called out as the single most important negative result in the epic's research basis — do not build OPE infrastructure without this.
How
gate.closeAuditHoldoutPct(manifest-only, 0–20%, fractional allowed, default 0 = byte-identical): that fraction of would-auto-close PRs is HELD for human adjudication instead of closing, with ε and the draw persisted — the propensity record.Invariants, each pinned by a test:
maybeApplyCloseAuditHoldoutsits immediately afterapplyPrecisionBreakersin the processor; all downstream consumers — disposition labels, the recorded verdict, execution — read the post-holdout plan, so a diverted PR honestly recordshold.)auto_with_approval) closes already get a human.decision_audit_labelsas stratumholdout_closewith a NULL outcome (the PR is still open; the human adjudication is its ground truth) and surface the manual-review label via the exact conversiondowngradeCloseToHolduses.Verification
draw ≥ εcase).