diff --git a/dev-docs/superpowers/specs/2026-05-15-crewli-starter-gui-redesign-design.md b/dev-docs/superpowers/specs/2026-05-15-crewli-starter-gui-redesign-design.md index 2e25cca9..1909f6c3 100644 --- a/dev-docs/superpowers/specs/2026-05-15-crewli-starter-gui-redesign-design.md +++ b/dev-docs/superpowers/specs/2026-05-15-crewli-starter-gui-redesign-design.md @@ -281,9 +281,28 @@ Custom components are first-class in Storybook exactly like PrimeVue ones. crewli-starter `ComponentsPage.vue` (~80 PrimeVue components) is the **source of truth for the standard-component catalog**. -**Story placement:** custom/wrapper stories co-located next to the -`.vue` (moves with the file at cutover); PrimeVue standard catalog and -Foundations centralized under `stories/`. +**Story placement (binding — two disjoint classes):** + +1. **Custom/wrapper components.** Every component authored in this repo + — shell pieces (`AppSidebar`, `AppTopbar`, `WorkspaceSwitcher`, + `RightDrawer`, …), Tier-1 primitives (`StatusTag`, `StatCard`, + `StateBlock`, `PageHead`, `TagsInput`, `EnergyDots`, `EnergyPicker`), + `DraggableBlock`, and the template layer — **including components + that internally wrap a PrimeVue component**. Their `.stories.ts` is + **co-located next to the `.vue`** so it moves with the component at + cutover and is deleted with it. This is the default for essentially + all `components-v2/**` work. +2. **PrimeVue standard catalog + Foundations.** The ~80-component + pure-PrimeVue demo gallery (source of truth: crewli-starter + `ComponentsPage.vue`) and the Foundations stories + (Color/Typography/Spacing/Icons/Dark/Density) — neither has an owning + `.vue`. These are **centralized under `stories/`**. + +"Wraps a PrimeVue component" does **not** reclassify a component into +the catalog — a wrapper is still custom and co-locates. (Plan 2 misread +the prior wording and centralized 6 shell stories under +`src/stories/v2/`; Plan 3 carries a cleanup task to migrate them — see +commit body.) **Story tree:** `Foundations/` (Color, Typography, Spacing, Icons, Dark mode, Density) · `PrimeVue/` (~80, grouped as in ComponentsPage) · @@ -395,18 +414,42 @@ knowledge, not a per-page decision** — it lives in one map | Status value(s) | `severity` | Semantics | |---|---|---| -| `approved`, `confirmed`, `completed`, `active` | `success` | terminal-good / active | -| `pending`, `pending_approval`, `invited` | `warn` | awaiting action | -| `rejected`, `cancelled`, `declined` | `danger` | terminal-bad | -| `draft` | `secondary` | not yet live | -| `inactive`, `expired` | `secondary` (muted) | dormant | -| (unmapped fallback) | `info` | + dev-warn so gaps surface | +| `approved`, `completed`, `confirmed`, `contracted`, `paid_in_full` | `success` | terminal-good / fully settled | +| `pending_approval`, `pending`, `applied`, `option`, `offered`, `reverted` | `warn` | organizer action required | +| `invited`, `requested`, `deposit_paid` | `info` | awaiting external party / in-progress — no viewer action | +| `none`, `draft`, `dismissed` | `secondary` | muted — absent / not-yet-live / archived | +| `rejected`, `cancelled`, `declined`, `no_show` | `danger` | terminal-bad | +| (unmapped at runtime) | renders `info` + dev console warn | unreachable in a passing build — §8.X consistency test fails on any gap | Rule: **every** backend status enum mirrored into `src/types/` gets a row here in the same PR that adds the enum (extends the existing "mirror backend PHP enums" project rule). `StatusTag` never inlines a severity; it always resolves through this map. +### 8.X Enforcement (binding) + +The §8 severity map is mechanically enforced by a single Vitest unit +test, `apps/app/tests/unit/utils/statusSeverity.consistency.spec.ts`, +added in Plan 3 alongside `statusSeverity.ts`. It imports the live enum +modules (`ShiftAssignmentStatus`, `ArtistEngagementStatus`, +`PaymentStatus`, `PersonStatus`, `MatchStatus`) and asserts **both** +directions: + +1. **Completeness** — every value of every listed enum resolves to an + explicit severity in `statusSeverity.ts`, never the dev-fallback. + Guards the failure mode that left 11 values silent-falling to grey + `info`. +2. **No phantoms** — every key in `statusSeverity.ts` corresponds to a + value present in at least one listed enum. Guards the inverse mode + (the original table mapped `active`/`inactive`/`expired`, which exist + in no enum). + +Adding a new mirrored enum, or a new value on an existing one, requires +extending **both** `statusSeverity.ts` and this test's enum-list in the +**same commit**. A silent fallback or an orphan key is a test failure +that blocks CI, not a convention. This extends the existing "mirror +backend PHP enums" rule (CLAUDE.md) with a mechanical gate. + **Tier-2 — Smart Filter subsystem (secure generic version now):** `SmartFilterBar` + `FilterChip` + `FilterPopover` + `AddFilterMenu` + 5 editors (Text / NumberRange / MultiSelect / EnumGrid / Tag) +