/trace grows a turn-decisions table under the rule trace (V-564)

Both tables answer the same question, who won and who lost, one about nudges
and the other about utterances, so they share a page rather than splitting the
nav. A turn is one collapsible row; never_asked is coloured like a block,
because it usually is one. A read failure is logged and the rule trace above it
still renders: a daemon too old to know the method is the ordinary case during
a rolling deploy.
This commit is contained in:
2026-08-06 00:52:58 +04:00
parent a5b245dbf5
commit eec3d9bed2
3 changed files with 80 additions and 3 deletions
+18 -1
View File
@@ -1415,12 +1415,29 @@ func handleTrace(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI) {
http.Error(w, "core read failed", http.StatusBadGateway)
return
}
// The turn records share this page rather than getting one of their own
// (V-564): both answer the same question — who won, who lost and why — and
// one is about nudges while the other is about utterances. A read failure
// here is not fatal to the page: the rule trace above it still renders, and
// a daemon too old to know the method is the ordinary case during a rolling
// deploy.
turns, err := core.TurnDecisions(ctx, 25)
if err != nil {
log.Printf("trace: turn decisions: %v", err)
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := traceTmpl.Execute(w, trace); err != nil {
if err := traceTmpl.Execute(w, traceData{Tick: trace, Turns: turns}); err != nil {
log.Printf("trace render: %v", err)
}
}
// traceData — what trace.html renders: the last tick's rule arbitration and the
// last turns' claim arbitration.
type traceData struct {
Tick ipc.TickTrace
Turns []ipc.TurnDecision
}
func handleMorning(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI) {
if core == nil {
http.Error(w, "morning disabled (no -core)", http.StatusServiceUnavailable)