Files
executus/examples/reviewer/reviewer_test.go
T
steve ea9475da54
executus CI / test (pull_request) Failing after 1m5s
Adversarial Review (Gadfly) / review (pull_request) Successful in 8m18s
P5: light-tier canary — gadfly-shaped reviewer on executus core
examples/reviewer proves the core is sufficient for a static-binary light host
(gadfly's shape) with NO batteries:
- config.Env + model.Configure  -> env-driven model fleet + tier overrides
- model.ParseModelForContext    -> tier resolution + failover
- fanout.Run (PerKey caps)      -> N models x M lenses swarm, per-provider bound
- model.GenerateWith[T]         -> structured findings per (model, lens) cell
- Consolidate                   -> one verdict-led report section per model

Hermetic test runs the full 2x3 swarm against majordomo's fake provider and
asserts the consolidated verdicts. A go list -deps CI check asserts the canary
imports ZERO batteries (the light-tier invariant) — gadfly's go.sum stays free
of gorm/redis/discordgo/sqlite. README + docs updated.

This is the canary; migrating the LIVE gadfly repo onto executus core is a
follow-up (kept separate to not destabilize the active reviewer).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 00:22:02 -04:00

103 lines
3.2 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 main
import (
"context"
"strings"
"testing"
"gitea.stevedudenhoeffer.com/steve/majordomo/provider/fake"
"gitea.stevedudenhoeffer.com/steve/executus/fanout"
)
// TestReviewSwarm proves the light-tier path end-to-end against the fake
// provider: a 2-model × 3-lens swarm runs, structured findings parse, and
// consolidation produces one verdict-led section per model — no batteries, no
// network.
func TestReviewSwarm(t *testing.T) {
fp := fake.New("fakeprov")
// Model "hot" reports a high-severity finding on every lens; "cold" reports
// nothing. Each model is called once per lens (3×), so enqueue 3 each.
hot := `{"findings":[{"severity":"high","title":"SQL injection","detail":"unsanitized id in query"}]}`
cold := `{"findings":[]}`
for i := 0; i < 3; i++ {
fp.Enqueue("hot", fake.Reply(hot))
fp.Enqueue("cold", fake.Reply(cold))
}
hotM, err := fp.Model("hot")
if err != nil {
t.Fatal(err)
}
coldM, err := fp.Model("cold")
if err != nil {
t.Fatal(err)
}
models := []NamedModel{
{Name: "hot", Provider: "fakeprov", Model: hotM},
{Name: "cold", Provider: "fakeprov", Model: coldM},
}
lenses := []Lens{{Name: "security"}, {Name: "correctness"}, {Name: "error-handling"}}
results := Review(context.Background(), models, lenses, "some diff",
fanout.Options[cell]{MaxConcurrent: 6, PerKey: map[string]int{"fakeprov": 3}})
// 2 models × 3 lenses = 6 cells, all successful.
if len(results) != 6 {
t.Fatalf("got %d cells, want 6", len(results))
}
var hotFindings, coldFindings, errs int
for _, r := range results {
if r.Err != nil {
errs++
continue
}
switch r.Model {
case "hot":
hotFindings += len(r.Findings)
case "cold":
coldFindings += len(r.Findings)
}
}
if errs != 0 {
t.Errorf("expected no cell errors, got %d", errs)
}
if hotFindings != 3 { // one per lens
t.Errorf("hot model findings = %d, want 3", hotFindings)
}
if coldFindings != 0 {
t.Errorf("cold model findings = %d, want 0", coldFindings)
}
report := Consolidate(results)
if !strings.Contains(report, "hot — blocking issues found") {
t.Errorf("hot section should lead with a blocking verdict:\n%s", report)
}
if !strings.Contains(report, "cold — no issues found") {
t.Errorf("cold section should report no issues:\n%s", report)
}
if !strings.Contains(report, "SQL injection") {
t.Errorf("report should surface the finding:\n%s", report)
}
}
// TestConsolidateVerdicts checks the worst-severity-led header logic.
func TestConsolidateVerdicts(t *testing.T) {
got := Consolidate([]LensResult{
{Model: "m", Lens: "a", Findings: []Finding{{Severity: SevSmall, Title: "x"}}},
{Model: "m", Lens: "b", Findings: []Finding{{Severity: SevMedium, Title: "y"}}},
})
if !strings.Contains(got, "m — minor issues") {
t.Errorf("medium-max should be 'minor issues', got:\n%s", got)
}
// An errored lens is surfaced in the header.
got = Consolidate([]LensResult{
{Model: "m", Lens: "a", Findings: []Finding{{Severity: SevCritical, Title: "boom"}}},
{Model: "m", Lens: "b", Err: context.DeadlineExceeded},
})
if !strings.Contains(got, "blocking issues found") || !strings.Contains(got, "errored") {
t.Errorf("critical + errored lens header wrong:\n%s", got)
}
}