Mockup: Settings in sections (components, tabs, nested sidebar, one setting per ⌘K hit) #304

Open
opened 2026-11-02 05:59:21 +00:00 by kayg · 28 comments
Owner

Mockup (J92): Settings in sections — components on the left, tabs inside, nested in the sidebar, one setting per ⌘K hit.

Request (owner, 2026-11-02)

Settings need better sections: "a row per subcomponent? imitating a sidebar selection + tabs? of course in our actual sidebar this would appear as nested settings."

Proposed structure (to refine):

  • Mesh: Keys (WireGuard rotation 7 d, identity rotation 7 d) | Names (DNS suffix, .internal) | Rules
  • Machines: Certificates (self-renewal window 90 d after expiry) | Joining (add-host token 15 min, up code 10 min)
  • SSH: Certificates (person certificate 24 h, 1–24 h) | Forwarding (later)
  • Accounts and sign-in: Sessions (browser 30 d sliding, 1–90 d) | CLI keys (30 d sliding, 1–365 d) | Passkeys | Recovery
  • Proxy: Published services | Certificates
  • the existing sections (Appearance, Terminal, Phones, About, …) moved into the same model.

Each key setting shows its default, its allowed range, a Reset and a one-line plain explanation; out-of-range values are refused inline.

Deliverable: a LIVE mockup in the mock harness (?mock=1&proto=clusters…): the Settings window with a left column of components and tabs inside; the main sidebar showing nested Settings › Component › Tab; ⌘K jumping straight to one setting; desktop and phone (on phone the drill-down list replaces the left column). Served on dev-02, linked from the mockups index. Screenshots at 1440×900 DPR 2 and 393×852 DPR 3; ±0.5 px alignment checked.

Not product code. Nothing is saved, no server API is touched. The owner reviews the visuals.

Plan and estimate (posted within 15 min of start)

Base: origin/dev b0e79b31e. Branch: settings-sections-mock-j92.

  1. Catalogue + checks (pure, unit-tested) — one data file: components → tabs → settings (id, plain title, one-line explanation, kind, unit, default, min, max). One validate(setting, text) that refuses out-of-range input with a plain message, and one search(query) used by ⌘K. ~30 min.
  2. Shared pieces in packages/ui — reuse the capsule tabs, key/value rows, switch, slider, icon buttons and warm tooltip. New there: only a setting row (title, one-line explanation, value field with unit, "default · range" caption, Reset icon) and a section list (left column on desktop, drill-down list on phone). Look first for anything existing to extend. ~1.5 h.
  3. Mock wiring (?settings=1) — a Settings view window with the two-pane layout; sidebar tree rows nested Settings › Component › Tab (tree.ts / branched.ts); ⌘K rows per setting that open the component, tab and the row (highlighted); phone drill-down with back. Existing sections move into the model (Appearance, Terminal, Phones, About reuse their current panels as tabs). ~1.5 h.
  4. Build on dev-02, serve on a free port, add to mockups.html; Playwright check of left edges and centre lines (±0.5 px); screenshots 1440×900 @2 and 393×852 @3 on this issue. ~1 h.

Estimate: about 4.5 h in total. I stop and report at 9 h.

NOT building: persistence, server API, real validation on the server, the Forwarding feature (shown as "later"), any change to the product Settings view, general form framework.

Questions for the owner are listed on the issue as I find them (I will pick the obvious default and move on).

Mockup (J92): Settings in sections — components on the left, tabs inside, nested in the sidebar, one setting per ⌘K hit. ## Request (owner, 2026-11-02) Settings need better sections: "a row per subcomponent? imitating a sidebar selection + tabs? of course in our actual sidebar this would appear as nested settings." Proposed structure (to refine): - **Mesh**: Keys (WireGuard rotation 7 d, identity rotation 7 d) | Names (DNS suffix, `.internal`) | Rules - **Machines**: Certificates (self-renewal window 90 d after expiry) | Joining (add-host token 15 min, `up` code 10 min) - **SSH**: Certificates (person certificate 24 h, 1–24 h) | Forwarding (later) - **Accounts and sign-in**: Sessions (browser 30 d sliding, 1–90 d) | CLI keys (30 d sliding, 1–365 d) | Passkeys | Recovery - **Proxy**: Published services | Certificates - the existing sections (Appearance, Terminal, Phones, About, …) moved into the same model. Each key setting shows its default, its allowed range, a Reset and a one-line plain explanation; out-of-range values are refused inline. Deliverable: a LIVE mockup in the mock harness (`?mock=1&proto=clusters…`): the Settings window with a left column of components and tabs inside; the main sidebar showing nested Settings › Component › Tab; ⌘K jumping straight to one setting; desktop and phone (on phone the drill-down list replaces the left column). Served on dev-02, linked from the mockups index. Screenshots at 1440×900 DPR 2 and 393×852 DPR 3; ±0.5 px alignment checked. Not product code. Nothing is saved, no server API is touched. The owner reviews the visuals. ## Plan and estimate (posted within 15 min of start) Base: `origin/dev` b0e79b31e. Branch: `settings-sections-mock-j92`. 1. **Catalogue + checks (pure, unit-tested)** — one data file: components → tabs → settings (id, plain title, one-line explanation, kind, unit, default, min, max). One `validate(setting, text)` that refuses out-of-range input with a plain message, and one `search(query)` used by ⌘K. ~30 min. 2. **Shared pieces in `packages/ui`** — reuse the capsule tabs, key/value rows, switch, slider, icon buttons and warm tooltip. New there: only a *setting row* (title, one-line explanation, value field with unit, "default · range" caption, Reset icon) and a *section list* (left column on desktop, drill-down list on phone). Look first for anything existing to extend. ~1.5 h. 3. **Mock wiring (`?settings=1`)** — a Settings view window with the two-pane layout; sidebar tree rows nested Settings › Component › Tab (tree.ts / branched.ts); ⌘K rows per setting that open the component, tab and the row (highlighted); phone drill-down with back. Existing sections move into the model (Appearance, Terminal, Phones, About reuse their current panels as tabs). ~1.5 h. 4. **Build on dev-02, serve on a free port, add to `mockups.html`; Playwright check of left edges and centre lines (±0.5 px); screenshots 1440×900 @2 and 393×852 @3 on this issue.** ~1 h. Estimate: about 4.5 h in total. I stop and report at 9 h. NOT building: persistence, server API, real validation on the server, the Forwarding feature (shown as "later"), any change to the product Settings view, general form framework. Questions for the owner are listed on the issue as I find them (I will pick the obvious default and move on).
Author
Owner

Started. Branch settings-sections-mock-j92, base origin/dev b0e79b31e3. Worktree ~/Developer/Worktrees/infraternal-J92 on the control host (edit only); builds and captures on infraternal-dev-02-std. Plan and estimate are in the issue body (about 4.5 h).

Started. Branch `settings-sections-mock-j92`, base `origin/dev` b0e79b31e3d0f3dc89ae3ca67b466d929c6d03ba. Worktree `~/Developer/Worktrees/infraternal-J92` on the control host (edit only); builds and captures on `infraternal-dev-02-std`. Plan and estimate are in the issue body (about 4.5 h).
Author
Owner

Correction from the owner (2026-11-02), replaces the plan in the issue body

"absolutely no to tabs inside each component. one row is one component yes so let's say it's Mesh and the first window is keys so we can name the whole cluster Settings and then the first row first item would show at the top as Settings > Mesh > Keys (> being breadcrumbs each of Settings, Mesh, Keys in their respective pills)"

No tabs anywhere. New model:

  • Settings = one cluster (view) of windows, like Console and the rest.
  • Each ROW of the cluster = one component (Mesh, Machines, SSH, …).
  • Each WINDOW in a row = one group of that component (Mesh → Keys, Names, Rules; …). Settings with their default, range, Reset, one-line explanation and inline refusal sit in that window.
  • Top breadcrumb: three pills Settings › Mesh › Keys, following the focused window. Each pill navigates: Settings opens the view list, Mesh lists the components (jump to a row), Keys lists the groups of this row.
  • Main sidebar shows the same nesting: Settings › Mesh › Keys.
  • ⌘K jumps to a single setting: flies to its window and highlights its row.
  • Phone: the existing phone canvas conventions (99 % windows, swipe sideways between columns, up and down inside a column).

Where each setting lives is still being decided

The whole map is ONE table (catalog.ts: component → groups → settings, with default, range, unit, explanation). Placeholders where unsure (flagged in the table). Moving a setting is a one-line edit.

How I build the rows (decision, so the owner can overrule)

The canvas already has a grid of windows (D212: a window may span columns, band heights are shared). Desktop: one group of columns, one band per component, each window one group; a row with fewer groups gives the spare width to its last window. Phone: the same windows as plain columns (column = n-th group of each component), because a 3-screen-wide window cannot exist on a phone. The breadcrumb and sidebar read the same table, so they stay right either way.

Steps and estimate (from now): about 6 h; I stop and report at 12 h

  1. Catalogue (the one table) + pure value checks (parse "36 h", range, text pattern) with unit tests. 45 min.
  2. packages/ui: a setting row (title, one-line explanation, value field with unit, "Default · range", Reset icon button, inline refusal). Reuse key/value list, switch, icon buttons, tooltip. 1 h.
  3. Mock wiring ?settings=sections: the Settings view built from the table (desktop grid, phone columns); each window body renders its group. Existing sections (Appearance, Window sizes, Toolbar, Shortcuts, About, Hosts…) become groups of rows (they reuse their current panels unchanged). 1.5 h.
  4. Breadcrumb pills in the top capsule (3 pills + popover lists); sidebar nesting (a depth on tree leaves); ⌘K rows per setting and per group. 1.5 h.
  5. Build on dev-02, serve, mockups index, alignment spec (±0.5 px), screenshots 1440×900 @2 and 393×852 @3. 1 h.

NOT building: persistence, server API, tabs, the Forwarding feature (an empty "later" window), changes to the product Settings view.

## Correction from the owner (2026-11-02), replaces the plan in the issue body > "absolutely no to tabs inside each component. one row is one component yes so let's say it's Mesh and the first window is keys so we can name the whole cluster Settings and then the first row first item would show at the top as Settings > Mesh > Keys (> being breadcrumbs each of Settings, Mesh, Keys in their respective pills)" No tabs anywhere. New model: - **Settings = one cluster (view) of windows**, like Console and the rest. - **Each ROW of the cluster = one component** (Mesh, Machines, SSH, …). - **Each WINDOW in a row = one group of that component** (Mesh → Keys, Names, Rules; …). Settings with their default, range, Reset, one-line explanation and inline refusal sit in that window. - **Top breadcrumb**: three pills `Settings › Mesh › Keys`, following the focused window. Each pill navigates: Settings opens the view list, Mesh lists the components (jump to a row), Keys lists the groups of this row. - **Main sidebar** shows the same nesting: Settings › Mesh › Keys. - **⌘K** jumps to a single setting: flies to its window and highlights its row. - **Phone**: the existing phone canvas conventions (99 % windows, swipe sideways between columns, up and down inside a column). ### Where each setting lives is still being decided The whole map is ONE table (`catalog.ts`: component → groups → settings, with default, range, unit, explanation). Placeholders where unsure (flagged in the table). Moving a setting is a one-line edit. ### How I build the rows (decision, so the owner can overrule) The canvas already has a grid of windows (D212: a window may span columns, band heights are shared). Desktop: one group of columns, one band per component, each window one group; a row with fewer groups gives the spare width to its last window. Phone: the same windows as plain columns (column = n-th group of each component), because a 3-screen-wide window cannot exist on a phone. The breadcrumb and sidebar read the same table, so they stay right either way. ### Steps and estimate (from now): about 6 h; I stop and report at 12 h 1. Catalogue (the one table) + pure value checks (parse "36 h", range, text pattern) with unit tests. 45 min. 2. `packages/ui`: a setting row (title, one-line explanation, value field with unit, "Default · range", Reset icon button, inline refusal). Reuse key/value list, switch, icon buttons, tooltip. 1 h. 3. Mock wiring `?settings=sections`: the Settings view built from the table (desktop grid, phone columns); each window body renders its group. Existing sections (Appearance, Window sizes, Toolbar, Shortcuts, About, Hosts…) become groups of rows (they reuse their current panels unchanged). 1.5 h. 4. Breadcrumb pills in the top capsule (3 pills + popover lists); sidebar nesting (a `depth` on tree leaves); ⌘K rows per setting and per group. 1.5 h. 5. Build on dev-02, serve, mockups index, alignment spec (±0.5 px), screenshots 1440×900 @2 and 393×852 @3. 1 h. NOT building: persistence, server API, tabs, the Forwarding feature (an empty "later" window), changes to the product Settings view.
Author
Owner

Ready for review: Settings as rows of windows (mockup)

Try it: http://10.69.69.117:47650/mockups.html (first entry, #304), or directly http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections

What to try (desktop and phone):

  1. It opens on Settings › Mesh › Keys. Press the Mesh pill: the list of components; Keys: the groups of this row; Settings: the view list. Each pill moves you.
  2. Open the sidebar (top left): Settings lists the components, and the open one lists its groups, nested (Mesh › Keys / Names / Rules).
  3. ⌘K: type wireguard, dns, browser stays, token or about. Each jumps to the window and fades a quiet fill on the row.
  4. In Connection keys type 400: refused inline ("Pick 1 to 30 days. Still using 7 d."), nothing saved; Escape restores. Type 336 h: understood as 14 d, and a Reset icon (tooltip "Reset to 7 d") appears. Reset puts the default back.
  5. Phone: swipe sideways between components, up and down between groups. The first breadcrumb pill is its icon only.

How it is built (read this before judging the layout)

  • Settings is one cluster. Desktop: the canvas's own grid of windows (D212), one screen wide: a row per component, a window per group; a row of n windows splits the width into n equal windows (measured below). Phone: plain columns, one per component with its groups stacked, because a window spanning columns would be wider than a phone.
  • No tabs anywhere. Where each setting lives is ONE table: apps/tracer/src/canvas/mock/settings-map/catalog.ts (guesses marked PLACEHOLDER, your numbers OWNER). Windows, breadcrumb, sidebar and ⌘K all read it. Moving a setting is a one-line edit.
  • Existing sections moved in unchanged: Appearance (Look, Window sizes), Terminal (Shortcuts), Phones (Toolbar), Machines › Details (the old Hosts), Machines › Found hosts, Mesh › Rules, About › This build, People › Roles. The old ⌘K → Settings: … entries and ? still open them.

Evidence (final head, dev-02, headless Chromium)

  • 2 Playwright specs pass, 0 fail (test/settings-sections.spec.ts), all within ±0.5 px: every row flush with equal 16 px gutters; the windows of a row level (top and bottom) and exactly equal in width; no overlaps; title, help, field and range on one left edge; field and Reset on one centre line; breadcrumb pills on one centre line and centred on the screen (±1 px); the sidebar's nested glyph sits under its parent's name; phone targets ≥ 44 px.
  • 8 unit tests for the value rules and 8 for the table (row sizes, track plan, ids, owner numbers, old sections, ⌘K rows). tsc clean.
  • Screenshots attached below: 1440×900 @2× (01–08) and 393×852 @3× (p01–p05). I looked at each at full size; I do not judge them as final.

Findings (not fixed, not in scope)

  1. ⌘K matches the exact typed phrase only (substring of label and hint): browser signed in finds nothing for "Browser stays signed in for". It applies to every palette row. Words in any order would be friendlier.
  2. In a quarter-width window (four to a row) the window pill truncates with an ellipsis ("Certificat…", Machines › Certificates). It is the product's pill; TASTE says no ellipsis.
  3. A strip of ordinary columns is wider than a 1440 screen (a column is a third of it, scaled by the UI size 1.1), so three windows do not fit; the Settings grid is deliberately sized to the screen instead.

Questions for the owner (I picked the default and moved on)

  • Row order: I followed your order (Mesh, Machines, SSH, Accounts and sign-in, Proxy) and put People, Appearance, Terminal, Phones, About after. Personal rows (Appearance…) first instead?
  • People (the old Users section) has no row in your list; I made one. Phones holds only Toolbar; Terminal only Shortcuts. Rows with one group are a window as wide as the screen, which looks empty: merge them, or cap the width?
  • On a phone the axes swap (component = column, groups stacked). OK?
  • Ranges other than the ones you gave (for example Connection keys 1–30 d, Machine identity 1–90 d, Add-machine token 1–60 min) are my guesses.
  • Accounts and sign-in has four groups (the most a row holds); Sessions also lists the signed-in devices (old Devices section).
## Ready for review: Settings as rows of windows (mockup) **Try it:** http://10.69.69.117:47650/mockups.html (first entry, #304), or directly http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections What to try (desktop and phone): 1. It opens on **Settings › Mesh › Keys**. Press the **Mesh** pill: the list of components; **Keys**: the groups of this row; **Settings**: the view list. Each pill moves you. 2. Open the sidebar (top left): **Settings** lists the components, and the open one lists its groups, nested (Mesh › Keys / Names / Rules). 3. **⌘K**: type `wireguard`, `dns`, `browser stays`, `token` or `about`. Each jumps to the window and fades a quiet fill on the row. 4. In *Connection keys* type `400`: refused inline ("Pick 1 to 30 days. Still using 7 d."), nothing saved; Escape restores. Type `336 h`: understood as 14 d, and a **Reset** icon (tooltip "Reset to 7 d") appears. Reset puts the default back. 5. Phone: swipe sideways between components, up and down between groups. The first breadcrumb pill is its icon only. ### How it is built (read this before judging the layout) - Settings is one cluster. **Desktop**: the canvas's own grid of windows (D212), one screen wide: a row per component, a window per group; a row of n windows splits the width into n equal windows (measured below). **Phone**: plain columns, one per component with its groups stacked, because a window spanning columns would be wider than a phone. - **No tabs anywhere.** Where each setting lives is ONE table: `apps/tracer/src/canvas/mock/settings-map/catalog.ts` (guesses marked `PLACEHOLDER`, your numbers `OWNER`). Windows, breadcrumb, sidebar and ⌘K all read it. Moving a setting is a one-line edit. - Existing sections moved in unchanged: Appearance (Look, Window sizes), Terminal (Shortcuts), Phones (Toolbar), Machines › Details (the old Hosts), Machines › Found hosts, Mesh › Rules, About › This build, People › Roles. The old `⌘K → Settings: …` entries and `?` still open them. ### Evidence (final head, dev-02, headless Chromium) - 2 Playwright specs pass, 0 fail (`test/settings-sections.spec.ts`), all within **±0.5 px**: every row flush with equal 16 px gutters; the windows of a row level (top and bottom) and exactly equal in width; no overlaps; title, help, field and range on one left edge; field and Reset on one centre line; breadcrumb pills on one centre line and centred on the screen (±1 px); the sidebar's nested glyph sits under its parent's name; phone targets ≥ 44 px. - 8 unit tests for the value rules and 8 for the table (row sizes, track plan, ids, owner numbers, old sections, ⌘K rows). `tsc` clean. - Screenshots attached below: 1440×900 @2× (`01`–`08`) and 393×852 @3× (`p01`–`p05`). I looked at each at full size; I do not judge them as final. ### Findings (not fixed, not in scope) 1. **⌘K matches the exact typed phrase only** (substring of label and hint): `browser signed in` finds nothing for "Browser stays signed in for". It applies to every palette row. Words in any order would be friendlier. 2. In a quarter-width window (four to a row) the **window pill truncates with an ellipsis** ("Certificat…", Machines › Certificates). It is the product's pill; TASTE says no ellipsis. 3. A strip of ordinary columns is wider than a 1440 screen (a column is a third of it, scaled by the UI size 1.1), so three windows do not fit; the Settings grid is deliberately sized to the screen instead. ### Questions for the owner (I picked the default and moved on) - Row order: I followed your order (Mesh, Machines, SSH, Accounts and sign-in, Proxy) and put People, Appearance, Terminal, Phones, About after. Personal rows (Appearance…) first instead? - **People** (the old Users section) has no row in your list; I made one. **Phones** holds only Toolbar; **Terminal** only Shortcuts. Rows with one group are a window as wide as the screen, which looks empty: merge them, or cap the width? - On a phone the axes swap (component = column, groups stacked). OK? - Ranges other than the ones you gave (for example Connection keys 1–30 d, Machine identity 1–90 d, Add-machine token 1–60 min) are my guesses. - Accounts and sign-in has four groups (the most a row holds); Sessions also lists the signed-in devices (old Devices section).
Author
Owner

Gate for the first version (head 06f46c08e), verbatim

scripts/verify fast on infraternal-dev-02-std, clean worktree, through build-slot:

+---------------------------+--------------+
| Rust gate                 | Result       |
+---------------------------+--------------+
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| test                      | FAIL (101)   |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| static builds             | PASS         |
+---------------------------+--------------+
VERIFY_EXIT=1

