# Plan: persist the routing trace **Owner's call, 06-08-2026. Vikunja #629, umbrella #628.** **Verdict: the per-turn decision record now persists.** That reverses a written decision, which is the point of this file. It is not an incidental telemetry feature. Do not read it as one. Last verified: 06-08-2026 @ 799cf55 ## What the old decision said `internal/decision` kept a 25-turn in-memory ring and persisted nothing. The argument was in `CLAUDE.md` and it was a good one. A turn record is read minutes after the turn or never, so a table that outlives the diagnosis buys nothing. His words did not belong in it. ## Why it reversed V-546 replaces the generative router with classification heads on e5-small. Fitting prototypes and calibrating a distance both need real utterances. V-631 measured how few there are. Nine of the 31 modes in `internal/modes` have no seed example at all, and they are exactly the nine with no deterministic matcher. The seed corpus cannot supply them. A seed row is a phrase someone wrote for a matcher, not a thing he said. The 202 generated contrast pairs were tried and cost four points of fixture accuracy. So the choice was between no routing heads and a persisted trace. The owner chose the trace. ## Retention, and why it is two answers **Raw trace: 14 days.** `store.RoutingTraceRetention` in `internal/store/routingtraces.go`. That is the life of a diagnosis with room for a weekend. The bound is an age and not a row count. The useful question is what she did this week, and a busy Tuesday must not push last Friday out. **A correction: indefinite.** The owner corrects a turn on `/chat` (V-630). The pair is then promoted out of the trace into a seed-shaped row and kept, because a label is not a transcript. What stays in `routing_traces` is the transcript. It expires on the same 14 days as every other row, corrected or not. ## What keeps it safe The utterance is stored in clear. A 384-dimension vector of a short sentence is substantially recoverable. Storing vectors instead would be a privacy claim we cannot support, and making it would be worse than staying silent. - **Nothing here leaves the box.** The rule that the owner's notes and facts are never search input covers this table too. No query source reads it, and no upstream engine can. - **Retention is enforced on write and again at start.** `WriteRoutingTrace` prunes every 64th row, which is hours at human rate. `pruneTracesOnStart` covers the case write alone cannot. A box that goes quiet keeps every row until the next sixty-fourth turn. Without the start-time prune, the bound would hold only for a box in daily use. - **Deletion already exists.** `Store.Wipe` drops every table the database reports, so `mavend -wipe -confirm-wipe` covers this one with no list to edit. - **The ring did not move.** It is still what `/trace` reads and still what a test with no store gets. The table is a second sink beside it. A failed insert is logged and swallowed, because a trace must never change what he hears. ## What is not decided Whether some utterances must never be promoted into a durable label, no matter how badly they routed. That is a content rule and it belongs beside the personal boundary, not in the trace writer. Recorded here, left to the owner.