Skip to content

feat(benchmark): multi-class proposal scorer on the shared primitives (#9262) - #9599

Merged
JSONbored merged 1 commit into
mainfrom
feat/benchmark-scorer-9262
Jul 29, 2026
Merged

feat(benchmark): multi-class proposal scorer on the shared primitives (#9262)#9599
JSONbored merged 1 commit into
mainfrom
feat/benchmark-scorer-9262

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Stacked: #9595 (#9260) → #9598 (#9261) → this. Based against #9598's branch so the diff shows only this change; retarget as the stack lands.

What

Multi-class scoring built on scoreBacktest and compareBacktestScores, deliberately not beside them. This module is an adapter that reshapes (proposal, ground truth) pairs into the exact inputs those functions already take — a second scoring implementation is precisely the drift #9262 exists to prevent, so the guarantee is mechanical: an equivalent binary case scored through this adapter and through scoreBacktest directly produces the identical report, asserted as the suite's first test.

The reuse works by borrowing the primitive's positive-class slot per action: for action A, the positive class is "the realized action was A" and the classifier answers "the agent proposed A". The ruleId slot carries the action name, which makes each per-action report self-labeling and makes compareBacktestScores' rule-mismatch throw double as a guard against accidentally comparing two different actions.

The aggregation decision (issue requirement 2), recorded in the module header

Macro is the headline; micro is published alongside.

Under single-label scoring — one prediction per work unit — micro precision, micro recall and plain accuracy are all the same number, so it's reported once, honestly labeled, rather than three times as if independent. Being pooled, it's dominated by whichever action is most frequent, which here is overwhelmingly merge: an agent that answers "merge" to everything scores 0.8 micro on the test corpus while never having made a decision. Macro weights each action equally and exposes exactly that agent through its floor-level close/request_changes numbers — and since the benchmark's question is "can this agent make maintainer decisions", including the rare expensive ones, macro is the number that answers it. Both are published because a benchmark reporting only its headline invites the reader to reconstruct the other one wrongly.

An action with no realized instances has null metrics and is excluded from the macro mean rather than counted as 0; actionsScored publishes how many actions entered it, so "macro over 1 of 5 actions" can't be misread as "macro over 5".

Coverage and denominators (#9215 semantics)

coverage = decided / (decided + abstained); abstentions lower coverage and never enter a confusion-matrix count. Silence and a declared {kind: "abstain"} are the same act and are scored the same way — scoring them differently would reward whichever one an agent's emitter happened to produce. #9261's unresolved units leave the denominator before scoring starts, and proposals for units outside the snapshot are counted as unscorableProposals: ignored for scoring so padding inflates nothing, but visible, because a nonzero count means the agent is answering a different question than the one asked. Every rate is null rather than 0 when its denominator is empty.

Pareto floor across actions (requirement 4)

Extended to the multi-class case: any regressed action decides the verdict. The regression test uses a clean trade — the candidate buys perfect merge recall (0.33 → 1) by spending close recall (1 → 0.33) with precision pinned at 1 on both sides — and asserts the verdict is regressed, not a wash.

Tests (13 node:test cases, 100% of branches)

Anti-drift equality against the primitive (plus hand-checked TP/FP/TN/FN); all five actions one-vs-rest; the answer-merge-to-everything regression showing micro 0.8 against a floored macro; null-metric exclusion from the macro mean; abstention/coverage semantics with declared and silent abstentions treated identically; unresolved exclusion; unscorable proposals; last-proposal-wins resubmission; the empty-corpus null arms; report identity fields; the Pareto trade regression; improved/unchanged verdicts with per-action detail; and the cross-subject throw.

Closes #9262

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb

loopover-orb Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-28 23:36:43 UTC

3 files · 1 AI reviewer · no blockers · CI green · clean

⏸️ Suggested Action - Manual Review

  • AI review did not produce public notes: The configured AI reviewer returned no usable public assessment for this PR head.

Review summary
AI review is unavailable for this PR head. LoopOver is holding this PR for manual review until the configured AI provider returns a usable public review summary.

Nits — 1 non-blocking
  • AI review did not produce public notes — Fix the configured AI provider, then re-run LoopOver review before relying on the result.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ⚠️ Gate result — Not blocking (Advisory; not blocking this PR.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #9262
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 14 registered-repo PR(s), 13 merged, 310 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 14 PR(s), 310 issue(s).
Improvement ✅ Minor risk: clean · value: minor
Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is registered but has no active allocation in the current snapshot.
  • Public profile languages: Python, TypeScript, Ruby, Go, MDX, Shell, Solidity, JavaScript
  • Official Gittensor activity: 14 PR(s), 310 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Then work through the remaining 1 step in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask 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.

  • @loopover ask <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Decision record
  • action: hold · clause: ai_review_inconclusive
  • config: 8a0f1607cd8ac526eaf7258cbda2f86bba0eeb27f50a8119e017c561fed10c38 · pack: oss-anti-slop · ci: passed
  • record: 317fde5d10cf62b7ebad159b32757053dc7855dace691436b5e40c2d0b7e1401 (schema v5, head 6426fc9)

🟩 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.

  • Re-run LoopOver review

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 28, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
loopover-ui 6e9a31d Commit Preview URL

Branch Preview URL
Jul 28 2026, 11:20 PM

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.91%. Comparing base (1819298) to head (6e9a31d).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9599      +/-   ##
==========================================
+ Coverage   89.89%   89.91%   +0.01%     
==========================================
  Files         883      884       +1     
  Lines      111692   111911     +219     
  Branches    26579    26605      +26     
==========================================
+ Hits       100408   100623     +215     
  Misses       9992     9992              
- Partials     1292     1296       +4     
Flag Coverage Δ
backend 95.37% <2.22%> (-0.08%) ⬇️
engine 66.55% <100.00%> (+0.20%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...loopover-engine/src/calibration/benchmark-score.ts 100.00% <100.00%> (ø)
packages/loopover-engine/src/index.ts 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes

@JSONbored
JSONbored force-pushed the feat/benchmark-scorer-9262 branch from d1e8271 to f41fd97 Compare July 28, 2026 21:52
@JSONbored
JSONbored force-pushed the feat/benchmark-scorer-9262 branch from f41fd97 to 6426fc9 Compare July 28, 2026 21:54
@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 28, 2026
@JSONbored
JSONbored force-pushed the feat/benchmark-scorer-9262 branch from 6426fc9 to 4b0caee Compare July 28, 2026 22:55
Base automatically changed from feat/benchmark-ground-truth-9261 to main July 28, 2026 23:17
…#9262)

Scoring built ON scoreBacktest and compareBacktestScores, deliberately not
beside them: this module is an adapter that reshapes (proposal, ground
truth) pairs into the exact inputs those functions already take. A second
scoring implementation is the drift the issue exists to prevent, so the
guarantee is mechanical -- an equivalent binary case scored through this
adapter and through scoreBacktest directly produces the identical report,
asserted in the tests.

The reuse borrows the primitive's positive-class slot per action: for
action A the positive class is "the realized action was A" and the
classifier answers "the agent proposed A". The `ruleId` slot carries the
action name, which makes each per-action report self-labeling and makes
compareBacktestScores' rule-mismatch throw double as a guard against
comparing two different actions.

AGGREGATION -- the recorded decision, in the module header. Macro is the
headline, micro published alongside. Under single-label scoring micro
precision, micro recall and accuracy are all the same number and it is
reported once, honestly labeled, rather than three times as if
independent; being pooled, it is dominated by the most frequent action, so
an agent answering "merge" to everything scores 0.8 on this corpus while
being worthless. Macro weights each action equally and exposes exactly
that agent through its floor-level close/request_changes numbers, which is
why it answers the benchmark's actual question. An action with no realized
instances has null metrics and is EXCLUDED from the macro mean rather than
counted as 0, and actionsScored publishes how many entered it.

Coverage follows #9215: coverage = decided / (decided + abstained);
abstentions lower coverage and never enter a confusion-matrix count.
Silence and a declared abstention are the same act and are scored the
same way. #9261's unresolved units leave the denominator before scoring
starts, and proposals for units outside the snapshot are counted as
unscorable -- ignored for scoring, so padding inflates nothing, but
visible, because a nonzero count means the agent answered a different
question than the one asked.

The Pareto floor extends to the multi-class case: ANY regressed action
decides the verdict, so gaining on merge while losing on close is a trade,
and a trade is not a win.

Closes #9262
@JSONbored
JSONbored force-pushed the feat/benchmark-scorer-9262 branch from 4b0caee to 6e9a31d Compare July 28, 2026 23:17
@JSONbored
JSONbored merged commit 534dfd5 into main Jul 29, 2026
8 checks passed
@JSONbored
JSONbored deleted the feat/benchmark-scorer-9262 branch July 29, 2026 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

benchmark: proposal scorer — multi-class over the existing confusion-matrix + Pareto primitives

1 participant