textmachine/backend/internal/pipeline/live_reprobe_threshold_test.go

66 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
}
}