mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 15:33:18 +08:00
Avoid rounding near-perfect compare pass rates to 100%.
With a few fails among tens of thousands of rows, 1-decimal rounding hid residual failures; keep extra precision so the UI never shows 100% when fails remain. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
8a79e962a8
commit
1653a31b16
2 changed files with 57 additions and 7 deletions
|
|
@ -204,6 +204,27 @@ def normalize_store_unchanged(raw: Any) -> str:
|
|||
return m if m in _STORE_UNCHANGED_MODES else "auto"
|
||||
|
||||
|
||||
def compute_pass_rate(*, success: int, fail: int, empty_as: float = 100.0) -> float:
|
||||
"""Pass rate for cutover UI.
|
||||
|
||||
With million-row sheets, 3 fails / 50k can round to 100.0% at 1 decimal —
|
||||
never report 100 when any fail remains; add decimals until it stays < 100.
|
||||
"""
|
||||
s = max(0, int(success or 0))
|
||||
f = max(0, int(fail or 0))
|
||||
judged = s + f
|
||||
if judged <= 0:
|
||||
return float(empty_as)
|
||||
rate = (s / judged) * 100.0
|
||||
if f <= 0:
|
||||
return round(rate, 1)
|
||||
for nd in (1, 2, 3, 4):
|
||||
r = round(rate, nd)
|
||||
if r < 100.0:
|
||||
return r
|
||||
return 99.9999
|
||||
|
||||
|
||||
def resolve_unchanged_policy(
|
||||
mode: str, *, before_n: int, after_n: int
|
||||
) -> dict[str, Any]:
|
||||
|
|
@ -2885,7 +2906,9 @@ def _enrich_summary(summary: dict[str, Any], sheets: list[dict[str, Any]]) -> di
|
|||
matched = changed + unchanged
|
||||
diff_count = fail_count
|
||||
pass_rate = (
|
||||
round((success_count / judged) * 100, 1) if judged else (100.0 if total == 0 else 0.0)
|
||||
compute_pass_rate(success=success_count, fail=fail_count, empty_as=100.0 if total == 0 else 0.0)
|
||||
if judged
|
||||
else (100.0 if total == 0 else 0.0)
|
||||
)
|
||||
diff_rate = round((fail_count / judged) * 100, 1) if judged else 0.0
|
||||
|
||||
|
|
@ -2920,7 +2943,11 @@ def _enrich_summary(summary: dict[str, Any], sheets: list[dict[str, Any]]) -> di
|
|||
# Pending sheets must not look like "100% pass"
|
||||
"pass_rate": None
|
||||
if pending
|
||||
else (round((su / sj) * 100, 1) if sj else (100.0 if st == 0 else 0.0)),
|
||||
else (
|
||||
compute_pass_rate(success=su, fail=sf, empty_as=100.0 if st == 0 else 0.0)
|
||||
if sj
|
||||
else (100.0 if st == 0 else 0.0)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1376,7 +1376,22 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
|||
const fail = sheetFailOf(c);
|
||||
const ok = sheetSuccessOf(c);
|
||||
const judged = fail + ok;
|
||||
return judged ? Math.round((ok / judged) * 1000) / 10 : 100;
|
||||
if (!judged) return 100;
|
||||
const rate = (ok / judged) * 100;
|
||||
if (fail <= 0) return Math.round(rate * 10) / 10;
|
||||
// 3 fails / 50k ≈ 99.994% — 1-decimal round becomes 100%; keep digits until < 100
|
||||
for (const nd of [1, 2, 3, 4]) {
|
||||
const r = Math.round(rate * 10 ** nd) / 10 ** nd;
|
||||
if (r < 100) return r;
|
||||
}
|
||||
return 99.9999;
|
||||
};
|
||||
|
||||
const formatPassRate = (rate: number | null | undefined) => {
|
||||
if (rate === null || rate === undefined || Number.isNaN(rate)) return "…";
|
||||
// Trim trailing zeros but keep enough precision for near-100 rates
|
||||
const s = Number(rate).toFixed(4).replace(/\.?0+$/, "");
|
||||
return `${s}%`;
|
||||
};
|
||||
|
||||
const summary = runDetail?.summary || {};
|
||||
|
|
@ -3591,7 +3606,15 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
|||
pass_rate: pending
|
||||
? null
|
||||
: judged
|
||||
? Math.round((unchanged / judged) * 1000) / 10
|
||||
? (() => {
|
||||
const rate = (unchanged / judged) * 100;
|
||||
if (fail <= 0) return Math.round(rate * 10) / 10;
|
||||
for (const nd of [1, 2, 3, 4]) {
|
||||
const r = Math.round(rate * 10 ** nd) / 10 ** nd;
|
||||
if (r < 100) return r;
|
||||
}
|
||||
return 99.9999;
|
||||
})()
|
||||
: 100,
|
||||
};
|
||||
})
|
||||
|
|
@ -3641,7 +3664,7 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
|||
title={
|
||||
pending
|
||||
? `${label} · ${t("bizCompare.sheetPending")}`
|
||||
: `${label} · ${t("bizCompare.kindFail")} ${fail} · ${t("bizCompare.kindSuccess")} ${ok} · ${t("bizCompare.passRateShort")} ${rate ?? "…"}%`
|
||||
: `${label} · ${t("bizCompare.kindFail")} ${fail} · ${t("bizCompare.kindSuccess")} ${ok} · ${t("bizCompare.passRateShort")} ${formatPassRate(rate)}`
|
||||
}
|
||||
>
|
||||
<span className="bs-cmp-nav__dot" aria-hidden />
|
||||
|
|
@ -3658,7 +3681,7 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
|||
{pending ? "—" : ok}
|
||||
</span>
|
||||
<span className="bs-cmp-nav__num bs-cmp-nav__num--rate">
|
||||
{pending || rate === null ? "…" : `${rate}%`}
|
||||
{pending || rate === null ? "…" : formatPassRate(rate)}
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -3714,7 +3737,7 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
|||
<span className="bs-cmp-strip__pass-value">
|
||||
{activeSheetPending || activePassRate === null
|
||||
? "…"
|
||||
: `${activePassRate}%`}
|
||||
: formatPassRate(activePassRate)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="bs-cmp-strip__kinds" role="group">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue