fix(planning): consult the plan model only when no deterministic strategy applies

Propose built every strategy to record the alternatives, and the model
strategy's build is a live call to the plan role, so planning a direct
action spent a model call on an alternative that could never be selected
(B2, docs/planning.md). The model is now recorded as "not consulted" once
a deterministic draft is chosen, and the approver's reason no longer lists
it among the alternatives considered. A test counts the calls both ways.
This commit is contained in:
Andy Dixon
2026-10-05 19:35:20 +01:00
parent b6538600d1
commit 5cf3813a2e
3 changed files with 42 additions and 1 deletions
+34
View File
@@ -510,6 +510,40 @@ func TestInvalidModelPlanNeverRuns(t *testing.T) {
}
}
// A model is consulted only when no deterministic strategy applies (B2):
// planning a direct capability action must not spend a live model call on
// an alternative that cannot be selected.
func TestModelIsNotConsultedWhenADeterministicStrategyApplies(t *testing.T) {
f := newFixture(t)
calls := 0
f.exec.Planner.Model = func(context.Context, ids.ID, string, []capabilities.Capability) (string, ids.ID, error) {
calls++
return `{"steps":[]}`, ids.Nil, nil
}
it, _ := f.vol.CreateIntention(f.ctx, f.vol.Direct(f.es, "test"), volition.Intention{MindID: f.mind.ID, Description: "check the status page", Kind: volition.IntentAct,
Proposal: &volition.Proposal{Kind: "capability", Capability: "service.status", Params: map[string]any{"service": "atlas-worker"}}})
p, err := f.exec.Start(f.ctx, f.exec.rec(), it)
if err != nil {
t.Fatal(err)
}
if calls != 0 {
t.Fatalf("the model was called %d time(s) although the direct strategy applied", calls)
}
recorded := false
for _, a := range p.Alternatives {
recorded = recorded || (a.Strategy == "model" && !a.Selected && strings.HasPrefix(a.Why, "not consulted"))
}
if p.Strategy != "direct" || !recorded {
t.Fatalf("expected the direct strategy with the model recorded as not consulted: %+v", p.Alternatives)
}
// With no deterministic strategy the model is consulted.
pursue, _ := f.vol.CreateIntention(f.ctx, f.vol.Direct(f.es, "test"), volition.Intention{MindID: f.mind.ID, Description: "make the dashboard faster", Kind: volition.IntentPursue})
f.exec.Start(f.ctx, f.exec.rec(), pursue) //nolint:errcheck
if calls != 1 {
t.Fatalf("the model should be consulted once when nothing else applies, got %d", calls)
}
}
// Regression: an executor holding a stale "pending" copy of a step must not
// move it back to "ready" after another executor has claimed it, or the
// step can be claimed and run a second time.