From 7ea271596240e99219a5f635623113f44227287d Mon Sep 17 00:00:00 2001 From: hermes-pimentel Date: Tue, 29 Sep 2026 20:32:01 -0300 Subject: [PATCH 1/2] qwen3_5: do not salvage an aborted prefill under MTP The Prefilling branch of salvage_continuation checked the DFlash context but not the MTP state, so the next request of the conversation planned a PrivateEndpoint reuse its MTP head could not materialize and failed with HTTP 500 "published MTP checkpoint is not materializable" on every retry. --- src/models/qwen3_5/program/transactions/commit.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/models/qwen3_5/program/transactions/commit.cpp b/src/models/qwen3_5/program/transactions/commit.cpp index 0104a6993c..72629cb2e2 100644 --- a/src/models/qwen3_5/program/transactions/commit.cpp +++ b/src/models/qwen3_5/program/transactions/commit.cpp @@ -732,6 +732,9 @@ bool ProgramImpl::salvage_continuation(SequenceState& state, RequestControl& req state.dflash_context_frontier < frontier) { return false; } + // An aborted prefill leaves the MTP head's KV and tail hidden state behind the cursor; the next + // request of the conversation could not materialize such an endpoint. + if (speculative_backend == SpeculativeBackend::Mtp) { return false; } } else if (lifecycle == Lifecycle::Active || lifecycle == Lifecycle::Finishable) { frontier = state.execution_frontier; if (frontier < kSalvageMinFrontier || state.text_kv_valid != frontier) { return false; } From 064ca4241b19117f6713ae62dfc203ec0ac62504 Mon Sep 17 00:00:00 2001 From: Valeriy Selitskiy <239034+iamwavecut@users.noreply.github.com> Date: Sat, 3 Oct 2026 15:46:53 +0200 Subject: [PATCH 2/2] qwen3_5: refuse an MTP salvage exactly when the planner cannot reuse it Mirror request_plan.cpp's PrivateEndpoint condition (tail hidden state, MTP KV up to frontier - 1) instead of refusing every salvaged prefill under MTP. A prefill cut before its last chunk has no tail hidden state and is refused as before; an endpoint that carries both stays publishable. --- src/models/qwen3_5/program/transactions/commit.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/models/qwen3_5/program/transactions/commit.cpp b/src/models/qwen3_5/program/transactions/commit.cpp index 72629cb2e2..566cf7c12d 100644 --- a/src/models/qwen3_5/program/transactions/commit.cpp +++ b/src/models/qwen3_5/program/transactions/commit.cpp @@ -732,9 +732,13 @@ bool ProgramImpl::salvage_continuation(SequenceState& state, RequestControl& req state.dflash_context_frontier < frontier) { return false; } - // An aborted prefill leaves the MTP head's KV and tail hidden state behind the cursor; the next - // request of the conversation could not materialize such an endpoint. - if (speculative_backend == SpeculativeBackend::Mtp) { return false; } + // The next request reuses this endpoint under MTP only with the tail hidden state and the + // MTP KV up to frontier - 1 (request_plan.cpp). A prefill cut before its last chunk has no + // tail hidden state, so the conversation resumes from its last captured checkpoint. + if (speculative_backend == SpeculativeBackend::Mtp && + (!state.tail_hidden_valid || state.mtp_kv_valid + 1 < frontier)) { + return false; + } } else if (lifecycle == Lifecycle::Active || lifecycle == Lifecycle::Finishable) { frontier = state.execution_frontier; if (frontier < kSalvageMinFrontier || state.text_kv_valid != frontier) { return false; }