Session:11:27
(lockloop re-investigation + thinking-loop-guard pi extension)
Full-corpus re-investigation (all 2,165 sessions,
superseding the 10-17 four-session sample): 19 pure-lock
thinking loops, all z-ai/glm-5.3-flash (openrouter), 0/359
deepseek, 0/189 gpt-5.4 — rate 0.028% of 67,505 glm thinking turns.
Every loop starts on the first token of thinking right after a
toolResult; nothing dangling in context (prefix never ends in
"lock"-like fragment). By day: 9-20 ×2, 10-17 ×12
across 5 projects in 2.5h (provider incident window, not content), 10-18
×1, 10-19 ×4.
Cost quantified: ~879k reasoning tokens ≈
$0.44 total. lock = exactly 4 chars/token
(verified against the one recorded error loop: 283,854
tokens ↔︎ 1,135,416 chars). Only $0.14 was
recorded — pi logs `usage: 0` on aborted streams, so ~$0.30
burned invisibly. Real damage was the 1.5 MB/378k-token monster (10-18
02:38) + retry-relock chain (phorma re-locked 5× — aborted garbage
thinking stays in context).
Built thinking-loop-guard pi extension
(~/.pi/agent/extensions/thinking-loop-guard/, auto-loads):
(1) message_update stream guard aborts within ~10–13 tokens
on a repetition suffix (thresholds: 40 chars for 4–8 char units, 48 for
2–3, 64 for single; -=_~/whitespace units exempt); (2)
message_end sanitizer replaces degenerate thinking with a
text note before persistence — kills the retry-relock
chain; (3) /loopguard toggle + hits. TDD: 13
tests green
(node --test ~/.pi/agent/extensions/thinking-loop-guard/),
plus mock-pi simulation proving abort at 48 loop chars and sanitizer on
a 1.6 MB aborted message.
Key pi extension APIs used:
message_update (token-by-token, ctx.abort()),
message_end replacement lands before session persistence
incl. aborted messages, pi.appendEntry for hit
logging.
Durable knowledge routed to global whisper rules
(turu append global, id a5c4d6b4…).
Next: watch for loop hits via
/loopguard hits; if glm-5.3-flash still degenerates at
medium thinking, consider switching default model or reporting to
openrouter/z-ai.