test(routing): pin tool-schema parity with supervisor

Captures the four routed skills' (review, debug, retrospective, trainer)
tool definitions as a JSON snapshot and asserts the routing pod's registry
advertises byte-equal schemas. A deliberate schema change fails this test,
requiring an intentional snapshot update in lockstep with consumers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mathias Bergqvist
2026-05-04 22:59:06 +02:00
parent 3a99d5e20e
commit 751f410ca6
2 changed files with 177 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
package routing_test
import (
"context"
"encoding/json"
"os"
"sort"
"testing"
"github.com/mathiasbq/supervisor/internal/registry"
"github.com/mathiasbq/supervisor/internal/skills/debug"
"github.com/mathiasbq/supervisor/internal/skills/retrospective"
"github.com/mathiasbq/supervisor/internal/skills/review"
"github.com/mathiasbq/supervisor/internal/skills/trainer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestToolsListMatchesSupervisorSnapshot pins the four routed skills' tool
// definitions to the supervisor's current advertisement. A deliberate schema
// change must be reflected here by updating testdata/tools_list.snapshot.json.
func TestToolsListMatchesSupervisorSnapshot(t *testing.T) {
complete := func(_ context.Context, _, _, _ string) (string, int64, error) {
return "", 0, nil
}
reg := registry.New()
reg.Register(review.New(review.Config{
SkillPrompt: "stub",
DefaultModel: "stub",
CompleteFunc: complete,
}))
reg.Register(debug.New(debug.Config{
SkillPrompt: "stub",
DefaultModel: "stub",
CompleteFunc: complete,
}))
reg.Register(retrospective.New(retrospective.Config{
SkillPrompt: "stub",
DefaultModel: "stub",
CompleteFunc: complete,
}))
reg.Register(trainer.New(trainer.Config{
ReaderPrompt: "stub",
WriterPrompt: "stub",
DefaultModel: "stub",
CompleteFunc: complete,
}))
wanted := map[string]bool{
"review": true,
"debug": true,
"retrospective": true,
"trainer": true,
}
var routed []registry.ToolDef
for _, td := range reg.Tools() {
if wanted[td.Name] {
routed = append(routed, td)
}
}
sort.Slice(routed, func(i, j int) bool { return routed[i].Name < routed[j].Name })
got, err := json.MarshalIndent(routed, "", " ")
require.NoError(t, err)
want, err := os.ReadFile("testdata/tools_list.snapshot.json")
require.NoError(t, err)
// Normalize both via re-encode so whitespace differences don't dominate.
var gotV, wantV any
require.NoError(t, json.Unmarshal(got, &gotV))
require.NoError(t, json.Unmarshal(want, &wantV))
gotN, _ := json.MarshalIndent(gotV, "", " ")
wantN, _ := json.MarshalIndent(wantV, "", " ")
assert.Equal(t, string(wantN), string(gotN),
"tool advertisement drifted from supervisor snapshot — update testdata/tools_list.snapshot.json deliberately if the schema change is intentional")
}