Skip to content

feat: expand dashboard fonts with preview picker - #540

Merged
m-aebrer merged 7 commits into
aebrer:masterfrom
Anjiro81:feature/issue-510-font-catalog-preview-picker
Oct 8, 2026
Merged

m-aebrer merged 7 commits into
aebrer:masterfrom
Anjiro81:feature/issue-510-font-catalog-preview-picker

Conversation

@Anjiro81

@Anjiro81 Anjiro81 commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Closes #510

Add 15 popular Latin serif and 15 popular Latin sans-serif fonts to Dashboard, preserving all six existing choices and Theme default (36 explicit fonts plus Theme default).

Render each font choice in its own typeface using an accessible preview picker. Preserve browser-local appearance preferences and reasonable font-loading behavior. Every added family must have real regular, italic, bold, and bold-italic styles; preview faces load progressively as options approach the visible scroll window.

Manual font uploads and dedicated multilingual font bundles are explicitly excluded; existing multilingual browser/system fallback remains intact.

Revised implementation plan: #540 (comment)
Approved scope update: #510 (comment)

Requirement amendment (native core styles, replacements, overhead measurements): #540 (comment)

@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Implementation Plan

Problem analysis and scope authority

Issue #510 requires a materially broader licensed Dashboard font catalog, direct previews for each picker option, keyboard accessibility, preserved appearance persistence, and catalog/rendering tests with reasonable loading behavior.

The current catalog has six explicit families plus Theme default. Its native <select> displays plain labels; theme cards preview only the committed font. Native option typography is not consistently controllable across OS/browser menus, so a focused custom font listbox is needed for reliable previews.

The requester explicitly chose “Catalog and preview picker only; handle uploads separately.” No font-upload storage, file API, server/RPC protocol, theme-color editor, TUI theme mapping, or general-purpose component-library refactor is included.

Base inspected: upstream master e5a8b0a8f0b81f3c10cbba48927e661af6fe5c30. Existing appearance behavior, IDs, storage keys, fallback stacks, and theme-card isolation must remain compatible.

Deliverables

1. Expand the curated catalog and package compliant assets

  • Add Source Code Pro, Roboto Mono, Inconsolata, Inter, Source Sans 3, and Source Serif 4: three additional monospace choices, two sans-serif choices, and one serif choice. This doubles explicit choices to twelve, plus Theme default.
  • Preserve all existing IDs and labels. Keep deterministic picker order, with Theme default first and existing accessible families still clearly identified.
  • Add the intended CSS family/stack information needed to render each option reliably; keep the public preference a stable font ID.
  • Bundle local WOFF2 faces covering regular and emphasized Dashboard weights, with real italics where available. Document genuine upstream limitations such as Inconsolata's lack of an italic face.
  • Prefer unmodified upstream WOFF2 when available. If conversion/subsetting is needed, record the exact source revision, source checksum, commands/tools, transformations, resulting checksum, coverage, and retained axes.
  • Include upstream licenses/copyright notices in the repository and npm package. Do not reuse Reserved Font Names in modified font binaries. For the Source families, use unmodified artifacts or compliant renamed derivatives, clearly documented as such. Respect internal naming notices as well as standalone license files; CSS aliases alone are not a substitute for compliant internal names.
  • Source availability and OFL licensing were verified in google/fonts at immutable commit 9710da1eacb3be272583c3224dcb70f9da6eadbb; upstream project records are available in each family's METADATA.pb. This is a concrete acquisition reference, not a requirement to use larger TTF payloads unchanged.
  • Record before/after bundled and preview payload sizes. Do not add eager global preload or a runtime font dependency.

2. Build an accessible, per-font preview picker

  • Add a focused SolidJS FontPicker integrated into ThemeGallery, replacing only the font selector. Leave the native color-mode selector and theme selection surface unchanged.
  • Use an accessible select-only combobox/listbox interaction: labelled trigger, expanded/controls relationships, stable option IDs, selected/active state, and one clearly identified name per option.
  • Render each visible option name using its own font stack at a regular preview weight. The committed trigger also displays the selected preference clearly.
  • Separate temporary navigation from committed font preference: navigating options must not change the whole Dashboard or write localStorage until selection is committed.
  • Support pointer/touch selection, ArrowUp/ArrowDown, Home/End, prefix typeahead, Enter/Space commit, Escape cancellation, outside dismissal, ordinary Tab/Shift+Tab exit, and correct focus restoration. Scroll the highlighted item into view. Tear down global listeners/timers on close/unmount.
  • Keep popup width/height bounded by the viewport; provide usable mobile targets and a scrollable catalog without horizontal overflow.
  • Preview Theme default using the active theme's built-in family, even if an explicit font currently overrides the page. Do not mutate theme/font state just to calculate a preview.

3. Preserve appearance and loading contracts

  • Extend FontId, catalog validation, FONT_IDS, CSS mappings, and the synchronous index.html bootstrap allowlist together.
  • Continue using dreb.dashboard.font, guarded storage, default-key removal, invalid-value fallback, and existing cross-tab reconciliation. Existing preferences continue restoring without migration.
  • Keep theme, color mode, and explicit font independent. Selecting Theme default restores theme typography; theme cards retain their existing deliberate IBM baseline when no explicit override is chosen.
  • Mount preview options only while the picker is open, so opening Settings with a closed picker does not fetch every font. Opening it may fetch the regular preview face for each family; inactive bold/italic faces must remain lazy.
  • Reopening uses browser caching. Closing/canceling must not commit changes. Missing/unavailable font resources must leave names readable through fallback stacks without breaking selection/navigation.
  • Preserve the existing Google-hosted IBM Plex behavior; self-hosting it is not part of this change.

4. Tests and documentation as part of the feature

  • Add focused component tests for the picker rather than growing general Settings tests for every internal detail.
  • Add a real Solid/Vite/Playwright fixture rendering production ThemeGallery/FontPicker and styles. Reuse the existing settings-layout fixture/server conventions; jsdom cannot prove webfont rendering or network loading.
  • Keep existing appearance/first-frame/browser tests working with the expanded catalog and changed selector semantics.
  • Update root README, coding-agent README, Dashboard README, Dashboard appearance documentation, and font provenance descriptions. Distinguish closed-picker lazy loading from deliberate open-menu previews.

Acceptance criteria

  1. The picker offers the twelve explicit font families above plus Theme default, retaining every existing choice and stable ID.
  2. Every visible font option directly renders in its intended typeface when that face is available; font names remain readable, and Theme default reflects the active theme's built-in typography.
  3. Font selection remains browser-local and independent of theme/color mode. Restore, cross-tab changes, default reset, unavailable storage, and invalid stored values preserve current behavior.
  4. The picker is keyboard accessible and usable with mouse/touch, with correct active/selected state, cancellation, dismissal, and focus handling.
  5. Added assets have recorded immutable provenance, accurate transformation/name/coverage notes, hashes, and redistributed license/copyright files included in the published package.
  6. Closed-picker Settings startup does not request unused new families. Opening previews requests regular preview faces, not every inactive weight/style. Payload and request behavior are measured and documented.
  7. Catalog, picker behavior, actual browser previews/loading, bootstrap restoration, and mobile layout have automated coverage; checks/build/full offline tests/workspace-link verification pass.

Files to create or modify

Client state and UI

  • packages/dashboard/src/client/state/appearance.ts: expanded catalog/type validation and preview family metadata or small associated helper; preserve persistence APIs.
  • packages/dashboard/src/client/components/font-picker.tsx (new): focused accessible preview selector and lifecycle handling.
  • packages/dashboard/src/client/components/theme-gallery.tsx: integrate the picker and preserve current preview-card behavior.
  • packages/dashboard/src/client/styles/app.css: trigger, popup, option, highlighted/selected, focus, and mobile styles.
  • packages/dashboard/src/client/styles/themes.css: additional font faces and explicit root/scoped overrides.
  • packages/dashboard/src/client/index.html: expanded early-restore allowlist.

Assets and redistribution

  • packages/dashboard/src/client/assets/fonts/: added WOFF2 faces plus family license/provenance records; update older records where their loading descriptions become inaccurate.
  • packages/dashboard/package.json: include new license/provenance records in the package files allowlist.

Tests and fixtures

  • packages/dashboard/test/client/font-picker.test.tsx (new): focused component interaction/accessibility/persistence tests.
  • packages/dashboard/test/client/font-picker.browser.test.ts (new): production Solid fixture, browser typography/loading, keyboard and mobile verification.
  • packages/dashboard/test/client/fixtures/font-picker.html and font-picker.tsx (new): mount the production appearance controls with shipped styles, with no server/RPC runtime required.
  • packages/dashboard/test/client/appearance.test.ts: expanded catalog, family metadata consistency, all-ID restoration/bootstrap and packaging/provenance contracts.
  • packages/dashboard/test/client/screens.test.tsx: migrate native font-select assertions to the actual picker; keep settings-load-failure and selected-font/theme integration coverage.
  • packages/dashboard/test/client/appearance.browser.test.ts: add new active-font families/coverage expectations and retain existing isolated lazy-loading/first-frame contracts.

Documentation

  • README.md
  • packages/coding-agent/README.md
  • packages/dashboard/README.md
  • packages/coding-agent/docs/dashboard.md
  • Font provenance records affected by the new open-picker loading behavior.

No server, RPC, service-worker policy, or host-upload change is expected. Vite's existing font fingerprinting and same-origin static caching remain sufficient.

Testing approach

  1. Catalog and state: unique IDs/labels, expected twelve explicit choices, CSS family metadata/override consistency, all added IDs valid and restorable, unchanged existing IDs/default semantics, storage failures, cross-tab synchronization, bootstrap allowlist equivalence.
  2. Component: accessible label/roles/state; click/open/commit; no commitment during arrow/Home/End/typeahead navigation; active option scrolling; Enter/Space selection; Escape leaves preference unchanged; Tab exits without trapping; outside pointer dismissal; repeated open/close and unmount cleanup; reactive changes to selected preference/theme while mounted.
  3. Rendered browser previews: render the production picker via Vite, open it, wait for fonts, verify each option's resolved family and successful face load using representative text. Distinguish real loading from fallback-only CSS declarations. Exercise Theme default under Gruvbox and a non-Gruvbox theme while an explicit override is active.
  4. Network/loading: fresh browser contexts; capture font requests before opening, after opening, after selecting, and after reopen. Closed menu does not request unused added families; regular previews are requested when opened, unused italic/emphasis faces are not. Simulated font-fetch failure keeps names/navigation usable.
  5. Responsive/accessibility: desktop and narrow mobile viewport; popup and options fit horizontally, internal scrolling reveals the last option, keyboard focus remains visible, controls have usable touch targets. Verify Escape does not leak into unrelated global handlers.
  6. Assets/package: verify provenance hashes, representative glyph coverage/fallbacks, weight/style declarations, and presence of all new legal/provenance files in npm pack --dry-run --json output (disable lifecycle scripts for inspection if necessary). Include any needed inspection helper in tests or reproducible tooling rather than relying only on manual assertions.
  7. Repository validation: run focused tests during implementation, npm run check, npm run build, npm run verify-workspace-links, and complete offline npm test. Build before a real-Dashboard smoke check. Do not enable live provider tests.

Risks and remaining implementation checks

  • Reserved font names are an actual acquisition constraint, especially for Source Code Pro/Source Sans 3 and Source Serif's internal notices. Select compliant artifacts or properly rename modified binaries; do not omit the family silently.
  • A custom picker trades native accessibility for controllable rendering, so keyboard/focus/screen-reader semantics need deliberate tests. Keep this component narrowly scoped and dependency-free.
  • Previewing all choices intentionally increases open-menu requests; do not let it increase ordinary Settings startup or download every font variant.
  • Proportional fonts change line widths; retain glyph fallback and check controls/code/mobile layout rather than treating all families as monospace.
  • Bootstrap literals and existing hard-coded tests can drift during expansion; contract tests must cover the complete catalog.
  • Exact asset payload depends on source faces and processing. Report measured sizes and adjust the processing, not the approved family list or scope, if inefficient artifacts are found.

Plan created by mach6

@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Revised Implementation Plan — expanded additive catalog

This plan supersedes the earlier twelve-font plan: #540 (comment).

Scope authority and problem

