Files
Maven/internal/router/acttarget.go
T
claude 0a2e194e76 router: migrate refusesCommand and ActHasEntityTarget to CapabilitySelection (slice 6c)
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.
2026-09-06 21:43:14 +04:00

44 lines
1.5 KiB
Go

package router
import "github.com/kami/maven/internal/lexicon"
// ActHasEntityTarget reports whether an act names something that Nexus may be
// asked to resolve. A local zero-argument tool may still be valid; this gate is
// only about crossing into the ecosystem, where an entity is mandatory.
//
// A matched function carries its target in Args. An unmatched entity act is
// the Hexis discovery lane, so it must at least contain a verb plus a subject.
// A bare verb and a demonstrative-only tail carry no target evidence and stay
// local/clarify instead of sending free ambiguity to Nexus.
func ActHasEntityTarget(decision Decision) bool {
if decision.Intent != IntentAct {
return false
}
if decision.CapabilitySelection.Resolved {
if len(decision.CapabilitySelection.Args) > 0 {
return hasNamedEntityToken(decision.CapabilitySelection.Args)
}
// A resident-model act may name the accepted verb and its target in
// Text while leaving Args empty. Resolved establishes that the first token
// is the operation; only a meaningful tail can establish the entity.
tokens := planTokens(decision.Slots.Text)
return len(tokens) > 1 && hasNamedEntityToken(tokens[1:])
}
tokens := planTokens(decision.Slots.Text)
if len(tokens) < 2 {
return false
}
return hasNamedEntityToken(tokens[1:])
}
func hasNamedEntityToken(tokens []string) bool {
references := lexicon.UnresolvedReferences()
for _, token := range tokens {
if lexicon.IsFillerParticle(token) || hasExactWord(references, token) {
continue
}
return true
}
return false
}