0aefe021b0
Reasons are the auditable explanation of a pure decision, so one that describes the architecture rots the moment the architecture moves. The operational refusal asserted that manual interventions were recorded by no event type: true when written, false the day OperatorInterventionRecorded landed, and still printed under every refusal after that. It now reports the counts and the thresholds they missed. Why a count is zero is not this function's business, since no intervention happening, none being recorded, and none being migrated all read the same from here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVbaKucEYBjMqVeUgJUsc1
79 lines
3.0 KiB
Go
79 lines
3.0 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|