Issue #510 requires a materially broader licensed font catalog, per-option typeface previews, accessible keyboard selection, preserved appearance preferences, and automated coverage with reasonable loading/payload.

The requester subsequently asked for 15 serif and 15 sans-serif Latin fonts and explicitly required that all existing choices remain available. The approved scope update is recorded at #510 (comment).

We will add thirty families, not replace existing ones: 36 explicit fonts plus Theme default. Existing IDs/labels, localStorage keys, defaults, theme behavior, and multilingual system/browser fallback remain compatible. Manual uploads, dedicated multilingual font bundles, IBM Plex self-hosting, theme-color editing, TUI changes, server/RPC changes, and a general-purpose component library are out of scope.

The existing native font selector renders plain names; per-option font styling is inconsistent in native OS menus. A focused accessible preview listbox will replace only that control.

Deliverable 1 — additive catalog and compliant assets

Keep these six choices unchanged: IBM Plex Mono, JetBrains Mono, Fira Code, Iosevka, OpenDyslexic, Atkinson Hyperlegible. Also retain Theme default.

Add fifteen sans-serif families:

  1. Roboto
  2. Open Sans
  3. Google Sans
  4. Inter
  5. Montserrat
  6. Poppins
  7. Lato
  8. Roboto Condensed
  9. Arimo
  10. Oswald
  11. Noto Sans
  12. DM Sans
  13. Raleway
  14. Nunito
  15. Nunito Sans

Add fifteen serif families:

  1. Playfair Display
  2. Roboto Slab
  3. Merriweather
  4. Lora
  5. Noto Serif
  6. Cormorant Garamond
  7. Libre Baskerville
  8. PT Serif
  9. Instrument Serif
  10. EB Garamond
  11. Fraunces
  12. Bitter
  13. DM Serif Display
  14. Source Serif 4
  15. Newsreader

Selection evidence: Google's public catalog metadata at https://fonts.google.com/metadata/fonts, retrieved 2026-10-02, exposes a popularity ordering. The lists above follow that ordering within serif/sans-serif families supporting Latin, excluding dedicated non-Latin-script variants such as Noto Sans JP/KR and Noto Serif JP. Poppins remains a common Latin choice despite also supporting Devanagari. This is a dated popularity-based selection, not a claim that global rankings never change; ordering is frozen, not fetched at runtime.

Available source fonts/licenses were verified at immutable google/fonts commit 9710da1eacb3be272583c3224dcb70f9da6eadbb. Roboto Slab there uses Apache 2.0; the other selected families use OFL. Preserve relevant copyright/license/trademark notices, including Google Sans TRADEMARKS.md.

  • Bundle Latin-focused WOFF2 assets with regular/emphasized weights and real italic where available. Use variable axes efficiently where appropriate; document upright-only families such as Oswald/Roboto Slab and genuine style/weight limitations rather than pretending synthetic faces are real.
  • Prefer unmodified official webfont artifacts where naming restrictions make modification awkward. If converting/subsetting, comply with Reserved Font Names and internal notices through correctly renamed derivatives or explicit upstream permissions. CSS aliases alone do not fix internal naming violations. Google Sans trademark restrictions require particular care; use original-authorized names/artifacts without implying sponsorship.
  • For every family record immutable source/reference, source and output checksums, license, exact processing commands/tool versions, naming decisions, glyph coverage, supported weights/styles/axes, and measured sizes.
  • Include every legal/provenance record in npm redistribution, not just the repository. Add reproducible acquisition/inspection tooling if needed for this larger batch; no runtime font dependency.
  • Preserve general punctuation, accented Latin, code text, and existing fallback behavior. Do not bundle CJK or other dedicated script payloads merely because upstream fonts support them.

Deliverable 2 — accessible preview picker

  • Add a focused SolidJS FontPicker integrated into ThemeGallery; leave color mode and theme controls unchanged.
  • Offer clearly labelled sections for existing choices, new sans-serif choices, and new serif choices, with Theme default first. Section headings are not selectable options; every actual choice has a stable ID, accessible name, active/selected state, and its own typeface preview.
  • Use a labelled select-only combobox/listbox pattern with expanded/controls relationships. Keep temporary keyboard highlight separate from committed preference: navigation does not change Dashboard typography or storage until commitment.
  • Support mouse/touch, ArrowUp/Down, Home/End, prefix typeahead, Enter/Space selection, Escape cancellation, outside dismissal, normal Tab/Shift+Tab exit, active-option scrolling, and appropriate focus restoration. Remove listeners/timers on close/unmount and prevent Escape leakage to unrelated handlers.
  • Bound popup width/height to the viewport, with internal scrolling and usable mobile targets; all 37 choices must remain reachable.
  • Render option names at a regular preview weight. Preview Theme default using the active theme's built-in family even when an explicit override is selected, without mutating state. The closed trigger clearly identifies the committed preference.

Deliverable 3 — persistence and loading compatibility

  • Update catalog types/IDs, validation, preview-family metadata, CSS overrides/faces, and synchronous bootstrap allowlist together.
  • Preserve dreb.dashboard.font, guarded storage, default removal, invalid-value fallback, cross-tab synchronization, existing saved values, and independent theme/color-mode choices.
  • Keep current theme-card behavior: Theme default cards retain their deliberate baseline; committed explicit fonts propagate to previews.
  • Render font-option previews only while the picker is open. Closed-picker Settings startup must not fetch unused added families. Opening may load regular preview faces for the catalog, but must not also fetch every inactive italic/emphasis variant.
  • Account for variable faces combining weights: those bytes are one face, not an extra weight request. Measure before/after package and open-picker payload rather than inventing an unapproved arbitrary budget.
  • Reopen should reuse cache. Font-load failure keeps names readable with fallback and does not break keyboard navigation or selection. Existing multilingual fallback remains available.

Deliverable 4 — tests and documentation

  • Keep unit/component tests focused and add real-browser tests rendering production Solid components/styles, not copied fake picker markup.
  • Update all documentation listing fonts/loading behavior: root README, coding-agent README, Dashboard README, Dashboard appearance docs, and provenance records whose lazy-loading description changes.
  • Clearly distinguish closed-picker startup loading from intentional open-menu previews and explain Latin coverage/fallback. Do not describe new proportional families as monospace.

Acceptance criteria

  1. All six existing choices retain IDs/labels/behavior; all thirty listed additions are selectable: 36 explicit fonts plus Theme default.
  2. Every option previews its intended typeface when available, including theme-dependent Theme default; fallback names remain readable on failed loads.
  3. Selection persists and restores per browser without migration, independent of theme/mode; default reset, invalid storage, storage errors, and cross-tab updates remain correct.
  4. All choices are reachable by pointer/touch and keyboard with correct semantics, highlight/commit separation, dismissal, scrolling, and focus behavior on desktop/mobile.
  5. Assets have accurate immutable provenance/checksums, naming/license/trademark compliance, coverage/style notes, and legal records included in the published package.
  6. Closed picker does not eagerly load unused additions; open previews do not download unrelated style variants. Measured package/preview payload is reported.
  7. Automated catalog/state, component, rendering/network, packaging, bootstrap, and mobile tests pass alongside check/build/full offline tests/workspace-link verification.

Files to create or modify

State/UI:

  • packages/dashboard/src/client/state/appearance.ts: expanded IDs/catalog/group/family metadata; preserve storage APIs.
  • packages/dashboard/src/client/components/font-picker.tsx (new): accessible grouped preview picker.
  • packages/dashboard/src/client/components/theme-gallery.tsx: integrate picker; retain theme cards.
  • packages/dashboard/src/client/styles/app.css: trigger/popup/option/group/focus/responsive styling.
  • packages/dashboard/src/client/styles/themes.css: added font faces and scoped overrides.
  • packages/dashboard/src/client/index.html: complete early-restore allowlist.

Assets/package:

  • packages/dashboard/src/client/assets/fonts/: thirty-family assets/licenses/provenance; correct affected existing provenance descriptions.
  • packages/dashboard/package.json: npm legal/provenance allowlist.
  • packages/dashboard/scripts/ font-acquisition/inspection helper if required: reproducible development tooling only.

Tests:

  • packages/dashboard/test/client/font-picker.test.tsx (new).
  • packages/dashboard/test/client/font-picker.browser.test.ts (new).
  • packages/dashboard/test/client/fixtures/font-picker.html and font-picker.tsx (new): production ThemeGallery and styles through existing Vite/Playwright fixture patterns.
  • packages/dashboard/test/client/appearance.test.ts: full catalog/persistence/bootstrap contracts.
  • packages/dashboard/test/client/screens.test.tsx: replace native-select font assumptions; keep Settings integration.
  • packages/dashboard/test/client/appearance.browser.test.ts: expanded active typography/coverage/loading expectations, preserving first-frame/isolation tests.
  • Focused asset/provenance/package test under packages/dashboard/test/ as appropriate.

Docs: README.md, packages/coding-agent/README.md, packages/dashboard/README.md, packages/coding-agent/docs/dashboard.md, and relevant asset provenance records.

No server/RPC or service-worker policy change is expected; existing Vite fingerprinting/static caching applies.

Testing approach

  1. Catalog/state: count and exact lists, no retired existing IDs, unique IDs/names, group membership, CSS/metadata/bootstrap consistency, restoration for every addition, defaults/errors/cross-tab behavior.
  2. Picker component: semantic label/roles/relationships, pointer commit, navigation without writes, Home/End and prefix typeahead across section boundaries, Enter/Space commit, Escape/Tab/outside dismissal, scroll-to-active, focus restoration, reactive theme/preference changes, repeated opens/unmount cleanup.
  3. Actual browser fonts: production Vite/Solid fixture; open picker, await intended face loading, inspect every option's resolved family and representative glyph rendering. Verify Theme default under Gruvbox and a non-Gruvbox theme with an explicit override active. Test selected proportional fonts in controls/code and theme cards.
  4. Network: fresh contexts and intercepted font requests before open/after open/after selection/reopen. Assert no unused new families on closed startup, no unnecessary inactive-style requests for regular preview, cached reopen, and readable interactive fallback on simulated request failures.
  5. Responsive: desktop and narrow mobile widths; viewport bounds, internal scrolling to last choice, readable group labels, touch targets, visible focus, no leaked Escape/global handlers.
  6. Assets/redistribution: source/output hashes, glyph/weight/style/axis declarations, compliant internal names where modified, license/trademark retention, and npm pack --dry-run --json legal-record inclusion with lifecycle scripts disabled if necessary. Inspection helpers are reproducible; tests must not contact live font catalogs.
  7. Validation: focused suites, npm run check, npm run build, npm run verify-workspace-links, full offline npm test, then built Dashboard smoke verification. No paid/live provider tests.

Risks and implementation checks

  • Thirty additions make acquisition/verification substantial; use one pinned manifest/tooling workflow rather than inconsistent one-off downloads. Do not silently remove existing or planned choices to reduce workload.
  • License/RFN/trademark details differ; preserve Apache notices for Roboto Slab and inspect both standalone and embedded font naming/legal records.
  • Some popular serif/display families have only regular/italic. Document synthesis/weight mapping accurately and verify readability at Dashboard sizes.
  • Thirty open-menu previews are a deliberate request increase; control faces/styles and record bytes without penalizing ordinary startup.
  • A custom listbox must not lose native keyboard/accessibility behavior. Section headings must not disturb option indexes or typeahead.
  • Popularity rankings change; freeze this approved list and source evidence rather than dynamically changing installed preferences.

Plan created by mach6

@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Requirement amendment — real core styles and measured overhead

The requester revised the font requirements during implementation: if an added family lacks important native styles (regular, italic, bold), replace it with another popular family, and assess whether more than thirty options impose unacceptable latency/frontend overhead. This supersedes the prior plan's permission to retain upright-only/display families with synthetic styles; all other approved scope remains intact.

Keep all six existing choices unchanged; add fifteen sans-serif and fifteen serif families (36 explicit choices plus Theme default). Require real upstream regular 400, italic 400, bold 700, and bold-italic 700 for each addition; variable axes may supply actual weights without separate downloads. Do not fabricate coverage through CSS declarations or synthesis.

