fix(analyze): write an undefined paired p-value as null, not as NaN

A paired contrast where censoring orders no pair has no p-value, and JSON has
no NaN, so --json failed with 'marshal summary: json: unsupported value: NaN'
and wrote no summary at all after printing a complete report. The two fields
join the medians and the rates already carried as pointers, undefined reading
as null in the summary and n/a in the report.

Reachable since a clean run started being censored where it stopped: an arm
the wall clock stops before its partner ever violates orders nothing.
This commit is contained in:
pj committed 2026-08-18 20:24:10 +05:30
1 parent 8fad1937bb
commit 4bcd82a8a6
6 files changed
+60 -23

No files matched your search

+8 -1
View File
@@ -149,7 +149,7 @@ func writePaired(out io.Writer, comparison pairedComparison) {
formatStepDifference(comparison.MedianDifference), comparison.BothViolated, comparison.Sign, comparison.A12)
fmt.Fprintf(out, "sign test over the %d ordered pair(s), p %s, holm p %s\n",
comparison.FirstSooner+comparison.SecondSooner,
formatPValue(comparison.PValue), formatPValue(comparison.HolmPValue))
formatOptionalPValue(comparison.PValue), formatOptionalPValue(comparison.HolmPValue))
if len(comparison.UnpairedSeeds) > 0 {
fmt.Fprintf(out, "%d seed(s) usable in one arm only and left out of the pairing: %v\n",
len(comparison.UnpairedSeeds), comparison.UnpairedSeeds)
@@ -209,6 +209,13 @@ func formatSingletons(summary armSummary) string {
return fmt.Sprintf("%d/%d (%.3f)", summary.SingletonDefects, summary.DistinctDefects, *summary.SingletonFraction)
}
func formatOptionalPValue(value *float64) string {
if value == nil {
return "n/a"
}
return formatPValue(*value)
}
func formatPValue(value float64) string {
switch {
case math.IsNaN(value):