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

+10 -11
View File
@@ -65,9 +65,12 @@ type pairedComparison struct {
// of matched seeds on which the first arm took more steps, an unordered pair
// counting as half. A matched design has no reason to compare the two arms
// as pooled bags of runs when each seed has a partner.
A12 float64 `json:"a12_within_pairs"`
PValue float64 `json:"p_value"`
HolmPValue float64 `json:"holm_p_value"`
A12 float64 `json:"a12_within_pairs"`
// PValue is undefined, and null in the summary, when censoring left no pair
// ordered: there is nothing for the test to be a test of, and JSON has no
// way to write the number that is not there.
PValue *float64 `json:"p_value"`
HolmPValue *float64 `json:"holm_p_value"`
}
// pairArms matches the two arms by seed and contrasts them pair by pair. A seed
@@ -84,13 +87,7 @@ func pairArms(first, second arm) (pairedComparison, error) {
return pairedComparison{}, err
}
comparison := pairedComparison{
First: first.Name,
Second: second.Name,
A12: math.NaN(),
PValue: math.NaN(),
HolmPValue: math.NaN(),
}
comparison := pairedComparison{First: first.Name, Second: second.Name, A12: math.NaN()}
var differences []float64
for _, seed := range sortedSeeds(firstBySeed, secondBySeed) {
left, inFirst := firstBySeed[seed]
@@ -130,7 +127,9 @@ func pairArms(first, second arm) (pairedComparison, error) {
comparison.Sign = -1
}
comparison.A12 = (float64(comparison.SecondSooner) + 0.5*float64(comparison.Unordered)) / float64(comparison.Pairs)
comparison.PValue = signTest(comparison.FirstSooner, comparison.SecondSooner)
if tested := signTest(comparison.FirstSooner, comparison.SecondSooner); !math.IsNaN(tested) {
comparison.PValue = &tested
}
return comparison, nil
}