Reject Oswald and Roboto Slab (no real italic), Instrument Serif and DM Serif Display (no real bold). Replace them using the next eligible Latin families in the frozen popularity evidence: Rubik, Crimson Text, Arvo, Bodoni Moda.

Final sans-serif roster: Roboto, Open Sans, Google Sans, Inter, Montserrat, Poppins, Lato, Roboto Condensed, Arimo, Noto Sans, DM Sans, Raleway, Nunito, Nunito Sans, Rubik.

Final serif roster: Playfair Display, Merriweather, Lora, Noto Serif, Cormorant Garamond, Libre Baskerville, PT Serif, EB Garamond, Fraunces, Bitter, Source Serif 4, Newsreader, Crimson Text, Arvo, Bodoni Moda.

Verify eligibility against pinned upstream metadata and actual bundled faces, and test those core styles in Chromium. Refresh provenance, naming, checksums, notices, bootstrap registry, docs, and catalog tests together. Selected replacements are expected to use OFL; verify the actual pinned sources rather than retaining obsolete Apache records.

Measure bundled bytes, regular-preview bytes, closed-startup requests, first-open requests, cache reuse, DOM/menu responsiveness and mobile bounds. Mount options only while open and apply per-family preview typography as rows approach the visible scroll window using IntersectionObserver; older browsers fall back to the complete open-menu preview. This keeps the full catalog reachable while avoiding the all-family first-open download burst. Inactive styles remain lazy; selected typography remains unaffected. Document measured tradeoffs rather than assuming the option count itself is slow.

Original approved additive plan: #540 (comment)

@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Implementation complete — revised font catalog and accessible lazy previews

Commit: 0e30f5c081ce96e8adf086063f31e6989428f298
Pushed to: Anjiro81/dreb, feature/issue-510-font-catalog-preview-picker

Implemented the additive plan and the requester’s native-style amendment: #540 (comment). The requester accepted the measured package-size tradeoff and authorized continuing with the full catalog.

Delivered

  • Retained all six existing choices and Theme default; added fifteen Latin sans-serif and fifteen Latin serif families (37 total options).
  • Replaced Oswald, Roboto Slab, Instrument Serif, and DM Serif Display with Rubik, Crimson Text, Arvo, and Bodoni Moda. Every addition provides real regular 400, italic 400, bold 700, and bold-italic 700 through actual upstream faces/axes, not CSS synthesis.
  • Added 75 licensed WOFF2 resources from pinned google/fonts commit 9710da1eacb3be272583c3224dcb70f9da6eadbb, with neutral derivative font identifiers, complete source/output hashes, coverage/axis/processing records, all thirty OFLs, and Google Sans trademark notice.
  • Added reproducible development acquisition/inspection tooling with locked sources/tool versions and offline verification. Exact upstream notice/metadata bytes are preserved, including original whitespace/line endings, using narrowly scoped Git attributes; indexed blobs were checked against the verified working copies.
  • Integrated a dependency-free Solid select-only combobox/listbox with grouped choices, independent highlight/commit, keyboard/typeahead, Escape/Tab/outside dismissal, scrolling, focus restoration, touch/mobile bounds, and lifecycle cleanup. Native key handling prevents Escape leakage to unrelated document listeners.
  • Preview options mount only while open. IntersectionObserver applies per-family typography near the visible scroll window, rather than requesting every family at first opening. Previously visited faces stay warm; older browsers fall back to complete open-menu previews. Inactive style-only resources stay lazy. Failed font fetches do not block readable names or selection.
  • Preserved browser-local persistence, existing IDs/labels/storage keys, cross-tab updates, independent theme/mode behavior, synchronous restoration for all new IDs, and existing theme-card baselines. Theme default’s picker preview reflects the active theme even under an explicit override.
  • Updated state, bootstrap allowlist, generated font CSS, package legal/provenance inclusion, existing integration tests, focused component/browser/asset tests, and all affected documentation. Source font binaries are not duplicated in npm packaging; only fingerprinted built assets ship alongside legal/provenance records and the development helper.

Measured overhead

Measurement Result
Added complete font resources 5,457,532 B
Existing + added font resources 6,852,996 B
All thirty regular-preview resources, when progressively explored 2,350,576 B
Closed default Settings startup No added-font requests
Cold desktop first opening 7 regular resources: five existing plus two additions; 109,412 B of new fonts
Reopening No additional requests for already visited faces
Local opening time Roughly 15–22 ms; hardware/network dependent
Open-menu DOM increase 118 elements
Production JS gzip delta, same-toolchain baseline +2,464 B
Production CSS gzip delta, same-toolchain baseline +1,869 B
Dashboard npm package with changes ~7.37 MB compressed / ~9.24 MB unpacked, excluding dependencies
Published Dashboard 2.69.0 baseline ~1.82 MB compressed / ~2.98 MB unpacked, excluding dependencies

The count is inexpensive frontend work; complete font assets primarily increase distribution size. A Chromium check with 4× CPU slowdown, 150 ms latency and 1.6 Mbit/s throughput remained interactive without waiting for typefaces. Dashboard is separately installed, so the fonts do not enlarge a CLI-only installation. These are measurements, not universal speed guarantees.

Verification

  • Full offline workspace tests: 6,435 passed, zero failed; live provider tests disabled.
  • Commit hooks: 6,435 passed, zero failed, 741 skipped; lint and type checks passed.
  • npm run check, complete workspace build, workspace-link verification, and staged diff checks passed.
  • Offline font verifier: thirty families, seventy-five resources; every core style, binary/hash/naming/coverage/legal record verified. Acquisition execution additionally checked deterministic offline rebuilding and corruption/safeguard rejection.
  • Real Solid/Vite/Chromium tests: all added option faces actually load when revealed; all 120 family/style/weight combinations load; no inactive style-only downloads during regular previews; cache reuse, failed fetches, keyboard/focus, native touch selection, 320/375/768 px bounds, and all-new-ID bootstrap/scoped typography verified.
  • npm pack --dry-run --json --ignore-scripts: all legal/provenance/metadata records and the reproduction helper included; no duplicate source WOFF2 files.
  • Built Dashboard binary smoke under an isolated temporary home: mobile Settings, 37 choices, persisted Lora restoration, Bodoni Moda commitment/reload, correct typography and zero browser runtime errors.

Worktree clean after commit. No server/RPC, upload, dedicated multilingual bundle, IBM self-hosting, theme-color editor, or TUI changes. Formal review has not been started; the implementation is now durably saved for explicit requester-authorized review.


Progress tracked by mach6

@Anjiro81
Anjiro81 marked this pull request as ready for review October 2, 2026 12:51
@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Unverified Review Candidates — Pending Assessment

Review round: 1
Reviewed commit: 0e30f5c

These are unverified candidates. Severity reflects reviewer confidence; do not treat any item as a merge blocker until the assessment comment is posted.

The full PR was reviewed against the latest native-core-style/viewport-lazy amendment, not superseded rosters. All six existing choices and the approved fifteen-plus-fifteen additions remain authoritative. Uploads, dedicated multilingual bundles, IBM self-hosting, server/RPC/TUI changes and unrelated appearance work remain excluded. The requester accepted the measured package-size tradeoff; no arbitrary payload budget is introduced.

Critical

None reported.

Important

Finding 1 — Background scrolling can move the open popup outside the viewport.

  • Source: code-reviewer; confidence 100/100.
  • Evidence: packages/dashboard/src/client/components/font-picker.tsx:26–39,148–153. Repositioning uses the trigger's unbounded vertical rectangle even after it scrolls offscreen. Background wheel/trackpad scrolling does not fire outside pointer dismissal.
  • Reproduction: production Solid fixture, 375×667, open the picker, move pointer outside its list, then wheel the surrounding page by 550 px. Popup remained expanded with bounds approximately top −266 / bottom 134, hiding most rows/active option. Desktop reproduction likewise went above the viewport.
  • Proposed remedy: dismiss when the anchor leaves the viewport, or clamp vertical placement/available height. Preserve internal list scrolling and viewport-lazy previews.

Finding 2 — Pointer opening relies on browser-specific button focus.

  • Source: code-reviewer; confidence 90/100.
  • Evidence: components/font-picker.tsx:42–46,186–190. reveal() opens without focusing the trigger; keyboard handling lives only on that button. Safari does not normally focus a button on mouse click.
  • Trigger/consequence: pointer-open in supported Safari, then use arrows/typeahead/Escape without tabbing to the trigger. Keys can remain directed at the body/previous Settings control instead of the popup; active-descendant semantics refer to an unfocused control. Commit focuses the trigger, but only after selection.
  • Proposed remedy: focus the trigger when revealing, ideally with preventScroll. This browser-specific candidate was not executed in Safari/WebKit by the specialist and requires independent factual assessment; Chromium-only focus tests do not settle it.

Finding 3 — Reserved names remain the primary names shown for renamed derivatives.

  • Source: code-reviewer; confidence 85/100.
  • Evidence: src/client/state/font-catalog.ts:10,15,19–21,24,32 and components/font-picker.tsx:234/committed label. E.g. the binary/CSS family is Dreb Sans 07, but the selector offers the modified subset simply as Lato. Several actual bundled OFLs reserve these source names.
  • Actual license wording (assets/fonts/expanded/licenses/lato/OFL.txt:63–66) restricts Reserved Font Names for modified versions and applies the restriction to the primary font name presented to users. Internal neutral names are correct but may not address the separate user-facing menu-name requirement.
  • Parent supplemental reference: official OFL FAQ, item 5.3 explicitly says primary name includes font menus; original names may remain in clearly differentiated description/source attribution. Subsetting is modification (item 2.6); the retained Latin-only inventory is not the full-inventory functional-equivalence exception.
  • Proposed remedy: use the neutral derivative name as primary, with clearly secondary original-family attribution/description, or record applicable explicit permission. Preserve all existing choices and preference IDs. Independent assessment must verify applicability and practical compliance rather than presuming the provenance's attribution sentence resolves the visible primary label.

Suggestions

Finding 4 — Automated native-style assertions can approve upright bytes as italic.

  • Source: test-reviewer; confidence 100/100.
  • Evidence: test/client/font-picker.browser.test.ts:145–166, test/font-catalog-assets.test.ts:33–49. FontFace CSS descriptors/successful loading and manifest/checksum assertions do not inspect intrinsic binary style/axes/names.
  • Mutation: in a temporary copy, substitute Roboto normal bytes for italic and update its output checksum/size. All ten picker browser and both asset tests pass; the existing offline Python verifier rejects it. Current committed assets themselves pass that verifier.
  • Proposed improvement: invoke pinned offline scripts/build-font-catalog.py --verify in CI, or equivalent intrinsic binary assertions. This is future-regression protection, not a claim that today's assets are synthetic or wrong.

Finding 5 — The touch-scrolling test bypasses a native swipe.

  • Source: test-reviewer; confidence 100/100.
  • Evidence: font-picker.browser.test.ts:228–245: tap opening, programmatic scrollIntoViewIfNeeded(), tap commitment.
  • Mutation: temporary touch-action: none leaves the existing test green but prevents actual touch panning. Independent native touch gesture on the current production component moves scrollTop 0→197, keeps it open and leaves preference unchanged.
  • Proposed improvement: test a real swipe and assert scrolling without commitment/dismissal, then reach/tap a late choice. Current native scrolling works.

Finding 6 — New bootstrap cases depend on an unstubbed Google stylesheet.

  • Source: test-reviewer; confidence 98/100.
  • Evidence: test/client/appearance.browser.test.ts:1031–1049, production index.html:22–26. Thirty fresh-context restoration cases inherit the pre-existing external IBM stylesheet without interception.
  • Probe: hold that intercepted response (no external fetch); domcontentloaded/bootstrap stays pending until empty CSS is fulfilled. A slow external response can therefore exhaust the suite's ten-second timeout independently of local font correctness. The dedicated picker suite already intercepts external fonts.
  • Proposed improvement: stub Google CSS/font responses in appearance test contexts. The external dependency predates this PR; no change to actual IBM hosting is requested.

Finding 7 — Unused naming-policy constant.

  • Source: simplifier; confidence 100/100.
  • Evidence: scripts/build-font-catalog.py:59, IDENTITY_IDS has no reads. Active naming policy is name_values().
  • Proposed improvement: delete the unused declaration; preserve notice IDs and actual name transformations.

