fix(orb): report null mergeRate for a zero-sample slop band - #9921
Conversation
buildSlopOutcomeCalibration fabricated a 0% merge rate for a slop band with no resolved PRs, which for a discrimination table reads as "every PR in this band was closed" -- the strongest possible claim the table can make. Mirror overallMergeRate's existing null-for-empty treatment: SlopBandCalibration.mergeRate is now number | null, computeDiscriminates narrows sampled bands with a type guard instead of comparing against a nullable field, and the MCP CLI's shared n/a-below-sample renderer now actually exercises its null arm for a per-band rate. Widened the OpenAPI response shape and the UI card's type to match.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-29 23:24:12 UTC
Review summary Nits — 3 non-blocking
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. Visual preview
Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy. Scroll preview
A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show. 🟩 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.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9921 +/- ##
==========================================
- Coverage 79.52% 79.25% -0.27%
==========================================
Files 281 284 +3
Lines 58577 61033 +2456
Branches 6833 7683 +850
==========================================
+ Hits 46581 48374 +1793
- Misses 11706 12028 +322
- Partials 290 631 +341
Flags with carried forward coverage won't be shown. Click here to find out more.
|


Summary
buildSlopOutcomeCalibrationfabricated amergeRate: 0for a slop band with zeroresolved PRs, which for a per-band discrimination table reads as "every PR in this
band was closed" — the strongest possible claim the table can make.
overallMergeRatefive lines later already treats an empty pool as
null; this makes the per-band figureconsistent with it.
SlopBandCalibration.mergeRateis nownumber | null;buildSlopOutcomeCalibrationreturns
nullfor any band withsampleSize === 0(src/services/outcome-calibration.ts).computeDiscriminatesnarrows the sampled-bands array with anisSampledBandtypeguard instead of comparing a nullable field directly — behaviour is unchanged (a
sampled band's
sampleSize >= MIN_BAND_SAMPLEalready guarantees a non-null rate).maintain outcome-calibrationrenderer (packages/loopover-mcp/bin/loopover-mcp.ts)already had a shared
n/a (below sample)guard for null/undefined rates — it justnever had a null per-band
mergeRateto actually exercise. Added a regression testthat drives it and confirms the plain-text output reads
n/a, not0%.src/openapi/schemas.ts'sOutcomeCalibrationResponse.slopwasz.unknown()(noper-band shape modeled at all); gave it the real structured shape with a nullable
mergeRate, and regeneratedapps/loopover-ui/public/openapi.jsonvianpm run ui:openapi.SlopBandCalibrationtype to match (apps/loopover-ui/src/components/site/app-panels/slop-band-calibration-card.tsx)— its render logic already gated on
sampleSize > 0, not onmergeRateitself, so nobehaviour change.
Not a UI-visible change: the card already showed "— no samples" for a zero-sample band
via the
sampleSizegate, so there's no rendered difference to screenshot.Test plan
npx vitest run test/unit/outcome-calibration.test.ts— new regression test asserts acorpus with zero
high-band resolved PRs producesmergeRate: nullfor that band, andthat
computeDiscriminates's verdict over the three sampled bands is unaffected.npx vitest run test/unit/mcp-cli-maintain.test.ts— new regression test asserts theCLI's plain-text output renders a null-mergeRate band as
n/a, not0%.npx vitest run test/unit/openapi.test.ts— route/schema parity checks still pass.npm run ui:openapi:check— regenerated artifact is stable.Closes #9641
UI Evidence
before
after
before
after
before
after