diff --git a/CLAUDE.md b/CLAUDE.md index f5ae7f8..0e1c631 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,13 +5,15 @@ any task, and read the wave file for the task you are on. Do not work from this ## 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 +Every change traces to an item ID (`CR-001`, `F1`, `S1`, `A1`, `B1`, `C1`, `D1`). 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. +this repo that other people are reading. New scope decided mid-build gets a **new** ID rather +than a widened old one - that is what the `D` prefix is for. See +`docs/waves/decisions-2026-08-18.md`. ## Scope discipline @@ -51,7 +53,11 @@ These are recorded decisions, not oversights. Do not "clean them up": - **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`. + not a bug. It is `confirmEarlyRelease()` in `wp-creation-app.js`, called from the issue and + release paths. Named by function, not by line: this file and `IMPLEMENTATION.md` X2 both + cited `wp-creation-app.js:1962-1972` until Aug 18 2026, and those lines are + `deletePackage()`/`clearSaved()` - a different rule entirely. Corrected before T7.3, which + is the task told not to remove it. - **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. diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index 7f09fa8..f12226e 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -5,6 +5,9 @@ Companion document for humans: `WorkPackageSuite_Consolidated_Change_Request_R2. 55 items, 9 waves, dependency-ordered. Read `CLAUDE.md` first. +Ten further items (`D1`-`D10`) were decided on August 18 2026 and are recorded in +`docs/waves/decisions-2026-08-18.md`. 65 items total. + --- ## 1. Where this came from @@ -33,9 +36,26 @@ decision. Do not reopen these without a spec revision. | `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. +> `B7` was confirmed as "dissolve the iframe" on August 14 2026 and again at the wave 7 +> handoff. It is not a scheduling decision. + +**A second set of decisions closed on August 18 2026**, at the wave 6 exit, in answer to +twenty-one questions and eleven follow-ups. They are recorded in +`docs/waves/decisions-2026-08-18.md` as `D1`-`D10`. They add three tasks and amend +acceptance criteria on seven others; they do not reopen anything above. + +| ID | Decision | Amends | +|---|---|---| +| `D1` | Sample data returns to the creator, visible on the unframed page | `B7`, `S7` | +| `D2` | The QA distribution list is configured in the SOP, not per work package | `CR-014` | +| `D3` | The creator stays one page: side navigation plus collapsible sections | `F6` | +| `D4` | `Urgent` surfaces the audited override; it does not bypass the constraint gate | `CR-003`, `A1` | +| `D5` | Usage data moves to the admin console | `B7` | +| `D6` | The material list uploads at SOP configuration | `CR-013` | +| `D7` | Archived projects are readable, by project admins only | `B3`, `C1` | +| `D8` | 5MB a file, 2GB a project, PDFs and images, stored in the same database | `CR-007` | +| `D9` | `Ready for QA` appears in Field View | `CR-014` | +| `D10` | Email is switched on and off from the admin console | `CR-011`, `CR-014` | ## 3. Cross-track dependencies @@ -45,7 +65,7 @@ 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. | +| `X2` | `CR-015` | `A1` | **Blocking** | The hold-not-clearing bug and the transition model are the same code. `confirmEarlyRelease()` in `wp-creation-app.js` is a deliberate logged-override path, so hold state is not purely derived from open constraints. Fixing them separately means fixing it twice. **Corrected Aug 18 2026:** this row and `CLAUDE.md` both cited `wp-creation-app.js:1962-1972`, which is `deletePackage()`/`clearSaved()`. The override path is `confirmEarlyRelease()`, called from the issue and release paths. Named by function so it survives the `T7.1` rewrite. | | `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. | @@ -66,9 +86,9 @@ be built as written, or cannot be built once, until something else lands. | 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` | +| 7 | The creator | `docs/waves/wave-7.md` | `B7` `A1` `CR-015` `A2` `A6` `CR-014` `CR-007` `B6` `S1`(creator) `F6` `D1` `D2` `D3` `D4` `D5` `D8` `D9` `D10` | +| 8 | Kitting and material | `docs/waves/wave-8.md` | `CR-009` `CR-010` `CR-011` `CR-012` `CR-013` `D6` `D10` | +| 9 | Verification and cleanup | `docs/waves/wave-9.md` | `CR-008` `CR-017` `S6` `S7` `C1` `C2` `C4` `D7` | **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 @@ -132,6 +152,19 @@ Every one of the 55 items appears in exactly one wave, except where noted. | CR-018 | 6 | S12 | 4 | C4 | 4 and 9 | | | | S13 | 1 | | | +### The August 18 items + +| Item | Wave | Task | Item | Wave | Task | +|---|---|---|---|---|---| +| D1 | 7 | T7.1 | D6 | 8 | T8.6 | +| D2 | 7 | T7.6 | D7 | 9 | T9.8 | +| D3 | 7 | T7.2 | D8 | 7 | T7.7 | +| D4 | 7 | T7.3 | D9 | 7 | T7.6 | +| D5 | 7 | T7.10 | D10 | 7 and 8 | T7.6, T8.3 | + +That is 65 items across 9 waves. `D10` is the only one split across two waves: the gate and +its console control are built once at `T7.6` and reused by `T8.3`. + `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. @@ -161,3 +194,11 @@ them; do not invent placeholder values in their absence. 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. + +**Status, August 18 2026.** None of the four has arrived. Confirmed at the wave 6 exit that +this does not change the plan: `D6` extends the `CR-005` upload pattern to the material list +so `CR-013` is buildable without Nate's spreadsheet, and the B100 list is still expected +through the same door. Because no real list has ever been loaded, every location on record +is sample data - which is why the free-text migration question was closed without work +(`decisions-2026-08-18.md`, "Closed without work"). That answer does not survive the first +real project. diff --git a/docs/waves/decisions-2026-08-18.md b/docs/waves/decisions-2026-08-18.md new file mode 100644 index 0000000..b10a283 --- /dev/null +++ b/docs/waves/decisions-2026-08-18.md @@ -0,0 +1,273 @@ +# Decisions — August 18, 2026 + +Approved by Nick Siegfried during wave 7 planning, in answer to twenty-one questions raised +at the wave 6 exit and eleven follow-ups. + +These are **new items**, not reinterpretations of existing ones. `CLAUDE.md` forbids +renumbering or reinterpreting `CR`/`F`/`S`/`A`/`B`/`C` IDs because they are referenced in +documents outside this repo, so everything decided here gets its own `D` prefix and each +entry names the existing item it amends. Where a `D` item changes an acceptance criterion, +the original criterion is quoted and the replacement is stated, so a reader of the R2 +document can see exactly what moved. + +Ten items. Seven are new build work; three amend criteria on work already scheduled. + +--- + +## D1 — Sample data returns to the creator + +- **Amends:** `B7` (`T7.1`), `S7` (`T9.4`) +- **Surface:** `html/` + +`wp-creation-styles.css` opens with `body.embedded .embed-hide { display: none }` — framed, +the creator hides its own header, its sample-data controls and its analytics button. `T7.1` +dissolves the frame, so "framed" stops being a state and those three controls need a home or +a deletion. Decided: **the sample-data control comes back and is visible.** + +That collides with `S7`, which reduces four sample-data affordances under three names to one. +It is not a contradiction: `S7`'s complaint is that there are four of them, that they are +named inconsistently, and that one sits a click from live project data. A single, clearly +named, confirmed affordance on the creator satisfies both. `T9.4` owns making it the only +one; `T7.1` owns making it visible. + +**Done when:** the creator's sample-data control is reachable on the unframed page, and +`T9.4` still ends with exactly one affordance app-wide. + +--- + +## D2 — The QA distribution list is configured in the SOP + +- **Amends:** `CR-014` (`T7.6`) +- **Surface:** `server/` + `html/` + +`CR-014` says entering `Ready for QA` "emails the assigned QA representative and the QA/QC +members named on the work package". Asked who should receive it, the answer was **the QA +group only, and the group is set up once during SOP configuration as a dropdown** — not typed +per work package. + +That makes the recipient list SOP configuration, which means a wizard field, which means +`T7.6` acquires a dependency on the wave 5 SOP wizard it did not have. + +Rejection routing was also settled: **a rejection notifies the work package owner and the +distribution list**, not only the person who submitted it. + +**Replaces the `CR-014` done-when** "entering it sends email to the QA rep and named QA/QC +members" with: + +- the QA distribution list is chosen in the SOP wizard from project members +- entering `Ready for QA` emails that list and nobody else +- rejection emails the work package owner and the same list + +--- + +## D3 — The creator stays one page: side navigation plus collapsible sections + +- **Amends:** `F6` (`T7.2`) +- **Surface:** `html/` + +`T7.2` as written says "section tabs or an equivalent that shows one coherent group at a +time", with the done-when "no single view exceeds roughly two screen heights at 1440px". +Asked to choose, the answer was **one long form with navigation down the side** — and then, +when the height conflict was raised, the decision was delegated: *"do what you recommend is +best to UX."* + +**Recommended and adopted:** one page, persistent side navigation, and each section +collapsible with only the current one open by default, plus an `Expand all` control for +people who would rather scroll straight through. Tabs were rejected because they hide +sections a first-time author does not know exist; an uncollapsed long form was rejected +because it is the ~4,700px page `F6` exists to fix. + +**Replaces the `F6` done-when** "no single view exceeds roughly two screen heights at 1440px" +with "no single view exceeds roughly two screen heights at 1440px **at rest**" — that is, +with the default collapse state, which is the state the page is actually in when it loads. +Expanding everything deliberately is allowed to exceed it. + +**Replaces** "toggled-off sections have no tab" with "toggled-off sections have no entry in +the side navigation", and "tabs are keyboard operable and follow the tab pattern with +`aria-selected` and arrow keys" with "the side navigation is keyboard operable, marks the +current section with `aria-current`, and each section header is a real disclosure button with +`aria-expanded`". + +--- + +## D4 — Urgent surfaces the audited override; it does not bypass the gate + +- **Amends:** `CR-003` (`T6.2`, shipped) and `A1` (`T7.3`) +- **Surface:** `html/` + +Asked whether an `Urgent` package should be issuable while a constraint is still open, the +first answer was "maybe, with a constraint active". The concern raised back: silently +bypassing the gate would undermine the delay-documentation use case that is the entire +business justification for the constraint workflow — a constraint log that can be shown to +have been skipped stops supporting a notice of delay. **Answer: yes, surface the audited +path instead.** + +So `Urgent` does not create a new bypass. It makes the existing logged-override path — +`confirmEarlyRelease()` — prominent on an urgent package, so the release still produces a +history entry with who, when and why. + +**Adds to the `T7.3` done-when list:** + +- an `Urgent` package with an open constraint offers the logged override in the primary + action position rather than behind a secondary control +- taking it still writes actor, timestamp and reason to history +- no code path releases a constrained package without writing that entry + +--- + +## D5 — Usage data moves to the admin console + +- **Amends:** `B7` (`T7.1`) +- **Surface:** `html/` +- **New task:** `T7.10` + +`docs/reference/creator-frame.md` §2b records that five of the nine colliding script globals +are usage analytics implemented twice, and that the wizard's `showAnalytics` has no caller +because the button lives on the creator. Asked where it belongs now that the creator is a +page in its own right, the answer was **the admin console**. + +That deletes one of the two implementations rather than merging them, and takes an +operator-facing control off a package-authoring screen. + +**Done when:** analytics is reachable from `admin.html`, no analytics control remains on the +creator or the wizard, and only one of the two implementations survives. + +--- + +## D6 — The material list uploads at SOP configuration + +- **Amends:** `CR-013` (`T8.5`) +- **Surface:** `server/` + `html/` +- **New task:** `T8.6` + +`CR-013` is explicit that there is no parts catalog: line items are free text, because +Nate's spreadsheet and the master material workbook have not been supplied +(`IMPLEMENTATION.md` section 8). Asked whether to wait for them or build the upload path now, +the answer was **upload now**. + +This is `CR-005` applied to a second list. The location upload built at `T5.4` — paste or +file, validated, rejected rows reported with the source line, editable afterwards — is the +pattern to reuse rather than re-invent. + +**This does not open the out-of-scope parts catalog.** Section 7 defers "full material request +and inventory system, including the parts catalog and warehouse integration". A project-scoped +list uploaded by the project is not a catalog, carries no inventory levels and integrates +with nothing. If the diff grows a stock count, it has crossed the line. + +**Done when:** a material list uploads during SOP configuration, `T8.5` line items select +from it, free text still works when the list is empty, and no inventory or warehouse field +exists in the diff. + +--- + +## D7 — Archived projects are readable, by project admins + +- **Amends:** `B3` (`T5.2`, shipped), `C1` +- **Surface:** `server/` + `html/` +- **New task:** `T9.8` + +Archiving exists for both projects and work packages, and the server already refuses writes +to an archived project. What it does not do is show them: an archived project leaves the +launcher and there is no way back to it. Asked who should be able to open one, the answer +was **project admins only**, arrived at after considering everyone. + +So this is a listing and a read-only render behind a role check, not a new archive +mechanism. + +**Done when:** a project admin can list and open archived projects, everything renders +read-only, a non-admin sees no archived projects at all, and no write path is reachable from +the read-only view. + +--- + +## D8 — Upload limits: 5MB a file, 2GB a project, PDFs and images, one database + +- **Amends:** `CR-007` (`T7.7`) +- **Surface:** `server/` + `html/` + +Four answers, taken together: + +| Question | Answer | +|---|---| +| Per-file size limit | 5MB | +| Accepted types | PDFs and images | +| Where files live | the same database as everything else | +| What caches offline | only the work packages assigned to that person | + +The follow-up was the consequence: 5MB files in the same database means every encrypted +backup carries them, and a busy project reaches a gigabyte without anyone noticing until a +restore is slow. Splitting the files out was **rejected** on the grounds that a backup which +excludes the drawings is a backup you cannot restore from. **A per-project ceiling of 2GB was +approved instead**, with a warning before it is reached. + +**Adds to the `CR-007` done-when list:** + +- a file over 5MB is refused before upload, with the limit stated +- a type outside PDF and image is refused before upload, with the accepted types stated +- a project at 80% of 2GB warns, and at 2GB refuses with a message naming the ceiling +- the running project total is visible where uploads happen +- offline caching covers the requesting user's assigned packages, not the whole project + +--- + +## D9 — Ready for QA appears in Field View + +- **Amends:** `CR-014` (`T7.6`) +- **Surface:** `html/` + +`CR-014` puts the new state on "a dashboard view or filter". Asked whether the field needs to +see it too, the answer was **yes, it shows in field view**. + +**Adds to the `T7.6` done-when list:** Field View shows which packages are in `Ready for QA`, +and the state is legible at 390px without colour being the only signal. + +--- + +## D10 — Email is switched on and off from the admin console + +- **Amends:** `CR-011` (`T8.3`), `CR-014` (`T7.6`) +- **Surface:** `server/` + `html/` + +All new outbound email in this plan ships **gated off** — a standing instruction from the +wave 5 kickoff, verified against a capture sink rather than a real mail server. Asked who +turns it on, the answer was **the admin controls email**. + +That makes the gate a stored setting with a console control, not an environment variable +somebody edits on the server. Existing hardening constraints stand: the SMTP password lives +in the environment and nowhere else, and no customer IP appears in an email body. + +**Done when:** the send path is complete and exercised against a capture sink, the default is +off, an administrator can turn it on from `admin.html`, a non-administrator cannot, and +changing it is written to the audit log. + +--- + +## Closed without work + +**Free-text location migration.** Work packages created before `CR-004` recorded their +location as typed text, and those values match nothing in the structured list, so they do not +roll up. The question was whether somebody should match them by hand or leave them as +history. Answer: *"It is just sample data at this point so that is ok."* No migration is +built and no item is opened. If this plan ever runs against a database with real +pre-`CR-004` packages in it, this decision has to be revisited before `T6.4`'s rollups can be +trusted — noted here so that is a decision and not a surprise. + +**The off-palette colours.** `BL-004`, `BL-005`, `BL-008` and `BL-009` were each deferred by +their own wave on the same grounds: fixing them changes a rendered colour, and the wave that +found them was forbidden to change one. Together they are the help centre's separate +52-colour palette, two dialogs styled by inline attributes, a second brand blue and a ninth +amber. Asked whether to unify them or leave them, the answer was **change them**. They stay +in wave 9 under `C4`, but they are now approved work rather than four open questions. + +--- + +## What this changes in the wave table + +| Wave | Was | Now also | +|---|---|---| +| 7 | `B7` `A1` `CR-015` `A2` `A6` `CR-014` `CR-007` `B6` `S1`(creator) `F6` | `D1` `D2` `D3` `D4` `D5` `D8` `D9` `D10`(half) | +| 8 | `CR-009` `CR-010` `CR-011` `CR-012` `CR-013` | `D6` `D10`(half) | +| 9 | `CR-008` `CR-017` `S6` `S7` `C1` `C2` `C4` | `D7`, and `C4` now carries the four approved colour items | + +Three new tasks — `T7.10`, `T8.6` and `T9.8`. Everything else is an amended criterion on a +task that already existed. diff --git a/docs/waves/wave-7.md b/docs/waves/wave-7.md index dd5dd64..65159d4 100644 --- a/docs/waves/wave-7.md +++ b/docs/waves/wave-7.md @@ -1,20 +1,29 @@ # Wave 7 — The creator -**Items:** `B7`, `A1`, `CR-015`, `A2`, `A6`, `CR-014`, `CR-007`, `B6`, `S1` (creator), `F6` +**Items:** `B7`, `A1`, `CR-015`, `A2`, `A6`, `CR-014`, `CR-007`, `B6`, `S1` (creator), `F6`, +and from August 18: `D1`, `D2`, `D3`, `D4`, `D5`, `D8`, `D9`, `D10` **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. +dissolved. Do it first - everything after it is cheaper on the far side. + +**Read `docs/waves/decisions-2026-08-18.md` before starting.** Eight of its ten items land in +this wave, four of them as changes to done-when lists written below. Where a task carries an +`Amended` block, that block wins over the text above it. + +**Read `docs/reference/creator-frame.md` before `T7.1`.** It is the measurement of the +boundary: 21 colliding stylesheet selectors, 9 colliding script globals, 0 colliding markup +ids, 28 cross-frame call sites, and the three questions no count can answer. --- ### T7.1 — B7: Dissolve the creator iframe -- **Items:** `B7` +- **Items:** `B7`, `D1` - **Depends on:** T6.5 -- **Blocks:** T7.2 through T7.9 +- **Blocks:** T7.2 through T7.10 - **Surface:** `html/` - **Files:** parent page hosting the creator, the creator itself, cross-frame messaging @@ -32,6 +41,28 @@ 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. +**Amended August 18 (`D1`, `D5`).** `creator-frame.md` section 4 lists three questions this +task has to settle. Two are now answered: + +- **Does the creator get the app bar back?** Yes. It is the only page in `html/` that loads + neither `wp-chrome.css` nor `wp-chrome.js`, and a page without the app bar is not a page. + Expect to redo the wizard's layout arithmetic - `chromeHeight()`, `--wp-chrome-h`, the + `embed-full` sizing. +- **What happens to `body.embedded`?** It goes, and with it `.embed-hide`. The three controls + it was hiding: the creator's own header stays hidden because the app bar replaces it; the + **sample-data control becomes visible** (`D1`); the analytics button stays visible here and + **moves to the admin console at `T7.10`** (`D5`). Do not delete it in this task - a task + that both dissolves the frame and deletes a feature is two diffs. +- **One sequence component or two?** Still open, and still this task's call. Nine of the 21 + colliding selectors are the sequence editor. The wizard authors the sequence and the creator + renders it; confirmed August 18 that those stay two adjustable things, which argues for + scoping rather than merging. If you scope, say so and leave `BL-015` open for wave 9. + +**Do not** fold `BL-001`, `BL-006`, `BL-007` or `BL-013` into this diff. They are logged +against this file and they are cheaper now than ever, and they are still separate items. What +this task owes them is a **measurement**: record whether each still reproduces after the +rebuild, so `T7.2` and `T9.5` inherit a fact rather than an assumption. + **Done when:** - [ ] no iframe remains in the creator; grep confirms @@ -40,12 +71,16 @@ behind a flag. - [ ] `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 +- [ ] the creator renders the standard app bar, and the wizard's chrome arithmetic still holds at 390px and 1440px +- [ ] `body.embedded` and `.embed-hide` are gone; grep confirms +- [ ] the sample-data control is visible and reachable on the creator (`D1`) +- [ ] `BL-001`, `BL-006`, `BL-007` and `BL-013` are each re-measured after the rebuild and their entries updated with the result --- -### T7.2 — F6 + A4 pattern: Section tabs replace the 4,700px form +### T7.2 — F6 + D3: Side navigation and collapsible sections replace the 4,700px form -- **Items:** `F6` +- **Items:** `F6`, `D3` - **Depends on:** T7.1, T5.5, T3.5 - **Blocks:** T7.9 - **Surface:** `html/` @@ -58,24 +93,41 @@ jump links standing in for structure. 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. +**Amended August 18 (`D3`) - the answer is not tabs.** Asked to choose, the decision was one +page with navigation down the side; asked about the height conflict that creates, the call was +delegated. Adopted: **one page, persistent side navigation, sections collapsible, only the +current one open by default, plus an `Expand all`.** Tabs were rejected because they hide +sections a first-time author does not know exist. An uncollapsed long form was rejected +because it is the 4,700px page `F6` exists to fix. The done-when list below is the amended +one; it replaces four of the six entries as written. + +`BL-013` is folded in here and only here: the creator's inputs have `outline: none` with a +1.05:1 glow as their only focus cue, which is a standing `CLAUDE.md` violation on the page +with the most form controls in the app. A rebuilt form ships the `T3.4` ring or it is not +done. + **Done when:** -- [ ] no single view exceeds roughly two screen heights at 1440px -- [ ] toggled-off sections have no tab +- [ ] no single view exceeds roughly two screen heights at 1440px **at rest** - that is, in the default collapse state the page loads in +- [ ] toggled-off sections have no entry in the side navigation - [ ] 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 +- [ ] the side navigation is keyboard operable and marks the current section with `aria-current` +- [ ] each section header is a real `