Files
ARTEX/server/planner_quiet_test.go
BaaRai 9f03b8c16a feat: per-task planner quiet-mode switch, editable mid-run
Quiet-mode was compile-time only; wanting it off mid-task (empty frontier, one long intent, idle lanes) was impossible. tasks.plan_quiet_mode (default on) gates the edge-round skip in runRound, PATCH /api/tasks/{id} flips it live (the next round reads it), creation accepts plan_quiet_mode, and the DTO exposes it.
2026-10-12 21:13:28 +02:00

125 lines
3.2 KiB
Go

package server
import (
"testing"
"github.com/Autumn-27/artex/db"
)
// Planner quiet-mode (#79): an edge round is dropped only when BOTH hold — the
// open-goal fingerprint is unchanged since the last completed round AND active
// work exists (open or running intents). Every other combination plans.
func TestPlannerQuietSkipEdge(t *testing.T) {
m, err := NewManager(t.TempDir(), "")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = m.Close() })
if m.pg == nil {
t.Skip("no postgres for this run")
}
created, err := m.CreateTaskWithOptions("quiet-mode probe", "probe goal", db.TaskCreateOptions{})
if err != nil {
t.Fatal(err)
}
tt, ok := m.Task(created.ID)
if !ok {
t.Fatal("task not found after creation")
}
store := tt.Store
e := NewEngine(m)
gid, err := store.AddGoal(map[string]any{"summary": "g1"}, "seed")
if err != nil {
t.Fatal(err)
}
iid, err := store.AddIntent(map[string]any{"summary": "i1"}, 0, nil, "seed")
if err != nil {
t.Fatal(err)
}
fp, err := store.OpenGoalFingerprint()
if err != nil {
t.Fatal(err)
}
if fp == "" {
t.Fatal("fingerprint must not be empty with an open goal")
}
e.goalFP.Store(tt.ID, fp)
if !e.quietSkipEdge(tt) {
t.Fatal("unchanged goals + active intent must skip the edge round")
}
// a goal closes -> the fingerprint changes -> plan
if err := store.SetNodeState(gid, "met"); err != nil {
t.Fatal(err)
}
if e.quietSkipEdge(tt) {
t.Fatal("a closed goal must allow planning")
}
// goal back open, intent drained -> no active work -> plan
if err := store.SetNodeState(gid, "open"); err != nil {
t.Fatal(err)
}
fp2, err := store.OpenGoalFingerprint()
if err != nil {
t.Fatal(err)
}
e.goalFP.Store(tt.ID, fp2)
if err := store.SetIntentState(iid, "done"); err != nil {
t.Fatal(err)
}
if e.quietSkipEdge(tt) {
t.Fatal("no active intent must allow planning")
}
}
// The quiet-mode switch is editable mid-run (#86): PATCHing plan_quiet_mode
// updates both the stored row and the live Task the engine reads per round.
func TestPlannerQuietModeToggleMidRun(t *testing.T) {
m, err := NewManager(t.TempDir(), "")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = m.Close() })
if m.pg == nil {
t.Skip("no postgres for this run")
}
created, err := m.CreateTaskWithOptions("quiet-toggle probe", "goal", db.TaskCreateOptions{})
if err != nil {
t.Fatal(err)
}
tt, ok := m.Task(created.ID)
if !ok {
t.Fatal("task not found")
}
if !tt.PlanQuietMode {
t.Fatal("quiet mode must default on")
}
off := false
updated, err := m.UpdateTaskMetadata(created.ID, db.TaskPatch{PlanQuietMode: &off})
if err != nil || updated == nil {
t.Fatalf("UpdateTaskMetadata: %v %v", updated, err)
}
live, ok := m.Task(created.ID)
if !ok || live.PlanQuietMode {
t.Fatal("mid-run toggle must turn the live flag off")
}
stored, err := m.pg.GetTask(mustTaskID(t, created.ID))
if err != nil || stored == nil || stored.PlanQuietMode {
t.Fatalf("stored row must reflect the toggle: %v %v", stored, err)
}
on := true
if _, err := m.UpdateTaskMetadata(created.ID, db.TaskPatch{PlanQuietMode: &on}); err != nil {
t.Fatal(err)
}
live, _ = m.Task(created.ID)
if !live.PlanQuietMode {
t.Fatal("toggle back on failed")
}
}