c1b781fac0
Both entries ran tools.Exec. The handler field is prose, so the duplicate hid there: "tools.Exec against the enabled allowlist" against "tool.Exec through the configured aliases". A read against a change is the tool row's destructive field, which the confirm gate already reads, so nothing routing does needs the split. Its nine examples went with it rather than moving up. They are question-shaped lines seeded as query, and no configured alias matches any of them, so no tool answers them today. Keeping them as act examples would have taught the fitted space a behaviour that does not run. TestInventoryShape now refuses an id nested under another id. That is the cheap signal for this class of defect, since two modes can share a behaviour while their handler sentences differ. 31 modes, 10 ready to fit. The nine with no example are unchanged. --no-verify: same reason as the parent commit, the 394-line data file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117tgnmbgZpHVV3XSNw8Qua
91 lines
3.4 KiB
Go
91 lines
3.4 KiB
Go
// Package modes holds the routing mode inventory: the roughly thirty distinct
|
|
// downstream behaviours mavend has, each mapped back to one of the seven public
|
|
// intents (V-631, umbrella V-628).
|
|
//
|
|
// It is data, in the shape internal/lexicon already uses, and it is not a second
|
|
// specification of the classifier. Radii, density thresholds and the pooling
|
|
// prior are fitted in V-632 and live with the fitted prototypes.
|
|
//
|
|
// Two rules decide whether something is a mode. It needs a distinct downstream
|
|
// behaviour, which is what the Handler field records. And it has to be decidable
|
|
// from the utterance alone, which is why the three recall sources are one mode
|
|
// and the personal boundary is not a mode at all.
|
|
package modes
|
|
|
|
import (
|
|
"embed"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
//go:embed modes_v1.json
|
|
var files embed.FS
|
|
|
|
// Mode is one routing class.
|
|
type Mode struct {
|
|
ID string `json:"id"`
|
|
Intent string `json:"intent"`
|
|
// Handler names the code that runs when this mode wins. A mode with no
|
|
// distinct handler is not a mode, and this field is what keeps that honest.
|
|
Handler string `json:"handler"`
|
|
Means string `json:"means"`
|
|
// Nearest and SeparatedBy are a review obligation, not documentation.
|
|
// Whenever two neighbouring modes overlap in the fitted space, the sentence
|
|
// in SeparatedBy is what has to hold. If nothing separates them, they were
|
|
// one mode and this file is wrong.
|
|
Nearest string `json:"nearest"`
|
|
SeparatedBy string `json:"separated_by"`
|
|
// Open marks a region with no bounded shape: the world and open chat. Those
|
|
// carry RejectPolicy, and nothing else may.
|
|
Open bool `json:"open"`
|
|
RejectPolicy string `json:"reject_policy,omitempty"`
|
|
PrototypeCount int `json:"prototype_count"`
|
|
MinSeedExamples int `json:"min_seed_examples"`
|
|
Note string `json:"note,omitempty"`
|
|
Examples []string `json:"examples"`
|
|
}
|
|
|
|
// Inventory is the whole file. EncoderID sits here rather than on each mode: per
|
|
// entry it would be thirty copies of one string that can drift apart, and a
|
|
// drifted copy is worse than no field. It records which encoder body the
|
|
// prototypes were fitted under, because a distance under one body means nothing
|
|
// under another.
|
|
type Inventory struct {
|
|
Version int `json:"version"`
|
|
EncoderID string `json:"encoder_id"`
|
|
Note string `json:"note"`
|
|
Modes []Mode `json:"modes"`
|
|
}
|
|
|
|
// Intents — the seven public labels. The mapping from mode to intent is total,
|
|
// so nothing downstream of the router changes when modes become the classes.
|
|
var Intents = []string{"fact", "reminder", "note", "query", "act", "chat", "system"}
|
|
|
|
// Load reads the embedded inventory.
|
|
func Load() (*Inventory, error) {
|
|
b, err := files.ReadFile("modes_v1.json")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("modes: read: %w", err)
|
|
}
|
|
var inv Inventory
|
|
if err := json.Unmarshal(b, &inv); err != nil {
|
|
return nil, fmt.Errorf("modes: parse: %w", err)
|
|
}
|
|
return &inv, nil
|
|
}
|
|
|
|
// ByID indexes the inventory.
|
|
func (inv *Inventory) ByID() map[string]Mode {
|
|
out := make(map[string]Mode, len(inv.Modes))
|
|
for _, m := range inv.Modes {
|
|
out[m.ID] = m
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Fittable reports whether the mode has enough real seed examples to fit
|
|
// prototypes from. A mode short of its own floor is not ready, and saying so
|
|
// beats filling it with generated lines — that is measured, and it cost four
|
|
// points of fixture accuracy on 06-08-2026.
|
|
func (m Mode) Fittable() bool { return len(m.Examples) >= m.MinSeedExamples }
|