Import the R2 implementation spec into the repo

The plan was delivered as wp-suite-implementation-spec.zip and lived only in
Downloads, so every "read CLAUDE.md first" instruction in it pointed at a file
the repo did not have. Bring it in unchanged: CLAUDE.md, IMPLEMENTATION.md, and
docs/waves/wave-0 through wave-9 plus backlog.md.

UX-REVIEW-2026-08-14.md is committed alongside it. It is the review that
produced F1-F6, S1-S13 and the A/B/C assessments, and item IDs throughout the
wave files cite it, so it belongs under version control rather than sitting
untracked in the working tree.

No application code changes here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-14 17:42:56 -05:00
parent 9459e76a6c
commit 3d99d4b9d0
14 changed files with 2254 additions and 0 deletions

120
UX-REVIEW-2026-08-14.md Normal file
View File

@@ -0,0 +1,120 @@
# UX Review — Work Package Suite
**Date:** 2026-08-14 · **Branch:** `users/directory-super-user` · **Scope:** `html/` — 6 pages, 4 stylesheets, ~11.9k lines
Full write-up with screenshots: <https://claude.ai/code/artifact/09d89aa1-54b9-41db-9e09-e1fc8fb55852>
**Method.** Two passes. A full read of the frontend, then the app run locally
(`uvicorn server.app:app`, throwaway SQLite DB) and driven in Chrome through the real
first-run flow: sign in → create project → SOP wizard → creator → directory → field view
at 390px. Section 1 below is browser-verified; section 2 is read from source.
> Incidental find: `server/seed_demo.py` no longer authenticates, so it can't seed a
> running instance — every `/api/` route requires a session and the script sends none.
> It predates the commit that taught the smoke test to sign in.
---
## 1. Rendering defects (browser-verified, reproducible today)
No design decisions needed for any of these.
| # | Defect | Severity |
|---|---|---|
| F1 | **Header project switcher is stale on every page.** Hero, picker and create-user card show the active project; the app bar still reads "Select a project". Two sources of truth, global one loses. | High |
| F2 | **App bar breaks at 390px — on Field View.** Nav wraps to 3 rows and clips: "Sign out" cut in half, search truncated. This is the gloved-hands surface. | High |
| F3 | **Logo/project-name collision in the SOP header.** `.header-left` and the injected chrome fight for the same run of the bar. | Medium |
| F4 | **Comments drawer renders off-screen over the header** in the standalone creator. | Medium |
| F5 | **SOP wizard fields read as read-only**`#f4f4f4` fill, `#e0e0e0` border. Cause: the wizard redeclares its own tokens and never sees `--cds-field: #ffffff`. | Medium |
| F6 | **The creator is one ~4,700px form** — 11 cards rendered at once, jump links standing in for structure. | Medium |
F1 and F2 are prerequisites for the proposed chrome work.
---
## 2. Structural findings (from source)
### Costs users work
- **Validation is `alert()`-only, covering 3 of 10 wizard steps.** 79 native dialogs app-wide,
43 in the creator. `wp-creation-app.js:1144` says "Subject and WP Type are required" without
naming, highlighting or scrolling to the field — on a form ten cards deep.
`validateStep` guards only steps 1, 5, 6 while the markup marks required fields throughout.
- **No autosave, no unsaved-work guard.** The only `beforeunload` listener is analytics dwell
tracking (`work-package-suite-app.js:326`).
- **Nothing is linkable.** No `pushState` anywhere. Tab switches, dashboard views and package
selections change no URL — can't send someone a link to WP07; refresh loses your place.
- **No global nav on the two pages people live in.** Drawer + app bar ship on `admin`, `field`,
`users`. The SOP wizard has its own header and no drawer; the creator has neither, plus a
different brand treatment (mono wordmark vs. logo chip).
### Costs consistency
- **Four parallel token systems.** `#0f62fe` is declared 4× (`--cds-interactive-01`, `--primary`,
`--accent` twice). Already caused a bug — see the comment at
`work-package-suite-styles.css:336` about `.field-hint` rendering unstyled.
- **Icon set is mixed emoji + dingbats** (⤓ ⤒ 👁 ★ 📊 ⧉ 🕘 💬 ▤ ⚙ 🔒 ⚡ ⎙ ◔ ▦). `▤` is used for
two different things on the same page.
- **Four sample-data affordances under three names.** One sits a click from live project data
with no confirm and no undo.
### Costs accessibility (and the field case)
- **Hover-only tooltips carry load-bearing instructions.** 15 `.help-tip` badges, `<span>`s with
no `tabindex` — so the `:focus` half of their CSS rule is dead code and there's no touch path.
- **SOP step rail not keyboard-reachable.** All 10 steps are `<div onclick>`; 12 `<div>` + 2
`<span>` click handlers app-wide.
- **Zero `aria-live` regions.** Both toast systems and every admin banner announce nothing.
`login.html` gets this right with `role="alert"`/`role="status"`; the pattern never spread.
- **Helper text at ~2.9:1** (`--text-dim: #8d8d8d` at 12px). `console.css:85-87` already
diagnosed and fixed this; the other two sheets didn't follow.
- **Wizard removes the focus ring** — `outline: none` plus a pale 3px glow
(`work-package-suite-styles.css:322-328`).
---
## 3. Assessment of the proposed change list
Strong work — nearly every item maps to something verifiable, and two rank above anything in
this review's own findings. 9 endorsed, 7 need adjustment, 6 gaps.
### Endorse as proposed
| ID | Item | Note |
|---|---|---|
| A1 | **Guarded status transitions** | Best item on the list. But: Issue (Hold) is a *branch* from several states, and there's a deliberate **logged-override** path for predecessors (`wp-creation-app.js:1962-1972`). "One legal next action" is too narrow — model as primary-next **+ audited override**. |
| A2 | De-duplicate constraint warning | Triplication confirmed. Caveat: the top banner is the only one visible without scrolling, so the tab count badge must carry that weight. |
| A3 | Fields that look editable | Confirmed (F5). Pair with token consolidation or it drifts back. |
| A4 | Vertical stepper + progress | Also retires the orphaned "1 / 10" counter. Make the steps real `<button>`s while rebuilding. |
| A5 | One button system, no green/blue mix | Real: green `Save & View` + green `SOP Complete` vs blue elsewhere. **Scope "sentence case" to buttons/field labels** — the uppercase card-header idiom in `console.css` is deliberate and works. |
| A6 | Sidebar triage data + inline hold reason | Cheap — hold reason is already captured by the hold modal. |
| A7 | Card status lines · footer clarity · Language & time | Localization is a real shipped feature (`admin.js:484-517`), so keeping it is correct. |
### Right diagnosis, adjust the prescription
| ID | Item | Adjustment |
|---|---|---|
| B1 | Collapse the 8-item nav | **Don't build a new avatar menu — ship the drawer you already have.** It's the best chrome in the app and already holds the whole nav; it's just on 3 pages of 6 while a flat strip duplicates it. Put it everywhere, delete the strip. Fixes F2. |
| B2 | Un-truncate the switcher | Fix **correctness (F1) first**. "Micron EUV Cleanroom Enable · 2667008" won't fit 280px, and existing rules narrow it to 150px under 900px — needs a breakpoint plan. |
| B3 | Remove the project-picker card | The first-run empty state lives *inside* that card. A header dropdown is the wrong home for "create your first project" — the launcher needs an explicit empty state. |
| B4 | 4-cell pipeline strip | Hard data dependency: launcher SOP status reads `localStorage`, and the creator's dashboard admits it "reads local data now; wires to SQL in Phase 2". Per-browser numbers that look authoritative are worse than none. **Server aggregates first.** |
| B5 | Autosave status text | Must ship with **actual autosave + dirty guard**. A "✓ All changes saved" toast already appears (that's the sync outbox, not your draft), so the app arguably implies this today. |
| B6 | Wizard actions beside the fields | On Constraints/Sequence steps that means scrolling to save. **Prefer sticky** — the creator's sticky save bar already solves it. |
| B7 | Toolbar into the tab row | Unstated prerequisite: tab row is in the parent, toolbar in the iframe child. This **requires dissolving the iframe** — the largest engineering item on the list. Name and schedule it. |
### Not addressed
| ID | Gap |
|---|---|
| C1 | **Accessibility** — and the redesign touches every broken part. The step rail being rebuilt is 10 `<div onclick>`s; the status pills being replaced are the moment for a real radio group; the tooltips are unreachable on the tablet Field View targets. Skipping these means paying for the same components twice. |
| C2 | **Mobile** — no item on the list, and it's where the worst rendering is (F2). |
| C3 | **Token consolidation** — without it, "one button system" gets implemented four times and drifts, exactly as `.field-hint` did. |
| C4 | **URL state · icon system · unsaved-changes guard · sample-data sprawl** — none addressed. |
---
## 4. Recommended sequence
Ordered by dependency, not preference.
1. **The six rendering defects.** No design decisions; F1/F2 unblock the chrome work.
2. **Drawer everywhere, flat strip deleted.** Reuses the best existing component, fixes phone-width collapse, settles global nav before anything is redrawn.
3. **Token consolidation.** One source of truth, page sheets aliasing to it. Every later visual item lands once instead of four times.
4. **Launcher + SOP wizard.** Pipeline strip (after server aggregates), empty-state ownership, vertical stepper, editable fields, autosave + guard. Make the 10 steps buttons while rebuilding.
5. **The creator.** Guarded transitions, de-duplicated warnings, section tabs, triage data. **Decide the iframe question up front** — most of this depends on it.
**Dependencies:** B1 resolves F2 · B2 depends on F1 · A3 depends on C3 · B7 gates most of step 5.