Source: ddx-documentation/research/template-triage.md
Task 010 · 2026-10-23 · archive root: `_claude-archive/create-nextjs-template/` (workspace root, gitignored; same relative path as in the workspace). ## 1. Baseline (measured BEFORE any edit, 2026-10-23T00:18:34Z) Scope: `ddx-web/src` as scaffolded (563 files). Commands are the `ddx-wip/job_ui-shell-rnd-workspace/02_OUTCOMES_AC.md` guard patterns. | AC | Guard | Lines | Files | Gate | |---|---|---|---|---| | AC6.1 | `from '@prisma` / `fetch(` in `src/components` | 0 | 0 | pass | | AC9.1 | `new EventSource` in `src` | 1 | 1 | pass (≤1) | | AC11.3 | `from '@/components/ui/` in `page.tsx` | 36 | 18 | FAIL | | AC12.3 | hex `#rrggbb` in `src/components` | 0 | 0 | pass | | AC12.4 | `[N px\|rem]` in `*.tsx` | 74 | 47 | FAIL | | AC13.1 | `geist` (case-insensitive) in `src` | 0 | 0 | pass (Urbanist + JetBrains_Mono present) | | AC13.4 | `150ms\|250ms\|400ms` in `src` | 5 | 3 | FAIL | | AC14.5 | `border-(l\|t)-N` in `*.tsx` | 2 | 1 | FAIL | Union of token-violating files (AC12.3 + 12.4 + 13.4 + 14.5): **50 files** (plan time said 52). Notes: - AC9.1 hit: `src/lib/sse/client/consumer.ts:52` — the one allowed owner moves to `src/lib/sse/manager.ts` in task 031. - Hex outside `src/components` (not AC12.3 scope, listed for task 015): `src/lib/logger.ts`, `src/lib/logger/browser.ts`, `src/styles/brand-tokens.ts`, `src/app/globals.css`, `showcase/sections/inputs-section.tsx` (parked). - AC13.4 hits: `src/app/globals.css:186-188` (`--duration-fast/normal/slow`), `ddx/DDXImageViewer.tsx:487`, `ddx/chat/DDXChatTypingIndicator.tsx:32`. - AC14.5 hits: `ddx/DDXCodeEditor.tsx:225,239` (`border-t-0`). - AC11.3 files: `(marketing)/page.tsx`, 5 `(auth)/auth/*/page.tsx` (forgot-password, register, logout, select-org), 12 `portal/[role]/**/page.tsx` (parked). ### Token-violation list for task 015 (AC12.4 file · count) KEEP folders (stay in `ddx-web/src`, task 015 fixes): `ui/tabs.tsx` 2 · `ui/tooltip.tsx` 1 · `ui/dropdown-menu.tsx` 1 · `ui/color-picker.tsx` 1 · `ui/checkbox.tsx` 1 · `ui/button.tsx` 1 · `ui/badge.tsx` 1 · `app/globals.css` (AC13.4 ×3). Parked in the widened pass (§4): `layout/Header.tsx` 2 · `layout/Sidebar.tsx` 1 · `layout/Footer.tsx` 1 · `debug/SSEInspectorPanel.tsx` 7 · `debug/UIDebugInspector.tsx` 3 · `ddx/DDXContainer.tsx` 4 · `ddx/DDXCombobox.tsx` 3 · `ddx/ProgressStepper.tsx` 2 · `ddx/DDXTimeSlotPicker.tsx` 2 · `ddx/DDXTimePicker.tsx` 2 · `ddx/DDXSectionBlock.tsx` 2 · `ddx/DDXMenubar.tsx` 2 · `ddx/DDXFormComponents.tsx` 2 · `ddx/DDXFilterBar.tsx` 2 · `ddx/DDXEntityPanel.tsx` 2 · `ddx/DDXAudioPlayer.tsx` 2 · 1 each: `ddx/LocaleSwitcher`, `DDXTimeline`, `DDXTabs`, `DDXTable`, `DDXStatusBadge`, `DDXMiniCalendar`, `DDXImageViewer`, `DDXHeaderMenu`, `DDXFormCompound`, `DDXErrorBoundary`, `DDXEmptyState`, `DDXDateTimePicker`, `DDXDateRangePicker`, `DDXCalendarView`, `DDXCalendarNavigation`, `DDXAsyncErrorBoundary`, `DDXAppShell`, `DDXAdvancedComponents`. Parked by this task: `kit-demo/PatternProgress` 2 · `PatternMarquee` 2 · `PatternMediaViewer` 1 · `PatternCalendar` 1 · `dev/kit/layout.tsx` 2 · `showcase/sections/layout-section.tsx` 1. ## 2. Triage table Verdicts: **KEEP** stays in `ddx-web/src` · **PORT-LATER** (owner task) the family task ports it into its inventory folder and fixes tokens · **DROP** demo/HMS-only, never ported. Status: `parked` = in the archive now · `in src` = not moved yet (see §4). | Path (under `ddx-web/src/`) | Verdict | Owner | Status | |---|---|---|---| | `components/ui/*` (25 shadcn primitives) | KEEP | 015 tokens | in src | | `components/providers/*` (Org, Query, Session, Settings, Sse, Theme, ThemeMode) | KEEP | 014 / 029 / 031 | in src | | `components/feedback/{Banner,ConfirmDialog,EmptyState}` | PORT-LATER | 021 | in src | | `components/tables/DataTable*` | PORT-LATER | 023 | in src | | `components/layout/{Header,Footer,PublicLayout,MobileDrawer,CopyrightYear,AuthLocaleSwitcher}` | PORT-LATER | 026 | in src | | `components/forms/PasswordInput` | PORT-LATER | 028 | in src | | `components/layout/{PortalShell,Sidebar,SidebarContext,StatusBar,UserMenu,ShellScroll,ResizablePanels,PinnedActions,DDXContainer,workspace-command.css}` | PORT-LATER | 029 | in src | | `components/layout/{Breadcrumbs,AutoBreadcrumbs,PageHeader*,PageActionBar*}` | PORT-LATER | 030 | in src | | `components/navigation/PortalLink` | PORT-LATER | 030 | in src | | `components/settings/DensityChooser` | PORT-LATER | 029 | in src | | `components/templates/{List,Detail,Edit,New,Print,Export}View`, `StickyFormFooter`, `views/*` | PORT-LATER | 033 | in src | | `components/media/{AudioPlayer,ImageContainer}` | PORT-LATER | 034 (player → 038) | in src | | `components/consent/{ConsentGate,CookieConsent}` | PORT-LATER | 026 | in src | | `components/debug/*` (8 files) | DROP | — | **parked** | | `components/ddx/DDXNotify`, `DDXBanner`, `DDXAlert*`, `DDXConfirmDialog`, `DDXDialog`, `dialogs/*`, `DDXEmptyState`, `DDXErrorState`, `DDXNotFoundState`, `errors/*`, `DDXErrorBoundary`, `DDXAsyncErrorBoundary` | PORT-LATER | 021 | **parked** | | `components/ddx/DDXTable*`, `DDXPagination*`, `DDXFilterBar`, `DDXListCard`, `DDXRecordRow*`, `DDXStats*`, `DDXSparkline`, `DDXTrendIndicator`, `DDXViewToggle`, `skeletons/*`, `DDXPageSkeleton*`, `DDXSkeleton`, `DDXLoading*`, `DDXSpinner` | PORT-LATER | 023 | **parked** | | `components/ddx/DDXHeader`, `DDXHeaderMenu`, `DDXFooter`, `DDXMinimalFooter`, `DDXHeroSection`, `DDXMarquee`, `DDXLogo`, `LocaleSwitcher`, `ThemeToggle`, `DDXReadingLayout`, `DDXSectionBlock` | PORT-LATER | 026 | **parked** | | `components/ddx/DDXForm*`, `DDXField`, `DDXInput`, `DDXTextarea`, `DDXSelect`, `DDXRadixSelect`, `DDXCombobox`, `DDXRadioGroup`, `DDXSwitch`, `DDXSlider`, `DDX{Date,DateRange,DateTime,Time,TimeSlot}Picker`, `date-input.ts`, `DDXFileUpload`, `DDXAvatarUpload`, `DDXEditableText`, `DDXEditPageLayout`, `wizard/*`, `ProgressStepper`, `hooks/useFormField` | PORT-LATER | 028 | **parked** | | `components/ddx/DDXAppShell`, `shell-context`, `DDXNavigation`, `DDXUserMenu`, `DDXSheet`, `DDXDensityToggle`, `density-context`, `DDXLayoutVariantToggle`, `DDXScrollArea`, `layout/*`, `DDXContainer*` (+ `DDXContainer/`), `DDXFloatingPanel`, `DDXDraggable`, `settings/*`, `themes.ts` | PORT-LATER | 029 | **parked** | | `components/ddx/DDXBreadcrumb`, `DDXPageHeader*`, `DDXHeading`, `DDXActionBar`, `DDXTabs`, `DDXMenubar`, `DDXDropdownMenu`, `DDXContextMenu` | PORT-LATER | 030 | **parked** | | `components/ddx/utils/DDXEventBus` | PORT-LATER | 031 | **parked** | | `components/ddx/DDXDetailSidebar`, `DDXEntityPanel*`, `DDXEntityCard`, `DDXProfileCard`, `DDXCard`, `DDXCollapsible`, `DDXAccordion`, `DDXTimeline`, `DDXBadge`, `DDXStatusBadge`, `DDXAvatar`, `DDXTooltip`, `DDXCopyableText`, `DDXProgress`, `progress/*`, `DDXAdvancedComponents`, `AnimatedComponents`, `animations.ts`, `ClientOnly`, `hooks/*` (rest), `i18n.ts`, `icons/*`, `index.ts` | PORT-LATER | 033 | **parked** | | `components/ddx/DDXImageViewer`, `DDXMediaDisplay`, `DDXCodeEditor`, `DDXSafeHtml` | PORT-LATER | 034 | **parked** | | `components/ddx/chat/*` (8 files) | PORT-LATER | 037 | **parked** | | `components/ddx/DDXAudioPlayer` | PORT-LATER | 038 | **parked** | | `components/ddx/DDXBrandLoader` | PORT-LATER | 021 (BrandLoader family) | **parked** | | `components/ddx/DDXCalendar*`, `DDXMiniCalendar`, `DDXAppointmentDetails` | DROP | — (HMS clinical scheduling, WS8 NOT) | **parked** | | `components/ddx/clinical-surface-policy.ts` | DROP | — | **parked** | | `components/kit-demo/*` (10 mock-data + 14 Pattern files) | DROP | — | **parked** | | `app/[locale]/(app)/portal/[role]/**` (patients, appointments, inventory, showcase, dashboard, help, settings, layout, 3× `data.ts`, `stats.ts`) | DROP (route shape → 029/030) | — | **parked** | | `app/[locale]/(marketing)/dev/**` (kit pattern routes) | DROP | — | **parked** | | `ddx-web/prisma/schema.prisma` | DROP (WS2: no DB in web) | — | **parked** | | `locales/*/mock.json`, `locales/*/kit.json` | DROP | — | **parked** | | `app/[locale]/(app)/layout.tsx` | replaced by pass-through | 029 / 031 re-mount cascade | edited | | `lib/toast.ts` (toast bus feeding DDXNotify) | DROP (toasts forbidden; notifications → 021) | — | **parked** | ## 3. Parked (269 files) `_claude-archive/create-nextjs-template/ddx-web/` holds: - first pass (81 files): `src/components/kit-demo/` · `src/app/[locale]/(app)/portal/[role]/` · `src/app/[locale]/(marketing)/dev/` · `prisma/` - widened pass (188 files, lead decision 2026-10-23): `src/components/ddx/` · `src/components/debug/` · `src/lib/toast.ts` · `src/locales/{en,fr,de,es}/{mock,kit}.json` Rollback: move each path back to the same place under `ddx-web/`, and revert the §4 rewires. `sonner` stays in `package.json` (task 009 owns the package list); nothing imports it now. ## 4. Widened pass — importers rewired before parking The first sweep found importers outside the task 010 files. The lead widened the scope (option 1). Each swap uses plain semantic markup and semantic token utilities only. | File (under `ddx-web/src/`) | Change | Future owner | |---|---|---| | `app/[locale]/layout.tsx` | removed `DDXNotifyHost` + `DDXDebugProvider` imports and mounts | 021 | | `app/[locale]/loading.tsx` | `DDXBrandLoader` → `div` skeleton (`size-12 animate-pulse rounded-full bg-muted`) | 023 | | `app/global-error.tsx`, `app/global-not-found.tsx` | `Heading` → `h1` | 019 | | `app/[locale]/{error,not-found,forbidden,unauthorized}.tsx` | `Heading` → `h1`/`h2` | 019 | | `app/[locale]/(marketing)/page.tsx` | `Heading` → `h1` + `h2` | 019 | | `app/[locale]/(auth)/auth/{login,reset-password,forgot-password,register,verify-email,otp,magic-link,select-org}` | `Heading` → `h1` (9 headings) | 019 | | `components/{templates/PrintView,templates/ExportView,feedback/EmptyState,layout/PageHeader,layout/PageActionBar}.tsx` | `Heading` → `h1`/`h2`/`h3` | 019 | | `components/layout/PageActionBar.test.tsx` | dropped the `vi.mock('@/components/ddx')` block | — | | `lib/density.ts` | label keys `kit.density.*` → `settings.density.*` | — | | `locales/{en,fr,de,es}/settings.json` | added `density.cosy` + `density.large` (values from each locale's `kit.json`) | — | | `i18n/types.ts`, `lib/i18n/types.ts`, `i18n/next-intl.d.ts` | removed the `mock` + `kit` namespaces | — | Each swap carries a `// … replaced by inventory entry in task 019|023` line at the removed import. Heading classes = the old `DDXHeading` variant classes (no hex, no arbitrary px, no motion values). Sweep after the rewire: `rg -n -e '@/components/(ddx|debug|kit-demo)' -e '@/lib/toast' -e 'locales/en/(mock|kit)' ddx-web/src` → 0 code importers. Still in src (owner tasks rewire or port them): `components/{layout,feedback,forms,templates,tables, media,navigation,settings,consent}` (verdicts in §2) and `src/lib/debug/` (library used by `lib/logger/browser.ts` and `hooks/useSSE.ts`). ## 5. After counts (same guards, after parking) | AC | Before | After | |---|---|---| | AC9.1 files | 1 | 1 (`lib/sse/client/consumer.ts`) | | AC11.3 page files | 18 | 5 (marketing + 4 auth pages → 035) | | AC12.3 lines | 0 | 0 | | AC12.4 lines | 74 | 12 (`ui/*`, `layout/*` → 015) | | AC13.4 lines | 5 | 3 (`app/globals.css:186-188` → 015) | | AC14.5 lines | 2 | 0 | | AC13.1 geist | 0 | 0 | | files in `ddx-web/src` | 563 | 295 | Not compiled: typecheck, lint and build are lead-owned (/unify). The `(app)` group has no page until 029/030 add the portal routes. ## 6. Task 015 sweep — BEFORE / AFTER (2026-10-23) Same guard commands as §1, run over `ddx-web/src`. "015 start" = measured at task 015 start (after tasks 010 + 012). "After 015" = after the sweep of `components/ui/*`. | AC | Guard | Baseline §1 | 015 start | After 015 | Note | |---|---|---|---|---|---| | AC12.3 | hex in `src/components` | 0 | 0 | 0 | pass | | AC12.4 | `[N px\|rem]` in `*.tsx` | 74 | 12 | 0 | incl. `layout/{Header,Sidebar,Footer}` (scope widened by lead) | | AC13.4 | `150\|250\|400ms` in `src` | 5 | 0 | 0 | `globals.css` already fixed by 012 | | AC14.5 | `border-(l\|t)-N` in `*.tsx` | 2 | 0 | 0 | pass | | AC13.1 | `geist` in `src` | 0 | 0 | 0 | pass | | AC11.3 | `@/components/ui/` in `page.tsx` (files) | 18 | 5 | 5 | owner 035, not a 015 guard | Extra (invariant row 21, not a guard regex): numeric `duration-100` ×8 and `duration-300` ×2 in `components/ui/*` → `duration-fast` (120 ms) and `duration-slow` (320 ms). ### Swaps (`components/ui/`) | File | Before | After | |---|---|---| | `button.tsx` (sm) | `rounded-[min(var(--radius-md),12px)]` · `text-[0.8rem]` | `rounded-md` · `text-xs` | | `checkbox.tsx` | `rounded-[4px]` | `rounded-sm` (same 4 px) | | `tooltip.tsx` | `rounded-[2px]` | `rounded-xs` (same 2 px) | | `tabs.tsx` | `p-[3px]` · `ring-[3px]` | `p-0.75` · `ring-3` (same values) | | `badge.tsx` | `ring-[3px]` | `ring-3` | | `dropdown-menu.tsx` | `min-w-[96px]` | `min-w-24` (same 96 px) | | `color-picker.tsx` | `text-[10px]` | `text-xs` | | `select`, `dropdown-menu`, `dialog`, `sheet`, `popover` | `duration-100` | `duration-fast` | | `progress`, `circular-progress` | `duration-300` | `duration-slow` | ### Gaps (no token — raised to the lead, no value invented) - **G4** — no micro type step below `text-xs` (12 px). Template used `text-[10px]` (eyebrow / env badge / footer note) and `text-[0.8rem]`; snapped to `text-xs`. If DESIGN.md wants a 10 px eyebrow, it needs a `--text-2xs` row in the bridge. - **G5** — `rounded-xs/sm/md/lg` still resolve to Tailwind defaults; the brand file ships no `--radius-*` and the bridge maps only role radii (G1). Primitives keep the default steps. - **G6** — `min-h-[60vh]` in `[locale]/{error,loading,not-found}.tsx` is viewport-relative (not a guard hit); no token exists. Left as is. ### Layout files (scope widened by lead, 2026-10-23) — done `components/layout/Sidebar.tsx:123`, `Header.tsx:38`, `Header.tsx:135`, `Footer.tsx:47`: `text-[10px]` ×3 → `text-xs`, `min-w-[140px]` → `min-w-36`. In the same 3 files, numeric `duration-200/300` → `duration-base` / `duration-slow`. Token swaps only; owners 026 / 029 still port these files. Other `layout/*` files (e.g. `MobileDrawer.tsx`) keep numeric durations.
Task 010 · 2026-10-23 · archive root: _claude-archive/create-nextjs-template/
(workspace root, gitignored; same relative path as in the workspace).
Scope: ddx-web/src as scaffolded (563 files). Commands are the
ddx-wip/job_ui-shell-rnd-workspace/02_OUTCOMES_AC.md guard patterns.
Union of token-violating files (AC12.3 + 12.4 + 13.4 + 14.5): 50 files (plan time said 52).
Notes:
src/lib/sse/client/consumer.ts:52 — the one allowed owner moves to
src/lib/sse/manager.ts in task 031.src/components (not AC12.3 scope, listed for task 015):
src/lib/logger.ts, src/lib/logger/browser.ts, src/styles/brand-tokens.ts,
src/app/globals.css, showcase/sections/inputs-section.tsx (parked).src/app/globals.css:186-188 (--duration-fast/normal/slow),
ddx/DDXImageViewer.tsx:487, ddx/chat/DDXChatTypingIndicator.tsx:32.ddx/DDXCodeEditor.tsx:225,239 (border-t-0).(marketing)/page.tsx, 5 (auth)/auth/*/page.tsx
(forgot-password, register, logout, select-org), 12 portal/[role]/**/page.tsx (parked).KEEP folders (stay in ddx-web/src, task 015 fixes): ui/tabs.tsx 2 · ui/tooltip.tsx 1 ·
ui/dropdown-menu.tsx 1 · ui/color-picker.tsx 1 · ui/checkbox.tsx 1 · ui/button.tsx 1 ·
ui/badge.tsx 1 · app/globals.css (AC13.4 ×3).
Parked in the widened pass (§4): layout/Header.tsx 2 · layout/Sidebar.tsx 1 · layout/Footer.tsx 1 ·
debug/SSEInspectorPanel.tsx 7 · debug/UIDebugInspector.tsx 3 · ddx/DDXContainer.tsx 4 ·
ddx/DDXCombobox.tsx 3 · ddx/ProgressStepper.tsx 2 · ddx/DDXTimeSlotPicker.tsx 2 ·
ddx/DDXTimePicker.tsx 2 · ddx/DDXSectionBlock.tsx 2 · ddx/DDXMenubar.tsx 2 ·
ddx/DDXFormComponents.tsx 2 · ddx/DDXFilterBar.tsx 2 · ddx/DDXEntityPanel.tsx 2 ·
ddx/DDXAudioPlayer.tsx 2 · 1 each: ddx/LocaleSwitcher, DDXTimeline, DDXTabs, DDXTable,
DDXStatusBadge, DDXMiniCalendar, DDXImageViewer, DDXHeaderMenu, DDXFormCompound,
DDXErrorBoundary, DDXEmptyState, DDXDateTimePicker, DDXDateRangePicker,
DDXCalendarView, DDXCalendarNavigation, DDXAsyncErrorBoundary, DDXAppShell,
DDXAdvancedComponents.
Parked by this task: kit-demo/PatternProgress 2 · PatternMarquee 2 · PatternMediaViewer 1 ·
PatternCalendar 1 · dev/kit/layout.tsx 2 · showcase/sections/layout-section.tsx 1.
Verdicts: KEEP stays in ddx-web/src · PORT-LATER (owner task) the family task ports it
into its inventory folder and fixes tokens · DROP demo/HMS-only, never ported.
Status: parked = in the archive now · in src = not moved yet (see §4).
_claude-archive/create-nextjs-template/ddx-web/ holds:
src/components/kit-demo/ · src/app/[locale]/(app)/portal/[role]/ ·
src/app/[locale]/(marketing)/dev/ · prisma/src/components/ddx/ ·
src/components/debug/ · src/lib/toast.ts · src/locales/{en,fr,de,es}/{mock,kit}.jsonRollback: move each path back to the same place under ddx-web/, and revert the §4 rewires.
sonner stays in package.json (task 009 owns the package list); nothing imports it now.
The first sweep found importers outside the task 010 files. The lead widened the scope (option 1). Each swap uses plain semantic markup and semantic token utilities only.
Each swap carries a // … replaced by inventory entry in task 019|023 line at the
removed import. Heading classes = the old DDXHeading variant classes (no hex, no arbitrary
px, no motion values). Sweep after the rewire:
rg -n -e '@/components/(ddx|debug|kit-demo)' -e '@/lib/toast' -e 'locales/en/(mock|kit)' ddx-web/src
→ 0 code importers.
Still in src (owner tasks rewire or port them): components/{layout,feedback,forms,templates,tables, media,navigation,settings,consent} (verdicts in §2) and src/lib/debug/ (library used by
lib/logger/browser.ts and hooks/useSSE.ts).
Not compiled: typecheck, lint and build are lead-owned (/unify). The (app) group has no page
until 029/030 add the portal routes.
Same guard commands as §1, run over ddx-web/src. "015 start" = measured at task 015 start
(after tasks 010 + 012). "After 015" = after the sweep of components/ui/*.
Extra (invariant row 21, not a guard regex): numeric duration-100 ×8 and duration-300 ×2
in components/ui/* → duration-fast (120 ms) and duration-slow (320 ms).
components/ui/)text-xs (12 px). Template used text-[10px] (eyebrow /
env badge / footer note) and text-[0.8rem]; snapped to text-xs. If DESIGN.md wants a
10 px eyebrow, it needs a --text-2xs row in the bridge.rounded-xs/sm/md/lg still resolve to Tailwind defaults; the brand file ships no
--radius-* and the bridge maps only role radii (G1). Primitives keep the default steps.min-h-[60vh] in [locale]/{error,loading,not-found}.tsx is viewport-relative (not a
guard hit); no token exists. Left as is.components/layout/Sidebar.tsx:123, Header.tsx:38, Header.tsx:135, Footer.tsx:47:
text-[10px] ×3 → text-xs, min-w-[140px] → min-w-36. In the same 3 files, numeric
duration-200/300 → duration-base / duration-slow. Token swaps only; owners 026 / 029
still port these files. Other layout/* files (e.g. MobileDrawer.tsx) keep numeric durations.
adr/
deploy/
research/