No way to see WHY a prediction stalled: capture a profile on a latency spike #42
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
[claude 2026-08-23] Reported by the operator.
Symptom
Local session, no WAN. In vim: hit ESC, then
ba few times. Threeunderlined
bbbsit on screen, then everything catches up at once. Noinsight into what happened — was the daemon stalled, or did the overlay
simply hold a doomed prediction until its deadline?
What exists today
Aggregate counters only.
predict.Counters(src/predict.zig:95) tracksmade / confirmed / contradicted / expired / suppressed, and the client
prints them once at exit (
dumpPredictStats, src/interact.zig:1383); thewall republishes the zoomed tile's set each pass (src/wallview.zig:1514).
Not one of those carries TIME. There is no per-prediction age, no ingress ->
egress timeline, nothing that distinguishes a slow daemon from a prediction
that was never going to be confirmed.
predict.zigis deliberatelyclock-free — it takes
now_msfrom the caller (src/predict.zig:172) — sothe instrumentation belongs at the caller, not in the module.
Leading hypothesis for the vim case (needs the tooling to confirm)
Possibly not a latency spike at all:
predictAt(k.ch < 0x20, src/predict.zig:334) — butsuppress()only counts the refusal. It does NOT flush the queue and doesNOT drop
confident. So confidence earned while typing in insert modestill stands after ESC.
bis printable, so it IS predicted at the cursor, and displayedbecause the overlay is still confident.
band moves the cursor; the predicted cellnever changes to
b. Under the "not yet is not wrong" rule(src/predict.zig:17) the prediction is not refuted — it stays pending
until
expire_after_frames(8) orexpire_after_ms(1000,src/predict.zig:152-156) fires.
If that is what is happening, the delay is the designed 1s bound, and the
real bug is a policy one (a mode-changing key should cost confidence, or
demote). The point of this issue is that TODAY WE CANNOT TELL.
The ask
An opt-in mechanism that captures a profile when prediction delay spikes.
Sketch, not a decision:
madeand its verdict). Crossing it arms one capture.made_seqvs the applied seq, the verdict that ended it (confirmed /contradicted / expired), and the overlay's policy state at the time
(
ctx,confident,streak) — the last three are what separate thehypothesis above from a genuine stall.
ingress -> pty write -> pty read -> engine feed -> delta egress. Local
means a unix socket, so any multi-hundred-ms gap is a stall inside a
process, not on the wire.
continuous trace. Write it somewhere findable — the daemon log, or under
$XDG_STATE_HOME/mux/.Trap for whoever picks this up
The record MUST stamp the build mode.
zig buildis Debug and Debug buildsghostty with its page-integrity check on — ~600x on output-heavy work
(CLAUDE.md, and mux-debug-builds-are-600x-slow). A profile captured in
the dev tree that does not say so will indict the wrong code.
Migrated from git-collab issue
86159ab08389b6b9f449881dc5160c07fceac7dc.Original author: a73x dev@a73x.sh.
[claude 2026-08-23] Repro correction from the operator: it is not vim. It is
the Claude Code input box WITH VIM MODE ENABLED — a TUI that repaints its own
frame per keystroke. The keystroke mechanism is the same (normal-mode
b,w,jare non-echoing printable bytes, predicted and displayed onconfidence earned in insert mode, retired only at expire_after_ms), but the
cost is worse: the delta for one keystroke is already a frame-sized repaint
from the TUI, and a contradiction adds
renderClippedover the wholeviewport on top of it (src/interact.zig:1691).
Also reported: typing RAPIDLY into that box stalls. Candidate that is not a
latency spike at all —
offerPredictionrefuses any chunk wherechunk.len != 1(src/interact.zig:961). Fast typing coalesces at the tty, soa burst arrives as one multi-byte read and gets zero prediction. The faster
you type, the less prediction you get.
Control not yet run: does the same rapid typing stall in Claude Code OUTSIDE
mux? If it does, prediction is a red herring and the profile should be
pointed at the TUI's own render cost.
[claude 2026-08-23] First increment landed on branch worktree-predict-local-gate
(
aac3c2d): the overlay measures its own keystroke-to-confirm round trip andhides predictions below 20ms srtt (shows again above 30ms; mosh's pair). On a
local socket nothing underlined is ever painted, so the "bbb" cannot occur.
Predictions stay queued and judged while hidden, and the stats line has a
new
local=counter. make check + full e2e green; installed to ~/.local/binfor the operator's hands-on.
Still open from this thread, deliberately deferred: the full-screen repaint
on expiry fires even when nothing was painted (per-cell rollback, item 3),
ESC-demotes-confidence, coalesced bursts get zero prediction, and the
profile capture this issue is actually about.