Skip to content

prefill: refuse mid-chunk tail capture on aux-carrying models (Flash-Next warm path never engaged on Windows) - #157

Closed
AzeezIsh wants to merge 1 commit into
mainfrom
fix/fnext-midchunk-aux
Closed

AzeezIsh wants to merge 1 commit into
mainfrom
fix/fnext-midchunk-aux

Conversation

@AzeezIsh

@AzeezIsh AzeezIsh commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Bug

On gfx1151 builds (atlas_scale), Qwen3.8-Flash-Next's prefix-cache warm path never engages. Every warm turn logs Prefix cache hit: N tokens (… blocks) but no SSM snapshot — recomputing all KV and recomputes the whole prompt. On the #149 Windows replay, TTFT came out within 5–10% of the no-cache #80 leg (Devin's measurement and diagnosis, war room 12:30Z).

Root cause (from the #149 serve log, turn 1 → turn 2)

Intermediate SSM checkpoint saved at token 2320 (snapshot_id 0, block 145)   <- tail-split ckpt at tb-bs, CARRIES aux
midchunk tail SSM capture at token 2336 (snap 1)                              <- aux-less
midchunk EARLY tail SSM capture at token 2320 (snap 2)                        <- aux-less, SAME prefix key as snap 0 -> displaces + frees it
Saved SSM snapshot 0 for 2339 tokens [chunk]                                  <- id 0 reused on turn 1 with 9 free slots
...
Prefix cache hit: 2336 tokens (146 blocks) but no SSM snapshot — recomputing all KV
  1. Flash-Next is aux-carrying. Its PLE n-gram history and QSA indexer keys are position-exact only at a completed pass end. So the mid-chunk capture (tb, tb-bs) is necessarily aux-less, and the restore gate declines aux-less slots (prefix_lookup.rs: "decline aux-less slots — e.g. mid-chunk tail captures").
  2. The tb-bs sibling overwrites the good anchor. It's registered under the same prefix key as prefill_b_save_checkpoint's tail-split checkpoint, which does carry aux and is eligible for both match points. insert_tail_sibling displaces that checkpoint and the caller frees it.
  3. Net: no eligible snapshot at or below the next turn's match, on every turn.

Why GB10 (#69) never saw this: mid-chunk capture only runs on atlas_scale builds, so GB10 always used the tail-split anchor.

Fix

prepare_midchunk_capture returns None when requires_aux_state(). The tail-split checkpoint at tb-bs then survives and serves both tb and tb-bs matches, the same path GB10 takes. Models without aux state, including the 27B, are unaffected: the gate is false for them and their mid-chunk capture is unchanged.

Checks

Unblocks #149.

🤖 Generated with Claude Code

Qwen3.8-Flash-Next carries per-sequence aux state (PLE n-gram history,
QSA indexer keys), which is position-exact only at a completed pass end.
The mid-chunk capture is therefore aux-less, and the restore gate
declines aux-less slots. Its tb-bs sibling is also indexed under the same
prefix key as prefill_b_save_checkpoint's tail-split checkpoint, which
does carry aux, so registering the sibling displaced and freed the only
anchor the next turn could restore. Every warm turn recomputed the whole
prompt: winbox #149 replay, 2026-10-02, logs 'Prefix cache hit: N tokens
... but no SSM snapshot' on every turn and TTFT within 5-10% of no-cache.

Refusing the plan leaves the tail-split checkpoint at tb-bs as the anchor
for both match points, the same path non-atlas_scale builds (GB10, #69)
already take.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AzeezIsh

AzeezIsh commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Note from #158: restoring a warm SSM snapshot reuses the KV for [snapshot, matched) from the earlier request instead of recomputing it, and on GB10 that produced a wrong tool-call answer. Windows never restored before this PR, so merging #157 alone would switch that path on for gfx1151. #157 is correct as a fix for the aux displacement, but it should land with (or behind) the #158 fix and a caching-on vs caching-off equality check. Keeping it draft until then.

@AzeezIsh

AzeezIsh commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Status (2026-10-06): blocked on #163. The fix is correct; landing it alone is unsafe.

What it fixes: on gfx1151 builds, an aux-less mid-chunk snapshot displaces the aux-carrying tail-split anchor. Flash-Next's warm path therefore never restores.

Fresh evidence that it's still needed: winbox p7R (2026-10-05, HIP prefill-train tree P4, prefix caching on, 9 slots at interval 2048) logged 1006 prefix-cache hits, 0 Marconi SSM hits and 1006 "no SSM snapshot" lines. Every warm turn recomputed the full prompt. The replay itself was clean (1007/1007, 0 faults, score 0.5127), so the cache is on but does nothing on Windows until this lands.

Why it waits: turning on warm restores on gfx1151 exposes #158, where caching on changes temperature-0 output. That gave a wrong tool round trip on GB10. #163 is the #158 fix.

To unblock:

  1. prefix cache: caching on = caching off at temperature 0 on SSM-hybrid models (fixes #158) #163 merges. It needs Devin's reiner 709 (battery on 93025338) and the cache-on slowdown understood (701: 4870–5394 s vs 4201 s with caching off).
  2. Rebase this PR on main + prefix cache: caching on = caching off at temperature 0 on SSM-hybrid models (fixes #158) #163.
  3. Winbox gate:

Owner: Claude (rebase + gate); the #163 dependency is Devin's.

@AzeezIsh

AzeezIsh commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

FYI for re-validating this on Windows: winbox was memory-starved until today. The BIOS carve-out was 32 GB, and every Flash-Next serve since 10-06 23:59 died mid-load. It's now 96 GB dedicated (107.9 GB HIP-visible), so the #149 + #157 warm-path replay can run with real Marconi slot headroom. Re-measure the commit ceiling first. Details: #144 (comment)

@github-actions github-actions Bot added the needs-rebase Conflicts with main — its green checks are NOT real (GitHub skips merge-commit workflows) label Oct 15, 2026
@AzeezIsh

Copy link
Copy Markdown
Contributor Author

Closing as landed: main has this refusal in an extended form (if self.requires_aux_state() || !midchunk_capture_writer_exists(..) in prefill_b/midchunk_capture.rs, via #174). Verified 2026-10-18 against b9a7edad8: the merge leaves no net diff; the only added line not found verbatim on main is the original one-condition if self.requires_aux_state() {, which main's two-condition guard replaces. Branch kept.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-rebase Conflicts with main — its green checks are NOT real (GitHub skips merge-commit workflows)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant