Repository navigation
fix(webui): load the model catalogue for the session-less home slot - #168
Merged
Fectivnfy112357 merged 1 commit intoOct 19, 2026
Merged
Conversation
The composer's Model picker rendered disabled and showed the bare "Model"
placeholder when the app booted straight into the new-task screen. It only
recovered once the user opened a conversation.
Root cause: `start()` treats the home slot as a catalogue context like any
other, but nothing ever *read* it. `selectSession` only points
`shownCatalogueKey` at the home key, and the two readers that could fill it
were both unreachable on a session-less boot:
- `refreshInspection` requires a `sessionId`, so it stays inert without one.
- `loadModels` had exactly one caller, the settings modal, which only runs
once the user opens settings.
So `catalogue.read(shownKey)` returned undefined, the picker projected an
empty `models` array, and `ModelPicker.public.tsx:184` evaluated
`disabled={models.length === 0}` to true. Opening a conversation called
`loadModels(sessionId)` and hid the defect.
The fix is one line: after `selectSession`, read whichever context it just
chose. Passing `initialSessionId` rather than a bare no-arg call covers both
the home boot and the routed boot, so the two paths cannot drift apart.
Validation
----------
Unit level, `webui-application-lifecycle.test.ts`, two new cases:
- a session-less `start()` must read the catalogue and must not attach a
`sessionId` to that read (the home context asks for the runtime-wide
catalogue, not some session's);
- a routed `start({ initialSessionId })` must read with that session's id.
Both were written before the fix and both failed against it (2 failed /
29 passed). After the fix the file is 31 passed / 0 failed.
Negative injection, 4/4 killed, 0 survivors, each restored afterwards:
- A. delete the added line outright;
- B. swap `loadModels` for `acquireModels` — loads without calling
`selectCatalogue`, so the shown key never updates;
- C. move the call inside the `if (initialSessionId !== undefined)` block,
which reinstates the exact original defect;
- D. pass a literal `undefined` instead of forwarding `initialSessionId`.
Mutation B is why the fix calls `loadModels` rather than `acquireModels`,
and mutation D is why the second test exists: a literal `undefined` is
indistinguishable from the real thing on the home path and is only caught by
the routed case.
An earlier draft of mutation C was written as an insertion on the line after
a braceless `if`, which is a no-op, and the test correctly did not catch it.
The mutation was wrong, not the test; it was rewritten with an explicit block
before being counted.
Browser verification
--------------------
Served by `dev:server` on 127.0.0.1:8787 against the rebuilt `dist-webui`
bundle, confirmed to contain the call. Reading
`.webui-model-selector-trigger` directly rather than judging by colour:
- with the fix: no `disabled` attribute, label `deepseek-v4.1-flash-free`,
and the menu lists the full catalogue (MiniMax M3.1-Flash-Preview, M3,
M2.7-highspeed, M2.7; opencode-zen space-bunny-free, deepseek-v4.1-flash-free);
- with the call removed: `disabled=""` and the bare `Model` placeholder,
reproducing the report.
The second build is the control that gives the first one meaning: it proves
the DOM read can see `disabled` at all, so "no disabled attribute" is an
observation rather than a blind spot. Console: 0 errors, 0 warnings.
Gates
-----
All five run on the new architecture baseline `33016455`:
- `check:source` 5188 files
- `typecheck:webui` exit 0
- `check:webui-dependency` 435 files / 1557 refs / 0 violations
- `check:webui-boundary` 432 inputs
- `test:webui` 19 failed / 2886 passed / 4 skipped
The 19 failures are the pre-existing baseline, unchanged by this patch: the
same run before the change reported 19 failed / 2884 passed / 4 skipped, so
this adds 2 passes and 0 failures. They look Windows-specific — two of them
compare POSIX-shaped paths against `fileURLToPath` output
(`webui-design-tokens.test.ts:84` asserts a path `endsWith`
`src/client/styles/tokens.css`, and `webui-dependency-check.test.ts:939`
expects `C:\...` but receives `C:/...`). Not addressed here; flagging them so
the count is not mistaken for a regression.
CI caveat
---------
Actions have been disabled repository-wide since 2026-10-07
(`gh workflow run` returns `HTTP 422: Actions has been disabled for this
repository`), so this PR will show no checks and the numbers above are local
Windows runs only. The baseline has had no Linux or macOS run since.
Re-enabling Actions needs a repository admin.
|
Reviewed against the WebUI source and runtime contract. The startup read is correctly scoped: There are still no CI checks attached to this head. I did not dispatch a workflow; this merge proceeds based on the source review and the validation reported in the PR description. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The composer's Model picker rendered disabled, showing only the bare
Modelplaceholder, whenever the app booted straight into the new-task screen. Opening a conversation made it work.Why
start()treats the home slot as a catalogue context like any other, but nothing ever read it.selectSessiononly pointsshownCatalogueKeyat the home key.refreshInspectionrequires asessionId, so it stays inert on a session-less boot.loadModelshad exactly one caller — the settings modal — which only runs once the user opens settings.So
catalogue.read(shownKey)returnedundefined, the picker projected an emptymodelsarray, andModelPicker.public.tsx:184evaluateddisabled={models.length === 0}totrue. Opening a conversation calledloadModels(sessionId)and hid the defect.One line, right after
selectSession:Forwarding
initialSessionIdrather than making a separate no-arg call covers the home boot and the routed boot with one code path, so the two cannot drift apart.Validation
Unit — tests written before the fix, both failed against it
webui-application-lifecycle.test.ts, 2 new cases (before: 2 failed / 29 passed; after: 31 passed / 0 failed):start()must read the catalogue, and must not attach asessionIdto that read — the home context asks for the runtime-wide catalogue, not some session's;start({ initialSessionId })must read with that session's id.Negative injection — 4/4 killed, 0 survivors, each restored
loadModels→acquireModelsselectCatalogue, so the shown key never updatesif (initialSessionId !== undefined)blockundefinedinstead of forwardinginitialSessionIdB is why the fix calls
loadModelsand notacquireModels. D is why the second test exists — a literalundefinedis indistinguishable from the real thing on the home path and is caught only by the routed case.Browser — with a control, so the positive result means something
Served by
dev:serveron127.0.0.1:8787against the rebuiltdist-webuibundle (confirmed to contain the call). Reading.webui-model-selector-triggerdirectly rather than judging by colour:disabledattributedeepseek-v4.1-flash-freedisabled=""ModelThe second build is what gives the first one meaning: it proves the DOM read can see
disabledat all, so "no disabled attribute" is an observation rather than a blind spot.Console: 0 errors, 0 warnings.
Gates — all five on baseline
33016455check:sourcetypecheck:webuicheck:webui-dependencycheck:webui-boundarytest:webuiThe 19 failures are pre-existing and unchanged by this patch — the same run before the change reported 19 failed / 2884 passed / 4 skipped. This adds 2 passes, 0 failures.
They look Windows-specific. Two are unambiguous:
webui-design-tokens.test.ts:84asserts a pathendsWith("src/client/styles/tokens.css"), andwebui-dependency-check.test.ts:939expectsC:\Users\...but receivesC:/Users/...— both compare POSIX-shaped paths againstfileURLToPathoutput. A third (plugin-action-inventory.test.ts:121-123) reportspplication\port-slices.ts, a path missing its first character. Not addressed here — flagging them so the count is not mistaken for a regression, and so they can get a Linux run once Actions is back.Actions have been disabled repository-wide since 2026-10-07:
Zero runs repo-wide since then. Every number above is a local Windows run. The
webuibaseline has not been exercised on Linux or macOS since. Re-enabling requires a repository admin (Settings → Actions → General) — asking for that separately.Related: #33 was merged and then reverted at @MCpok's request while the webui architecture was being reworked; that branch is untouched by this PR.