e1f84a3474
Two defects found reviewing the PR. The insert ran on the turn's own context, so a caller that hung up or timed out cancelled it. That is exactly the turn worth having. It now runs detached, with a one-second bound of its own, because a write must not hold the reply. Retention was enforced on write alone, so a box that goes quiet for a month kept every row until the next sixty-fourth turn. pruneTracesOnStart closes that, and RoutingTraceRetention is exported so the daemon reads the same number the store enforces. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117tgnmbgZpHVV3XSNw8Qua
63 lines
3.2 KiB
Markdown
63 lines
3.2 KiB
Markdown
# 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.
|