From bee4bb3c1f3f89ab66f8efc353ce36d0668e0964 Mon Sep 17 00:00:00 2001 From: Mathias Bergqvist Date: Tue, 5 May 2026 23:22:15 +0200 Subject: [PATCH] =?UTF-8?q?chore(routing):=20pre-merge=20cleanup=20?= =?UTF-8?q?=E2=80=94=20Plan=207=20reminders,=20code=5Freview=E2=86=92revie?= =?UTF-8?q?w,=20operator=20note?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- DECISIONS.md | 25 +++++++++++++++++++++++++ README.md | 2 ++ cmd/routing/main.go | 7 +++++++ internal/routing/log.go | 2 +- internal/routing/log_test.go | 4 ++-- internal/routing/router_test.go | 8 ++++---- 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index 0040fe3..1f731b7 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -67,6 +67,31 @@ Record *why* things are the way they are. Future-you will thank present-you. --- +## Plan 6: routing pod reuses internal/skills/{review,debug,retrospective,trainer} + +Plan 6 (Mode 2 routing pod, 2026-05-04) introduces a second consumer of +the four cost-routable skill packages. The routing pod constructs each +skill via `.New(Config{...})` and hands it `routing.Router.Run` as +the `CompleteFunc`. Plan 7 (supervisor retirement) MUST NOT delete the +four packages. + +**Plan 7's allowed deletions:** +- `internal/skills/{tdd,spec,tier}/` (not consumed by the routing pod) +- `cmd/supervisor/` (binary) +- `Dockerfile` (supervisor's, at repo root — distinct from `Dockerfile.routing`) +- supervisor manifests in the infra repo +- NodePort `:30320` + +**Plan 7's preserved code:** +- `internal/skills/{review,debug,retrospective,trainer}/` +- `internal/registry` +- `internal/mcp` +- `internal/exec/litellm.go` +- `internal/routing/` (entirely new in Plan 6) +- `cmd/routing/` + +--- + ## 2026-04-08 — Mistral Vibe gets its own adapter **Context**: Vibe doesn't read `AGENTS.md` — it uses `~/.vibe/prompts/` and `~/.vibe/agents/` with TOML config. diff --git a/README.md b/README.md index f619890..59c7d74 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,8 @@ The supervisor probes connectivity at call time: | `HYPERGUILD_ROUTE_LOCAL_CEIL` | `0.70` | Below pass rate, route to Claude. Between CEIL and FLOOR is the sample band. | | `HYPERGUILD_PASS_RATE_TTL_SECONDS` | `60` | Per-skill pass-rate cache TTL | +> **Operator note:** LiteLLM at `LITELLM_BASE_URL` must register both `HYPERGUILD_LOCAL_MODEL` and `HYPERGUILD_CLAUDE_MODEL` for routing to do useful work. If a model is missing, LiteLLM returns 4xx, the routing pod's local route fails, the fail-open retry on Claude likely also fails (since both are missing), and the only signal is `final_status: "fail"` on `_routing` entries in the brain. + ## Phase 2 (planned) - `review` skill — structured code review with iron law enforcement diff --git a/cmd/routing/main.go b/cmd/routing/main.go index a008180..9d942b5 100644 --- a/cmd/routing/main.go +++ b/cmd/routing/main.go @@ -1,5 +1,12 @@ package main +// The internal/skills/{debug,retrospective,review,trainer} packages imported +// below are also imported by cmd/supervisor. Plan 7 (supervisor retirement) +// MUST NOT delete these four packages — the routing pod is their second +// consumer. Plan 7 deletes only internal/skills/{tdd,spec,tier} (the skills +// that don't route to local), the supervisor binary, and supervisor manifests. +// See docs/superpowers/specs/2026-05-04-mode-2-routing-pod-design.md (Constraints). + import ( "context" "log/slog" diff --git a/internal/routing/log.go b/internal/routing/log.go index 39305de..5a964de 100644 --- a/internal/routing/log.go +++ b/internal/routing/log.go @@ -12,7 +12,7 @@ import ( // LogEntry describes a single routing decision to log via the brain MCP. type LogEntry struct { SessionID string - Skill string // the original skill the call routed (e.g., "code_review") + Skill string // the original skill the call routed (e.g., "review") Decision string // "local" or "claude" or "claude_fallback" Message string // free-form, e.g. "model=qwen35, pass_rate=0.94" ProjectRoot string diff --git a/internal/routing/log_test.go b/internal/routing/log_test.go index c59323a..6333bb5 100644 --- a/internal/routing/log_test.go +++ b/internal/routing/log_test.go @@ -27,7 +27,7 @@ func TestLoggerLogDecision(t *testing.T) { l := routing.NewLogger(srv.URL) err := l.LogDecision(context.Background(), routing.LogEntry{ SessionID: "sess-1", - Skill: "code_review", + Skill: "review", Decision: "local", Message: "model=qwen35, pass_rate=0.94", ProjectRoot: "/home/x/proj", @@ -44,7 +44,7 @@ func TestLoggerLogDecision(t *testing.T) { assert.Equal(t, "_routing", args["skill"]) assert.Equal(t, "decide", args["phase"]) assert.Equal(t, "skip", args["final_status"]) - assert.Contains(t, args["message"].(string), "code_review: local") + assert.Contains(t, args["message"].(string), "review: local") assert.Equal(t, "sess-1", args["session_id"]) assert.Equal(t, "/home/x/proj", args["project_root"]) assert.Equal(t, float64(1234), args["duration_ms"]) diff --git a/internal/routing/router_test.go b/internal/routing/router_test.go index 269fbc0..20f6ceb 100644 --- a/internal/routing/router_test.go +++ b/internal/routing/router_test.go @@ -64,7 +64,7 @@ func TestRouterRoutesLocalAtHighPassRate(t *testing.T) { r, _, _ := newRouter(t, llm, 0.95) out, _, err := r.Run(context.Background(), routing.RunInput{ - Skill: "code_review", System: "sys", User: "user", SessionID: "s1", ProjectRoot: "/p", + Skill: "review", System: "sys", User: "user", SessionID: "s1", ProjectRoot: "/p", }) require.NoError(t, err) assert.Equal(t, "ok", out) @@ -80,7 +80,7 @@ func TestRouterRoutesClaudeAtLowPassRate(t *testing.T) { r, _, _ := newRouter(t, llm, 0.3) _, _, err := r.Run(context.Background(), routing.RunInput{ - Skill: "code_review", System: "sys", User: "user", SessionID: "s2", + Skill: "review", System: "sys", User: "user", SessionID: "s2", }) require.NoError(t, err) @@ -95,7 +95,7 @@ func TestRouterFailsOpenLocalErrorToClaude(t *testing.T) { r, _, _ := newRouter(t, llm, 0.95) // would route local out, _, err := r.Run(context.Background(), routing.RunInput{ - Skill: "code_review", System: "sys", User: "user", SessionID: "s3", + Skill: "review", System: "sys", User: "user", SessionID: "s3", }) require.NoError(t, err) assert.Equal(t, "ok-after-fallback", out) @@ -125,7 +125,7 @@ func TestRouterDefaultsToLocalWhenBrainUnreachable(t *testing.T) { } _, _, err := r.Run(context.Background(), routing.RunInput{ - Skill: "code_review", System: "sys", User: "user", SessionID: "s4", + Skill: "review", System: "sys", User: "user", SessionID: "s4", }) require.NoError(t, err)