mirror of
https://github.com/hansjone/netx.git
synced 2026-10-18 22:10:48 +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"
|
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(
|
def resolve_unchanged_policy(
|
||||||
mode: str, *, before_n: int, after_n: int
|
mode: str, *, before_n: int, after_n: int
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
|
|
@ -2885,7 +2906,9 @@ def _enrich_summary(summary: dict[str, Any], sheets: list[dict[str, Any]]) -> di
|
||||||
matched = changed + unchanged
|
matched = changed + unchanged
|
||||||
diff_count = fail_count
|
diff_count = fail_count
|
||||||
pass_rate = (
|
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
|
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"
|
# Pending sheets must not look like "100% pass"
|
||||||
"pass_rate": None
|
"pass_rate": None
|
||||||
if pending
|
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 fail = sheetFailOf(c);
|
||||||
const ok = sheetSuccessOf(c);
|
const ok = sheetSuccessOf(c);
|
||||||
const judged = fail + ok;
|
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 || {};
|
const summary = runDetail?.summary || {};
|
||||||
|
|
@ -3591,7 +3606,15 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
||||||
pass_rate: pending
|
pass_rate: pending
|
||||||
? null
|
? null
|
||||||
: judged
|
: 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,
|
: 100,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
@ -3641,7 +3664,7 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
||||||
title={
|
title={
|
||||||
pending
|
pending
|
||||||
? `${label} · ${t("bizCompare.sheetPending")}`
|
? `${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 />
|
<span className="bs-cmp-nav__dot" aria-hidden />
|
||||||
|
|
@ -3658,7 +3681,7 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
||||||
{pending ? "—" : ok}
|
{pending ? "—" : ok}
|
||||||
</span>
|
</span>
|
||||||
<span className="bs-cmp-nav__num bs-cmp-nav__num--rate">
|
<span className="bs-cmp-nav__num bs-cmp-nav__num--rate">
|
||||||
{pending || rate === null ? "…" : `${rate}%`}
|
{pending || rate === null ? "…" : formatPassRate(rate)}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -3714,7 +3737,7 @@ export function BizComparePage({ pageMode = "all" }: { pageMode?: BizComparePage
|
||||||
<span className="bs-cmp-strip__pass-value">
|
<span className="bs-cmp-strip__pass-value">
|
||||||
{activeSheetPending || activePassRate === null
|
{activeSheetPending || activePassRate === null
|
||||||
? "…"
|
? "…"
|
||||||
: `${activePassRate}%`}
|
: formatPassRate(activePassRate)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="bs-cmp-strip__kinds" role="group">
|
<div className="bs-cmp-strip__kinds" role="group">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue