66 lines
2.8 KiB
Go
66 lines
2.8 KiB
Go
package pipeline
|
||
|
||
import "testing"
|
||
|
||
// live_reprobe_threshold_test.go: the ARITHMETIC of the classifier acceptance threshold, lifted out of
|
||
// the `live` build tag so it is exercised by the ordinary battery. The rig that spends money on it lives
|
||
// in live_reprobe_test.go; this file carries no build tag on purpose, so both tag sets compile it and the
|
||
// paid rig and the free unit test can never disagree about what "accepted" means.
|
||
|
||
// The ratified acceptance threshold of the §2 type-classifier (D39.136 п.6б, closing row 116): the
|
||
// SAMPLED form — «≥4 of 5 runs at N=5 reach 6/6» — replacing D39.69 §2's "6/6" read over a single call.
|
||
//
|
||
// The form is ratified for N=5 ONLY. A different sample size has no ratified threshold at all, and
|
||
// DERIVING one (a ratio, a binomial bound) would be a session inventing an acceptance criterion — the
|
||
// quiet bypass the rig exists to prevent — so classify6Accepted refuses it instead of scaling.
|
||
const (
|
||
classify6SampleN = 5
|
||
classify6RunsAtFullOK = 4
|
||
)
|
||
|
||
// classify6SampleRatified reports whether the threshold covers a sample of this size at all. It is a
|
||
// separate question from the verdict because it must be answerable BEFORE any call is bought.
|
||
func classify6SampleRatified(runs int) (ok bool, why string) {
|
||
if runs != classify6SampleN {
|
||
return false, "the ratified threshold (D39.136 п.6б) is defined ONLY for N=5 — a sample of another size has no acceptance criterion, and deriving one here would be inventing the gate rather than applying it"
|
||
}
|
||
return true, ""
|
||
}
|
||
|
||
// classify6Accepted resolves a finished probe run against the ratified threshold. `ok` is the verdict;
|
||
// `why` is the operator-facing reason, non-empty whenever ok is false.
|
||
func classify6Accepted(runs, runsAtFull int) (ok bool, why string) {
|
||
if ok, why := classify6SampleRatified(runs); !ok {
|
||
return false, why
|
||
}
|
||
if runsAtFull < classify6RunsAtFullOK {
|
||
return false, "fewer than 4 of the 5 runs reached 6/6"
|
||
}
|
||
return true, ""
|
||
}
|
||
|
||
func TestClassify6ThresholdIsTheRatifiedSampledForm(t *testing.T) {
|
||
// 4/5 is the case the pre-ratification rig failed on: D39.136 п.6б exists precisely because effort
|
||
// `low` measured 4-of-5 on 02.08 and the "every run" form called that a regression.
|
||
for _, c := range []struct {
|
||
runs, atFull int
|
||
want bool
|
||
}{
|
||
{5, 5, true},
|
||
{5, 4, true},
|
||
{5, 3, false},
|
||
{5, 0, false},
|
||
{4, 4, false}, // N≠5: refused, never scaled to "4/4 is also ≥80%"
|
||
{10, 9, false},
|
||
{1, 1, false},
|
||
{6, 6, false}, // not even a SUPERSET of the ratified sample is derived from it
|
||
} {
|
||
got, why := classify6Accepted(c.runs, c.atFull)
|
||
if got != c.want {
|
||
t.Errorf("classify6Accepted(runs=%d, atFull=%d) = %v (%s), want %v", c.runs, c.atFull, got, why, c.want)
|
||
}
|
||
if !got && why == "" {
|
||
t.Errorf("a refusal must carry its reason (runs=%d, atFull=%d)", c.runs, c.atFull)
|
||
}
|
||
}
|
||
}
|