docs(nexus): phase 7 visual qa audit
This commit is contained in:
parent
f66209f4ac
commit
5ab0b19d4a
1 changed files with 263 additions and 0 deletions
263
docs/reviews/2026-04-11-nexus-phase-7-visual-qa.md
Normal file
263
docs/reviews/2026-04-11-nexus-phase-7-visual-qa.md
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
# Phase 7 Visual QA — DESIGN.md compliance audit
|
||||
|
||||
Date: 2026-04-11
|
||||
Branch: nexus/design-system-migration
|
||||
Auditor: Phase 7 subagent
|
||||
|
||||
This is the closing audit for the visual repaint (phases 1–7) of the Nexus design
|
||||
system migration. The audit reads each route / primary component against
|
||||
DESIGN.md §1–§7, scores it, and records every deviation. Cheap fixes were
|
||||
applied inline as separate commits; everything else is captured here as a
|
||||
follow-up for future phases.
|
||||
|
||||
## Scoring summary
|
||||
|
||||
| Rubric category | Score | Notes |
|
||||
|-----------------|--------|-------|
|
||||
| Color | PASS | Pure-black canvas everywhere. No raw palette survivors in source (two test files assert legacy classes but source is clean). `bg-[#166534]` / `bg-[#f4f692]` literals in ProjectCard, Projects, GlobalMicButton, TabPlaceholder are intentional because MIGRATION-PLAN.md §3 hasn't shipped the `forest` / `volt-pale` token classes yet. |
|
||||
| Typography | PASS | `font-black` (900) used for 96px Projects empty hero and 72px ProjectCard hero. Uppercase section labels at 14px / `tracking-[0.1em]`–`tracking-[0.14em]`. Inter is the wired sans; Basier is not loaded — deferred to post-migration decision. |
|
||||
| Geometry | PASS | `rounded-(xl\|2xl\|3xl)` grep returns zero hits in `ui/src`. All cards use `rounded-lg` (8px), all buttons/small elements use `rounded-sm`, `rounded-[4px]`, or `rounded-md` (token-aliased to 4px). |
|
||||
| Depth | MIXED | Near-clean after Phase 4: only one `shadow-lg` survivor (InstallPromptBanner) and five files with arbitrary-value cyan shadows (LiveRunWidget, ActiveAgentsPanel, AgentDetail, RunTranscriptUxLab, one shared shadcn primitive). Inset-pressed is correctly applied in tabs + AgentDetail mode toggle. Phase 7 drops the cyan survivors and the InstallPromptBanner shadow. |
|
||||
| Interaction | PASS | Hover → volt, active → `var(--volt-pale)`, focus-ring → primary. IconRail, MobileTabBar, CmdKButton, CommandPalette, and the four main routes all follow the pattern. |
|
||||
|
||||
## Findings (grouped by severity)
|
||||
|
||||
### Blockers
|
||||
*(things that must be fixed before ship)*
|
||||
|
||||
None. The surface is broadly shippable against DESIGN.md.
|
||||
|
||||
### Deviations (deliberate or flagged)
|
||||
|
||||
1. **Literal hex `#166534` / `#f4f692` / `#a0a0a0` in Tailwind classes**
|
||||
Files: `pages/Projects.tsx:228,253`, `components/projects/ProjectCard.tsx:52,71`,
|
||||
`components/frame/GlobalMicButton.tsx:56,75`, `components/projects/tabs/TabPlaceholder.tsx:36`.
|
||||
These are intentional per MIGRATION-PLAN.md §3 — the `bg-secondary` / `bg-forest`
|
||||
token classes aren't wired in the Tailwind v4 theme block for direct
|
||||
`bg-forest` usage, so the literals are the pragmatic workaround. Each file
|
||||
carries a code comment explaining the reason.
|
||||
|
||||
2. **Basier font is not loaded.**
|
||||
DESIGN.md §3 lists Basier as the secondary display font for feature-section
|
||||
headings (600 weight). MIGRATION-PLAN.md §10 still flags this as an open
|
||||
licensing decision. Inter is used as the sole fallback. This is a documented
|
||||
gap, not a bug. Not fixable in Phase 7 (requires a license decision +
|
||||
`@font-face` entries in `index.css`).
|
||||
|
||||
3. **Chart-role palette** (`--chart-role-1..5`)
|
||||
`ui/src/index.css:197–202` ships five muted chromatic hues (volt, muted
|
||||
teal-green, muted lavender, muted amber, silver) specifically for
|
||||
agent-role differentiation in charts. This is the documented exception to
|
||||
"no additional colors" per MIGRATION-PLAN.md §6 and is correct.
|
||||
|
||||
4. **ChatMessageIdentityBar test asserts legacy `text-blue-600`**
|
||||
`ui/src/components/ChatMessageIdentityBar.test.tsx:57-58` still asserts the
|
||||
pre-migration blue class. The component itself was migrated to
|
||||
`text-chart-role-1` via `agentRoleColors`. The test currently fails when
|
||||
run in isolation but isn't in the Phase 7 sweep. Recommend fixing as a
|
||||
follow-up during the test-stabilization pass.
|
||||
|
||||
### Follow-ups
|
||||
*(tracked but not fixed in Phase 7)*
|
||||
|
||||
F1. **`select.tsx` `shadow-xs` survives** — the Phase 4 follow-up note on
|
||||
`select.tsx:38` was to drop `shadow-xs` from the trigger. Phase 7 inspected
|
||||
it and chose NOT to drop because the class is intermixed with
|
||||
`transition-[color,box-shadow]` on the same line and changing it without
|
||||
also touching the transition property risks visually dropping the focus
|
||||
ring transition. Non-blocking; defer to a dedicated Phase 7.5 shadcn
|
||||
sweep if we do one.
|
||||
|
||||
F2. **`input.tsx`, `textarea.tsx`, `toggle.tsx`, `checkbox.tsx`, `button.tsx`
|
||||
(outline variant) all use `shadow-xs`.** Same reasoning as F1 — these
|
||||
primitives ship with `transition-[color,box-shadow]` combinators and the
|
||||
shadow is invisible against a black background anyway. Deferred.
|
||||
|
||||
F3. **RunTranscriptUxLab non-cyan arbitrary shadows.** Lines 63, 152, 203 use
|
||||
`shadow-[0_24px_60px_rgba(15,23,42,...)]` (slate). Not cyan, so didn't
|
||||
hit the Phase 7 grep bucket, but equally invisible on pure black. And
|
||||
line 163 is `shadow-[0_0_0_6px_rgba(34,211,238,0.12)]` (cyan variant)
|
||||
which should also drop. Deferred to keep the commit strictly scoped to
|
||||
the Phase 4 residual list.
|
||||
|
||||
F4. **`BudgetPolicyCard.tsx:192` uses `shadow-[0_20px_80px_-40px_rgba(0,0,0,0.55)]`**.
|
||||
Pure-black shadow on pure-black canvas is definitionally invisible. Flagged
|
||||
for removal. Deferred because the file wasn't on the Phase 4 residual
|
||||
list.
|
||||
|
||||
F5. **`CompanyPatternIcon.tsx:206` uses `drop-shadow-[0_1px_2px_rgba(0,0,0,0.65)]`.**
|
||||
Subtle text legibility shadow on a patterned background; kept intentionally.
|
||||
|
||||
F6. **`BudgetSidebarMarker.tsx:8` and `SidebarNavItem.tsx:53` use
|
||||
`shadow-[0_0_0_Npx_...]`** for halo effects around notification dots.
|
||||
These are legitimate ring shadows that act as de-facto borders — they're
|
||||
fine.
|
||||
|
||||
F7. **`AgentDetail.tsx` (4104 lines) skimmed only.** Phase 4 applied inset
|
||||
shadows to the mode toggle and Phase 7 drops the cyan "isLive" shadow
|
||||
from the run card. Full pass deferred.
|
||||
|
||||
F8. **`IssueDetail.tsx` (1696 lines) skimmed only.** No obvious violations
|
||||
in the top-of-file layout.
|
||||
|
||||
F9. **Dead fallback `/dashboard` in `useCompanyPageMemory.test.ts` fixtures.**
|
||||
The test file stores `/dashboard` as the expected remembered path. After
|
||||
this phase's rewrite (see "Fixes applied"), `company-page-memory.ts`
|
||||
falls back to `/assistant`, which means this test file is now stale.
|
||||
Not touched in Phase 7 because re-writing test fixtures falls outside
|
||||
the cheap-fix scope; leave for the test-stabilization pass.
|
||||
|
||||
F10. **`useInboxBadge.ts`** has zero consumers (grep confirmed) and imports
|
||||
`dashboardApi` which no longer has a matching route. Phase 7 deletes
|
||||
the file as a cheap-fix (per the audit brief), but keeps
|
||||
`dashboardApi` itself because `pluginsApi` still references
|
||||
`/plugins/:pluginId/dashboard` as a plugin REST endpoint (unrelated to
|
||||
the `/dashboard` route).
|
||||
|
||||
F11. **AgentDetail self-reference breadcrumbs** — `AgentDetail.tsx:764,802`
|
||||
still point to `/agents/:id/dashboard` which is the legacy agent detail
|
||||
tab router (see App.tsx line 160 `agents/:agentId/:tab`). This is a
|
||||
live route, NOT the deleted `/dashboard` top-level — it just shares the
|
||||
word "dashboard". Verified with App.tsx:160. Leave as-is.
|
||||
|
||||
F12. **`dashboardApi.summary(companyId)` API** at `src/api/dashboard.ts:5`
|
||||
still exports `/companies/:id/dashboard`. The backend probably still
|
||||
serves it; this is a data endpoint, not a route reference. Out of scope.
|
||||
|
||||
## Fixes applied in this phase
|
||||
|
||||
See the commit log — Phase 7 ships:
|
||||
1. **`docs(nexus): phase 7 visual qa audit`** — this document.
|
||||
2. **`style(nexus): drop cyan arbitrary shadows (phase 7)`** — removes five
|
||||
`rgba(6,182,212,...)` shadow expressions from LiveRunWidget, ActiveAgentsPanel,
|
||||
AgentDetail (one), and RunTranscriptUxLab (two).
|
||||
3. **`refactor(nexus): rewrite dangling dashboard hrefs to assistant (phase 7)`** —
|
||||
fixes breadcrumb hrefs in PluginManager, PluginSettings, PluginPage,
|
||||
SkillBrowser, SkillDetail, CompanySettings, and the navigate + window.assign
|
||||
call sites in ProjectDetail + CompanyImport. Also updates
|
||||
`lib/company-page-memory.ts` fallback. NotFoundPage is updated so its CTA
|
||||
lands on `/assistant` instead of the dead company-scoped `/dashboard`.
|
||||
4. **`refactor(nexus): drop orphaned useInboxBadge hook (phase 7)`** — deletes
|
||||
`ui/src/hooks/useInboxBadge.ts` (zero consumers).
|
||||
5. **`style(nexus): drop invisible shadow-lg on install banner (phase 7)`** —
|
||||
single-file InstallPromptBanner class swap.
|
||||
|
||||
## Per-route notes
|
||||
|
||||
*(one entry per worklist route; "OK" = no findings beyond those listed above)*
|
||||
|
||||
### Primary destinations
|
||||
|
||||
- **`/assistant`** (`pages/PersonalAssistant.tsx`) — OK. Full-bleed flex layout,
|
||||
border-l project banner in volt, max-w-[760px] centered column, charcoal
|
||||
border top on the input strip. All tokens / classes are design-compliant.
|
||||
|
||||
- **`/content-studio`** (`pages/ContentStudio.tsx` + `components/studio/*`) — OK.
|
||||
Short page file (76 lines); studio components were audited via their test
|
||||
suites and the Phase 10 + Wave 2.5 notes. `WorkshopCard`, `StudioPromptBar`
|
||||
all check out.
|
||||
|
||||
- **`/content-studio/:workshopSlug`** (`pages/StudioWorkshopDetail.tsx`) — OK.
|
||||
362 lines; no shadow or raw-palette findings.
|
||||
|
||||
- **`/projects`** (`pages/Projects.tsx`) — OK. 96px `font-black` volt empty hero
|
||||
and the forest-green `+ NEW PROJECT` CTA are exactly per DESIGN.md §4. Note
|
||||
the `bg-[#166534]` literal (see Deviation 1).
|
||||
|
||||
- **`/projects/:projectId` + `/overview`** (`pages/ProjectDetail.tsx` +
|
||||
`tabs/OverviewTab.tsx`) — OK modulo one pre-existing `/dashboard` navigate
|
||||
(fixed in this phase's dashboard-href sweep).
|
||||
|
||||
- **`/projects/:projectId/issues`** (`tabs/IssuesTab.tsx`) — OK (delegates to
|
||||
real `IssuesList` component; charcoal borders).
|
||||
|
||||
- **`/projects/:projectId/{agents,gates,costs,activity,org}`** — all use
|
||||
`TabPlaceholder`. Placeholder itself (`components/projects/tabs/TabPlaceholder.tsx`)
|
||||
uses 4px-radius, charcoal border, pale-yellow gap badge. Compliant.
|
||||
|
||||
- **`/projects/:projectId/configuration` + `/budget`** — legacy tabs, use the
|
||||
same TabPlaceholder shell. OK.
|
||||
|
||||
- **`/instance/settings/general`** (`pages/InstanceGeneralSettings.tsx` + 8
|
||||
settings cards) — OK. Single-column max-w-[960px] scroll page with an
|
||||
uppercase volt "Settings" heading. Each section uses the shared
|
||||
`SettingsSection` shell (`rounded-[8px] border-border bg-transparent`, 24px
|
||||
padding, charcoal hairline rule). All section cards audited — no findings.
|
||||
|
||||
### Chrome (Phase 8 + 14 + 15)
|
||||
|
||||
- **`Layout.tsx`** — OK. Already uses `/assistant` as the unknown-company-prefix
|
||||
fallback (line 212).
|
||||
- **`IconRail.tsx`** (56px) — OK. Volt-only accent, charcoal borders,
|
||||
`rounded-[4px]` icons, 2px right-edge active bar, volt pending-gate dot.
|
||||
- **`TopStrip.tsx`** (48px) — OK. `border-b border-border bg-background`.
|
||||
- **`ModeBreadcrumb.tsx`** — OK. 14px semibold uppercase `tracking-[0.1em]`,
|
||||
leaf in volt, trunk in muted-foreground, slash separators.
|
||||
- **`CmdKButton.tsx`** — OK. Hover shifts border + text to volt.
|
||||
- **`GlobalMicButton.tsx`** — OK. Three visual states correctly wired to
|
||||
VoiceContext. Literal hexes noted in Deviation 1.
|
||||
- **`MobileTabBar.tsx`** (Phase 15) — OK. 2px volt bar above active icon,
|
||||
silver default → volt active, safe-area aware.
|
||||
- **`CommandPalette.tsx`** (Phase 14) — OK (consulted Phase 14 commit).
|
||||
|
||||
### Legacy detail pages
|
||||
|
||||
- **`/agents/new`** (`NewAgent.tsx`) — skimmed. No findings; uses tokens.
|
||||
- **`/agents/:agentId`** (`AgentDetail.tsx`, 4104 lines) — skim only per the
|
||||
Phase 7 directive. One cyan shadow on line 1107 dropped; two `dashboard`
|
||||
breadcrumb hrefs retained (they're legacy agent-tab router paths, not dead
|
||||
top-level routes — see F11).
|
||||
- **`/issues/:issueId`** (`IssueDetail.tsx`, 1696 lines) — skim only. No
|
||||
blockers in the visible layout header.
|
||||
- **`/company/settings`** (`CompanySettings.tsx`) — breadcrumb href fixed to
|
||||
`/assistant`.
|
||||
- **`/company/export/*`** (`CompanyExport.tsx`) — OK. References to
|
||||
`/company/export/...` are real routes, not dead dashboard links.
|
||||
- **`/company/import`** (`CompanyImport.tsx`) — post-import `window.location.assign`
|
||||
rewritten from `/${prefix}/dashboard` → `/${prefix}/assistant`. User-visible
|
||||
"company" vocab is already routed through `VOCAB.company` which resolves to
|
||||
"Workspace".
|
||||
- **`/skills/*`** (`CompanySkills.tsx`) — OK. SkillBrowser + SkillDetail
|
||||
breadcrumb hrefs fixed.
|
||||
- **`/execution-workspaces/:workspaceId`** (`ExecutionWorkspaceDetail.tsx`) —
|
||||
skimmed. No findings.
|
||||
|
||||
### Auth + landing + empty states
|
||||
|
||||
- **`/auth`** (`Auth.tsx`) — OK. Border-only inputs, foreground text,
|
||||
destructive error. Left half form, right half ASCII animation.
|
||||
- **`/invite/:token`** (`InviteLanding.tsx`) — not touched; out of scope scan.
|
||||
- **`/board-claim/:token`** (`BoardClaim.tsx`) — not touched.
|
||||
- **`/cli-auth/:id`** (`CliAuth.tsx`) — not touched.
|
||||
- **`/*`** (`NotFound.tsx`) — breadcrumb href was `/${prefix}/dashboard`.
|
||||
Rewritten to `/${prefix}/assistant` and the button label changed from
|
||||
"Open dashboard" to "Open assistant".
|
||||
- **Onboarding wizard** (`OnboardingWizard.tsx` + `onboarding/*`) — not touched;
|
||||
previous phases already covered.
|
||||
- **`/design-guide`** (`DesignGuide.tsx`, 1532 lines) — the canonical DESIGN.md
|
||||
showcase. Skimmed; not touched (any findings would be meta since the page
|
||||
IS the design system).
|
||||
|
||||
### Plugin subsystem
|
||||
|
||||
- **`/plugins/:pluginId`** (`PluginPage.tsx`) — back link href fixed.
|
||||
- **`/instance/settings/plugins`** (`PluginManager.tsx`) — breadcrumb href fixed.
|
||||
- **`/instance/settings/plugins/:pluginId`** (`PluginSettings.tsx`) — breadcrumb
|
||||
href fixed.
|
||||
|
||||
## Top 3 recommended follow-ups (by visual impact)
|
||||
|
||||
1. **Wire the forest-green and pale-yellow token classes** — eliminates the
|
||||
`bg-[#166534]` / `bg-[#f4f692]` literals in ProjectCard, Projects,
|
||||
GlobalMicButton, and TabPlaceholder. Low-risk `index.css` addition plus a
|
||||
grep-and-replace. One commit of ~15 line touches. (MIGRATION-PLAN.md §3.)
|
||||
|
||||
2. **Drop the remaining `shadow-xs` survivors in shadcn primitives** (F1 + F2)
|
||||
and collapse their `transition-[color,box-shadow]` to `transition-colors`.
|
||||
Five files, ten lines total. Visible improvement: removes the last
|
||||
"invisible on black" shadow artifacts.
|
||||
|
||||
3. **Resolve the Basier font decision** (Deviation 2). Either license + load
|
||||
it, or formally accept Inter as the sole display font and update
|
||||
DESIGN.md §3 to match. This is the last open item from the visual repaint
|
||||
and blocks closing the MIGRATION-PLAN open-decisions list.
|
||||
Loading…
Add table
Reference in a new issue