diff --git a/devlog/_plan/260830_models_provider_header/000_baseline_and_roadmap.md b/devlog/_plan/260830_models_provider_header/000_baseline_and_roadmap.md
new file mode 100644
index 0000000000..f56cca71d6
--- /dev/null
+++ b/devlog/_plan/260830_models_provider_header/000_baseline_and_roadmap.md
@@ -0,0 +1,168 @@
+# 000 — Models provider-row header: unreadable chip, overlapping name, meaningless controls
+
+Reported against the running dashboard's Models page with a screenshot: "이부분도
+존나 이상해 신규 2개 꺼짐, 펜, 스위치(이건 뭘하는지도 모르겠음), 사용자 지정창이랑
+마지막 스위치는 뭔지도 모름".
+
+Two distinct failures are stacked in one header, and they need different fixes:
+
+- **Geometry** — the "신규 N개, 꺼짐" chip collapses into a rounded blob and the
+ provider name paints on top of the active count.
+- **Meaning** — three controls are operable but unlabeled: a sighted user cannot
+ tell what they do. This half is not a layout bug and cannot be fixed by
+ layout.
+
+As with the sidecar unit, every defect below carries a measured baseline from a
+CDP harness (`Emulation.setDeviceMetricsOverride`, dpr 2, live
+`getBoundingClientRect`), so each claim is re-checkable.
+
+## Baseline (ko, provider rows on `#models`)
+
+Measured with `.tmp/uiux2/head.ts`, which settles on `innerWidth === target` and
+on rendered provider rows before reading geometry. The proxy at 127.0.0.1:10100
+supplies the live provider list through the Vite `OPENCODEX_PROXY_TARGET` proxy,
+so these are real rows, not fixtures.
+
+| width | provider | header h | name box w | chip lines | chip w |
+|-------|----------|----------|------------|-----------|--------|
+| 1440 | opencode-free | 44.8 | 96.5 | 1 | 92.1 |
+| 1280 | opencode-free | 55.7 | 67.2 | **2** | 69.6 |
+| 1280 | openai | 55.7 | **9.9** | **2** | 57.7 |
+| 1100 | opencode-free | **115.1** | **0.0** | **6** | 34.1 |
+| 1100 | cursor | **115.1** | **0.0** | **6** | 34.1 |
+| 1024 | opencode-free | 75.8 | 96.5 | 1 | — |
+
+The 1100 row is the screenshot state: a six-line chip 34.1px wide, a name box
+measuring **zero**, and a header 2.6x its correct height. 1024 recovers because
+the container query at `styles-models-workspace.css:517` moves the actions onto
+their own row, which returns the toggle's width. The defect therefore lives in a
+**band** (roughly 1040-1380 in this layout), which is why it is easy to miss at
+either extreme.
+
+## Defect 1 — the chip is a shrinkable flex item with no single-line floor
+
+`.models-chip` (`styles-models-workspace.css:315`) declares
+`display: inline-block` plus padding, border and `border-radius`, and nothing
+else. Because it sits inside `.row models-provider-toggle`
+(`Models.tsx:1226`) and `.row` is `display: flex` (`styles.css:1205`), the chip
+is a **flex item**: its `inline-block` outer display is blockified and its
+initial `flex-shrink: 1` applies. Measured computed values confirm it —
+`white-space: normal`, `flex-shrink: 1`.
+
+`inline-block` does not imply `white-space: nowrap`. The chip's only floor is
+`min-width: auto`, which resolves to the text's **min-content** width — and for
+Korean that is nearly one syllable, because CJK line-breaking permits a break
+between Hangul syllable blocks. So `신규 2개, 꺼짐` legally becomes
+`신규 / 2 / 개, / 꺼 / 짐`, and the fixed padding wrapped around that narrow
+column is exactly the observed blob.
+
+~~Fix: give the chip a single-line floor.~~ **Superseded.** Measurement showed the
+chip is not independently broken: it is starved of width by a collapsed ancestor,
+and it returns to one line as soon as that ancestor claims its intrinsic width. An
+audit also found a chip-level floor unsafe across the eight other `.models-chip`
+call sites. The shipped fix leaves the shared `.models-chip` primitive untouched;
+it adds an ellipsis only to the toggle-scoped descendant — see `010` and `011`.
+
+## Defect 2 — the name overflows a zero-width box instead of reflowing
+
+The name span carries inline `whiteSpace: "nowrap"` (`Models.tsx:1232`) while
+`styles-models-workspace.css:267` gives it `min-width: 0` and
+`overflow-wrap: anywhere`. Those two fight: `nowrap` suppresses the wrapping
+that `overflow-wrap: anywhere` was added to provide, `min-width: 0` lets the box
+shrink to nothing, and the default `overflow: visible` means the glyphs keep
+painting outside the box — straight across the sibling count.
+
+Nothing positions these elements on top of each other: there is no `position`,
+transform, or negative margin anywhere in the applicable rules. The count is
+laid out normally *after* a box that measures 0px, so the collision is pure
+overflow.
+
+Why the header's own `flex-wrap: wrap` does not save it: the header's direct
+children are only the toggle button and the actions container. Wrapping does not
+propagate into descendants, and the toggle's inner `.row` has no `flex-wrap`,
+so the chevron, name, chips and count are locked on one line and shrink against
+each other.
+
+The upstream enabler is `flex: 1` on the toggle (`Models.tsx:1229`), which
+resolves to `flex: 1 1 0%` — zero basis, shrink allowed — combined with
+`min-width: 0`. The toggle then accepts whatever the wide actions cluster leaves
+it rather than forcing a wrap.
+
+~~Fix: let the toggle's own row wrap.~~ **Superseded.** Inner wrapping is inert:
+line construction inside the button runs after its used width has been assigned, so
+wrapping redistributes 31px rather than asking for more. Measured: the candidate
+left the name box at 0.0px, byte-identical to baseline. The shipped fix gives the
+toggle a real flex **basis** so its content enters the header's wrap decision, and
+removes every child's min-content floor so the row can always shrink back inside the
+card — see `010`.
+
+## Defect 3 — three controls carry no visible meaning (two switches and the `+`)
+
+`Switch` (`ui.tsx:8`) accepts a `label` prop and spends it **only** on
+`aria-label` (`ui.tsx:11`); its sole child is ``. So
+every `Switch` in this codebase is, to a sighted user, an unlabeled toggle. The
+user's "이건 뭘하는지도 모르겠음" is a correct reading of the UI.
+
+Audit of the header controls in visual order:
+
+| control | visible | aria-label | title | verdict |
+|---------|---------|-----------|-------|---------|
+| collapse button | chevron + name + count | (children) | — | OK |
+| pencil | icon only | 공급자 별칭 편집 | yes | OK |
+| default-aliases Switch | knob only | 기본 별칭 사용 | — | **OPAQUE** |
+| 사용자 지정 창 | text | — | — | OK |
+| `+` | `+` only | 커스텀 모델 추가 | — | **OPAQUE** |
+| preset segmented | 프리셋 / 전체 | group only | — | OK |
+| 모두 켜기 / 모두 끄기 | text | — | — | OK |
+| cap Switch | knob only | 기본 {value} | — | **OPAQUE** |
+| cap Select | number only | 기본 {value} | — | **OPAQUE** |
+
+The pencil is fine precisely because it pairs an icon with `title` — that is the
+pattern the opaque controls are missing.
+
+Two aggravating details:
+
+1. The cap Switch's accessible name is `기본 128k` — a *value*, not a function.
+ Even a screen-reader user is not told this governs the context-window cap.
+2. For routed providers with the cap off, `(capOn || nativeProviderGroup)`
+ (`Models.tsx:1360`) hides the Select, so the only thing left is a bare
+ toggle with no adjacent number to hint at its purpose. The worst state is the
+ default state.
+
+### Design constraint
+
+This is a dense expert control surface: `DESIGN_VARIANCE 2`, `MOTION 1`, density
+D6+. The domain gate is strict — no decorative kit, no motion, no new color. The
+fix is *labels and reflow*, and the correct instrument is the existing
+`title`-plus-icon pattern already proven by the pencil, plus a visible text
+label where the header has room for one.
+
+UX-LAZY-01 was applied to each control before relabeling it rather than after:
+every one of them is a real per-provider setting with no correct global default,
+so none can be deleted or absorbed. They need meaning, not removal.
+
+## Roadmap
+
+- `010` — let the toggle's content be seen, and make every child yield (geometry).
+ Five designs; the first four were rejected by audit or stress measurement and
+ `011` records why.
+- `020` — control affordances: visible labels for the opaque controls, and a
+ `Switch` that can render one.
+
+Each is one PABCD work-phase and one stacked PR. `010` lands first because `020`
+adds visible text to the same header and would otherwise be measured against a
+layout that is still collapsing.
+
+## Verification contract
+
+- Re-measure the sweep at 1440/1280/1100/1024 in ko + ru + fr + en and require:
+ chip `lines === 1` everywhere, name box width > 0, zero name/count overlap, and
+ header height within one line-height of the 1440 baseline.
+- A focused `gui/tests` regression per phase, driven red against current CSS
+ first.
+- Remote gates only (`ssh lidge` + `ocx-run`); the local full suite is forbidden
+ by the user. Push `--no-verify`.
+- Before/after screenshots at the failing width, per `AGENTS.md` enforce-target.
+
+
+
diff --git a/devlog/_plan/260830_models_provider_header/010_toggle_basis_and_shrink.md b/devlog/_plan/260830_models_provider_header/010_toggle_basis_and_shrink.md
new file mode 100644
index 0000000000..dd86c0b9d3
--- /dev/null
+++ b/devlog/_plan/260830_models_provider_header/010_toggle_basis_and_shrink.md
@@ -0,0 +1,286 @@
+# 010 — Let the toggle's content be seen, and make every child yield
+
+Fixes the geometry half. Meaning is phase `020`.
+
+**Sixth design.** The five before it were each rejected by an adversarial reviewer or
+by a stress measurement, and the rejections are the useful part — they map the shape
+of the problem:
+
+| draft | approach | killed by |
+|-------|----------|-----------|
+| 1 | shared-chip `nowrap`/`flex-shrink: 0` + inner `flex-wrap` + name ellipsis | inner wrap is inert; shared-chip change unsafe elsewhere |
+| 2 | `min-width: max-content` floor | unbounded: 64-char name overflowed the card by 216px |
+| 3 | floor + 16rem name cap + 12rem chip cap | 64-char name **and** alias together still overflowed 64px |
+| 4 | `flex-basis: auto` + ellipsis on name and chip | the count and badge children kept min-content floors |
+| 5 | `flex-basis: auto` + one rule for every child | let the fixed-size chevron shrink to 2.5px |
+| **6** | **draft 5 + a `flex: none` exemption for the icon** | — |
+
+Drafts 2-4 were three versions of one mistake: bound the row by naming the children
+that could overflow it, then discover the next child. Draft 5 stops naming children —
+and then over-applied, shrinking an icon that has no text to truncate. Draft 6 keeps
+the universal rule and exempts the one child whose size is intrinsic rather than
+textual. `011` records each failure.
+
+## The mechanism, measured
+
+At 1100px the collapsed row measures:
+
+| element | width |
+|---------|-------|
+| `.models-provider-head` | 488.0 |
+| `.models-provider-actions` | **422.9** (scrollWidth 423) |
+| `.models-provider-toggle` | **31.1** (scrollWidth 93) |
+| name span inside it | **0.0** (scrollWidth 44) |
+
+The toggle carries inline `flex: 1` (`Models.tsx:1229`), which resolves to
+`flex: 1 1 0%`. That zero **basis** is the defect. A flex item with a zero base size
+never reports a content requirement, so the header — which already has
+`flex-wrap: wrap` — never learns the toggle needs room and never wraps the actions
+cluster to its own line. It keeps one line and hands the toggle the 31px remainder.
+
+Inside that remainder the name absorbs the whole deficit, measures 0.0px, and —
+carrying inline `white-space: nowrap` with default `overflow: visible` — paints its
+glyphs across the count. The chip blob is the same starvation, finished by CJK
+line-breaking between Hangul syllables. Even the chevron collapses: measured 0px wide
+on a starved row, against 14px on a healthy one.
+
+Two independent properties are required:
+
+- **Visibility** — the toggle's content must enter the header's wrap decision, so it
+ receives a share rather than a remainder. That is `flex-basis: auto`.
+- **Boundedness** — whatever the content, the row must not force itself wider than the
+ card. Shrinkability alone does not give this: a flex child stops at its own
+ `min-width: auto` floor, which is its min-content width, and the *sum* of those
+ floors can exceed the container.
+
+The bound has one precondition worth stating plainly, because the round-5 audit caught
+the document overstating it: `> *` selects **element** children. A bare string
+interpolated directly into the button becomes an anonymous flex item, which no selector
+can reach, and it would keep its own min-content floor. Every child today is an
+`