T0.2 - baseline captured; all six rendering defects confirmed present

Runs the app from a clean database, captures the before images, and records
which of F1-F6 actually still reproduce. All six do.

Rather than eyeball screenshots, each defect is measured in a browser by
tests/f_items.py, which reports REPRODUCES / FIXED / INCONCLUSIVE and never a
silent pass. That makes it both the wave 0 record and the wave 1-3 regression
check: an item is done when its probe flips to FIXED.

  F1  hero says "Job A", app bar still says "Select a project", no reload
  F2  "Sign out" spans x382-432 in a 390px viewport - cut in half, 3 rows
  F3  chrome paints over the logo by 106x32px; .header-left collapses to 0
  F4  comments drawer overlaps the header by 380x91px in the standalone creator
  F5  5 of 5 ENABLED wizard inputs compute #f4f4f4 on #e0e0e0
  F6  11 cards in one 5,017px scroll, 0 tabs (review said ~4,700px; it grew)

Three probes needed care to avoid reporting a false pass, and the traps are
worth knowing before anyone verifies a fix:

  F1 disappears if localStorage is primed first, because then both sources of
  truth agree. The probe clears it and drives the real picker.
  F3 needs a long project name that is long IN THE DATABASE - any page reached
  with ?project= re-pulls it and overwrites a locally-faked one. It also cannot
  be measured by comparing .header-left to the chrome: under the long name
  .header-left (flex:1, min-width:0) collapses to clientWidth 0, so that
  comparison reports a tidy zero gap while the chrome paints across the logo.
  It measures against .logo, which is flex-shrink:0. My first two attempts at
  this probe both reported FIXED for those reasons; the screenshot did not.
  F5 must ignore genuinely disabled inputs or a fix looks done while real
  fields stay grey.

14 screenshots, not the 12 the plan asks for, because there are 7 pages
(file-map D1). Capture also measures horizontal overflow, which is how BL-001
was found.

Tooling: cdp.py gains viewport() and screenshot() - it could do neither, and
T0.2 requires 390px and 1440px images. 390px sets the mobile flag rather than
just narrowing the window, since every page declares width=device-width and
Chrome otherwise lays out at 980px and no media query under test fires. Both
new scripts reuse browser_check.py's seed() and start_server() instead of
growing a second fixture. Existing browser_check still passes 71/71.

No application code changed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-14 18:06:36 -05:00
parent c2e35b9261
commit fe8a27e022
22 changed files with 774 additions and 2 deletions

View File

@@ -0,0 +1,86 @@
# Baseline — August 14, 2026
**Task:** `T0.2` · **Branch:** `feat/wp-suite-r2-implementation` · commit before wave 1
The before images every later PR compares against, and the record of which rendering defects
were confirmed present at the start.
## Screenshots
14 images, `<page>-<width>.png`, at 390px and 1440px. The plan says 12 (6 pages × 2); there are
7 pages, so there are 14 — see `file-map.md` D1.
| Page | 390px | 1440px |
|---|---|---|
| login | `login-390.png` | `login-1440.png` |
| launcher | `launcher-390.png` | `launcher-1440.png` |
| SOP wizard | `sop-390.png` | `sop-1440.png` |
| creator | `creator-390.png` | `creator-1440.png` |
| admin | `admin-390.png` | `admin-1440.png` |
| field view | `field-390.png` | `field-1440.png` |
| directory/users | `users-390.png` | `users-1440.png` |
Regenerate, or capture the "after" half of a comparison:
```bash
python tests/baseline_shots.py # -> here
python tests/baseline_shots.py --out /tmp/after --label after
```
390px is captured with Chrome's mobile flag set, not as a narrow desktop window. Every page
declares `width=device-width`, so this is the layout a field tablet actually gets. The script
asserts the width it asked for is the width the page saw.
## F1F6: all six reproduce
Measured in a browser by `tests/f_items.py`, not read from source. Re-run any time:
```bash
python tests/f_items.py # all six
python tests/f_items.py F2 F5 # a subset, after one task
```
Each probe reports `REPRODUCES`, `FIXED` or `INCONCLUSIVE` — never a silent pass. The same
script is the regression check for waves 13: an item is done when its probe flips to `FIXED`.
| Item | Verdict | Measured | Evidence |
|---|---|---|---|
| **F1** | REPRODUCES | Picked "Job A" in the launcher picker: hero became `Job A`, app bar stayed `Select a project`, `wp_active_project=projA`, no reload. | `launcher-1440.png` |
| **F2** | REPRODUCES | Field view at 390px: `Sign out` occupies x 382432 against a 390px viewport — cut in half. Bar is 424px of content in 374px, ~3 rows tall. | `field-390.png`, `launcher-390.png` |
| **F3** | REPRODUCES | SOP header with the real long name: injected chrome paints over the logo by 106×32px at 1024px and 41×32px at 1440px; `.header-left` collapses to `clientWidth 0`. | `f-evidence/F3-sop-header-*-longname.png` |
| **F4** | REPRODUCES | Standalone creator: comments drawer overlaps the header by 380×91px once open. | `creator-1440.png` |
| **F5** | REPRODUCES | 5 of 5 **enabled** wizard inputs compute to `rgb(244,244,244)` fill with `rgb(224,224,224)` border — the `#f4f4f4`/`#e0e0e0` the review named. | `sop-1440.png` |
| **F6** | REPRODUCES | Creator is 11 cards in a single 5,017px scroll, 0 sectioning controls, 3 jump links. Review said ~4,700px; it has grown. | `creator-1440.png` |
### Notes that change how a fix gets verified
- **F1** is only visible if `localStorage` is *not* primed first. Setting both
`wp_active_project` and `wp_active_project_obj` before load makes the two sources agree and
hides the defect. The probe clears storage and drives the real picker.
- **F3** is only visible with a genuinely long project name, and it has to be long **in the
database** — any page reached with `?project=` re-pulls the project from the server and
overwrites a name faked in `localStorage`. The probe seeds
`Micron EUV Cleanroom Enable 2667008` as a real project.
- **F3** cannot be measured by comparing `.header-left` to the chrome. Under the long name
`.header-left` (`flex:1; min-width:0`) collapses to zero width, so that comparison reports a
tidy zero gap while the chrome is painting across the logo. The probe measures against
`.logo`, which is `flex-shrink:0` and therefore the one box in the bar whose position means
something. A fix that leaves `.header-left` collapsed has not fixed F3.
- **F5** must ignore genuinely disabled inputs, or the fix looks done while real fields stay
grey. The probe counts only enabled, visible, non-hidden fields.
## Horizontal overflow, measured at capture time
`documentElement.scrollWidth` against `clientWidth`. Recorded because four pages overflow at
390px and one also overflows at desk width, which no `F` item covers.
| Page | 390px viewport | 1440px viewport |
|---|---|---|
| launcher | 425px content | — |
| SOP wizard | 429px content | — |
| creator | 485px content | **1551px content** |
| field view | 432px content | — |
| login, admin, users | fits | fits |
The 1440px creator overflow is logged as `BL-001`. The 390px ones are `F2` and its
neighbourhood, resolved properly by `B1` in wave 2.

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

@@ -195,11 +195,16 @@ an addressable URL.
```bash
uvicorn server.app:app # against a throwaway SQLite database
python server/smoketest.py # API; signs in
python tests/browser_check.py # pages boot, self-contained
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
@@ -217,6 +222,11 @@ python tests/baseline_shots.py --pages creator --widths 390,768,1024,1440
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 13 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`.
---
## Discrepancies