diff --git a/cmd/antidriftd/main.go b/cmd/antidriftd/main.go index ef29757..012abac 100644 --- a/cmd/antidriftd/main.go +++ b/cmd/antidriftd/main.go @@ -45,7 +45,8 @@ func main() { ctrl.SetCoach(svc) ctrl.SetDriftJudge(svc) ctrl.SetNudge(svc) - log.Printf("ai: %s backend (coach + drift judge + nudge)", backend.Name()) + ctrl.SetReviewer(svc) + log.Printf("ai: %s backend (coach + drift judge + nudge + reviewer)", backend.Name()) } // Wire the Tasks port: Amazing Marvin via ampy's `am` CLI. The command is diff --git a/internal/web/web_test.go b/internal/web/web_test.go index b99ae81..834006f 100644 --- a/internal/web/web_test.go +++ b/internal/web/web_test.go @@ -317,6 +317,51 @@ func TestPlanningStatePayloadCarriesKnowledge(t *testing.T) { } } +type stubReviewer struct { + refl ai.Reflection +} + +func (s stubReviewer) Review(ctx context.Context, finished, history string) (ai.Reflection, error) { + return s.refl, nil +} + +func TestReflectionFlowsToReviewThenPlanning(t *testing.T) { + s := newTestServer(t) + s.ctrl.SetReviewer(stubReviewer{refl: ai.Reflection{Recap: "held focus well", CarryForward: "start in the editor"}}) + r := s.Router() + _ = post(t, r, "/planning", "") + body := `{"next_action":"a","success_condition":"b","timebox_secs":1500}` + if w := post(t, r, "/commitment", body); w.Code != http.StatusOK { + t.Fatalf("/commitment code %d body %s", w.Code, w.Body.String()) + } + if w := post(t, r, "/complete", ""); w.Code != http.StatusOK { + t.Fatalf("/complete code %d", w.Code) + } + deadline := time.Now().Add(2 * time.Second) + for time.Now().Before(deadline) { + if rv := s.ctrl.State().Reflection; rv != nil && rv.Status == "ready" { + break + } + time.Sleep(5 * time.Millisecond) + } + js := s.stateJSON() + if !strings.Contains(js, `"recap":"held focus well"`) { + t.Fatalf("review payload missing recap: %s", js) + } + + // End -> Locked -> Planning: the carry-forward should surface on planning. + if w := post(t, r, "/end", ""); w.Code != http.StatusOK { + t.Fatalf("/end code %d", w.Code) + } + if w := post(t, r, "/planning", ""); w.Code != http.StatusOK { + t.Fatalf("/planning code %d", w.Code) + } + js2 := s.stateJSON() + if !strings.Contains(js2, `"carry_forward":"start in the editor"`) { + t.Fatalf("planning payload missing carry-forward: %s", js2) + } +} + func TestKnowledgePathSelectionReloads(t *testing.T) { s := newTestServer(t) s.ctrl.SetKnowledge(stubSource{profile: knowledge.Profile{Path: "/default"}})