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>
86
docs/reference/baseline/README.md
Normal 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.
|
||||
|
||||
## F1–F6: 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 1–3: 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 382–432 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.
|
||||
BIN
docs/reference/baseline/admin-1440.png
Normal file
|
After Width: | Height: | Size: 296 KiB |
BIN
docs/reference/baseline/admin-390.png
Normal file
|
After Width: | Height: | Size: 243 KiB |
BIN
docs/reference/baseline/creator-1440.png
Normal file
|
After Width: | Height: | Size: 340 KiB |
BIN
docs/reference/baseline/creator-390.png
Normal file
|
After Width: | Height: | Size: 299 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/reference/baseline/field-1440.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
docs/reference/baseline/field-390.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/reference/baseline/launcher-1440.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
docs/reference/baseline/launcher-390.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
docs/reference/baseline/login-1440.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/reference/baseline/login-390.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/reference/baseline/sop-1440.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
docs/reference/baseline/sop-390.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
docs/reference/baseline/users-1440.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
docs/reference/baseline/users-390.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
@@ -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 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`.
|
||||
|
||||
---
|
||||
|
||||
## Discrepancies
|
||||
|
||||