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, " ") if !strings.Contains(joined, "manual interventions are not recorded") { t.Fatalf("the refusal must say the intervention count is structurally zero: %v", check.Reasons) } }