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:
102
CLAUDE.md
Normal file
102
CLAUDE.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Working rules — Work Package Suite
|
||||||
|
|
||||||
|
This repo is being changed against a fixed spec. Read `IMPLEMENTATION.md` before starting
|
||||||
|
any task, and read the wave file for the task you are on. Do not work from this file alone.
|
||||||
|
|
||||||
|
## The spec is the source of truth
|
||||||
|
|
||||||
|
Every change traces to an item ID (`CR-001`, `F1`, `S1`, `A1`, `B1`, `C1`). If you are about
|
||||||
|
to make a change that has no ID, stop. Either it belongs to an existing item and you should
|
||||||
|
say which, or it is out of scope and should be logged in `docs/waves/backlog.md` instead of
|
||||||
|
built.
|
||||||
|
|
||||||
|
Do not renumber, merge, or reinterpret item IDs. They are referenced in documents outside
|
||||||
|
this repo that other people are reading.
|
||||||
|
|
||||||
|
## Scope discipline
|
||||||
|
|
||||||
|
- **One task per PR.** Task IDs are `T<wave>.<n>`. Reference the task ID and the item IDs in
|
||||||
|
the commit message and PR title.
|
||||||
|
- **Do not fix things you notice in passing.** The codebase has known problems documented as
|
||||||
|
S1 through S13, all scheduled. Fixing S6 while doing T3.2 makes the diff unreviewable and
|
||||||
|
breaks the wave ordering. Log it, move on.
|
||||||
|
- **Do not reorder waves.** The ordering is dependency-driven and documented in
|
||||||
|
`IMPLEMENTATION.md` section 4. Waves 1 through 4 are prerequisites: they produce almost no
|
||||||
|
visible change and every later wave assumes them.
|
||||||
|
- **Do not start a wave until the previous wave is merged**, unless the task explicitly says
|
||||||
|
it is independent.
|
||||||
|
|
||||||
|
## Frontend and backend boundary
|
||||||
|
|
||||||
|
The UX review that produced F1-F6 and S1-S13 covered `html/` only. Several change requests
|
||||||
|
need server work and will be silently half-built if you treat them as frontend-only:
|
||||||
|
|
||||||
|
| Item | Needs server work |
|
||||||
|
|---|---|
|
||||||
|
| CR-004, CR-018 | Structured location storage and aggregate endpoints. Not localStorage. |
|
||||||
|
| CR-007 | File upload, storage, and retrieval for drawing attachments. |
|
||||||
|
| CR-011, CR-014 | Outbound email and a durable link target per work package. |
|
||||||
|
| CR-013 | Material request persistence. |
|
||||||
|
| B4 | Aggregate endpoints replacing localStorage-derived counts. |
|
||||||
|
|
||||||
|
If a task touches one of these and you find yourself writing to `localStorage`, you are
|
||||||
|
building the wrong thing. Say so and stop.
|
||||||
|
|
||||||
|
## Things that must not change
|
||||||
|
|
||||||
|
These are recorded decisions, not oversights. Do not "clean them up":
|
||||||
|
|
||||||
|
- **Actual Hours stays in Closeout (CR-017).** Its removal was proposed and rejected.
|
||||||
|
- **Localization stays (A7).** `admin.js` language and time handling is a shipped feature.
|
||||||
|
- **Uppercase card headers in `console.css` stay (A5).** The sentence-case rule applies to
|
||||||
|
buttons and field labels only. The uppercase header idiom is deliberate.
|
||||||
|
- **The logged-override path for predecessors stays (A1).** It is an audited business rule,
|
||||||
|
not a bug. See `wp-creation-app.js:1962-1972`.
|
||||||
|
- **Removed fields are hidden, not deleted (CR-002, CR-016).** Retain the data and the model.
|
||||||
|
Removal is expressed through the CR-006 section toggles.
|
||||||
|
|
||||||
|
## The token rule
|
||||||
|
|
||||||
|
After wave 3 there is exactly one place a color, spacing or type value is defined. Page
|
||||||
|
stylesheets alias that source and declare nothing new.
|
||||||
|
|
||||||
|
Adding a raw hex value to a page stylesheet is a defect regardless of what the task asked
|
||||||
|
for. Four parallel token systems is what produced S5, and the `.field-hint` comment at
|
||||||
|
`work-package-suite-styles.css:336` is the bug that resulted. Do not recreate it.
|
||||||
|
|
||||||
|
## Accessibility is in scope
|
||||||
|
|
||||||
|
Approved Aug 14, 2026 (C1). Any component you rebuild ships accessible or it is not done:
|
||||||
|
|
||||||
|
- Interactive elements are `<button>`, `<a>`, or an input. Never a `<div>` with `onclick`.
|
||||||
|
There are currently 12 `<div>` and 2 `<span>` click handlers app-wide; do not add a 15th.
|
||||||
|
- Anything conveying instructions is reachable by keyboard and by touch. Hover-only is not
|
||||||
|
acceptable — Field View runs on tablets.
|
||||||
|
- Status changes and toasts announce through an `aria-live` region. `login.html` already does
|
||||||
|
this correctly with `role="alert"` and `role="status"`. Copy that pattern.
|
||||||
|
- Focus is always visible. Do not use `outline: none` without a replacement of at least equal
|
||||||
|
visibility.
|
||||||
|
- Text meets 4.5:1 against its background, 3:1 for large text.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
A task is not done because the code is written. Every task file lists its own done-when
|
||||||
|
checks. In addition, for any task touching the frontend:
|
||||||
|
|
||||||
|
1. Run the app locally: `uvicorn server.app:app` against a throwaway SQLite database.
|
||||||
|
2. Exercise the affected flow at **390px** and at **1440px**. Field View at 390px is the
|
||||||
|
gloved-hands surface and is where the worst rendering was found.
|
||||||
|
3. Capture before and after screenshots into the PR.
|
||||||
|
4. Run the existing smoke test. It signs in; `server/seed_demo.py` does not, which is S13.
|
||||||
|
|
||||||
|
If a done-when check cannot be verified, do not mark the task complete. Say which check
|
||||||
|
failed and why.
|
||||||
|
|
||||||
|
## Asking versus assuming
|
||||||
|
|
||||||
|
The four gating decisions are closed and recorded in `IMPLEMENTATION.md` section 2. Nothing
|
||||||
|
else in the spec is a decision waiting to be made.
|
||||||
|
|
||||||
|
Where a task says "confirm with Nick", that is a product question, not an implementation
|
||||||
|
blocker: build to the written acceptance criteria, and raise the question in the PR
|
||||||
|
description. Do not invent a different behavior because the written one seems incomplete.
|
||||||
163
IMPLEMENTATION.md
Normal file
163
IMPLEMENTATION.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# Work Package Suite — Implementation Plan
|
||||||
|
|
||||||
|
Derived from **Consolidated Change Request R2**, August 14, 2026.
|
||||||
|
Companion document for humans: `WorkPackageSuite_Consolidated_Change_Request_R2.docx`.
|
||||||
|
|
||||||
|
55 items, 9 waves, dependency-ordered. Read `CLAUDE.md` first.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Where this came from
|
||||||
|
|
||||||
|
Three inputs were merged to produce this plan:
|
||||||
|
|
||||||
|
| Source | Produced | IDs |
|
||||||
|
|---|---|---|
|
||||||
|
| 13 in-app feedback comments, Aug 14 2026 (01:11–01:32 PM) | Functional change requests | `CR-001`–`CR-018` |
|
||||||
|
| Micron EUV review meeting, Aug 14 2026 | Functional change requests and context | included above |
|
||||||
|
| UX review of `html/`, Aug 14 2026, branch `users/directory-super-user` | Rendering defects, structural findings, proposal assessment | `F1`–`F6`, `S1`–`S13`, `A1`–`A7`, `B1`–`B7`, `C1`–`C4` |
|
||||||
|
|
||||||
|
`F1`–`F6` were verified in a browser and are reproducible. `S1`–`S13` were read from source
|
||||||
|
and carry file and line references. `A`/`B`/`C` items assess a separately proposed UX change
|
||||||
|
list; their IDs are carried over unchanged so the two documents line up.
|
||||||
|
|
||||||
|
## 2. Decisions (all closed)
|
||||||
|
|
||||||
|
Approved by Nick Siegfried, August 14 2026. Nothing in this plan is blocked pending a
|
||||||
|
decision. Do not reopen these without a spec revision.
|
||||||
|
|
||||||
|
| ID | Decision |
|
||||||
|
|---|---|
|
||||||
|
| `CR-009` | **Keep and extend Kitting.** Build `CR-010`, `CR-011`, `CR-012`. Ship it toggled **off** for the Micron EUV SOP via the `CR-006` section toggles. Kitting is not happening at Micron today; the team expects to get there. |
|
||||||
|
| `CR-013` | **Build the lightweight material request.** Line items (description, quantity, unit), needed-by date, requestor, delivery location, status. **Defer** the parts catalog, live inventory, and warehouse integration. Sequence after the creator has real section structure (see `X6`). |
|
||||||
|
| `B7` | **Dissolve the creator iframe.** Scheduled as `T7.1`, the first task of wave 7. This is the largest engineering item in the plan and most of wave 7 depends on it. |
|
||||||
|
| `C1` | **Accessibility is in scope.** Fold it into components already being rebuilt rather than treating it as a separate pass. Rules are in `CLAUDE.md`. |
|
||||||
|
|
||||||
|
> If the `B7` decision was meant as "schedule the decision" rather than "dissolve the
|
||||||
|
> iframe", that is the one line in this plan to correct before wave 7 starts. Everything
|
||||||
|
> before wave 7 is unaffected either way.
|
||||||
|
|
||||||
|
## 3. Cross-track dependencies
|
||||||
|
|
||||||
|
These are the reason the wave order is what it is. Each row is a change request that cannot
|
||||||
|
be built as written, or cannot be built once, until something else lands.
|
||||||
|
|
||||||
|
| ID | Item | Depends on | Type | Why |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `X1` | `CR-011`, `CR-014` | `S3` | **Blocking** | Both promise an email containing a direct link to the work package. There is no `pushState` anywhere in the app, so no work package has an addressable URL. The emails cannot be built until URL state exists. |
|
||||||
|
| `X2` | `CR-015` | `A1` | **Blocking** | The hold-not-clearing bug and the transition model are the same code. `wp-creation-app.js:1962-1972` shows a deliberate logged-override path, so hold state is not purely derived from open constraints. Fixing them separately means fixing it twice. |
|
||||||
|
| `X3` | `CR-014` | `A1` | Sequencing | `Ready for QA` is a new state and must land inside the guarded transition model, not beside it. |
|
||||||
|
| `X4` | `CR-006` | `B7` | Sequencing | Section toggles must suppress sections inside the creator, which is an iframe child until `T7.1`. |
|
||||||
|
| `X5` | `CR-004`, `CR-018` | `B4` | **Blocking** | Rollup by building, floor and sector cannot come from `localStorage`. Same data dependency that blocks the pipeline strip. |
|
||||||
|
| `X6` | `CR-013` | `F6`, `A4` | Sequencing | A material request card is a 12th card on a form already ~4,700px tall. Build it after the form has section structure. |
|
||||||
|
| `X7` | `CR-003` | `C3` | Sequencing | Priority color coding needs one source of truth for color, or Normal/High/Urgent get four implementations. |
|
||||||
|
| `X8` | `CR-007` | `F2`, `S2` | **Blocking** | Offline drawing access is a tablet feature and the app bar breaks at 390px. Uploading into a form with no autosave risks losing the upload. |
|
||||||
|
| `X9` | `CR-005` | `A4`, `F5`, `S9` | Sequencing | A new wizard step should be built during the stepper rebuild, with the read-only-looking fields and keyboard access fixed at the same time. |
|
||||||
|
| `X10` | `CR-002`, `CR-016` | `CR-006`, `C3` | Sequencing | Both removals are expressed as toggles, not deletions. Without token consolidation the toggled styling drifts. |
|
||||||
|
|
||||||
|
## 4. Wave order
|
||||||
|
|
||||||
|
| Wave | Focus | File | Items |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 0 | Orientation and file map | `docs/waves/wave-0.md` | — |
|
||||||
|
| 1 | Rendering defects and tooling | `docs/waves/wave-1.md` | `F1` `F3` `F4` `F5`(interim) `S13` |
|
||||||
|
| 2 | Drawer everywhere, flat strip deleted | `docs/waves/wave-2.md` | `B1` `S4` `F2` |
|
||||||
|
| 3 | Token consolidation and button system | `docs/waves/wave-3.md` | `C3` `S5` `A3` `A5` |
|
||||||
|
| 4 | Platform prerequisites | `docs/waves/wave-4.md` | `B4` `S3` `S2` `B5` `S10` `S11` `S12` |
|
||||||
|
| 5 | Launcher and SOP wizard | `docs/waves/wave-5.md` | `A4` `B3` `S9` `CR-005` `CR-006` `CR-002` `CR-016` `S1`(wizard) |
|
||||||
|
| 6 | Work package general information | `docs/waves/wave-6.md` | `CR-001` `CR-003` `CR-004` `CR-018` `A7` |
|
||||||
|
| 7 | The creator | `docs/waves/wave-7.md` | `B7` `A1` `CR-015` `A2` `A6` `CR-014` `CR-007` `B6` `S1`(creator) `F6` |
|
||||||
|
| 8 | Kitting and material | `docs/waves/wave-8.md` | `CR-009` `CR-010` `CR-011` `CR-012` `CR-013` |
|
||||||
|
| 9 | Verification and cleanup | `docs/waves/wave-9.md` | `CR-008` `CR-017` `S6` `S7` `C1` `C2` `C4` |
|
||||||
|
|
||||||
|
**Waves 1 through 4 produce almost no field-visible change.** That is deliberate and it is
|
||||||
|
roughly the first third of the effort. It is called out here because the Micron team is
|
||||||
|
already skeptical about time spent, and silence during these waves reads as nothing
|
||||||
|
happening. The trade is that waves 5 through 8 land once instead of being rebuilt, which is
|
||||||
|
the failure mode the review documented at `work-package-suite-styles.css:336`.
|
||||||
|
|
||||||
|
### Deltas from the R2 sequence
|
||||||
|
|
||||||
|
The R2 document's nine-wave table did not place `A5`, `A7`, or `F6`. This plan places `A5`
|
||||||
|
in wave 3 (it depends on token consolidation), `A7` in wave 6 (it is general-information
|
||||||
|
surface work), and `F6` in wave 7 (its actual fix is section tabs, not a CSS change). `F2`
|
||||||
|
moves fully to wave 2 because `B1` resolves it; wave 1 only stops the clipping.
|
||||||
|
|
||||||
|
## 5. Task format
|
||||||
|
|
||||||
|
Every task in a wave file follows this shape. Do not start a task that is missing a
|
||||||
|
done-when list; flag it instead.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### T5.4 — CR-005: Upload location lists at SOP setup
|
||||||
|
|
||||||
|
- **Items:** CR-005
|
||||||
|
- **Depends on:** T5.1
|
||||||
|
- **Blocks:** T6.3
|
||||||
|
- **Surface:** html/ + server/
|
||||||
|
- **Files:** <paths from docs/reference/file-map.md>
|
||||||
|
- **Do:** ...
|
||||||
|
- **Do not:** ...
|
||||||
|
- **Done when:**
|
||||||
|
- [ ] verifiable check
|
||||||
|
- [ ] verifiable check
|
||||||
|
```
|
||||||
|
|
||||||
|
`Done when` entries must be checkable by running or looking at something. "Confirm with
|
||||||
|
Nick" is never a done-when; it goes in the PR description.
|
||||||
|
|
||||||
|
## 6. Traceability
|
||||||
|
|
||||||
|
Every one of the 55 items appears in exactly one wave, except where noted.
|
||||||
|
|
||||||
|
| Item | Wave | Item | Wave | Item | Wave |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| CR-001 | 6 | F1 | 1 | A1 | 7 |
|
||||||
|
| CR-002 | 5 | F2 | 1 interim, 2 full | A2 | 7 |
|
||||||
|
| CR-003 | 6 | F3 | 1 | A3 | 1 interim, 3 full |
|
||||||
|
| CR-004 | 6 | F4 | 1 | A4 | 5 |
|
||||||
|
| CR-005 | 5 | F5 | 1 interim, 3 full | A5 | 3 |
|
||||||
|
| CR-006 | 5 | F6 | 7 | A6 | 7 |
|
||||||
|
| CR-007 | 7 | S1 | 5 wizard, 7 creator | A7 | 6 |
|
||||||
|
| CR-008 | 9 | S2 | 4 | B1 | 2 |
|
||||||
|
| CR-009 | 8 | S3 | 4 | B2 | 2 |
|
||||||
|
| CR-010 | 8 | S4 | 2 | B3 | 5 |
|
||||||
|
| CR-011 | 8 | S5 | 3 | B4 | 4 |
|
||||||
|
| CR-012 | 8 | S6 | 9 | B5 | 4 |
|
||||||
|
| CR-013 | 8 | S7 | 9 | B6 | 7 |
|
||||||
|
| CR-014 | 7 | S8 | 9 | B7 | 7 |
|
||||||
|
| CR-015 | 7 | S9 | 5 | C1 | all, audited in 9 |
|
||||||
|
| CR-016 | 5 | S10 | 4 | C2 | all, audited in 9 |
|
||||||
|
| CR-017 | 9 (guard only) | S11 | 4 | C3 | 3 |
|
||||||
|
| CR-018 | 6 | S12 | 4 | C4 | 4 and 9 |
|
||||||
|
| | | S13 | 1 | | |
|
||||||
|
|
||||||
|
`F5` and `A3` are the same defect from two sources. `C1` and `C2` are standing requirements
|
||||||
|
enforced per task under `CLAUDE.md`, with a dedicated audit in wave 9. `CR-017` is a
|
||||||
|
do-not-remove guard rather than a build.
|
||||||
|
|
||||||
|
## 7. Out of scope
|
||||||
|
|
||||||
|
Deferred by decision. Do not build these, and do not treat them as gaps:
|
||||||
|
|
||||||
|
- Full material request and inventory system, including the parts catalog and warehouse
|
||||||
|
integration. Revisit once Paul Coonrod is engaged.
|
||||||
|
- Asset database integration. Clinton's team owns that database; the Assets section is
|
||||||
|
toggled off in the interim (`CR-016`).
|
||||||
|
- CxAlloy or GC QA system integration. The QA gate is notification-only until CxAlloy lands.
|
||||||
|
- P6 activity list import and validated lookup. `CR-001` uses free text.
|
||||||
|
|
||||||
|
## 8. Inputs the plan is waiting on
|
||||||
|
|
||||||
|
These do not block code, but they block the data that makes several features real. Track
|
||||||
|
them; do not invent placeholder values in their absence.
|
||||||
|
|
||||||
|
| Input | Owner | Blocks |
|
||||||
|
|---|---|---|
|
||||||
|
| B100 floor and area list | David Leal | `CR-004`, `CR-005` real data |
|
||||||
|
| Material spreadsheet | Nate, via David Leal | `CR-013` field set |
|
||||||
|
| Master material workbook, preferred request format | Paul Coonrod | `CR-013` scope |
|
||||||
|
| QA process of record (Excel questionnaire moving into CxAlloy) | David Ramstorf, Lupe, Cody Schaefer | `CR-014` beyond notification |
|
||||||
|
|
||||||
|
Where a list is required and not yet supplied, build the upload path (`CR-005`) and seed with
|
||||||
|
an obviously-fake sample. Do not hardcode guessed floor names.
|
||||||
120
UX-REVIEW-2026-08-14.md
Normal file
120
UX-REVIEW-2026-08-14.md
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
# UX Review — Work Package Suite
|
||||||
|
|
||||||
|
**Date:** 2026-08-14 · **Branch:** `users/directory-super-user` · **Scope:** `html/` — 6 pages, 4 stylesheets, ~11.9k lines
|
||||||
|
|
||||||
|
Full write-up with screenshots: <https://claude.ai/code/artifact/09d89aa1-54b9-41db-9e09-e1fc8fb55852>
|
||||||
|
|
||||||
|
**Method.** Two passes. A full read of the frontend, then the app run locally
|
||||||
|
(`uvicorn server.app:app`, throwaway SQLite DB) and driven in Chrome through the real
|
||||||
|
first-run flow: sign in → create project → SOP wizard → creator → directory → field view
|
||||||
|
at 390px. Section 1 below is browser-verified; section 2 is read from source.
|
||||||
|
|
||||||
|
> Incidental find: `server/seed_demo.py` no longer authenticates, so it can't seed a
|
||||||
|
> running instance — every `/api/` route requires a session and the script sends none.
|
||||||
|
> It predates the commit that taught the smoke test to sign in.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Rendering defects (browser-verified, reproducible today)
|
||||||
|
|
||||||
|
No design decisions needed for any of these.
|
||||||
|
|
||||||
|
| # | Defect | Severity |
|
||||||
|
|---|---|---|
|
||||||
|
| F1 | **Header project switcher is stale on every page.** Hero, picker and create-user card show the active project; the app bar still reads "Select a project". Two sources of truth, global one loses. | High |
|
||||||
|
| F2 | **App bar breaks at 390px — on Field View.** Nav wraps to 3 rows and clips: "Sign out" cut in half, search truncated. This is the gloved-hands surface. | High |
|
||||||
|
| F3 | **Logo/project-name collision in the SOP header.** `.header-left` and the injected chrome fight for the same run of the bar. | Medium |
|
||||||
|
| F4 | **Comments drawer renders off-screen over the header** in the standalone creator. | Medium |
|
||||||
|
| F5 | **SOP wizard fields read as read-only** — `#f4f4f4` fill, `#e0e0e0` border. Cause: the wizard redeclares its own tokens and never sees `--cds-field: #ffffff`. | Medium |
|
||||||
|
| F6 | **The creator is one ~4,700px form** — 11 cards rendered at once, jump links standing in for structure. | Medium |
|
||||||
|
|
||||||
|
F1 and F2 are prerequisites for the proposed chrome work.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Structural findings (from source)
|
||||||
|
|
||||||
|
### Costs users work
|
||||||
|
- **Validation is `alert()`-only, covering 3 of 10 wizard steps.** 79 native dialogs app-wide,
|
||||||
|
43 in the creator. `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.
|
||||||
|
`validateStep` guards only steps 1, 5, 6 while the markup marks required fields throughout.
|
||||||
|
- **No autosave, no unsaved-work guard.** The only `beforeunload` listener is analytics dwell
|
||||||
|
tracking (`work-package-suite-app.js:326`).
|
||||||
|
- **Nothing is linkable.** No `pushState` anywhere. Tab switches, dashboard views and package
|
||||||
|
selections change no URL — can't send someone a link to WP07; refresh loses your place.
|
||||||
|
- **No global nav on the two pages people live in.** Drawer + app bar ship on `admin`, `field`,
|
||||||
|
`users`. The SOP wizard has its own header and no drawer; the creator has neither, plus a
|
||||||
|
different brand treatment (mono wordmark vs. logo chip).
|
||||||
|
|
||||||
|
### Costs consistency
|
||||||
|
- **Four parallel token systems.** `#0f62fe` is declared 4× (`--cds-interactive-01`, `--primary`,
|
||||||
|
`--accent` twice). Already caused a bug — see the comment at
|
||||||
|
`work-package-suite-styles.css:336` about `.field-hint` rendering unstyled.
|
||||||
|
- **Icon set is mixed emoji + dingbats** (⤓ ⤒ 👁 ★ 📊 ⧉ 🕘 💬 ▤ ⚙ 🔒 ⚡ ⎙ ◔ ▦). `▤` is used for
|
||||||
|
two different things on the same page.
|
||||||
|
- **Four sample-data affordances under three names.** One sits a click from live project data
|
||||||
|
with no confirm and no undo.
|
||||||
|
|
||||||
|
### Costs accessibility (and the field case)
|
||||||
|
- **Hover-only tooltips carry load-bearing instructions.** 15 `.help-tip` badges, `<span>`s with
|
||||||
|
no `tabindex` — so the `:focus` half of their CSS rule is dead code and there's no touch path.
|
||||||
|
- **SOP step rail not keyboard-reachable.** All 10 steps are `<div onclick>`; 12 `<div>` + 2
|
||||||
|
`<span>` click handlers app-wide.
|
||||||
|
- **Zero `aria-live` regions.** Both toast systems and every admin banner announce nothing.
|
||||||
|
`login.html` gets this right with `role="alert"`/`role="status"`; the pattern never spread.
|
||||||
|
- **Helper text at ~2.9:1** (`--text-dim: #8d8d8d` at 12px). `console.css:85-87` already
|
||||||
|
diagnosed and fixed this; the other two sheets didn't follow.
|
||||||
|
- **Wizard removes the focus ring** — `outline: none` plus a pale 3px glow
|
||||||
|
(`work-package-suite-styles.css:322-328`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Assessment of the proposed change list
|
||||||
|
|
||||||
|
Strong work — nearly every item maps to something verifiable, and two rank above anything in
|
||||||
|
this review's own findings. 9 endorsed, 7 need adjustment, 6 gaps.
|
||||||
|
|
||||||
|
### Endorse as proposed
|
||||||
|
| ID | Item | Note |
|
||||||
|
|---|---|---|
|
||||||
|
| A1 | **Guarded status transitions** | Best item on the list. But: Issue (Hold) is a *branch* from several states, and there's a deliberate **logged-override** path for predecessors (`wp-creation-app.js:1962-1972`). "One legal next action" is too narrow — model as primary-next **+ audited override**. |
|
||||||
|
| A2 | De-duplicate constraint warning | Triplication confirmed. Caveat: the top banner is the only one visible without scrolling, so the tab count badge must carry that weight. |
|
||||||
|
| A3 | Fields that look editable | Confirmed (F5). Pair with token consolidation or it drifts back. |
|
||||||
|
| A4 | Vertical stepper + progress | Also retires the orphaned "1 / 10" counter. Make the steps real `<button>`s while rebuilding. |
|
||||||
|
| A5 | One button system, no green/blue mix | Real: green `Save & View` + green `SOP Complete` vs blue elsewhere. **Scope "sentence case" to buttons/field labels** — the uppercase card-header idiom in `console.css` is deliberate and works. |
|
||||||
|
| A6 | Sidebar triage data + inline hold reason | Cheap — hold reason is already captured by the hold modal. |
|
||||||
|
| A7 | Card status lines · footer clarity · Language & time | Localization is a real shipped feature (`admin.js:484-517`), so keeping it is correct. |
|
||||||
|
|
||||||
|
### Right diagnosis, adjust the prescription
|
||||||
|
| ID | Item | Adjustment |
|
||||||
|
|---|---|---|
|
||||||
|
| B1 | Collapse the 8-item nav | **Don't build a new avatar menu — ship the drawer you already have.** It's the best chrome in the app and already holds the whole nav; it's just on 3 pages of 6 while a flat strip duplicates it. Put it everywhere, delete the strip. Fixes F2. |
|
||||||
|
| B2 | Un-truncate the switcher | Fix **correctness (F1) first**. "Micron EUV Cleanroom Enable · 2667008" won't fit 280px, and existing rules narrow it to 150px under 900px — needs a breakpoint plan. |
|
||||||
|
| B3 | Remove the project-picker card | The first-run empty state lives *inside* that card. A header dropdown is the wrong home for "create your first project" — the launcher needs an explicit empty state. |
|
||||||
|
| B4 | 4-cell pipeline strip | Hard data dependency: launcher SOP status reads `localStorage`, and the creator's dashboard admits it "reads local data now; wires to SQL in Phase 2". Per-browser numbers that look authoritative are worse than none. **Server aggregates first.** |
|
||||||
|
| B5 | Autosave status text | Must ship with **actual autosave + dirty guard**. A "✓ All changes saved" toast already appears (that's the sync outbox, not your draft), so the app arguably implies this today. |
|
||||||
|
| B6 | Wizard actions beside the fields | On Constraints/Sequence steps that means scrolling to save. **Prefer sticky** — the creator's sticky save bar already solves it. |
|
||||||
|
| B7 | Toolbar into the tab row | Unstated prerequisite: tab row is in the parent, toolbar in the iframe child. This **requires dissolving the iframe** — the largest engineering item on the list. Name and schedule it. |
|
||||||
|
|
||||||
|
### Not addressed
|
||||||
|
| ID | Gap |
|
||||||
|
|---|---|
|
||||||
|
| C1 | **Accessibility** — and the redesign touches every broken part. The step rail being rebuilt is 10 `<div onclick>`s; the status pills being replaced are the moment for a real radio group; the tooltips are unreachable on the tablet Field View targets. Skipping these means paying for the same components twice. |
|
||||||
|
| C2 | **Mobile** — no item on the list, and it's where the worst rendering is (F2). |
|
||||||
|
| C3 | **Token consolidation** — without it, "one button system" gets implemented four times and drifts, exactly as `.field-hint` did. |
|
||||||
|
| C4 | **URL state · icon system · unsaved-changes guard · sample-data sprawl** — none addressed. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Recommended sequence
|
||||||
|
|
||||||
|
Ordered by dependency, not preference.
|
||||||
|
|
||||||
|
1. **The six rendering defects.** No design decisions; F1/F2 unblock the chrome work.
|
||||||
|
2. **Drawer everywhere, flat strip deleted.** Reuses the best existing component, fixes phone-width collapse, settles global nav before anything is redrawn.
|
||||||
|
3. **Token consolidation.** One source of truth, page sheets aliasing to it. Every later visual item lands once instead of four times.
|
||||||
|
4. **Launcher + SOP wizard.** Pipeline strip (after server aggregates), empty-state ownership, vertical stepper, editable fields, autosave + guard. Make the 10 steps buttons while rebuilding.
|
||||||
|
5. **The creator.** Guarded transitions, de-duplicated warnings, section tabs, triage data. **Decide the iframe question up front** — most of this depends on it.
|
||||||
|
|
||||||
|
**Dependencies:** B1 resolves F2 · B2 depends on F1 · A3 depends on C3 · B7 gates most of step 5.
|
||||||
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