Finding 8 — Static face selection can use a direct ordered allowlist.

  • Source: simplifier; confidence 100/100.
  • Evidence: scripts/build-font-catalog.py:203–205, concatenated lists/conditional for 400, optional normal500/600, 700.
  • Proposed improvement: use normal (400,500,600,700) or italic (400,700) plus presence filtering, retaining the preceding required-400/700 and ambiguity checks. Thirty pinned metadata files and 256 synthetic combinations (286 cases) independently matched existing outputs/rejections.

Finding 9 — Repeated requested-font byte accounting.

  • Source: simplifier; confidence 100/100.
  • Evidence: font-picker.browser.test.ts:95–98,124–127 repeat the same manifest/request matching pipeline.
  • Proposed improvement: a small test-local requestedCatalogBytes() helper; preserve measurement timing, current request-list access, per-resource counting and independent expected-regular-byte assertions. No runtime abstraction is proposed.

Strengths and verification

  • Complete revised roster, real four-core-style sources, preserved existing assets/IDs/persistence, actual progressive option typography and synchronous restoration are well connected. Completeness specialist found no missing deliverable; error auditor found no additional error-handling candidate.
  • Actual loaded/visible font rendering was independently checked, including Chromium platform-font inspection for all added labels. Font-fetch failures stay readable/interactive; inactive style-only faces remain lazy; warm reopening avoids new visited-resource requests.
  • All thirty OFLs, Google Sans trademark notice, immutable source/output hashes, exact metadata/notice bytes, neutral internal names, coverage/axis/processing records and package inclusion were verified. All 17 existing binaries remain byte-identical. User-facing RFN naming remains a separate candidate above.
  • Independent full offline validation: 6,435 tests passed, zero failed; check reported no source rewrites; workspace links and offline font verifier passed. Specialists also ran focused and mutation/interaction probes in temporary copies without changing the repository.
  • GitHub Coverage, Lint & Type Check, and Test checks pass for this PR. Passing tests/CI do not by themselves resolve the above untested candidates.
  • Actual payload/performance evidence supports the approved count and viewport-lazy approach; no unsupported asset-budget or all-font-on-open requirement was imposed.

Agents run: code-reviewer, error-auditor, test-reviewer, completeness-checker, simplifier. Configured preferred models were unavailable; all specialist invocations used the harness's available parent-model fallback in independent contexts.

No fixes were made. The following independent assessment will classify all nine candidates using factual, scope and practical gates.


Reviewed by mach6

@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Review Assessment

Unverified candidates

Review round: 1
Reviewed commit: 0e30f5c

Outcome: 3 merge blockers, 3 deferred useful follow-ups, 3 nitpicks; 0 false positives or discarded observations. All nine candidates were independently checked against actual source, original requests, latest approved scope and concrete practical consequences. The parent accepts the independent assessment below. Tests and GitHub CI pass, but do not cover the two identified interaction failures or the separate primary-menu-name licensing condition.

Classifications

Finding Classification Reasoning
1 — popup leaves viewport during background scrolling Merge blocker Factual: components/font-picker.tsx:26–39,148–156 positions from the trigger's unbounded vertical rectangle after page scrolling. Independently reproduced at 375×667: open picker, pointer outside list, wheel surrounding Settings 550 px; menu remains expanded with popup top about −266 / bottom 134, hiding most choices. Scope: the approved custom picker explicitly requires viewport bounds and usable scrolling/reachability. Practical: ordinary wheel/trackpad use strands the active menu partly offscreen. Outside pointer/focus dismissal and Escape/reopening can recover, but wheel-only scrolling does not trigger those safeguards. Closing for an offscreen anchor or keeping placement bounded prevents the reproduced harm.
2 — pointer opening does not establish trigger focus Merge blocker Factual: font-picker.tsx:42–46,186–190 opens without explicit focus; only the trigger handles keys, and explicit focus occurs after commitment. MDN documents Safari's intentional non-focusing mouse clicks. A production non-focusing-activation diagnostic leaves the prior control focused and End/Escape do not navigate/close the popup. Scope: supported-browser keyboard accessibility, opening focus and cancellation are required by the issue/approved picker contract. Practical: a macOS Safari user clicks open, then presses navigation/typeahead/Escape; keys go to body/another Settings control, sometimes scrolling or changing that control. Manual tabbing/pointer selection are recovery, not sufficient opening behavior. Explicit trigger focus on reveal fixes the mixed pointer/keyboard failure. No Safari/WebKit execution is claimed; documented browser behavior and the code/diagnostic establish the problem.
3 — RFNs used as primary derivative menu names Merge blocker Factual: e.g. state/font-catalog.ts:10 uses primary label Lato for modified Dreb Sans 07; font-picker.tsx:192,234 shows only that label in trigger/options. Actual bundled Lato OFL reserves the name and applies the restriction to the primary user-facing name (expanded/licenses/lato/OFL.txt:1,63–66). Official OFL FAQ item 5.3 explicitly includes font menus; descriptions may acknowledge source if clearly differentiated. No applicable permission is recorded. Source/derivative inspection confirms subsetting removes codepoints, so the full-inventory functional-equivalence exception does not apply. Scope: legally redistributable additions and naming compliance are explicit acceptance criteria. Practical: shipping routinely identifies restricted modified derivatives to users by bare reserved original names, failing that redistribution/naming condition despite correct internal neutral names and retained notices. A compliant primary derivative name plus secondary source attribution—or applicable permission—resolves this current acceptance failure.
4 — CSS/manifest tests can miss intrinsically incorrect italic bytes Deferred useful follow-up Factual: style tests check descriptors/loading/hash declarations, not intrinsic font tables; the upright-for-italic mutation remains green while the existing offline verifier rejects it. Scope: current real core styles and binary inspection are already delivered; specific CI integration of that Python helper is not required. Practical: future incorrectly regenerated assets could evade the weaker tests, so CI verifier integration is valuable. All current 75 binaries independently pass, with pinned sources/deterministic generation providing existing safeguards. No current wrong-style resource or unmet acceptance criterion was found.
5 — mobile test uses programmatic scrolling instead of native swipe Deferred useful follow-up Factual: the test uses scrollIntoViewIfNeeded() before tapping; a touch-action:none mutation evades it. Scope: current mobile reachability and coverage are delivered; that specific swipe assertion is not mandated. Practical: a future panning regression could strand touch-only users despite a green test. Independent native input on the current component scrolls 0→203, keeps the popup open and leaves preference unchanged. Add real swipe coverage as future regression protection, not as a fix for an existing failure.
6 — appearance bootstrap tests inherit external Google CSS dependency Deferred useful follow-up Factual: thirty new cases follow existing fresh-context index navigation without stubbing the pre-existing Google stylesheet; held-response evidence shows navigation/bootstrap can stall. Scope: this test/production IBM dependency predates the PR, and current required tests/CI pass; changing IBM hosting remains excluded. Practical: external latency can cause unrelated local/CI timeouts. Stubbing the response is worthwhile harness isolation, but no new product dependency, current required-check failure or material PR-introduced regression is established.
7 — unused IDENTITY_IDS declaration Nitpick Factual: scripts/build-font-catalog.py:59 has no reads; name_values() drives actual naming. Scope: cleanup is not needed for licensed assets or correctness. Practical: minor maintainer confusion only; generated bytes/runtime behavior are unaffected.
8 — simplify static-weight list expression Nitpick Factual: build-font-catalog.py:203–205 can be expressed as an ordered allowlist; existing required-core and ambiguity checks make its current selection correct. Scope: expression style is not an acceptance requirement. Practical: independent 286-case equivalence evidence shows a readability-only change, not user harm.
9 — factor duplicated byte-accounting pipeline Nitpick Factual: font-picker.browser.test.ts:95–98,124–127 repeat the correct request-to-manifest sum. Scope: helper extraction is not required for measured loading. Practical: optional maintenance simplification; current measurements are correct.

Component/state paths in the table are under packages/dashboard/src/client/; abbreviated expanded/... assets are under packages/dashboard/src/client/assets/fonts/. Test files are under packages/dashboard/test/client/ and the acquisition helper is under packages/dashboard/scripts/.

RFN scope clarification

The actual restricted new-label inventory includes Lato, Raleway, Playfair Display, Merriweather, Lora, Libre Baskerville, PT Serif and Arvo. Bitter also needs the same check: its bundled declaration reserves “Bitter Pro,” and OFL FAQ 5.4 prohibits using individual complete RFN words. This is additional evidence for finding 3, not another finding.

Do not remove original attribution, mutate immutable notices, silently replace approved families, rename existing choices, or assume every source label is an RFN. The current primary bare labels must be differentiated where the actual license requires it. Internal neutral-name verification is correct but does not test a custom font menu's primary display name. Official FAQ 5.3 permits clearly secondary descriptive source reference; legal permission is an alternative if obtained and recorded.

Action Plan — merge blockers only

  1. Finding 3: compliant primary names. Use permissible primary derivative names for RFN-restricted additions in both options and committed trigger, with clearly secondary source-family attribution/description, or record applicable written permission. Keep all 30 additions, 37 total choices, preference IDs, unchanged original six labels, pinned provenance and notices. Preserve useful source-family discovery/typeahead while separating source attribution from the derivative identity. Evidence: actual primary/accessibility names checked against bundled RFNs before/after selection; unambiguous source description; unchanged IDs/persistence/roster; real previews and keyboard behavior; offline binary/legal verifier still passes.
  2. Finding 2: opening focus. Focus the trigger during reveal, preferably with preventScroll, without committing a preference. Regression: begin focused elsewhere, activate without depending on the browser's default button focus, verify trigger focus, then send real focused-target keyboard input (not just locator.press() that focuses it). Navigation/typeahead and Escape must work without writes; Tab/Shift+Tab still exit. Safari/WebKit confirmation is valuable but no unsupported claim of existing WebKit execution is required.
  3. Finding 1: dynamic viewport safety. Dismiss when the trigger leaves the viewport, or maintain bounded/usable vertical placement; preserve internal catalog scrolling and viewport-lazy previews. Regression: production narrow fixture, open and wheel surrounding page until the anchor exits; require closed-without-commit or fully bounded usable menu. Independently exercise internal scrolling/late choices without dismissal or commitment; retain stationary-anchor bounds tests.

Findings 4–9 are not part of the required action plan. Follow-up issues can be created for findings 4–6 if the requester wants separate tracking; nitpicks remain optional.

Verification and limits

The independent assessor inspected the full PR (all 168 paths), actual code, nine candidates, all specialist reports, original quoted requests and latest amendments. It reproduced background-scroll failure, checked non-focusing activation, performed a native touch swipe, inspected actual RFN source/derivative inventories, verified all current binaries offline, and independently retrieved official OFL/MDN guidance. No live provider/font-catalog calls, code changes, fixes, commits or review-fix loop occurred. Git HEAD/worktree remain unchanged and clean.

Independent full-suite evidence remains 6,435 passed, zero failed, with GitHub Coverage/Lint & Type Check/Test checks passing. The full approved catalog, actual four core styles, progressive previews, licensing records/internal neutral names, preserved old choices and accepted package overhead remain strengths. The remaining blockers are specifically the two newly introduced interaction failures and primary RFN menu naming—not font-count or asset-budget objections.


Assessment by mach6

@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Round 1 blocker fixes committed and pushed

Commit: 907bfd6798b6a40707c4444c1693d9bc45c03e3c — fix: resolve dashboard font picker review blockers
Branch: Anjiro81/dreb, feature/issue-510-font-catalog-preview-picker

Implemented the authorized action plan for findings 1, 2 and 3 from #540 (comment). All 37 choices, original six labels, preference IDs/storage keys, approved source families, and four real core styles remain intact.

