Skip to content

catalog: add Qwen3.8-Flash-Next, and stamp its renderer on pull (#1192) - #1259

Merged
gen16k merged 1 commit into
mainfrom
feat/1192-flash-next-catalog
Sep 6, 2026
Merged

gen16k merged 1 commit into
mainfrom
feat/1192-flash-next-catalog

Conversation

@gen16k

@gen16k gen16k commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

What lands

qwen3.8-flash-next — 180B on disk, 6B active, 262,144 native context, one ollama-tag
variant at UD-Q2_K_XL. The entry the pin move in #1235 existed for.

Measured end to end on sv-evox2 (Ryzen AI Max+ 395, 127 GB unified) against the pinned
0.33.3, probe stamped 3bf816378e7c: agent-harness grade pass over 12 trials, and all
six request shapes accepted
.

Why the tag alone was not enough

The tag as published accepts only three of the six. Its config carries no renderer, so ollama
renders prompts with the GGUF's embedded Jinja, whose line 110 is
raise_exception('System message must be at the beginning.') — and that is exactly
trailing-system, system-after-tool-roundtrip and developer-turn, the shapes a coding
agent sends.

I read the config blob of all 24 GGUF tags carrying this model, across six namespaces.
Not one declares a renderer. Every safetensors/MLX tag does. That is the packaging route, not
a publisher's oversight: ollama's convert path stamps the field and its GGUF create path does
not, so the next large community quantization lands in the same hole.

So the manifest names the renderer and the pull path stamps it onto the local copy.

tag as pulled after Puller.Stamp
renderer '' qwen3.8
parser '' qwen3.5
layers projector, model, license, params identical four
disk — 0.00 GB

ollama create on the same tag name reports using existing layer for every blob, so the
projector and the license layer survive and every identifier downstream stays what it was.
Only the small config object is rewritten. With it:

shape as pulled stamped
trailing-system rejected 500 accepted 200
system-after-tool-roundtrip rejected 500 accepted 200
developer-turn rejected 500 accepted 200

This is what ollama does for this model itself — its own library tag declares
renderer: qwen3.8 / parser: qwen3.5, and that renderer ships in the pin.
normalizeQwen38Messages (model/renderers/qwen35.go:136) folds every system and developer
turn into one leading system turn, the same operation the gateway does, with no branch inside
it that can refuse a shape. No engine bump was needed: v0.34.0-rc1 registers exactly the
same renderers as 0.33.3.

Decision 20260828/1930 is untouched. A model that cannot render the shapes a coding agent
sends is still one this project does not offer. This one renders them, so the gate is passed,
not exempted. My earlier suggestion that the decision might need revisiting is withdrawn.

The stamp does not survive a re-pull, so it lives inside Pull

Worth reading even if you skim the rest, because it changed the shape of the code. Measured on
the machine:

before re-pull   renderer='qwen3.8' parser='qwen3.5'
re-pull took 2s, disk delta 0.00 GB
after re-pull    renderer=''        parser=''
after re-stamp   renderer='qwen3.8' parser='qwen3.5'

ollama pull on a tag that is already present moves no weights and takes two seconds — and
rewrites the local manifest back to the published config, clearing the renderer. It is cheap
enough to happen on any update check, and the cleared state is not "unimproved": it is a model
that 500s on three of the six shapes while the store records them as accepted.

So stamping is not a public method a caller remembers to invoke after pulling. It is the tail
of Pull(ctx, tag, want, onProgress) and cannot be separated from it. A failed pull stamps
nothing; a repeated pull re-stamps. Both are tested.

The 122B drops to manual_only

Same generation swap as #823. The replacement is lighter on the same hosts — 55.1 GB resident
against 81.0 — and graded on real hardware rather than inherited. The 122B stays listed,
resolvable, pullable and servable; a host already holding those weights carries on unchanged.

Two things this surfaced that are worth reading

VariantSHA cannot carry the renderer. Its payload is frozen — widening it makes every
persisted measurement on every host stop matching at once — so a stamped and an unstamped
variant hash alike, and a manifest that quietly drops its renderer would leave the old "all six
accepted" record looking valid. The shapes store therefore records the renderer a measurement
was taken under and compares it against the manifest, next to engine_version, which is there
for the same reason. Caveat stated in the code: recording the manifest's value at import binds
the record to the manifest, so it catches a later edit, not a run measured before the stamp —
that needs the probe to report what it used, which it does not yet.

Two hostfit tests asserted on capacity-plus-roofline where they meant the recommendation
gate.
They agreed for every catalog we had shipped, so nothing separated them. A 180B-A6B
entry does: 55 GB of weights against a 24 GB card, but only 6B read per token, so the roofline
is happy and the old rule reaches for it. The product default does not move — measured,
not assumed:

waired#942 host (big RAM, 24 GB card)     RTX 5080 16 GB
  bestByTier      = qwen3.8-flash-next      qwen3.8-flash-next
  bestRecommended = qwen3.6-35b-a3b         qwen3.5-9b     <- unchanged
  flash-next: Recommend=false reason="weights_spill"

Both tests now assert both sides, so the ladder cannot silently do the gate's job again.

Also here

  • Quant ladder gains Q2_K, Q3_K_M, UD-Q2_K_XL. The UD row's bpw is measured (78.87 GB
    over 180e9 params), not modelled — dynamic quants have no a-priori table value, and folding
    one onto plain Q2_K under-estimates its weights by a quarter.
  • New host class amd-unified-128gb: the only shape in the fleet with the addressable memory
    to hold these weights without spilling, and a spilling host grades itself, not the model.
  • The catalog: a source that exists is not a source ollama can render (#1238) #1240 sources guard accepts a manifest-supplied renderer. It was written when the only
    fix was a different tag; that is no longer true, and it now says which of the two is missing.
  • catalog-radar's licence rule said the catalog carries only Apache-2.0 and MIT. It now carries
    one Qwen Community License 1.0 entry, so the rule says what it is — the bar for what the
    radar may propose, not a precedent. The reasoning is recorded on the private side
    (waired-ai/waired#1325), per the workspace placement rule; nothing user-facing mentions it.
  • Knowledge note 20260906/0400 gets a 補足: its "waiting on one upstream field" conclusion was
    wrong, and the correction is recorded rather than the note edited.

kv_bytes_per_token_fp16 is the derivable 24576, and waired-agent#1255 carries why that is
incomplete: the engine allocates a second, asymmetric KV cache the derivation has no term for,
so real KV is 33792 B/token and a budget built on the annotation under-counts by 38%. Not
fixed here — that is a scoring change touching every hybrid model, and this model is the
evidence, not the scope.

Verification

go run ./cmd/catalog-tool validate --all
go run ./cmd/catalog-tool agentgrade --check --require-pass
go run ./cmd/catalog-tool shapes --check --require-accepted
make catalog-docs && go run ./cmd/catalog-tool docs --check
go test ./... ./scripts/... -count=1          # and ./proto/... in its own module
go test -tags integration -count=1 ./internal/catalog/...
cd docs-site && npm run i18n:check

All green locally, including the catalog-sources integration leg against the live registry.

Evidence: ~/verify-20260906-l100/evox2/ — grade-stamped.json, grade-stamped.log, plus the
pre-stamp grade-unary.json for the before/after.

Fixes #1192
Refs waired-ai/waired#1312

🤖 Generated with Claude Code

https://claude.ai/code/session_0167iiPnKQz1qcuz2bhNBGep

The entry the pin move in #1235 existed for. Measured end to end on
sv-evox2 (Ryzen AI Max+ 395, 127 GB unified) against the pinned 0.33.3:
12 trials of the agent-harness grade pass, and all six request shapes are
accepted.

The tag as published accepts only three of those six. Its config carries
no renderer, so ollama renders prompts with the GGUF's embedded Jinja,
which raises "System message must be at the beginning." on the three
shapes a coding agent actually sends. Reading the config blob of all 24
GGUF tags carrying this model, across six namespaces, not one declares a
renderer — the safetensors convert path stamps it automatically and the
GGUF create path does not, so this is a property of the packaging route
rather than one publisher's oversight.

The manifest therefore names the renderer and the pull path stamps it
onto the local copy. `ollama create` on the same tag reuses every layer,
so it costs 0.00 GB and keeps the projector and the license blob; only
the small config object is rewritten, and every identifier downstream
stays what it was. With it, the three refused shapes answer 200 with
nothing else changed.

This is what ollama does for the same model: its own library tag declares
renderer qwen3.8 / parser qwen3.5, and that renderer ships in the pin —
normalizeQwen38Messages folds every system and developer turn into one
leading system turn, the same operation the gateway does, with no branch
inside it that can refuse a shape. No engine bump was needed; v0.34.0-rc1
registers exactly the same renderers as 0.33.3.

Decision 20260828/1930 is untouched. A model that cannot render the
shapes a coding agent sends is still one this project does not offer;
this one renders them, so the gate is passed rather than exempted.

Also here:

- qwen3.5-122b-a10b drops to manual_only. Same generation swap as #823:
  the replacement is lighter on the same hosts (55.1 GB resident against
  81.0) and graded on real hardware rather than inherited.
- The shapes store records the renderer a measurement was taken under and
  compares it against the manifest, because VariantSHA cannot: that
  payload is frozen, so a manifest that quietly drops its renderer keeps
  the same SHA and the old record would go on claiming shapes the engine
  would now refuse.
- The sources guard from #1240 accepts a manifest-supplied renderer. It
  was written when the only fix was a different tag; that is no longer
  true, and it now says which of the two is missing.
- The quant ladder gains Q2_K, Q3_K_M and UD-Q2_K_XL. The UD row's bpw is
  measured, not modelled — dynamic quants have no a-priori table value,
  and folding one onto plain Q2_K under-estimates its weights by a
  quarter.
- Two hostfit tests asserted on capacity-plus-roofline where they meant
  the recommendation gate. A 180B-A6B entry separates the two for the
  first time — 55 GB of weights against a 24 GB card, but only 6B read
  per token — so they now assert both sides. The default on those hosts
  does not move; `weights_spill` still holds it.
- catalog-radar's licence rule said the catalog carries only Apache-2.0
  and MIT. It now carries one Qwen Community License 1.0 entry, so the
  rule says what it actually is: the bar for what the radar may propose,
  not a precedent to follow.

waired-agent#1255 carries the KV modelling gap this measurement found:
the engine allocates a second, asymmetric KV cache the derivation has no
term for, so the annotation under-counts real KV by 38%.

Fixes #1192
Refs waired-ai/waired#1312

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167iiPnKQz1qcuz2bhNBGep
Signed-off-by: gen16k <gen16k@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 6, 2026 •

Copy link
Copy Markdown

📘 Docs preview — the preview channel for this PR has been deleted now that it is closed.

@gen16k
gen16k merged commit 4b004fa into main Sep 6, 2026
35 checks passed
gen16k added a commit that referenced this pull request Sep 6, 2026
…ents stop contradicting the file they are in (#1261)

The Strix Halo arms rest on upstream facts that move without notice, and
#1250 wrote the recheck list for them. Three things it did not cover.

ggml-org/llama.cpp#27856 (open, checked 2026-09-06) has qwen4exp — the
architecture behind the Flash-Next entry #1259 just shipped — collapsing
3.5-4x in decode once context passes ~1k on HIP/gfx1151, plateauing at
5.5-6.1 tok/s where CUDA decays only mildly. It moves with the VENDORED
LLAMA.CPP version rather than with ollama's release or its ROCm overlay,
so it is on a different recheck axis from the four ollama threads already
listed and ollama's release notes will never mention it.

It also lands on the arm nobody was watching. The Windows arm already
names Vulkan, so it never reaches HIP; the LINUX arm prefers ROCm, and
the #290 probe cannot see this failure — it falls back only on positive
evidence of CPU residency (size_vram == 0), and a model that is on the
GPU but 4x slow at depth is not that. Conservative by design, but the
failure shape is outside the arm. No Linux Strix Halo is in the fleet, so
this is an upstream report, not an observation here; the note says so.

Two stale comments in the same file, both left by #1247 correcting one
copy of a figure and not the other:

  - BackendROCm's doc calls the Windows ROCm overlay ~350 MiB. WantsROCm,
    sixty lines below it, already carries the measured 247 MB at 0.33.3,
    as does the knowledge note.
  - The backend table test names its case "vulkan only (no ROCm on Win
    APU)". The arm it pins says the opposite in as many words — "Vulkan,
    because it is FASTER here — not because ROCm is absent" — because
    ROCm does engage gfx1151 under Windows. The assertion was right; the
    name was the last copy of the claim #1233 disproved.

No behaviour change: comments, one test case name, and a knowledge-note
section.

Refs #1233
Refs #1247
Refs #1255

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167iiPnKQz1qcuz2bhNBGep
Signed-off-by: gen16k <gen16k@users.noreply.github.com>
gen16k added a commit that referenced this pull request Sep 6, 2026
… every page in both languages (#1264)

Restructures docs.waired.ai around the order a person actually meets Waired, and rewrites every page from zero in both languages against a saved corpus of human-written documentation (Tailscale and Discord for English; LINE Developers, SmartHR, and the JTF style guide for Japanese). Owner request of 2026-09-06.

## Structure

- 32 page pairs become 56, in eight sidebar groups that follow the journey: Get started → Install and set up → Use it from your tools → Models and routing → The Waired app and console → Fix a problem → How it works → Reference. Every group and item has a Japanese sidebar label (the ja sidebar was all English before).
- The four longest pages are split so a reader lands on the thing they came for: first-run becomes Sign in / Set up in the browser / Set up in the terminal / Servers and auth keys / Run setup again; troubleshooting becomes a hub plus six symptom pages; the CLI reference becomes a hub plus five command-group pages; the Claude Code guide gains How turns are routed / Subagents / The status line.
- New pages for things that had none: Meet the Waired app, How Waired chooses a model, Choose which computer answers (routing), Share this computer, Notices, The Status… report.
- URLs the product prints are unchanged (`/quickstart/`, `/public-share/`, `/reference/cli/`, `/reference/model-catalog/`, `/reference/install-options/`). Moved pages get 301s in both `astro.config.mjs` and `firebase.json`: `/getting-started/first-run/` → `/getting-started/sign-in/`, `/guides/models/` → `/guides/choose-a-model/`, `/guides/public-share/` → `/public-share/`, and their `/ja/` twins. The first two of those were already 404s on the live site.
- The `what-is-waired` figure is now HTML and CSS instead of an SVG, so it follows the site theme and is readable in both languages.

## Prose

- English: one voice (Tailscale's), the reader is "you", UI actions are *select* / *press* / *run*, UI labels are `**bold**`, product output is quoted verbatim, no dash chains or parentheticals.
- Japanese: 敬体, no space between Japanese and Latin characters (LINE style), [操作対象] / 「表示文字列」 / screen names without brackets, dictionary-form task headings. The 2026-09-06 owner decisions are recorded in `docs-site/TRANSLATION.md` §Register, next to the 106 existing term rulings, all of which are applied.
- Japanese paragraphs are written on one line. Browsers drop a soft line break between two Japanese characters but render one next to a Latin character as a space, so a wrapped source cannot keep the no-space rule. The rule and its reason are in TRANSLATION.md.
- Retired vocabulary is gone from both trees: the AI / your AI, graphics card, graphics memory, AI engine, speed check, under-spec, AI model, tray (outside the program name `waired-tray`), and the bare 「窓」 for context window.
- The owner-ruled public wording on what reaches Anthropic (waired#1313) is on the Claude Code guide and the privacy page, with the fail-closed decision cited.

## Kept in step with main

Three commits landed on `main` while this branch was open and are carried into the pages that now hold the text: Qwen3.8 Flash Next and the never-chosen Qwen3.5 122B (#1259, on How Waired chooses a model), the `none here` form of the local window line (#1258, on the Claude Code troubleshooting page and the coding-tools CLI reference), and the Public Share refusal wording (#1256, in the base).

Two in-flight PRs were coordinated with their sessions and are written into these pages ahead of them, so their rebases keep the text: the lighter variants of Qwen3.8 27B and Qwen3.6 35B-A3B and the catalog memory-column sentence (#1268, which lands first), and the app labels that the fix for #1269 introduces (`Sign in…`, `Pause Waired` / `Resume Waired`, and the `○ Paused` top line). The app's Disconnect and `waired pause` are one switch, so the pause page now has one section for it. Until #1269 lands the app still shows `Sign in...`, `Disconnect`, and `○ Disconnected`.

## Guards and tests

- New `scripts/ci/docs-links-check.mjs` resolves every root-relative link and `#anchor` in `dist/` and runs after the build in `deploy-docs.yml`. Astro only fails on a bad sidebar slug; body links to renamed pages built green and 404'd before.
- `i18n:report`: 56 pairs, 0 out of sync. `i18n-pair-guard` and `docs-surface-guard`: OK against main.
- Two Go test comments cite the pages that now hold the sentences they quote (`internal/router/reason_lines_test.go`, `internal/gui/tray/status_report_test.go`). No pinned string changed. `go test ./internal/router/ ./internal/gui/tray/` passes.

## Screenshots

Four of the five captures are real and included:

- `setup-wizard-progress.png` and `setup-wizard-progress-ja.png`, taken with Playwright against the development console during a real 1.9 GB download, masked in the DOM (device renamed to `my-desktop`, account chip and pre-release banner hidden).
- `app-ready.png` and `app-not-signed-in.png`, taken on a Mac at 2× in the dark appearance: the menu opened and read through System Events, captured on its own rectangle, and the account row repainted in the image so no real address ships. `CAPTURES.md` records the method.

`claude-code-statusline.png` stays a labelled placeholder until a release prints the `⚡` segment the docs quote (0.0.3-rc5 prints it without the prefix); tracked in #1270. Taking the signed-out capture found that the app's **Sign out…** on macOS signs nothing out; filed as #1269. The fix for it also changes the app's `Sign in...` label to `Sign in…`, so the docs quote that form; until it lands the app shows three periods.

## Why one PR

The plan allowed two. Get-started and install pages link forward to guide, troubleshooting, and reference pages that only exist in the new structure, so landing the first half alone would have shipped 404s. Review by group is still possible: each group is one sidebar section, and each commit is one slice.

Refs waired-ai/waired#1314
Fixes #1254

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_019puN41reeo6o9gXkiRTbBr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

catalog: Qwen3.8-Flash-Next (125B-A6B) — macOS-only on the pinned engine, nothing in the fleet can grade it

1 participant