You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
./ds4_test --think-tool-recovery fails on current main (b7e9f00). The
recovery mechanism itself still works: detection triggers exactly when the
stanza opening completes (trigger=22/23), and the forced close
("</think>", two tokens) is injected and eval'd into the session. But the
FIRST sampled token after injection is EOS, so the test's final phase —
"verifies the live model then emits a valid, parseable call" (per 91bafb5) —
fails:
91bafb5 introduced this on the measurement that "that position predicts a
fresh stanza opening strongly enough that the call restarts cleanly". That
no longer holds for either official Flash GGUF.
(Formatting note: the think open/close and DSML markers in this issue are
written inside quoted/code spans so chat clients that treat them as control
tags render this cleanly.)
Environment
M5 Max 128 GB, Metal backend
Models: official antirez/deepseek-v4-gguf releases, sha256-verified
against HF LFS oids:
DeepSeek-V4-Flash-Layers37-42Q4KExperts-OtherExpertLayersIQ2XXSGateUp-Q2KDown-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-fixed.gguf
(undated; oid edabc92a…)
Failure signature is identical in every failing cell: recovery triggers,
injection succeeds, then immediate EOS.
Interpretation — two independent effects
Checkpoint effect: the July-31 weights EOS at the injection point even on
the OLD engine (54b36ed row: undated passes, -0731 fails). Related: DeepSeek-V4-Flash-0731 support #635.
Engine effect: commits in 54b36ed..b7e9f00 shift the older (undated)
weights into the same EOS behavior (undated column: pass → fail).
Bisectable using the undated GGUF between those two refs.
Related observations
DS4_TEST_RECOVERY_PROBE=1 shows the model's NATURAL turn now closes "</think>" before emitting the tool call (well-formed list_files stanza).
The pathological scenario the recovery targets — stanza opening inside an
unclosed "<think>" block — no longer arises naturally, so the recovery
rarely fires; but when it does (or when the test's force-fed prefix is
replayed), the continuation is EOS instead of a restarted call.
91bafb5 notes re-emitting the stanza opening was rejected because "the
duplicated opening reads as an already-made call and the model ends the
turn" — the model now ends the turn even without the duplicated opening.
Fork-side mitigations (context from a downstream fork)
Our fork (nazerim/ds4) hardens the recovery's AFTERMATH; all of it passes on
the merged tree and is independent of this regression:
KV-cache consistency: recovery's injected close used to diverge from the
canonical form the next request renders, causing token-mismatch disk-KV
misses and full-prefill rebuilds. A recovery-fired flag now forces
checkpoint canonicalization at turn end (in-place rewrite anchored at the
longest common prefix; disk prefix-anchor fallback for oversized tails).
Streaming consistency: THINKING-mode streams hold back DSML markers so
streamed reasoning matches the canonical KV suffix.
Detection hardening: scan-from off-by-one fix, 8-byte hold string, plus
two regression tests (prose-marker immunity, spurious-then-legitimate
stanzas) — all green on current main.
So detection/injection/state-consistency are sound; only the live-model
continuation assumption regressed.
Repro
make ds4_test
./ds4_test --think-tool-recovery # with either official GGUF
DS4_TEST_RECOVERY_PROBE=1 ./ds4_test --think-tool-recovery # natural turn
./ds4_test --think-tool-recoveryfails on current main (b7e9f00). Therecovery mechanism itself still works: detection triggers exactly when the
stanza opening completes (
trigger=22/23), and the forced close(
"</think>", two tokens) is injected and eval'd into the session. But theFIRST sampled token after injection is EOS, so the test's final phase —
"verifies the live model then emits a valid, parseable call" (per 91bafb5) —
fails:
91bafb5 introduced this on the measurement that "that position predicts a
fresh stanza opening strongly enough that the call restarts cleanly". That
no longer holds for either official Flash GGUF.
(Formatting note: the think open/close and DSML markers in this issue are
written inside quoted/code spans so chat clients that treat them as control
tags render this cleanly.)
Environment
against HF LFS oids:
DeepSeek-V4-Flash-Layers37-42Q4KExperts-OtherExpertLayersIQ2XXSGateUp-Q2KDown-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-fixed.gguf(undated; oid edabc92a…)
-0731suffix (oid 659e22fb…)Matrix (all cells run on this hardware)
Failure signature is identical in every failing cell: recovery triggers,
injection succeeds, then immediate EOS.
Interpretation — two independent effects
the OLD engine (54b36ed row: undated passes, -0731 fails). Related: DeepSeek-V4-Flash-0731 support #635.
54b36ed..b7e9f00shift the older (undated)weights into the same EOS behavior (undated column: pass → fail).
Bisectable using the undated GGUF between those two refs.
Related observations
DS4_TEST_RECOVERY_PROBE=1shows the model's NATURAL turn now closes"</think>"before emitting the tool call (well-formedlist_filesstanza).The pathological scenario the recovery targets — stanza opening inside an
unclosed
"<think>"block — no longer arises naturally, so the recoveryrarely fires; but when it does (or when the test's force-fed prefix is
replayed), the continuation is EOS instead of a restarted call.
duplicated opening reads as an already-made call and the model ends the
turn" — the model now ends the turn even without the duplicated opening.
limit with the call dropped at parse, the turn ends short with no tool
call (retryable by the agent loop). Agent sessions relying on recovery for
the pathological case get a dropped call rather than a recovered one.
"pre-existing flaky … flip[ping] between runs" on CUDA/GB10, suggesting
the continuation phase is borderline on other hardware too.
Fork-side mitigations (context from a downstream fork)
Our fork (nazerim/ds4) hardens the recovery's AFTERMATH; all of it passes on
the merged tree and is independent of this regression:
canonical form the next request renders, causing token-mismatch disk-KV
misses and full-prefill rebuilds. A recovery-fired flag now forces
checkpoint canonicalization at turn end (in-place rewrite anchored at the
longest common prefix; disk prefix-anchor fallback for oversized tails).
streamed reasoning matches the canonical KV suffix.
two regression tests (prose-marker immunity, spurious-then-legitimate
stanzas) — all green on current main.
So detection/injection/state-consistency are sound; only the live-model
continuation assumption regressed.
Repro
Happy to help bisect the engine effect if useful.