Changes and regression evidence

  • Finding 1 — viewport safety: background scrolling dismisses the expanded picker once its trigger moves outside the vertical viewport, without committing. The popup is fixed-position from its initial mount, avoiding transient document-flow/scroll-anchoring effects before placement is calculated. Production Chromium tests wheel the surrounding page at 375 and 1024 px and verify dismissal without storage writes. A separate real internal-wheel test reaches the last option, keeps the menu open, leaves page scroll/selection unchanged, then commits normally. Existing stationary 320/375/768 px bounds and touch-selection checks pass; unit coverage also exercises anchors above and below the viewport.
  • Finding 2 — opening focus: reveal explicitly calls focus({ preventScroll: true }) on the trigger. Tests begin focused on another control, activate via non-focusing HTMLElement.click(), and verify actual focus before sending keyboard input through page.keyboard, not an implicitly focusing locator. End, source-family typeahead, Escape, Tab and Shift+Tab work without unwanted preference writes. This is Chromium/non-focusing-activation evidence; no Safari/WebKit execution is claimed.
  • Finding 3 — primary naming: the nine RFN-restricted additions use neutral derivative names as primary option/trigger text, with smaller, separate “Based on …” source attribution and accessible descriptions. Original source-family typeahead remains supported. Tests derive restrictions from the actual bundled OFL headers, reject individual reserved words in primary names, inspect all nine displayed/committed names, and check distinct primary option names/source descriptions in Chromium's accessibility tree. Persistence/reload retains the original IDs.
  • PT Serif word-level compliance: its declarations reserve “PT Sans,” “PT Serif” and “ParaType”; the individual-word restriction also affects the prior internal name Dreb Serif 07. It now uses Dreb Text 07, including internal binary/PostScript identities, CSS, registry, manifest, reproduction helper and provenance. Only its four WOFF2 binaries changed. Per-face coverage/style/weight, verified outlines/hints, immutable input hashes/notices, all other 29 catalog records, the other 71 additions and all 17 original binaries remain unchanged.
  • Updated root/product/Dashboard documentation and measured payload/bundle figures. Findings 4–9 remain outside this required batch; no uploads, dedicated multilingual bundles, IBM hosting, server/RPC/TUI, or unrelated appearance changes were introduced.

Verification

  • Full offline workspace suite: 6,446 passed, zero failed. Commit hooks independently passed 6,446, with 741 skipped; live provider tests disabled.
  • npm run check: lint/type checks pass, final run applied no rewrites; git diff --check and staged diff checks pass.
  • Complete workspace build and npm run verify-workspace-links pass.
  • Pinned offline intrinsic font verifier and deterministic offline rebuild pass: 30 families / 75 resources, real core styles, naming, hashes, coverage, outlines/hints and legal records verified.
  • All twenty staged blobs matched the validated files; all seventy-five indexed font hashes matched the staged catalog before commit.
  • Package/legal inclusion checks pass in the full suite; source WOFF2 files are not duplicated in npm packaging.
  • Built Dashboard smoke under isolated temporary home passes: mobile Settings, 37 choices, Lora restoration, Bodoni Moda commitment/reload, correct typography and zero browser runtime errors.

Refreshed measurements

Measurement Result
Added font resources 5,457,304 B
Existing + added fonts 6,852,768 B
All thirty progressively loaded regular previews 2,350,548 B
Cold desktop opening Seven regular resources; 109,412 B new-font bytes
Closed default startup / warm reopening No added startup requests / no new visited-face requests
Open-menu DOM increase 136 elements
Same-toolchain production gzip delta versus pre-feature baseline 2,795 B JS + 1,881 B CSS = 4,676 B

The approved approximately 5.46 MB distribution tradeoff is preserved; the four-face naming correction reduces font bytes by 228 B. Throttled interaction remains responsive without waiting for font completion. Local timings are not universal device/network guarantees.

HEAD matches the pushed PR commit and the worktree is clean. The fixes are now durably saved. Formal re-review has not been started; the requester decides whether to begin the next round.


Progress tracked by mach6

@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Unverified Review Candidates — Pending Assessment

Review round: 2
Reviewed commit: 907bfd6

These are unverified candidates. Severity reflects reviewer confidence; do not treat any item as a merge blocker until the assessment comment is posted.

The full PR was reviewed: all 168 changed paths, original issue/discussion, superseding native-style/viewport-lazy amendment and actual source/assets. The fix delta was supplementary only. The approved 37 choices and approximately 5.46 MB distribution tradeoff remain authoritative; excluded uploads, IBM self-hosting and unrelated appearance/server/RPC/TUI work are not reintroduced.

Stable numbering retains round 1 findings 4–9; finding 10 is new. Previously assessed blockers 1–3 are independently verified fixed, rather than repeated as current candidates.

Critical

None reported.

Important

No new product correctness, error-handling or incomplete-deliverable candidate reported at confidence ≥80.

Suggestions

Finding 4 — automated style assertions can still accept upright bytes declared as italic.

  • Source: test-reviewer; confidence 100/100; repeated round 1 deferred follow-up.
  • Evidence: packages/dashboard/test/client/font-picker.browser.test.ts:139–169, test/font-catalog-assets.test.ts:26–55. A fresh temporary Roboto upright-for-italic substitution, with updated declared checksum/size, passes all fifteen picker-browser and both asset tests; the pinned intrinsic verifier rejects it.
  • Suggested improvement: invoke that offline verifier in CI, or equivalent intrinsic binary-table checks. All current committed faces pass intrinsic verification; the candidate concerns future regression protection, not a current incorrect font.

Finding 5 — touch reachability test still bypasses finger panning.

  • Source: test-reviewer; confidence 100/100; repeated round 1 deferred follow-up.
  • Evidence: packages/dashboard/test/client/font-picker.browser.test.ts:317–338 taps open, programmatically scrolls, then taps the last choice. A temporary touch-action: none mutation remains green but native touch panning then stays 0→0.
  • Suggested improvement: add native swipe assertions before late-option commitment. Fresh native touch input on the current component moves scrollTop 0→201, keeps the menu expanded and does not commit.

Finding 6 — appearance restoration tests inherit uncontrolled external Google CSS.

  • Source: test-reviewer; confidence 100/100; repeated round 1 deferred follow-up.
  • Evidence: packages/dashboard/test/client/appearance.browser.test.ts:1031–1046. Locally holding the inherited stylesheet keeps DOMContentLoaded/bootstrap pending; fulfilling empty CSS releases restoration. Slow external responses can consume the ten-second timeout.
  • Suggested improvement: stub those external requests in test contexts, without changing production IBM hosting. All 135 appearance browser cases pass; the dependency predates this PR and the probe is not a current CI outage.

Finding 7 — unused naming-policy constant remains.

  • Source: simplifier; confidence 100/100; repeated round 1 nitpick.
  • Evidence: packages/dashboard/scripts/build-font-catalog.py:58–60; IDENTITY_IDS has no reads. Active transformations/checks use name_values(), rename() and validate_names().
  • Suggested improvement: delete the unused declaration while retaining notice policy and all name/source validation.

Finding 8 — static-weight selection can use a direct ordered allowlist.

  • Source: simplifier; confidence 100/100; repeated round 1 nitpick.
  • Evidence: packages/dashboard/scripts/build-font-catalog.py:203–208; the concatenated weight lists can be one normal (400,500,600,700) or italic (400,700) allowlist with presence filtering.
  • Suggested improvement: simplify the expression without removing required 400/700, ambiguity checks or variable-face handling. Fresh equivalence across thirty source metadata files and 256 synthetic combinations matches outputs/rejections.

Finding 9 — requested-font byte accounting remains duplicated.

  • Source: simplifier; confidence 100/100; repeated round 1 nitpick.
  • Evidence: packages/dashboard/test/client/font-picker.browser.test.ts:95–98,124–127; identical correct request-to-catalog byte sums.
  • Suggested improvement: a test-local helper preserving current request-array access, timing, per-resource counting and independent expected-regular-byte assertions.

Finding 10 — scroll-dismissal regression installs an unused animation-frame mock.

  • Source: simplifier; confidence 100/100; new low-severity cleanup.
  • Evidence: packages/dashboard/test/client/font-picker.test.tsx:144–147; production scroll handling calls positioning synchronously, not through requestAnimationFrame.
  • Suggested improvement: remove the misleading mock. Temporary instrumentation records zero calls in both geometry cases; all thirteen component cases pass with it removed. Dismissal/no-commit assertions remain intact.

Verified fixes and strengths

  • Previous finding 1: fixed-position from first mount plus offscreen-anchor dismissal prevents the reproduced page-wheel failure. Real surrounding-page wheel tests at 375/1024 px verify close/no writes; independent internal-wheel and native-touch probes keep scrolling usable without commitment. Stationary 320/375/768 px bounds pass. Temporarily disabling the guard fails the new unit regressions.
  • Previous finding 2: reveal explicitly focuses with preventScroll. Non-focusing activation establishes actual trigger focus before page.keyboard navigation/typeahead/Escape/Tab/Shift+Tab; removing explicit focus fails the regression. No Safari/WebKit execution is claimed.
  • Previous finding 3: all nine restricted additions have neutral primary option/trigger names and clearly separate source descriptions; source-family typeahead and preference IDs persist. Actual OFL headers, AX names/descriptions/committed values and binary identities were independently checked. PT Serif consistently uses Dreb Text 07, avoiding the reserved individual word. Restoring bare primary source names fails license-derived assertions.
  • The final 15+15 roster and all six existing choices remain complete. Real core styles, actual primary-label platform-font rendering for all thirty additions, progressive previews, no unnecessary style-only requests, default/theme-card behavior, storage/bootstrap/cross-tab compatibility and failed-resource usability pass independent checks.
  • All 75 new outputs, 136 pinned source records, embedded/standalone notices, coverage/axes and package inclusion were checked. All 17 original binaries remain byte-identical; only PT Serif's four outputs changed after the first implementation. Its non-name tables/outlines/hints remain unchanged apart from the expected head checksum.
  • Fresh parent full offline suite: 6,446 passed, zero failed; read-only lint/types, engines/hooks, workspace links and offline intrinsic verifier pass. The test specialist independently ran 540 relevant tests plus mutation/native-input/platform-font probes. Other specialists ran independent targeted, failure-path and equivalence checks.
  • GitHub Coverage, Lint & Type Check and Test pass for the reviewed commit. Measurements remain consistent: 5,457,304 B added fonts; 2,350,548 B explored regular previews; 109,412 B new fonts on cold opening; 136 added elements.

Agents run: code-reviewer, error-auditor, test-reviewer, completeness-checker, simplifier. Configured preferred models were unavailable; each ran in an independent context using the available openai-codex/gpt-6.1-sol parent-model fallback. No model-family diversity claim is made.

No code changes or fixes were made. Independent phase-two assessment follows.


Reviewed by mach6

@Anjiro81

Anjiro81 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Review Assessment

Round 2 unverified candidates

Review round: 2
Reviewed commit: 907bfd6

Outcome: 0 merge blockers, 3 deferred useful follow-ups, 4 nitpicks; 0 false positives or discarded observations. All seven current candidates were independently checked against actual source, original issue/quoted requests, latest approved amendments and concrete practical impact. Previous blockers 1–3 are verified fixed and are not counted as current candidates. The parent accepts the independent assessment below.

Classifications

