This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/ROADMAP-UI.md
Jeffrey Smith c9b9e68c18
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-frontend (push) Successful in 5s
CI/CD / test-go-pg (push) Successful in 2m42s
CI/CD / test-sqlite (push) Successful in 3m1s
CI/CD / build-and-deploy (push) Successful in 1m8s
Feat v0.6.14 visual polish (#49)
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
2026-04-01 13:25:04 +00:00

12 KiB
Raw Blame History

Armature — v0.6.x UI Hardening Roadmap

Goal: Fix all viewport scaling, banner integration, and styling inconsistencies so Claude Code can run a meaningful automated usability survey against a stable, uniform UI.


Problem Inventory

P1 — Viewport & Scaling (blocks everything)

# Issue Where Impact
1 Dual layout systemsbase.html template has its own banner→surface→footer column; app-shell.js Preact shell has a separate sw-shellsw-shell__bodysw-shell__surface column. They never coordinate. server/pages/templates/base.htmlsrc/js/sw/shell/app-shell.js Every surface inherits an ambiguous viewport ancestor.
2 Transform-based scaling is brokentransform: scale() on #surfaceInner doesn't reflow layout. Breaks getBoundingClientRect (menu.js already carries a scale-correction hack at line 20), scroll containment, pointer events, and the inverse-width/height hack (100/s%) doesn't account for banners consuming viewport space. base.html:56-67, appearance.js:41-53, menu.js:20-33 Menus, tooltips, dropdowns all mis-positioned at any non-100% scale. Click targets wrong.
3 Banner height desyncbase.html hardcodes --banner-h: 28px and renders banners in-flow. app-shell.js ShellBanner measures offsetHeight into --banner-top-height / --banner-bottom-height and uses position: fixed + body padding. Two independent banner systems. base.html:31,72-75,103-107app-shell.js:25-42, sw-shell.css:22-37,63-69 With banners enabled, content overflows by the banner height or gets double-inset depending on which code path is active.
4 100vh on mobile.sw-shell, .chat-app, .chat-loading, .login-shell use 100vh which doesn't subtract mobile browser chrome (address bar, toolbar). sw-shell.css:9, chat/css/main.css:15,25, sw-login.css:7 Content overflows on iOS Safari, Android Chrome.
5 Chat uses 100vh not 100%.chat-app { height: 100vh } ignores parent container (which already excludes banners/footer). Notes correctly uses height: 100%. Every extension surface that copies chat's pattern will inherit the bug. packages/chat/css/main.css:15 Chat surface overflows behind banners.

P2 — CSS Architecture

# Issue Where Impact
6 Class name collisions.settings-section defined in both modals.css:41-43 and surfaces.css:75-83 with different padding, margin, and border-bottom rules. .sw-dropdown in primitives.css:443 (styled <select>) vs sw-primitives.css:262 (custom dropdown component). .sw-tabs in primitives.css:459 vs sw-primitives.css:234. Kernel CSS Styles randomly win depending on load order. Bug reports differ by surface.
7 Old/new primitive duplication — Two button systems (.btn-primary/.btn-small in primitives.css vs .sw-btn--primary/.sw-btn--sm in sw-primitives.css). Two toast systems (.toast vs .sw-toast). Two dropdown, two tabs implementations. primitives.csssw-primitives.css No single source of truth for any component. Extension authors can't know which to use.
8 Extension CSS bleeds globally — Extension main.css loaded via <link> at document level, no scoping. Any class name can override kernel or sibling extension styles. base.html:26-28, extension-surface.css Package CSS fights with kernel. Two packages with .sidebar both lose.
9 No intermediate breakpoint — Only 768px mobile breakpoint. No tablet (7681024px). Secondary workspace pane hardcoded 480px. Admin nav hardcoded 200px. layout.css:263, surfaces.css:305 Cramped layout on iPad/small laptops.

P3 — Visual Consistency

# Issue Where Impact
10 Mixed unit systemspx, rem, em used interchangeably with no rationale. Some font-sizes in px (primitives), others in rem (sw-primitives), others in em (user-picker). All CSS files Zoom/scale behaves differently per element.
11 Google Fonts CDN dependency@import url(...) in variables.css:5 blocks rendering if CDN is slow; breaks entirely on air-gapped deployments. variables.css:5 FOUT or blank page on slow networks. No offline support.
12 No spacing scale — Padding/margins are ad-hoc values (10px, 12px, 14px, 16px, 20px, 24px, 28px…). No design-token spacing scale. All CSS Inconsistent visual rhythm across surfaces.
13 Hardcoded fallback colors in component CSSsw-shell.css, sw-primitives.css have inline fallbacks like var(--accent, #b38a4e) — a gold color from a previous theme that doesn't match the current blue #6c9fff. sw-shell.css, sw-primitives.css Wrong colors flash briefly if variables load late.

Roadmap

v0.6.9 — Session Lifetime Config

Shipped. Admin-configurable TTLs, "keep me logged in" checkbox, idle timeout, config-driven generateTokens(), 7 new tests. See CHANGELOG.md for details.

v0.6.10 — Viewport Foundation

Shipped. Single layout model: body → shell → surface. CSS zoom replaces transform: scale(). 100dvh fallbacks everywhere. Extension surfaces use 100% instead of 100vh. Dead shell layout code deprecated. See CHANGELOG.md.

v0.6.11 — CSS Deduplication

Shipped. Old primitive system retired. One class per concept. See CHANGELOG.md.

Step Description
Audit collision inventory Script that finds all duplicate class selectors across kernel CSS files. Produce a machine-readable collision report (JSON).
Migrate .settings-section Remove modals.css:41-43 definition. The surfaces.css definition is authoritative. Modals that used the old styles get explicit overrides scoped to .modal .settings-section.
Retire primitives.css old components .btn-primary, .btn-small, .btn-danger, .btn-full → migrate all usages to .sw-btn--*. .toast-container / .toast → migrate to .sw-toast-container / .sw-toast. Old .popup-menu → migrate to .sw-menu. Old .sw-dropdown (styled select in primitives.css) → rename to .sw-native-select or delete if unused. Old .sw-tabs / .sw-tab-btn in primitives.css → delete (sw-primitives.css version is authoritative).
Mark deprecated classes Any remaining old classes get a /* DEPRECATED v0.6.11 — use .sw-btn--* */ comment and a 1-version grace period for package authors.
Package CSS audit Scan all packages/*/css/main.css for references to deprecated kernel classes. Fix in-tree packages.

v0.6.12 — Extension CSS Isolation

Shipped. Prefix enforcement via linter. All 12 in-tree packages migrated. See CHANGELOG.md.

Step Description
Scoping strategy Prefix enforcement (option B). @scope support still patchy; prefix works everywhere, trivially lintable.
Linter scripts/lint-package-css.sh — validates first class selector in every rule starts with .ext-{slug}. Exempts :root, @keyframes, @font-face, @media, .sw-* kernel classes, .cm-* CodeMirror classes.
Kernel CSS contract docs/EXTENSION-CSS.md — stable public classes (.sw-btn--*, .sw-input, .sw-field, .sw-dialog, .sw-toast, .sw-menu, .sw-tabs, etc.) and all CSS variables. Everything else internal.
Migrate in-tree packages data-ext="{{.Surface}}" on extension mount. All 12 packages prefixed to .ext-{slug}-*. CSS + JS updated in lockstep.

v0.6.13 — Responsive & Spacing

Shipped. Spacing token scale (--sp-1 through --sp-12, 4px grid) in variables.css. Tablet breakpoint (max-width: 1024px) in layout, surfaces, login. All kernel CSS and 12 in-tree packages migrated to spacing tokens. EXTENSION-CSS.md updated with spacing table and breakpoint guide. Font-size scale deferred to v0.6.14. See CHANGELOG.md.

v0.6.14 — Visual Polish

Shipped. Stale fallback colors purged (~65 instances), fonts self-hosted (DM Sans + JetBrains Mono woff2), border-radius standardized to three tokens (--radius-sm, --radius, --radius-lg). Also fixed v0.6.13 spacing regressions (half-step tokens), theme settings default, surface overflow, and user menu zoom drift. See CHANGELOG.md.

v0.6.15 — User Display Audit

Every place a user identity appears in the UI must show a human-readable name, never a UUID. Fallback chain: display_name → username → "Unknown".

Step Description
Participant display-name resolution chat-core participants endpoint resolves display_name from the users table at query time instead of relying on a creation-time snapshot. If the stored display_name is empty, look up users.display_name or users.username by participant_id.
Audit all user-facing identity surfaces Walk every surface that shows user identity: chat participant list, chat message sender names, chat typing indicators, workflow assignees, team member lists, admin user list, notification actor names. Ensure the fallback chain is display_name → username → "Unknown" everywhere.
SDK user-resolve utility Add sw.users.resolve(id) or similar to the SDK — returns {id, username, display_name, avatar} with local caching. Surfaces use this instead of ad-hoc lookups.
Stale snapshot cleanup Remove or deprecate the static display_name column in the participants table. All display names come from the users table via the resolve utility.

v0.6.16 — Usability Survey Gate

Make the UI machine-auditable so Claude Code can run an automated survey.

Step Description
UI inventory manifest scripts/generate-ui-inventory.sh — walks kernel CSS + package CSS, extracts every rendered class, groups by surface, outputs ui-inventory.json. Fields: {surface, component, classes, file, line, responsive_breakpoints, spacing_tokens_used, font_size_tokens_used}.
Contrast checker Script that parses variables.css light/dark token pairs and checks WCAG AA contrast ratios for all text-* on bg-* combinations. Outputs pass/fail report.
Component coverage matrix Markdown table: each kernel primitive (button, input, dropdown, dialog, toast, menu, tabs, avatar, spinner, tooltip, drawer, banner) × each surface that uses it. Identifies surfaces still using deprecated old-style components.
Touch target audit Script that finds all <button>, [role=button], clickable elements across templates and JS, checks for min-width/min-height ≥ 44px on mobile breakpoint.
Claude Code survey prompt docs/USABILITY-SURVEY.md — structured prompt template that Claude Code can execute against the codebase. Sections: viewport correctness, banner integration, responsive behavior, styling consistency, accessibility basics (contrast, touch targets, focus indicators), component uniformity. Each section has pass/fail criteria and file paths to inspect.
Survey dry-run Run the survey. Fix anything it catches. Tag v0.6.16 only after clean survey.

Sequencing Rationale

v0.6.9  Session Lifetime Config ✅ SHIPPED
  ↓
v0.6.10 Viewport Foundation     ✅ SHIPPED
  ↓
v0.6.11 CSS Deduplication       ✅ SHIPPED
  ↓
v0.6.12 Extension CSS Isolation ✅ SHIPPED
  ↓
v0.6.13 Responsive & Spacing    ✅ SHIPPED
  ↓
v0.6.14 Visual Polish           ✅ SHIPPED
  ↓
v0.6.15 User Display Audit     ← No UUIDs in the UI, ever
  ↓
v0.6.16 Usability Survey Gate   ← Machine-audit the finished product

Each version is independently shippable and testable. No version depends on anything after it.


What "Usability Survey by Code" Means

The v0.6.15 deliverables give Claude Code (or any automated tool) three things:

  1. A structured inventory (ui-inventory.json) of every component, on every surface, with its CSS file and line number.

  2. Automated checks (contrast, touch targets, token usage) that produce machine-readable pass/fail reports.

  3. A survey prompt (USABILITY-SURVEY.md) with explicit criteria and file paths, so Claude Code can cat the relevant files, run the scripts, and produce a scored report without human guidance.

The survey is not a substitute for real user testing — it's a structural quality gate that catches the class of bugs (overflow, contrast, misalignment, inconsistent styling) that have historically slipped through.