Files
Project-SDE-WP-Suite/docs/reference/file-map.md
n.siegfried fe8a27e022 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>
2026-08-14 18:06:36 -05:00

17 KiB
Raw Blame History

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 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 418700), 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 16312) — 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-* (2117) and --wp-appbar-* (169176) 114 + 6
console.css unprefixed (1220) 28
work-package-suite-styles.css unprefixed (118) 16
wp-creation-styles.css unprefixed (931) 21
wp-chrome.css --wpc-*, scoped to .wp-chrome, not :root (1836) 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-lg0 4px 16px rgba(0,0,0,0.16) (wizard) vs a different blur in the creator
  • --monoconsole.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: 967984
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 321328, outline:none on 325
work-package-suite-styles.css:336 comment about .field-hint unstyled CONFIRMED comment 336338, rule on 339
console.css:85-87 contrast fix not propagated CONFIRMED comment 8587, 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.cssoutline: 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

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:

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 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

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 19621972 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 19621972 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.

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 F1F5 and T7.x rebuilds this page anyway.