mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-15 04:30:55 +08:00
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.
125 lines
3.2 KiB
Go
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")
|
|
}
|
|
}
|