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:
2026-08-14 17:42:56 -05:00
parent 9459e76a6c
commit 3d99d4b9d0
14 changed files with 2254 additions and 0 deletions

297
docs/waves/wave-7.md Normal file
View 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