Finding Classification Reasoning
4 — CSS/manifest style tests can accept upright bytes as italic Deferred useful follow-up Factual: assertions check descriptors/loading/signature/hash declarations, not intrinsic font tables; a fresh reconciled temporary mutation passes fifteen browser/two asset tests, while the standalone verifier rejects intrinsic identity. Scope: real core styles are required and all current 75 files pass intrinsic checks; this particular Python CI integration is not mandated. Practical: a future incorrect regeneration could hide behind updated declarations/hashes, making CI integration useful. That sequence is not reachable with today's verified bytes; pinned sources, strict generation and the offline verifier remain safeguards. No current wrong-style face or failed acceptance criterion.
5 — touch reachability test bypasses actual finger panning Deferred useful follow-up Factual: the test taps but scrolls programmatically; a temporary touch-action:none mutation stays green while native input fails to pan. Scope: current mobile reachability and automated mobile coverage are delivered; a specific swipe assertion is not mandated. Practical: future CSS could strand touch-only users despite this test. On current production styles, independently repeated native touch moves 0→201, preserves expanded state and writes no preference; no current mobile failure. Add the stronger gesture assertion as optional regression protection.
6 — restoration harness inherits external Google stylesheet dependency Deferred useful follow-up Factual: locally holding the pre-existing stylesheet keeps DOMContentLoaded/bootstrap pending until fulfillment; new contexts do not intercept it. Scope: required restoration coverage is delivered and passes; the stylesheet/order and similar old tests predate this PR. IBM hosting changes are excluded. Practical: external latency can produce unrelated local/CI test timeouts; stubbing improves isolation. The probe establishes susceptibility, not a current outage, failed required check or new product dependency.
7 — unused IDENTITY_IDS Nitpick Factual: independent AST/search finds no reads; actual rewriting/checks use name_values(), rename() and validate_names(). Scope: deleting an unused constant is unnecessary for compliant assets. Practical: maintainer confusion only; no runtime/generation path consumes it, and active notice/name validation remains effective.
8 — simplify static-weight selection Nitpick Factual: a direct ordered allowlist is equivalent across thirty source files and 256 synthetic combinations, including rejections. Scope: required-core/ambiguity checks already enforce correct acquisition; expression style is not a criterion. Practical: no current wrong-weight trigger or output difference. Readability-only change, preserving all safeguards and the variable branch.
9 — duplicate requested-byte accounting Nitpick Factual: the two pipelines are identical and correct, evaluated at different observation times. Scope: measurements are required, helper extraction is not. Practical: no current divergence or incorrect payload; independent expected-byte/style/cache checks remain. A test-local helper reduces maintenance duplication only.
10 — unused animation-frame mock in scroll regression Nitpick Factual: production positioning is synchronous; instrumented geometry cases record zero mock calls, and all thirteen component cases pass without it. Scope: dismissal regression coverage is effective with the mock present; cleanup is not needed for the approved fix. Practical: it suggests nonexistent scheduling to maintainers, but actual geometry/dismissal/no-write assertions and real wheel regressions still execute. No shipping harm.

Paths/line references and confidence are in the linked candidates comment. Stable numbering carries findings 4–9 from round 1; finding 10 is new. Useful follow-ups remain outside the required action plan.

Prior blocker verification

  • Finding 1 — fixed: initial fixed positioning removes transient document-flow/scroll anchoring; an offscreen anchor dismisses without committing. Real surrounding-page wheel tests at 375/1024 px pass. Separate internal wheel and native touch reachability keep the list open and preference unchanged; stationary bounds/last-choice tests pass at 320/375/768 px. Disabling the guard fails the geometry regressions.
  • Finding 2 — fixed: reveal explicitly focuses with preventScroll before opening. Non-focusing activation begins elsewhere, verifies actual focus, then sends End/source-family typeahead/Escape/Tab/Shift+Tab through page.keyboard; no unwanted writes. Removing focus fails the active-element assertion. Chromium/non-focusing-path evidence only; no Safari/WebKit execution claimed.
  • Finding 3 — fixed: actual bundled RFNs agree with the nine restricted additions. Primary UI/binary identities are neutral; source names are separate “Based on …” descriptions/typeahead aliases. AX option names/descriptions and committed values were inspected, not just DOM labels. For example, the Lato control has name font, value Dreb Sans 07 Based on Lato, description Based on Lato: differentiated attribution, not a bare reserved primary name. PT Serif consistently uses Dreb Text 07 / DrebText07, avoiding the reserved individual word. Its four identity-renamed outputs preserve other tables/outlines/hints except the expected head checksum; other 29 catalog records, other 71 additions and all 17 original binaries are unchanged. Stable IDs and actual typeface previews remain intact.

Action Plan — merge blockers only

No further fixes are required by this review before merge. Findings 4–6 may be tracked as separate optional follow-up issues; findings 7–10 are optional cleanup. Do not turn them into another blocker-fix batch without approval.

The final 15+15 source roster, all 37 choices, real four core styles, progressive open-only previews/unsupported-browser fallback, existing labels/IDs/storage/bootstrap/theme behavior, immutable provenance/notices and npm redistribution remain delivered. The requester-approved approximately 5.46 MB tradeoff and explicit exclusions remain authoritative.

Verification and limits

  • Full review target: 168 paths / complete 984,419-byte diff, original issue and all discussion/plans/amendments; generated records inspected structurally and matched to actual files/sources/binaries. Fix comparison was supplementary only.
  • Fresh parent full offline suite: 6,446 passed, zero failed, 741 skipped; read-only lint/type/engines/hooks, workspace links and offline intrinsic verifier pass. GitHub Coverage, Lint & Type Check and Test pass for this HEAD.
  • Fresh independent assessor: 109 unmutated feature tests, all 75 intrinsic font outputs, actual platform-font/committed-AX/native-touch/held-stylesheet probes, thirteen no-RAF component cases and temporary mutation checks pass as documented. The test specialist independently ran 540 relevant cases; other roles ran additional failure-path/equivalence/native-input probes.
  • All 136 pinned source records, 75 output binaries/embedded notices and actual package inclusion were checked; all thirty primary labels render real custom-font glyphs. Current additions 5,457,304 B, all-new regular previews 2,350,548 B, combined fonts 6,852,768 B; cold opening requests 109,412 B new fonts, with no unnecessary style-only preview requests and cache reuse.
  • No fresh full build/deterministic rebuild/built-binary smoke is claimed for this review; successful current-source implementation evidence remains recorded in the prior progress comment. Specialist temporary full rebuilds were timeboxed, not counted as completed. No physical-device/screen-reader-product/WebKit execution or live acquisition/provider calls claimed.
  • Required specialists and independent assessor ran separate contexts using the harness's available parent-model fallback after preferred models were unavailable. No model-family diversity claim is made.

No source changes, fixes, write-mode lint, in-place asset rebuilds, commits or pushes occurred during review. HEAD/worktree remain unchanged and clean. The requester decides whether to publish or separately track optional follow-ups.


Assessment by mach6

@Anjiro81

Anjiro81 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Release preparation saved — final CI blocked

Proposed version: 2.70.0 (minor, additive Dashboard font feature)
Version commit: 5695c067e8e07b0283bb593a2b486cddfc1ecad4 — chore: bump version to 2.70.0

The version bump is committed/pushed on the PR branch, before merge as required. All seven workspace versions, root package, lockfile workspace fields and semantic-search plugin manifest are synchronized. Only version fields changed across ten files; the lockfile dependency graph is unchanged.

Pre-merge review had zero merge blockers and no conflicts. The documentation audit checked the affected root/product/Dashboard docs, appearance references, all existing/expanded provenance and links; no additional docs changes were needed and there is no maintained changelog.

Local release-preparation checks pass:

  • Complete build, lint/types, engines/hooks and workspace links.
  • Built CLI --version and actual interactive TUI banner both show 2.70.0; TUI smoke used isolated HOME and no prompt/provider calls.
  • Built Dashboard mobile smoke: 37 font choices, Lora restoration, PT Serif commitment/actual stored-state restoration, neutral Dreb Text 07 identity, four loaded core faces and zero runtime errors. Temporary harness setup/count-selector errors were corrected before this successful run; no product code was changed.
  • Commit hooks: 6,446 passed, zero failed, 744 skipped; live API tests disabled.

Final CI gate failed — merge not attempted

Coverage job failed in:

packages/dashboard/test/client/font-picker.browser.test.ts:372

Case: “bounds the popup and keeps the last option reachable at 768px”.

Observed geometry result: popup fits: true, scrolls: true, document documentFits: true, but lastVisible: false (expected true). Coverage test totals: one failed, 5,791 passed, 719 skipped. This requires investigation/fixing; it is not waived as an unrelated or pre-existing failure. The separate Lint & Type Check and Test jobs pass for the version commit.

Publishing stops at the failed gate. No code fix, CI retry, merge, tag or GitHub release was performed. Next authorized step: /skill:mach6-implement 540 ci.

A subsequent merge also needs maintainer permissions: the authenticated upstream viewer permission is READ. The release bump is ready for the maintainer's merge once final CI is repaired; never tag this unmerged feature branch as the release.

Worktree clean, HEAD matches the pushed version commit. Round-two reviewed implementation remains 907bfd6798b6a40707c4444c1693d9bc45c03e3c; this commit only synchronizes version fields.


Progress tracked by mach6

@Anjiro81

Anjiro81 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

CI visibility failure fixed and saved

Commit: 8b1c6d24f2ed0e1d1d38bdbaa121527a239ee0c0 — fix: preserve font picker scroll position during preview loading

Pushed to fork/feature/issue-510-font-catalog-preview-picker. Proposed release version remains 2.70.0.

Reproduced cause

The failed Coverage job exposed a real scroll-anchoring issue at 768px, not an assertion that simply needed more waiting. After viewport-lazy preview fonts loaded, Chromium adjusted popup scrollTop from 1370 to 1368 and left the last option 1.203125px beyond the popup boundary. At 4× CPU, 16/20 immediate measurements failed and 20/20 settled measurements failed, even after font readiness and five rendering frames.

Scoped fix and regression

  • Disable overflow-anchor only on .font-picker-list, preserving the explicit keyboard/internal-scroll position during font swaps. No new component JS or asynchronous interaction gate.
  • Add delayed-WOFF2 regressions at 320, 375 and 768px: navigate End with fallback text, prove full visibility without commitment, release real font responses, wait for loaded preview faces and settled font layout, then prove the last choice remains fully visible, active and uncommitted before Space selects it.
  • Share the identical popup measurement helper. All original bounds assertions are preserved, without tolerance, retries around the assertion or weakened visibility expectations.
  • The new 768px regression failed against the original CSS after fonts settled. After the fix, all three regressions pass; a fresh 20-iteration 4× CPU probe has zero immediate or settled visibility failures.

Exactly two files changed: packages/dashboard/src/client/styles/app.css and packages/dashboard/test/client/font-picker.browser.test.ts. Catalog roster, identities, font resources, legal metadata, package manifests and release version are unchanged.

Validation

Node 22; live API calls disabled.

  • Complete npm run coverage (the failed CI command): 5,796 passed, zero failed, 718 skipped; 297 files passed / 26 skipped.
  • Complete offline suite: 6,449 passed, zero failed, 744 skipped.
  • Commit hooks independently repeat 6,449 passed, zero failed, 744 skipped, with clean formatting.
  • Final picker browser suite: 18 passed, including delayed-font regressions and original viewport bounds, native wheel, focus, keyboard, AX identities, lazy downloads and throttling checks.
  • Lint/types/engines/hooks, complete workspace build, workspace-link verification and git diff --check: pass.
  • Fresh built 2.70.0 Dashboard mobile smoke: 37 choices, Lora restoration, PT Serif commitment and actual stored-state restoration, neutral primary identity, four loaded core faces, zero runtime errors.

Browser evidence is Chromium; no Safari/WebKit or physical-device claim. Local coverage passing is not a claim that the newly pushed GitHub checks have passed. CI must pass before merge; upstream merge still requires maintainer permissions. No merge, tag, release or formal re-review performed in this batch.

The CI fix is now durably saved for authorized re-review. Worktree clean.


Progress tracked by mach6

@Anjiro81

Anjiro81 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Unverified Review Candidates — Pending Assessment

Review round: 3
Reviewed commit: 8b1c6d2

These are unverified candidates. Severity reflects reviewer confidence; do not treat any item as a merge blocker until the assessment comment is posted.

Reviewed the full 177-path PR, original issue and all discussion, quoted requests and superseding amendments, actual source/assets/docs/package/version records. Comparison with prior reviewed 907bfd6798b6a40707c4444c1693d9bc45c03e3c is supplementary only. The approved 15+15 additions, six unchanged old choices, 37 total options, real core styles, accepted approximately 5.46 MB distribution tradeoff and exclusions remain authoritative.

Stable candidate IDs 4–10 remain; no new candidate. Previous blockers 1–3 and the subsequent CI visibility failure are independently verified fixed, not repeated as current candidates.

Critical

None reported.

Important

No new product-correctness, error-handling or incomplete-deliverable candidate at confidence ≥80.

Suggestions

Finding 4 — automated descriptors/hashes can accept upright bytes declared italic.

  • Source: test-reviewer; confidence 100/100, recurring optional future-regression protection.
  • Evidence: packages/dashboard/test/client/font-picker.browser.test.ts:153–185, test/font-catalog-assets.test.ts:26–55. Fresh temporary Roboto upright-for-italic substitution with reconciled size/hash/totals passes 18 picker browser + two asset tests, while intrinsic verification rejects its actual identity.
  • Suggested improvement: integrate the existing offline binary verifier in CI, or equivalent table assertions. All current 75 committed outputs pass actual intrinsic inspection; no current wrong-style face is alleged. Real styles are required, but this particular CI integration is not an approved categorical deliverable.