The test failure is not from this branch: 4 of 128 tests failed, all restart::tests::*, each exceeded 57.4s; status=signal: 9 (SIGKILL) on a VM with three other gates running (test result: FAILED. 123 passed; 4 failed). This diff changes 0 Rust/Cargo files (21 files, +1261/−11, all TypeScript and CSS). The same four tests, rerun alone on the same build with --test-threads=1: test result: ok. 18 passed; 0 failed. This is the wall-clock dependence tracked in #207. I did not run the gate on an unmodified origin/dev (it would be a second 15-minute Rust build for a diff with no Rust).

New instruction from the owner (replaces the table)

The owner's current map (single mapping table, Title Case, no brackets in names):

  • Appearance → Theme · Font · Size · Layout
  • Terminal → Typing · Scrollback · Multiplexer
  • You → Profile · Passkeys · Recovery · Apps (CLI and MCP keys: 30 d sliding, 1–365; last used / expires / revoke) · Devices (browsers: 30 d sliding, 1–90; Sign out)
  • Machines → New Machines (add-host link 15 min, up code 10 min, default install mode system or user, default sign-in account, join the mesh automatically) · Updates
  • Mesh → Keys (WireGuard 7 d, identity 7 d, certificate self-renewal 90 d after expiry, CA expiry and lock state read-only) · Names · Access · Connections
  • Sharing → Published Services · Certificates
  • About → Version · Licences

Each window gets a ? in its title pill that opens the matching docs heading as a window in the Docs cluster, beside it (placement still being confirmed: easy to move). Breadcrumb: Settings › Row › Window.

