"Micron EUV Cleanroom Enable 2667008" did not fit. The switcher capped the name
at 240px inside a 280px button, so the real project name was ellipsised to
"Micron EUV Clean..." on the one control whose job is to tell you which job you
are in - which is the failure this item exists to prevent.
The plan, now written into docs/reference/file-map.md so it is not re-litigated:
>= 1024px the full project NAME. Caps raised to 400px / 340px, which is
enough for a real name with no ellipsis.
< 1024px the project NUMBER alone, e.g. 2667008. Dropping the name beats
shortening it: short, stable, unambiguous.
The number is no longer prefixed to the name at wide widths. Real names already
end with their number, so the old format printed it twice - the test project
rendered as "2667008 - Micron EUV Cleanroom Enable 2667008".
The full name stays reachable at every width by three routes, none hover-only,
because the Field View is a touch surface:
- the drawer, which now shows the active project under its head, wrapping onto
as many lines as it needs and never truncated. This is the guaranteed route,
and it subscribes to ProjectData.onActiveChange so it does not go stale when
the launcher switches project without reloading.
- the switcher's title attribute, carrying the full number and name, which
surfaces on keyboard focus as well as hover.
- the switcher popover, which lists every project in full.
Crossing the breakpoint re-labels, so a resized window does not keep whichever
form was chosen at load.
Verified with the real long name at 390, 768, 1024 and 1440: nothing truncated
at any width (scrollWidth vs clientWidth, not by eye), and the drawer carries
the whole name at all four. T1.1 correctness holds - the switcher never reads
"Select a project" while a project is active.
f_items: F1-F5 FIXED, F3 still passing at all four widths with the wider
switcher. browser_check 71/71.
Wave 2 complete: one drawer on six pages, no flat strip, F2 resolved for real,
S4 closed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
364 lines
20 KiB
Markdown
364 lines
20 KiB
Markdown
# File map — `html/` and the references the plan depends on
|
||
|
||
**Task:** `T0.1` · **Produced:** August 14, 2026 · **Branch:** `feat/wp-suite-r2-implementation`
|
||
|
||
Wave 0 exists because the item IDs and line numbers in this plan came from a UX review of
|
||
branch `users/directory-super-user`, not from a fresh read. This document is the fresh read.
|
||
Everything below was verified against the working tree, not quoted from the review.
|
||
|
||
**Read the [Discrepancies](#discrepancies) section before starting any wave.** Four things the
|
||
plan asserts are wrong, and one of them (`A1`) guards a code path CLAUDE.md says must not change.
|
||
|
||
---
|
||
|
||
## 1. Pages
|
||
|
||
`html/` holds **7 pages, 6 stylesheets, 11,867 lines**. The plan says "6 pages, 4 stylesheets,
|
||
roughly 11,900 lines" — the line count is right, the other two are not. See D1.
|
||
|
||
| Page | Called in this plan | Lines | Stylesheets (load order) | Scripts (load order) | Iframe |
|
||
|---|---|---|---|---|---|
|
||
| `html/login.html` | login | 163 | `theme-light.css` | `login.js` | neither |
|
||
| `html/index.html` | launcher | 703 | `theme-light.css`, `wp-chrome.css` | `auth-guard`, `wp-format`, `feedback-config`, `project-data`, `help`, *(inline 418–700)*, `wp-chrome` | neither |
|
||
| `html/work-package-suite.html` | SOP wizard | 437 | `theme-light.css`, `wp-chrome.css`, `work-package-suite-styles.css` | `auth-guard`, `wp-format`, `feedback-config`, `project-data`, `help`, `work-package-suite-app`, `wp-chrome` | **hosts** |
|
||
| `html/wp-creation-index.html` | creator | 401 | `theme-light.css`, `wp-creation-styles.css` | `auth-guard`, `wp-format`, `feedback-config`, `project-data`, `help`, `wp-creation-app` | **child** |
|
||
| `html/admin.html` | admin | 219 | `theme-light.css`, `wp-chrome.css`, `console.css`, `wp-sidenav.css` | `auth-guard`, `wp-format`, `console-util`, `admin`, `wp-chrome`, `wp-sidenav` | neither |
|
||
| `html/users.html` | directory/users | 106 | `theme-light.css`, `wp-chrome.css`, `console.css`, `wp-sidenav.css` | `auth-guard`, `wp-format`, `console-util`, `users`, `wp-chrome`, `wp-sidenav` | neither |
|
||
| `html/field.html` | field view | 93 | `theme-light.css`, `wp-chrome.css`, `wp-sidenav.css` | `auth-guard`, `wp-format`, `project-data`, `help`, `field`, `wp-chrome`, `wp-sidenav` | neither |
|
||
|
||
No script anywhere in `html/` uses `defer`, `async`, or `type="module"`. Every one is a
|
||
render-blocking classic script. `auth-guard.js` and `wp-format.js` load in `<head>`; the rest
|
||
load at the end of `<body>`.
|
||
|
||
### The iframe boundary (matters for `B7` / `T7.1`)
|
||
|
||
`work-package-suite.html:383` declares `<iframe id="wp-frame">` with **no `src`**.
|
||
`work-package-suite-app.js:581` sets it at runtime to
|
||
`wp-creation-index.html?embedded=1&project=<id>`.
|
||
|
||
The creator is the only page that loads **neither `wp-chrome.css` nor `wp-chrome.js`** — that is
|
||
why it has no app bar of its own and why it looks like part of the wizard. `T7.1` has to give it
|
||
that chrome back, or deliberately not.
|
||
|
||
Three scripts branch on `window.top !== window.self` and will change behaviour when the frame
|
||
goes away:
|
||
|
||
| Script | Line | Framed behaviour |
|
||
|---|---|---|
|
||
| `auth-guard.js` | 15 | redirects `window.top` to `login.html` |
|
||
| `wp-chrome.js` | 17 | returns early, renders no chrome |
|
||
| `help.js` | — | suppresses the Help FAB in the child |
|
||
|
||
### Pages that are not what the plan implies
|
||
|
||
- **`field.html` is 93 lines.** It is a shell; `field.js` (178 lines) builds it. A task that says
|
||
"edit the field view page" almost always means `field.js`.
|
||
- **`index.html` carries ~296 lines of inline `<style>`** (lines 16–312) — the bulk of the
|
||
launcher's CSS is not in any stylesheet. `T3.x` token work has to reach inside it.
|
||
- **`admin.html` and `users.html` are near-identical shells** over `console.css` + `console-util.js`.
|
||
|
||
---
|
||
|
||
## 2. Stylesheets
|
||
|
||
| File | Lines | Purpose | Consumed by |
|
||
|---|---|---|---|
|
||
| `theme-light.css` | 249 | Carbon light (g10) token set, base type, shared dark appbar | **all 7 pages** (always first) |
|
||
| `console.css` | 191 | dense admin tables and toolbars | admin, users |
|
||
| `work-package-suite-styles.css` | 610 | SOP wizard page sheet | SOP wizard |
|
||
| `wp-chrome.css` | 237 | injected chrome: project switcher, global search | launcher, SOP wizard, admin, users, field |
|
||
| `wp-creation-styles.css` | 884 | creator page sheet | creator |
|
||
| `wp-sidenav.css` | 90 | off-canvas nav drawer | admin, users, field |
|
||
|
||
**No `@import` exists in any stylesheet.** Composition is entirely `<link>` order.
|
||
`theme-light.css` is linked first on all 7 pages.
|
||
|
||
### The four parallel token systems (`S5`, consolidated in wave 3)
|
||
|
||
| Sheet | Prefix | Root tokens |
|
||
|---|---|---|
|
||
| `theme-light.css` | `--cds-*` (2–117) and `--wp-appbar-*` (169–176) | 114 + 6 |
|
||
| `console.css` | **unprefixed** (12–20) | 28 |
|
||
| `work-package-suite-styles.css` | **unprefixed** (1–18) | 16 |
|
||
| `wp-creation-styles.css` | **unprefixed** (9–31) | 21 |
|
||
| `wp-chrome.css` | `--wpc-*`, scoped to `.wp-chrome`, **not `:root`** (18–36) | 0 at root |
|
||
| `wp-sidenav.css` | none — every colour is a hardcoded hex | 0 |
|
||
|
||
The three unprefixed sheets are the collision risk. They are **mutually exclusive per page**
|
||
today (console on admin+users, wizard sheet on the wizard, creator sheet on the creator), so
|
||
nothing currently breaks — wave 3 must not assume that stays true once chrome is unified.
|
||
|
||
Redeclared across sheets with the **same** value: `--bg`, `--border`, `--border-strong`,
|
||
`--text`, `--accent`, `--red`, `--shadow`, `--text-dim`.
|
||
Redeclared with **different** values — these are the real defects:
|
||
|
||
- `--shadow-lg` — `0 4px 16px rgba(0,0,0,0.16)` (wizard) vs a different blur in the creator
|
||
- `--mono` — `console.css` drops `ui-monospace` and `Segoe UI Mono` from the stack
|
||
- `--surface` — `#fff` (console) vs `#ffffff` (creator); same colour, two notations
|
||
- `--appbar: #161616` (wizard) duplicates `--wp-appbar-bg: #161616` (theme) under another name
|
||
|
||
Set at runtime on `documentElement`, declared in no stylesheet:
|
||
`--wp-chrome-h` (`work-package-suite-app.js:528`), `--rail-top` (`wp-creation-app.js`).
|
||
Declared on `body` rather than `:root`: `--nav-w` (`wp-creation-styles.css:673,674,805`).
|
||
|
||
Only cross-file dependency: `work-package-suite-styles.css` consumes `--cds-hover-primary`,
|
||
which only `theme-light.css` declares.
|
||
|
||
---
|
||
|
||
## 3. Verified references
|
||
|
||
Every reference the plan relies on, checked against the working tree.
|
||
|
||
| Reference | Claim | Status | Actually |
|
||
|---|---|---|---|
|
||
| `wp-creation-app.js:1144` | `alert()` "Subject and WP Type are required" | **CONFIRMED** | exact |
|
||
| `wp-creation-app.js:1962-1972` | logged-override path for predecessors | **MOVED — see D2** | that range is `dashIssue()`, which *refuses*. Real path: **`967–984`** |
|
||
| `work-package-suite-app.js:326` | only `beforeunload`, analytics dwell | **CONFIRMED** | exact; sole `beforeunload` in all of `html/` |
|
||
| `work-package-suite-styles.css:322-328` | `outline:none` + pale 3px glow | **CONFIRMED** | block runs 321–328, `outline:none` on 325 |
|
||
| `work-package-suite-styles.css:336` | comment about `.field-hint` unstyled | **CONFIRMED** | comment 336–338, rule on 339 |
|
||
| `console.css:85-87` | contrast fix not propagated | **CONFIRMED** | comment 85–87, fix on 88 |
|
||
| `admin.js:484-517` | language and time localization | **CONFIRMED** | exact — "Localization defaults" block |
|
||
| `server/seed_demo.py` | seeds without authenticating | **CONFIRMED** | zero auth code in 178 lines |
|
||
|
||
Notes that change what a later task should do:
|
||
|
||
- **`work-package-suite-styles.css`** — `outline: none` appears **three** times, not once: 325
|
||
(the cited block), 347 (`.user-pick:focus`, same pale glow), and 501
|
||
(`.seq-step input.seq-label:focus`, *no* replacement glow at all). `A3`/`F5` should fix all three.
|
||
- **`console.css:85-87`** — the comment measures `#8d8d8d` on white at **3.3:1**. Wave 4's `T4.6`
|
||
says "about 2.9:1". They disagree; `T4.6` should re-measure rather than quote either. Both
|
||
other sheets still bind helper text to the rejected `#8d8d8d`
|
||
(`work-package-suite-styles.css:10`, `wp-creation-styles.css:17`), and the creator applies it
|
||
at **10px** (`wp-creation-styles.css:374`), worse than the 12px the comment measures.
|
||
- **`seed_demo.py`** fails *loudly but confusingly*: `call()` swallows the `HTTPError` and returns
|
||
the error body, so line 101's `proj["id"]` raises `KeyError` instead of reporting a 401.
|
||
Only `/api/health` is unauthenticated, so the health check passes and it dies immediately after.
|
||
|
||
---
|
||
|
||
## 4. Baseline counts
|
||
|
||
Recorded so wave 9 can prove they went down. Run from `html/` unless stated.
|
||
|
||
| # | Metric | Review | Actual | Command |
|
||
|---|---|---|---|---|
|
||
| 1 | native dialogs app-wide | 79 | **79** ✓ | `grep -ohE '\b(alert\|confirm\|prompt)\(' *.js *.html \| wc -l` |
|
||
| 2 | …of those, in the creator | 43 | **43** ✓ | same, over `wp-creation-app.js` |
|
||
| 3 | `<div onclick>` | 12 | **12** ✓ | `grep -oE '<div[^>]*onclick' *.html *.js \| wc -l` |
|
||
| 4 | `<span onclick>` | 2 | **2** ✓ | `grep -oE '<span[^>]*onclick' *.html *.js \| wc -l` |
|
||
| 5 | `#0f62fe` accent systems | 4 | **4** ✓ | see below |
|
||
| 6 | `.help-tip` badges | 15 | **15** ✓ | `grep -oE 'class="help-tip"' *.html \| wc -l` |
|
||
| 7 | `aria-live` regions | 0 | **0** ✓ | `grep -ohE 'aria-live' *.html *.js \| wc -l` |
|
||
| 8 | `pushState` calls | 0 | **0** ✓ | `grep -ohE 'pushState' *.html *.js \| wc -l` |
|
||
|
||
Dialogs by file: `wp-creation-app.js` 43 · `work-package-suite-app.js` 14 · `users.js` 10 ·
|
||
`admin.js` 6 · `index.html` 6.
|
||
`<div onclick>` by file: `work-package-suite.html` 10 · `wp-creation-index.html` 1 ·
|
||
`work-package-suite-app.js` 1. Both `<span onclick>` are in `wp-creation-app.js`.
|
||
|
||
**Metric 5 needs its definition stated**, or wave 9 will measure a different thing.
|
||
`#0f62fe` appears **31** times across `html/`, and **14** of those are custom-property
|
||
declarations. The review's "4" is the number of **stylesheets that declare their own accent
|
||
token** — the four parallel systems:
|
||
|
||
```
|
||
grep -nE '^\s*--[a-zA-Z0-9-]+\s*:\s*#0f62fe' *.css # 14 declarations, in 4 sheets
|
||
```
|
||
|
||
| Sheet | Token |
|
||
|---|---|
|
||
| `theme-light.css` | `--cds-interactive-01` (+ 6 Carbon aliases) |
|
||
| `work-package-suite-styles.css:2` | `--primary` |
|
||
| `wp-chrome.css:25` | `--wpc-accent` |
|
||
| `wp-creation-styles.css:18` | `--accent` |
|
||
|
||
**The wave 9 target is 1.** Track the sheet count, not the raw occurrence count.
|
||
|
||
**Metric 6:** 15 in page markup (`work-package-suite.html` 3, `wp-creation-index.html` 12).
|
||
A 16th lives in `help.js:261` inside the help centre's own copy, demonstrating the component —
|
||
it is not a page badge. None carries `tabindex`, and `help.js:26` styles only `:hover`/`:focus`,
|
||
so a `<span>` with no tabindex is **keyboard-unreachable**. That is the `C1` defect, and it
|
||
confirms "unreachable" literally.
|
||
|
||
**Metric 7:** `login.html:99-100` uses `role="alert"` and `role="status"`, which are implicit
|
||
live regions. The count of the literal `aria-live` attribute is 0, matching the review. CLAUDE.md
|
||
points at these two lines as the pattern to copy — they are real and correct.
|
||
|
||
**Metric 8:** `pushState` is 0. There is **one** `history.replaceState` at `login.js:196`,
|
||
cleaning the URL after sign-in. It is not routing, so `X1`'s premise holds: no work package has
|
||
an addressable URL.
|
||
|
||
---
|
||
|
||
## 5. Running it
|
||
|
||
```bash
|
||
uvicorn server.app:app # against a throwaway SQLite database
|
||
python server/smoketest.py # API; needs WP_SMOKE_USER / WP_SMOKE_PASSWORD
|
||
python tests/browser_check.py # pages boot and render, self-contained
|
||
python tests/baseline_shots.py # screenshots, self-contained
|
||
python tests/f_items.py # does each of F1-F6 still reproduce?
|
||
```
|
||
|
||
`server/smoketest.py` is the one that is **not** self-contained: it drives a server you point
|
||
it at and aborts unless `WP_SMOKE_USER` and `WP_SMOKE_PASSWORD` are set, because every route
|
||
but `/api/health` needs a session. Use an admin account — it creates and deletes a project.
|
||
|
||
`tests/browser_check.py` and `tests/baseline_shots.py` are self-contained: each creates a
|
||
throwaway SQLite database, seeds a fixture, starts its own uvicorn on a free port, drives
|
||
headless Edge or Chrome over CDP, and tears everything down. **Your real `wpsuite.db` is never
|
||
touched.** Both need Edge or Chrome on the machine; set `WP_BROWSER` to override discovery.
|
||
|
||
Screenshots for a before/after pair:
|
||
|
||
```bash
|
||
python tests/baseline_shots.py --out docs/reference/baseline # before (committed)
|
||
python tests/baseline_shots.py --out /tmp/after --label after # after
|
||
python tests/baseline_shots.py --pages creator --widths 390,768,1024,1440
|
||
```
|
||
|
||
`tests/` is referenced by **no wave file**. `T0.2` needs screenshots and `T7.3` requires "a
|
||
regression test covers the clear-last-constraint path" without naming a home for it — both
|
||
belong here.
|
||
|
||
`tests/f_items.py` is both halves of the same measurement: it recorded that all six defects
|
||
reproduce before wave 1, and it is how waves 1–3 prove each one stopped. An item is done when
|
||
its probe flips from `REPRODUCES` to `FIXED`. It never reports a silent pass — a probe that
|
||
cannot decide says `INCONCLUSIVE`.
|
||
|
||
---
|
||
|
||
## The project switcher: what it shows at each width (`B2`, `T2.3`)
|
||
|
||
Written here because `T2.3` says to, so it is not re-litigated. Test name is always
|
||
**"Micron EUV Cleanroom Enable 2667008"** — the real one, and the one that breaks things.
|
||
|
||
| Width | The app bar shows | Why |
|
||
|---|---|---|
|
||
| **≥ 1024px** | the full project **name** | There is room. The cap is raised to 400px (button) / 340px (name) so a real name fits without an ellipsis. |
|
||
| **< 1024px** | the project **number** alone, e.g. `2667008` | Short, stable, unambiguous. Dropping the name entirely beats shortening it to "Micron EUV Clean…" on the one control whose job is to tell you which job you are in. |
|
||
|
||
The number is not prefixed to the name at wide widths. Real project names already end
|
||
with their number, so `2667008 — Micron EUV Cleanroom Enable 2667008` printed it twice.
|
||
|
||
**The full name is reachable at every width by three routes**, none of them hover-only
|
||
(Field View is a touch surface — `C1`):
|
||
|
||
1. **The drawer** — `.wp-sidenav-proj`, under the drawer head, on every page. Wraps onto
|
||
as many lines as it needs and is never truncated. This is the guaranteed one.
|
||
2. **The switcher's `title`** — the full `number — name`, so it surfaces on hover *and*
|
||
on keyboard focus.
|
||
3. **The switcher popover** — every project is listed with its full name and number.
|
||
|
||
The ellipsis is kept only as a backstop for a name longer than anything real. Verified
|
||
at 390, 768, 1024 and 1440: no truncation at any of them, and the drawer carries the
|
||
whole name at all four.
|
||
|
||
`T1.1` correctness is preserved — with a project active the switcher never reads
|
||
"Select a project"; with none active it reads exactly that at every width.
|
||
|
||
## Discrepancies
|
||
|
||
Things the plan asserts that the repo contradicts. Listed per T0.1's fourth done-when.
|
||
|
||
### D1 — "6 pages, 4 stylesheets" is wrong; it is 7 and 6
|
||
|
||
`wave-0.md:21` says 6 pages and 4 stylesheets. There are **7 pages and 6 stylesheets**. T0.1's
|
||
own parenthetical at `wave-0.md:24-25` lists **seven** names, so the document contradicts itself
|
||
in the same task. The missing stylesheets are `wp-chrome.css` and `wp-sidenav.css`.
|
||
|
||
**Consequence:** every "all 6 pages" done-when in waves 2, 3, 5 and 9 is off by one, and `T0.2`
|
||
asks for "12 baseline screenshots (6 pages x 2 widths)" when the correct number is **14**.
|
||
14 were captured. Treat "6 pages" as "all pages" wherever it appears.
|
||
|
||
### D2 — `A1`'s protected line reference points at the wrong function
|
||
|
||
This is the important one. CLAUDE.md, under *Things that must not change*, says:
|
||
|
||
> **The logged-override path for predecessors stays (A1).** It is an audited business rule, not
|
||
> a bug. See `wp-creation-app.js:1962-1972`.
|
||
|
||
`IMPLEMENTATION.md`'s `X2` cites the same range. **Lines 1962–1972 are `dashIssue()`**, which is
|
||
the *opposite* code: the dashboard guard that **refuses** to issue and tells you to
|
||
"Open the package to release it early with a logged reason". The reviewer read that sentence and
|
||
correctly concluded a logged override exists — but cited the mention, not the implementation.
|
||
|
||
The actual audited path is:
|
||
|
||
| Part | Location |
|
||
|---|---|
|
||
| **`confirmEarlyRelease()` — the override itself** | **`wp-creation-app.js:967-984`** |
|
||
| state `pkgGateOverride` | `:392`, reset at `:481`, `:488`, `:1744` |
|
||
| call site — status change | `:998-1002` |
|
||
| call site — save | `:1149-1150` |
|
||
| persisted onto the package | `:1117` (`gateOverride:`) |
|
||
| rendered in the printed package | `:1215` |
|
||
| rehydrated when loading a package | `:1674` |
|
||
| the *guard* the plan actually cited | `:1960-1974` (`dashIssue`) |
|
||
|
||
The comment at `:967-969` states the rule plainly: *"Releasing with an unclosed predecessor is
|
||
allowed but must be explained. The reason rides on the package (`data.gateOverride`) and the
|
||
server writes it to the audit log."*
|
||
|
||
**Consequence for `T7.3`:** the "do not remove" instruction must be applied to **`967-984` and
|
||
its seven satellites**, not to `1962-1972`. A task that preserved only 1962–1972 would delete the
|
||
audited business rule while believing it had protected it. `dashIssue()` must also survive — it
|
||
is what stops the dashboard becoming a quiet way around the gate — but it is a second thing to
|
||
protect, not the same thing.
|
||
|
||
`X2`'s reasoning is unaffected: hold state genuinely is not purely derived from open
|
||
constraints, so `CR-015` and `A1` remain the same code and the same task.
|
||
|
||
### D3 — four documents the plan reads from do not exist yet
|
||
|
||
Not errors; they are deliverables not yet produced. Recorded so no task treats one as a missing
|
||
input and goes looking for a rename.
|
||
|
||
| Path | Created by | Also read by |
|
||
|---|---|---|
|
||
| `docs/reference/file-map.md` | `T0.1` | `T0.2`, `T1.1`, `T2.1`, `T2.3` |
|
||
| `docs/reference/tokens.md` | `T3.1` | `T3.2`, `T3.5`, `T9.3` |
|
||
| `docs/reference/accessibility-audit.md` | `T9.5` | — |
|
||
| `docs/reference/completion.md` | `T9.7` | — |
|
||
|
||
`backlog.md:16` contains `path/to/file.js:120` inside a fenced format template. It is a
|
||
placeholder, not a reference — do not resolve it.
|
||
|
||
### D5 — `T2.1`'s premise is already satisfied: there are no "three near-copies"
|
||
|
||
`wave-2.md:25` asks to "lift the drawer into one shared implementation the pages include,
|
||
rather than three near-copies". There are no copies. `html/wp-sidenav.js` (221 lines) and
|
||
`html/wp-sidenav.css` (90 lines) are already **one** implementation, included by admin,
|
||
field view and directory. Verified: `.wp-sidenav`, `.wp-navscrim` and `.wp-navbtn` are
|
||
declared in exactly one file, and no page defines its own drawer.
|
||
|
||
The review said the drawer "ships on 3 of 6 pages while a flat strip duplicates it". The
|
||
duplication is between the drawer and the **flat strip**, not among three drawers. The plan
|
||
appears to have read "3 of 6 pages" as "3 copies".
|
||
|
||
It already meets every `T2.1` done-when as it stands, including the last one: `activeProjectId()`
|
||
(`wp-sidenav.js:62-68`) reads `?project=` then falls back to `ProjectData.getActiveId()`, which
|
||
is the single source `T1.1` established. It also self-mounts into `.wp-appbar` **or** `.header`
|
||
and returns early inside an iframe, so it is already built to go on the remaining pages.
|
||
|
||
**Consequence:** `T2.1` is a no-op beyond this verification. The real work of wave 2 is `T2.2`.
|
||
Nothing was refactored, because refactoring a single shared component into a single shared
|
||
component would be churn with regression risk and no gain.
|
||
|
||
### D4 — the creator overflows horizontally at 1440px, not just at 390px
|
||
|
||
Measured during `T0.2`, not in the review. Content width against the viewport it was given:
|
||
|
||
| Page | 390px | 1440px |
|
||
|---|---|---|
|
||
| launcher | 425 | ok |
|
||
| SOP wizard | 429 | ok |
|
||
| creator | 485 | **1551** |
|
||
| field view | 432 | ok |
|
||
| login, admin, users | ok | ok |
|
||
|
||
Four pages overflow at 390px, which is `F2` and its neighbours. The creator also overflows by
|
||
111px **at desk width**, which no `F` item covers. Logged to `docs/waves/backlog.md`; not fixed
|
||
here, since wave 1 is scoped to `F1`–`F5` and `T7.x` rebuilds this page anyway.
|