Repository navigation
Conversation
|
Empirical evidence (gfx1101, ROCm/HIP 7.15 container, Reproduced the trigger deterministically — any request whose budget dies inside the think span: This build's serve log, per failure: …followed by the cold reset; subsequent requests run a real generation rather than resuming the mid-turn session. Negative case verified: a gateway-side validation 400 (oversized explicit Note on reproduction scope: with this model/config the poisoned slot's retained state surfaces as a fast repeat |
d45e511 to
52b15e0
Compare
…E_UI) Port of feat/serve-chat-ui-v040 onto the 0.4.x beta line (the v040 branch is authored against master; serve/complete.rs, serve/mod.rs and serve/http.rs have since been refactored on beta, so the Rust hunks were re-applied against the beta shapes rather than rebased). What ships: - Zero-dependency chat frontend: five static assets embedded via include_str! (index/app/db/render/style), served by a new serve/ui.rs matcher that shares the listener and the existing /v1/chat/completions path. IndexedDB history, branching, markdown/highlighting, effort picker, live TTFT/tok-s strip, mobile layout, ember palette. - Enablement in precedence order: --ui, --open (implies --ui, launches the browser), serve.ui = true, HIPFIRE_SERVE_UI=1. Off is byte-for-byte the old behavior: / and /ui both 404. Non-loopback binds warn on stderr; detached children get --ui. - Security headers on every UI route: strict CSP (default-src 'none', frame-ancestors 'none', form-action 'none'), X-Frame-Options: DENY, nosniff, no-cache — the page is an unauthenticated control surface and is not frameable. - /health and /v1/models publish the resident model's reasoning contract and effort rungs (from meta.loaded — no runtime lock), and capabilities gains chat_ui. - Carries the two gateway fixes the UI surfaced: mid-generation daemon failures without attested rollback poison the session so the next request cold-resets (poisons_session_state), and completion_timings no longer reports wall tok/s as decode tok/s. (slots.rs unchanged: beta already clamps max_tokens_fit via hipfire_generate::common::fit_max_tokens_if.) Verified on gfx1101 against a fresh --ui --no-prewarm serve: / -> 302 /ui; /ui 200 with the full header set; all four assets 200 with correct content types; non-UI paths still 404; /health reports chat_ui: true and the reasoning fields. cargo test -p hipfire-cli 312/312; crate maps regenerated. (cherry picked from commit c12f810) # Conflicts: # crates/hipfire-cli/map.md # crates/hipfire-cli/src/serve/complete.rs # crates/hipfire-config/map.md # docs/env-vars.md [land/pr808: the poisons_session_state carry (#806) is not taken; the completion_timings carry is #807, which this branch already contains. docs/env-vars.md and docs/CONFIG.md regenerated with check-lifecycle.py --write.]
Review notes (gfx1151 / Strix Halo, ROCm 7.2)Recommendation: request-changes (reproduce on current beta first; narrow the classifier; drop unrelated hunks).
Agent-assisted review; head e5aba2a. Evidence: static read of the diff; local validation on gfx1151 follows in a separate comment where applicable. |
Re-scope after review (fivetide, 2026-10-08): the originally observed
trigger ("unsafe multi_slot terminal: open_think") is gone on current
beta — 325f31c made an unclosed <think> a reasoning-only stop with the
session closed at commit, and every post-admission error path in
slots.rs already closes the session before emitting. Mid-generation
failures that cannot attest a rollback still exist on beta (slots.rs
emits class=internal for a multi-slot engine death after produced
tokens, class=generation for unsafe terminals, class=gpu for vision
faults), so the gateway guard stays as defense-in-depth for daemon
regressions, with the classification corrected:
- Poison on any typed daemon error without an attested rollback EXCEPT
the pre-generation-by-wire-contract classes (validation, malformed,
context_length, unsupported, overload, cancel, transport). The old
deny-list exempted internal and transient — both can carry unattested
mid-generation state, so they now poison; internal is beta's
engine-death class and is not even a client error_class constant,
which is what made the deny-list unmaintainable.
- The poison flag is process-global by design (the gateway has no
per-conversation session key; the daemon owns slot lifecycle). The
follow-up reset is refused by the daemon while any multi-slot session
is active or queued, so under concurrency a poison costs the poisoned
request's own attempt plus one full reload — never a reset under a
live slot. Disclosed on the flag and at both use sites.
- A reset that cannot attest rollback now clears the resident model
whether it was forced by retry policy or by poison (previously forced
retries only) — same unknown-state situation, now stated.
Empirical verification on this host is wire-level, not GPU-level (no
ROCm runtime available): a fake-daemon HTTP test drives the real serve
lowering and asserts the wire log — an internal/rolled_back=false
failure is followed by exactly one reset before the next generate, and
a validation refusal by none.
hipfire-cli only; the unrelated isa/peacemaker/quantize/xdna hunks and
the daemon main.rs helper move from the old head are dropped (beta
639907c already landed equivalent skips).
Tests: cargo test -p hipfire-cli 345/345 (new: poison classifier table,
fake-daemon wire reset test); check-crate-maps.py --check green;
leanup-ratchets green.
e5aba2a to
307ce09
Compare
|
Closing: the triggering failure mode no longer exists on beta, verified empirically on the hardware class where it was found. gfx1101 / RX 7700 XT, ROCm 7.2.4 container, What the review surfaced that's still real (daemon-side, follow-up material): Thanks @fivetide — the "reproduce on current beta first" call was right. Clean head ( |
Validation on gfx1151 (Strix Halo, ROCm 7.2): the trigger does not reproduce on current betaBeta
So on beta the observed corruption needs a different trigger. The remaining Agent-assisted; beta 639907c; PR head e5aba2a not built (conflicts with beta). |
Summary
A daemon generation error that reports
rolled_back: falsepoisons the gateway's session flag, so the next request cold-resets instead of resuming a mid-turn slot session.Re-scope after review (fivetide, 2026-10-08): the originally observed trigger (
unsafe multi_slot terminal: open_think) is gone on current beta —325f31cc1made an unclosed<think>a reasoning-only stop with the session closed at commit, and every post-admission error path inslots.rsalready closes the session before emitting. Mid-generation failures that cannot attest a rollback still exist on beta (classinternalfor a multi-slot engine death after produced tokens, classgenerationfor unsafe terminals, classgpufor vision faults), so the guard stays as defense-in-depth for daemon regressions, with the classification corrected per review.Which surface(s) does this touch?
crates/hipfire-cli/src/serve(gateway)Changes
poisons_session_state): poison on any typed daemon error without an attested rollback EXCEPT the pre-generation-by-wire-contract classes (validation,malformed,context_length,unsupported,overload,cancel,transport), each mapped to its beta pre-generation sites in the comment. The old deny-list exemptedinternalandtransient; both can carry unattested mid-generation state and now poison.internalis beta's engine-death class and not even ahipfire_client::error_classconstant — that desync is exactly why the deny-list shape was wrong.clear_residenton failed reset is now unconditional (previously forced retries only) — undisclosed in the old head, now stated: an unattested reset leaves the same unknown-state situation either way.Test plan
cargo test -p hipfire-cli— 345/345, including the poison-classifier table test and a fake-daemon HTTP wire test that drives the real serve lowering and asserts the wire log: aninternal/rolled_back=falsefailure is followed by exactly oneresetbefore the nextgenerate; avalidationrefusal by none.scripts/check-crate-maps.py --checkgreen;scripts/leanup-ratchets.shgreen.Single commit on current beta,
hipfire-clionly. The unrelatedhipfire-isa/peacemaker-irtoolchain skips (beta639907cc3landed equivalents),quant_mqtest rewrite,hipfire-xdnaclippy allow, and the daemonmain.rshelper move from the old head are dropped — along with the merge conflicts they caused.