| 1 | package cli |
| 2 | |
| 3 | import ( |
| 4 | "strings" |
| 5 | "testing" |
| 6 | |
| 7 | "reasonix/internal/event" |
| 8 | ) |
| 9 | |
| 10 | func TestCompletionSummaryOutputIsTiered(t *testing.T) { |
| 11 | complete := &event.CompletionSummaryInfo{ |
| 12 | Preset: "balanced", Verdict: "complete", Mutations: 2, |
| 13 | ChecksPassed: 4, Review: "passed", |
| 14 | } |
| 15 | m := newTestChatTUI() |
| 16 | m.ingestEvent(event.Event{Kind: event.CompletionSummary, Completion: complete}) |
| 17 | if len(*m.pendingCommit) != 0 { |
| 18 | t.Fatalf("ordinary completion summary should be silent, committed=%v", *m.pendingCommit) |
| 19 | } |
| 20 | |
| 21 | partial := &event.CompletionSummaryInfo{ |
| 22 | Preset: "balanced", Verdict: "partial", Mutations: 2, |
| 23 | ChecksPassed: 3, ChecksFailed: 1, Review: "passed", GapKinds: []string{"stale_check"}, |
| 24 | } |
| 25 | m = newTestChatTUI() |
| 26 | m.ingestEvent(event.Event{Kind: event.CompletionSummary, Completion: partial}) |
| 27 | lines := strings.Join(*m.pendingCommit, "\n") |
| 28 | if !strings.Contains(lines, "!") || strings.Contains(lines, "balanced") || strings.Contains(lines, "stale_check") { |
| 29 | t.Fatalf("non-verbose partial summary should be a localized short warning, committed=%q", lines) |
| 30 | } |
| 31 | |
| 32 | m = newTestChatTUI() |
| 33 | m.showReasoning = true |
| 34 | m.ingestEvent(event.Event{Kind: event.CompletionSummary, Completion: partial}) |
| 35 | lines = strings.Join(*m.pendingCommit, "\n") |
| 36 | if !strings.Contains(lines, "stale_check") || !strings.Contains(lines, "partial") || strings.Contains(lines, "balanced") { |
| 37 | t.Fatalf("verbose mode should include raw completion details without a mode label, committed=%q", lines) |
| 38 | } |
| 39 | |
| 40 | unreviewed := &event.CompletionSummaryInfo{ |
| 41 | Verdict: "partial", Mutations: 1, Review: "unavailable", GapKinds: []string{"unreviewed_change"}, |
| 42 | } |
| 43 | m = newTestChatTUI() |
| 44 | m.ingestEvent(event.Event{Kind: event.CompletionSummary, Completion: unreviewed}) |
| 45 | if len(*m.pendingCommit) != 0 { |
| 46 | t.Fatalf("standard unreviewed changes must stay silent, committed=%v", *m.pendingCommit) |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | func TestCompletionSummaryUsesTurnTimeAttention(t *testing.T) { |
| 51 | requiredSuppressed := &event.CompletionSummaryInfo{ |
| 52 | Verdict: "partial", ChecksSuppressed: 1, GapKinds: []string{"suppressed_requirement"}, |
| 53 | Floor: "delivery", Attention: true, |
| 54 | } |
| 55 | if !completionSummaryNeedsAttention(requiredSuppressed, "standard") { |
| 56 | t.Fatal("backend attention must survive a later floor change") |
| 57 | } |
| 58 | quietStandard := &event.CompletionSummaryInfo{ |
| 59 | Verdict: "partial", GapKinds: []string{"unverified_change"}, |
| 60 | Floor: "standard", Attention: false, |
| 61 | } |
| 62 | if completionSummaryNeedsAttention(quietStandard, "delivery") { |
| 63 | t.Fatal("historical standard summary must not be reclassified by the current floor") |
| 64 | } |
| 65 | legacySuppressed := &event.CompletionSummaryInfo{Verdict: "partial", ChecksSuppressed: 1} |
| 66 | if !completionSummaryNeedsAttention(legacySuppressed, "delivery") { |
| 67 | t.Fatal("legacy suppressed checks must fail closed") |
| 68 | } |
| 69 | } |
| 70 |