package operations import ( "strings" "testing" "orchestra/internal/domain" ) func debtItem(class domain.DebtClass, kinds ...struct { kind domain.ObservationKind task string }) domain.DebtItem { item := domain.DebtItem{Class: class} for _, k := range kinds { item.Observations = append(item.Observations, domain.DebtObservation{Kind: k.kind, TaskID: k.task}) } return item } type obs = struct { kind domain.ObservationKind task string } // The thresholds are the whole policy, so each class gets its own case. Polish // is the one that must never pass, or the ledger becomes a cleanup generator. func TestDebtEligibilityPerClass(t *testing.T) { fail := obs{domain.ObservationFailureClass, "t1"} if !CheckDebtEligibility(debtItem(domain.DebtCorrectness, fail)).Eligible { t.Fatal("correctness debt is eligible on first observation") } twice := debtItem(domain.DebtOperational, fail, obs{domain.ObservationFailureClass, "t1"}) if CheckDebtEligibility(twice).Eligible { t.Fatal("two occurrences on one task must not qualify as operational debt") } spread := debtItem(domain.DebtOperational, fail, obs{domain.ObservationFailureClass, "t2"}, obs{domain.ObservationFailureClass, "t3"}) if !CheckDebtEligibility(spread).Eligible { t.Fatal("three occurrences across three tasks must qualify") } manual := debtItem(domain.DebtOperational, obs{domain.ObservationManualIntervention, "t1"}) if !CheckDebtEligibility(manual).Eligible { t.Fatal("one manual intervention must qualify on its own") } blocked := debtItem(domain.DebtStructural, obs{domain.ObservationBlockReason, "t1"}, obs{domain.ObservationBlockReason, "t2"}) if !CheckDebtEligibility(blocked).Eligible { t.Fatal("two blocked tasks in one component must qualify as structural") } polish := debtItem(domain.DebtPolish, fail, fail, fail, fail, fail) if CheckDebtEligibility(polish).Eligible { t.Fatal("polish must never promote itself, at any recurrence") } } // A refusal has to say what is missing. "Not eligible" alone sends an operator // reading code, which is the mistake SubmissionCheck already documents. func TestDebtRefusalNamesTheMissingEvidence(t *testing.T) { check := CheckDebtEligibility(debtItem(domain.DebtOperational, obs{domain.ObservationFailureClass, "t1"})) if check.Eligible || len(check.Reasons) == 0 { t.Fatalf("want a refusal with reasons, got %+v", check) } joined := strings.Join(check.Reasons, " ") // Every reason is a fact about this item. The old text asserted that no // event type recorded manual interventions, which stopped being true the // day one did, leaving a correct decision explained by a lie. for _, want := range []string{"1 occurrences across 1 tasks", "0 recorded, needs 1"} { if !strings.Contains(joined, want) { t.Fatalf("the refusal does not state %q: %v", want, check.Reasons) } } for _, forbidden := range []string{"event type", "every current log"} { if strings.Contains(joined, forbidden) { t.Fatalf("a reason describes the architecture instead of the item: %v", check.Reasons) } } }