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:
53
docs/waves/backlog.md
Normal file
53
docs/waves/backlog.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Backlog
|
||||
|
||||
Anything noticed during implementation that is real but not in the plan goes here instead of
|
||||
into the current PR. `CLAUDE.md` requires this: every change traces to an item ID, so
|
||||
unplanned work gets logged rather than built.
|
||||
|
||||
Add an entry, do not fix it inline. This file is reviewed at `T9.7` and feeds the next spec
|
||||
revision.
|
||||
|
||||
## Format
|
||||
|
||||
```markdown
|
||||
### BL-001 — Short title
|
||||
|
||||
- **Found during:** T3.2
|
||||
- **Where:** path/to/file.js:120
|
||||
- **What:** one or two sentences on the problem
|
||||
- **Why not now:** out of scope for the current wave / needs a product decision / larger than the task
|
||||
- **Suggested wave or follow-up:** wave 9 / next revision / needs Nick
|
||||
```
|
||||
|
||||
## Known follow-ups already identified in the spec
|
||||
|
||||
These are logged from the source documents, not discovered in code. They are real but
|
||||
deliberately deferred.
|
||||
|
||||
### BL-000a — Validated P6 activity lookup
|
||||
|
||||
- **From:** `CR-001`
|
||||
- **What:** `CR-001` accepts free text for the P6 Activity ID. A validated lookup against an imported P6 activity list was identified as the eventual want.
|
||||
- **Why not now:** the Micron schedule is actively being reworked, so importing an activity list now would import churn.
|
||||
- **Suggested:** next revision, once the schedule stabilizes.
|
||||
|
||||
### BL-000b — Field-level toggles in General Information
|
||||
|
||||
- **From:** `CR-006`
|
||||
- **What:** `CR-006` toggles whole sections. General Information may need per-field toggles, since projects differ in which identifiers they use.
|
||||
- **Why not now:** section-level toggles cover every removal request currently on the list.
|
||||
- **Suggested:** next revision, if a second project needs a different field set.
|
||||
|
||||
### BL-000c — Estimated versus actual hours productivity factor
|
||||
|
||||
- **From:** `CR-017`
|
||||
- **What:** Actual Hours is retained and rolls up. Comparing it against estimated hours would produce a productivity factor, which was the stated reason for wanting the field.
|
||||
- **Why not now:** estimated hours capture is not in scope this round.
|
||||
- **Suggested:** next revision.
|
||||
|
||||
### BL-000d — Attachment merge versus list on export
|
||||
|
||||
- **From:** `CR-008` / `T9.1`
|
||||
- **What:** whether the PDF export merges attachments into one package or lists them separately.
|
||||
- **Why not now:** product decision, raised in the `T9.1` PR.
|
||||
- **Suggested:** needs Nick.
|
||||
91
docs/waves/wave-0.md
Normal file
91
docs/waves/wave-0.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Wave 0 — Orientation
|
||||
|
||||
**Do this before wave 1.** Nothing else in the plan should be started until `T0.1` is merged.
|
||||
|
||||
The item IDs and file references throughout this plan come from a UX review conducted on
|
||||
branch `users/directory-super-user`, not from a fresh read of the repo you are in. The line
|
||||
numbers were accurate at the time of the review. Confirm them before relying on them.
|
||||
|
||||
---
|
||||
|
||||
### T0.1 — Build the file map
|
||||
|
||||
- **Items:** none (prerequisite)
|
||||
- **Depends on:** nothing
|
||||
- **Blocks:** every other task
|
||||
- **Surface:** documentation only
|
||||
- **Files:** creates `docs/reference/file-map.md`
|
||||
|
||||
**Do:**
|
||||
|
||||
Inventory the frontend and record it. The review described `html/` as 6 pages, 4
|
||||
stylesheets, roughly 11,900 lines. Confirm that and write down what is actually there.
|
||||
|
||||
For each of the 6 pages record: file path, what it is called in this plan (launcher, SOP
|
||||
wizard, creator, admin, field view, directory/users, login), which stylesheets it loads,
|
||||
which scripts it loads, and whether it renders inside an iframe or hosts one.
|
||||
|
||||
For each stylesheet record: path, and which pages consume it.
|
||||
|
||||
Then verify these specific references from the review and record the current line number
|
||||
next to each, or mark it `NOT FOUND`:
|
||||
|
||||
| Reference | Claim |
|
||||
|---|---|
|
||||
| `wp-creation-app.js:1144` | `alert()` reading "Subject and WP Type are required" |
|
||||
| `wp-creation-app.js:1962-1972` | logged-override path for predecessor constraints |
|
||||
| `work-package-suite-app.js:326` | the only `beforeunload` listener, analytics dwell tracking |
|
||||
| `work-package-suite-styles.css:322-328` | `outline: none` plus a pale 3px focus glow |
|
||||
| `work-package-suite-styles.css:336` | comment about `.field-hint` rendering unstyled |
|
||||
| `console.css:85-87` | the contrast fix that was not propagated |
|
||||
| `admin.js:484-517` | language and time localization |
|
||||
| `server/seed_demo.py` | seeding script that does not authenticate |
|
||||
|
||||
Also record counts, so later waves can prove they went down:
|
||||
|
||||
- occurrences of `alert(`, `confirm(`, `prompt(` — review found 79 app-wide, 43 in the creator
|
||||
- `<div` and `<span` elements carrying `onclick` — review found 12 and 2
|
||||
- declarations of `#0f62fe` — review found 4
|
||||
- `.help-tip` elements — review found 15
|
||||
- `aria-live` regions — review found 0
|
||||
- `pushState` calls — review found 0
|
||||
|
||||
**Do not:** change any application code in this task. It is a read and a document.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] `docs/reference/file-map.md` exists and lists all pages, stylesheets and scripts
|
||||
- [ ] every reference in the table above is confirmed with a current line number or marked `NOT FOUND`
|
||||
- [ ] the seven counts are recorded with the command used to produce each
|
||||
- [ ] any file path used in a later wave file that does not exist is listed under a `Discrepancies` heading
|
||||
|
||||
---
|
||||
|
||||
### T0.2 — Confirm the app runs and the baseline is captured
|
||||
|
||||
- **Items:** none (prerequisite)
|
||||
- **Depends on:** T0.1
|
||||
- **Blocks:** every task with a visual done-when
|
||||
- **Surface:** local environment
|
||||
- **Files:** creates `docs/reference/baseline/`
|
||||
|
||||
**Do:**
|
||||
|
||||
Run the app locally (`uvicorn server.app:app` against a throwaway SQLite database) and drive
|
||||
the first-run flow: sign in, create a project, SOP wizard, creator, directory, field view.
|
||||
|
||||
Capture baseline screenshots at **390px** and **1440px** for each of the 6 pages into
|
||||
`docs/reference/baseline/`. Name them `<page>-<width>.png`. These are the before images
|
||||
every later PR compares against.
|
||||
|
||||
While doing this, confirm each of `F1` through `F6` still reproduces and note it. If one does
|
||||
not reproduce, say so in the PR rather than deleting the task from wave 1.
|
||||
|
||||
**Do not:** fix anything you see. Wave 1 does that.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the app runs locally from a clean database
|
||||
- [ ] 12 baseline screenshots exist (6 pages x 2 widths)
|
||||
- [ ] each of `F1`–`F6` is marked reproduces / does not reproduce, with a screenshot reference
|
||||
- [ ] the exact run command and any setup steps are recorded in `docs/reference/file-map.md`
|
||||
185
docs/waves/wave-1.md
Normal file
185
docs/waves/wave-1.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# Wave 1 — Rendering defects and tooling
|
||||
|
||||
**Items:** `F1`, `F2` (interim), `F3`, `F4`, `F5` (interim), `S13`
|
||||
**Depends on:** wave 0
|
||||
**Why first:** none of these need a design decision, and `F1` and `F2` block all chrome work
|
||||
in wave 2.
|
||||
|
||||
Two tasks here are deliberately partial. `F2` gets a containment fix only because `B1` in
|
||||
wave 2 resolves it properly, and `F5` gets a one-line fix because `C3` in wave 3 removes the
|
||||
underlying cause. Do not over-build either.
|
||||
|
||||
---
|
||||
|
||||
### T1.1 — F1: Header project switcher is stale on every page
|
||||
|
||||
- **Items:** `F1`
|
||||
- **Depends on:** T0.1
|
||||
- **Blocks:** T2.1, T2.2
|
||||
- **Surface:** `html/`
|
||||
- **Files:** per file-map — the app bar/header component and whatever holds active-project state
|
||||
|
||||
**Problem:** The hero, the project picker and the create-user card all show the active
|
||||
project. The app bar still reads "Select a project". Two sources of truth for the same value,
|
||||
and the global one loses.
|
||||
|
||||
**Do:**
|
||||
|
||||
Find every place the active project is read or stored. There is more than one. Collapse them
|
||||
to a single source, and have the app bar subscribe to it rather than holding its own copy.
|
||||
Set the value on project selection and on page load, including a hard refresh and a
|
||||
deep-linked page.
|
||||
|
||||
**Do not:** introduce a state library. This is a single value with a small number of readers.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the app bar shows the active project on all 6 pages
|
||||
- [ ] value survives a hard refresh on every page
|
||||
- [ ] switching projects updates the app bar and the hero in the same interaction, with no reload
|
||||
- [ ] with no project selected, the app bar reads "Select a project" and the picker is reachable
|
||||
- [ ] exactly one code path writes active-project state; note its location in the PR
|
||||
|
||||
---
|
||||
|
||||
### T1.2 — F2 (interim): stop the app bar clipping at 390px
|
||||
|
||||
- **Items:** `F2` partial
|
||||
- **Depends on:** T1.1
|
||||
- **Blocks:** nothing (superseded by T2.2)
|
||||
- **Surface:** `html/`
|
||||
- **Files:** app bar styles
|
||||
|
||||
**Problem:** At 390px the nav wraps to three rows and clips. "Sign out" is cut in half and
|
||||
search is truncated. Field View runs at this width on tablets with gloved hands.
|
||||
|
||||
**Do:** The smallest change that guarantees no control is unreachable or visually cut. Allow
|
||||
the bar to scroll or stack rather than clip. This is triage, not a redesign — `T2.2` deletes
|
||||
this markup.
|
||||
|
||||
**Do not:** build a responsive menu, a hamburger, or an avatar dropdown. Wave 2 ships the
|
||||
existing drawer instead, and anything built here would be thrown away.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] at 390px no nav control is clipped or unreachable on any of the 6 pages
|
||||
- [ ] "Sign out" is fully visible and tappable at 390px
|
||||
- [ ] search is either fully usable or deliberately hidden at this width, not truncated
|
||||
- [ ] no layout change at 1440px — screenshot diff against baseline is empty
|
||||
- [ ] the PR states this is interim and names `T2.2` as the real fix
|
||||
|
||||
---
|
||||
|
||||
### T1.3 — F3: Logo and project name collide in the SOP header
|
||||
|
||||
- **Items:** `F3`
|
||||
- **Depends on:** T1.1
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** SOP wizard page and its header styles, `.header-left`
|
||||
|
||||
**Problem:** `.header-left` and the injected chrome compete for the same run of the bar and
|
||||
overlap.
|
||||
|
||||
**Do:** Give the two elements a defined relationship rather than letting both claim the same
|
||||
space. Verify with a long project name — "Micron EUV Cleanroom Enable 2667008" is the real
|
||||
one and it is what breaks things.
|
||||
|
||||
**Do not:** solve it by truncating the project name. `B2` in wave 2 owns truncation and
|
||||
needs a breakpoint plan, not a silent ellipsis.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] no overlap at 390px, 768px, 1024px and 1440px
|
||||
- [ ] tested with the longest real project name
|
||||
- [ ] the logo remains fully visible at all four widths
|
||||
|
||||
---
|
||||
|
||||
### T1.4 — F4: Comments drawer renders off-screen over the header
|
||||
|
||||
- **Items:** `F4`
|
||||
- **Depends on:** T0.1
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** standalone creator page and comments drawer styles
|
||||
|
||||
**Problem:** In the standalone creator, the comments drawer renders off-screen and over the
|
||||
header.
|
||||
|
||||
**Do:** Fix the positioning context and stacking. Check whether the drawer is positioned
|
||||
relative to the iframe or the parent — if the iframe boundary is implicated, note it in the
|
||||
PR because `T7.1` removes that boundary.
|
||||
|
||||
**Do not:** raise `z-index` until something happens to work. Identify the containing block
|
||||
first and say what it was in the PR.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the drawer opens fully on screen in the standalone creator at 390px and 1440px
|
||||
- [ ] the drawer does not cover the header
|
||||
- [ ] the drawer closes and reopens correctly, and scroll position is not lost
|
||||
- [ ] behavior is identical in the embedded and standalone creator
|
||||
|
||||
---
|
||||
|
||||
### T1.5 — F5 (interim): SOP wizard fields read as read-only
|
||||
|
||||
- **Items:** `F5` partial, `A3` partial
|
||||
- **Depends on:** T0.1
|
||||
- **Blocks:** nothing (completed by T3.4)
|
||||
- **Surface:** `html/`
|
||||
- **Files:** SOP wizard stylesheet
|
||||
|
||||
**Problem:** Wizard inputs render with a `#f4f4f4` fill and `#e0e0e0` border, which reads as
|
||||
disabled. Users do not type in them. The cause is that the wizard redeclares its own tokens
|
||||
and never sees `--cds-field: #ffffff`.
|
||||
|
||||
**Do:** Make the fields look editable. The minimal correct fix is to have the wizard consume
|
||||
the existing field token instead of its local override.
|
||||
|
||||
**Do not:** start token consolidation here. That is `T3.1`–`T3.3` and it is a separate,
|
||||
mechanical, whole-app change. Fix the field appearance only.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] wizard inputs render with a white fill and a border visually consistent with inputs elsewhere
|
||||
- [ ] genuinely disabled inputs still look disabled and are distinguishable from enabled ones
|
||||
- [ ] no other component changes appearance — screenshot diff limited to the wizard
|
||||
- [ ] the PR notes that `T3.4` removes the underlying duplicate token
|
||||
|
||||
---
|
||||
|
||||
### T1.6 — S13: `server/seed_demo.py` cannot seed a running instance
|
||||
|
||||
- **Items:** `S13`
|
||||
- **Depends on:** T0.1
|
||||
- **Blocks:** nothing, but makes every later task's setup faster
|
||||
- **Surface:** `server/`
|
||||
- **Files:** `server/seed_demo.py`, and the smoke test for reference
|
||||
|
||||
**Problem:** Every `/api/` route requires a session and the script sends none, so it cannot
|
||||
seed a running instance. It predates the commit that taught the smoke test to sign in.
|
||||
|
||||
**Do:** Give the script the same authentication the smoke test uses. Reuse that code path
|
||||
rather than writing a second one.
|
||||
|
||||
**Do not:** add a bypass, a debug flag, or an unauthenticated seeding route to the server.
|
||||
The script authenticates like a client; the server does not get weaker.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] `seed_demo.py` runs against a freshly started instance and exits 0
|
||||
- [ ] the seeded data is visible in the UI after running it
|
||||
- [ ] running it twice does not error or duplicate data, or it fails with a clear message
|
||||
- [ ] no new unauthenticated route exists — confirm by diff
|
||||
|
||||
---
|
||||
|
||||
## Wave 1 exit criteria
|
||||
|
||||
- [ ] `F1`, `F3`, `F4` fully resolved and confirmed against the wave 0 baseline screenshots
|
||||
- [ ] `F2` and `F5` contained, with their real fixes referenced (`T2.2`, `T3.4`)
|
||||
- [ ] `S13` fixed and seeding works
|
||||
- [ ] no new `<div onclick>`, no new raw hex values, no new `alert()` calls introduced
|
||||
- [ ] `F6` untouched — it is a structural problem fixed by section tabs in `T7.2`
|
||||
108
docs/waves/wave-2.md
Normal file
108
docs/waves/wave-2.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Wave 2 — Drawer everywhere, flat strip deleted
|
||||
|
||||
**Items:** `B1`, `B2`, `S4`, `F2` (full)
|
||||
**Depends on:** wave 1 merged
|
||||
**Why here:** this settles global navigation before anything else is redrawn, and it resolves
|
||||
the 390px collapse properly.
|
||||
|
||||
**The correction that defines this wave.** The proposed UX change list called for building a
|
||||
new avatar menu to collapse the eight-item nav. Do not build it. The app already has a
|
||||
drawer that holds the entire nav, and the review's judgment was that it is the best chrome in
|
||||
the app. It ships on 3 of 6 pages while a flat strip duplicates it. Shipping the existing
|
||||
drawer everywhere and deleting the strip is less work than building the menu, and it fixes
|
||||
`F2` as a side effect.
|
||||
|
||||
---
|
||||
|
||||
### T2.1 — Extract the drawer into a shared component
|
||||
|
||||
- **Items:** `B1` part 1
|
||||
- **Depends on:** T1.1
|
||||
- **Blocks:** T2.2
|
||||
- **Surface:** `html/`
|
||||
- **Files:** the drawer markup/styles/script currently used by admin, field view and directory
|
||||
|
||||
**Do:** Lift the drawer into one shared implementation the pages include, rather than three
|
||||
near-copies. Keep its current behavior and appearance — this is extraction, not redesign.
|
||||
Where the three copies differ, take the admin version unless the PR explains otherwise.
|
||||
|
||||
**Do not:** change the drawer's visual design, its animation, or its contents in this task.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] one drawer implementation exists; no page defines its own
|
||||
- [ ] admin, field view and directory look and behave identically to the wave 0 baseline
|
||||
- [ ] screenshot diff against baseline for those three pages is empty at both widths
|
||||
- [ ] the drawer reads active-project state from the single source established in `T1.1`
|
||||
|
||||
---
|
||||
|
||||
### T2.2 — Mount the drawer on all six pages and delete the flat strip
|
||||
|
||||
- **Items:** `B1` part 2, `S4`, `F2` full
|
||||
- **Depends on:** T2.1
|
||||
- **Blocks:** T5.1, T7.2
|
||||
- **Surface:** `html/`
|
||||
- **Files:** all 6 pages, the flat nav strip markup and styles
|
||||
|
||||
**Problem:** The SOP wizard has its own header and no drawer. The creator has neither. These
|
||||
are the two pages people actually live in, so global nav is missing exactly where it is most
|
||||
needed (`S4`).
|
||||
|
||||
**Do:** Mount the shared drawer on all six pages, including the SOP wizard and the creator.
|
||||
Delete the flat nav strip and its styles entirely. Reconcile the SOP wizard's bespoke header
|
||||
against the shared chrome — the wizard keeps its step context, it does not keep its own
|
||||
global nav.
|
||||
|
||||
Unify the brand treatment while you are here: the creator uses a mono wordmark and everything
|
||||
else uses a logo chip. Pick the logo chip.
|
||||
|
||||
**Do not:** leave the flat strip in place behind a media query "just in case". Delete it. Its
|
||||
existence is what produced the duplication.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] all 6 pages render the same drawer with the same contents
|
||||
- [ ] the flat nav strip is deleted; grep confirms no remaining references
|
||||
- [ ] at 390px on every page, no nav control is clipped and every destination is reachable
|
||||
- [ ] Field View at 390px passes with tap targets of at least 44px
|
||||
- [ ] the creator and the SOP wizard show the same brand treatment as the other four pages
|
||||
- [ ] the interim fix from `T1.2` is removed rather than layered on top
|
||||
|
||||
---
|
||||
|
||||
### T2.3 — B2: Project switcher truncation and breakpoints
|
||||
|
||||
- **Items:** `B2`
|
||||
- **Depends on:** T2.2
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** app bar / drawer header styles
|
||||
|
||||
**Problem:** "Micron EUV Cleanroom Enable 2667008" does not fit 280px, and existing rules
|
||||
narrow the switcher to 150px below 900px. This needs a breakpoint plan, not a width bump.
|
||||
|
||||
**Do:** Decide what the switcher shows at each breakpoint and implement that. A workable
|
||||
plan: full name where it fits, project code alone at narrow widths, full name always
|
||||
available in the drawer or on hover/focus. Whatever you choose, write it into
|
||||
`docs/reference/file-map.md` so it is not re-litigated.
|
||||
|
||||
**Do not:** apply a plain ellipsis at every width. A project name truncated to "Micron EUV
|
||||
Clean..." on the page where someone confirms which project they are in is the failure this
|
||||
item exists to prevent.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the active project is identifiable at 390px, 768px, 1024px and 1440px
|
||||
- [ ] the full name is reachable at every width by some means, and that means is documented
|
||||
- [ ] correctness from `T1.1` is preserved — the switcher never reads "Select a project" while a project is active
|
||||
- [ ] tested with the longest real project name
|
||||
|
||||
---
|
||||
|
||||
## Wave 2 exit criteria
|
||||
|
||||
- [ ] one drawer, six pages, no flat strip
|
||||
- [ ] `F2` resolved for real; the `T1.2` interim is gone
|
||||
- [ ] `S4` closed: global nav exists on the SOP wizard and the creator
|
||||
- [ ] no visual regression on admin, field view or directory versus baseline
|
||||
147
docs/waves/wave-3.md
Normal file
147
docs/waves/wave-3.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Wave 3 — Token consolidation and one button system
|
||||
|
||||
**Items:** `C3`, `S5`, `A3`/`F5` (full), `A5`
|
||||
**Depends on:** wave 2 merged
|
||||
**Why here:** every remaining visual task lands once instead of four times. Skipping this
|
||||
means "one button system" gets implemented in four token systems and drifts, which is exactly
|
||||
how `.field-hint` broke.
|
||||
|
||||
This wave should produce **no intentional visual change** except the two known defects it
|
||||
fixes. Treat any other diff in the screenshot comparison as a bug in your refactor.
|
||||
|
||||
---
|
||||
|
||||
### T3.1 — Inventory the token systems
|
||||
|
||||
- **Items:** `C3` part 1, `S5` part 1
|
||||
- **Depends on:** T2.3
|
||||
- **Blocks:** T3.2
|
||||
- **Surface:** documentation
|
||||
- **Files:** creates `docs/reference/tokens.md`
|
||||
|
||||
**Problem:** Four parallel token systems. `#0f62fe` alone is declared four times, as
|
||||
`--cds-interactive-01`, `--primary`, and `--accent` twice.
|
||||
|
||||
**Do:** Produce a mapping table: every custom property and every raw hex, hsl or rgb value in
|
||||
the four stylesheets, where it is declared, what consumes it, and which canonical token it
|
||||
maps to. Include spacing and type scales, not just color. Mark genuine duplicates,
|
||||
near-duplicates (values one or two hex digits apart, which are usually accidents), and
|
||||
one-offs.
|
||||
|
||||
**Do not:** change any stylesheet in this task.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] `docs/reference/tokens.md` lists every declaration with file and line
|
||||
- [ ] every value is mapped to a proposed canonical token or flagged as a one-off with a reason
|
||||
- [ ] near-duplicates are called out explicitly, since those are where unintended visual change will come from
|
||||
- [ ] the `#0f62fe` count matches or corrects the wave 0 baseline count
|
||||
|
||||
---
|
||||
|
||||
### T3.2 — Establish one source of truth
|
||||
|
||||
- **Items:** `C3` part 2, `S5` part 2
|
||||
- **Depends on:** T3.1
|
||||
- **Blocks:** T3.3, T3.4, T4.6, T4.7
|
||||
- **Surface:** `html/`
|
||||
- **Files:** all 4 stylesheets
|
||||
|
||||
**Do:** Create the canonical token set in one place. Convert the other stylesheets to alias
|
||||
it. Page stylesheets declare no new values. Keep existing custom property names as aliases
|
||||
where deleting them would touch large amounts of markup — an alias pointing at the canonical
|
||||
token is fine; a second declaration of the same literal is not.
|
||||
|
||||
**Do not:** change any rendered value in this task, including the two known defects. Fix
|
||||
those in `T3.3` and `T3.4` so their diffs are reviewable separately from a 4-stylesheet
|
||||
refactor.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] exactly one declaration exists per canonical value; grep for `#0f62fe` returns 1
|
||||
- [ ] no page stylesheet declares a raw color, spacing or type value
|
||||
- [ ] screenshot diff against the wave 2 state is empty on all 6 pages at both widths
|
||||
- [ ] `docs/reference/tokens.md` is updated to reflect what was actually built
|
||||
|
||||
---
|
||||
|
||||
### T3.3 — Fix `.field-hint` and the drift it documents
|
||||
|
||||
- **Items:** `S5` part 3
|
||||
- **Depends on:** T3.2
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** `work-package-suite-styles.css` around line 336
|
||||
|
||||
**Problem:** There is a comment at `work-package-suite-styles.css:336` describing
|
||||
`.field-hint` rendering unstyled. It is the documented consequence of the duplicate token
|
||||
systems.
|
||||
|
||||
**Do:** Fix `.field-hint` properly now that the tokens are consolidated, and delete the
|
||||
comment. Then check for the same class of failure elsewhere: any selector that silently
|
||||
renders unstyled because it referenced a token the page never saw.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] `.field-hint` renders correctly everywhere it appears
|
||||
- [ ] the stale comment is deleted
|
||||
- [ ] any other silently-unstyled selectors found are listed in the PR and either fixed or logged
|
||||
|
||||
---
|
||||
|
||||
### T3.4 — A3/F5 full fix: fields look editable
|
||||
|
||||
- **Items:** `A3`, `F5` full
|
||||
- **Depends on:** T3.2
|
||||
- **Blocks:** T5.1
|
||||
- **Surface:** `html/`
|
||||
- **Files:** SOP wizard stylesheet
|
||||
|
||||
**Do:** Remove the wizard's local field token override entirely, so it consumes the canonical
|
||||
field token. Remove the interim fix from `T1.5` rather than leaving both.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the wizard declares no field-specific color of its own
|
||||
- [ ] enabled inputs are visually identical to enabled inputs on every other page
|
||||
- [ ] disabled inputs remain clearly distinguishable from enabled ones
|
||||
- [ ] the `T1.5` interim change is gone; grep confirms it
|
||||
|
||||
---
|
||||
|
||||
### T3.5 — A5: one button system
|
||||
|
||||
- **Items:** `A5`
|
||||
- **Depends on:** T3.2
|
||||
- **Blocks:** T5.1, T7.2
|
||||
- **Surface:** `html/`
|
||||
- **Files:** button styles, and any page overriding them
|
||||
|
||||
**Problem:** Green `Save & View` and green `SOP Complete` against blue everywhere else. Two
|
||||
button languages competing.
|
||||
|
||||
**Do:** One button system: primary, secondary, tertiary, destructive. Map every existing
|
||||
button to one of those roles. Green becomes a status color, not an action color.
|
||||
|
||||
Apply sentence case **to buttons and field labels only**.
|
||||
|
||||
**Do not:** touch the uppercase card-header idiom in `console.css`. It is deliberate, it
|
||||
works, and the review specifically scoped the sentence-case rule to exclude it. Changing it
|
||||
is out of scope.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] every button in the app maps to one of four documented roles
|
||||
- [ ] no green action buttons remain; `Save & View` and `SOP Complete` use the primary role
|
||||
- [ ] buttons and field labels are sentence case
|
||||
- [ ] uppercase card headers in `console.css` are unchanged — confirm by diff
|
||||
- [ ] button roles are documented in `docs/reference/tokens.md`
|
||||
|
||||
---
|
||||
|
||||
## Wave 3 exit criteria
|
||||
|
||||
- [ ] one token source of truth; page sheets alias only
|
||||
- [ ] `#0f62fe` declared once
|
||||
- [ ] no unintended visual change on any page versus wave 2
|
||||
- [ ] fields look editable, buttons speak one language
|
||||
215
docs/waves/wave-4.md
Normal file
215
docs/waves/wave-4.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# Wave 4 — Platform prerequisites
|
||||
|
||||
**Items:** `B4`, `S3`, `S2`, `B5`, `S10`, `S11`, `S12`, part of `C4`
|
||||
**Depends on:** wave 3 merged
|
||||
**Why here:** `X1` and `X5` are blocking dependencies that resolve in this wave. Two of the
|
||||
most valuable field requests — the QA gate (`CR-014`) and the kitting notification
|
||||
(`CR-011`) — promise emails containing a direct link to a work package. Nothing in this app
|
||||
has a URL. Until `T4.2` lands, those emails cannot be built.
|
||||
|
||||
`T4.5` through `T4.7` are small and could be done any time. They are here because every
|
||||
component built in waves 5 through 8 inherits them, and retrofitting is what `C1` warns
|
||||
about.
|
||||
|
||||
---
|
||||
|
||||
### T4.1 — B4: Server aggregates replace localStorage-derived counts
|
||||
|
||||
- **Items:** `B4`
|
||||
- **Depends on:** T3.2
|
||||
- **Blocks:** T5.3, T6.3, T6.5
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** server API, launcher, creator dashboard
|
||||
|
||||
**Problem:** Launcher SOP status reads `localStorage`, and the creator's dashboard carries a
|
||||
comment admitting it reads local data and wires to SQL in Phase 2. Per-browser numbers that
|
||||
look authoritative are worse than no numbers: two people looking at the same project see
|
||||
different counts and neither is told.
|
||||
|
||||
**Do:** Add server endpoints returning the aggregate counts the launcher and dashboard need,
|
||||
computed from the database. Point both surfaces at them. Delete the `localStorage` reads for
|
||||
anything presented as a count or a status rollup.
|
||||
|
||||
Design the aggregate shape to support grouping by building, floor and sector, because
|
||||
`CR-018` needs exactly that in wave 6. You do not have to expose the grouping yet, but do not
|
||||
build a shape that cannot.
|
||||
|
||||
**Do not:** leave a `localStorage` fallback for counts. A silently-stale fallback is the
|
||||
failure mode being fixed. If the endpoint fails, show an error state.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] launcher and dashboard counts come from the server
|
||||
- [ ] two different browsers signed in as different users show identical counts for the same project
|
||||
- [ ] no `localStorage` read remains behind any displayed count; grep confirms
|
||||
- [ ] endpoint failure shows an explicit error state, not a zero and not a stale number
|
||||
- [ ] the aggregate response can be grouped by location without a schema change
|
||||
|
||||
---
|
||||
|
||||
### T4.2 — S3: URL state
|
||||
|
||||
- **Items:** `S3`, part of `C4`
|
||||
- **Depends on:** T2.2
|
||||
- **Blocks:** T7.6, T8.3 (blocking dependency `X1`)
|
||||
- **Surface:** `html/`
|
||||
- **Files:** all 6 pages, routing/state handling
|
||||
|
||||
**Problem:** No `pushState` anywhere. Tab switches, dashboard views and package selections
|
||||
change no URL. You cannot send someone a link to WP07, and a refresh loses your place.
|
||||
|
||||
**Do:** Give addressable state a URL. At minimum: the selected project, the selected work
|
||||
package, the active tab or section, and the active dashboard view or filter. Restore state
|
||||
from the URL on load. Make browser back and forward behave.
|
||||
|
||||
Deep links must work for a signed-out user: land on login, then continue to the requested
|
||||
target after signing in. An email link that dumps the recipient on a dashboard is the
|
||||
failure this task exists to prevent.
|
||||
|
||||
**Do not:** use hash-only routing if the server can serve paths. Do not put anything secret
|
||||
in the URL.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] a URL identifying a specific work package opens that work package directly
|
||||
- [ ] the same URL works for a signed-out user via login, landing on the requested target
|
||||
- [ ] refresh preserves project, package, tab and view
|
||||
- [ ] browser back and forward move through states without a full reload or a broken view
|
||||
- [ ] copying the URL and opening it in a second browser reaches the same view
|
||||
- [ ] `pushState` count is greater than 0; record the new count
|
||||
|
||||
---
|
||||
|
||||
### T4.3 — S2: Autosave and unsaved-work guard
|
||||
|
||||
- **Items:** `S2`, part of `C4`
|
||||
- **Depends on:** T4.2
|
||||
- **Blocks:** T7.7 (blocking dependency `X8`)
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** creator, SOP wizard, `work-package-suite-app.js:326`
|
||||
|
||||
**Problem:** No autosave and no unsaved-work guard. The only `beforeunload` listener is
|
||||
analytics dwell tracking. On a form roughly 4,700px tall, a mis-click loses everything.
|
||||
|
||||
**Do:** Autosave drafts on a debounce and on step or section change. Add a real
|
||||
`beforeunload` guard for genuinely unsaved changes, alongside the analytics listener rather
|
||||
than replacing it. Add draft recovery: if a session ends with unsaved work, offer it back on
|
||||
return.
|
||||
|
||||
**Do not:** fire the guard when nothing has changed. A dialog that appears on every exit
|
||||
gets clicked through and is worse than none.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] typing then navigating away and returning restores the work
|
||||
- [ ] typing then closing the tab prompts; not typing then closing does not
|
||||
- [ ] autosave survives a browser crash simulation (kill the tab, reopen)
|
||||
- [ ] the analytics dwell listener still functions
|
||||
- [ ] autosave failure is surfaced to the user, not swallowed
|
||||
|
||||
---
|
||||
|
||||
### T4.4 — B5: Honest save status
|
||||
|
||||
- **Items:** `B5`
|
||||
- **Depends on:** T4.3
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** creator, SOP wizard, existing toast system
|
||||
|
||||
**Problem:** An "All changes saved" toast already appears, but it belongs to the sync outbox,
|
||||
not the draft. The app already implies a promise it does not keep.
|
||||
|
||||
**Do:** A persistent save-state indicator tied to the actual draft: saving, saved with a
|
||||
timestamp, or failed with a retry. Distinguish it clearly from the sync outbox message, or
|
||||
rename the outbox message so the two are not confused.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the indicator reflects real draft state, verified by watching it during a save failure
|
||||
- [ ] a failed save is visually distinct from a successful one and offers a retry
|
||||
- [ ] the sync outbox message no longer reads as a draft-save confirmation
|
||||
- [ ] the indicator is announced via `aria-live` (see `T4.5`)
|
||||
|
||||
---
|
||||
|
||||
### T4.5 — S10: `aria-live` regions
|
||||
|
||||
- **Items:** `S10`
|
||||
- **Depends on:** T3.2
|
||||
- **Blocks:** nothing, but every later task depends on the pattern existing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** both toast systems, admin banners, `login.html` as the reference
|
||||
|
||||
**Problem:** Zero `aria-live` regions app-wide. Both toast systems and every admin banner
|
||||
announce nothing. `login.html` already does this correctly with `role="alert"` and
|
||||
`role="status"`; the pattern never spread.
|
||||
|
||||
**Do:** Copy the `login.html` pattern into both toast systems and the admin banners. Errors
|
||||
use `role="alert"` (assertive), confirmations use `role="status"` (polite).
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] every toast and banner announces
|
||||
- [ ] errors interrupt, confirmations do not
|
||||
- [ ] verified with a screen reader, or with an automated check plus a manual read of the markup
|
||||
- [ ] `aria-live` region count is greater than 0; record it
|
||||
|
||||
---
|
||||
|
||||
### T4.6 — S11: Helper text contrast
|
||||
|
||||
- **Items:** `S11`
|
||||
- **Depends on:** T3.2
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** canonical tokens, `console.css:85-87` as the reference
|
||||
|
||||
**Problem:** `--text-dim: #8d8d8d` at 12px is about 2.9:1. `console.css:85-87` already
|
||||
diagnosed and fixed this; the other two sheets did not follow. Now that tokens are
|
||||
consolidated, fix it once.
|
||||
|
||||
**Do:** Raise the dim-text token to meet 4.5:1 against its actual backgrounds. Check it on
|
||||
every surface it lands on, including shaded cards and table rows, not just white.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] all helper and hint text measures at least 4.5:1 against its real background
|
||||
- [ ] the fix lives in the canonical token, not per-sheet
|
||||
- [ ] `console.css` no longer needs its local override; remove it
|
||||
- [ ] measured values are recorded in the PR
|
||||
|
||||
---
|
||||
|
||||
### T4.7 — S12: Restore the focus ring
|
||||
|
||||
- **Items:** `S12`
|
||||
- **Depends on:** T3.2
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** `work-package-suite-styles.css:322-328`
|
||||
|
||||
**Problem:** `outline: none` plus a pale 3px glow. Keyboard users cannot see where they are.
|
||||
|
||||
**Do:** A visible focus indicator meeting at least 3:1 against adjacent colors, applied
|
||||
consistently to every interactive element. Use `:focus-visible` so mouse users do not see
|
||||
rings on click.
|
||||
|
||||
**Do not:** ship `outline: none` without a replacement anywhere in the app.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] tabbing through every page shows a clearly visible indicator at each stop
|
||||
- [ ] the indicator meets 3:1 against adjacent colors on every background it appears on
|
||||
- [ ] no `outline: none` remains without an accompanying visible replacement; grep confirms
|
||||
- [ ] mouse clicks do not leave a persistent ring
|
||||
|
||||
---
|
||||
|
||||
## Wave 4 exit criteria
|
||||
|
||||
- [ ] counts come from the server and match across browsers
|
||||
- [ ] work packages are addressable by URL, including from a signed-out state
|
||||
- [ ] drafts autosave and unsaved work is guarded
|
||||
- [ ] toasts announce, helper text is legible, focus is visible
|
||||
- [ ] `X1` and `X5` are cleared, unblocking `CR-011`, `CR-014`, `CR-004` and `CR-018`
|
||||
239
docs/waves/wave-5.md
Normal file
239
docs/waves/wave-5.md
Normal file
@@ -0,0 +1,239 @@
|
||||
# Wave 5 — Launcher and SOP wizard
|
||||
|
||||
**Items:** `A4`, `B3`, `S9`, `S1` (wizard), `CR-005`, `CR-006`, `CR-002`, `CR-016`
|
||||
**Depends on:** wave 4 merged
|
||||
**Why here:** `CR-006` is the enabler for every removal request in the plan. Building it
|
||||
before `CR-002` and `CR-016` means nothing gets deleted that another project may need.
|
||||
|
||||
First field-visible wave. Everything before this was prerequisites.
|
||||
|
||||
---
|
||||
|
||||
### T5.1 — A4 + S9: Vertical stepper with real buttons
|
||||
|
||||
- **Items:** `A4`, `S9`
|
||||
- **Depends on:** T3.4, T3.5, T2.2
|
||||
- **Blocks:** T5.4, T5.5
|
||||
- **Surface:** `html/`
|
||||
- **Files:** SOP wizard step rail
|
||||
|
||||
**Problem:** The step rail is 10 `<div>` elements with `onclick`, so it is unreachable by
|
||||
keyboard. There is also an orphaned "1 / 10" counter doing the job a stepper should do.
|
||||
|
||||
**Do:** Rebuild the rail as a vertical stepper showing all 10 steps, which is complete, which
|
||||
is current, and which are not yet reachable. Every step is a real `<button>`. Retire the
|
||||
"1 / 10" counter.
|
||||
|
||||
Per `C1`, this is the moment to make it accessible — it is being rebuilt anyway.
|
||||
|
||||
**Do not:** ship a single `<div onclick>` in the replacement. The app-wide count from wave 0
|
||||
must go **down** by 10.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] all 10 steps are `<button>` elements
|
||||
- [ ] the rail is fully operable by keyboard: tab, arrow keys, enter and space
|
||||
- [ ] current step is exposed with `aria-current`
|
||||
- [ ] completed, current and unavailable states are distinguishable without relying on color alone
|
||||
- [ ] the "1 / 10" counter is gone
|
||||
- [ ] app-wide `<div onclick>` count dropped by 10 versus the wave 0 baseline
|
||||
|
||||
---
|
||||
|
||||
### T5.2 — B3: Launcher empty state, then remove the picker card
|
||||
|
||||
- **Items:** `B3`
|
||||
- **Depends on:** T4.1
|
||||
- **Blocks:** T5.3
|
||||
- **Surface:** `html/`
|
||||
- **Files:** launcher, project picker card
|
||||
|
||||
**Problem:** The proposal removes the project-picker card, but the first-run empty state
|
||||
lives inside it. A header dropdown is the wrong home for "create your first project".
|
||||
|
||||
**Do:** Build an explicit first-run empty state on the launcher: no projects yet, here is how
|
||||
to create one, here is the sample project. Only once that exists, remove the picker card.
|
||||
Order matters — removing the card first strands new users.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] a brand-new account with zero projects sees a clear path to create one
|
||||
- [ ] the sample project remains discoverable from the empty state
|
||||
- [ ] the picker card is removed only after the empty state ships
|
||||
- [ ] switching projects still works from the header for users who have projects
|
||||
|
||||
---
|
||||
|
||||
### T5.3 — B4 surface: pipeline strip
|
||||
|
||||
- **Items:** `B4` UI half
|
||||
- **Depends on:** T4.1, T5.2
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** launcher
|
||||
|
||||
**Do:** Build the four-cell pipeline strip against the server aggregates from `T4.1`. Each
|
||||
cell links through to the filtered list, using the URL state from `T4.2`.
|
||||
|
||||
**Do not:** ship it against `localStorage`. That is the specific thing `B4` warns about.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] every number comes from a server endpoint
|
||||
- [ ] each cell links to a filtered view via a shareable URL
|
||||
- [ ] a project with zero work packages renders a sensible empty state, not four zeros that look broken
|
||||
- [ ] the strip announces updates via `aria-live` if it refreshes in place
|
||||
|
||||
---
|
||||
|
||||
### T5.4 — CR-005: Upload building / floor / sector lists at SOP setup
|
||||
|
||||
- **Items:** `CR-005`
|
||||
- **Depends on:** T5.1
|
||||
- **Blocks:** T6.3
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** SOP wizard, server API, schema
|
||||
|
||||
**Intent:** The location taxonomy differs per project. On Micron, floors within B100 behave
|
||||
like separate buildings, so floor and sector are the unit of both execution and cost
|
||||
tracking. Configure it once per SOP rather than hard-coding it.
|
||||
|
||||
**Do:** A wizard step accepting a bulk upload (CSV or paste) of Building / Floor / Sector
|
||||
values, with the hierarchy preserved. Editable after import: add, rename, deactivate. Store
|
||||
as structured codes, not display strings — `CR-018` needs to group by them.
|
||||
|
||||
Deactivating a value hides it from new work packages without breaking existing ones that
|
||||
reference it.
|
||||
|
||||
**Do not:** hardcode floor or building names. The B100 list has not been supplied yet (see
|
||||
`IMPLEMENTATION.md` section 8). Seed with obviously-fake sample values.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] CSV upload and paste both work and report rejected rows with reasons
|
||||
- [ ] duplicates are detected and reported rather than silently merged
|
||||
- [ ] values are editable after import
|
||||
- [ ] deactivating a value hides it from new work packages; an existing work package referencing it still renders
|
||||
- [ ] values are stored as codes suitable for grouping
|
||||
- [ ] no guessed real-world floor names exist anywhere in the code
|
||||
|
||||
---
|
||||
|
||||
### T5.5 — CR-006: Section toggles
|
||||
|
||||
- **Items:** `CR-006`
|
||||
- **Depends on:** T5.1
|
||||
- **Blocks:** T5.6, T5.7, T7.2
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** SOP wizard, work package renderer, PDF export, creator
|
||||
|
||||
**Intent:** This is the structural fix behind most removal requests in the plan. Rather than
|
||||
deleting fields globally, each project turns on only the sections it uses. It is what lets
|
||||
Micron drop Kitting and Assets while another project keeps them.
|
||||
|
||||
**Do:** In the SOP creation tool, list every work package section with an on/off toggle:
|
||||
General Information, Location, Scope of Work, Assets, Materials, Kitting, Drawings and
|
||||
Attachments, Constraints, QA/QC, Closeout. Default all on for a new SOP.
|
||||
|
||||
A section toggled off does not render in the creation form, the detail view, or the PDF
|
||||
export. Data already captured is retained, and toggling back on restores it intact.
|
||||
|
||||
**Do not:** delete data on toggle-off. Ever. And note `X4`: the creator is an iframe child
|
||||
until `T7.1`, so toggle propagation into the creator may need revisiting in wave 7 — test it
|
||||
and say what you found.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] all 10 sections are toggleable
|
||||
- [ ] a section toggled off is absent from the form, the detail view and the PDF export
|
||||
- [ ] toggling off then on restores prior data with no loss
|
||||
- [ ] new SOPs default to all sections on
|
||||
- [ ] toggle state propagates into the creator, or the PR documents exactly where it does not and why
|
||||
|
||||
---
|
||||
|
||||
### T5.6 — CR-002: Remove Acumatica Cost Code and Task
|
||||
|
||||
- **Items:** `CR-002`
|
||||
- **Depends on:** T5.5
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/` + `server/`
|
||||
- **Files:** work package form, detail view, PDF export
|
||||
|
||||
**Intent:** The team concluded these are noise on a field work package. Cost codes are
|
||||
effectively constant and the Acumatica task mapping is a PM concern. The cost visibility they
|
||||
actually want is by building and floor, which is `CR-004` and `CR-018`.
|
||||
|
||||
**Do:** Hide both fields from the form, the detail view and the PDF export, using the section
|
||||
or field toggle mechanism from `T5.5`. Retain the data and the model.
|
||||
|
||||
**Do not:** drop the columns or delete the data. Another project may need these fields, and
|
||||
that is what the toggles are for.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] neither field appears in the form, detail view or PDF export for the Micron EUV SOP
|
||||
- [ ] existing records still hold their values; confirm by querying
|
||||
- [ ] the fields can be re-enabled for another SOP without a code change
|
||||
- [ ] no schema migration drops data
|
||||
|
||||
---
|
||||
|
||||
### T5.7 — CR-016: Assets section off for Micron EUV
|
||||
|
||||
- **Items:** `CR-016`
|
||||
- **Depends on:** T5.5
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** configuration
|
||||
- **Files:** SOP configuration for Micron EUV
|
||||
|
||||
**Intent:** Asset content duplicates the database Clinton's team maintains. Integration is
|
||||
deferred, so the section comes out in the interim.
|
||||
|
||||
**Do:** Toggle Assets off for the Micron EUV SOP. Leave the section and its data model in the
|
||||
application so the eventual database integration has somewhere to land.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] Assets does not render for Micron EUV in the form, detail view or export
|
||||
- [ ] the section and model remain in the codebase
|
||||
- [ ] another SOP can enable Assets and it works
|
||||
|
||||
---
|
||||
|
||||
### T5.8 — S1 (wizard): Inline validation
|
||||
|
||||
- **Items:** `S1` wizard half
|
||||
- **Depends on:** T5.1
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** SOP wizard validation, `wp-creation-app.js:1144` for the pattern to replace
|
||||
|
||||
**Problem:** Validation is `alert()`-only and `validateStep` guards only steps 1, 5 and 6,
|
||||
while the markup marks required fields throughout. The message "Subject and WP Type are
|
||||
required" names no field, highlights nothing and scrolls nowhere.
|
||||
|
||||
**Do:** Inline validation on every step that has required fields. Errors appear at the field,
|
||||
the first invalid field receives focus, and the message says what is wrong. Announce via the
|
||||
`aria-live` region from `T4.5`. Remove the wizard's `alert()` calls.
|
||||
|
||||
**Do not:** add a native `alert()`, `confirm()` or `prompt()` anywhere. The app-wide count
|
||||
from wave 0 must go down.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] every step with required fields validates them
|
||||
- [ ] each error renders at its field and is associated via `aria-describedby`
|
||||
- [ ] submitting an invalid step focuses and scrolls to the first error
|
||||
- [ ] errors announce to screen readers
|
||||
- [ ] the wizard's native dialog count is 0; record the new app-wide count
|
||||
|
||||
---
|
||||
|
||||
## Wave 5 exit criteria
|
||||
|
||||
- [ ] the stepper is keyboard operable and `<div onclick>` count dropped by at least 10
|
||||
- [ ] section toggles work end to end, including the export
|
||||
- [ ] Acumatica fields and Assets are hidden by configuration, with no data deleted
|
||||
- [ ] the wizard has no `alert()` calls left
|
||||
- [ ] first-run users can create a project
|
||||
153
docs/waves/wave-6.md
Normal file
153
docs/waves/wave-6.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Wave 6 — Work package general information
|
||||
|
||||
**Items:** `CR-001`, `CR-003`, `CR-004`, `CR-018`, `A7`
|
||||
**Depends on:** wave 5 merged
|
||||
**Why here:** these are the field's most-requested changes and they need the location lists
|
||||
(`T5.4`), the server aggregates (`T4.1`) and the token system (`T3.2`) to already exist.
|
||||
|
||||
---
|
||||
|
||||
### T6.1 — CR-001: P6 Activity ID and Description
|
||||
|
||||
- **Items:** `CR-001`
|
||||
- **Depends on:** T5.5
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** work package model, General Information section, list/dashboard, PDF export
|
||||
|
||||
**Intent:** Every work package traces back to the P6 schedule activity that drives it, so a
|
||||
date on the work package is anchored to a schedule activity rather than floating on its own.
|
||||
The meeting placed this at the top of the work package, next to the due date.
|
||||
|
||||
**Do:** Add `P6 Activity ID` and `P6 Activity Description` to General Information. Free text
|
||||
is acceptable — a validated lookup against an imported activity list is explicitly deferred,
|
||||
partly because the Micron schedule is actively being reworked.
|
||||
|
||||
Display the Activity ID next to the Due Date so the schedule driver is visible without
|
||||
scrolling. Add it to the list/dashboard as a sortable column and to the PDF export.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] both fields exist, persist, and survive a reload
|
||||
- [ ] Activity ID renders next to Due Date on the detail view
|
||||
- [ ] the list/dashboard column sorts correctly, including with empty values
|
||||
- [ ] both fields appear on the PDF export
|
||||
- [ ] the fields respect the `CR-006` section toggles
|
||||
|
||||
---
|
||||
|
||||
### T6.2 — CR-003: Priority
|
||||
|
||||
- **Items:** `CR-003`
|
||||
- **Depends on:** T3.5
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** work package model, General Information, list/dashboard, PDF export
|
||||
|
||||
**Intent:** Due date alone does not convey urgency. Exactly three levels, agreed live in the
|
||||
meeting: Normal, High, Urgent. Normal is the baseline default.
|
||||
|
||||
**Do:** A required dropdown with those three values, defaulting to Normal. Filterable and
|
||||
sortable on the dashboard. Color-coded using canonical tokens only (`X7`). Printed on the
|
||||
PDF export.
|
||||
|
||||
Priority is independent of status: it can change after issue without a status change.
|
||||
|
||||
**Do not:** add a fourth level. Do not introduce a new color outside the token system.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] exactly three values exist; Normal is the default on a new work package
|
||||
- [ ] the dashboard filters and sorts by priority
|
||||
- [ ] priority colors come from canonical tokens; no raw hex added
|
||||
- [ ] color is not the only signal — the label is always present
|
||||
- [ ] priority prints on the PDF export
|
||||
- [ ] changing priority does not alter status
|
||||
|
||||
---
|
||||
|
||||
### T6.3 — CR-004: Building / Floor / Sector dropdowns
|
||||
|
||||
- **Items:** `CR-004`
|
||||
- **Depends on:** T5.4, T4.1
|
||||
- **Blocks:** T6.4, T8.4
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** Location section, work package model, dashboard filters
|
||||
|
||||
**Intent:** Users pick location from a controlled list rather than typing it. Floors within
|
||||
B100 behave like separate buildings and are the unit of both execution and cost tracking.
|
||||
|
||||
**Do:** Three dependent dropdowns in the Location section, sourced from the project
|
||||
configuration built in `T5.4`. Selecting a Building filters Floors; selecting a Floor filters
|
||||
Sectors. Store codes, not display strings. Add dashboard filters for all three.
|
||||
|
||||
**Do not:** free-text these fields, and do not read the option lists from `localStorage`
|
||||
(`X5`).
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] all three render as dropdowns populated from project configuration
|
||||
- [ ] dependent filtering works, and clearing a parent clears its children
|
||||
- [ ] values persist as codes; confirm by inspecting stored data
|
||||
- [ ] the dashboard filters by each of the three
|
||||
- [ ] a work package referencing a deactivated value still renders correctly
|
||||
- [ ] all option data comes from the server
|
||||
|
||||
---
|
||||
|
||||
### T6.4 — CR-018: Rollup by floor and area
|
||||
|
||||
- **Items:** `CR-018`
|
||||
- **Depends on:** T6.3, T4.1
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** aggregate endpoints, dashboard
|
||||
|
||||
**Intent:** This is why the Acumatica cost code was removed rather than relabeled. The
|
||||
tracking dimension the team wants is floor and area, not an accounting code. For Phase 2 the
|
||||
intent is to stop treating B100 as one building and monitor by floor, since each floor
|
||||
carries its own instrumentation and material load.
|
||||
|
||||
**Do:** Extend the `T4.1` aggregates to group and total by Building, Floor and Sector. Surface
|
||||
grouped totals on the dashboard. Where hours are captured (Closeout `Actual Hours`, retained
|
||||
per `CR-017`), roll them up along the same dimensions.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the dashboard groups and totals by Building, Floor and Sector
|
||||
- [ ] totals reconcile against an unfiltered count; verify with a known data set
|
||||
- [ ] Actual Hours rolls up along the same dimensions
|
||||
- [ ] grouping is computed server-side
|
||||
- [ ] work packages with no location assigned appear in an explicit "unassigned" group rather than vanishing
|
||||
|
||||
---
|
||||
|
||||
### T6.5 — A7: Card status lines, footer clarity, language and time
|
||||
|
||||
- **Items:** `A7`
|
||||
- **Depends on:** T3.5
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** card components, footer, `admin.js:484-517`
|
||||
|
||||
**Do:** Clarify status lines on cards and tidy the footer as proposed.
|
||||
|
||||
**Do not:** remove localization. `admin.js:484-517` handles language and time and it is a
|
||||
shipped feature. The review specifically endorsed keeping it. If the proposal reads as
|
||||
removing it, that reading is wrong.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] card status lines read clearly and use the canonical status colors
|
||||
- [ ] the footer is unambiguous about what it is showing
|
||||
- [ ] localization still functions; verify by switching language and time format
|
||||
- [ ] `admin.js:484-517` behavior is unchanged
|
||||
|
||||
---
|
||||
|
||||
## Wave 6 exit criteria
|
||||
|
||||
- [ ] P6 activity, priority and structured location all persist and export
|
||||
- [ ] the dashboard filters by priority and by all three location levels
|
||||
- [ ] rollups are server-computed and reconcile
|
||||
- [ ] localization intact
|
||||
297
docs/waves/wave-7.md
Normal file
297
docs/waves/wave-7.md
Normal file
@@ -0,0 +1,297 @@
|
||||
# Wave 7 — The creator
|
||||
|
||||
**Items:** `B7`, `A1`, `CR-015`, `A2`, `A6`, `CR-014`, `CR-007`, `B6`, `S1` (creator), `F6`
|
||||
**Depends on:** wave 6 merged, and `T4.2` (URL state) merged
|
||||
**Why last among the build waves:** most of it depends on the iframe decision, and `CR-014`
|
||||
depends on `X1`.
|
||||
|
||||
`T7.1` is the largest engineering item in the plan. Decided and approved: the iframe gets
|
||||
dissolved. Do it first — everything after it is cheaper on the far side.
|
||||
|
||||
---
|
||||
|
||||
### T7.1 — B7: Dissolve the creator iframe
|
||||
|
||||
- **Items:** `B7`
|
||||
- **Depends on:** T6.5
|
||||
- **Blocks:** T7.2 through T7.9
|
||||
- **Surface:** `html/`
|
||||
- **Files:** parent page hosting the creator, the creator itself, cross-frame messaging
|
||||
|
||||
**Problem:** The tab row lives in the parent and the toolbar lives in the iframe child, so
|
||||
folding one into the other is impossible while the boundary exists. The boundary is also
|
||||
implicated in `F4` and possibly in `CR-006` toggle propagation (`X4`).
|
||||
|
||||
**Do:** Remove the iframe boundary so the creator renders in the parent document. Expect to
|
||||
untangle: cross-frame messaging, duplicated styling, focus and scroll management, and
|
||||
anything relying on separate document contexts.
|
||||
|
||||
Do this as its own PR with no feature work attached. It will be large and it needs to be
|
||||
reviewable as a structural change.
|
||||
|
||||
**Do not:** bundle any other item into this task, and do not leave a dormant iframe path
|
||||
behind a flag.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] no iframe remains in the creator; grep confirms
|
||||
- [ ] every creator feature works as it did before: verify against the wave 0 baseline screenshots and a functional pass
|
||||
- [ ] `F4` no longer reproduces
|
||||
- [ ] `CR-006` section toggles propagate into the creator with no special-casing
|
||||
- [ ] browser back and forward still behave with the `T4.2` URL state
|
||||
- [ ] no cross-frame messaging code remains
|
||||
|
||||
---
|
||||
|
||||
### T7.2 — F6 + A4 pattern: Section tabs replace the 4,700px form
|
||||
|
||||
- **Items:** `F6`
|
||||
- **Depends on:** T7.1, T5.5, T3.5
|
||||
- **Blocks:** T7.9
|
||||
- **Surface:** `html/`
|
||||
- **Files:** creator layout, jump links
|
||||
|
||||
**Problem:** The creator is one form roughly 4,700px tall with 11 cards rendered at once and
|
||||
jump links standing in for structure.
|
||||
|
||||
**Do:** Give the form real structure — section tabs or an equivalent that shows one coherent
|
||||
group at a time. Respect the `CR-006` toggles: a section toggled off has no tab. Retire the
|
||||
jump links. Section identity belongs in the URL (`T4.2`) so a section is linkable.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] no single view exceeds roughly two screen heights at 1440px
|
||||
- [ ] toggled-off sections have no tab
|
||||
- [ ] each section is addressable by URL and survives refresh
|
||||
- [ ] jump links are gone
|
||||
- [ ] tabs are keyboard operable and follow the tab pattern with `aria-selected` and arrow keys
|
||||
- [ ] unsaved work is preserved when moving between sections (`T4.3`)
|
||||
|
||||
---
|
||||
|
||||
### T7.3 — A1 + CR-015: Guarded transitions and the hold bug
|
||||
|
||||
- **Items:** `A1`, `CR-015`
|
||||
- **Depends on:** T7.1
|
||||
- **Blocks:** T7.4, T7.6
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** status handling, constraint handling, `wp-creation-app.js:1962-1972`
|
||||
|
||||
**This is one task, not two (`X2`).** The hold-not-clearing bug and the transition model are
|
||||
the same code. `CR-015` is the highest-severity item in the plan and it was reproduced live
|
||||
in front of the Micron team.
|
||||
|
||||
**Problem:** Clearing all constraints does not clear the hold. Hold state is not purely
|
||||
derived from open constraints, which is why it goes stale.
|
||||
|
||||
**Do:** Model transitions explicitly. For each state, define the primary next action **plus
|
||||
an audited override**. "One legal next action" is too narrow — `wp-creation-app.js:1962-1972`
|
||||
contains a deliberate logged-override path for predecessors, and Issue (Hold) is a branch
|
||||
from several states, not a single linear step.
|
||||
|
||||
Derive hold state from open constraints rather than storing it independently, or if it must
|
||||
be stored, recalculate it on every constraint change. Write every hold and release to the
|
||||
work package history with timestamp, user and reason.
|
||||
|
||||
**Do not:** remove the logged-override path. It is an audited business rule. And do not fix
|
||||
the symptom by recalculating on page load only.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] clearing the last open constraint clears the hold and returns the work package to its prior status, with no refresh
|
||||
- [ ] logging a new constraint on an in-progress work package places it back on hold
|
||||
- [ ] clearing that constraint releases it again
|
||||
- [ ] the override path still works and still logs
|
||||
- [ ] Issue (Hold) is reachable from every state it should branch from
|
||||
- [ ] every hold and release is in the history with timestamp, user and reason
|
||||
- [ ] a regression test covers the clear-last-constraint path specifically
|
||||
- [ ] the exact root cause is stated in the PR
|
||||
|
||||
**Why the history matters:** the delay-documentation use case is the business justification
|
||||
for the whole constraint workflow. If a constraint log can be shown to have been wrong, it
|
||||
stops supporting a notice of delay or a change order claim.
|
||||
|
||||
---
|
||||
|
||||
### T7.4 — A2: De-duplicate the constraint warning
|
||||
|
||||
- **Items:** `A2`
|
||||
- **Depends on:** T7.3
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** creator constraint warnings
|
||||
|
||||
**Problem:** The same warning appears three times.
|
||||
|
||||
**Do:** Keep one. The top banner is the only one visible without scrolling, so it stays. The
|
||||
tab count badge then has to carry the weight the removed duplicates were carrying — make the
|
||||
count prominent enough to notice from any section.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the warning appears once
|
||||
- [ ] the tab badge shows the open constraint count and is legible at 390px
|
||||
- [ ] with the constraints section scrolled out of view, a user can still tell constraints are open
|
||||
- [ ] the banner announces via `aria-live` when the count changes
|
||||
|
||||
---
|
||||
|
||||
### T7.5 — A6: Sidebar triage data and inline hold reason
|
||||
|
||||
- **Items:** `A6`
|
||||
- **Depends on:** T7.3
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** creator sidebar
|
||||
|
||||
**Do:** Surface triage data in the sidebar, including the hold reason inline. The hold reason
|
||||
is already captured by the hold modal, so this is display work.
|
||||
|
||||
**Use case to test against:** someone in a stand-up is asked why a package has not moved.
|
||||
They open it on a phone and need the answer without scrolling or clicking.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the hold reason is visible in the sidebar without opening the modal
|
||||
- [ ] status, priority, due date, P6 activity and open constraint count are all visible together
|
||||
- [ ] usable at 390px
|
||||
- [ ] a package with no hold shows a sensible state rather than an empty slot
|
||||
|
||||
---
|
||||
|
||||
### T7.6 — CR-014: Ready for QA gate
|
||||
|
||||
- **Items:** `CR-014`
|
||||
- **Depends on:** T7.3, T4.2 (blocking dependency `X1`)
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** status model, notification service, QA section
|
||||
|
||||
**Intent:** Looping QA in has historically been the failure point. Marlena raised this
|
||||
directly: QA needs to see inbound work and organize their schedule ahead of time rather than
|
||||
being told after the fact.
|
||||
|
||||
**Do:** Add `Ready for QA` between In Progress and Complete/Closed, inside the `T7.3`
|
||||
transition model (`X3`). Entering that state emails the assigned QA representative and the
|
||||
QA/QC members named on the work package.
|
||||
|
||||
The email includes the work package number and title, location, a scope summary, and **a
|
||||
direct link that opens that work package** — this is why `T4.2` is a hard prerequisite. A
|
||||
dashboard view lists everything sitting in Ready for QA. The QA representative can accept or
|
||||
reject; rejection returns the package to In Progress with a required comment.
|
||||
|
||||
**Do not:** build the email with a link to the app root. That is the failure `X1` exists to
|
||||
prevent.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the new state exists in the transition model, not beside it
|
||||
- [ ] entering it sends email to the QA rep and named QA/QC members
|
||||
- [ ] the link in the email opens that specific work package, including for a signed-out recipient via login
|
||||
- [ ] a dashboard view or filter lists all packages in Ready for QA
|
||||
- [ ] rejection returns to In Progress and requires a comment
|
||||
- [ ] the transition is written to history
|
||||
- [ ] email failure is logged and surfaced, not silent
|
||||
|
||||
**Note:** QA currently runs off a comprehensive Excel questionnaire being migrated into
|
||||
CxAlloy. Integration with CxAlloy is explicitly out of scope. This gate is notification only.
|
||||
|
||||
---
|
||||
|
||||
### T7.7 — CR-007: Upload drawings for offline access
|
||||
|
||||
- **Items:** `CR-007`
|
||||
- **Depends on:** T7.2, T4.3 (blocking dependency `X8`)
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** Drawings and Attachments section, file storage, export
|
||||
|
||||
**Intent:** Today the section holds links, typically to a Bluebeam session. The field wants
|
||||
the specific PDF attached instead: a general foreman opens the package and sees exactly the
|
||||
sheet and the highlighted section relevant to their scope, with no navigation and no
|
||||
connectivity dependency. Links stay supported for those who want them.
|
||||
|
||||
**Do:** File upload alongside the existing link support. Store files with the work package.
|
||||
Include them when the package is exported or downloaded. Make them available offline on a
|
||||
tablet. Each attachment gets a short description field so the creator can note the focus
|
||||
area, for example "Tray section, Level 3 east only".
|
||||
|
||||
Show file size limits and supported types in the UI before upload, not after failure.
|
||||
|
||||
**Do not:** build this before `T4.3`. Uploading into a form with no autosave risks losing
|
||||
both the upload and the surrounding work.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] PDF upload works and the file is retrievable
|
||||
- [ ] links still work alongside uploads
|
||||
- [ ] attachments are included in export or download
|
||||
- [ ] an uploaded drawing opens on a tablet with the network disabled
|
||||
- [ ] the description field persists and prints on the export
|
||||
- [ ] limits and supported types are stated before upload
|
||||
- [ ] upload failure is clear and recoverable, with no loss of surrounding form work
|
||||
- [ ] the whole flow works at 390px
|
||||
|
||||
**Accepted tradeoff:** this shifts effort onto the package creator to isolate the right
|
||||
sheet. That was raised in the meeting and accepted.
|
||||
|
||||
---
|
||||
|
||||
### T7.8 — B6: Sticky action bar
|
||||
|
||||
- **Items:** `B6`
|
||||
- **Depends on:** T7.2
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** creator and wizard action bars
|
||||
|
||||
**Problem:** The proposal placed actions beside the fields, but on the Constraints and
|
||||
Sequence steps that means scrolling to save.
|
||||
|
||||
**Do:** A sticky action bar instead. The creator already solves this; reuse that pattern in
|
||||
the wizard rather than inventing a second one.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] save and primary actions are reachable without scrolling on every step and section
|
||||
- [ ] verified specifically on Constraints and Sequence
|
||||
- [ ] the bar does not obscure fields at 390px
|
||||
- [ ] it shows the save state from `T4.4`
|
||||
|
||||
---
|
||||
|
||||
### T7.9 — S1 (creator): Inline validation
|
||||
|
||||
- **Items:** `S1` creator half
|
||||
- **Depends on:** T7.2
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** creator validation, `wp-creation-app.js:1144`
|
||||
|
||||
**Problem:** 43 native dialogs in the creator alone. `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.
|
||||
|
||||
**Do:** Inline validation matching the wizard pattern from `T5.8`. Errors at the field, focus
|
||||
and scroll to the first invalid one, and with section tabs now in place, the tab containing
|
||||
errors is marked. Remove the creator's native dialogs.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] no `alert()`, `confirm()` or `prompt()` remains in the creator; count is 0
|
||||
- [ ] every required field validates inline
|
||||
- [ ] submitting focuses and scrolls to the first error, switching sections if needed
|
||||
- [ ] sections containing errors are marked in the tab row
|
||||
- [ ] errors announce via `aria-live`
|
||||
- [ ] the app-wide native dialog count is recorded against the wave 0 baseline of 79
|
||||
|
||||
---
|
||||
|
||||
## Wave 7 exit criteria
|
||||
|
||||
- [ ] no iframe; `F4` resolved structurally
|
||||
- [ ] `CR-015` fixed with a regression test and a stated root cause
|
||||
- [ ] hold state is derived, and history records every transition
|
||||
- [ ] the QA gate emails a working deep link
|
||||
- [ ] drawings upload and open offline on a tablet
|
||||
- [ ] creator native dialog count is 0
|
||||
164
docs/waves/wave-8.md
Normal file
164
docs/waves/wave-8.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# Wave 8 — Kitting and material
|
||||
|
||||
**Items:** `CR-009`, `CR-010`, `CR-011`, `CR-012`, `CR-013`
|
||||
**Depends on:** wave 7 merged
|
||||
**Decision, approved Aug 14 2026:** keep and extend Kitting, then ship it **toggled off** for
|
||||
the Micron EUV SOP. Kitting is not happening at Micron today — it is complicated by
|
||||
journeyman ratio and warehouse cost — but the team expects to get there, and prefab arguably
|
||||
already qualifies.
|
||||
|
||||
That means this wave builds functionality that will not be visible on the pilot project. That
|
||||
is intentional. Do not shortcut it on the grounds that nobody is using it, and do not switch
|
||||
it on for Micron.
|
||||
|
||||
---
|
||||
|
||||
### T8.1 — CR-009: Kitting section retained and structured
|
||||
|
||||
- **Items:** `CR-009`
|
||||
- **Depends on:** T7.9
|
||||
- **Blocks:** T8.2, T8.3, T8.4
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** Kitting section, SOP configuration
|
||||
|
||||
**Do:** Confirm the Kitting section is intact and structured to receive `T8.2` through
|
||||
`T8.4`. Define kitting statuses explicitly. Proposed set, adjust only with a stated reason:
|
||||
`Not Started`, `Picking`, `Staged`, `In Transit`, `Delivered`.
|
||||
|
||||
Then set the section off for the Micron EUV SOP via the `CR-006` toggles.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] kitting statuses are defined as an explicit set, not free text
|
||||
- [ ] the section is off for Micron EUV and absent from its form, detail view and export
|
||||
- [ ] a different SOP can enable it and it works fully
|
||||
- [ ] no kitting data is deleted anywhere
|
||||
|
||||
---
|
||||
|
||||
### T8.2 — CR-010: Warehouse Owner dropdown
|
||||
|
||||
- **Items:** `CR-010`
|
||||
- **Depends on:** T8.1
|
||||
- **Blocks:** T8.3
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** Kitting section, dashboard filters
|
||||
|
||||
**Intent:** A named person owns fulfillment of the kit. Today that is Paul Coonrod and
|
||||
everything bottlenecks through him informally, so the work package should record it
|
||||
explicitly.
|
||||
|
||||
**Do:** A Warehouse Owner dropdown populated from project members. That person receives
|
||||
kitting notifications by default. Filterable on the dashboard so a warehouse owner can see
|
||||
everything assigned to them.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the dropdown lists project members and persists a selection
|
||||
- [ ] the selected owner is a default recipient for `T8.3` notifications
|
||||
- [ ] the dashboard filters by warehouse owner
|
||||
- [ ] removing someone from the project does not break existing work packages referencing them
|
||||
|
||||
---
|
||||
|
||||
### T8.3 — CR-011: Kitting status change notification
|
||||
|
||||
- **Items:** `CR-011`
|
||||
- **Depends on:** T8.2, T4.2 (blocking dependency `X1`)
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** notification service, kitting status handling
|
||||
|
||||
**Intent:** Extends the existing status-change notification pattern to kitting so the field
|
||||
knows when material moves from requested to staged to delivered without chasing it in Teams.
|
||||
|
||||
**Do:** A kitting status change emails the work package distribution list. The email states
|
||||
the work package, the old and new status, who changed it, the delivery location, and a direct
|
||||
link to the work package. Match the existing status-change email pattern so users see one
|
||||
convention, not two.
|
||||
|
||||
**Do not:** send a link to the app root (`X1`).
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] every kitting status change sends to the distribution list
|
||||
- [ ] the email includes old status, new status, actor, delivery location and a working deep link
|
||||
- [ ] the link opens that specific work package, including via login for a signed-out recipient
|
||||
- [ ] formatting and tone match the existing status-change email
|
||||
- [ ] rapid consecutive changes do not produce a burst of near-identical emails
|
||||
- [ ] send failures are logged and surfaced
|
||||
|
||||
---
|
||||
|
||||
### T8.4 — CR-012: Delivery location on Kitting / Material
|
||||
|
||||
- **Items:** `CR-012`
|
||||
- **Depends on:** T8.1, T6.3
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** Kitting section, print/pick output
|
||||
|
||||
**Intent:** Delivery logistics are the real pain. Staging at the warehouse, getting it on a
|
||||
truck, then making sure material reaches the correct floor lay-down, shark cage or conduit
|
||||
tree rather than being picked at will by whoever is closest.
|
||||
|
||||
**Do:** Capture delivery location using the same Building / Floor / Sector lists as `CR-004`,
|
||||
plus a free-text detail field for specifics like lay-down area, shark cage or conduit tree.
|
||||
Include the delivery location on the kitting notification email and on any pick or delivery
|
||||
printout.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] delivery location uses the shared location lists, not a parallel free-text field
|
||||
- [ ] the detail field persists and prints
|
||||
- [ ] the location appears on the `T8.3` email
|
||||
- [ ] it appears on any pick or delivery printout
|
||||
|
||||
---
|
||||
|
||||
### T8.5 — CR-013: Lightweight material request
|
||||
|
||||
- **Items:** `CR-013`
|
||||
- **Depends on:** T8.4, T7.2 (sequencing dependency `X6`)
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** Materials section, request model, dashboard
|
||||
|
||||
**Decision, approved Aug 14 2026:** build the lightweight version. Defer the parts catalog,
|
||||
live inventory and warehouse integration.
|
||||
|
||||
**Intent:** Material requests run today through per-floor Teams chats and a spreadsheet, all
|
||||
funneling to Paul Coonrod. The comparison drawn in the meeting was a project where requests
|
||||
went into a OneNote and became, in the words used at the time, word vomit. The point of this
|
||||
item is structure, not features.
|
||||
|
||||
**In scope:** line items (description, quantity, unit), needed-by date, requestor, delivery
|
||||
location (reuse `T8.4`), and status.
|
||||
|
||||
**Out of scope, do not build:** master parts catalog dropdown, live inventory levels,
|
||||
warehouse system integration.
|
||||
|
||||
**Do:** Build the in-scope set. Requests are visible on the dashboard and filterable by
|
||||
delivery location and status.
|
||||
|
||||
**Do not:** build this before `T7.2`. A material card added to the pre-tab creator is a 12th
|
||||
card on a 4,700px form. And do not invent a parts list — Nate's spreadsheet and the master
|
||||
material workbook have not been supplied yet (see `IMPLEMENTATION.md` section 8).
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] line items can be added, edited and removed, with quantity and unit
|
||||
- [ ] needed-by date, requestor, delivery location and status all persist
|
||||
- [ ] requests appear on the dashboard, filterable by location and status
|
||||
- [ ] no parts catalog, inventory count or warehouse integration exists in the diff
|
||||
- [ ] the section respects `CR-006` toggles
|
||||
- [ ] the whole flow works at 390px, since requests originate in the field
|
||||
|
||||
---
|
||||
|
||||
## Wave 8 exit criteria
|
||||
|
||||
- [ ] Kitting is fully built and toggled off for Micron EUV
|
||||
- [ ] notifications carry working deep links and a delivery location
|
||||
- [ ] the material request is the lightweight scope, nothing more
|
||||
- [ ] no guessed part numbers or floor names anywhere in the code
|
||||
217
docs/waves/wave-9.md
Normal file
217
docs/waves/wave-9.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# Wave 9 — Verification and cleanup
|
||||
|
||||
**Items:** `CR-008`, `CR-017` (guard), `S6`, `S7`, `S8`, `C1` audit, `C2` audit, part of `C4`
|
||||
**Depends on:** wave 8 merged
|
||||
**Why last:** `CR-008` reviews the PDF export against the final structure rather than
|
||||
reviewing it twice. The audits confirm the standing requirements actually held across eight
|
||||
waves rather than being asserted per PR.
|
||||
|
||||
---
|
||||
|
||||
### T9.1 — CR-008: PDF export review
|
||||
|
||||
- **Items:** `CR-008`
|
||||
- **Depends on:** T8.5
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `server/` + `html/`
|
||||
- **Files:** PDF export
|
||||
|
||||
**Problem:** The export was never walked through in the meeting. It needs a pass to confirm
|
||||
it prints what the field actually needs and nothing it does not, now that the work package
|
||||
structure has changed substantially.
|
||||
|
||||
**Do:** Review the export section by section against the final structure. Sections toggled
|
||||
off under `CR-006` must be omitted. The export must include: P6 Activity ID and Description,
|
||||
Priority, Building / Floor / Sector, scope of work, materials, constraints with status,
|
||||
QA/QC, and an attachment index. Removed fields — ACU Cost Code, Acumatica Task — must not
|
||||
appear.
|
||||
|
||||
Open question to raise in the PR, not to decide alone: should attachments merge into a single
|
||||
PDF package, or be listed as separate files? The field preference expressed in the meeting
|
||||
was to hand someone exactly the sheet they need and nothing more, which argues for a merged
|
||||
package with only the attached sheets. Propose, do not assume.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] every listed field appears in the export
|
||||
- [ ] toggled-off sections are absent
|
||||
- [ ] ACU Cost Code and Acumatica Task appear nowhere
|
||||
- [ ] the export is legible printed in black and white
|
||||
- [ ] the export is legible opened on a tablet
|
||||
- [ ] the attachment index lists every attachment with its description
|
||||
- [ ] the merge-versus-list question is raised in the PR with a recommendation
|
||||
|
||||
---
|
||||
|
||||
### T9.2 — CR-017: Actual Hours guard
|
||||
|
||||
- **Items:** `CR-017`
|
||||
- **Depends on:** T9.1
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** verification only
|
||||
- **Files:** Closeout section
|
||||
|
||||
**This is a guard, not a build.** Removing Actual Hours was floated in the meeting and
|
||||
rejected — Marlena said she likes tracking actual hours spent so it can be measured. It is
|
||||
listed here so a later simplification pass does not quietly drop it.
|
||||
|
||||
**Do:** Confirm Actual Hours still exists in Closeout, is optional rather than required, and
|
||||
survived eight waves of change.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] Actual Hours exists in Closeout and persists
|
||||
- [ ] it is optional, and a work package can be closed without it
|
||||
- [ ] it rolls up per `T6.4`
|
||||
- [ ] a follow-up item is logged for comparing actual against estimated hours to produce a productivity factor
|
||||
|
||||
---
|
||||
|
||||
### T9.3 — S6: One icon system
|
||||
|
||||
- **Items:** `S6`
|
||||
- **Depends on:** T9.1
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** every page
|
||||
|
||||
**Problem:** The icon set mixes emoji and dingbats, and at least one glyph is used for two
|
||||
different meanings on the same page.
|
||||
|
||||
**Do:** Pick one icon system and convert everything to it. Build a mapping of meaning to icon
|
||||
and record it in `docs/reference/tokens.md`. Resolve every duplicate meaning.
|
||||
|
||||
**Do not:** leave emoji in the UI. They render differently per platform, which is part of why
|
||||
the same glyph reads as two things.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] one icon system across all 6 pages
|
||||
- [ ] no glyph carries two meanings anywhere
|
||||
- [ ] every icon has a text label or an accessible name
|
||||
- [ ] the meaning-to-icon mapping is documented
|
||||
- [ ] icons render identically on Windows, macOS and a tablet
|
||||
|
||||
---
|
||||
|
||||
### T9.4 — S7: Sample-data cleanup
|
||||
|
||||
- **Items:** `S7`
|
||||
- **Depends on:** T9.1
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/` + `server/`
|
||||
- **Files:** every sample-data affordance
|
||||
|
||||
**Problem:** Four sample-data affordances under three names. One sits a single click from
|
||||
live project data with no confirm and no undo.
|
||||
|
||||
**Do:** Reduce to one affordance with one name. Move it away from live project actions. Add a
|
||||
confirmation stating exactly what will happen, and make it reversible or clearly scoped to a
|
||||
sample project only.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] exactly one sample-data affordance exists, under one name
|
||||
- [ ] it is not adjacent to any live project action
|
||||
- [ ] it confirms before acting, naming what it will do
|
||||
- [ ] it cannot touch live project data; verify by attempting it against a real project
|
||||
- [ ] the other three affordances are removed; grep confirms
|
||||
|
||||
---
|
||||
|
||||
### T9.5 — C1 + S8: Accessibility audit
|
||||
|
||||
- **Items:** `C1`, `S8`
|
||||
- **Depends on:** T9.3
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** all pages, `.help-tip` elements
|
||||
|
||||
**`S8` is finished here** because tooltips are the one accessibility item with no natural
|
||||
host component earlier in the plan. 15 `.help-tip` badges are `<span>` elements with no
|
||||
`tabindex`, so the `:focus` half of their CSS rule is dead code and there is no touch path at
|
||||
all — on tablets, which is exactly what Field View targets.
|
||||
|
||||
**Do:** Make every `.help-tip` reachable by keyboard and by touch. Then audit the whole app
|
||||
against the `CLAUDE.md` rules and record results in `docs/reference/accessibility-audit.md`.
|
||||
|
||||
Compare against the wave 0 baseline counts:
|
||||
|
||||
| Metric | Baseline | Target |
|
||||
|---|---|---|
|
||||
| `<div>` / `<span>` with `onclick` | 12 / 2 | 0 |
|
||||
| `.help-tip` unreachable by keyboard | 15 | 0 |
|
||||
| `aria-live` regions | 0 | at least 1 per toast system and banner |
|
||||
| Text below 4.5:1 | present | 0 |
|
||||
| `outline: none` without replacement | present | 0 |
|
||||
| Native dialogs (`alert`/`confirm`/`prompt`) | 79 | 0, or documented exceptions |
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] every `.help-tip` works by keyboard and by touch
|
||||
- [ ] every metric above meets target, or the gap is documented with a reason and a follow-up item
|
||||
- [ ] a full keyboard-only pass completes the primary flow: sign in, create project, SOP wizard, create work package, issue it
|
||||
- [ ] the audit document exists with per-page results
|
||||
|
||||
---
|
||||
|
||||
### T9.6 — C2: Mobile pass
|
||||
|
||||
- **Items:** `C2`
|
||||
- **Depends on:** T9.5
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** `html/`
|
||||
- **Files:** all pages
|
||||
|
||||
**Problem:** Nothing in the original proposal touched mobile, and it is where the worst
|
||||
rendering was found. Field View at 390px is the gloved-hands surface.
|
||||
|
||||
**Do:** A deliberate pass at 390px across all 6 pages and the full primary flow. Capture
|
||||
after screenshots and compare against the wave 0 baseline.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] the full primary flow completes at 390px without horizontal scrolling
|
||||
- [ ] tap targets are at least 44px throughout
|
||||
- [ ] no control is clipped, overlapped or unreachable on any page
|
||||
- [ ] `CR-007` attachments open at 390px, offline
|
||||
- [ ] `T8.5` material requests can be raised at 390px
|
||||
- [ ] after screenshots for all 6 pages at 390px are committed alongside the baseline
|
||||
|
||||
---
|
||||
|
||||
### T9.7 — Final reconciliation
|
||||
|
||||
- **Items:** all
|
||||
- **Depends on:** T9.6
|
||||
- **Blocks:** nothing
|
||||
- **Surface:** documentation
|
||||
- **Files:** creates `docs/reference/completion.md`
|
||||
|
||||
**Do:** Walk all 55 items from `IMPLEMENTATION.md` section 6 and record, for each: built /
|
||||
deferred / not applicable, the PR that delivered it, and any deviation from its written
|
||||
acceptance criteria.
|
||||
|
||||
Explicitly confirm the four out-of-scope items in section 7 were not built: no parts catalog
|
||||
or inventory, no asset database integration, no CxAlloy integration, no P6 activity import.
|
||||
|
||||
Then list what the plan learned that the next revision should carry: items whose acceptance
|
||||
criteria turned out wrong, inputs still outstanding, and follow-ups logged along the way.
|
||||
|
||||
**Done when:**
|
||||
|
||||
- [ ] all 55 items are accounted for with a PR reference or a stated reason
|
||||
- [ ] every deviation from written acceptance criteria is documented
|
||||
- [ ] the four out-of-scope items are confirmed unbuilt
|
||||
- [ ] outstanding inputs from `IMPLEMENTATION.md` section 8 are restated with current status
|
||||
- [ ] follow-ups are collected in one place for the next revision
|
||||
|
||||
---
|
||||
|
||||
## Wave 9 exit criteria
|
||||
|
||||
- [ ] the export matches the final structure
|
||||
- [ ] one icon system, one sample-data affordance
|
||||
- [ ] accessibility metrics hit target or are documented
|
||||
- [ ] the primary flow works at 390px
|
||||
- [ ] every item is reconciled
|
||||
Reference in New Issue
Block a user