Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions apps/loopover-ui/public/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,8 @@
"type": "number"
},
"gamingFlagsCaught": {
"type": "number"
"type": "number",
"nullable": true
},
"accuracyCiPct": {
"type": "object",
Expand Down Expand Up @@ -645,18 +646,23 @@
"lambda": {
"type": "number"
},
"coveragePct": {
"n": {
"type": "number"
},
"n": {
"aiJudgedCoveragePct": {
"type": "number"
},
"backfilledPct": {
"type": "number",
"nullable": true
}
},
"required": [
"alpha",
"lambda",
"coveragePct",
"n"
"aiJudgedCoveragePct",
"n",
"backfilledPct"
]
},
"merge": {
Expand All @@ -669,18 +675,23 @@
"lambda": {
"type": "number"
},
"coveragePct": {
"n": {
"type": "number"
},
"n": {
"aiJudgedCoveragePct": {
"type": "number"
},
"backfilledPct": {
"type": "number",
"nullable": true
}
},
"required": [
"alpha",
"lambda",
"coveragePct",
"n"
"aiJudgedCoveragePct",
"n",
"backfilledPct"
]
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,20 @@ describe("FairnessReportPage (#fairness-analytics)", () => {
expect(screen.getByText("2 human-reversed, lifetime")).toBeTruthy();
});

it("#9068: renders the insufficient-instances state (not a fabricated zero) when gamingFlagsCaught is null", async () => {
apiFetch.mockResolvedValue({
ok: true,
data: { ...FIXTURE, fleetAccuracy: { ...FIXTURE.fleetAccuracy, gamingFlagsCaught: null } },
status: 200,
durationMs: 10,
});
renderWithClient(<FairnessReportPage />);
await waitFor(() => expect(screen.getByText("Anti-gaming flags caught")).toBeTruthy());
const gamingCard = screen.getByText("Anti-gaming flags caught").closest("div")!.parentElement!;
expect(gamingCard.textContent).toContain("—");
expect(gamingCard.textContent).toContain("not enough registered instances");
});

it("REGRESSION: does not crash when the API response predates the fleetAccuracy field (old backend/new frontend deployment skew)", async () => {
const { fleetAccuracy: _omitted, ...payloadWithoutFleetAccuracy } = FIXTURE;
apiFetch.mockResolvedValue({
Expand Down
11 changes: 8 additions & 3 deletions apps/loopover-ui/src/components/site/fairness-report-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,16 @@ export function FairnessReportPage() {
<Card className="p-5">
<div className="text-token-xs text-muted-foreground">Anti-gaming flags caught</div>
<div className="mt-2 text-token-xl font-medium">
{data.fleetAccuracy ? intFmt.format(data.fleetAccuracy.gamingFlagsCaught) : "—"}
{data.fleetAccuracy?.gamingFlagsCaught != null
? intFmt.format(data.fleetAccuracy.gamingFlagsCaught)
: "—"}
</div>
<p className="mt-2 text-token-sm text-muted-foreground">
self-hosted instances flagged for mass-submitting easy PRs to inflate their own
precision
{/* #9068: null (not 0) below the fleet's own eligibility floor -- a structural zero must
never read as "checked, found none". */}
{data.fleetAccuracy?.gamingFlagsCaught != null
? "self-hosted instances flagged for mass-submitting easy PRs to inflate their own precision"
: "not enough registered instances yet to compare for a gaming pattern"}
</p>
</Card>
<Card className="p-5">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,32 @@ export type PublicStats = {
closePrecisionCiPct?: { lo: number; hi: number } | null;
coveragePct?: number | null;
decidedCount?: number;
/** #9050: `aiJudgedCoveragePct` (renamed from `coveragePct`) is the share of the arm's AI-JUDGED
* sub-population the guarantee covers, not a share of all decided signals (that's the sibling
* `coveragePct` above) -- render the population it's actually over, not a bare percentage.
* `backfilledPct` is null when the stored calibration predates that field. */
guaranteed?: {
close: { alpha: number; lambda: number; coveragePct: number; n: number } | null;
merge: { alpha: number; lambda: number; coveragePct: number; n: number } | null;
close: {
alpha: number;
lambda: number;
aiJudgedCoveragePct: number;
n: number;
backfilledPct: number | null;
} | null;
merge: {
alpha: number;
lambda: number;
aiJudgedCoveragePct: number;
n: number;
backfilledPct: number | null;
} | null;
};
instanceCount: number;
windowDays: number;
gamingFlagsCaught: number;
/** #9068: null (not 0) when the fleet has fewer than GAMING_MIN_ELIGIBLE eligible instances -- the
* anti-farming detector cannot run below that floor, so a structural zero must never render as "checked,
* found none". */
gamingFlagsCaught: number | null;
};
/** Trailing weekly history of totals.accuracyPct's SAME formula (#4447). */
accuracyTrend: Array<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,41 @@ describe("ProofOfPowerStats", () => {
expect(screen.getAllByRole("img", { name: "Trend over the last 8 weeks" })).toHaveLength(3);
});

it("#9050: disambiguates the published guarantee's coverage as the AI-judged sub-population, with the backfilled-vs-live split", async () => {
apiFetch.mockResolvedValue({
ok: true,
status: 200,
durationMs: 1,
data: {
...PAYLOAD,
fleetAccuracy: {
accuracyPct: 80,
coveragePct: 64.3,
instanceCount: 3,
windowDays: 90,
gamingFlagsCaught: null, // #9068: below the fleet's own eligibility floor
guaranteed: {
close: {
alpha: 0.05,
lambda: 0.9,
aiJudgedCoveragePct: 57.1,
n: 129,
backfilledPct: 98.7,
},
merge: null,
},
},
},
});
renderWithClient(<ProofOfPowerStats />);
await screen.findByText("Decision accuracy");
expect(
screen.getByText(
"merge/close calls confirmed by outcome · at 64.3% coverage · closes ≥95% guaranteed at 57.1% coverage of AI-judged closes (98.7% backfilled) · 3 self-hosted instances",
),
).toBeTruthy();
});

it("settles the count-up on the real reviewed total (not stuck at 0 when rAF never fires)", async () => {
// Deterministic (#flake): force prefers-reduced-motion so useCountUp lands the final value synchronously on
// mount, instead of running the requestAnimationFrame tween. jsdom has no matchMedia, so the unfixed test took
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,13 @@ export function ProofOfPowerStats({ className }: { className?: string }) {
fleetEligible
? // #8829: a bare accuracy scalar at unstated coverage is gameable (holding more raises it), so
// the tile names the coverage it was earned at whenever the backend supplies it.
`merge/close calls confirmed by outcome${data.fleetAccuracy.coveragePct != null ? ` · at ${data.fleetAccuracy.coveragePct}% coverage` : ""}${data.fleetAccuracy.guaranteed?.close ? ` · closes ≥${Math.round((1 - data.fleetAccuracy.guaranteed.close.alpha) * 1000) / 10}% guaranteed at ${data.fleetAccuracy.guaranteed.close.coveragePct}% coverage` : ""} · ${intFmt.format(data.fleetAccuracy.instanceCount)} self-hosted instance${data.fleetAccuracy.instanceCount === 1 ? "" : "s"}${data.fleetAccuracy.gamingFlagsCaught > 0 ? ` · ${intFmt.format(data.fleetAccuracy.gamingFlagsCaught)} gaming pattern${data.fleetAccuracy.gamingFlagsCaught === 1 ? "" : "s"} flagged` : ""}`
// #9050: the guarantee's own coverage is named "of AI-judged closes" -- it's the share of the
// AI-judgment sub-population the threshold covers, not a share of all closes (that reading
// sits confusingly next to the sibling coveragePct just before it, which IS over all decided
// signals) -- plus the backfilled-vs-live split behind the evidence, when supplied.
// #9068: gamingFlagsCaught is null (not 0) below the fleet's own eligibility floor, so the
// suffix is omitted entirely rather than rendering a structural zero as "checked, found none".
`merge/close calls confirmed by outcome${data.fleetAccuracy.coveragePct != null ? ` · at ${data.fleetAccuracy.coveragePct}% coverage` : ""}${data.fleetAccuracy.guaranteed?.close ? ` · closes ≥${Math.round((1 - data.fleetAccuracy.guaranteed.close.alpha) * 1000) / 10}% guaranteed at ${data.fleetAccuracy.guaranteed.close.aiJudgedCoveragePct}% coverage of AI-judged closes${data.fleetAccuracy.guaranteed.close.backfilledPct != null ? ` (${data.fleetAccuracy.guaranteed.close.backfilledPct}% backfilled)` : ""}` : ""} · ${intFmt.format(data.fleetAccuracy.instanceCount)} self-hosted instance${data.fleetAccuracy.instanceCount === 1 ? "" : "s"}${data.fleetAccuracy.gamingFlagsCaught != null && data.fleetAccuracy.gamingFlagsCaught > 0 ? ` · ${intFmt.format(data.fleetAccuracy.gamingFlagsCaught)} gaming pattern${data.fleetAccuracy.gamingFlagsCaught === 1 ? "" : "s"} flagged` : ""}`
: totals.reversed > 0
? `${intFmt.format(totals.reversed)} human-reversed`
: "reversal-grounded"
Expand Down
7 changes: 5 additions & 2 deletions src/openapi/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,13 @@ export const PublicStatsSchema = z
closePrecisionCiPct: z.object({ lo: z.number(), hi: z.number() }).nullable(),
coveragePct: z.number().nullable(),
decidedCount: z.number(),
guaranteed: z.object({ close: z.object({ alpha: z.number(), lambda: z.number(), coveragePct: z.number(), n: z.number() }).nullable(), merge: z.object({ alpha: z.number(), lambda: z.number(), coveragePct: z.number(), n: z.number() }).nullable() }),
guaranteed: z.object({
close: z.object({ alpha: z.number(), lambda: z.number(), aiJudgedCoveragePct: z.number(), n: z.number(), backfilledPct: z.number().nullable() }).nullable(),
merge: z.object({ alpha: z.number(), lambda: z.number(), aiJudgedCoveragePct: z.number(), n: z.number(), backfilledPct: z.number().nullable() }).nullable(),
}),
instanceCount: z.number(),
windowDays: z.number(),
gamingFlagsCaught: z.number(),
gamingFlagsCaught: z.number().nullable(),
}),
/** Trailing weekly history of totals.accuracyPct's SAME formula (#4447) -- null counts/accuracyPct on a week means
* too few decided (merged+closed) PRs to publish meaningful or non-identifying details. */
Expand Down
Loading
Loading