router/semantic: slice 23 corpus fast-path reconciliation — DeriveFastPath over the real router replaces the regex mirror, factory/merge validated, corpus rebuilt (dataset_hash unchanged), drift diagnostic and rerun tooling
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package semantic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kami/maven/internal/router"
|
||||
)
|
||||
|
||||
// ExperimentActVerbs is the act allowlist shared by the experiment's legacy
|
||||
// baseline (the eval fixture and the slice-22 harness), the routed-heads
|
||||
// harness, and the corpus fast-path derivation. One non-test list so the
|
||||
// corpus derivation can never drift from what the measurement router accepts.
|
||||
func ExperimentActVerbs() []string {
|
||||
return []string{
|
||||
"перезапусти", "перезагрузи", "выключи", "включи", "останови", "запусти",
|
||||
"закрой", "открой", "сделай", "поставь",
|
||||
"restart", "reboot", "stop", "start", "turn off", "turn on", "open", "close",
|
||||
}
|
||||
}
|
||||
|
||||
func experimentActMatcher() router.ActMatcher {
|
||||
return router.DefaultActMatcher{Fns: ExperimentActVerbs()}
|
||||
}
|
||||
|
||||
// FastPathOutcome is the derived fast-path classification for one surface.
|
||||
// Matched mirrors TryFastPath; Grammar names the winning stage-0 grammar for
|
||||
// attribution, or the empty string when nothing resolved.
|
||||
type FastPathOutcome struct {
|
||||
Matched bool
|
||||
Grammar string
|
||||
}
|
||||
|
||||
var (
|
||||
fastPathOnce sync.Once
|
||||
fastPathRouter *router.Router
|
||||
fastPathGrammars []router.Grammar
|
||||
)
|
||||
|
||||
// DeriveFastPath mirrors the production fast path for a surface: it runs
|
||||
// TryFastPath over the daemon's ordered stage-0 grammar list with the
|
||||
// experiment's act allowlist — the exact router the legacy baseline measures —
|
||||
// and reports whether a grammar resolved the utterance. This is the
|
||||
// authoritative derivation for corpus fast_path_resolved metadata. The
|
||||
// classifier, threshold and LLM never run on the fast path, so they are not
|
||||
// wired here.
|
||||
func DeriveFastPath(text string) FastPathOutcome {
|
||||
fastPathOnce.Do(func() {
|
||||
acts := experimentActMatcher()
|
||||
fastPathGrammars = router.StageZeroGrammars(acts)
|
||||
fastPathRouter = router.New(router.Config{
|
||||
Grammars: fastPathGrammars,
|
||||
Extractor: router.Extractor{
|
||||
Time: router.StubDateTimeParser{},
|
||||
Acts: acts,
|
||||
Facts: router.DefaultFactParser{},
|
||||
},
|
||||
})
|
||||
})
|
||||
res, err := fastPathRouter.TryFastPath(context.Background(), router.NormalizedInput{
|
||||
Text: text,
|
||||
MatchText: router.NormalizeMatchText(text),
|
||||
}, time.Now())
|
||||
if err != nil || !res.Matched {
|
||||
return FastPathOutcome{}
|
||||
}
|
||||
// Attribute the winner by replaying TryFastPath's ordered first-accept
|
||||
// walk, including the wake-stripped alternate. A matcher that matched the
|
||||
// shape but declined the content falls through, exactly as the router does.
|
||||
stripped, hadWake := router.StripWakeToken(text)
|
||||
for _, g := range fastPathGrammars {
|
||||
_, matched, ok := g.Evaluate(text)
|
||||
if !matched && hadWake {
|
||||
_, matched, ok = g.Evaluate(stripped)
|
||||
}
|
||||
if matched && ok {
|
||||
return FastPathOutcome{Matched: true, Grammar: g.Name}
|
||||
}
|
||||
}
|
||||
return FastPathOutcome{Matched: true}
|
||||
}
|
||||
Reference in New Issue
Block a user