// 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 }