Repository navigation
release-check: a second, long-then-short NPU turn, because one short prompt cannot see #911 - #923
bong-water-water-bong wants to merge 2 commits into
Conversation
…prompt cannot see #911 The c17 board (3 Nov 13:22, engine #911) served the NPU chat row at 96.6 tok/s and then hung on the NEXT request: 0 chunks, lemond's "Backend did not send [DONE]", and an amdxdna TDR in the same second. The row that would have caught it did not exist - chat-npu is one non-streaming 48-token /no_think prompt, which cannot tell "the route works" from "the route works once". chat-npu-multiturn sends a long prompt (~70 words, the board's own repro) and then a short follow-up carrying the history, both streamed, thinking off. It counts DELTAS of content and reasoning_content, not the [DONE] marker: lemond appends [DONE] itself when the backend never sent one, so a row grepping for it would have passed this exact failure (measured in the board's lemond.log). A new aie2_legacy_tdr_detect line during the two turns fails the row even when chunks arrive, and a turn that hits the 240 s cap fails naming the cap. The decision is a pure function (npu_turns_verdict) so --self-test drives it - 7 new cases: both turns answer, the board's 0 chunks, a TDR with chunks, a turn-2 timeout, a silent first turn, a transport failure, an empty TDR count. Measured: ./rowproof-npu-multiturn.sh, four arms - a healthy stream PASS, the board's 200+[DONE]+no-deltas FAIL naming "0 chunks", a hung turn 2 FAIL naming the cap, and the REAL NPU through '1bit serve --device npu' PASS (turn 1 192 chunks, turn 2 15 chunks, no TDR). sh -n, busybox ash -n and release-check --self-test green. Refs #911 (this is the gate gap it named, not the fix).
PR Reviewer Guide 🔍(Review updated until commit 6e81045)Here are some key observations to aid the review process:
|
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: CHANGES at c69af2850 — the keyword item is fixed; the row still sends a request sequence the demo does not, and that is the shape that failed.
Fixed, and thank you for the explicit wording: Refs #911 — this closes the gate gap the issue names, not the defect itself (no closes), the title carries no closing keyword, and #911 is still OPEN. That half is closed.
Still open — the history assumption. The row's turn 2 carries the conversation:
os/mini/release-check.sh (this head, ~:663)
printf '{"model":"%s","messages":[{"role":"user","content":"%s"},{"role":"assistant","content":"%s"},{"role":"user","content":"In one short sentence: …"}]…but the page that produced #911 sends one user message and keeps nothing:
os/v3/puppy/embed/opt/1bit/webapp/index.html:122-126 (main)
fetch(api + "/api/v1/chat/completions", { …,
body: JSON.stringify({ model: m, messages: [{ role: "user", content: text }],
max_tokens: 512, temperature: 0, stream: true }) })ask() clears the input, appends to out.textContent for display, and has no localStorage/sessionStorage/history
array anywhere in the file (grep -n 'localStorage\|sessionStorage\|push(\|history\[' → nothing). And the failure text you
quote is that page's own status line — done: 0 chunks in 5.9 s is stat.textContent = "done: " + chunks + " chunks in …".
So the failing request was a fresh single-message request issued while the route still held the previous 512-token turn,
not a request that replayed the answer.
That difference is load-bearing, not cosmetic: with history, turn 2's prompt is ~192 tokens re-processed; without it, turn 2
is a ~15-token prompt against whatever state the first turn left in the runtime — which is exactly where your own root-cause
note points (ctx_size 32768 from the router versus the dx kernel set's 4096 cached tokens). A row that always sends the
long history cannot see the second shape, and the arm you ran on the device (turn 1 192 chunks, turn 2 15 chunks, no TDR)
is evidence about the history shape only. As written the row can be green while the demo still hangs — the same class as
#906, one level up.
Two asks:
- Turn 2 = the page's body:
messages: [{role:"user", content:"<short question>"}], no replayed assistant turn. If the
history variant is worth keeping, make it a second arm clearly labelled as not the page's shape — the gate row should
be the shape the demo will send. max_tokens: the page sends 512 for its turn; the row sends 192 (turn 1) and 96 (turn 2). If 192 is a deliberate
cost choice, say so in the comment next to it, because "the board's own repro" and the demo's own cap are 512.
Nothing else needs re-review on my side: the [DONE]-marker point is right and well argued (lemond appending it is why a
marker-grep row would have passed this exact failure), the TDR delta across the pair is the right instrument, an unreadable
dmesg is said out loud rather than counted clean, and the 7 npu_turns_verdict self-test cases cover the decision's
branches. #922 must not be merged — its title still carries closes #911, and this PR supersedes it.
|
Persistent review updated to latest commit 6e81045 |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
Superseded by #922, which is now READY and covers both shapes: its arm A is this PR's missing piece — a single-message, no-history follow-up, exactly what os/v3/puppy/embed/opt/1bit/webapp/index.html:122-126 sends — and its arm B is the history shape this row sends. Merge #922 and close this; both add a row to the same file, so merging both would duplicate the coverage and conflict on the hunks.
The head move (6e810455b) is a merge of main only; the row's request bodies are unchanged from c69af2850, so my CHANGES on it stands as written.
|
Superseded by #922 (merged 18:43Z, Keeping the two would mean two rows asserting the same thing with different wording on every stick, so this one goes. What is worth carrying over from it, and is in the #911 record either way:
|
Root cause (why a row is needed at all)
Engine #911, from the c17 board on 3 Nov 13:22 (engine
ca1d42f, package c21):chat-npupassed at 96.6 tok/s, then the next request on the same route hung — 0 chunks, lemond'sWARNING: Backend did not send [DONE] marker, andaie2_legacy_tdr_detect: TDR timeout detectedin the same second (boarddmesg.log/lemond.log, evidence in~/briefs/NPU-MULTITURN-TDR-2026-11-03.mdand~/briefs/RELEASE-C17-VERDICT.md).The gate could not see it:
chat-npuis one non-streaming, 48-token,/no_thinkprompt. One prompt cannot tell "the route works" from "the route works once".The change
os/mini/release-check.shonly — a new rowchat-npu-multiturn, run when the NPU and an NPU model are present:enable_thinking:false;contentandreasoning_content, not the[DONE]marker — lemond appends[DONE]itself when the backend never sent one, so a row grepping for[DONE]would have passed this exact failure (measured in the board's ownlemond.log);aie2_legacy_tdr_detectline during the two turns fails the row even when chunks arrive; a turn that reaches the 240 s cap fails naming the cap;npu_turns_verdict) so--self-testdrives it, likelemonade_verdict(os: prove the API key is enforced in 1bit-release-check, do not infer it #569);chat-npu(no/dev/accel/accel*, or no NPU entry listed), so a VM is unchanged.Measured (before / after)
~/wt/release-rc/rowproof-npu-multiturn.sh— extracts the block verbatim and drives four arms:200+[DONE], zero deltas1bit serve -m ~/models/npu/Qwen3-0.6B --device npu, undernpu-holdsh -n,busybox ash -nandos/mini/release-check.sh --self-test(7 new cases: both turns answer / 0 chunks / TDR with chunks / turn-2 timeout / silent turn 1 / transport failure / empty TDR count) are green;tools/copyright.py --checkrc 0.Notes for the fixer of #911
On this box the direct route answered both turns (
192+15chunks, no TDR), so the hang is not simply "any second request". The board's router log has the difference in two adjacent lines, both from the same load:i.e. lemond allocated 8x the context the dx kernel set says it serves. Worth testing
--ctx-size 4096(or a cap in the router) on the board repro. This row goes through the lemond API, so it will exercise whatever the router decides.Refs #911 — this closes the gate gap the issue names, not the defect itself (no
closes).