Cross-lineage scrum on b2e45f7 produced 1 convergent + 3 single-reviewer
findings worth fixing. All apply.
1. (Opus WARN + Qwen INFO convergent) scripts/playbook_lift.sh: replace
sleep 2.5 in SQL probe with active polling up to 5s. refresh_every=1s
is a lower bound; under load the manifest may not be visible in a
fixed sleep, which would 4xx the probe and abort the reality run.
2. (Opus INFO) scripts/playbook_lift.sh: report template glued
"env JUDGE_MODEL" + value as "env JUDGE_MODELqwen2.5:latest" with no
separator. Replaced two :+/:- substitution chains with a single
JUDGE_SOURCE variable computed once at the top of the harness.
3. (Opus INFO) scripts/staffing_workers/main.go: -id-prefix "" silently
allowed, defeating the flag's purpose (cross-corpus collision prevent).
Now log.Fatal at startup with explicit hint.
4. (Opus WARN) cmd/{pathwayd,observerd}/main_test.go: newTestRouter
returned http.Handler then re-cast to chi.Router for chi.Walk.
Returning chi.Router directly satisfies http.Handler AND avoids an
assertion that would panic if future middleware wraps the router.
Dismissed (with rationale):
- Kimi INFO hardcoded MinIO endpoint: harness is local-by-design.
- Kimi WARN matrixd accepts 502/500: documented; real retriever needs
real upstreams the test doesn't spin up.
- Qwen INFO queryd string.Contains: brittle but very low risk; restating
through typed-error path would couple without adding signal.
go test ./cmd/{matrixd,queryd,pathwayd,observerd} all green.
Verdicts at reports/scrum/_evidence/2026-04-30/verdicts/lift_001_*.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
108 lines
3.3 KiB
Go
108 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"git.agentview.dev/profit/golangLAKEHOUSE/internal/observer"
|
|
"git.agentview.dev/profit/golangLAKEHOUSE/internal/workflow"
|
|
)
|
|
|
|
// newTestRouter builds the observerd router with an in-memory store
|
|
// and a workflow runner with no modes registered. Closes R-005 for
|
|
// observerd.
|
|
//
|
|
// Returns chi.Router (not http.Handler) so chi.Walk works without a
|
|
// type assertion that would panic if a future refactor wraps the
|
|
// router in plain net/http middleware.
|
|
func newTestRouter(t *testing.T) chi.Router {
|
|
t.Helper()
|
|
h := &handlers{
|
|
store: observer.NewStore(nil),
|
|
runner: workflow.NewRunner(),
|
|
}
|
|
r := chi.NewRouter()
|
|
h.register(r)
|
|
return r
|
|
}
|
|
|
|
func TestRoutesMounted(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
want := map[string]bool{
|
|
"GET /observer/stats": false,
|
|
"POST /observer/event": false,
|
|
"POST /observer/workflow/run": false,
|
|
"GET /observer/workflow/modes": false,
|
|
}
|
|
_ = chi.Walk(r, func(method, route string, _ http.Handler, _ ...func(http.Handler) http.Handler) error {
|
|
key := method + " " + route
|
|
if _, ok := want[key]; ok {
|
|
want[key] = true
|
|
}
|
|
return nil
|
|
})
|
|
for k, mounted := range want {
|
|
if !mounted {
|
|
t.Errorf("route not mounted: %s", k)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStats_GET(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
req := httptest.NewRequest("GET", "/observer/stats", nil)
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected 200, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestWorkflowModes_GET(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
req := httptest.NewRequest("GET", "/observer/workflow/modes", nil)
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected 200, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
// TestEvent_InvalidOp locks the validation path: an ObservedOp with
|
|
// missing required fields must 400, not 500. Without this assertion,
|
|
// observer.ErrInvalidOp could silently slip into the 500 branch on a
|
|
// future refactor and clients would see "internal" instead of the
|
|
// actual validation error.
|
|
func TestEvent_InvalidOp(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
// Empty body — no endpoint, no source — fails ObservedOp validation.
|
|
body := []byte(`{}`)
|
|
req := httptest.NewRequest("POST", "/observer/event", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, req)
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("expected 400 on invalid op, got %d (body=%s)", w.Code, w.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestWorkflowRun_UnknownMode locks the 400 path on workflow definitions
|
|
// that reference modes not registered with the runner. The harness's
|
|
// reality test runs depend on this so an unknown-mode misconfiguration
|
|
// surfaces as a definition error, not a server error.
|
|
func TestWorkflowRun_UnknownMode(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
body := []byte(`{"workflow":{"name":"t","nodes":[{"id":"n1","mode":"does.not.exist"}]}}`)
|
|
req := httptest.NewRequest("POST", "/observer/workflow/run", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, req)
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("expected 400 on unknown mode, got %d (body=%s)", w.Code, w.Body.String())
|
|
}
|
|
}
|