Only a literal pattern may take the personal boundary off a turn (V-666)

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
This commit is contained in:
2026-08-09 01:56:46 +04:00
parent 2512d686a1
commit c938148619
5 changed files with 84 additions and 21 deletions
+18 -4
View File
@@ -79,6 +79,15 @@ type querySource struct {
// not named do not get to try. The lookups still run, because a named
// destination is evidence and not a promise.
guesses bool
// boundary — dropping this source widens what leaves the box, so only a
// literal pattern may do it (V-666, owner's call of 2026-08-09).
//
// Every other guesser costs an answer when it is wrongly taken off a turn.
// This one costs the rule that a question about him never reaches an
// upstream engine. A grammar read the words to name a destination. A model
// and a softmax both inferred one, and neither may spend that.
boundary bool
}
// querySources is the ordered chain actionQuery walks; first source to claim
@@ -156,7 +165,7 @@ var querySources = []querySource{
// below answers from the world's. A question about him that got this far
// has no answer in his data, and no outside source can supply one, so this
// stops the walk rather than let the encyclopedia and the model guess.
{name: "personal", answer: (*reactiveHandler).queryPersonal, dest: router.SourceRecall, guesses: true},
{name: "personal", answer: (*reactiveHandler).queryPersonal, dest: router.SourceRecall, guesses: true, boundary: true},
// The world, read live. Owner's ruling of 2026-08-02: a metasearch hit beats
// a frozen ZIM, so SearXNG asks before Kiwix does. Nothing of his is at
// stake by this point — the boundary above already stopped every question
@@ -198,12 +207,17 @@ var querySources = []querySource{
// No destination named ⇒ the table exactly as written, which is what shipped
// before the field existed. That is the floor. The classifier arm names
// nothing, so a box whose model is down routes queries the way it always did.
func queryWalk(dest router.Source) (walk, skipped []querySource) {
// The personal boundary is the one exception, and anchored is what buys it
// (V-666). A grammar matched a literal pattern to name the destination. The
// routing heads and the resident model inferred one, and an inferred SourceWorld
// takes the boundary off a question about him. That widens what is asked
// upstream rather than costing a local answer, so those two keep it.
func queryWalk(dest router.Source, anchored bool) (walk, skipped []querySource) {
if dest == router.SourceUnknown {
return querySources, nil
}
for _, s := range querySources {
if s.guesses && s.dest != dest {
if s.guesses && s.dest != dest && (anchored || !s.boundary) {
skipped = append(skipped, s)
continue
}
@@ -219,7 +233,7 @@ func (h *reactiveHandler) actionQuery(ctx context.Context, dec router.Decision)
// (V-564). Finish names everyone below the winner.
decision.Expect(ctx, decision.StageQuery, querySourceNames())
rec := decision.From(ctx)
walk, skipped := queryWalk(dec.Source)
walk, skipped := queryWalk(dec.Source, dec.SourceAnchored)
for _, src := range skipped {
rec.Note(decision.Claim{
Stage: decision.StageQuery, Claimant: src.name, Outcome: decision.NeverAsked,
+32 -10
View File
@@ -10,7 +10,7 @@ import (
// 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)
walk, skipped := queryWalk(router.SourceUnknown, false)
if len(skipped) != 0 {
t.Errorf("skipped %d sources with no destination named, want none", len(skipped))
}
@@ -32,15 +32,16 @@ func TestANamedDestinationSilencesTheOtherGuessers(t *testing.T) {
dest router.Source
utterance string
silenced string
anchored bool // a stage 0 grammar named the destination
}{
{router.SourceWorld, "что такое TCP?", "weather"},
{router.SourceWorld, "сколько будет 17 на 23?", "weather"},
{router.SourceWorld, "кто такой Линус Торвальдс?", "personal"},
{router.SourceRecall, "какой у меня любимый язык?", "feeds"},
{router.SourceCalendar, "что в календаре на завтра?", "weather"},
{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)
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)
}
@@ -56,7 +57,7 @@ func TestANamedDestinationSilencesTheOtherGuessers(t *testing.T) {
// 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)
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)
@@ -74,7 +75,7 @@ func TestNamingTheWorldStillReadsHisDataFirst(t *testing.T) {
// makes "какой у меня любимый язык?" answer "не нашла у тебя такой записи"
// rather than reaching SearXNG once nothing local had it.
func TestNamingRecallKeepsTheBoundary(t *testing.T) {
walk, _ := queryWalk(router.SourceRecall)
walk, _ := queryWalk(router.SourceRecall, true)
if !inWalk(walk, "personal") {
t.Fatal("the personal boundary was skipped on a turn named for his own data")
}
@@ -83,12 +84,33 @@ func TestNamingRecallKeepsTheBoundary(t *testing.T) {
}
}
// 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)
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))
}