Files
2026-07-13 13:00:08 +08:00

58 lines
2.5 KiB
Go

package planmode
import "testing"
// These tests pin the model-facing Marker prose to the actual gate: every tool
// the Marker advertises as available must pass Decide, and every tool it names
// as forbidden must be blocked. This is the anti-drift guard the centralized
// policy set out to provide — without it, the Marker text and the executable
// gate can silently diverge (the model is told it may call a tool that the gate
// then refuses, or vice versa). If you edit Marker, update these lists too.
func TestMarkerAdvertisedAllowedToolsPassDecide(t *testing.T) {
p := Policy{}
// Marker: "ask clarifying questions with ask, maintain planning state with
// todo_write, and delegate isolated read-only research with read_only_task
// or read_only_skill". The two delegations are non-built-ins that self-report
// plan-safe, exactly as the agent supplies at the call site.
allowed := []Call{
{Name: "ask"},
{Name: "todo_write"},
{Name: "read_only_task", ReadOnly: true, Safety: PlanSafetySafe},
{Name: "read_only_skill", ReadOnly: true, Safety: PlanSafetySafe},
}
for _, c := range allowed {
if d := p.Decide(c); d.Blocked {
t.Errorf("Marker advertises %q as available while planning, but Decide blocked it: %s", c.Name, d.Message)
}
}
}
func TestMarkerForbiddenToolsAreBlocked(t *testing.T) {
p := Policy{}
// Marker: "You must not write files, run unsafe shell commands, install
// capabilities, mutate memory, delegate to writer-capable sub-agents or
// skills, control long-lived processes, or mark execution steps complete."
forbidden := []Call{
{Name: "write_file"}, // write files
{Name: "edit_file"}, // write files
{Name: "multi_edit"}, // write files
{Name: "install_source"}, // install capabilities
{Name: "install_skill"}, // install capabilities
{Name: "remember"}, // mutate memory
{Name: "forget"}, // mutate memory
{Name: "task"}, // delegate to writer-capable sub-agents
{Name: "run_skill"}, // delegate to writer-capable skills
{Name: "kill_shell"}, // control long-lived processes
// "mark execution steps complete" — the key anti-drift case. complete_step
// is pseudo-read-only (ReadOnly()==true) and self-reports unsafe; the gate
// must still refuse it on either signal.
{Name: "complete_step", ReadOnly: true, Safety: PlanSafetyUnsafe},
}
for _, c := range forbidden {
if d := p.Decide(c); !d.Blocked {
t.Errorf("Marker says %q is unavailable while planning, but Decide allowed it", c.Name)
}
}
}