First field-visible wave. Waves 1-4 moved almost nothing on screen; every page in this one looks different. Baseline counts, against wave 0 <div onclick> 12 -> 2 (T5.1 took exactly ten) native dialogs app-wide 79 -> 64 (T5.1 2, T5.2 1, T5.8 13) ...in the SOP wizard 14 -> 0 ...in the creator 43 -> 43 wave 7's colour literals outside theme-light.css 0 -> 0, held SOP wizard steps 10 -> 12 (T5.4 Locations, T5.5 Sections) Six probes now cover this wave, 399 checks between them, each written because its task's done-when could not be checked by anything that already existed. Screenshots re-captured at 390 and 1440 across all seven pages. One overflow, the known creator@390 (BL-001), unchanged. The two beforeunload log lines on sop@1440 and creator@1440 are present at wave 4 too - captured both sides during T5.1 rather than assuming. BL-010 is honestly unchanged: every rule wave 5 added consumes --wp-s*, and none of the 829 pre-existing spacing/type/radius literals were converted, because none of the pages carrying them were re-laid-out here. T7.1 still owns it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
311 lines
13 KiB
Markdown
311 lines
13 KiB
Markdown
# 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
|
||
|
||
- [x] the stepper is keyboard operable and `<div onclick>` count dropped by at least 10
|
||
— **12 → 2**, exactly ten, and the two survivors are wave 7's and wave 9's
|
||
- [x] section toggles work end to end, including the export
|
||
- [x] Acumatica fields and Assets are hidden by configuration, with no data deleted
|
||
- [x] the wizard has no `alert()` calls left — **0**, raw and comment-stripped
|
||
- [x] first-run users can create a project
|
||
|
||
---
|
||
|
||
## Wave 5 exit — what shipped, and what it cost
|
||
|
||
First field-visible wave. Everything before this was prerequisites, and the difference
|
||
shows: waves 1–4 moved almost nothing on screen, and every page in this one looks
|
||
different.
|
||
|
||
### The tasks
|
||
|
||
| Task | Items | What landed |
|
||
|---|---|---|
|
||
| `T5.1` | `A4` `S9` | Vertical stepper, ten real `<button>`s, keyboard operable, states in words |
|
||
| `T5.2` | `B3` | First-run empty state, then the picker card removed; switching moved to the app bar |
|
||
| `T5.3` | `B4` UI | Four-cell pipeline strip, every number from the server, every cell a shareable link |
|
||
| `T5.4` | `CR-005` | Per-project Building / Floor / Sector taxonomy — new table, four routes, step 11 |
|
||
| `T5.5` | `CR-006` | Section toggles, shared registry, form + detail view + export |
|
||
| `T5.6` | `CR-002` | Acumatica cost code and task, hidden by field toggle |
|
||
| `T5.7` | `CR-016` | Assets off for Micron EUV, by configuration |
|
||
| `T5.8` | `S1` wizard | Inline validation on five steps; thirteen native dialogs retired |
|
||
|
||
### Baseline counts
|
||
|
||
| Metric | Wave 0 | End of wave 5 | Moved by |
|
||
|---|---|---|---|
|
||
| `<div onclick>` | 12 | **2** | `T5.1` |
|
||
| native dialogs app-wide | 79 | **64** | `T5.1` (2), `T5.2` (1), `T5.8` (13) |
|
||
| …of those, in the SOP wizard | 14 | **0** | `T5.8` |
|
||
| …of those, in the creator | 43 | 43 | wave 7 |
|
||
| colour literals outside `theme-light.css` | 0 | **0** | held |
|
||
| SOP wizard steps | 10 | **12** | `T5.4`, `T5.5` |
|
||
|
||
### Probes added
|
||
|
||
Five, each written because its task's done-when could not be checked by anything that
|
||
already existed. Run them **one at a time**.
|
||
|
||
```bash
|
||
python tests/stepper_check.py # A4/S9 71 checks
|
||
python tests/launcher_check.py # B3 58 checks (two seeded databases)
|
||
python tests/pipeline_check.py # B4 UI 43 checks
|
||
python tests/locations_check.py # CR-005 58 checks
|
||
python tests/sections_check.py # CR-006/CR-002/CR-016 88 checks
|
||
python tests/validation_check.py # S1 81 checks
|
||
```
|
||
|
||
### The four things the probes caught that a review would not have
|
||
|
||
1. **`T5.1`** — the rail did not track the form. Fill step 1 and every step ahead stayed
|
||
padlocked until you navigated. A rail that lies about the form is worse than the strip
|
||
it replaced, because that one at least lied consistently.
|
||
2. **`T5.2`** — `f_items.py`'s `F1` went `INCONCLUSIVE`, not `FAIL`. Its probe drove the
|
||
picker card's `<select>`, which `B3` deleted. It refused to guess, which is the
|
||
behaviour `f_items` exists for.
|
||
3. **`T5.3`** — a pipeline link landed on "complete the SOP first". Not the strip's fault:
|
||
`browser_check`'s fixture stores a SOP shape production never writes. Logged as BL-018.
|
||
4. **`T5.6`** — a probe reported the cost code being eaten by a section toggle. It was not;
|
||
the probe used an invented code and `wp_cost` is a `<select>` that silently drops an
|
||
unknown value. That silent drop is real, is not this wave's, and is BL-019.
|
||
|
||
### Open, carried into wave 6 and beyond
|
||
|
||
- **BL-010** (raw spacing and type values) is **unchanged**. Every rule wave 5 added
|
||
consumes `--wp-s*`; none of the 483/281/65 pre-existing literals were converted, because
|
||
none of the pages carrying them were re-laid-out here. `T7.1` still owns it.
|
||
- **X4** is resolved rather than deferred — see `T5.5`'s commit. The SOP-borne propagation
|
||
path is unaffected by `B7`; the live hand-off across the frame is what `T7.1` removes.
|
||
- **BL-018** (the WP tab's gate is the last `localStorage`-derived status) is the one
|
||
finding in this wave that is a real user-facing weakness rather than a test artefact.
|