Finding 5 — touch test still bypasses actual finger panning.

  • Source: test-reviewer; confidence 100/100, recurring optional regression-strengthening.
  • Evidence: font-picker.browser.test.ts:336–357; tap open → programmatic scrollIntoViewIfNeeded() → tap commit. Temporary touch-action:none remains green while native touch movement becomes 0→0.
  • Suggested improvement: add genuine swipe/no-dismissal/no-write/late-tap coverage. Current independently executed native input moves 0→256, keeps the menu open and leaves storage null; other specialists also verified current native panning. No current touch failure established.

Finding 6 — restoration tests retain inherited external stylesheet timing dependency.

  • Source: test-reviewer; confidence 100/100, recurring optional harness isolation.
  • Evidence: appearance.browser.test.ts:1031–1046, production index.html:22–34. A locally held pre-existing Google CSS response blocks DOMContentLoaded/bootstrap; empty fulfillment releases restoration. Slow external responses can consume the test timeout independently of local fonts.
  • Suggested improvement: intercept external CSS/font routes in appearance-test contexts, not change production IBM hosting. All 135 appearance browser cases pass in a temporary copy with only offline route isolation; current required GitHub CI also passes. This susceptibility predates the PR and is not a current outage/new product dependency.

Finding 7 — unused naming-policy constant.

  • Source: simplifier; confidence 100/100, recurring cleanup.
  • Evidence: scripts/build-font-catalog.py:59; independent AST/search finds zero reads of IDENTITY_IDS. Actual rewriting/validation use name_values(), rename() and validate_names().
  • Suggested improvement: delete the declaration, preserving active notice/name safeguards. Maintainer confusion only, not a compliance/runtime failure.

Finding 8 — static-weight selection can use one ordered allowlist.

  • Source: simplifier; confidence 100/100, recurring readability.
  • Evidence: build-font-catalog.py:203–208; equivalent normal (400,500,600,700) / italic (400,700) allowlist with presence filtering can replace concatenation.
  • Suggested improvement: simplify without removing required 400/700, ambiguity checks or variable branch. Fresh 291-case output/rejection equivalence includes 30 metadata files, 256 combinations and five extra variable/ambiguity cases. No current wrong output.

Finding 9 — duplicate requested-font byte sums.

  • Source: simplifier; confidence 100/100, recurring test-local cleanup.
  • Evidence: font-picker.browser.test.ts:109–112,138–141; identical correct request-to-manifest sums at separate observation points.
  • Suggested improvement: a small helper preserving current request-array access, timing, per-resource counting and independent expected-byte assertion. Fresh 257 request-set equivalence checks and 18 browser tests pass with temporary extraction. Current measurements are correct.

Finding 10 — unused RAF mock in scroll-dismissal regression.

  • Source: simplifier; confidence 100/100, recurring test cleanup.
  • Evidence: font-picker.test.tsx:144–147; production scroll positioning is synchronous. Fresh instrumentation records zero calls in both geometry cases; all 13 component cases pass with only the mock removed.
  • Suggested improvement: remove that unused mock. Do not confuse it with the new browser regression's genuinely necessary post-font rendering-frame settlement.

Paths abbreviated above are under packages/dashboard/ (test/client/, scripts/, or src/client/).

Verified fixes and strengths

  • Prior finding 1: initial fixed positioning and offscreen-anchor dismissal prevent the page-wheel failure. Fresh actual surrounding-page wheel tests at375/1024, internal wheel and native touch remain correct without unintended commitment. Removing the guard fails above/below regressions.
  • Prior finding 2: explicit opening focus({preventScroll:true}) establishes the real keyboard target. Non-focusing activation then actual page.keyboard navigation/typeahead/Escape/Tab/Shift+Tab passes; removing focus fails the intended active-element assertion. Chromium/non-focusing-path evidence, not Safari/WebKit execution.
  • Prior finding 3: nine license-restricted derivatives have neutral primary UI/binary identities and separate source descriptions/typeahead. Actual OFL headers, individual reserved words, AX option names/descriptions and committed values checked. PT Serif consistently uses Dreb Text07 / DrebText07; stable IDs/original six names persist. Restoring bare primary source names fails license-derived assertions.
  • CI visibility fix: popup-only overflow-anchor:none preserves explicit scrolling after lazy font swaps. Independent temporary/page-only reversals reproduce baseline768px scrollTop1370→1368, last row1.203125px beyond popup after font/layout settlement. Test specialist: 20/20 settled baseline failures vs20/20 current passes. New held-font regressions at320/375/768 and original exact bounds/assertions pass; no tolerance, assertion retry or JS interaction delay masks the harm.
  • Complete approved roster/native styles, actual platform-font glyphs for all30 labels, progressive/open-only previews and no-IO fallback, style laziness/cache/failure usability, persistence/bootstrap/theme compatibility and legal/package inclusion were checked against actual files. All17 original binaries remain byte-identical.
  • Release-preparation versions match 2.70.0 in root/all seven workspace/plugin/lock fields; independent normalized lock comparisons prove the dependency graph unchanged.
  • Fresh parent full offline suite:6,449 passed, zero failed,744 skipped; read-only lint/types/hooks/engines/workspace links and parent hash/roster/version contracts pass. Test specialist independently completed 543 relevant cases, including135 appearance cases isolated offline in a temporary copy and296 unchanged Settings cases, plus native input/platform-font/mutation probes. All other specialists ran independent focused/equivalence/error-path checks.
  • GitHub Coverage, Lint & Type Check, Test pass for this exact reviewed HEAD; run37610531448 verified independently by head SHA. Earlier failed run37606272226 is superseded.

Evidence limits

The historical pinned Python venv/source cache have been cleaned; pinned verifier attempts fail the toolchain gate and are not counted as successful. Specialists transparently inspected actual current WOFF2 tables and ran the unchanged read-only verification function with available alternate fontTools/Brotli tools. No version spoofing, acquisition/rebuild or fresh original-TTF outline/notices comparison is claimed. Current hashes/identity/intrinsic styles/axes/coverage/local immutable records pass; earlier successful pinned deterministic rebuild/source comparisons remain prior implementation evidence.

No fresh parent full build/coverage/deterministic rebuild/built-binary smoke claimed for this review; successful fix-phase evidence applies to this source. No physical-device/screen-reader-product/WebKit/live-provider/live-font-acquisition execution claimed.

Agents run: code-reviewer, error-auditor, test-reviewer, completeness-checker, simplifier, each in an independent context using available openai-codex/gpt-6.1-sol fallback after preferred models were unavailable. No model-family diversity claim.

No tracked edits, fixes, write-mode lint, in-place rebuilds, commits or pushes during review. A specialist removed its generated untracked Python bytecode cache; worktree clean. Round-three independent assessment with practical and acceptance counter-pressure follows.


Reviewed by mach6

@Anjiro81

Anjiro81 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Review Assessment

Round-three unverified candidates

Review round: 3
Reviewed commit: 8b1c6d2

Outcome: 0 merge blockers, 3 deferred useful follow-ups, 4 nitpicks; 0 false positives or discarded observations. Previous blockers 1–3 and the subsequent CI visibility failure are resolved, not counted as current candidates. No new finding.

The independent assessor, developer's advocate and devil's advocate received the same seven candidates, full PR/issue context, verbatim requests/acceptance criteria, approved amendments and actual source. All agree that no candidate establishes a current material failure or unmet approved requirement. The parent accepts this outcome. The practical critic calls mandatory cleanup for findings7–10 low-value review ceremony; the parent classifies the factual observations as nitpicks, not mandatory work. No disagreement required escalation or voting.

Classifications

Finding Classification Reasoning
4 — descriptors/hashes can approve upright bytes declared italic Deferred useful follow-up Factual: browser/manifest tests do not inspect intrinsic tables; a reconciled temporary upright-for-italic mutation passes18 browser/two asset tests, while actual intrinsic verification rejects it. Scope: real four core styles are mandatory; a prescribed Python CI job is not. All75 current outputs pass independent intrinsic normal/italic, static-weight/variable-axis and identity checks. Practical: a future maintainer could replace bytes, update declarations and omit existing strict generation/verification, leading to wrong italics in a later release. Pinned sources, source-style checks, deterministic output comparison and the delivered verifier already safeguard acquisition; there is no current wrong-style file or runtime upload/acquisition path. CI integration improves future detection rather than repairing this release.
5 — touch test bypasses native panning Deferred useful follow-up Factual: the committed test taps and programmatically scrolls; touch-action:none mutation evades it. Scope: usable touch/mobile reachability and coverage are delivered; this specific native-input assertion is not mandated. Practical: future panning-suppressing CSS could strand touch-only users. Current independently executed native input moves0→256, stays expanded and writes nothing; other specialists corroborate native scrolling. Native overflow, bounds, internal-scroll exclusion from dismissal and current wheel/tap tests are safeguards. A swipe assertion strengthens future protection, not a current usability fix.
6 — restoration harness inherits external Google CSS timing Deferred useful follow-up Factual: locally holding the pre-existing stylesheet blocks DOMContentLoaded/bootstrap until fulfillment. Scope: restoration coverage and passing checks are delivered; stylesheet/order and equivalent original tests predate this PR. Production IBM hosting changes remain excluded. Practical: external latency can waste developer/CI time through unrelated test timeouts; route isolation would help. Current exact-HEAD CI/full suite pass, and135 appearance cases independently pass with offline route isolation only in a temporary copy. Susceptibility is not a current outage or new product dependency. If an actual required-check failure appears, it must be fixed, not waived as pre-existing.
7 — unused IDENTITY_IDS Nitpick Factual: zero reads; active transformations/checks use name_values(), rename() and validate_names(). Scope: deletion is unnecessary for compliant native assets. Practical: small maintainer confusion only; no runtime/generation path consumes it and no current output changes.
8 — simplify static-weight expression Nitpick Factual: ordered allowlist is equivalent with required400/700, ambiguity checks and variable handling retained; fresh independent286-case and specialist291-case equivalence checks agree. Scope: correct core-style acquisition already enforced; expression style is not required. Practical: marginal reading effort only, no supported metadata/current-user trigger produces wrong weights.
9 — duplicate requested-byte sums Nitpick Factual: identical correct sums at different observation points; independent257-request-set checks and temporary helper/browser run agree. Scope: measured loading is required, helper extraction is not. Practical: possible future duplicate-edit maintenance only; current per-resource totals, request/style/cache checks and independent expected-byte oracle are correct.
10 — unused RAF mock Nitpick Factual: production scroll positioning is synchronous; mock records zero calls and13 component cases pass without it. Scope: actual geometry/dismissal/no-write coverage already works. Practical: misleading scheduling scaffolding only, not a runtime failure or missed present regression. The new browser test's real post-font frame settlement is distinct and should remain.

Paths and confidence scores are in the linked candidates comment. Stable IDs4–10 retain their previous meaning; recurrence does not create new scope authority.

Prior blocker and CI-fix verification

  • Finding1 resolved: current popup is fixed from first mount; vertical offscreen-anchor dismissal prevents the original surrounding-page wheel failure without commitment. Actual375/1024 wheel regressions pass; guard reversal fails the intended geometry assertions. Internal wheel/native touch preserve scrolling and late-choice reachability without page scroll, dismissal or writes.
  • Finding2 resolved: opening explicitly focuses with preventScroll. Non-focusing activation starts elsewhere, asserts actual focus, then uses actual focused-target keyboard input for navigation/source typeahead/Escape/Tab/Shift+Tab. Removing focus fails the regression. Chromium/non-focusing-path evidence; no Safari/WebKit execution claimed.
  • Finding3 resolved: actual OFL headers/individual-word restrictions agree with nine neutral primary option/trigger identities and differentiated “Based on …” source descriptions. AX names/descriptions, commitment/reload and source-family discovery are tested. All four PT outputs use Dreb Text 07 / DrebText07; registry/CSS/helper/provenance agree. Old six labels/IDs and notices remain unchanged.
  • CI visibility failure resolved: .font-picker-list { overflow-anchor:none; } is scoped to this explicit internal scroll surface. Strict old bounds/target/commit assertions remain byte-equivalent in the helper. Held-font regressions at320/375/768 measure fallback visibility, loaded face/font readiness/layout settlement, active identity/no writes, then Space commitment. Independent test-specialist baseline20/20 settled failures (scrollTop1370→1368, last row1.203125px outside) contrast with20/20 current passes; multiple other specialists independently reverse the CSS and reproduce the failure. More waiting does not repair the baseline. No tolerance, assertion retry or production interaction delay hides it.

