0a2e194e76
Migrate the two remaining action-routing consumers from compatibility Decision.Slings fields to authoritative Decision.CapabilitySelection: - refusesCommand: reads CapabilitySelection.Fn instead of Slots.Fn - ActHasEntityTarget: reads CapabilitySelection.Resolved and CapabilitySelection.Args instead of Slots.HasFn and Slots.Args Slots.Text remains the source for entity text when positional args do not contain the target (unchanged). Regression tests prove: - prohibited sentinel preserved byte-for-byte through SelectCapability - blanked Slots.Fn/Args/HasFn do not affect migrated consumers - Praxis/Hexis entity-target routing unchanged - stage-0 deterministic act unchanged - classifier/extractor act unchanged do not remove the compatibility mirrors yet.
80 lines
2.5 KiB
Go
80 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/kami/maven/internal/router"
|
|
)
|
|
|
|
// TestRefusesCommandUsesCapabilitySelection proves that refusesCommand reads
|
|
// CapabilitySelection.Fn rather than the compatibility Slots.Fn. When
|
|
// CapabilitySelection is populated with the prohibited sentinel but Slots.Fn
|
|
// is blank, the refusal must still fire.
|
|
func TestRefusesCommandUsesCapabilitySelection(t *testing.T) {
|
|
dec := router.Decision{
|
|
Intent: router.IntentAct,
|
|
CapabilitySelection: router.CapabilitySelection{
|
|
Fn: router.ProhibitedActFn,
|
|
Resolved: true,
|
|
},
|
|
// Slots compatibility fields deliberately blank.
|
|
}
|
|
if !refusesCommand(dec) {
|
|
t.Fatal("refusesCommand should return true when CapabilitySelection.Fn == ProhibitedActFn")
|
|
}
|
|
}
|
|
|
|
// TestRefusesCommandUtteranceFallback proves that the utterance-based
|
|
// prohibition check still works as a defense-in-depth belt when
|
|
// CapabilitySelection does not carry the sentinel.
|
|
func TestRefusesCommandUtteranceFallback(t *testing.T) {
|
|
dec := router.Decision{
|
|
Utterance: "don't restart nginx",
|
|
}
|
|
if !refusesCommand(dec) {
|
|
t.Fatal("refusesCommand should return true for a prohibited utterance")
|
|
}
|
|
}
|
|
|
|
// TestRefusesCommandNonProhibitedCapability proves that an act with a
|
|
// non-prohibited capability is NOT refused even when Slots.Fn happens to
|
|
// carry the prohibited sentinel (cross-contamination).
|
|
func TestRefusesCommandNonProhibitedCapability(t *testing.T) {
|
|
dec := router.Decision{
|
|
Intent: router.IntentAct,
|
|
Utterance: "restart nginx",
|
|
CapabilitySelection: router.CapabilitySelection{
|
|
Fn: "restart",
|
|
Resolved: true,
|
|
},
|
|
}
|
|
if refusesCommand(dec) {
|
|
t.Fatal("refusesCommand should return false for a non-prohibited capability")
|
|
}
|
|
}
|
|
|
|
// TestRefusesCommandProhibitedSentinelPreservedThroughPipeline proves that the
|
|
// command-prohibition grammar sentinel survives through SelectCapability into
|
|
// CapabilitySelection byte-for-byte.
|
|
func TestRefusesCommandProhibitedSentinelPreservedThroughPipeline(t *testing.T) {
|
|
dec := router.Decision{
|
|
Intent: router.IntentAct,
|
|
Slots: router.Slots{
|
|
Fn: router.ProhibitedActFn,
|
|
HasFn: true,
|
|
},
|
|
}
|
|
sel := router.SelectCapability(dec, nil)
|
|
dec.CapabilitySelection = sel
|
|
|
|
if dec.CapabilitySelection.Fn != router.ProhibitedActFn {
|
|
t.Errorf("CapabilitySelection.Fn = %q, want %q", dec.CapabilitySelection.Fn, router.ProhibitedActFn)
|
|
}
|
|
if !dec.CapabilitySelection.Resolved {
|
|
t.Error("CapabilitySelection.Resolved should be true")
|
|
}
|
|
if !refusesCommand(dec) {
|
|
t.Fatal("refusesCommand should return true after pipeline preserves the sentinel")
|
|
}
|
|
}
|