Plan and estimate (from now): about 4 h; I report at 8 h

  1. Rewrite catalog.ts to this map (still ONE table), with the docs link of each window in the same table (heading id), so moving a setting or a link is one line. 30 min.
  2. Setting kinds the owner's list needs beyond a duration and a text: a count (scrollback lines), a choice (install mode, default account), a switch (join the mesh automatically), and a list with a row action (Apps: Revoke; Devices: Sign out). Same row shape: name, one line, control, default and range, Reset. 1.5 h.
  3. Windows built from the existing panels where one exists (Theme, Font, Size, Layout are today's Appearance panel split into its blocks; Typing is Shortcuts; Version is About). 45 min.
  4. The ? button in the title pill, opening the docs heading as a window in the Docs cluster beside the current one. First look at how the Docs cluster and its windows open. 1 h.
  5. Rows can now hold 5 windows (You): the track plan generalises (seams at k/5); window width falls to ~265 px at 1440. Rerun the alignment spec, captures, index entry. 45 min.

NOT building: persistence, server API, a docs system (I link into the existing one), changes to the product Settings view.

## Gate for the first version (head 06f46c08e), verbatim `scripts/verify fast` on infraternal-dev-02-std, clean worktree, through build-slot: ``` +---------------------------+--------------+ | Rust gate | Result | +---------------------------+--------------+ | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | test | FAIL (101) | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | static builds | PASS | +---------------------------+--------------+ VERIFY_EXIT=1 ``` The `test` failure is not from this branch: 4 of 128 tests failed, all `restart::tests::*`, each `exceeded 57.4s; status=signal: 9 (SIGKILL)` on a VM with three other gates running (`test result: FAILED. 123 passed; 4 failed`). This diff changes **0** Rust/Cargo files (21 files, +1261/−11, all TypeScript and CSS). The same four tests, rerun alone on the same build with `--test-threads=1`: `test result: ok. 18 passed; 0 failed`. This is the wall-clock dependence tracked in #207. I did not run the gate on an unmodified `origin/dev` (it would be a second 15-minute Rust build for a diff with no Rust). ## New instruction from the owner (replaces the table) The owner's current map (single mapping table, Title Case, no brackets in names): - **Appearance** → Theme · Font · Size · Layout - **Terminal** → Typing · Scrollback · Multiplexer - **You** → Profile · Passkeys · Recovery · Apps (CLI and MCP keys: 30 d sliding, 1–365; last used / expires / revoke) · Devices (browsers: 30 d sliding, 1–90; Sign out) - **Machines** → New Machines (add-host link 15 min, `up` code 10 min, default install mode system or user, default sign-in account, join the mesh automatically) · Updates - **Mesh** → Keys (WireGuard 7 d, identity 7 d, certificate self-renewal 90 d after expiry, CA expiry and lock state read-only) · Names · Access · Connections - **Sharing** → Published Services · Certificates - **About** → Version · Licences Each window gets a **?** in its title pill that opens the matching docs heading as a window in the Docs cluster, beside it (placement still being confirmed: easy to move). Breadcrumb: Settings › Row › Window. ### Plan and estimate (from now): about 4 h; I report at 8 h 1. Rewrite `catalog.ts` to this map (still ONE table), with the **docs link** of each window in the same table (heading id), so moving a setting or a link is one line. 30 min. 2. Setting kinds the owner's list needs beyond a duration and a text: a **count** (scrollback lines), a **choice** (install mode, default account), a **switch** (join the mesh automatically), and a **list with a row action** (Apps: Revoke; Devices: Sign out). Same row shape: name, one line, control, default and range, Reset. 1.5 h. 3. Windows built from the existing panels where one exists (Theme, Font, Size, Layout are today's Appearance panel split into its blocks; Typing is Shortcuts; Version is About). 45 min. 4. The **?** button in the title pill, opening the docs heading as a window in the Docs cluster beside the current one. First look at how the Docs cluster and its windows open. 1 h. 5. Rows can now hold 5 windows (You): the track plan generalises (seams at k/5); window width falls to ~265 px at 1440. Rerun the alignment spec, captures, index entry. 45 min. NOT building: persistence, server API, a docs system (I link into the existing one), changes to the product Settings view.
Author
Owner

Ready for review (second version): the owner's map, a "?" per window, a Docs cluster

Try it: http://10.69.69.117:47650/mockups.html (first entry, #304), or directly http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections (deep links: &at=mesh.keys, &at=machines.new-machines, &at=you.apps, &at=terminal.scrollback, &at=about)

Head 74f3eaf3c on settings-sections-mock-j92 (five atomic commits). Everything is built from ONE table, apps/tracer/src/canvas/mock/settings-map/catalog.ts: the owner's map of 2026-11-02, in order, Title Case. Moving a setting, renaming a window or pointing its "?" at another docs heading is a one-line edit there. Guesses are marked PLACEHOLDER, the owner's numbers OWNER.

What to try (desktop and phone):

  1. It opens on Settings › Appearance › Theme. Press the Appearance pill: the seven rows; the last pill: the windows of this row; Settings: the view list.
  2. Sidebar (top left): Settings lists the rows, and the open one lists its windows, nested.
  3. ? in a window's title pill: opens that window's docs heading as a window in the Docs cluster, which sits right of Settings (under it on a phone); Mesh › Keys opens "WireGuard session keys". A window with no page yet says so ("There is no page about this yet."): only Passkeys, Recovery, Apps, Devices, New Machines, Keys and Multiplexer have one.
  4. ⌘K: wireguard, dns, browsers stay, token, about.
  5. Mesh › Keys: type 400 in Connection Keys: refused inline; 336 h is read as 14 d; Reset appears. Machines › New Machines: a segmented choice (Install For, Sign In As) and a switch (Join The Mesh), each with its own Reset. You › Apps: the key list with Revoke (asks first). You › Devices: browsers with Sign Out.
  6. Phone: rows are columns (swipe sideways between rows, up and down between windows).

Evidence (final head, dev-02, headless Chromium)

  • Playwright, 2 specs pass, within ±0.5 px: every row flush with equal 16 px gutters; the windows of a row level and exactly equal in width (rows of 4, 3, 5, 2, 4, 2, 2 windows); no overlaps; no window name cut short; title, help, control and range on one left edge; control and Reset on one centre line; the "?" on its pill's centre line; breadcrumb pills on one centre line, centred on the screen (±1 px); sidebar glyph under its parent's name; phone targets ≥ 44 px.
  • Unit tests: 10 for the value rules, 10 for the table (the owner's map in order, Title Case, track plan for 1–5 windows, owner numbers, docs links, old sections, ⌘K rows). tsc clean.
  • Screenshots attached below: 1440×900 @2× (01–14) and 393×852 @3× (p01–p05). I looked at each; I do not judge them as final.

Findings (not fixed)

  1. Five windows in a row are a fifth of the screen (~270 px). You › Apps and the old Devices panel are cramped there (the unchanged Devices panel overlaps "iPhone" and "this device"). Options for the owner: You on two rows, or wider windows for Apps and Devices.
  2. The product caps a window's title pill at half the header (room for an input lock). Settings windows have no lock, so for the Settings view only I let the pill use the whole header (one CSS line in clusters.css); otherwise "Profile" shows as "Pr…".
  3. ⌘K matches the exact typed phrase (substring): browsers signed in finds nothing for "Browsers Stay Signed In For". Applies to every palette row.
  4. The keys docs page says "adjustable in Settings → Security", which is not where it is now.
  5. The owner's map has no window for the old Hosts panel (Extended info, host-connection lock) or the phone Toolbar panel. They have no home in this mockup (Typing holds Shortcuts only). The old ⌘K → Settings: … entries land on the nearest window.

Questions for the owner (default picked, moved on)

  • Where the "?" sits (end of the title pill now; one function, docs-button.ts) and where the Docs cluster sits (right of Settings, under it on a phone; one function buildDocsView and one argument of the flow host).
  • Placeholders: Terminal › Typing = the Shortcuts panel; Scrollback "Lines Kept" (1000–100000), Multiplexer "Offer To Switch"; Install For default System, Sign In As (Mine/Root), Join The Mesh default On; Profile, Updates, Connections, Published Services and Licences contents; the ranges you did not give (Connection Keys 1–30 d, Machine Identity 1–90 d, Add Link 1–60 min, Join Code 1–30 min).
  • Theme holds Background and both transparencies (placeholder: they had no window in your list); Layout is the old Window Sizes.
## Ready for review (second version): the owner's map, a "?" per window, a Docs cluster **Try it:** http://10.69.69.117:47650/mockups.html (first entry, #304), or directly http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections (deep links: `&at=mesh.keys`, `&at=machines.new-machines`, `&at=you.apps`, `&at=terminal.scrollback`, `&at=about`) Head `74f3eaf3c` on `settings-sections-mock-j92` (five atomic commits). Everything is built from ONE table, `apps/tracer/src/canvas/mock/settings-map/catalog.ts`: the owner's map of 2026-11-02, in order, Title Case. Moving a setting, renaming a window or pointing its "?" at another docs heading is a one-line edit there. Guesses are marked `PLACEHOLDER`, the owner's numbers `OWNER`. What to try (desktop and phone): 1. It opens on **Settings › Appearance › Theme**. Press the **Appearance** pill: the seven rows; the last pill: the windows of this row; **Settings**: the view list. 2. Sidebar (top left): **Settings** lists the rows, and the open one lists its windows, nested. 3. **?** in a window's title pill: opens that window's docs heading as a window in the **Docs** cluster, which sits right of Settings (under it on a phone); Mesh › Keys opens "WireGuard session keys". A window with no page yet says so ("There is no page about this yet."): only Passkeys, Recovery, Apps, Devices, New Machines, Keys and Multiplexer have one. 4. **⌘K**: `wireguard`, `dns`, `browsers stay`, `token`, `about`. 5. Mesh › Keys: type `400` in Connection Keys: refused inline; `336 h` is read as 14 d; Reset appears. Machines › New Machines: a segmented choice (Install For, Sign In As) and a switch (Join The Mesh), each with its own Reset. You › Apps: the key list with Revoke (asks first). You › Devices: browsers with Sign Out. 6. Phone: rows are columns (swipe sideways between rows, up and down between windows). ### Evidence (final head, dev-02, headless Chromium) - Playwright, 2 specs pass, within **±0.5 px**: every row flush with equal 16 px gutters; the windows of a row level and exactly equal in width (rows of 4, 3, 5, 2, 4, 2, 2 windows); no overlaps; no window name cut short; title, help, control and range on one left edge; control and Reset on one centre line; the "?" on its pill's centre line; breadcrumb pills on one centre line, centred on the screen (±1 px); sidebar glyph under its parent's name; phone targets ≥ 44 px. - Unit tests: 10 for the value rules, 10 for the table (the owner's map in order, Title Case, track plan for 1–5 windows, owner numbers, docs links, old sections, ⌘K rows). `tsc` clean. - Screenshots attached below: 1440×900 @2× (`01`–`14`) and 393×852 @3× (`p01`–`p05`). I looked at each; I do not judge them as final. ### Findings (not fixed) 1. **Five windows in a row are a fifth of the screen (~270 px).** You › Apps and the old Devices panel are cramped there (the unchanged Devices panel overlaps "iPhone" and "this device"). Options for the owner: You on two rows, or wider windows for Apps and Devices. 2. The product caps a window's title pill at half the header (room for an input lock). Settings windows have no lock, so for the Settings view only I let the pill use the whole header (one CSS line in `clusters.css`); otherwise "Profile" shows as "Pr…". 3. **⌘K matches the exact typed phrase** (substring): `browsers signed in` finds nothing for "Browsers Stay Signed In For". Applies to every palette row. 4. The keys docs page says "adjustable in Settings → Security", which is not where it is now. 5. The owner's map has no window for the old **Hosts** panel (Extended info, host-connection lock) or the phone **Toolbar** panel. They have no home in this mockup (Typing holds Shortcuts only). The old `⌘K → Settings: …` entries land on the nearest window. ### Questions for the owner (default picked, moved on) - **Where the "?" sits** (end of the title pill now; one function, `docs-button.ts`) and **where the Docs cluster sits** (right of Settings, under it on a phone; one function `buildDocsView` and one argument of the flow host). - Placeholders: Terminal › Typing = the Shortcuts panel; Scrollback "Lines Kept" (1000–100000), Multiplexer "Offer To Switch"; Install For default System, Sign In As (Mine/Root), Join The Mesh default On; Profile, Updates, Connections, Published Services and Licences contents; the ranges you did not give (Connection Keys 1–30 d, Machine Identity 1–90 d, Add Link 1–60 min, Join Code 1–30 min). - Theme holds Background and both transparencies (placeholder: they had no window in your list); Layout is the old Window Sizes.
Author
Owner

Finish: head 74f3eaf3cbb625e5156c2c3ff820e54931958013 on settings-sections-mock-j92 (base b0e79b31e, origin/dev)

Five atomic commits: 34e6bedeb ui: a setting row and the rules that refuse a bad value; e4cc06e47 ui: a tree leaf may sit under the leaf above it; beb346692 canvas: docs pages can open in a view of their own, and be opened by name; a4943b8e9 mockup: Settings as rows of windows; 74f3eaf3c test. 25 files, TypeScript and CSS only (0 Rust or Cargo files).

Review comment with URL, what to try, evidence, findings and questions: the previous comment on this issue. The preview is served at http://10.69.69.117:47660 (bun test double, PID 4044413 on infraternal-dev-02-std, started by me) and linked from http://10.69.69.117:47650/mockups.html.

scripts/verify fast on this head (dev-02, clean worktree, through build-slot), verbatim

+---------------------------+--------------+
| Rust gate                 | Result       |
+---------------------------+--------------+
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| test                      | FAIL (101)   |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| static builds             | PASS         |
+---------------------------+--------------+
VERIFY_EXIT=1

test failed on 10 of 764 server tests (test result: FAILED. 698 passed; 10 failed; 56 ignored): 8 in bootstrap_runtime::remote_backend::tests::* (for example The matching static infraternal binary is unavailable., Elapsed(())), enrollment::migration_tests::hostname_migration_upgrades_release6_copy_without_changing_canvas_or_checksums (left: 33 right: 32) and remote_http::tests::enrollment_http_is_bound_single_use_and_preserves_token_while_locked.

Not from this branch, shown: the same command (cargo test --workspace --locked -- bootstrap_runtime::remote_backend enrollment::migration_tests remote_http::tests::enrollment_http_is_bound_single_use, same build) on the unmodified base b0e79b31e gives test result: FAILED. 30 passed; 10 failed with the same 10 tests, and on this head the same. The diff touches no Rust. (The first version's gate, 06f46c08e, failed a different set, four restart::tests::* killed after ~57 s under load; they pass alone, 18 passed. #207 tracks that one. Both are the dev baseline, not this work.) Everything else passes, including the static builds.

Other checks on this head (dev-02)

  • tsc clean (TSC_EXIT=0), production-flag build ok.
  • Unit tests: 10 for the value rules, 10 for the table, 0 failed.
  • test/settings-sections.spec.ts: 2 passed (desktop 1440×900 @2×, phone 393×852 @3×), all alignment within ±0.5 px (details in the review comment).
  • Screenshots: attached to the previous comment (19 files).

Cleanup

Deleted my Rust target/ (the VM was at 21 GB free, below the 25 GB floor; now 94 GB) and my scratch files. Nothing of mine runs on either VM except the preview server above. Stop it with kill 4044413 when the owner has reviewed; to re-serve: bash ~/worktrees/j92-serve.sh (build: INFRATERNAL_CLUSTERS_PREVIEW=1 bun run build.ts in ~/worktrees/J92/apps/tracer).

How to test (three lines)

  1. Open http://10.69.69.117:47650/mockups.html and press "Appearance › Theme" (desktop, then the same link on a phone).
  2. Press a pill in the top bar, a "?" in a window title, then ⌘K and type wireguard.
  3. In Mesh › Keys type 400 in Connection Keys.
## Finish: head `74f3eaf3cbb625e5156c2c3ff820e54931958013` on `settings-sections-mock-j92` (base `b0e79b31e`, `origin/dev`) Five atomic commits: `34e6bedeb` ui: a setting row and the rules that refuse a bad value; `e4cc06e47` ui: a tree leaf may sit under the leaf above it; `beb346692` canvas: docs pages can open in a view of their own, and be opened by name; `a4943b8e9` mockup: Settings as rows of windows; `74f3eaf3c` test. 25 files, TypeScript and CSS only (0 Rust or Cargo files). Review comment with URL, what to try, evidence, findings and questions: the previous comment on this issue. The preview is served at http://10.69.69.117:47660 (bun test double, PID 4044413 on infraternal-dev-02-std, started by me) and linked from http://10.69.69.117:47650/mockups.html. ### `scripts/verify fast` on this head (dev-02, clean worktree, through build-slot), verbatim ``` +---------------------------+--------------+ | Rust gate | Result | +---------------------------+--------------+ | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | test | FAIL (101) | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | static builds | PASS | +---------------------------+--------------+ VERIFY_EXIT=1 ``` `test` failed on 10 of 764 server tests (`test result: FAILED. 698 passed; 10 failed; 56 ignored`): 8 in `bootstrap_runtime::remote_backend::tests::*` (for example `The matching static infraternal binary is unavailable.`, `Elapsed(())`), `enrollment::migration_tests::hostname_migration_upgrades_release6_copy_without_changing_canvas_or_checksums` (`left: 33 right: 32`) and `remote_http::tests::enrollment_http_is_bound_single_use_and_preserves_token_while_locked`. **Not from this branch, shown:** the same command (`cargo test --workspace --locked -- bootstrap_runtime::remote_backend enrollment::migration_tests remote_http::tests::enrollment_http_is_bound_single_use`, same build) on the unmodified base `b0e79b31e` gives `test result: FAILED. 30 passed; 10 failed` with the same 10 tests, and on this head the same. The diff touches no Rust. (The first version's gate, `06f46c08e`, failed a different set, four `restart::tests::*` killed after ~57 s under load; they pass alone, 18 passed. #207 tracks that one. Both are the dev baseline, not this work.) Everything else passes, including the static builds. ### Other checks on this head (dev-02) - `tsc` clean (`TSC_EXIT=0`), production-flag build ok. - Unit tests: 10 for the value rules, 10 for the table, 0 failed. - `test/settings-sections.spec.ts`: 2 passed (desktop 1440×900 @2×, phone 393×852 @3×), all alignment within ±0.5 px (details in the review comment). - Screenshots: attached to the previous comment (19 files). ### Cleanup Deleted my Rust `target/` (the VM was at 21 GB free, below the 25 GB floor; now 94 GB) and my scratch files. Nothing of mine runs on either VM except the preview server above. Stop it with `kill 4044413` when the owner has reviewed; to re-serve: `bash ~/worktrees/j92-serve.sh` (build: `INFRATERNAL_CLUSTERS_PREVIEW=1 bun run build.ts` in `~/worktrees/J92/apps/tracer`). ### How to test (three lines) 1. Open http://10.69.69.117:47650/mockups.html and press "Appearance › Theme" (desktop, then the same link on a phone). 2. Press a pill in the top bar, a "?" in a window title, then ⌘K and type `wireguard`. 3. In Mesh › Keys type `400` in Connection Keys.
Author
Owner

Owner decision applied: "?" is the first button of each window's action group

Try it: http://10.69.69.117:47650/mockups.html (first entry, #304; one more link, "With a No access card in Console"), or http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys&noaccess=1

Head 21cdaab2094f9b9ffe197549f2bc5df8083fae8c on settings-sections-mock-j92 (six atomic commits). The in-pill "?" is gone; it is now ? ◫ ⊟ ⌸ ✕ on a terminal (?, split right, split down, sessions, close), ? ✕ on an error card and on the add-host dialog, and just ? on a Settings window (a card with one action never collapses into "…").

Shortcut: the proposed keys are both taken, so I picked the free pair that D222's own rule gives

  • ⌘/ is taken (Mac): it is "Show these shortcuts" (D222). Ctrl+/ (PC) is the terminal's ^_ (undo in readline and emacs), and the panel already has Ctrl+Shift+/. Ctrl+Alt is AltGr, so it cannot be a default.
  • Proposed: ⌥⌘/ on a Mac, Ctrl+Shift+Alt+/ on a PC. D222 maps a Mac chord to the PC one by turning ⌘ into Ctrl+Shift and leaving Option as Alt (⌘⇧↩ is Ctrl+Shift+Alt+Enter). No known browser binding; not typed by the terminal; matched by the physical key because Option rewrites what "/" types; rebindable in Settings › Shortcuts. Rejected: Alt+/ and Alt+Shift+/ (readline: complete, list completions), F1 (programs in the terminal use it), Ctrl+Shift+H (history in Firefox and Edge).
  • It is registered only when the docs adapter exists (so the product, which has none, lists nothing), appears in the ? panel under Canvas ("Read about this window — Ctrl Shift Alt /", capture 15), and in ⌘K as "Read about this window" with its keys in the hint. The button, the shortcut and the ⌘K row call one function.

What it opens

The matching docs heading as a window in the Docs cluster, which sits right of Settings (under it on a phone). Settings windows read their link from the table; examples: a terminal → Multiplexer, the add-host dialog → "Host join token", a No access card → "At a glance". A window with no page yet says so ("There is no page about this yet."). A docs window itself has no "?".

Close-ups (attached): closeup-<d2|d3|p2|p3>-<settings|terminal|no-access|add-host>-<header|actions>.png

d2 = desktop DPR 2, d3 = desktop DPR 3, p2 and p3 = phone 393×852 at DPR 2 and 3. Plus 15-shortcuts-panel, 01-mesh-keys, 07-docs-cluster.

Alignment, measured (not looked at), at DPR 2 and DPR 3 on desktop and phone, ±0.5 px

For the 22 Settings windows, a terminal, the add-host dialog and a No access card: "?" is the first button; every button is one size on one centre line with equal gaps; every icon sits dead centre in its button (x and y); the group is the title pill's height and on its centre line; every group ends the same distance from its window's edge. The 20 earlier checks (rows flush, gutters, title/help/control/range on one left edge, breadcrumb centre, 44 px targets) still pass.

  • Tests: 4 Playwright tests pass; unit tests 10 (value rules) + 10 (table) + 2 (the keys collide with nothing); tsc clean.

Findings and a question

  1. Phone vs TASTE row 126 ("phone window headers carry two actions: Full screen and Close, header controls never larger than the title pill"): a phone terminal now shows ? ✕ (two actions, so within the rule) and a Settings window just ?, at the usual small size with a 44 px hit area. Nothing is added beyond two. If the owner wants the phone header untouched, the "?" can stay in ⌘K and the canvas row on phones only (one condition in frame.ts).
  2. The terminal's title pill truncates ("build-… · depl…") with the extra button: that is the product's cap of half the header (room for the input lock), unchanged. Only the Settings view lifts it.
  3. A docs page that is already open is brought into view but not made active (the reader's rule); pressing "?" twice therefore does not move focus to the docs window.
  4. Previous open findings stand (⌘K matches the exact phrase only; five windows to a row are cramped for Apps and Devices; the keys page still says "Settings → Security").
## Owner decision applied: "?" is the first button of each window's action group **Try it:** http://10.69.69.117:47650/mockups.html (first entry, #304; one more link, "With a No access card in Console"), or http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys&noaccess=1 Head `21cdaab2094f9b9ffe197549f2bc5df8083fae8c` on `settings-sections-mock-j92` (six atomic commits). The in-pill "?" is gone; it is now `? ◫ ⊟ ⌸ ✕` on a terminal (`?`, split right, split down, sessions, close), `? ✕` on an error card and on the add-host dialog, and just `?` on a Settings window (a card with one action never collapses into "…"). ### Shortcut: the proposed keys are both taken, so I picked the free pair that D222's own rule gives - **⌘/ is taken** (Mac): it is "Show these shortcuts" (D222). **Ctrl+/** (PC) is the terminal's `^_` (undo in readline and emacs), and the panel already has Ctrl+Shift+/. Ctrl+Alt is AltGr, so it cannot be a default. - **Proposed: ⌥⌘/ on a Mac, Ctrl+Shift+Alt+/ on a PC.** D222 maps a Mac chord to the PC one by turning ⌘ into Ctrl+Shift and leaving Option as Alt (⌘⇧↩ is Ctrl+Shift+Alt+Enter). No known browser binding; not typed by the terminal; matched by the physical key because Option rewrites what "/" types; rebindable in Settings › Shortcuts. Rejected: Alt+/ and Alt+Shift+/ (readline: complete, list completions), F1 (programs in the terminal use it), Ctrl+Shift+H (history in Firefox and Edge). - It is registered only when the docs adapter exists (so the product, which has none, lists nothing), appears in the `?` panel under Canvas ("Read about this window — Ctrl Shift Alt /", capture `15`), and in ⌘K as "Read about this window" with its keys in the hint. The button, the shortcut and the ⌘K row call one function. ### What it opens The matching docs heading as a window in the **Docs** cluster, which sits right of Settings (under it on a phone). Settings windows read their link from the table; examples: a terminal → Multiplexer, the add-host dialog → "Host join token", a No access card → "At a glance". A window with no page yet says so ("There is no page about this yet."). A docs window itself has no "?". ### Close-ups (attached): `closeup-<d2|d3|p2|p3>-<settings|terminal|no-access|add-host>-<header|actions>.png` d2 = desktop DPR 2, d3 = desktop DPR 3, p2 and p3 = phone 393×852 at DPR 2 and 3. Plus `15-shortcuts-panel`, `01-mesh-keys`, `07-docs-cluster`. ### Alignment, measured (not looked at), at DPR 2 and DPR 3 on desktop and phone, ±0.5 px For the 22 Settings windows, a terminal, the add-host dialog and a No access card: "?" is the first button; every button is one size on one centre line with equal gaps; every icon sits dead centre in its button (x and y); the group is the title pill's height and on its centre line; every group ends the same distance from its window's edge. The 20 earlier checks (rows flush, gutters, title/help/control/range on one left edge, breadcrumb centre, 44 px targets) still pass. - Tests: 4 Playwright tests pass; unit tests 10 (value rules) + 10 (table) + 2 (the keys collide with nothing); `tsc` clean. ### Findings and a question 1. **Phone vs TASTE row 126** ("phone window headers carry two actions: Full screen and Close, header controls never larger than the title pill"): a phone terminal now shows `? ✕` (two actions, so within the rule) and a Settings window just `?`, at the usual small size with a 44 px hit area. Nothing is added beyond two. If the owner wants the phone header untouched, the "?" can stay in ⌘K and the canvas row on phones only (one condition in `frame.ts`). 2. The terminal's title pill truncates ("build-… · depl…") with the extra button: that is the product's cap of half the header (room for the input lock), unchanged. Only the Settings view lifts it. 3. A docs page that is already open is brought into view but not made active (the reader's rule); pressing "?" twice therefore does not move focus to the docs window. 4. Previous open findings stand (⌘K matches the exact phrase only; five windows to a row are cramped for Apps and Devices; the keys page still says "Settings → Security").
Author
Owner

Finish (second round): head 21cdaab2094f9b9ffe197549f2bc5df8083fae8c on settings-sections-mock-j92 (base b0e79b31e, origin/dev)

Six atomic commits: 9b52069a1 ui: a setting row, and the rules that refuse a bad value; 76dff9d93 ui: a tree leaf may sit under the leaf above it; f480b88fc canvas: docs pages can open in a view of their own, and be opened by name; 6e21b22ff canvas: "?" is the first button of a window's action group, with a shortcut; d43d22600 mockup: Settings as rows of windows; 21cdaab20 test. 33 files, +1878/−30, TypeScript and CSS only (0 Rust or Cargo files).

Review comment (URL, what to try, the key choice and its collisions, measured alignment, findings, captures): the previous comment. Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; kill 4044413 when reviewed), linked from http://10.69.69.117:47650/mockups.html.

scripts/verify fast, dev-02, clean worktree, through build-slot, on 0bcf45321 verbatim

(The final head 21cdaab20 differs from it by one Playwright spec file: 8 lines, the add-host dialog opens with a retry. No Rust. verify fast does not run that file.)

+---------------------------+--------------+
| Rust gate                 | Result       |
+---------------------------+--------------+
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| test                      | FAIL (101)   |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| static builds             | PASS         |
+---------------------------+--------------+
VERIFY_EXIT=1

Why test failed, and why it is not this branch. This run: the linker was killed, ld returned 137 (out of memory) while linking the example mesh_revocation_fixture, error: could not compile infraternal-server, with three other jobs' gates running on the same VM ((test: 718s)). No test ran. The previous round's gate (head 74f3eaf3c) did run the tests and failed 10 server tests (698 passed; 10 failed), and I showed the same 10 fail identically on the unmodified base b0e79b31e (30 passed; 10 failed for the same filtered command, The matching static infraternal binary is unavailable, Elapsed(()), left: 33 right: 32). The first round's gate failed 4 restart::tests::* killed by wall-clock timeouts (they pass alone: 18 passed; #207). This diff contains 0 Rust/Cargo files, and 0 between 74f3eaf3c and now; so the Rust gate rows are the dev baseline, three different ways. I did not get a green test row on any head: please do not read it as green. Everything else in the table passes, including the static builds.

Other checks on the final head (dev-02)

  • tsc clean; production-flag build ok.
  • Unit tests: 10 for the value rules, 10 for the table, 2 for the shortcut keys; 0 failed.
  • test/settings-sections.spec.ts: 4 passed (desktop, phone, the "?" examples and shortcut, the close-ups at DPR 2 and 3), alignment within ±0.5 px.
  • Static D243 size: not affected (no Rust change); the gate's own report is above.

Cleanup

Deleted my Rust target/ and scratch files from dev-02 (free disk now 36 GB, other jobs' gates are using the rest). No other process of mine is running except the preview server above.

How to test (three lines)

  1. Open http://10.69.69.117:47650/mockups.html and press "Mesh › Keys" (then "With a No access card in Console").
  2. Press the "?" at the right of a window's header (or Ctrl+Shift+Alt+/, ⌥⌘/ on a Mac, or ⌘K "Read about this window").
  3. Open Console from the Settings pill, then ⌘K "add host": the "?" is first on a terminal, on the dialog and on the card.
## Finish (second round): head `21cdaab2094f9b9ffe197549f2bc5df8083fae8c` on `settings-sections-mock-j92` (base `b0e79b31e`, `origin/dev`) Six atomic commits: `9b52069a1` ui: a setting row, and the rules that refuse a bad value; `76dff9d93` ui: a tree leaf may sit under the leaf above it; `f480b88fc` canvas: docs pages can open in a view of their own, and be opened by name; `6e21b22ff` canvas: "?" is the first button of a window's action group, with a shortcut; `d43d22600` mockup: Settings as rows of windows; `21cdaab20` test. 33 files, +1878/−30, TypeScript and CSS only (0 Rust or Cargo files). Review comment (URL, what to try, the key choice and its collisions, measured alignment, findings, captures): the previous comment. Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; `kill 4044413` when reviewed), linked from http://10.69.69.117:47650/mockups.html. ### `scripts/verify fast`, dev-02, clean worktree, through build-slot, on `0bcf45321` verbatim (The final head `21cdaab20` differs from it by one Playwright spec file: 8 lines, the add-host dialog opens with a retry. No Rust. `verify fast` does not run that file.) ``` +---------------------------+--------------+ | Rust gate | Result | +---------------------------+--------------+ | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | test | FAIL (101) | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | static builds | PASS | +---------------------------+--------------+ VERIFY_EXIT=1 ``` **Why `test` failed, and why it is not this branch.** This run: the linker was killed, `ld returned 137` (out of memory) while linking the example `mesh_revocation_fixture`, `error: could not compile infraternal-server`, with three other jobs' gates running on the same VM (`(test: 718s)`). No test ran. The previous round's gate (head `74f3eaf3c`) did run the tests and failed 10 server tests (`698 passed; 10 failed`), and I showed the same 10 fail identically on the unmodified base `b0e79b31e` (`30 passed; 10 failed` for the same filtered command, `The matching static infraternal binary is unavailable`, `Elapsed(())`, `left: 33 right: 32`). The first round's gate failed 4 `restart::tests::*` killed by wall-clock timeouts (they pass alone: 18 passed; #207). This diff contains **0** Rust/Cargo files, and 0 between `74f3eaf3c` and now; so the Rust gate rows are the dev baseline, three different ways. I did not get a green `test` row on any head: please do not read it as green. Everything else in the table passes, including the static builds. ### Other checks on the final head (dev-02) - `tsc` clean; production-flag build ok. - Unit tests: 10 for the value rules, 10 for the table, 2 for the shortcut keys; 0 failed. - `test/settings-sections.spec.ts`: 4 passed (desktop, phone, the "?" examples and shortcut, the close-ups at DPR 2 and 3), alignment within ±0.5 px. - Static D243 size: not affected (no Rust change); the gate's own report is above. ### Cleanup Deleted my Rust `target/` and scratch files from dev-02 (free disk now 36 GB, other jobs' gates are using the rest). No other process of mine is running except the preview server above. ### How to test (three lines) 1. Open http://10.69.69.117:47650/mockups.html and press "Mesh › Keys" (then "With a No access card in Console"). 2. Press the "?" at the right of a window's header (or Ctrl+Shift+Alt+/, ⌥⌘/ on a Mac, or ⌘K "Read about this window"). 3. Open Console from the Settings pill, then ⌘K "add host": the "?" is first on a terminal, on the dialog and on the card.
Author
Owner

Contract note from J101 (#302), for the "?" popover: the docs build now writes quick-facts excerpts into /docs/index.json. Marker in the Markdown: > [!FACTS] directly under a heading (or under the page title for the page). Index shape: pages[].facts?: string and pages[].headings[].facts?: string, plain text, at most 320 characters, absent when the page wrote none (preview the page summary then). The same block is also shown on the page as a "Quick facts" panel. Branch docs-readable-j101.

Contract note from J101 (#302), for the "?" popover: the docs build now writes quick-facts excerpts into `/docs/index.json`. Marker in the Markdown: `> [!FACTS]` directly under a heading (or under the page title for the page). Index shape: `pages[].facts?: string` and `pages[].headings[].facts?: string`, plain text, at most 320 characters, absent when the page wrote none (preview the page `summary` then). The same block is also shown on the page as a "Quick facts" panel. Branch `docs-readable-j101`.
Author
Owner

Owner feedback applied: bigger breadcrumb, views menu in place, and "?" now opens a preview

Try it (same URL): http://10.69.69.117:47650/mockups.html (first entry, #304), or http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys&noaccess=1

Head 368136ec0 on settings-sections-mock-j92 (11 atomic commits on b0e79b31e; the four new ones are 009a758ac, f3d69d986, 72ceb042b, 368136ec0).

1. "The breadcrumbs need to be bigger" — sized like the main top pill

I measured both in the same page before changing anything. Desktop: the breadcrumb pills already had the main pill's height (41.8 px) and icon (17.6 px) and a slightly larger type size (14.85 vs 14.3 px); what made them read smaller was the dimmed ancestor names, tighter padding and gap (13.2 px against 15.4 px, 6.6 against 8.8) and, on a phone, type at 13.5 px against the main pill's 16 px. They now take the main pill's padding, gap, 1 rem icon, weight and tracking (including the mono-font override), the body type size (never below the main pill's: 14.85 px desktop, 16 px phone) and full colour for every name. On a phone the group was also about 27 px left of centre (it hugged the left of its track); it is now on the centre line. Measured at ±0.5 px: pill height, icon size, weight equal to the main pill's; the group's centre = the screen's centre (±1 px) on desktop and phone. Close-ups: closeup-<d2|d3|p2|p3>-breadcrumb.png beside closeup-…-main-pill.png.

2. "When Settings is clicked, it appears on the top left instead of in place" — fixed at the cause

The views list (and the ? shortcuts panel, the floating terminal and the palette) grow out of the top capsule. While the breadcrumb showed, I had hidden the capsule with display: none, so its rectangle was empty and the panel opened at the top left (the same bug put the ? shortcuts panel at the left edge in an earlier capture of mine). The capsule now stays in the layout as an invisible ghost with exactly the breadcrumb's rectangle, and what a morph writes on it (its fade, pointer-events, the palette's "covered" mark) is mirrored onto the breadcrumb, so all four panels start where the breadcrumb is and fade it, with no Settings code of its own. Measured on every animation frame of the open (a 900 ms recording): the panel's centre is the breadcrumb's centre and its top is the breadcrumb's top within 0.5 px, for the views list on desktop and phone and for the shortcuts panel on desktop; the breadcrumb fades to 0 while it is open and is fully visible and clickable after. Frames: morph-<d2|d3|p2|p3>-1…3.png (the breadcrumb, 60 ms, 140 ms, 320 ms after pressing Settings).
I did not touch the elastic overshoot or the scrolling in the docs window (the video shows them; another job has them).

3. "?" opens a preview, not the page

  • Press "?": a popover anchored to the button (a bottom sheet on a phone) with the heading's name, one lead sentence, two to four bullets and, for Mesh › Keys and At a glance, a small table. Expand icon at the top right opens the page as a window in the Docs cluster, at the heading. Escape or a press outside closes it; the button again closes it; Escape puts focus back on the "?"; the shortcut and ⌘K open it with focus on the expand icon (Enter expands). A window with no page yet says so in the preview, with no expand icon. No tooltip sits over it while it is open.
  • Phone sheet: handle, drag down (follows the finger 1:1) or press the dim area to close; clear of the home indicator; at most 70 % of the screen.
  • Source: the excerpt is read from the docs index, written once in the docs. I use J101's > [!FACTS] text as it is (first sentence = lead, the next ones = bullets, summary as the fallback) and propose one optional addition for tables on #302 (comment 74711, with the merge points). Until their build ships, the headings these windows point at get stand-ins in the same shape (mock/settings-map/docs-standin.ts).
  • Measured, ±0.5 px, at DPR 2 and 3 on desktop and phone, for a Settings window, a terminal, the add-host dialog and a No access card: the expand icon is on the title row's centre line, dead centre in its button, and the right-most thing in the row; title, lead, bullets and table share one left edge; a popover meets the "?" at its right edge and stays inside its window with the header's inset; a sheet has equal gutters and is at most 70 % of the screen.
  • Close-ups: closeup-<d2|d3|p2|p3>-preview-<settings|terminal|no-access|add-host>.png; whole-screen 07-preview.png, p03-preview.png, 07b-docs-cluster.png.

Tests (dev-02, final tree): 7 Playwright tests pass; unit tests: 10 for the value rules and 24 for the docs excerpt and source, the table and the shortcut keys, 0 failed; tsc clean.

Findings and questions

  1. Merge with the docs jobs (details on #302): my mock's empty docs view and J91's Docs view share an id and answer the same question; my expand icon's DocsAdapter.open becomes "fly to the page's window" there.
  2. The preview shows the page's summary (a lead only) for headings with no quick facts yet; most headings today. Quick facts per heading are what makes it useful, so writing them is the next step for the docs.
  3. The ⌘K "Read about this window" row and the shortcut open the preview, not the page: the owner may prefer them to open the page directly. One line in docs-action.ts.
  4. Unchanged and still open from before: the ⌘K phrase match, five windows to a row being cramped for Apps and Devices, the phone-header action count (TASTE row 126).
## Owner feedback applied: bigger breadcrumb, views menu in place, and "?" now opens a preview **Try it (same URL):** http://10.69.69.117:47650/mockups.html (first entry, #304), or http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys&noaccess=1 Head `368136ec0` on `settings-sections-mock-j92` (11 atomic commits on `b0e79b31e`; the four new ones are `009a758ac`, `f3d69d986`, `72ceb042b`, `368136ec0`). ### 1. "The breadcrumbs need to be bigger" — sized like the main top pill I measured both in the same page before changing anything. Desktop: the breadcrumb pills already had the main pill's height (41.8 px) and icon (17.6 px) and a slightly larger type size (14.85 vs 14.3 px); what made them read smaller was the **dimmed ancestor names**, **tighter padding and gap** (13.2 px against 15.4 px, 6.6 against 8.8) and, on a phone, **type at 13.5 px against the main pill's 16 px**. They now take the main pill's padding, gap, 1 rem icon, weight and tracking (including the mono-font override), the body type size (never below the main pill's: 14.85 px desktop, 16 px phone) and full colour for every name. On a phone the group was also about 27 px left of centre (it hugged the left of its track); it is now on the centre line. Measured at ±0.5 px: pill height, icon size, weight equal to the main pill's; the group's centre = the screen's centre (±1 px) on desktop and phone. Close-ups: `closeup-<d2|d3|p2|p3>-breadcrumb.png` beside `closeup-…-main-pill.png`. ### 2. "When Settings is clicked, it appears on the top left instead of in place" — fixed at the cause The views list (and the `?` shortcuts panel, the floating terminal and the palette) grow out of the top capsule. While the breadcrumb showed, I had hidden the capsule with `display: none`, so its rectangle was empty and the panel opened at the top left (the same bug put the `?` shortcuts panel at the left edge in an earlier capture of mine). The capsule now stays in the layout as an **invisible ghost with exactly the breadcrumb's rectangle**, and what a morph writes on it (its fade, pointer-events, the palette's "covered" mark) is mirrored onto the breadcrumb, so all four panels start where the breadcrumb is and fade it, with no Settings code of its own. Measured on every animation frame of the open (a 900 ms recording): the panel's centre is the breadcrumb's centre and its top is the breadcrumb's top within 0.5 px, for the views list on desktop and phone and for the shortcuts panel on desktop; the breadcrumb fades to 0 while it is open and is fully visible and clickable after. Frames: `morph-<d2|d3|p2|p3>-1…3.png` (the breadcrumb, 60 ms, 140 ms, 320 ms after pressing Settings). I did not touch the elastic overshoot or the scrolling in the docs window (the video shows them; another job has them). ### 3. "?" opens a preview, not the page - **Press "?"**: a popover anchored to the button (a bottom sheet on a phone) with the heading's name, one lead sentence, two to four bullets and, for Mesh › Keys and At a glance, a small table. **Expand icon at the top right** opens the page as a window in the Docs cluster, at the heading. Escape or a press outside closes it; the button again closes it; Escape puts focus back on the "?"; the shortcut and ⌘K open it with focus on the expand icon (Enter expands). A window with no page yet says so in the preview, with no expand icon. No tooltip sits over it while it is open. - **Phone sheet**: handle, drag down (follows the finger 1:1) or press the dim area to close; clear of the home indicator; at most 70 % of the screen. - **Source**: the excerpt is read from the docs index, written once in the docs. I use J101's `> [!FACTS]` text as it is (first sentence = lead, the next ones = bullets, `summary` as the fallback) and propose one optional addition for tables on #302 (comment 74711, with the merge points). Until their build ships, the headings these windows point at get stand-ins in the same shape (`mock/settings-map/docs-standin.ts`). - **Measured**, ±0.5 px, at DPR 2 and 3 on desktop and phone, for a Settings window, a terminal, the add-host dialog and a No access card: the expand icon is on the title row's centre line, dead centre in its button, and the right-most thing in the row; title, lead, bullets and table share one left edge; a popover meets the "?" at its right edge and stays inside its window with the header's inset; a sheet has equal gutters and is at most 70 % of the screen. - Close-ups: `closeup-<d2|d3|p2|p3>-preview-<settings|terminal|no-access|add-host>.png`; whole-screen `07-preview.png`, `p03-preview.png`, `07b-docs-cluster.png`. ### Tests (dev-02, final tree): 7 Playwright tests pass; unit tests: 10 for the value rules and 24 for the docs excerpt and source, the table and the shortcut keys, 0 failed; `tsc` clean. ### Findings and questions 1. **Merge with the docs jobs** (details on #302): my mock's empty `docs` view and J91's Docs view share an id and answer the same question; my expand icon's `DocsAdapter.open` becomes "fly to the page's window" there. 2. The preview shows the page's `summary` (a lead only) for headings with no quick facts yet; most headings today. Quick facts per heading are what makes it useful, so writing them is the next step for the docs. 3. The ⌘K "Read about this window" row and the shortcut open the preview, not the page: the owner may prefer them to open the page directly. One line in `docs-action.ts`. 4. Unchanged and still open from before: the `⌘K` phrase match, five windows to a row being cramped for Apps and Devices, the phone-header action count (TASTE row 126).
Author
Owner

Finish (third round): head 368136ec0d3df88f3e7fa4d6a5c899dfb53e3c0a on settings-sections-mock-j92 (base b0e79b31e, origin/dev)

11 atomic commits, TypeScript and CSS only (0 Rust or Cargo files). This round added 009a758ac (ui: a preview popover and a bottom sheet), f3d69d986 (canvas: "?" opens a preview from the docs index), 72ceb042b (mockup: the breadcrumb is the main pill's size and what grows out of the top pill grows out of it) and 368136ec0 (test).

Review comment with the results, the root causes and the 41 close-ups: the previous comment on this issue. The contract and merge points for the docs job are on #302 (comment 74711). Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; kill 4044413 when reviewed), linked from http://10.69.69.117:47650/mockups.html.

scripts/verify fast, infraternal-dev-01-compute01, clean worktree, through build-slot, on this head, verbatim

+---------------------------+--------------+
| Rust gate                 | Result       |
+---------------------------+--------------+
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| test                      | FAIL (101)   |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| static builds             | PASS         |
+---------------------------+--------------+
VERIFY_EXIT=1

test result: FAILED. 698 passed; 10 failed; 56 ignored ((test: 1077s)): the same 10 server tests as on the unmodified base b0e79b31e (8 in bootstrap_runtime::remote_backend::tests::*, enrollment::migration_tests::hostname_migration_upgrades_release6_copy_without_changing_canvas_or_checksums, remote_http::tests::enrollment_http_is_bound_single_use_and_preserves_token_while_locked). On the base, the same filtered command gives 30 passed; 10 failed with the same names (shown on this issue in the previous round); this round it fails the same way on x86 (compute01) as it did on arm (dev-02), so it is not machine-specific. This diff changes 0 Rust files. I still did not get a green test row on any head; please do not read it as green. Everything else passes, including the static builds.

Other checks (dev-02, final tree)

  • tsc clean; production-flag build ok.
  • Unit tests: 10 for the value rules; 24 for the docs excerpt and source, the table and the shortcut keys; 0 failed.
  • test/settings-sections.spec.ts: 7 passed (desktop, phone, the "?" examples and shortcut, the action-group close-ups, the preview, the breadcrumb and its morph, the breadcrumb close-ups), within ±0.5 px.

Cleanup

Deleted my Rust target/ from compute01 and dev-02 and my scratch files. Nothing of mine runs on either VM except the preview server above.

How to test (three lines)

  1. Open http://10.69.69.117:47650/mockups.html and press "Mesh › Keys (preview with a table: press ?)".
  2. Press the "?" in a window's header: a preview with the expand icon at its top right (a sheet on a phone); press the icon for the page; press the "Settings" pill in the top bar: the views list grows out of the breadcrumb, in place.
  3. Open "With a No access card in Console" and press the "?" on the card, then ⌘K "add host" and press the "?" on the dialog.
## Finish (third round): head `368136ec0d3df88f3e7fa4d6a5c899dfb53e3c0a` on `settings-sections-mock-j92` (base `b0e79b31e`, `origin/dev`) 11 atomic commits, TypeScript and CSS only (0 Rust or Cargo files). This round added `009a758ac` (ui: a preview popover and a bottom sheet), `f3d69d986` (canvas: "?" opens a preview from the docs index), `72ceb042b` (mockup: the breadcrumb is the main pill's size and what grows out of the top pill grows out of it) and `368136ec0` (test). Review comment with the results, the root causes and the 41 close-ups: the previous comment on this issue. The contract and merge points for the docs job are on #302 (comment 74711). Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; `kill 4044413` when reviewed), linked from http://10.69.69.117:47650/mockups.html. ### `scripts/verify fast`, infraternal-dev-01-compute01, clean worktree, through build-slot, on this head, verbatim ``` +---------------------------+--------------+ | Rust gate | Result | +---------------------------+--------------+ | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | test | FAIL (101) | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | static builds | PASS | +---------------------------+--------------+ VERIFY_EXIT=1 ``` `test result: FAILED. 698 passed; 10 failed; 56 ignored` (`(test: 1077s)`): the same 10 server tests as on the unmodified base `b0e79b31e` (8 in `bootstrap_runtime::remote_backend::tests::*`, `enrollment::migration_tests::hostname_migration_upgrades_release6_copy_without_changing_canvas_or_checksums`, `remote_http::tests::enrollment_http_is_bound_single_use_and_preserves_token_while_locked`). On the base, the same filtered command gives `30 passed; 10 failed` with the same names (shown on this issue in the previous round); this round it fails the same way on x86 (compute01) as it did on arm (dev-02), so it is not machine-specific. This diff changes 0 Rust files. I still did not get a green `test` row on any head; please do not read it as green. Everything else passes, including the static builds. ### Other checks (dev-02, final tree) - `tsc` clean; production-flag build ok. - Unit tests: 10 for the value rules; 24 for the docs excerpt and source, the table and the shortcut keys; 0 failed. - `test/settings-sections.spec.ts`: 7 passed (desktop, phone, the "?" examples and shortcut, the action-group close-ups, the preview, the breadcrumb and its morph, the breadcrumb close-ups), within ±0.5 px. ### Cleanup Deleted my Rust `target/` from compute01 and dev-02 and my scratch files. Nothing of mine runs on either VM except the preview server above. ### How to test (three lines) 1. Open http://10.69.69.117:47650/mockups.html and press "Mesh › Keys (preview with a table: press ?)". 2. Press the "?" in a window's header: a preview with the expand icon at its top right (a sheet on a phone); press the icon for the page; press the "Settings" pill in the top bar: the views list grows out of the breadcrumb, in place. 3. Open "With a No access card in Console" and press the "?" on the card, then ⌘K "add host" and press the "?" on the dialog.
Author
Owner

Round 2 (owner: clipped sides, popover that does not follow, narrowed windows) and items 4 to 6: results and 24 close-ups

Try it (same URLs): http://10.69.69.117:47650/mockups.html (entry #304), or http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys

Head a9fb92a36 on settings-sections-mock-j92 (base b0e79b31e). New commits this round, each one change: 8f16db6a6 (ui: popover mounted in its window), 5a86aad69 (mockup: natural widths, pill cap), ecfe45e6a (canvas: a step also stops at the bottom of a tall window), 1c84eacec (canvas: a menu opened from a pill is centred on it), 2a9519980 (mockup: Views button removed), 65043925e (mockup: windows as tall as their content), 01fcb3529 (mockup: Theme is two columns wide), the gesture fix, and the tests. 17 Playwright tests pass on dev-02 (the 7 from before and 10 new), tsc clean, unit tests pass (stops 10, settings map 9, docs 23).

1. Windows keep their natural width; the canvas scrolls

The desktop view was sized to the screen (each row split into equal parts of it). It is now one grid with a track per column of the longest row, every track the default window width; nothing reads the screen's width. A row longer than the screen is reached by the canvas pan and snap that exist (D159). Measured at 1440 x 900: every window's layout width equals another view's default width (Theme's is two columns, see below), windows of a row are level with equal gaps and a common left edge, none overlaps, the view is wider than the screen.
One thing I had to decide, please look at it: the canvas grid is one scroller only if some window crosses every seam between columns. A row's own windows never cross the seams between themselves, so the first seam could not be crossed by a left-aligned row of natural-width windows (the first column became a scroller of its own; I saw it in the first run: the first window of every row stood still while the rest moved). I gave Theme a default width of two columns (it holds a swatch grid, Background and two sliders), and the last window of each short row crosses the other seams. Rejected, with reasons in the commit: a hidden window spanning everything, a gap in one row, changing D212.

2. No clipping at any side

Cause: the title pill could use the whole header and pushed the action group out ("?" half cut). It now stops short by the group's width. Test at 1440x900, 393x852 and 1024x768: each of the 22 windows is flown into view; every control's box, grown by its focus ring (2 px + 2 px offset, measured from the computed outline after a keyboard focus), is inside its window and inside every clipping box between them (header: all four sides; body: both sides), the window is whole on screen, and the top bar's controls, pills and the MOCKUP tag are whole inside the screen with their rings. All pass within 0.5 px. Close-ups at DPR 2 (DPR 3 on the phone): edge-2x-1440x900-window-right.png, -window-left, -topbar-right, -topbar-left, -screen, the same for 1024x768 and edge-3x-393x852-*.

3. The "?" preview moves with its button

Cause: the popover floated over the screen and was placed once. It is now mounted inside the button's window and positioned in the window's own coordinates, so the camera's pan and zoom and a column's scroll move it in the same frame; no script follows. Test: open the "?" preview, pan the camera 300 px right and 300 px back, 40 frames each way, and a wheel pan; on every frame the offset between popover and button is the same within 0.5 px, the button really moved (> 250 px), and the preview closes once the button has left the screen. Frame strip: pan-strip-1..4.png.
Convention note: the existing details popover closes on any camera movement (onFrame); the shared popover now follows and closes only when its anchor leaves the screen, as the new TASTE row says. Anything else that closes on camera movement stays as it was; say if you want those changed too.

4. Menus from a pill are centred on the pill

Every breadcrumb pill's menu centre equals the pill's centre within 0.5 px at 1440x900 and 393x852 (or the screen's inset when that holds it back, which the test computes), and the grow origin is the pill's centre. The Settings pill's list (views) is centred on the Settings pill, no longer on the whole breadcrumb, and the rest of the breadcrumb fades with it. This touches the shared view list: toggle(from?), default the top pill. Captures: 20-menu-view|row|group.png, p20-menu-*.png (phone).

5. The round Views button

Removed in the mockup. I could not reproduce "does nothing": on a desktop it opens the views list (a 340 px panel under the pill), in this mockup and in the plain scene alike, so in the product it is not a button with no action; it duplicates the top pill (and the phone's toolbar row has the same item). I therefore did not touch the product canvas; there is no product-branch commit. If you want the button gone from the product as a duplicate, that is one line in toolbar/row.ts; say so and I will do it on its own branch.

6. Settings rows scroll as a whole

Every Settings window is as tall as its content (heights differ: 176 to 1080 px at 1440 wide), has no scroll area, and no element inside a window has a vertical scroll area or a scrollTop. A wheel notch steps the single grid scroller, so every one of the 22 windows moves by the same offset (measured on every step, down and up, within 0.5 px). Two consequences I handled:

  • Windows taller than the screen (Typing is 1080 px): the lock's steps went top to top, so a tall window's lower part was jumped over. A step now also stops with the bottom of a band taller than the screen in view (stepStops, pure and unit-tested). The test checks that each window's top and each window's bottom was on screen at some step. This changes product code (layout/stops.ts, columns.ts); for windows that fit, the stops are the same as before.
  • A short window leaves empty space beside a taller one and the wheel over empty space did nothing, because the step looked for a window under the pointer. A step now applies to the column or group whose extent holds the pointer (camera/gestures.ts, wheel and two-finger).
  • Phone (a column is a component, its windows stack): with the lock on, one finger now scrolls the column as a whole, two fingers still step window to window (and to a tall window's bottom first). Measured: every window of the column moves by the same offset in both, the columns beside it stand still, no window scrolls by itself. ⌘K to a setting scrolls the column or group to it (tested at 1440).
    Captures: scroll-d2-end.png, scroll-p3-column.png.

Findings

  1. The views list's "Search everything" row wraps onto two lines at 340 px (visible in 20-menu-view.png). I did not touch it; it is the shared list's width.
  2. With the lock off (free pan), a wheel over a group moves the camera, not the group (canScroll reads the column, which has no box in a group). Not touched; it is the "scrolling issue" that another job has, as far as I can tell.
  3. Phone: a one-finger vertical swipe over a Settings window used to scroll that window's pane; it now scrolls the column. If you prefer one finger to do nothing (steps only), it is one CSS line.
## Round 2 (owner: clipped sides, popover that does not follow, narrowed windows) and items 4 to 6: results and 24 close-ups **Try it (same URLs):** http://10.69.69.117:47650/mockups.html (entry #304), or http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys Head `a9fb92a36` on `settings-sections-mock-j92` (base `b0e79b31e`). New commits this round, each one change: `8f16db6a6` (ui: popover mounted in its window), `5a86aad69` (mockup: natural widths, pill cap), `ecfe45e6a` (canvas: a step also stops at the bottom of a tall window), `1c84eacec` (canvas: a menu opened from a pill is centred on it), `2a9519980` (mockup: Views button removed), `65043925e` (mockup: windows as tall as their content), `01fcb3529` (mockup: Theme is two columns wide), the gesture fix, and the tests. 17 Playwright tests pass on dev-02 (the 7 from before and 10 new), `tsc` clean, unit tests pass (stops 10, settings map 9, docs 23). ### 1. Windows keep their natural width; the canvas scrolls The desktop view was sized to the screen (each row split into equal parts of it). It is now one grid with a track per column of the longest row, every track the default window width; nothing reads the screen's width. A row longer than the screen is reached by the canvas pan and snap that exist (D159). Measured at 1440 x 900: every window's layout width equals another view's default width (Theme's is two columns, see below), windows of a row are level with equal gaps and a common left edge, none overlaps, the view is wider than the screen. **One thing I had to decide, please look at it:** the canvas grid is one scroller only if some window crosses every seam between columns. A row's own windows never cross the seams between themselves, so the first seam could not be crossed by a left-aligned row of natural-width windows (the first column became a scroller of its own; I saw it in the first run: the first window of every row stood still while the rest moved). I gave **Theme** a default width of two columns (it holds a swatch grid, Background and two sliders), and the last window of each short row crosses the other seams. Rejected, with reasons in the commit: a hidden window spanning everything, a gap in one row, changing D212. ### 2. No clipping at any side Cause: the title pill could use the whole header and pushed the action group out ("?" half cut). It now stops short by the group's width. Test at 1440x900, 393x852 and 1024x768: each of the 22 windows is flown into view; every control's box, grown by its focus ring (2 px + 2 px offset, measured from the computed outline after a keyboard focus), is inside its window and inside every clipping box between them (header: all four sides; body: both sides), the window is whole on screen, and the top bar's controls, pills and the MOCKUP tag are whole inside the screen with their rings. All pass within 0.5 px. Close-ups at DPR 2 (DPR 3 on the phone): `edge-2x-1440x900-window-right.png`, `-window-left`, `-topbar-right`, `-topbar-left`, `-screen`, the same for 1024x768 and `edge-3x-393x852-*`. ### 3. The "?" preview moves with its button Cause: the popover floated over the screen and was placed once. It is now mounted inside the button's window and positioned in the window's own coordinates, so the camera's pan and zoom and a column's scroll move it in the same frame; no script follows. Test: open the "?" preview, pan the camera 300 px right and 300 px back, 40 frames each way, and a wheel pan; on every frame the offset between popover and button is the same within 0.5 px, the button really moved (> 250 px), and the preview closes once the button has left the screen. Frame strip: `pan-strip-1..4.png`. **Convention note:** the existing details popover closes on any camera movement (`onFrame`); the shared popover now follows and closes only when its anchor leaves the screen, as the new TASTE row says. Anything else that closes on camera movement stays as it was; say if you want those changed too. ### 4. Menus from a pill are centred on the pill Every breadcrumb pill's menu centre equals the pill's centre within 0.5 px at 1440x900 and 393x852 (or the screen's inset when that holds it back, which the test computes), and the grow origin is the pill's centre. The Settings pill's list (views) is centred on the **Settings pill**, no longer on the whole breadcrumb, and the rest of the breadcrumb fades with it. This touches the shared view list: `toggle(from?)`, default the top pill. Captures: `20-menu-view|row|group.png`, `p20-menu-*.png` (phone). ### 5. The round Views button Removed in the mockup. **I could not reproduce "does nothing":** on a desktop it opens the views list (a 340 px panel under the pill), in this mockup and in the plain scene alike, so in the product it is not a button with no action; it duplicates the top pill (and the phone's toolbar row has the same item). I therefore did **not** touch the product canvas; there is no product-branch commit. If you want the button gone from the product as a duplicate, that is one line in `toolbar/row.ts`; say so and I will do it on its own branch. ### 6. Settings rows scroll as a whole Every Settings window is as tall as its content (heights differ: 176 to 1080 px at 1440 wide), has no scroll area, and no element inside a window has a vertical scroll area or a scrollTop. A wheel notch steps the single grid scroller, so every one of the 22 windows moves by the same offset (measured on every step, down and up, within 0.5 px). Two consequences I handled: - **Windows taller than the screen** (Typing is 1080 px): the lock's steps went top to top, so a tall window's lower part was jumped over. A step now also stops with the bottom of a band taller than the screen in view (`stepStops`, pure and unit-tested). The test checks that each window's top and each window's bottom was on screen at some step. **This changes product code** (`layout/stops.ts`, `columns.ts`); for windows that fit, the stops are the same as before. - **A short window leaves empty space beside a taller one** and the wheel over empty space did nothing, because the step looked for a window under the pointer. A step now applies to the column or group whose extent holds the pointer (`camera/gestures.ts`, wheel and two-finger). - **Phone** (a column is a component, its windows stack): with the lock on, one finger now scrolls the column as a whole, two fingers still step window to window (and to a tall window's bottom first). Measured: every window of the column moves by the same offset in both, the columns beside it stand still, no window scrolls by itself. ⌘K to a setting scrolls the column or group to it (tested at 1440). Captures: `scroll-d2-end.png`, `scroll-p3-column.png`. ### Findings 1. The views list's "Search everything" row wraps onto two lines at 340 px (visible in `20-menu-view.png`). I did not touch it; it is the shared list's width. 2. With the lock off (free pan), a wheel over a group moves the camera, not the group (`canScroll` reads the column, which has no box in a group). Not touched; it is the "scrolling issue" that another job has, as far as I can tell. 3. Phone: a one-finger vertical swipe over a Settings window used to scroll that window's pane; it now scrolls the column. If you prefer one finger to do nothing (steps only), it is one CSS line.
Author
Owner

Finish (round 2 and items 4 to 6)

Head a9fb92a36 on settings-sections-mock-j92 (base b0e79b31e). TypeScript and CSS only: git diff --stat b0e79b31e HEAD -- '*.rs' 'Cargo.*' is empty. The review comment with the results and 24 close-ups is the previous one on this issue. Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; kill 4044413 when reviewed), linked from http://10.69.69.117:47650/mockups.html.

scripts/verify fast, infraternal-dev-01-compute01, clean worktree, through build-slot, on this head, verbatim

+---------------------------+--------------+
| Rust gate                 | Result       |
+---------------------------+--------------+
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| test                      | FAIL (101)   |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| static builds             | PASS         |
+---------------------------+--------------+
VERIFY_EXIT=1

The test row is red and I did not get a green one. In this run cargo test stopped at the first failing binary, status_restart::service_states_are_truthful_in_text_and_json ("user/server/active: The status of part of this machine's setup is unknown."), after 459 s. That test passes alone on the same head (cargo test -p infraternal --test status_restart: 1 passed). To see the whole picture I ran the workspace with --no-fail-fast: 1752 tests passed and 21 distinct server tests failed (account_events review_revocation_r2 x4, bootstrap_runtime::remote_backend x8, enrollment migration, latest/release_payload staging x4, status/umask/restart tests, remote_http enrollment). The set differs from the 10 I reported on this branch two rounds ago and on the unmodified base, which says these tests are load- and environment-dependent on this VM; none of them touches anything this diff changes (0 Rust files, Rust tree byte-identical to the base). I did not run the base again this time. Please do not read the row as green.

Other checks (dev-02, final tree)

  • tsc clean; production-flag build ok.
  • Unit tests: stops 10 (new stepStops test), settings map 9 (grid held as one group for an administrator and a member), docs 23, value rules 10; 0 failed.
  • test/settings-sections.spec.ts: 17 passed (7 before; new: no clipped side at 1440x900, 393x852 and 1024x768; popover follows its button on a pan; menus centred on their pill at 1440 and 393; no Views button; whole-row wheel scrolling; ⌘K scroll to a setting; phone one-finger and two-finger scrolling), within 0.5 px (1 px for nothing).

Cleanup

Deleted my Rust target/ and scratch files on compute01 and dev-02; stopped my leftover test processes by PID. Nothing of mine runs on either VM except the preview server above.

Decisions I need from you

  1. Theme is two columns wide (reason in the review comment). OK, or would you rather something else cross the first seam?
  2. Views button: removed in the mockup only; in the product it opens the views list. Remove it there too as a duplicate?
  3. Phone: one finger scrolls a Settings column as a whole (two fingers still step). Keep?
## Finish (round 2 and items 4 to 6) Head `a9fb92a36` on `settings-sections-mock-j92` (base `b0e79b31e`). TypeScript and CSS only: `git diff --stat b0e79b31e HEAD -- '*.rs' 'Cargo.*'` is empty. The review comment with the results and 24 close-ups is the previous one on this issue. Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; `kill 4044413` when reviewed), linked from http://10.69.69.117:47650/mockups.html. ### `scripts/verify fast`, infraternal-dev-01-compute01, clean worktree, through build-slot, on this head, verbatim ``` +---------------------------+--------------+ | Rust gate | Result | +---------------------------+--------------+ | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | test | FAIL (101) | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | static builds | PASS | +---------------------------+--------------+ VERIFY_EXIT=1 ``` **The `test` row is red and I did not get a green one.** In this run `cargo test` stopped at the first failing binary, `status_restart::service_states_are_truthful_in_text_and_json` ("user/server/active: The status of part of this machine's setup is unknown."), after 459 s. That test **passes alone on the same head** (`cargo test -p infraternal --test status_restart`: 1 passed). To see the whole picture I ran the workspace with `--no-fail-fast`: 1752 tests passed and 21 distinct server tests failed (account_events review_revocation_r2 x4, bootstrap_runtime::remote_backend x8, enrollment migration, latest/release_payload staging x4, status/umask/restart tests, remote_http enrollment). The set differs from the 10 I reported on this branch two rounds ago and on the unmodified base, which says these tests are load- and environment-dependent on this VM; none of them touches anything this diff changes (0 Rust files, Rust tree byte-identical to the base). I did not run the base again this time. Please do not read the row as green. ### Other checks (dev-02, final tree) - `tsc` clean; production-flag build ok. - Unit tests: stops 10 (new `stepStops` test), settings map 9 (grid held as one group for an administrator and a member), docs 23, value rules 10; 0 failed. - `test/settings-sections.spec.ts`: 17 passed (7 before; new: no clipped side at 1440x900, 393x852 and 1024x768; popover follows its button on a pan; menus centred on their pill at 1440 and 393; no Views button; whole-row wheel scrolling; ⌘K scroll to a setting; phone one-finger and two-finger scrolling), within 0.5 px (1 px for nothing). ### Cleanup Deleted my Rust `target/` and scratch files on compute01 and dev-02; stopped my leftover test processes by PID. Nothing of mine runs on either VM except the preview server above. ### Decisions I need from you 1. Theme is two columns wide (reason in the review comment). OK, or would you rather something else cross the first seam? 2. Views button: removed in the mockup only; in the product it opens the views list. Remove it there too as a duplicate? 3. Phone: one finger scrolls a Settings column as a whole (two fingers still step). Keep?
Author
Owner

Round 3: windows start at the layout's size, nothing overlaps, and what I could not reconcile

Same URLs: http://10.69.69.117:47650/mockups.html (entry #304), http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys

Head 9c2762305 on settings-sections-mock-j92, rebased onto origin/dev 294042b56 (dev's own Docs view is now what the "?" opens; my own Docs view and flow-window plumbing are gone). 22 Playwright tests pass on dev-02, tsc clean, unit tests pass (stops 10, settings map and docs 33).

What was wrong

The Font-over-Theme overlap was my span hack, not the product: Theme spanned two columns and the windows that spanned were drawn at a fixed width on top of a grid that the drag then changed. All of it is removed.

1. Every window starts at the layout's size

The Settings view is plain columns, as every other view is: a column per component, its windows stacked in it, on a desktop and on a phone. Each column has defaultWidth (what a terminal window gets from Settings → Window Sizes) and each window h: 1 (one screen). No span, no band, no grid. Test: every Settings window's width equals a terminal window's width (1440x900 and 393x852; and with Window Sizes set to Wide and Full width, and Full width on the phone); its height equals the layout's height unless its content is longer. Captures: 01-mesh-keys.png (desktop), p01-mesh-keys.png (phone).

2. Scrolling, and the conflict

  • Content longer than a window. On a desktop the window grows (its height is its content's, never less than the layout's) and has no scroll area; the wheel steps the column, every window in it moves by the same offset, and the other columns stand still (tested; and every window's top and bottom, the tall one's included, was on screen at some step). I found no conflict between "full layout height" and "taller content grows": the layout's height is the minimum, not a cap. It applies only while the window is at the layout's height; a height the person set by dragging is theirs, and the pane scrolls inside it as it does everywhere.
  • Phone, owner's answer (b): one finger scrolls the content of the window under it (the pane scrolls inside; the window stays the layout's height), two fingers move the canvas, vertically a window at a time and sideways a column at a time, with the existing snap. Tested with raw touch events: one finger scrolls Typing's pane and no window moves; two fingers up step the column by one offset and the next column stands still; two fingers sideways move the canvas lock's index by one. This replaces my round-2 "one finger scrolls the column", which is removed.
  • D159 / D177: no change. D159 already says one finger inside a window scrolls its content and stops at the end, and two fingers anywhere pan the canvas in both axes; D177 says the same for the canvas lock (one finger scrolls the terminal, two fingers move windows). The owner's sentence is that rule applied to a Settings window as it is to a terminal; nothing for you to record unless you want it written down for non-terminal windows.
  • Desktop trackpad: no conflict. A two-finger swipe is a wheel, the canvas lock turns a wheel into a step (D177), and there is no inner scroll area for it to compete with. (A wheel over a terminal already goes to the canvas; the terminal's scrollback is reached through the input lock.)
  • The conflict I could not reconcile (decision for the owner): the owner's picture is a ROW of windows (a component) that scrolls down with the other rows. In the canvas, rows need the grid (D212), and the grid exists only where a window spans columns, which TASTE now rules out for a default layout. Without a span, columns are independent scrollers (and a short row leaves holes that plain columns cannot have). So a component is a column here, as it already was on the phone, and "Settings › Mesh › Keys" reads the same. If rows are wanted on a desktop, the grid needs a way to group columns without a span (a change to D212, the owner's). I did not patch around it: no hidden window, no wide window, no re-ordered components.

3. Resizing never draws one window over another

Test (1440x900 with the four edges, 393x852 with the four corner handles that a press and hold shows): each handle of three Settings windows (Theme, Keys, Certificates) is dragged in and out; on every animation frame no two window boxes intersect (the Settings, Docs and Console views are watched; what is drawn of a window counts, not what is scrolled out of its column), and the drags did change the window. Product check: the same drags on three Console terminal windows also pass on this branch. This branch changes none of the resize code (window-resize.ts, windows/frame.ts resize host, camera/ are identical to dev; the diff against dev in layout/ is only stops.ts and columns.ts, below), so I did not need a separate product commit; the overlap came from the mockup. I did not build a second copy of dev to run it there. Capture: narrowed-2x-1440x900.png (Theme narrowed by its right edge: Typing follows, nothing over anything). Skipped on the phone: up to 6 of the 24 handles lie below the screen's bottom edge for a window one screen tall.

4. Product changes kept or reverted from round 2

  • Reverted: camera/gestures.ts (a step over the empty part of a view): windows fill their columns now. Own revert commit with the reason.
  • Kept: layout/stops.ts + columns.ts (stepStops): a step also stops with the bottom of a window taller than the screen in view. It is still needed because a desktop Settings window grows with its content (Typing is 1080 px tall at 1440x900). For windows that fit it gives the same stops as before. Justified in its commit.
  • Kept: the popover mounted in its window (follows its button), menus centred on their pill; both are unaffected by this round.
  • Removed (owner answer (a)): the round Views button in the product (toolbar/row.ts, its CSS, real/rest.spec.ts presses the top pill, core-screen.spec.ts no longer lists it). The room reserved beside the top pill is two buttons now. The phone toolbar's own "Views" item stays (a different control). Commit 3276c5036; the mockup-only removal is reverted.

Findings

  1. The branch history now shows the grid era and its removal (add, then revert) rather than a squash; every commit builds. Say if you want it squashed for the merge.
  2. After the user shrinks a window below its content by dragging, the pane scrolls inside it (as everywhere); the "no inner scroller" rule is for the default.
  3. On a phone the MOCKUP tag sits over the first window's top-right edge by a few pixels (unchanged from before; it is the mockup's own label).
## Round 3: windows start at the layout's size, nothing overlaps, and what I could not reconcile Same URLs: http://10.69.69.117:47650/mockups.html (entry #304), http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys Head `9c2762305` on `settings-sections-mock-j92`, rebased onto origin/dev `294042b56` (dev's own Docs view is now what the "?" opens; my own Docs view and flow-window plumbing are gone). 22 Playwright tests pass on dev-02, `tsc` clean, unit tests pass (stops 10, settings map and docs 33). ### What was wrong The Font-over-Theme overlap was **my span hack**, not the product: Theme spanned two columns and the windows that spanned were drawn at a fixed width on top of a grid that the drag then changed. All of it is removed. ### 1. Every window starts at the layout's size The Settings view is **plain columns, as every other view is**: a column per component, its windows stacked in it, on a desktop and on a phone. Each column has `defaultWidth` (what a terminal window gets from Settings → Window Sizes) and each window `h: 1` (one screen). No span, no band, no grid. Test: every Settings window's width equals a terminal window's width (1440x900 and 393x852; and with Window Sizes set to Wide and Full width, and Full width on the phone); its height equals the layout's height unless its content is longer. Captures: `01-mesh-keys.png` (desktop), `p01-mesh-keys.png` (phone). ### 2. Scrolling, and the conflict - **Content longer than a window.** On a desktop the window **grows** (its height is its content's, never less than the layout's) and has no scroll area; the wheel steps the column, every window in it moves by the same offset, and the other columns stand still (tested; and every window's top and bottom, the tall one's included, was on screen at some step). I found no conflict between "full layout height" and "taller content grows": the layout's height is the minimum, not a cap. It applies only while the window is at the layout's height; a height the person set by dragging is theirs, and the pane scrolls inside it as it does everywhere. - **Phone, owner's answer (b):** one finger scrolls the content of the window under it (the pane scrolls inside; the window stays the layout's height), two fingers move the canvas, vertically a window at a time and sideways a column at a time, with the existing snap. Tested with raw touch events: one finger scrolls Typing's pane and **no window moves**; two fingers up step the column by one offset and the next column stands still; two fingers sideways move the canvas lock's index by one. This replaces my round-2 "one finger scrolls the column", which is removed. - **D159 / D177: no change.** D159 already says one finger inside a window scrolls its content and stops at the end, and two fingers anywhere pan the canvas in both axes; D177 says the same for the canvas lock (one finger scrolls the terminal, two fingers move windows). The owner's sentence is that rule applied to a Settings window as it is to a terminal; nothing for you to record unless you want it written down for non-terminal windows. - **Desktop trackpad:** no conflict. A two-finger swipe is a wheel, the canvas lock turns a wheel into a step (D177), and there is no inner scroll area for it to compete with. (A wheel over a terminal already goes to the canvas; the terminal's scrollback is reached through the input lock.) - **The conflict I could not reconcile (decision for the owner):** the owner's picture is a ROW of windows (a component) that scrolls down with the other rows. In the canvas, rows need the grid (D212), and the grid exists only where a window **spans** columns, which TASTE now rules out for a default layout. Without a span, columns are independent scrollers (and a short row leaves holes that plain columns cannot have). So a component is a **column** here, as it already was on the phone, and "Settings › Mesh › Keys" reads the same. If rows are wanted on a desktop, the grid needs a way to group columns without a span (a change to D212, the owner's). I did not patch around it: no hidden window, no wide window, no re-ordered components. ### 3. Resizing never draws one window over another Test (1440x900 with the four edges, 393x852 with the four corner handles that a press and hold shows): each handle of three Settings windows (Theme, Keys, Certificates) is dragged in and out; on **every animation frame** no two window boxes intersect (the Settings, Docs and Console views are watched; what is drawn of a window counts, not what is scrolled out of its column), and the drags did change the window. **Product check:** the same drags on three Console terminal windows also pass on this branch. This branch changes none of the resize code (`window-resize.ts`, `windows/frame.ts` resize host, `camera/` are identical to dev; the diff against dev in `layout/` is only `stops.ts` and `columns.ts`, below), so I did not need a separate product commit; the overlap came from the mockup. I did not build a second copy of dev to run it there. Capture: `narrowed-2x-1440x900.png` (Theme narrowed by its right edge: Typing follows, nothing over anything). Skipped on the phone: up to 6 of the 24 handles lie below the screen's bottom edge for a window one screen tall. ### 4. Product changes kept or reverted from round 2 - **Reverted:** `camera/gestures.ts` (a step over the empty part of a view): windows fill their columns now. Own revert commit with the reason. - **Kept:** `layout/stops.ts` + `columns.ts` (`stepStops`): a step also stops with the bottom of a window taller than the screen in view. It is still needed because a desktop Settings window grows with its content (Typing is 1080 px tall at 1440x900). For windows that fit it gives the same stops as before. Justified in its commit. - **Kept:** the popover mounted in its window (follows its button), menus centred on their pill; both are unaffected by this round. - **Removed (owner answer (a)):** the round Views button in the **product** (`toolbar/row.ts`, its CSS, `real/rest.spec.ts` presses the top pill, `core-screen.spec.ts` no longer lists it). The room reserved beside the top pill is two buttons now. The phone toolbar's own "Views" item stays (a different control). Commit `3276c5036`; the mockup-only removal is reverted. ### Findings 1. The branch history now shows the grid era and its removal (add, then revert) rather than a squash; every commit builds. Say if you want it squashed for the merge. 2. After the user shrinks a window below its content by dragging, the pane scrolls inside it (as everywhere); the "no inner scroller" rule is for the default. 3. On a phone the MOCKUP tag sits over the first window's top-right edge by a few pixels (unchanged from before; it is the mockup's own label).
Author
Owner

Finish (round 3)

Head 9c2762305 on settings-sections-mock-j92, rebased onto origin/dev 294042b56. TypeScript and CSS only: the diff against dev has no Rust or Cargo file. The review comment with the results and 8 captures (DPR 2: default layout, after a narrowing drag, the edges; phone DPR 3) is the previous one on this issue. Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; kill 4044413 when reviewed), linked from http://10.69.69.117:47650/mockups.html.

scripts/verify fast, infraternal-dev-01-compute01, clean worktree, through build-slot, on this head, verbatim

+---------------------------+--------------+
| Rust gate                 | Result       |
+---------------------------+--------------+
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| test                      | FAIL (101)   |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| static builds             | PASS         |
+---------------------------+--------------+
VERIFY_EXIT=1

The test row is red; I did not get a green one, and I could not reproduce dev's green. In this run cargo test stopped at the first failing binary, agent_daemon::real_binary_rootless_revocation_after_restart_stops_every_owned_terminal (scripts/test-rootless-revoke-live.py, "restart/descendant oracle failed"). That test passes alone on the same head (cargo test -p infraternal --test agent_daemon: 11 passed). The machine had four other gates running through build-slot at the time (slots 1 to 4 busy, one more queued). With --no-fail-fast on the same head: 2050 passed, 12 failed: account_events review_revocation_r2 x4, latest/release_payload private-staging x3, lookup_creates_private_staging_under_owner_restrictive_umask, restarted_latest_reclaims_metadata_after_process_stop, pending_channel_writers_preserve_authority_read_capacity, release_manifest signed identity, faithful_snapshot_preserves_public_mouse_encoder_reports. These are the same families as the last round's 21 (that set also had bootstrap_runtime::remote_backend, which now passes); they are umask, staging and timing tests and none touches anything this diff changes. Please do not read the row as green.

Other checks (dev-02, final tree)

  • tsc clean; production-flag build ok.
  • Unit tests: stops 10, settings map and docs 33 (including: every Settings window is defaultWidth wide and h: 1, no span, for an administrator and a member, at four screen sizes); 0 failed.
  • test/settings-sections.spec.ts: 22 passed. New this round: layout size (width of a terminal window, height of the layout, equal gaps, nothing over anything), Window Sizes Wide / Full width / phone Full width, the wheel through a column with a window longer than the screen (top and bottom reached), one finger and two fingers on a phone, and the edge drags (four edges at 1440x900, four corners at 393x852, three Settings windows and three terminals, no intersection on any animation frame).

Cleanup

Deleted my Rust target/ and scratch files on compute01 and dev-02. Nothing of mine runs on either VM except the preview server above.

Needs the owner

  1. Rows on a desktop need the grid to group columns without a span (D212): the one thing I could not reconcile, described in the review comment. Until then a component is a column.
  2. Squash the branch for the merge? The grid era and its removal are in the history as add and revert.
## Finish (round 3) Head `9c2762305` on `settings-sections-mock-j92`, rebased onto origin/dev `294042b56`. TypeScript and CSS only: the diff against dev has no Rust or Cargo file. The review comment with the results and 8 captures (DPR 2: default layout, after a narrowing drag, the edges; phone DPR 3) is the previous one on this issue. Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; `kill 4044413` when reviewed), linked from http://10.69.69.117:47650/mockups.html. ### `scripts/verify fast`, infraternal-dev-01-compute01, clean worktree, through build-slot, on this head, verbatim ``` +---------------------------+--------------+ | Rust gate | Result | +---------------------------+--------------+ | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | test | FAIL (101) | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | static builds | PASS | +---------------------------+--------------+ VERIFY_EXIT=1 ``` **The `test` row is red; I did not get a green one, and I could not reproduce dev's green.** In this run `cargo test` stopped at the first failing binary, `agent_daemon::real_binary_rootless_revocation_after_restart_stops_every_owned_terminal` (`scripts/test-rootless-revoke-live.py`, "restart/descendant oracle failed"). That test **passes alone on the same head** (`cargo test -p infraternal --test agent_daemon`: 11 passed). The machine had four other gates running through build-slot at the time (slots 1 to 4 busy, one more queued). With `--no-fail-fast` on the same head: 2050 passed, 12 failed: account_events `review_revocation_r2` x4, `latest`/`release_payload` private-staging x3, `lookup_creates_private_staging_under_owner_restrictive_umask`, `restarted_latest_reclaims_metadata_after_process_stop`, `pending_channel_writers_preserve_authority_read_capacity`, `release_manifest` signed identity, `faithful_snapshot_preserves_public_mouse_encoder_reports`. These are the same families as the last round's 21 (that set also had `bootstrap_runtime::remote_backend`, which now passes); they are umask, staging and timing tests and none touches anything this diff changes. Please do not read the row as green. ### Other checks (dev-02, final tree) - `tsc` clean; production-flag build ok. - Unit tests: stops 10, settings map and docs 33 (including: every Settings window is `defaultWidth` wide and `h: 1`, no span, for an administrator and a member, at four screen sizes); 0 failed. - `test/settings-sections.spec.ts`: 22 passed. New this round: layout size (width of a terminal window, height of the layout, equal gaps, nothing over anything), Window Sizes Wide / Full width / phone Full width, the wheel through a column with a window longer than the screen (top and bottom reached), one finger and two fingers on a phone, and the edge drags (four edges at 1440x900, four corners at 393x852, three Settings windows and three terminals, no intersection on any animation frame). ### Cleanup Deleted my Rust `target/` and scratch files on compute01 and dev-02. Nothing of mine runs on either VM except the preview server above. ### Needs the owner 1. Rows on a desktop need the grid to group columns without a span (D212): the one thing I could not reconcile, described in the review comment. Until then a component is a column. 2. Squash the branch for the merge? The grid era and its removal are in the history as add and revert.
Author
Owner

Round 4: one row of windows for each component, and the owner's correction

Same URLs: http://10.69.69.117:47650/mockups.html (entry #304), http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys

Head d242e28f6 on settings-sections-mock-j92, rebased onto origin/dev (c135935fa), cleaned into 15 atomic commits (the add/revert history of earlier rounds is gone; the Views-button removal commit is kept). 22 Playwright tests pass on dev-02 (2 of them flaked once under a parallel run and pass alone), tsc clean, unit tests pass (grid and layout 69 including 5 new, settings map and docs 33).

What the owner said, and what I built

"Settings - Appearance is one row which scrolls down to ... Access, no per window scrolling. they scroll up and down as groups", then, corrected: "two finger scroll to move vertically. single finger scroll should scroll inside the window." I built exactly that, and it replaces round 3's columns.

  • One row for each component. The Settings view is one grid of row groups: a track (column) for each window of the longest row, each the Window Sizes width (the width a terminal window gets), a band for each component, every window at its track and its band, one screen tall. No window spans. A row with fewer windows ends early. Test: every window's width equals a terminal window's and its height the layout's; the windows of a row are level with 12 px gaps; tracks line up from row to row; no span; nothing overlaps.
  • The layout change (D212 amendment), done in the layout, not around it. A column may now name a group (runtime only, like half); adjacent columns with the same name are one run, exactly as if a window spanned them: same DOM, steps, resize and drag. Rule changes: a cell is never covered twice, and in a row group a cell may be empty. Split right keeps the name. A view that declares row groups is arranged when it is built. 5 unit tests in grid.test.ts. Rejected alternatives are in the commit.
  • Windows keep the layout's size and scroll their own content. No window grows; I removed round 3's growth, the extra step stops (stepStops) and its CSS. A long window (Typing) scrolls inside.
  • Scrolling, desktop (D275): a wheel over content that can scroll scrolls that window only (tested: Typing's pane scrolls 50+ px, no window moves); over a pill or anything that cannot scroll it moves the canvas one row, every window of the view by the same offset, and the next row lands where this one was (tested at ±0.5 px, down and up); sideways moves to the next window of the row.
  • Phone (D159): one finger scrolls the content of the window under it and nothing else moves; two fingers up move the canvas one row (all windows by one offset), two fingers sideways move one window (the canvas lock's index +1). Tested with raw touch events.
  • Docs anchors (D317, #311): terminal/multiplexer#offer-to-switch, reference/keys#passkey | recovery-words | keys-last | browsers-stay-signed-in-for | add-link-lasts | connection-keys (Connection Keys now points at the 7-day key). Examples on a terminal, the add-host dialog and a No access card use the new paths too. Preview text comes from the docs' own [!FACTS]; stand-ins stay only for four headings that have none yet (passkey, recovery words, host join token, all keys at a glance).
  • Resizing. Each edge of three Settings windows (the corner handles on a phone) and three terminals is dragged in and out; no two window boxes intersect on any animation frame. In a row group a window's width is its track's (the windows above and below share it) and its height its band's, as in any group; that is why each window is dragged on a fresh canvas in the test. Capture: narrowed-2x-1440x900.png (Theme narrowed: Font follows, nothing over anything).

Captures (DPR 2 desktop, DPR 3 phone)

01-mesh-keys.png (default layout), strip-d2-1-before / 2-moving / 3-after.png (two rows and the scroll between them: the Appearance row and the Terminal row move as one), rows-d2-next-row.png, narrowed-2x-1440x900.png, p01-mesh-keys.png, strip-p3-1..3.png and rows-p3-next-row.png (phone: two fingers up).

Changes outside the mockup, each justified in its commit

  • layout/grid.ts, groups.on-demand.ts, model/types.ts, views/world.ts: the row group above.
  • camera/gestures.ts: a two-finger step finds its column over an empty cell (dev's wheel already did; a short row leaves empty cells).
  • ui/anchored-popover.ts: mounted inside its window so it moves with its button, and closes only when a button that was on screen has left it (a first version closed popovers opened for off-screen buttons, which broke dev's clusters-grid window-menu spec; fixed). Merged with dev's new point placement (at).
  • toolbar/viewlist.ts + viewlist.on-demand.ts: toggle(from?) so the views list is centred on the Settings pill (it follows dev's new hook/panel split).
  • toolbar/row.ts and CSS: the round Views button is removed from the product (owner answer a).

Other specs, against the dev baseline

clusters-grid.spec.ts: 9 failed on origin/dev and the same 9 fail on this head (none new). core-screen.spec.ts:151 also fails on both. sessions-canvas and sidebar-rename-remove specs I ran pass alone on both (three flaked once under load).

Findings

  1. The breadcrumb names the active window, and moving the canvas does not change which window is active (a click does). After a row step it still says "Terminal › Typing" while the You row is on screen (rows-d2-next-row.png). Same for terminals; I left it, but it reads as a bug in this view. Say if the breadcrumb should follow the row in view.
  2. The mockup tag overlaps the top-right of the first window on a phone by a few pixels (unchanged).
## Round 4: one row of windows for each component, and the owner's correction Same URLs: http://10.69.69.117:47650/mockups.html (entry #304), http://10.69.69.117:47660/?mock=1&proto=clusters&scene=3&settings=sections&at=mesh.keys Head `d242e28f6` on `settings-sections-mock-j92`, rebased onto origin/dev (`c135935fa`), cleaned into 15 atomic commits (the add/revert history of earlier rounds is gone; the Views-button removal commit is kept). 22 Playwright tests pass on dev-02 (2 of them flaked once under a parallel run and pass alone), `tsc` clean, unit tests pass (grid and layout 69 including 5 new, settings map and docs 33). ### What the owner said, and what I built "Settings - Appearance is one row which scrolls down to ... Access, no per window scrolling. they scroll up and down as groups", then, corrected: "two finger scroll to move vertically. single finger scroll should scroll inside the window." I built exactly that, and it replaces round 3's columns. - **One row for each component.** The Settings view is one grid of **row groups**: a track (column) for each window of the longest row, each the Window Sizes width (the width a terminal window gets), a band for each component, every window at its track and its band, one screen tall. **No window spans.** A row with fewer windows ends early. Test: every window's width equals a terminal window's and its height the layout's; the windows of a row are level with 12 px gaps; tracks line up from row to row; no span; nothing overlaps. - **The layout change (D212 amendment), done in the layout, not around it.** A column may now name a `group` (runtime only, like `half`); adjacent columns with the same name are one run, exactly as if a window spanned them: same DOM, steps, resize and drag. Rule changes: a cell is never covered twice, and in a row group a cell may be empty. Split right keeps the name. A view that declares row groups is arranged when it is built. 5 unit tests in `grid.test.ts`. Rejected alternatives are in the commit. - **Windows keep the layout's size and scroll their own content.** No window grows; I **removed** round 3's growth, the extra step stops (`stepStops`) and its CSS. A long window (Typing) scrolls inside. - **Scrolling, desktop (D275):** a wheel over content that can scroll scrolls that window only (tested: Typing's pane scrolls 50+ px, no window moves); over a pill or anything that cannot scroll it moves the canvas one row, **every window of the view by the same offset**, and the next row lands where this one was (tested at ±0.5 px, down and up); sideways moves to the next window of the row. - **Phone (D159):** one finger scrolls the content of the window under it and nothing else moves; two fingers up move the canvas one row (all windows by one offset), two fingers sideways move one window (the canvas lock's index +1). Tested with raw touch events. - **Docs anchors (D317, #311):** `terminal/multiplexer#offer-to-switch`, `reference/keys#passkey | recovery-words | keys-last | browsers-stay-signed-in-for | add-link-lasts | connection-keys` (Connection Keys now points at the 7-day key). Examples on a terminal, the add-host dialog and a No access card use the new paths too. Preview text comes from the docs' own `[!FACTS]`; stand-ins stay only for four headings that have none yet (passkey, recovery words, host join token, all keys at a glance). - **Resizing.** Each edge of three Settings windows (the corner handles on a phone) and three terminals is dragged in and out; no two window boxes intersect on any animation frame. In a row group a window's width is its **track's** (the windows above and below share it) and its height its **band's**, as in any group; that is why each window is dragged on a fresh canvas in the test. Capture: `narrowed-2x-1440x900.png` (Theme narrowed: Font follows, nothing over anything). ### Captures (DPR 2 desktop, DPR 3 phone) `01-mesh-keys.png` (default layout), `strip-d2-1-before / 2-moving / 3-after.png` (two rows and the scroll between them: the Appearance row and the Terminal row move as one), `rows-d2-next-row.png`, `narrowed-2x-1440x900.png`, `p01-mesh-keys.png`, `strip-p3-1..3.png` and `rows-p3-next-row.png` (phone: two fingers up). ### Changes outside the mockup, each justified in its commit - `layout/grid.ts`, `groups.on-demand.ts`, `model/types.ts`, `views/world.ts`: the row group above. - `camera/gestures.ts`: a two-finger step finds its column over an empty cell (dev's wheel already did; a short row leaves empty cells). - `ui/anchored-popover.ts`: mounted inside its window so it moves with its button, and closes only when a button that **was** on screen has left it (a first version closed popovers opened for off-screen buttons, which broke dev's `clusters-grid` window-menu spec; fixed). Merged with dev's new point placement (`at`). - `toolbar/viewlist.ts` + `viewlist.on-demand.ts`: `toggle(from?)` so the views list is centred on the Settings pill (it follows dev's new hook/panel split). - `toolbar/row.ts` and CSS: the round Views button is removed from the product (owner answer a). ### Other specs, against the dev baseline `clusters-grid.spec.ts`: 9 failed on **origin/dev** and the same 9 fail on this head (none new). `core-screen.spec.ts:151` also fails on both. `sessions-canvas` and `sidebar-rename-remove` specs I ran pass alone on both (three flaked once under load). ### Findings 1. The breadcrumb names the **active** window, and moving the canvas does not change which window is active (a click does). After a row step it still says "Terminal › Typing" while the You row is on screen (`rows-d2-next-row.png`). Same for terminals; I left it, but it reads as a bug in this view. Say if the breadcrumb should follow the row in view. 2. The mockup tag overlaps the top-right of the first window on a phone by a few pixels (unchanged).
Author
Owner

Finish (round 4)

Head c88619630 on settings-sections-mock-j92, rebased onto origin/dev c135935fa, 16 atomic commits (the Views-button removal commit is kept). TypeScript, CSS and tests only: no Rust or Cargo file. The review comment with the results and 11 captures (DPR 2 desktop, DPR 3 phone) is the previous one on this issue. Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; kill 4044413 when reviewed), linked from http://10.69.69.117:47650/mockups.html.

scripts/verify fast, infraternal-dev-01-compute01, clean worktree, through build-slot, on this head: VERIFY_EXIT=0

+---------------------------+--------------+
| Rust gate                 | Result       |
+---------------------------+--------------+
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| test                      | PASS         |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| static builds             | PASS         |
+---------------------------+--------------+
JavaScript transfer, critical: identity=1010708 gzip=315010/327680 brotli=262928/273408 bytes
JavaScript transfer, deferred: identity=174402 gzip=61071/61440 brotli=53887/55296 bytes
JavaScript transfer, onDemand largest chunk chunk-hk56g3sg.js: gzip=16223/20480 brotli=14410/18432 bytes
VERIFY_EXIT=0

The first gate run on this branch failed the transfer budget, not Rust: deferred JavaScript was 65,521 B gzip against 61,440 (dev's own 59,759). The breadcrumb and the "?" preview were static imports of the canvas. They are on-demand modules now (commit "canvas: the breadcrumb and the "?" preview load on demand, inside the deferred budget"); this whole branch costs +1,312 B of deferred gzip against dev, 369 B under the cap. J106's note applies: the next canvas feature on dev will trip it again; the ratchet is the orchestrator's.

Other checks (dev-02, final tree)

  • tsc clean; production-flag build ok.
  • Unit tests: grid and layout 69 (5 new for row groups), settings map and docs 33; 0 failed.
  • test/settings-sections.spec.ts: 22 passed.
  • Dev's own Playwright specs against this branch: clusters-grid.spec.ts 9 failed on this head and the same 9 on origin/dev; core-screen.spec.ts:151 fails on both; the window-menu, sessions-canvas, row-menu, sidebar and appwin specs I ran pass (three flaked once under a parallel run and pass alone, on both).

Cleanup

Deleted my Rust target/ and scratch files on compute01 and dev-02 and the baseline worktree; nothing of mine runs there except the preview server above.

Needs the owner

  1. The breadcrumb names the active window and a canvas move does not change it, so after a row step it still names the old row. Should it follow the row in view? (Same for terminals; unchanged.)
  2. In a row group a window's width is its track's and its height its band's, as in any group: narrowing Theme narrows every window in that column of the grid. Fine, or should a drag change only its own window?
## Finish (round 4) Head `c88619630` on `settings-sections-mock-j92`, rebased onto origin/dev `c135935fa`, 16 atomic commits (the Views-button removal commit is kept). TypeScript, CSS and tests only: no Rust or Cargo file. The review comment with the results and 11 captures (DPR 2 desktop, DPR 3 phone) is the previous one on this issue. Preview: http://10.69.69.117:47660 (PID 4044413 on infraternal-dev-02-std, mine; `kill 4044413` when reviewed), linked from http://10.69.69.117:47650/mockups.html. ### `scripts/verify fast`, infraternal-dev-01-compute01, clean worktree, through build-slot, on this head: `VERIFY_EXIT=0` ``` +---------------------------+--------------+ | Rust gate | Result | +---------------------------+--------------+ | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | test | PASS | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | static builds | PASS | +---------------------------+--------------+ JavaScript transfer, critical: identity=1010708 gzip=315010/327680 brotli=262928/273408 bytes JavaScript transfer, deferred: identity=174402 gzip=61071/61440 brotli=53887/55296 bytes JavaScript transfer, onDemand largest chunk chunk-hk56g3sg.js: gzip=16223/20480 brotli=14410/18432 bytes VERIFY_EXIT=0 ``` **The first gate run on this branch failed the transfer budget**, not Rust: deferred JavaScript was 65,521 B gzip against 61,440 (dev's own 59,759). The breadcrumb and the "?" preview were static imports of the canvas. They are on-demand modules now (commit "canvas: the breadcrumb and the "?" preview load on demand, inside the deferred budget"); this whole branch costs **+1,312 B** of deferred gzip against dev, 369 B under the cap. J106's note applies: the next canvas feature on dev will trip it again; the ratchet is the orchestrator's. ### Other checks (dev-02, final tree) - `tsc` clean; production-flag build ok. - Unit tests: grid and layout 69 (5 new for row groups), settings map and docs 33; 0 failed. - `test/settings-sections.spec.ts`: 22 passed. - Dev's own Playwright specs against this branch: `clusters-grid.spec.ts` 9 failed on this head and the same 9 on origin/dev; `core-screen.spec.ts:151` fails on both; the window-menu, sessions-canvas, row-menu, sidebar and appwin specs I ran pass (three flaked once under a parallel run and pass alone, on both). ### Cleanup Deleted my Rust `target/` and scratch files on compute01 and dev-02 and the baseline worktree; nothing of mine runs there except the preview server above. ### Needs the owner 1. The breadcrumb names the active window and a canvas move does not change it, so after a row step it still names the old row. Should it follow the row in view? (Same for terminals; unchanged.) 2. In a row group a window's width is its track's and its height its band's, as in any group: narrowing Theme narrows every window in that column of the grid. Fine, or should a drag change only its own window?
Author
Owner

J132 start and plan (make the approved Settings rows the product)

Branch settings-rows-j132, from J92's settings-sections-mock-j92 (c88619630), rebased cleanly onto origin/dev 301a05c3d (16 commits, no conflicts). Worktree ~/Developer/Worktrees/infraternal-j132 on the control host. Builds and gates go to a VM through build-slot.

Finding that needs a decision before the wiring step

The mockup's table (apps/tracer/src/canvas/mock/settings-map/catalog.ts) lists about 20 settings. On origin/dev only ONE of them has a server setting behind it: server_settings.api_key_lifetime_days (1–365, auth/security_settings.rs), which is "Keys Last". There is no server setting for: connection-key and machine-identity rotation, the certificate renewal grace period, the machine-name suffix, browser sign-in time, add-link and join-code lifetime, install mode, sign-in account, join-the-mesh, renew-early, scrollback lines, or multiplexer offer. Profile, Updates, Connections, Published Services and Licences hold made-up facts. So "wire every row to the real settings" is, for those, new server work (Rust + storage + the rule that enforces the value) in security-sensitive code, not a front-end change.

Plan (front end, on demand)

  1. Move the table, the window bodies and the model from canvas/mock/settings-map/ to a product path (canvas/views/settings-rows/), drop settingsRows/?settings=sections from mock/index.ts and mock/settings.ts. Settings always opens in rows; the product SettingsSource supplies the outline. Estimate 1.5 h.
  2. Breadcrumb follows the row in view (D323 answer 1): derive the crumb from the window at the camera's centre, not from the active window. Estimate 1 h.
  3. A resize drag changes only its own window (D323 answer 2): rework the row-group track/band sizing in layout/grid.ts so a window's width and height are its own. This is the largest layout change; estimate 2 h with grid unit tests.
  4. Wire each window to what exists: Appearance, Terminal › Typing, Devices, About, and "Keys Last" to api_key_lifetime_days through the existing security-settings API; the "?" links only to docs pages that exist (checked by a test against the docs index). Estimate 1.5 h.
  5. Specs converted to the real path at 1440×900 and 393×852, plus two new ones: breadcrumb follows the row, and a resize changes only its own window. Estimate 1.5 h.
  6. Production build, screenshots (phone and desktop, dark and light), scripts/verify fast, D188 budget lines. Estimate 1.5 h.

Total about 9 h for the front end. I stop and report at 18 h.

Not doing unless told

New server settings for the ~19 settings above. I will not show an editable control that saves nothing. Options for the orchestrator: (a) show only settings with a real backing and list the rest as "later" with one plain line; (b) open a server issue per setting and keep the control hidden until it lands; (c) approve the server work in this job and its estimate.

Other notes

  • D323 and D188 are not in DECISIONS.md on origin/dev (grep finds neither as an entry), so I am taking the two D323 answers from the job brief.
  • Budgets (D188): J92's measured deferred gzip is 61071/61440; dev has moved since. I will quote the budget lines from the rebased gate, and keep the Settings code in .on-demand.ts modules.
## J132 start and plan (make the approved Settings rows the product) Branch `settings-rows-j132`, from J92's `settings-sections-mock-j92` (c88619630), rebased cleanly onto origin/dev `301a05c3d` (16 commits, no conflicts). Worktree `~/Developer/Worktrees/infraternal-j132` on the control host. Builds and gates go to a VM through build-slot. ### Finding that needs a decision before the wiring step The mockup's table (`apps/tracer/src/canvas/mock/settings-map/catalog.ts`) lists about 20 settings. On origin/dev only ONE of them has a server setting behind it: `server_settings.api_key_lifetime_days` (1–365, `auth/security_settings.rs`), which is "Keys Last". There is no server setting for: connection-key and machine-identity rotation, the certificate renewal grace period, the machine-name suffix, browser sign-in time, add-link and join-code lifetime, install mode, sign-in account, join-the-mesh, renew-early, scrollback lines, or multiplexer offer. Profile, Updates, Connections, Published Services and Licences hold made-up facts. So "wire every row to the real settings" is, for those, new server work (Rust + storage + the rule that enforces the value) in security-sensitive code, not a front-end change. ### Plan (front end, on demand) 1. Move the table, the window bodies and the model from `canvas/mock/settings-map/` to a product path (`canvas/views/settings-rows/`), drop `settingsRows`/`?settings=sections` from `mock/index.ts` and `mock/settings.ts`. Settings always opens in rows; the product `SettingsSource` supplies the outline. Estimate 1.5 h. 2. Breadcrumb follows the row in view (D323 answer 1): derive the crumb from the window at the camera's centre, not from the active window. Estimate 1 h. 3. A resize drag changes only its own window (D323 answer 2): rework the row-group track/band sizing in `layout/grid.ts` so a window's width and height are its own. This is the largest layout change; estimate 2 h with grid unit tests. 4. Wire each window to what exists: Appearance, Terminal › Typing, Devices, About, and "Keys Last" to `api_key_lifetime_days` through the existing security-settings API; the "?" links only to docs pages that exist (checked by a test against the docs index). Estimate 1.5 h. 5. Specs converted to the real path at 1440×900 and 393×852, plus two new ones: breadcrumb follows the row, and a resize changes only its own window. Estimate 1.5 h. 6. Production build, screenshots (phone and desktop, dark and light), `scripts/verify fast`, D188 budget lines. Estimate 1.5 h. Total about 9 h for the front end. I stop and report at 18 h. ### Not doing unless told New server settings for the ~19 settings above. I will not show an editable control that saves nothing. Options for the orchestrator: (a) show only settings with a real backing and list the rest as "later" with one plain line; (b) open a server issue per setting and keep the control hidden until it lands; (c) approve the server work in this job and its estimate. ### Other notes - D323 and D188 are not in `DECISIONS.md` on origin/dev (grep finds neither as an entry), so I am taking the two D323 answers from the job brief. - Budgets (D188): J92's measured deferred gzip is 61071/61440; dev has moved since. I will quote the budget lines from the rebased gate, and keep the Settings code in `.on-demand.ts` modules.
Author
Owner

J132 progress (branch settings-rows-j132)

Owner decision taken in this job: show only backed settings. Layout kept; a setting with no backend has no control, and a window with nothing to show says "Not available yet." in one plain line.

Done on the branch (typecheck clean, 477 canvas unit tests pass on compute01)

  • Table, model and window bodies moved from canvas/mock/settings-map/ to canvas/settings-rows/. No settings=sections flag: Settings always opens in rows, in the product (product.ts) and in the mock.
  • SettingsSource gains backing(settingId) and data(component, group). The table (catalog.ts) holds no invented data any more.
  • Backed by the server: Keys Last (api_key_lifetime_days, 1–365, owner only; the write asks for a fresh passkey once and retries, as the device approval does). Backed on the client: Appearance (Theme, Font, Size, Layout), Terminal › Typing (Shortcuts + Toolbar), Terminal › Hosts (the old Hosts panel, which has no other home), You › Profile / Passkeys / Recovery (from the old Account panel), About › Version, About › Licences (AGPL-3.0-only, commercial features separate).
  • "?" links: a window shows the button only when the docs have its page; a unit test reads docs/user/ and checks every page and heading. The docs stand-in text (docs-standin.ts) is removed.
  • Breadcrumb names the row in view (window whose centre is nearest the screen centre once the camera rests; the focused window while it flies). D323 answer 1.
  • A resize drag changes only its own window in a row group (own width/height; a track is as wide as its widest window; a west drag cannot grow past the track's left edge). D323 answer 2.

Settings with no backend (each needs its own server issue)

connection-keys, machine-identity, renewal-window (Mesh › Keys); name-suffix (Mesh › Names); browser-session (You › Devices; the Devices list has no product source either); add-link, join-code, install-mode, sign-in-account, join-mesh (Machines › New Machines); renew-early (Sharing › Certificates); scrollback-lines (Terminal › Scrollback); multiplexer-offer (Terminal › Multiplexer). Windows with no data source: Machines › Updates, Mesh › Access, Mesh › Connections, Sharing › Published Services. The Mesh › Keys "Machine Authority" fact: the authority lock control is in Terminal › Hosts for now.

Not in D-files

D323 and D188 are not entries in DECISIONS.md on origin/dev; I used the two D323 answers from the job brief.

Next: Playwright specs on compute01 (running), budgets, screenshots, scripts/verify fast.

## J132 progress (branch `settings-rows-j132`) Owner decision taken in this job: **show only backed settings**. Layout kept; a setting with no backend has no control, and a window with nothing to show says "Not available yet." in one plain line. ### Done on the branch (typecheck clean, 477 canvas unit tests pass on compute01) - Table, model and window bodies moved from `canvas/mock/settings-map/` to `canvas/settings-rows/`. No `settings=sections` flag: Settings always opens in rows, in the product (`product.ts`) and in the mock. - `SettingsSource` gains `backing(settingId)` and `data(component, group)`. The table (`catalog.ts`) holds no invented data any more. - Backed by the server: **Keys Last** (`api_key_lifetime_days`, 1–365, owner only; the write asks for a fresh passkey once and retries, as the device approval does). Backed on the client: Appearance (Theme, Font, Size, Layout), Terminal › Typing (Shortcuts + Toolbar), Terminal › Hosts (the old Hosts panel, which has no other home), You › Profile / Passkeys / Recovery (from the old Account panel), About › Version, About › Licences (AGPL-3.0-only, commercial features separate). - "?" links: a window shows the button only when the docs have its page; a unit test reads `docs/user/` and checks every page and heading. The docs stand-in text (`docs-standin.ts`) is removed. - Breadcrumb names the row in view (window whose centre is nearest the screen centre once the camera rests; the focused window while it flies). D323 answer 1. - A resize drag changes only its own window in a row group (own width/height; a track is as wide as its widest window; a west drag cannot grow past the track's left edge). D323 answer 2. ### Settings with no backend (each needs its own server issue) connection-keys, machine-identity, renewal-window (Mesh › Keys); name-suffix (Mesh › Names); browser-session (You › Devices; the Devices list has no product source either); add-link, join-code, install-mode, sign-in-account, join-mesh (Machines › New Machines); renew-early (Sharing › Certificates); scrollback-lines (Terminal › Scrollback); multiplexer-offer (Terminal › Multiplexer). Windows with no data source: Machines › Updates, Mesh › Access, Mesh › Connections, Sharing › Published Services. The Mesh › Keys "Machine Authority" fact: the authority lock control is in Terminal › Hosts for now. ### Not in D-files D323 and D188 are not entries in `DECISIONS.md` on origin/dev; I used the two D323 answers from the job brief. Next: Playwright specs on compute01 (running), budgets, screenshots, `scripts/verify fast`.
Author
Owner

J132 progress 2 (head c869152f1, branch settings-rows-j132)

The two bugs found on 2026-11-04 (specs first, then fixes)

Each has a spec added before the fix (commit 2691071e6), run on that commit: 4 of 4 failed (desktop and phone, both bugs). After the fix commit the same specs pass, apart from two assertions of my own that I corrected (c869152f1).

  1. Sideways scroll into nothing. The camera's furthest left edge in a view of rows is now the row's last window plus the group's inset (camera/lock.ts rowLeftLimit). It uses the row being flown to; when a scroll or flight rests on a shorter row, the camera comes back inside. Spec: sideways scrolling stops at the end of the row, 1440×900 and 393×852.
  2. Active window leaving the view. Nav.windowInView is the one rule (the camera's stop gives the column, the band nearest the screen's middle gives the row). The breadcrumb reads it, and once the canvas rests an active window that is less than half on screen hands over to it. A change of Window Sizes frames the active window again. Spec: a layout change keeps the active window in view, and scrolling hands the focus on, both sizes.

Note: on this branch the Appearance row is Theme, Font, Size, Layout (four windows). Presets is J129's work (#323) and is not on this branch, so the specs use Layout and Theme. The row is shorter than the longest row (You, five), which is the same cause.

Needs a decision from the orchestrator

27 older Playwright tests fail on this branch because they open the old Settings windows (s-account, s-appearance, s-hosts, s-shortcuts, s-windows ...) that the mock no longer builds. Files: account-summary (4), clusters (4: lines 118, 839, 868, 1090; 118 and 1090 may also be the new "?" button on terminals), machine-sections (2), palette-polish (1), settings-edges (4), settings-query-roundtrip (2), settings-rows (6), shortcut-reset (2), sign-out (2). They are not in scripts/verify fast. Converting them to the new window ids is about 3 to 4 h more than my estimate. I have not started it.

Gate (scripts/verify fast) and the light-theme captures are queued on compute01 (position 7).

## J132 progress 2 (head `c869152f1`, branch `settings-rows-j132`) ### The two bugs found on 2026-11-04 (specs first, then fixes) Each has a spec added **before** the fix (commit `2691071e6`), run on that commit: 4 of 4 failed (desktop and phone, both bugs). After the fix commit the same specs pass, apart from two assertions of my own that I corrected (`c869152f1`). 1. **Sideways scroll into nothing.** The camera's furthest left edge in a view of rows is now the row's last window plus the group's inset (`camera/lock.ts` `rowLeftLimit`). It uses the row being flown to; when a scroll or flight rests on a shorter row, the camera comes back inside. Spec: `sideways scrolling stops at the end of the row`, 1440×900 and 393×852. 2. **Active window leaving the view.** `Nav.windowInView` is the one rule (the camera's stop gives the column, the band nearest the screen's middle gives the row). The breadcrumb reads it, and once the canvas rests an active window that is less than half on screen hands over to it. A change of Window Sizes frames the active window again. Spec: `a layout change keeps the active window in view, and scrolling hands the focus on`, both sizes. Note: on this branch the Appearance row is Theme, Font, Size, Layout (four windows). **Presets** is J129's work (#323) and is not on this branch, so the specs use Layout and Theme. The row is shorter than the longest row (You, five), which is the same cause. ### Needs a decision from the orchestrator 27 older Playwright tests fail on this branch because they open the old Settings windows (`s-account`, `s-appearance`, `s-hosts`, `s-shortcuts`, `s-windows` ...) that the mock no longer builds. Files: account-summary (4), clusters (4: lines 118, 839, 868, 1090; 118 and 1090 may also be the new "?" button on terminals), machine-sections (2), palette-polish (1), settings-edges (4), settings-query-roundtrip (2), settings-rows (6), shortcut-reset (2), sign-out (2). They are not in `scripts/verify fast`. Converting them to the new window ids is about 3 to 4 h more than my estimate. I have not started it. Gate (`scripts/verify fast`) and the light-theme captures are queued on compute01 (position 7).
Author
Owner

Deferred JS (D188): +6,118 B → +3,233 B gzip, by module

Measured with the production build on compute01, deferred class, gzip: dev 94834e0eb 54,299 B → this branch 57,532 B (cap 61,440): +3,233 B. Critical 319,051 (dev 318,146, cap 327,680); largest on-demand chunk 16,220 (cap 20,480). Per-module sizes below are the bundler's bytesInOutput (identity bytes, from the metafile); gzip is not measurable per module.

What is left in the deferred class (identity bytes, branch vs dev)

Module + B Why it has to load with the canvas
settings-rows/catalog.ts 2,199 where each setting lives: the sidebar tree, the breadcrumb and the window frames read it at start
settings-rows/model.ts 1,011 builds the Settings view (rows, tracks) and the sidebar outline
settings-rows/source.ts 890 the SettingsSource the canvas asks for the outline and a window's body
windows/frame.ts 716 "?" first button, the preloader for the own-size resize
settings-rows/product-source.ts 689 Keys Last backing, licences facts
settings-rows/docs-adapter.ts 677 which windows get a "?" and where it points
camera/lock.ts 597 stop owners, the loader for the row rules
toolbar/tree.ts 569 Settings › component › group in the sidebar
docs/docs-source.ts 388 open a page by name, look an entry up
toolbar/shortcuts.ts 322 the "?" shortcut and its row
other (pill, world, create, stops, icons, product, palette, ...) about 1,000 breadcrumb hook, row groups in the layout, wiring
Total 9,017

What I moved out (each its own commit)

Moved to an on-demand module Identity B
titles, help, allowed values of each setting (definitions.on-demand.ts) and the ⌘K rows (entries.on-demand.ts) about 7,000 (table 5,049 + rules 2,164 + rows)
the row rules: limit, window in view, follow (camera/rows.on-demand.ts) about 1,200
the own-size resize (windows/resize-rows.on-demand.ts) about 1,100 (net 700 after the loader)
the "?" action (windows/docs-action.on-demand.ts) 990
finding a window for an action, old section names (locate.on-demand.ts) about 500

Two build traps found on the way, both fixed and commented in the commits: a module imported dynamically by the canvas and statically by another on-demand module becomes a re-export chunk with no inputs, which the chunk classes count as critical (+22 KB gzip critical until fixed); and export type ... from of an on-demand module kept a chunk edge.

What pins the remaining +3.2 KB

Not the 3,000 B goal. 3.2 KB gzip is the structure the canvas needs before any Settings window exists: the table of where things live (3.2 KB identity), the Settings source and its docs adapter (2.3 KB), the sidebar tree and the "?" wiring (about 1.8 KB). Getting under +3,000 would need the sidebar's Settings subtree to build lazily (the tree shows it from the first paint, so it would appear a frame late) or the "?" wiring to wait for the first window; both change what the person sees, so I did not do them. Say if you want either.

## Deferred JS (D188): +6,118 B → +3,233 B gzip, by module Measured with the production build on compute01, deferred class, gzip: **dev `94834e0eb` 54,299 B → this branch 57,532 B (cap 61,440): +3,233 B.** Critical 319,051 (dev 318,146, cap 327,680); largest on-demand chunk 16,220 (cap 20,480). Per-module sizes below are the bundler's `bytesInOutput` (identity bytes, from the metafile); gzip is not measurable per module. ### What is left in the deferred class (identity bytes, branch vs dev) | Module | + B | Why it has to load with the canvas | |---|---|---| | `settings-rows/catalog.ts` | 2,199 | where each setting lives: the sidebar tree, the breadcrumb and the window frames read it at start | | `settings-rows/model.ts` | 1,011 | builds the Settings view (rows, tracks) and the sidebar outline | | `settings-rows/source.ts` | 890 | the `SettingsSource` the canvas asks for the outline and a window's body | | `windows/frame.ts` | 716 | "?" first button, the preloader for the own-size resize | | `settings-rows/product-source.ts` | 689 | Keys Last backing, licences facts | | `settings-rows/docs-adapter.ts` | 677 | which windows get a "?" and where it points | | `camera/lock.ts` | 597 | stop owners, the loader for the row rules | | `toolbar/tree.ts` | 569 | Settings › component › group in the sidebar | | `docs/docs-source.ts` | 388 | open a page by name, look an entry up | | `toolbar/shortcuts.ts` | 322 | the "?" shortcut and its row | | other (pill, world, create, stops, icons, product, palette, ...) | about 1,000 | breadcrumb hook, row groups in the layout, wiring | | **Total** | **9,017** | | ### What I moved out (each its own commit) | Moved to an on-demand module | Identity B | |---|---| | titles, help, allowed values of each setting (`definitions.on-demand.ts`) and the ⌘K rows (`entries.on-demand.ts`) | about 7,000 (table 5,049 + rules 2,164 + rows) | | the row rules: limit, window in view, follow (`camera/rows.on-demand.ts`) | about 1,200 | | the own-size resize (`windows/resize-rows.on-demand.ts`) | about 1,100 (net 700 after the loader) | | the "?" action (`windows/docs-action.on-demand.ts`) | 990 | | finding a window for an action, old section names (`locate.on-demand.ts`) | about 500 | Two build traps found on the way, both fixed and commented in the commits: a module imported dynamically by the canvas and statically by another on-demand module becomes a re-export chunk with no inputs, which the chunk classes count as critical (+22 KB gzip critical until fixed); and `export type ... from` of an on-demand module kept a chunk edge. ### What pins the remaining +3.2 KB Not the 3,000 B goal. 3.2 KB gzip is the structure the canvas needs before any Settings window exists: the table of where things live (3.2 KB identity), the Settings source and its docs adapter (2.3 KB), the sidebar tree and the "?" wiring (about 1.8 KB). Getting under +3,000 would need the sidebar's Settings subtree to build lazily (the tree shows it from the first paint, so it would appear a frame late) or the "?" wiring to wait for the first window; both change what the person sees, so I did not do them. Say if you want either.
Author
Owner

J132 progress 3 (head 1ae09ea71, branch settings-rows-j132)

Measured on compute01 (before the last two commits; the final run is queued):

  • scripts/verify fast's TypeScript half (ts_verify_fast, the same function the gate calls) on 168556d68: TS_VERIFY_EXIT=0. D188: critical 319,842 / 327,680 gzip (dev a89ebb0ae: 318,892), deferred 57,555 / 61,440 (dev: 54,336, so +3,219; was +6,118), largest on-demand chunk 16,214 / 20,480. The per-module table is in the previous comment.
  • The Rust half of the gate fails on different timing tests in different runs on this busy VM (remote_client::tests once, agent_daemon once). cargo test -p infraternal --test agent_daemon passes on the same head (11 passed) when it runs alone. No Rust file is changed by this branch. I am re-running the whole gate once more; if a timing test fails again I will say which, and prove it on dev.
  • Own specs on 168556d68 (dark and light): 26 of 29 pass. The 3 failures were the own-size resize specs, caused by the resize code being fetched on first pointer contact; a2061d89e fetches it at idle for Settings windows.
  • Converted older specs: 105 passed, 20 failed, 6 skipped on 168556d68. Most of the failures were palette words that also matched "Open shell on ..." rows; 1ae09ea71 uses the palette's exact labels ("Terminal › Typing"). Re-run queued (position about 9). The two sign-out.spec.ts failures are not mine: they fail identically on unmodified dev (94834e0eb).

Fixes found by the new specs, each its own commit: the end of a short row is a stop of its own (rows.on-demand.ts), measured from layout offsets and ending with the inset the longest row ends with; windowInView names a window of the row in view even when the stop's column is empty in that row.

## J132 progress 3 (head `1ae09ea71`, branch `settings-rows-j132`) **Measured on compute01 (before the last two commits; the final run is queued):** - `scripts/verify fast`'s TypeScript half (`ts_verify_fast`, the same function the gate calls) on `168556d68`: `TS_VERIFY_EXIT=0`. D188: critical 319,842 / 327,680 gzip (dev `a89ebb0ae`: 318,892), deferred 57,555 / 61,440 (dev: 54,336, so **+3,219**; was +6,118), largest on-demand chunk 16,214 / 20,480. The per-module table is in the previous comment. - The Rust half of the gate fails on different timing tests in different runs on this busy VM (`remote_client::tests` once, `agent_daemon` once). `cargo test -p infraternal --test agent_daemon` passes on the same head (11 passed) when it runs alone. No Rust file is changed by this branch. I am re-running the whole gate once more; if a timing test fails again I will say which, and prove it on dev. - Own specs on `168556d68` (dark and light): 26 of 29 pass. The 3 failures were the own-size resize specs, caused by the resize code being fetched on first pointer contact; `a2061d89e` fetches it at idle for Settings windows. - Converted older specs: 105 passed, 20 failed, 6 skipped on `168556d68`. Most of the failures were palette words that also matched "Open shell on ..." rows; `1ae09ea71` uses the palette's exact labels ("Terminal › Typing"). Re-run queued (position about 9). The two `sign-out.spec.ts` failures are not mine: they fail identically on unmodified dev (`94834e0eb`). **Fixes found by the new specs, each its own commit:** the end of a short row is a stop of its own (`rows.on-demand.ts`), measured from layout offsets and ending with the inset the longest row ends with; `windowInView` names a window of the row in view even when the stop's column is empty in that row.
Author
Owner

J132 finish: head 574037ea5 on settings-rows-j132 (the gate ran on ca248d9ba; the only change since is apps/tracer/test/palette-polish.spec.ts)

The two bugs of 2026-11-04 (captures attached to this comment, DPR 2 desktop 1440×900, DPR 3 phone 393×852, dark and light)

  • row-end-*: the last window of Appearance rests whole on screen with the inset the longest row ends with; scrolling further stays there.
  • layout-kept-*: after a wider layout the window the person was on is still in view and active.
  • active-follows-*: after scrolling on, the window in view is active and the breadcrumb names it.
    Each spec was committed before its fix and failed there (4 of 4); both are in settings-rows-of-windows.spec.ts at both sizes.

scripts/verify fast on ca248d9ba (compute01, through build-slot): VERIFY_EXIT=0

| Rust gate                 | Result       |
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| Traefik component manifest | PASS         |
| release component publication | PASS         |
| test                      | PASS         |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| doc coverage ratchet      | PASS         |
| static builds             | PASS         |
JavaScript transfer, critical: identity=1025839 gzip=319856/327680 brotli=266974/273408 bytes
JavaScript transfer, deferred: identity=160824 gzip=57562/61440 brotli=51063/55296 bytes
JavaScript transfer, onDemand largest chunk chunk-8f7379js.js: gzip=16216/20480 brotli=14368/18432 bytes
VERIFY_EXIT=0

Dev a89ebb0ae for comparison: critical 318,892, deferred 54,336, largest on-demand 16,218. Deferred is +3,226 B (was +6,118). Earlier gate runs failed in remote_client timing tests; dev's own fix for those (#334) is merged in, and with it the Rust test row passes.

Playwright, production build, 1440×900 and 393×852

  • settings-rows-of-windows.spec.ts: 29 passed, dark (mocha) and light (latte), twice each on the final head.
  • The older Settings specs, converted to the rows (commits with their reasons, ac799ea2a to 574037ea5), plus the specs that open Settings from elsewhere (account, sign-in rows, palette, shortcuts, hosts, fonts, UI size, version pill, phone gutter), 131 tests on ca248d9ba: 121 passed, 6 skipped, 4 failed. Of the 4, palette-polish is fixed since and passes (re-run alone); clusters.spec.ts:161 (camera zoom after Ctrl) I did not look into; clusters.spec.ts:1099 and shortcut-reset.spec.ts:49 are below.

Needs the owner or the orchestrator

  1. clusters.spec.ts:1099 (phone window header, 44 px touch targets) fails: a phone terminal header now holds "?", "…" and Close, and the "?" and "…" targets overlap. This comes from "?" being the first button on every terminal (J92's design). Options: no "?" in a phone header (it stays in "…" and ⌘K), or a wider spacing. I did not choose.
  2. shortcut-reset.spec.ts:49 (1440×900): after three keys are rebound the right edge of the key caps moves by 0.5 to 2.8 px (it varies from run to run) where the rule allows 0.5. Shortcuts now share the Terminal › Typing window with the toolbar panel; I did not find the cause.
  3. sign-out.spec.ts:144 and :309 fail the same way on unmodified dev 94834e0eb.
  4. settings-edges.spec.ts no longer measures the Size window (a single slider; its readout ends at the tick edge by the shared row's CSS); see that commit.
## J132 finish: head `574037ea5` on `settings-rows-j132` (the gate ran on `ca248d9ba`; the only change since is `apps/tracer/test/palette-polish.spec.ts`) ### The two bugs of 2026-11-04 (captures attached to this comment, DPR 2 desktop 1440×900, DPR 3 phone 393×852, dark and light) - `row-end-*`: the last window of Appearance rests whole on screen with the inset the longest row ends with; scrolling further stays there. - `layout-kept-*`: after a wider layout the window the person was on is still in view and active. - `active-follows-*`: after scrolling on, the window in view is active and the breadcrumb names it. Each spec was committed before its fix and failed there (4 of 4); both are in `settings-rows-of-windows.spec.ts` at both sizes. ### `scripts/verify fast` on `ca248d9ba` (compute01, through build-slot): `VERIFY_EXIT=0` ``` | Rust gate | Result | | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | Traefik component manifest | PASS | | release component publication | PASS | | test | PASS | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | doc coverage ratchet | PASS | | static builds | PASS | JavaScript transfer, critical: identity=1025839 gzip=319856/327680 brotli=266974/273408 bytes JavaScript transfer, deferred: identity=160824 gzip=57562/61440 brotli=51063/55296 bytes JavaScript transfer, onDemand largest chunk chunk-8f7379js.js: gzip=16216/20480 brotli=14368/18432 bytes VERIFY_EXIT=0 ``` Dev `a89ebb0ae` for comparison: critical 318,892, deferred 54,336, largest on-demand 16,218. Deferred is **+3,226 B** (was +6,118). Earlier gate runs failed in `remote_client` timing tests; dev's own fix for those (#334) is merged in, and with it the Rust `test` row passes. ### Playwright, production build, 1440×900 and 393×852 - `settings-rows-of-windows.spec.ts`: **29 passed**, dark (mocha) and light (latte), twice each on the final head. - The older Settings specs, converted to the rows (commits with their reasons, `ac799ea2a` to `574037ea5`), plus the specs that open Settings from elsewhere (account, sign-in rows, palette, shortcuts, hosts, fonts, UI size, version pill, phone gutter), 131 tests on `ca248d9ba`: **121 passed, 6 skipped, 4 failed**. Of the 4, `palette-polish` is fixed since and passes (re-run alone); `clusters.spec.ts:161` (camera zoom after Ctrl) I did not look into; `clusters.spec.ts:1099` and `shortcut-reset.spec.ts:49` are below. ### Needs the owner or the orchestrator 1. **`clusters.spec.ts:1099`** (phone window header, 44 px touch targets) fails: a phone terminal header now holds "?", "…" and Close, and the "?" and "…" targets overlap. This comes from "?" being the first button on every terminal (J92's design). Options: no "?" in a phone header (it stays in "…" and ⌘K), or a wider spacing. I did not choose. 2. **`shortcut-reset.spec.ts:49` (1440×900)**: after three keys are rebound the right edge of the key caps moves by 0.5 to 2.8 px (it varies from run to run) where the rule allows 0.5. Shortcuts now share the Terminal › Typing window with the toolbar panel; I did not find the cause. 3. `sign-out.spec.ts:144` and `:309` fail the same way on unmodified dev `94834e0eb`. 4. `settings-edges.spec.ts` no longer measures the Size window (a single slider; its readout ends at the tick edge by the shared row's CSS); see that commit.
Author
Owner

J132 finish: head 574037ea5 on settings-rows-j132 (the gate ran on ca248d9ba; the only change since is apps/tracer/test/palette-polish.spec.ts)

The two bugs of 2026-11-04 (captures attached to this comment, DPR 2 desktop 1440×900, DPR 3 phone 393×852, dark and light)

  • row-end-*: the last window of Appearance rests whole on screen with the inset the longest row ends with; scrolling further stays there.
  • layout-kept-*: after a wider layout the window the person was on is still in view and active.
  • active-follows-*: after scrolling on, the window in view is active and the breadcrumb names it.
    Each spec was committed before its fix and failed there (4 of 4); both are in settings-rows-of-windows.spec.ts at both sizes.

scripts/verify fast on ca248d9ba (compute01, through build-slot): VERIFY_EXIT=0

| Rust gate                 | Result       |
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| Traefik component manifest | PASS         |
| release component publication | PASS         |
| test                      | PASS         |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| doc coverage ratchet      | PASS         |
| static builds             | PASS         |
JavaScript transfer, critical: identity=1025839 gzip=319856/327680 brotli=266974/273408 bytes
JavaScript transfer, deferred: identity=160824 gzip=57562/61440 brotli=51063/55296 bytes
JavaScript transfer, onDemand largest chunk chunk-8f7379js.js: gzip=16216/20480 brotli=14368/18432 bytes
VERIFY_EXIT=0

Dev a89ebb0ae for comparison: critical 318,892, deferred 54,336, largest on-demand 16,218. Deferred is +3,226 B (was +6,118). Earlier gate runs failed in remote_client timing tests; dev's own fix for those (#334) is merged in, and with it the Rust test row passes.

Playwright, production build, 1440×900 and 393×852

  • settings-rows-of-windows.spec.ts: 29 passed, dark (mocha) and light (latte), twice each on the final head.
  • The older Settings specs, converted to the rows (commits with their reasons, ac799ea2a to 574037ea5), plus the specs that open Settings from elsewhere (account, sign-in rows, palette, shortcuts, hosts, fonts, UI size, version pill, phone gutter), 131 tests on ca248d9ba: 121 passed, 6 skipped, 4 failed. Of the 4, palette-polish is fixed since and passes (re-run alone); clusters.spec.ts:161 (camera zoom after Ctrl) I did not look into; clusters.spec.ts:1099 and shortcut-reset.spec.ts:49 are below.

Needs the owner or the orchestrator

  1. clusters.spec.ts:1099 (phone window header, 44 px touch targets) fails: a phone terminal header now holds "?", "…" and Close, and the "?" and "…" targets overlap. This comes from "?" being the first button on every terminal (J92's design). Options: no "?" in a phone header (it stays in "…" and ⌘K), or a wider spacing. I did not choose.
  2. shortcut-reset.spec.ts:49 (1440×900): after three keys are rebound the right edge of the key caps moves by 0.5 to 2.8 px (it varies from run to run) where the rule allows 0.5. Shortcuts now share the Terminal › Typing window with the toolbar panel; I did not find the cause.
  3. sign-out.spec.ts:144 and :309 fail the same way on unmodified dev 94834e0eb.
  4. settings-edges.spec.ts no longer measures the Size window (a single slider; its readout ends at the tick edge by the shared row's CSS); see that commit.
## J132 finish: head `574037ea5` on `settings-rows-j132` (the gate ran on `ca248d9ba`; the only change since is `apps/tracer/test/palette-polish.spec.ts`) ### The two bugs of 2026-11-04 (captures attached to this comment, DPR 2 desktop 1440×900, DPR 3 phone 393×852, dark and light) - `row-end-*`: the last window of Appearance rests whole on screen with the inset the longest row ends with; scrolling further stays there. - `layout-kept-*`: after a wider layout the window the person was on is still in view and active. - `active-follows-*`: after scrolling on, the window in view is active and the breadcrumb names it. Each spec was committed before its fix and failed there (4 of 4); both are in `settings-rows-of-windows.spec.ts` at both sizes. ### `scripts/verify fast` on `ca248d9ba` (compute01, through build-slot): `VERIFY_EXIT=0` ``` | Rust gate | Result | | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | Traefik component manifest | PASS | | release component publication | PASS | | test | PASS | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | doc coverage ratchet | PASS | | static builds | PASS | JavaScript transfer, critical: identity=1025839 gzip=319856/327680 brotli=266974/273408 bytes JavaScript transfer, deferred: identity=160824 gzip=57562/61440 brotli=51063/55296 bytes JavaScript transfer, onDemand largest chunk chunk-8f7379js.js: gzip=16216/20480 brotli=14368/18432 bytes VERIFY_EXIT=0 ``` Dev `a89ebb0ae` for comparison: critical 318,892, deferred 54,336, largest on-demand 16,218. Deferred is **+3,226 B** (was +6,118). Earlier gate runs failed in `remote_client` timing tests; dev's own fix for those (#334) is merged in, and with it the Rust `test` row passes. ### Playwright, production build, 1440×900 and 393×852 - `settings-rows-of-windows.spec.ts`: **29 passed**, dark (mocha) and light (latte), twice each on the final head. - The older Settings specs, converted to the rows (commits with their reasons, `ac799ea2a` to `574037ea5`), plus the specs that open Settings from elsewhere (account, sign-in rows, palette, shortcuts, hosts, fonts, UI size, version pill, phone gutter), 131 tests on `ca248d9ba`: **121 passed, 6 skipped, 4 failed**. Of the 4, `palette-polish` is fixed since and passes (re-run alone); `clusters.spec.ts:161` (camera zoom after Ctrl) I did not look into; `clusters.spec.ts:1099` and `shortcut-reset.spec.ts:49` are below. ### Needs the owner or the orchestrator 1. **`clusters.spec.ts:1099`** (phone window header, 44 px touch targets) fails: a phone terminal header now holds "?", "…" and Close, and the "?" and "…" targets overlap. This comes from "?" being the first button on every terminal (J92's design). Options: no "?" in a phone header (it stays in "…" and ⌘K), or a wider spacing. I did not choose. 2. **`shortcut-reset.spec.ts:49` (1440×900)**: after three keys are rebound the right edge of the key caps moves by 0.5 to 2.8 px (it varies from run to run) where the rule allows 0.5. Shortcuts now share the Terminal › Typing window with the toolbar panel; I did not find the cause. 3. `sign-out.spec.ts:144` and `:309` fail the same way on unmodified dev `94834e0eb`. 4. `settings-edges.spec.ts` no longer measures the Size window (a single slider; its readout ends at the tick edge by the shared row's CSS); see that commit.
Author
Owner

J211 start: branch settings-followups-j211, base a6d0223bf. Plan: (1) phone terminal header without "?" (done, pushed), (2) clusters.spec.ts:161 and (3) shortcut-reset.spec.ts:49: find which side is wrong, then verify quick + fast.

J211 start: branch `settings-followups-j211`, base `a6d0223bf`. Plan: (1) phone terminal header without "?" (done, pushed), (2) clusters.spec.ts:161 and (3) shortcut-reset.spec.ts:49: find which side is wrong, then verify quick + fast.
Author
Owner

J211 progress.

  • #1 (96fe7bc9f, pushed): a terminal's header on a touch device no longer gets "?" (only Close); desktop and non-terminal windows (Settings: "?" alone) unchanged. clusters.spec.ts "window header actions are one pill" passes on a production build (compute01, 1440×900 context + phone).
  • #2 clusters.spec.ts:161 — the product is wrong, narrowly. It failed 1 run in 9 (8/8 pass on re-run). The only async step is gestures.ts fetching the free-canvas chunk when the lock turns off (D188): a wheel that lands before it arrives is preventDefaulted and dropped (canvasWheel: if (free) … else e.preventDefault()). Spec added first (80f17b837, scripts delayed 1.5 s); fix (hold the wheel, play it when the chunk lands) follows.
  • #3 shortcut-reset.spec.ts:49: investigating.
J211 progress. - **#1 (`96fe7bc9f`, pushed):** a terminal's header on a touch device no longer gets "?" (only Close); desktop and non-terminal windows (Settings: "?" alone) unchanged. `clusters.spec.ts` "window header actions are one pill" passes on a production build (compute01, 1440×900 context + phone). - **#2 `clusters.spec.ts:161` — the product is wrong, narrowly.** It failed 1 run in 9 (8/8 pass on re-run). The only async step is `gestures.ts` fetching the free-canvas chunk when the lock turns off (D188): a wheel that lands before it arrives is `preventDefault`ed and dropped (`canvasWheel`: `if (free) … else e.preventDefault()`). Spec added first (`80f17b837`, scripts delayed 1.5 s); fix (hold the wheel, play it when the chunk lands) follows. - **#3 `shortcut-reset.spec.ts:49`:** investigating.
Author
Owner

J211 progress 2 (branch settings-followups-j211, head aa80cbe72).

  • #2 clusters.spec.ts:161 was the product. New spec 80f17b837 (scripts delayed 1.5 s so the free-canvas chunk is late) failed there ("Expected < 1, Received 1"); fix d28cf9b51 (hold the wheel while the chunk loads, play it when it lands) makes it pass; with the original 161 test, 6/6 (3 repeats each).
  • #3 shortcut-reset.spec.ts:49 was the spec. The failing line is not the "caps on one edge" check (that passed every run) but "the edge did not move": it compared the first row's right edge on the page before and after rebinding, and the window was still settling on the canvas. Received 2.8, 7.5 and 78.5 px in three runs. aa80cbe72 measures from the window's own left edge. 8/8 pass (4 repeats × 1440×900 and 393×852).
  • verify quick: QUICK_EXIT=0. First verify fast on aa80cbe72: every row PASS except test FAIL (101): infraternal-plugin-ssh --test install interrupted_upgrade_after_acknowledged_stop_restarts_the_previous_service ("Setup is already running on this host"), in code this branch does not touch. Run alone 5 times: 5/5 pass. Re-running the full gate.
J211 progress 2 (branch `settings-followups-j211`, head `aa80cbe72`). - **#2 `clusters.spec.ts:161` was the product.** New spec `80f17b837` (scripts delayed 1.5 s so the free-canvas chunk is late) **failed** there ("Expected < 1, Received 1"); fix `d28cf9b51` (hold the wheel while the chunk loads, play it when it lands) makes it pass; with the original 161 test, 6/6 (3 repeats each). - **#3 `shortcut-reset.spec.ts:49` was the spec.** The failing line is not the "caps on one edge" check (that passed every run) but "the edge did not move": it compared the first row's right edge *on the page* before and after rebinding, and the window was still settling on the canvas. Received 2.8, 7.5 and 78.5 px in three runs. `aa80cbe72` measures from the window's own left edge. 8/8 pass (4 repeats × 1440×900 and 393×852). - `verify quick`: `QUICK_EXIT=0`. First `verify fast` on `aa80cbe72`: every row PASS except `test` FAIL (101): `infraternal-plugin-ssh --test install interrupted_upgrade_after_acknowledged_stop_restarts_the_previous_service` ("Setup is already running on this host"), in code this branch does not touch. Run alone 5 times: 5/5 pass. Re-running the full gate.
Author
Owner

J211 finish: head aa80cbe72 on settings-followups-j211 (base a6d0223bf, not merged). Four commits: 96fe7bc9f phone header, 80f17b837 + d28cf9b51 wheel spec then fix, aa80cbe72 shortcut-reset spec.

scripts/verify quick: QUICK_EXIT=0. scripts/verify fast (compute01, build-slot), second run; the first failed on a flaky unrelated test, see the previous comment

| Rust gate                 | Result       |
+---------------------------+--------------+
| fmt                       | PASS         |
| VT native fmt             | PASS         |
| CLI plugin compile-out    | PASS         |
| clippy                    | PASS         |
| SSH runtime test helper   | PASS         |
| real-binary fixture paths | PASS         |
| Traefik component manifest | PASS         |
| release component publication | PASS         |
| test                      | PASS         |
| SSH inode reuse fixture   | PASS         |
| shim process-per-user     | PASS         |
| cargo-deny                | PASS         |
| gate architecture         | PASS         |
| doc coverage ratchet      | PASS         |
| static builds             | PASS         |
+---------------------------+--------------+
JavaScript transfer, critical: identity=1029455 gzip=321134/327680 brotli=268219/273408 bytes
JavaScript transfer, deferred: identity=161020 gzip=57638/61440 brotli=51231/55296 bytes
JavaScript transfer, onDemand: identity=431568 gzip=172837/20480 brotli=153616/18432 bytes
JavaScript transfer, onDemand largest chunk chunk-g9bny97s.js: gzip=16213/20480 brotli=14365/18432 bytes (class total gzip=172837 brotli=153616, not limited)
VERIFY_EXIT=0

Playwright (production build, compute01): window-header spec (phone 393×852 touch context) passes; new wheel spec and the original :161 6/6; shortcut-reset 8/8 (1440×900 and 393×852, 4 repeats). Caveat: these specs run in the ink theme only, and I did not capture screenshots (no visual change except the missing "?" in a phone terminal header). Dark/light were not run separately.

Decisions for the orchestrator: (1) with "?" gone from a phone terminal header there is no "…" any more (Close alone never folds), so "?" lives in ⌘K ("Read about this window") only, not in a "…" menu as the task text said; getting it into the canvas row is the D350 build. (2) Not in this branch: D350 is not in DECISIONS.md at this base.

J211 finish: head `aa80cbe72` on `settings-followups-j211` (base `a6d0223bf`, not merged). Four commits: `96fe7bc9f` phone header, `80f17b837` + `d28cf9b51` wheel spec then fix, `aa80cbe72` shortcut-reset spec. ### `scripts/verify quick`: `QUICK_EXIT=0`. `scripts/verify fast` (compute01, build-slot), second run; the first failed on a flaky unrelated test, see the previous comment ``` | Rust gate | Result | +---------------------------+--------------+ | fmt | PASS | | VT native fmt | PASS | | CLI plugin compile-out | PASS | | clippy | PASS | | SSH runtime test helper | PASS | | real-binary fixture paths | PASS | | Traefik component manifest | PASS | | release component publication | PASS | | test | PASS | | SSH inode reuse fixture | PASS | | shim process-per-user | PASS | | cargo-deny | PASS | | gate architecture | PASS | | doc coverage ratchet | PASS | | static builds | PASS | +---------------------------+--------------+ JavaScript transfer, critical: identity=1029455 gzip=321134/327680 brotli=268219/273408 bytes JavaScript transfer, deferred: identity=161020 gzip=57638/61440 brotli=51231/55296 bytes JavaScript transfer, onDemand: identity=431568 gzip=172837/20480 brotli=153616/18432 bytes JavaScript transfer, onDemand largest chunk chunk-g9bny97s.js: gzip=16213/20480 brotli=14365/18432 bytes (class total gzip=172837 brotli=153616, not limited) VERIFY_EXIT=0 ``` Playwright (production build, compute01): window-header spec (phone 393×852 touch context) passes; new wheel spec and the original :161 6/6; shortcut-reset 8/8 (1440×900 and 393×852, 4 repeats). Caveat: these specs run in the ink theme only, and I did not capture screenshots (no visual change except the missing "?" in a phone terminal header). Dark/light were not run separately. Decisions for the orchestrator: (1) with "?" gone from a phone terminal header there is no "…" any more (Close alone never folds), so "?" lives in ⌘K ("Read about this window") only, not in a "…" menu as the task text said; getting it into the canvas row is the D350 build. (2) Not in this branch: D350 is not in DECISIONS.md at this base.
Sign in to join this conversation.
No labels
launch-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/infraternal#304
No description provided.