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:
@@ -510,13 +510,21 @@ they look rather than guess.
|
|||||||
**The personal boundary is the one exception and it is deliberate.** It guesses,
|
**The personal boundary is the one exception and it is deliberate.** It guesses,
|
||||||
so naming `SourceWorld` drops it. That is what stops it answering "кто такой
|
so naming `SourceWorld` drops it. That is what stops it answering "кто такой
|
||||||
Линус Торвальдс?" with "не нашла у тебя такой записи", which it did on
|
Линус Торвальдс?" with "не нашла у тебя такой записи", which it did on
|
||||||
2026-08-07. The cost is that a destination a model wrote can now take the
|
2026-08-07. `TestNamingRecallKeepsTheBoundary` pins the other half: naming
|
||||||
boundary off a turn. A question about him that the model calls `world` reaches
|
`SourceRecall` keeps the boundary in front of the world.
|
||||||
SearXNG, where today the boundary stops it. Only the utterance leaves the box,
|
|
||||||
never his notes or history, so this widens what is asked and not what is sent.
|
**Only a stage 0 grammar may drop it** (owner's call, 09-08-2026, V-666). The
|
||||||
`TestNamingRecallKeepsTheBoundary` pins the other half: naming `SourceRecall`
|
question of who is allowed to was open until then. Three deciders name a
|
||||||
keeps the boundary in front of the world. Whether a model may drop it at all is
|
destination and two of them infer it: the routing heads and the resident model.
|
||||||
the owner's call and has not been made.
|
An inferred `SourceWorld` on a question about him would reach SearXNG, and that
|
||||||
|
widens what is asked rather than costing a local answer. So `Decision.SourceAnchored`
|
||||||
|
carries the provenance. It is a field and not `Stage == 0`. Stage 0 also means
|
||||||
|
confidence 1.0 and an anchored claim band, and one of those could stop implying
|
||||||
|
the others. `queryWalk` reads it for the source marked `boundary: true` and for
|
||||||
|
no other. So every other guesser still comes off the turn, whoever named the
|
||||||
|
destination. `TestOnlyAGrammarMayDropTheBoundary` pins both directions.
|
||||||
|
`definitionQueryPattern` claims "кто такой X", so the 2026-08-07 case is still
|
||||||
|
anchored and still answered.
|
||||||
|
|
||||||
What comes out is only the sources that **guess**. Those decide a turn is theirs by
|
What comes out is only the sources that **guess**. Those decide a turn is theirs by
|
||||||
cosine against frozen seeds, then answer whatever they claimed. They hold no table
|
cosine against frozen seeds, then answer whatever they claimed. They hold no table
|
||||||
|
|||||||
@@ -79,6 +79,15 @@ type querySource struct {
|
|||||||
// not named do not get to try. The lookups still run, because a named
|
// not named do not get to try. The lookups still run, because a named
|
||||||
// destination is evidence and not a promise.
|
// destination is evidence and not a promise.
|
||||||
guesses bool
|
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
|
// 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
|
// 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
|
// 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.
|
// 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
|
// 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
|
// 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
|
// 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
|
// No destination named ⇒ the table exactly as written, which is what shipped
|
||||||
// before the field existed. That is the floor. The classifier arm names
|
// 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.
|
// 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 {
|
if dest == router.SourceUnknown {
|
||||||
return querySources, nil
|
return querySources, nil
|
||||||
}
|
}
|
||||||
for _, s := range querySources {
|
for _, s := range querySources {
|
||||||
if s.guesses && s.dest != dest {
|
if s.guesses && s.dest != dest && (anchored || !s.boundary) {
|
||||||
skipped = append(skipped, s)
|
skipped = append(skipped, s)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -219,7 +233,7 @@ func (h *reactiveHandler) actionQuery(ctx context.Context, dec router.Decision)
|
|||||||
// (V-564). Finish names everyone below the winner.
|
// (V-564). Finish names everyone below the winner.
|
||||||
decision.Expect(ctx, decision.StageQuery, querySourceNames())
|
decision.Expect(ctx, decision.StageQuery, querySourceNames())
|
||||||
rec := decision.From(ctx)
|
rec := decision.From(ctx)
|
||||||
walk, skipped := queryWalk(dec.Source)
|
walk, skipped := queryWalk(dec.Source, dec.SourceAnchored)
|
||||||
for _, src := range skipped {
|
for _, src := range skipped {
|
||||||
rec.Note(decision.Claim{
|
rec.Note(decision.Claim{
|
||||||
Stage: decision.StageQuery, Claimant: src.name, Outcome: decision.NeverAsked,
|
Stage: decision.StageQuery, Claimant: src.name, Outcome: decision.NeverAsked,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
// whose model is down names nothing, and naming nothing has to walk the chain
|
// whose model is down names nothing, and naming nothing has to walk the chain
|
||||||
// the way it walked before the field existed.
|
// the way it walked before the field existed.
|
||||||
func TestNoDestinationWalksTheWholeChain(t *testing.T) {
|
func TestNoDestinationWalksTheWholeChain(t *testing.T) {
|
||||||
walk, skipped := queryWalk(router.SourceUnknown)
|
walk, skipped := queryWalk(router.SourceUnknown, false)
|
||||||
if len(skipped) != 0 {
|
if len(skipped) != 0 {
|
||||||
t.Errorf("skipped %d sources with no destination named, want none", len(skipped))
|
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
|
dest router.Source
|
||||||
utterance string
|
utterance string
|
||||||
silenced string
|
silenced string
|
||||||
|
anchored bool // a stage 0 grammar named the destination
|
||||||
}{
|
}{
|
||||||
{router.SourceWorld, "что такое TCP?", "weather"},
|
{router.SourceWorld, "что такое TCP?", "weather", true},
|
||||||
{router.SourceWorld, "сколько будет 17 на 23?", "weather"},
|
{router.SourceWorld, "сколько будет 17 на 23?", "weather", true},
|
||||||
{router.SourceWorld, "кто такой Линус Торвальдс?", "personal"},
|
{router.SourceWorld, "кто такой Линус Торвальдс?", "personal", true},
|
||||||
{router.SourceRecall, "какой у меня любимый язык?", "feeds"},
|
{router.SourceRecall, "какой у меня любимый язык?", "feeds", false},
|
||||||
{router.SourceCalendar, "что в календаре на завтра?", "weather"},
|
{router.SourceCalendar, "что в календаре на завтра?", "weather", true},
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
walk, skipped := queryWalk(c.dest)
|
walk, skipped := queryWalk(c.dest, c.anchored)
|
||||||
if inWalk(walk, c.silenced) {
|
if inWalk(walk, c.silenced) {
|
||||||
t.Errorf("%q named %q: %q is still asked", c.utterance, c.dest, 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
|
// data first, then the world", and a destination a model wrote must not be able
|
||||||
// to reverse it.
|
// to reverse it.
|
||||||
func TestNamingTheWorldStillReadsHisDataFirst(t *testing.T) {
|
func TestNamingTheWorldStillReadsHisDataFirst(t *testing.T) {
|
||||||
walk, _ := queryWalk(router.SourceWorld)
|
walk, _ := queryWalk(router.SourceWorld, true)
|
||||||
for _, look := range []string{"fact-by-key", "embed", "memory", "notes"} {
|
for _, look := range []string{"fact-by-key", "embed", "memory", "notes"} {
|
||||||
if !inWalk(walk, look) {
|
if !inWalk(walk, look) {
|
||||||
t.Errorf("%q was dropped; only the sources that guess may be dropped", 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 "не нашла у тебя такой записи"
|
// makes "какой у меня любимый язык?" answer "не нашла у тебя такой записи"
|
||||||
// rather than reaching SearXNG once nothing local had it.
|
// rather than reaching SearXNG once nothing local had it.
|
||||||
func TestNamingRecallKeepsTheBoundary(t *testing.T) {
|
func TestNamingRecallKeepsTheBoundary(t *testing.T) {
|
||||||
walk, _ := queryWalk(router.SourceRecall)
|
walk, _ := queryWalk(router.SourceRecall, true)
|
||||||
if !inWalk(walk, "personal") {
|
if !inWalk(walk, "personal") {
|
||||||
t.Fatal("the personal boundary was skipped on a turn named for his own data")
|
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
|
// 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
|
// comment on that table argues an order between two sources, and none of those
|
||||||
// reasons is about this field.
|
// reasons is about this field.
|
||||||
func TestTheWalkNeverReordersTheTable(t *testing.T) {
|
func TestTheWalkNeverReordersTheTable(t *testing.T) {
|
||||||
for _, dest := range append([]router.Source{router.SourceUnknown}, router.Sources...) {
|
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) {
|
if len(walk)+len(skipped) != len(querySources) {
|
||||||
t.Errorf("%q: %d walked + %d skipped, want %d", dest, len(walk), len(skipped), len(querySources))
|
t.Errorf("%q: %d walked + %d skipped, want %d", dest, len(walk), len(skipped), len(querySources))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,21 @@ type Decision struct {
|
|||||||
// before this field existed. See source.go for why it is twelve values.
|
// before this field existed. See source.go for why it is twelve values.
|
||||||
Source Source
|
Source Source
|
||||||
|
|
||||||
|
// SourceAnchored — a stage 0 grammar named that destination, matching a
|
||||||
|
// literal pattern to do it. Only the router sets this, and only there.
|
||||||
|
//
|
||||||
|
// It exists because one thing downstream is not reversible by evidence
|
||||||
|
// (V-666). Naming a destination normally takes guessing sources off a turn,
|
||||||
|
// and one of those is the personal boundary, which is what stops a question
|
||||||
|
// about him from reaching the world. A grammar that read "что такое X" may
|
||||||
|
// take it off. A model or a softmax may not, because a wrong destination
|
||||||
|
// there widens what leaves the box rather than costing an answer.
|
||||||
|
//
|
||||||
|
// Read Stage instead and the two decisions get coupled: stage 0 also means
|
||||||
|
// confidence 1.0 and an anchored claim band, and a later cascade change
|
||||||
|
// could make one true where the other is not.
|
||||||
|
SourceAnchored bool
|
||||||
|
|
||||||
// Continued — this decision was rebuilt from the previous turn rather
|
// Continued — this decision was rebuilt from the previous turn rather
|
||||||
// than routed, because the utterance was an ellipsis ("а завтра?").
|
// than routed, because the utterance was an ellipsis ("а завтра?").
|
||||||
// Handlers use it to know that Slots.Text is the PREVIOUS turn's topic
|
// Handlers use it to know that Slots.Text is the PREVIOUS turn's topic
|
||||||
|
|||||||
@@ -98,6 +98,10 @@ func (r *Router) Route(ctx context.Context, utterance string, now time.Time) (De
|
|||||||
continue // grammar matched shape but not content → fall through
|
continue // grammar matched shape but not content → fall through
|
||||||
}
|
}
|
||||||
d.Utterance = utterance
|
d.Utterance = utterance
|
||||||
|
// A literal pattern named that destination, which is the one provenance
|
||||||
|
// allowed to take the personal boundary off a turn (V-666). Set here and
|
||||||
|
// nowhere else, so no other arm of the cascade can claim it.
|
||||||
|
d.SourceAnchored = d.Source != SourceUnknown
|
||||||
// The grammar decided the intent; the extractor fills the slots it did
|
// The grammar decided the intent; the extractor fills the slots it did
|
||||||
// not match (V-572). See fillMatchedSlots for why every grammar gets it.
|
// not match (V-572). See fillMatchedSlots for why every grammar gets it.
|
||||||
r.fillMatchedSlots(ctx, &d, now)
|
r.fillMatchedSlots(ctx, &d, now)
|
||||||
|
|||||||
Reference in New Issue
Block a user