c938148619
Naming a destination takes the guessing query sources off a turn, and the personal boundary is one of them. Every other guesser costs an answer when it is wrongly dropped. This one costs the rule that a question about him never reaches an upstream engine. Three deciders name a destination now and two of them infer it: the routing heads and the resident model. Decision.SourceAnchored says a stage 0 grammar read the words instead. queryWalk honours it for the source marked boundary: true and for no other, so the rest of the table is unchanged. Owner's call of 2026-08-09. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ptwopxyo3Z2kwFckHkLvN
138 lines
5.2 KiB
Go
138 lines
5.2 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/kami/maven/internal/router"
|
|
)
|
|
|
|
// The floor, and it is the reason a destination is safe to add at all: a box
|
|
// whose model is down names nothing, and naming nothing has to walk the chain
|
|
// the way it walked before the field existed.
|
|
func TestNoDestinationWalksTheWholeChain(t *testing.T) {
|
|
walk, skipped := queryWalk(router.SourceUnknown, false)
|
|
if len(skipped) != 0 {
|
|
t.Errorf("skipped %d sources with no destination named, want none", len(skipped))
|
|
}
|
|
if len(walk) != len(querySources) {
|
|
t.Fatalf("walk has %d sources, want the whole table of %d", len(walk), len(querySources))
|
|
}
|
|
for i := range walk {
|
|
if walk[i].name != querySources[i].name {
|
|
t.Fatalf("position %d is %q, want %q", i, walk[i].name, querySources[i].name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The 2026-08-07 defects, one per line. Each is a source that decides by seed
|
|
// similarity claiming a turn that was never its own, and then answering it
|
|
// because it has no lookup that could come back empty.
|
|
func TestANamedDestinationSilencesTheOtherGuessers(t *testing.T) {
|
|
cases := []struct {
|
|
dest router.Source
|
|
utterance string
|
|
silenced string
|
|
anchored bool // a stage 0 grammar named the destination
|
|
}{
|
|
{router.SourceWorld, "что такое TCP?", "weather", true},
|
|
{router.SourceWorld, "сколько будет 17 на 23?", "weather", true},
|
|
{router.SourceWorld, "кто такой Линус Торвальдс?", "personal", true},
|
|
{router.SourceRecall, "какой у меня любимый язык?", "feeds", false},
|
|
{router.SourceCalendar, "что в календаре на завтра?", "weather", true},
|
|
}
|
|
for _, c := range cases {
|
|
walk, skipped := queryWalk(c.dest, c.anchored)
|
|
if inWalk(walk, c.silenced) {
|
|
t.Errorf("%q named %q: %q is still asked", c.utterance, c.dest, c.silenced)
|
|
}
|
|
if !inWalk(skipped, c.silenced) {
|
|
t.Errorf("%q named %q: %q is missing from the record of who was skipped",
|
|
c.utterance, c.dest, c.silenced)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Naming the world must not send the turn outside. His notes, his facts and the
|
|
// boundary in front of them are the invariant CLAUDE.md states as "the owner's
|
|
// data first, then the world", and a destination a model wrote must not be able
|
|
// to reverse it.
|
|
func TestNamingTheWorldStillReadsHisDataFirst(t *testing.T) {
|
|
walk, _ := queryWalk(router.SourceWorld, true)
|
|
for _, look := range []string{"fact-by-key", "embed", "memory", "notes"} {
|
|
if !inWalk(walk, look) {
|
|
t.Errorf("%q was dropped; only the sources that guess may be dropped", look)
|
|
}
|
|
}
|
|
if posOf(walk, "notes") > posOf(walk, "search") {
|
|
t.Error("search is asked before his notes are")
|
|
}
|
|
if posOf(walk, "search") < 0 {
|
|
t.Fatal("search is not in the walk at all")
|
|
}
|
|
}
|
|
|
|
// The boundary belongs to his data, so naming recall keeps it. That is what
|
|
// makes "какой у меня любимый язык?" answer "не нашла у тебя такой записи"
|
|
// rather than reaching SearXNG once nothing local had it.
|
|
func TestNamingRecallKeepsTheBoundary(t *testing.T) {
|
|
walk, _ := queryWalk(router.SourceRecall, true)
|
|
if !inWalk(walk, "personal") {
|
|
t.Fatal("the personal boundary was skipped on a turn named for his own data")
|
|
}
|
|
if posOf(walk, "personal") > posOf(walk, "search") {
|
|
t.Error("the boundary no longer sits in front of the world")
|
|
}
|
|
}
|
|
|
|
// The owner's call of 2026-08-09 (V-666): only a stage 0 grammar may take the
|
|
// personal boundary off a turn. The routing heads and the resident model both
|
|
// name a destination by inference, and an inferred SourceWorld would send a
|
|
// question about him upstream. Every other guesser still goes.
|
|
func TestOnlyAGrammarMayDropTheBoundary(t *testing.T) {
|
|
walk, skipped := queryWalk(router.SourceWorld, false)
|
|
if !inWalk(walk, "personal") {
|
|
t.Error("an inferred destination took the boundary off the turn")
|
|
}
|
|
if !inWalk(skipped, "weather") {
|
|
t.Error("weather is still asked; the rule covers the boundary alone")
|
|
}
|
|
if posOf(walk, "personal") > posOf(walk, "search") {
|
|
t.Error("the boundary no longer sits in front of the world")
|
|
}
|
|
if anchored, _ := queryWalk(router.SourceWorld, true); inWalk(anchored, "personal") {
|
|
t.Error(`a grammar named the world and the boundary stayed: ` +
|
|
`"кто такой Линус Торвальдс?" is answered "не нашла у тебя такой записи" again`)
|
|
}
|
|
}
|
|
|
|
// Whatever the destination, the walk is a subsequence of the table. Every
|
|
// comment on that table argues an order between two sources, and none of those
|
|
// reasons is about this field.
|
|
func TestTheWalkNeverReordersTheTable(t *testing.T) {
|
|
for _, dest := range append([]router.Source{router.SourceUnknown}, router.Sources...) {
|
|
walk, skipped := queryWalk(dest, true)
|
|
if len(walk)+len(skipped) != len(querySources) {
|
|
t.Errorf("%q: %d walked + %d skipped, want %d", dest, len(walk), len(skipped), len(querySources))
|
|
}
|
|
last := -1
|
|
for _, s := range walk {
|
|
at := posOf(querySources, s.name)
|
|
if at <= last {
|
|
t.Errorf("%q: %q is out of table order", dest, s.name)
|
|
}
|
|
last = at
|
|
}
|
|
}
|
|
}
|
|
|
|
func inWalk(list []querySource, name string) bool { return posOf(list, name) >= 0 }
|
|
|
|
func posOf(list []querySource, name string) int {
|
|
for i, s := range list {
|
|
if s.name == name {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|