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.
50 lines
2.1 KiB
Go
50 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/kami/maven/internal/router"
|
|
)
|
|
|
|
// commandProhibitionReply is deliberately operation-neutral. At this boundary
|
|
// Maven may know only that the user denied authority, not whether the model
|
|
// would have called it a reminder, board transition, local tool or Hexis act.
|
|
const commandProhibitionReply = "хорошо, не буду."
|
|
|
|
// resolveCommandProhibition is the first mutation boundary in a turn. It runs
|
|
// before a parked clarify answer or candidate selection can consume the words,
|
|
// and before any route/model is consulted. A direct prohibition is complete in
|
|
// itself: it needs no target lookup and makes no external call.
|
|
//
|
|
// A parked clarify request is unrelated state. Preserve it and say the pending
|
|
// question again, using the same bounded suspend policy as every other side
|
|
// request. Candidate lists likewise remain untouched; no ordinal was selected.
|
|
func (h *reactiveHandler) resolveCommandProhibition(ctx context.Context, text string) (string, bool) {
|
|
if !router.IsCommandProhibition(text) {
|
|
return "", false
|
|
}
|
|
// A later bare "да" must not revive authority the user has just revoked.
|
|
// Confirmation slots are all mutation authority and are process-local, so
|
|
// clearing the three under their shared mutex is both conservative and
|
|
// atomic. Clarify questions and candidate lists are not authority and stay.
|
|
h.mu.Lock()
|
|
h.pending = nil
|
|
h.pendingHexis = nil
|
|
h.pendingRoutine = nil
|
|
h.mu.Unlock()
|
|
if h.clarifyStore != nil {
|
|
if q := h.clarifyStore.Get(dialogueIDOf(ctx), h.now()); q != nil {
|
|
h.noteSuspended(ctx, q)
|
|
}
|
|
}
|
|
return commandProhibitionReply, true
|
|
}
|
|
|
|
// refusesCommand is the defense-in-depth form for execution entry points which
|
|
// can also be called with a reconstructed or test decision outside runTurn.
|
|
// The sentinel cannot be renamed into an enabled function, and the original
|
|
// utterance remains the authority even when a model rewrites Slots.Text.
|
|
func refusesCommand(dec router.Decision) bool {
|
|
return dec.CapabilitySelection.Fn == router.ProhibitedActFn || router.IsCommandProhibition(dec.Utterance)
|
|
}
|