Action Plan — merge blockers only

No further code fixes are required by this review before merge. Findings4–6 may be tracked as separate optional follow-up issues;7–10 remain optional cleanup. Do not silently convert these into another fix batch.

Continue the authorized publication workflow when requested. Version2.70.0 is already synchronized and pushed; do not double-bump merely because publication resumes after CI repair. Current CI passes; upstream merge still requires maintainer permissions. No merge/tag/release is performed by this review.

Full-scope acceptance and evidence limits

  • Full review target: 177 paths /26,450-line complete diff, original issue/all discussion and latest approved amendments, actual code/assets/legal/docs/package/version fields; prior907bfd delta supplemental only.
  • Final approved15+15 roster, all37 choices, native normal400/700 and italic400/700, real custom glyphs for all30 added primary labels, open-only viewport previews/no-IO fallback, style laziness/cache/failure usability, storage/bootstrap/cross-tab/theme compatibility, legal provenance and actual npm inclusion are delivered. All17 old binaries remain byte-identical; all75 added hashes match packaged built assets. Root/seven workspaces/plugin/lock versions are2.70.0; dependency graph unchanged. Added5,457,304B/regular2,350,548B/combined6,852,768B remain within the accepted tradeoff; no tighter budget introduced.
  • Fresh parent full offline suite:6,449 passed,0 failed,744 skipped; read-only lint/types/hooks/engines/workspace links and roster/hash/version contracts pass. Test specialist independently completed543 relevant cases and native/platform-font/mutation probes. Independent assessor separately completed94 unchanged-source cases, all75 intrinsic outputs, package/version and equivalence checks. Overlapping specialist counts are not added together.
  • GitHub Coverage, Lint & Type Check and Test pass for exact reviewed HEAD, run37610531448; workflow SHA/success independently captured. Earlier failed version-only run37606272226 is superseded, not waived.
  • Historical pinned Python venv/source cache are no longer usable. Pinned CLI attempts fail the toolchain gate and are not successes. Read-only actual-output verification with transparently disclosed available fontTools/Brotli versions passes intrinsic tables/identities/axes/coverage/hashes/local locked records. No guard/version spoofing or live acquisition. Entire expanded asset inventory/helper remain unchanged from the previously pinned-verified revision, preserving historical source/rebuild evidence without calling it fresh execution. No fresh original-TTF outline/embedded-notice comparison or deterministic rebuild claimed.
  • No fresh review full build/coverage/built-binary/TUI smoke; successful current-source implementation checks remain prior evidence. No WebKit/Safari/physical-device/screen-reader-product/live-provider/live-font-acquisition execution claimed. The acceptance critic performed read-only source/binary inspection and assessed recorded browser evidence, not fresh adversarial/browser tests.
  • Five specialists and three assessors ran independent contexts, all using available openai-codex/gpt-6.1-sol fallback after preferred models were unavailable. No model-family diversity claim.

No tracked source changes, fixes, write-mode lint, in-place rebuilds, commits or pushes during review. Generated bytecode artifact was removed by its owner; reviewed HEAD/worktree remain unchanged and clean. The requester decides publication and separate optional-issue tracking.


Assessment by mach6

@Anjiro81

Anjiro81 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Release-ready — maintainer squash merge required

Proposed release: 2.70.0
Final pushed HEAD: 8cf707e3bba6993cc3664bedb9809f983c405a24
Round-three review: assessment — zero merge blockers

Publication resumed after the authorized CI fix/re-review. All technical pre-merge checks are clear:

  • PR is open, mergeable and clean; no unresolved review blocker. Findings 4–6 remain optional follow-ups and 7–10 optional cleanup, not release requirements.
  • Version 2.70.0 was already committed/pushed in 5695c06; root, all seven workspaces, semantic-search plugin and lock fields match. No second bump or dependency re-resolution.
  • Fresh complete build, workspace-link check, compiled CLI --version and built Dashboard mobile smoke pass. Original interactive TUI version verification remains valid; no fresh TUI execution is claimed this resume.
  • Latest commit hooks independently pass 6,449 tests, zero failed, 744 skipped with live APIs disabled; lint/types pass.
  • Full documentation audit complete; no maintained changelog. Rebuilt upstream baseline/current frontend with the same installed Dashboard Vite 8.1.3 toolchain and default Node 22 gzip. The anchoring fix adds 10 gzip bytes compared with the earlier naming-fix measurement: 2,795 B JS + 1,891 B CSS = 4,686 B. Corrected exactly two stale documentation figures in 8cf707e, docs: refresh font bundle measurements for 2.70.0. No implementation, font binary, naming, licensing, roster or version changes after reviewed 8b1c6d2. Initial temporary baseline setup used root Vite/wrong dependency resolution and failed; the successful rerun used the actual Dashboard-local toolchain, not a failed attempt counted as measurement.
  • Workflow's single final CI watch passes: Coverage, Lint & Type Check, Test. Run head independently matches 8cf707e3bba6993cc3664bedb9809f983c405a24 and overall conclusion is success.

Merge attempted and blocked by account permissions

Immediately after passing final CI, attempted:

gh pr merge 540 --repo aebrer/dreb --squash --delete-branch \
  --match-head-commit 8cf707e3bba6993cc3664bedb9809f983c405a24

GitHub rejected it:

GraphQL: Anjiro81 does not have the correct permissions to execute MergePullRequest (mergePullRequest)

The account has upstream READ permission. PR remains OPEN; no merge or branch deletion occurred. Local/fork HEAD match and worktree is clean.

Maintainer handoff

  1. Squash merge this PR at the release-ready HEAD after confirming final CI.
  2. Use the merged default-branch version 2.70.0 for v2.70.0; do not bump again or tag the unmerged feature branch. Upstream is still 2.69.0 and no v2.70.0 tag existed at the preflight check.
  3. Continue tag/release preparation from merged master, verifying the merge commit first. GitHub release creation and release-note approval remain requester checkpoints.

No tag, GitHub release or npm publication was performed. Publishing pauses at maintainer merge permission, not a technical failure. Optional follow-up issues were not created without authorization.


Progress tracked by mach6

@m-aebrer

m-aebrer commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

almost ready, two questions though:

  1. in the font drop-down, under "Rubik" there is a non-selectable line that just says "Serif"... is that supposed to be there? It doesn't look like the other gray text

  2. didn't want to include a path for custom font uploads via GUI? it's fine if not, but we should at least document how to manually add custom fonts

overall this is great though and I agree it's basically ready to merge

@Anjiro81

Anjiro81 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

To 1. No shouldn't be there, let me check.
To 2. I deliberately skipped it, was too complicated

@Anjiro81

Anjiro81 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor Author

Clarification on category headings and custom fonts

Thanks for checking both points. One correction to my earlier reply: “Serif” was intentional—it is the category heading following Rubik, not a selectable font. Its presentation was too ambiguous, and its font-size rule also referenced an undefined token.

I've prepared clearer headings: “Sans-serif fonts” / “Serif fonts”, uppercase, full-width and separated by a hairline. They remain non-selectable group labels, visually distinct from the smaller “Based on …” source attribution. Clicking a heading keeps keyboard focus and the menu open without changing the font. Mobile/desktop regressions check that there are still exactly37 selectable fonts, then keyboard selection continues normally. Actual mobile rendering has also been inspected.

Uploads were deliberately kept separate from the approved scope, not simply omitted because they were difficult. The agreed request was “Catalog and preview picker only; handle uploads separately.” A GUI upload path would additionally need font validation, storage/registration, persistence and licensing handling. This PR does not introduce that mechanism.

Drew's request for manual documentation is reasonable. There is currently no runtime custom-font directory or font-path setting; uploading through Files or installing an OS font does not register a picker choice. I've added a developer-only “Custom fonts in a source build” guide in packages/coding-agent/docs/dashboard.md, linked from the root/product/Dashboard READMEs. It explains assets/notices, registry entry, a separate custom stylesheet, early-restore allowlist, contract-test updates, rebuild and use of the built server—not unsupported edits to a globally installed npm package. The managed generated catalog is kept separate. A temporary private-source probe verified an extra font's selection, real local face loading, persistence/reload and production-head restoration using those steps.

I hate LLMs...


Progress tracked by mach6

@m-aebrer

m-aebrer commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

These changes are local and not yet committed/pushed;

okay, lol, push em and I can proceed to merge :)

@Anjiro81

Anjiro81 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Maintainer follow-ups committed and pushed

Commit: 00518f0523dff3524cf39a73fd5cb39181dc33d1 — fix: clarify font categories and document custom font setup
Branch: Anjiro81/dreb, feature/issue-510-font-catalog-preview-picker

Both points from Drew's comment are addressed. This supersedes the local/uncommitted status in the clarification reply.

Clear category headings

  • The line after Rubik was the intended non-selectable serif category, not an extra font. It now says SERIF FONTS, with SANS-SERIF FONTS treated consistently.
  • Headings are uppercase/full-width hairline dividers in normal text color, with spacing, visibly separate from muted source descriptions and selectable rows. Replaced the undefined --fs-micro reference with the existing --fs-small token. Kept regular weight so headings do not request unrelated emphasis faces.
  • Clicking a heading preserves trigger focus, menu state and highlighted identity without committing. All37 actual choices and IDs remain intact.
  • New375/1024px Chromium regressions check names/appearance/non-option count, click/no-write/focus and subsequent real keyboard selection. Existing delayed-font/bounds/wheel/touch/name/loading tests remain green. The actual mobile screenshot was inspected.

Manual custom-font documentation, not a new upload feature

  • Custom fonts in a source build explains the actual developer workflow: separate custom assets/notices, registry entry, separate CSS, early bootstrap allowlist, private contract-test updates, rebuild and using the built server. Root/product/Dashboard READMEs link to it.
  • Explicitly documents no runtime upload/install directory/font-path setting/discovery. Host Files upload and OS installation do not register picker entries; editing globally installed package contents is not the supported workflow.
  • A temporary private-source probe using an existing licensed test face verifies38 choices in that temporary build, actual custom-face loading, selection, storage/reload and production-head restoration. No extra production font/asset was added.
  • Upload exclusion remains the explicitly approved “Catalog and preview picker only; handle uploads separately”, not merely a complexity excuse. No GUI/server/RPC/storage/upload implementation was smuggled into this fix.

Validation

  • Full offline suite and independent commit hooks: 6,451 passed, zero failed,744 skipped; live APIs disabled.
  • Complete coverage: 5,798 passed, zero failed,718 skipped.
  • Focused component/browser: 33 passed (13component +20browser).
  • Lint/types/hooks/engines, complete workspace build, workspace links and diff checks pass.
  • Fresh built2.70.0 Dashboard mobile smoke passes:37 choices, Lora restoration, PT Serif selection/actual saved-state restoration, four loaded faces and zero runtime errors.
  • Source-guide probe/setup and mobile inspection pass. Initial new-test count was corrected to exclude native color-mode options; temporary guide-probe FS allowlist/CSS fixture ordering were corrected before successful runs. These harness corrections did not weaken product assertions or add production behavior.
  • Refreshed same-toolchain bundle measurements: 2,815B JS +1,922B CSS =4,737B gzip delta versus upstream baseline; font payload,37-choice roster,136 open-menu elements and lazy request behavior unchanged.

Eight explicitly staged files; no font binaries, managed catalog/helper/legal records, manifests or version changes. Proposed release remains 2.70.0. Worktree clean; local and fork HEAD match.

No new GitHub CI success is claimed before the pushed commit's checks finish. No formal re-review, merge, tag or release performed; the source changes are now durably saved for authorized review and fresh CI. Maintainer merge permissions are still required.


Progress tracked by mach6

@m-aebrer
m-aebrer merged commit 4eab513 into aebrer:master Oct 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expand font choices and preview fonts in the dashboard selector

2 participants