nexus/.planning/phases/41-diagrams-icons-theme-engine/41-VERIFICATION.md

323 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
phase: 41-diagrams-icons-theme-engine
verified: 2026-04-04T21:30:58Z
status: gaps_found
score: 9/17 must-haves verified
gaps:
- truth: "buildPalette returns 7 named roles with dark and light variants from a single hex seed"
status: failed
reason: "theme-renderer.ts is an 8-line stub that throws 'renderThemePalette: not yet implemented'. No buildPalette, no OKLCH logic, no culori usage."
artifacts:
- path: "server/src/services/renderers/theme-renderer.ts"
issue: "Stub — throws NotImplemented, no real implementation"
missing:
- "Full OKLCH palette engine using culori (buildPalette, dark/light variants)"
- "All exported functions: buildPalette, exportToCss, exportToTailwind, exportToVSCode, exportToJson"
- truth: "All palette computations use OKLCH via culori -- no HSL intermediates anywhere"
status: failed
reason: "theme-renderer.ts contains no culori import and no computations at all. culori is installed in server/package.json but never used."
artifacts:
- path: "server/src/services/renderers/theme-renderer.ts"
issue: "Stub — no culori import or usage"
missing:
- "culori converter('oklch') usage for palette generation"
- truth: "WCAG AA contrast is validated per foreground/background pair"
status: failed
reason: "wcag-contrast is installed but never imported or called in theme-renderer.ts (stub). No validation logic exists."
artifacts:
- path: "server/src/services/renderers/theme-renderer.ts"
issue: "Stub — no wcag-contrast usage"
missing:
- "wcagContrast.hex(fg, bg) calls for each foreground/background pair"
- truth: "Four export formatters produce CSS variables, Tailwind config, VS Code theme, and JSON strings"
status: failed
reason: "No export formatter functions exist anywhere in the codebase. theme-renderer.ts is a stub."
artifacts:
- path: "server/src/services/renderers/theme-renderer.ts"
issue: "Stub — no formatters"
missing:
- "exportToCss, exportToTailwind, exportToVSCode, exportToJson functions"
- truth: "nexus-settings.json schema accepts optional customTheme field with seed and palette"
status: failed
reason: "server/src/services/nexus-settings.ts has not been extended. nexusSettingsSchema has no customTheme field. The server will silently reject or strip any customTheme in a PATCH."
artifacts:
- path: "server/src/services/nexus-settings.ts"
issue: "Schema missing customTheme field — schema unchanged from pre-phase baseline"
missing:
- "z.object customTheme field: { seedHex: z.string(), palette: z.array(...) }.optional()"
- truth: "User picks a seed color and sees a full palette grid with dark and light variants"
status: failed
reason: "ContentStudio Themes tab renders 'Theme engine coming soon.' — a hardcoded placeholder. ThemeSeedInput, ThemePaletteGrid, and all other theme UI components exist as files but are ORPHANED (never imported anywhere)."
artifacts:
- path: "ui/src/pages/ContentStudio.tsx"
issue: "Themes tab contains placeholder text, no theme components wired"
- path: "ui/src/components/ThemeSeedInput.tsx"
issue: "ORPHANED — defined but never imported"
- path: "ui/src/components/ThemePaletteGrid.tsx"
issue: "ORPHANED — defined but never imported"
missing:
- "Import and use ThemeSeedInput, ThemePaletteGrid, ThemePreviewPanel, ThemeExportTabs, ThemeApplyConfirmDialog in ContentStudio Themes tab"
- truth: "WCAG AA pass/fail badges are shown on each swatch"
status: failed
reason: "ThemePaletteGrid component is orphaned (not wired into ContentStudio). Even if wired, the server cannot supply wcagAA values because theme-renderer.ts is a stub."
artifacts:
- path: "ui/src/components/ThemePaletteGrid.tsx"
issue: "ORPHANED — not used in any page"
missing:
- "Wire ThemePaletteGrid into ContentStudio Themes tab"
- "Working theme-renderer.ts to produce wcagAA values"
- truth: "Theme preview updates live without full page refresh, scoped to .nexus-theme-preview"
status: failed
reason: "ThemePreviewPanel component exists and correctly uses container.style.setProperty() in a useEffect, but it is ORPHANED — never imported by ContentStudio or any other page. The live preview cannot be reached by any user."
artifacts:
- path: "ui/src/components/ThemePreviewPanel.tsx"
issue: "ORPHANED — exists but not imported anywhere"
missing:
- "Wire ThemePreviewPanel into ContentStudio Themes tab"
- truth: "User can export palette as CSS variables, Tailwind config, VS Code theme, or JSON via tabbed interface"
status: failed
reason: "ThemeExportTabs component exists but is ORPHANED. Additionally, the server-side formatter functions that generate the export strings do not exist (theme-renderer.ts stub)."
artifacts:
- path: "ui/src/components/ThemeExportTabs.tsx"
issue: "ORPHANED — defined but never imported"
missing:
- "Wire ThemeExportTabs into ContentStudio Themes tab"
- "Server-side export formatter functions (exportToCss, exportToTailwind, exportToVSCode, exportToJson)"
- truth: "User can apply the generated theme to their Nexus instance with a confirmation dialog"
status: failed
reason: "ThemeApplyConfirmDialog component exists but is ORPHANED. The PATCH to /api/nexus/settings with customTheme payload is never made from any UI component. The server-side schema also does not accept customTheme."
artifacts:
- path: "ui/src/components/ThemeApplyConfirmDialog.tsx"
issue: "ORPHANED — defined but never imported"
missing:
- "Wire ThemeApplyConfirmDialog into ContentStudio Themes tab with PATCH handler"
- "PATCH /api/nexus/settings handler that persists customTheme"
- truth: "theme-renderer.test.ts covers palette generation, WCAG validation, and export formats"
status: failed
reason: "server/src/__tests__/theme-renderer.test.ts does not exist. No test file was created."
artifacts:
- path: "server/src/__tests__/theme-renderer.test.ts"
issue: "MISSING — file not created"
missing:
- "Create server/src/__tests__/theme-renderer.test.ts"
- truth: "nexus-settings-custom-theme.test.ts covers customTheme schema extension"
status: failed
reason: "server/src/__tests__/nexus-settings-custom-theme.test.ts does not exist."
artifacts:
- path: "server/src/__tests__/nexus-settings-custom-theme.test.ts"
issue: "MISSING — file not created"
missing:
- "Create server/src/__tests__/nexus-settings-custom-theme.test.ts"
human_verification:
- test: "Navigate to /:companyId/content-studio and click Diagrams tab. Enter a description, select Flowchart, and click Generate Diagram."
expected: "Progress bar appears, SVG diagram renders after completion, Download SVG and Download PNG buttons work."
why_human: "Requires running dev server and LLM inference. Playwright browser dependency needs to be present at runtime."
- test: "In the Icons tab, enter icon descriptions, select count and style, click Generate."
expected: "Icon grid renders with checkboxes, bulk download works, PNG sizes are correct."
why_human: "Requires running dev server and LLM inference."
- test: "ContentStudio has no navigation link in the sidebar."
expected: "A nav link should be present for users to reach the page."
why_human: "Programmatic check confirms content-studio only appears in App.tsx route — no sidebar link found. Human must verify whether nav link is intentionally absent or missing."
---
# Phase 41: Diagrams, Icons, and Theme Engine Verification Report
**Phase Goal:** Users can generate diagrams from natural language, produce SVG icon sets from descriptions, and create a complete OKLCH color theme from a single seed color — all without binary dependencies beyond what is already installed
**Verified:** 2026-04-04T21:30:58Z
**Status:** gaps_found
**Re-verification:** No — initial verification
## Goal Achievement
### Observable Truths
| # | Truth | Status | Evidence |
|---|-------|--------|----------|
| 1 | Server has culori, @resvg/resvg-js, wcag-contrast, svgo, playwright-core installed | VERIFIED | All present in server/package.json and node_modules |
| 2 | renderContent switch dispatches diagram, icon-set, and theme-palette job types | VERIFIED | content-job-runner.ts lines 1728: three case branches with dynamic imports |
| 3 | useContentJob hook submits a job and subscribes to SSE progress | VERIFIED | ui/src/hooks/useContentJob.ts: 110 lines, submits via submitContentJob + opens EventSource |
| 4 | renderDiagram calls the LLM to synthesize Mermaid syntax from a natural language prompt | VERIFIED | diagram-renderer.ts lines 178183: puterChatComplete called with buildDiagramPrompt output |
| 5 | Mermaid source with %%{init}%% or click directives is stripped before rendering | VERIFIED | stripUnsafeDirectives exports at lines 1728; called at line 186 |
| 6 | renderDiagram returns a JSON bundle with svgBase64 and pngBase64 | VERIFIED | DiagramBundle assembled at lines 219225; buffer returned |
| 7 | renderIconSet returns a JSON bundle with N icons, each having svgSource and PNG variants at 16/32/64 | VERIFIED | icon-renderer.ts lines 157191: PNG_SIZES [16,32,64], IconSetBundle built |
| 8 | SVG output is sanitized via DOMPurify before storage | VERIFIED | diagram-renderer.ts lines 209212: DOMPurify(window).sanitize() called |
| 9 | Diagram supports architecture, flowchart, ERD, sequence, and mind map types | VERIFIED | DIAGRAM_TYPE_HINTS in diagram-renderer.ts covers all five; UI Select in DiagramGeneratePanel has all five |
| 10 | buildPalette returns 7 named roles with dark and light variants from a single hex seed | FAILED | theme-renderer.ts is an 8-line stub that throws NotImplemented |
| 11 | All palette computations use OKLCH via culori | FAILED | culori installed but never imported anywhere |
| 12 | WCAG AA contrast is validated per foreground/background pair | FAILED | wcag-contrast installed but never imported or called |
| 13 | Four export formatters produce CSS, Tailwind, VS Code, JSON | FAILED | No formatter functions exist |
| 14 | nexus-settings.json schema accepts optional customTheme field | FAILED | nexusSettingsSchema unchanged — no customTheme field |
| 15 | User can pick seed color and see full palette grid (dark/light) | FAILED | ContentStudio Themes tab is a placeholder; all theme components orphaned |
| 16 | WCAG badges shown on each swatch | FAILED | ThemePaletteGrid orphaned; server cannot produce wcagAA values |
| 17 | Theme preview scoped to .nexus-theme-preview updates live | FAILED | ThemePreviewPanel orphaned; ThemeContext.applyCustomTheme never called |
| 18 | Export palette via tabbed interface | FAILED | ThemeExportTabs orphaned; server has no formatters |
| 19 | Apply theme via confirmation dialog | FAILED | ThemeApplyConfirmDialog orphaned; no PATCH to /api/nexus/settings with customTheme |
| 20 | theme-renderer.test.ts covers palette/WCAG/exports | FAILED | File does not exist |
| 21 | nexus-settings-custom-theme.test.ts exists | FAILED | File does not exist |
**Score:** 9/21 truths verified
---
### Required Artifacts
| Artifact | Status | Details |
|----------|--------|---------|
| `server/src/services/renderers/types.ts` | VERIFIED | 38 lines; exports DiagramBundle, IconSetBundle, ThemePaletteBundle, RenderResult, PaletteRole |
| `ui/src/hooks/useContentJob.ts` | VERIFIED | 110 lines; exports useContentJob; wired via imports in DiagramGeneratePanel and IconGeneratePanel |
| `ui/src/api/contentJobs.ts` | VERIFIED | 43 lines; exports submitContentJob, getContentJob, getContentJobAsset |
| `server/src/services/renderers/diagram-renderer.ts` | VERIFIED | 232 lines; exports renderDiagram, stripUnsafeDirectives, buildDiagramPrompt |
| `server/src/services/renderers/icon-renderer.ts` | VERIFIED | 213 lines; exports renderIconSet |
| `server/src/__tests__/diagram-renderer.test.ts` | VERIFIED | Tests for stripUnsafeDirectives, LLM synthesis, bundle structure |
| `server/src/__tests__/icon-renderer.test.ts` | VERIFIED | Tests for validateAndCleanSvg, icon bundle structure |
| `ui/src/pages/ContentStudio.tsx` | PARTIAL | 43 lines; Diagrams and Icons tabs work; Themes tab is placeholder ("Theme engine coming soon.") |
| `ui/src/components/DiagramGeneratePanel.tsx` | VERIFIED | 158 lines; wired to useContentJob, DiagramPreview, DiagramSourcePanel |
| `ui/src/components/DiagramPreview.tsx` | VERIFIED | 65 lines |
| `ui/src/components/DiagramSourcePanel.tsx` | VERIFIED | 102 lines |
| `ui/src/components/DiagramSourcePanel.test.tsx` | VERIFIED | JSDOM tests for collapse/expand, textarea, re-render button |
| `ui/src/components/IconGeneratePanel.tsx` | VERIFIED | 230 lines; wired to useContentJob, IconResultGrid, IconDownloadBar |
| `ui/src/components/IconResultGrid.tsx` | VERIFIED | 106 lines |
| `ui/src/components/IconDownloadBar.tsx` | VERIFIED | 55 lines |
| `server/src/services/renderers/theme-renderer.ts` | STUB | 8 lines; exports renderThemePalette as a stub that throws; no culori, no WCAG, no formatters |
| `server/src/__tests__/theme-renderer.test.ts` | MISSING | File does not exist |
| `server/src/services/nexus-settings.ts` | STUB | Schema unchanged; no customTheme field added |
| `server/src/__tests__/nexus-settings-custom-theme.test.ts` | MISSING | File does not exist |
| `ui/src/components/ThemeSeedInput.tsx` | ORPHANED | 95 lines; well-formed component but never imported |
| `ui/src/components/ThemePaletteGrid.tsx` | ORPHANED | 120 lines; well-formed component but never imported |
| `ui/src/components/ThemePreviewPanel.tsx` | ORPHANED | 129 lines; correct setProperty logic but never imported |
| `ui/src/components/ThemePreviewPanel.test.tsx` | VERIFIED | JSDOM tests for .nexus-theme-preview CSS injection — component itself passes tests |
| `ui/src/components/ThemeExportTabs.tsx` | ORPHANED | 102 lines; well-formed component but never imported |
| `ui/src/components/ThemeApplyConfirmDialog.tsx` | ORPHANED | 43 lines; well-formed component but never imported |
| `ui/src/context/ThemeContext.tsx` | PARTIAL | 169 lines; applyCustomTheme added; reads customTheme on mount; but never PATCHes server, and server schema doesn't accept it |
---
### Key Link Verification
| From | To | Via | Status | Details |
|------|----|-----|--------|---------|
| content-job-runner.ts | diagram-renderer.ts | case "diagram" dynamic import | WIRED | Lines 1719 |
| content-job-runner.ts | icon-renderer.ts | case "icon-set" dynamic import | WIRED | Lines 2123 |
| content-job-runner.ts | theme-renderer.ts | case "theme-palette" dynamic import | WIRED (stub) | Lines 2527: wired but renderer throws |
| DiagramGeneratePanel.tsx | useContentJob | useContentJob hook | WIRED | Line 8 import, line 30 call |
| ContentStudio.tsx | App.tsx | Route registration | WIRED | App.tsx line 181: path="content-studio" |
| ThemeApplyConfirmDialog.tsx | /api/nexus/settings | PATCH with customTheme | NOT WIRED | No PATCH call exists anywhere in theme UI components |
| ThemeSeedInput.tsx | ContentStudio.tsx | import + use | NOT WIRED | Component orphaned |
| ThemePaletteGrid.tsx | ContentStudio.tsx | import + use | NOT WIRED | Component orphaned |
| ThemePreviewPanel.tsx | ContentStudio.tsx | import + use | NOT WIRED | Component orphaned |
| ThemeExportTabs.tsx | ContentStudio.tsx | import + use | NOT WIRED | Component orphaned |
| ThemeApplyConfirmDialog.tsx | ContentStudio.tsx | import + use | NOT WIRED | Component orphaned |
| theme-renderer.ts | culori | converter('oklch') | NOT WIRED | culori installed, never imported |
| theme-renderer.ts | wcag-contrast | wcagContrast.hex() | NOT WIRED | wcag-contrast installed, never imported |
---
### Data-Flow Trace (Level 4)
| Artifact | Data Variable | Source | Produces Real Data | Status |
|----------|---------------|--------|--------------------|--------|
| DiagramGeneratePanel.tsx | bundle (DiagramBundle) | renderDiagram via content job SSE | Yes (real Playwright render) | FLOWING |
| IconGeneratePanel.tsx | bundle (IconSetBundle) | renderIconSet via content job SSE | Yes (real LLM + SVGO) | FLOWING |
| ContentStudio.tsx Themes tab | palette | ThemePaletteBundle from renderThemePalette | No — stub throws | DISCONNECTED |
| ThemePreviewPanel.tsx | palette prop | Never passed (orphaned) | N/A | HOLLOW_PROP |
| ThemePaletteGrid.tsx | palette prop | Never passed (orphaned) | N/A | HOLLOW_PROP |
---
### Behavioral Spot-Checks
| Behavior | Command | Result | Status |
|----------|---------|--------|--------|
| theme-renderer throws on call | node -e "import('/opt/nexus/server/src/services/renderers/theme-renderer.ts').then(m=>m.renderThemePalette({}))" | Would throw "not yet implemented" | FAIL |
| culori installed in server | ls /opt/nexus/server/node_modules/culori | Directory exists | PASS |
| wcag-contrast installed | ls /opt/nexus/server/node_modules/wcag-contrast | Directory exists | PASS |
| ContentStudio route registered | grep content-studio ui/src/App.tsx | Line 181 found | PASS |
| Theme tab is placeholder | grep "coming soon" ui/src/pages/ContentStudio.tsx | Line 38 confirmed | FAIL |
---
### Requirements Coverage
| Requirement | Description | Status | Evidence |
|-------------|-------------|--------|----------|
| DIAG-01 | User can generate diagrams from natural language description | SATISFIED | renderDiagram calls LLM via puterChatComplete; DiagramGeneratePanel wired |
| DIAG-02 | System renders Mermaid syntax to SVG and PNG formats | SATISFIED | Playwright renders to SVG; Resvg rasterizes to PNG |
| DIAG-03 | User can view and edit Mermaid source for refinement | SATISFIED | DiagramSourcePanel: collapsible, editable, re-render wired |
| DIAG-04 | System supports architecture, flowchart, ERD, sequence, mind map | SATISFIED | DIAGRAM_TYPE_HINTS covers all 5; UI Select has all 5 |
| DIAG-05 | Mermaid rendering enforces strict security level to prevent XSS | SATISFIED | securityLevel: "strict" in buildMermaidHtml; stripUnsafeDirectives removes %%{init}%% and click directives |
| ICON-01 | User can generate SVG icons from a text description | SATISFIED | renderIconSet uses LLM; IconGeneratePanel wired |
| ICON-02 | System produces icon sets with consistent visual style | SATISFIED | Style parameter (outline/filled/rounded) passed to LLM and to bundle |
| ICON-03 | User can export icons in multiple sizes and formats (SVG, PNG) | SATISFIED | PNG_SIZES [16,32,64] rasterized; IconDownloadBar provides export |
| THEME-01 | User can pick a seed color and receive a complete palette | BLOCKED | theme-renderer.ts stub; Themes tab placeholder |
| THEME-02 | System generates palette in OKLCH color space with Catppuccin-style naming | BLOCKED | No OKLCH computation exists |
| THEME-03 | System validates WCAG AA contrast for all foreground/background pairs | BLOCKED | wcag-contrast unused |
| THEME-04 | User can preview Nexus UI with generated palette live | BLOCKED | ThemePreviewPanel orphaned |
| THEME-05 | User can export palette as CSS, Tailwind, VS Code, JSON | BLOCKED | No export formatters; ThemeExportTabs orphaned |
| THEME-06 | System generates dark and light variants from single seed color | BLOCKED | No dark/light generation logic |
| THEME-07 | User can apply generated theme in one click | BLOCKED | ThemeApplyConfirmDialog orphaned; no PATCH to server; schema missing customTheme |
---
### Anti-Patterns Found
| File | Line | Pattern | Severity | Impact |
|------|------|---------|----------|--------|
| server/src/services/renderers/theme-renderer.ts | 7 | `throw new Error("renderThemePalette: not yet implemented")` | Blocker | Any theme-palette job crashes at runtime |
| ui/src/pages/ContentStudio.tsx | 38 | `"Theme engine coming soon."` hardcoded placeholder text | Blocker | Themes tab entirely inaccessible to users |
| ui/src/context/ThemeContext.tsx | 85-88 | Reads `customTheme` from `/api/nexus/settings` on mount but server schema has no such field; will always silently no-op | Warning | Custom theme persistence cannot work |
---
### Human Verification Required
#### 1. Diagram generation end-to-end
**Test:** Start dev server, navigate to `/:companyId/content-studio`, describe a flowchart, click Generate Diagram.
**Expected:** Progress bar appears; SVG renders; Download SVG and Download PNG produce valid files; Expand source panel shows editable Mermaid; Re-render diagram updates diagram.
**Why human:** Requires running dev server + LLM inference + Playwright Chromium at runtime.
#### 2. Icon generation end-to-end
**Test:** In Icons tab, enter descriptions, select style/count, click Generate.
**Expected:** Icon grid renders with checkboxes; individual and bulk download works; PNG sizes 16/32/64 are valid.
**Why human:** Requires running dev server + LLM inference.
#### 3. Sidebar navigation
**Test:** Check if any sidebar nav item links to content-studio.
**Expected:** A nav link should exist so users can reach the page.
**Why human:** No sidebar link was found in grep results — only `App.tsx` has the route. A human should confirm whether this is intentional or a missing nav link.
---
### Gaps Summary
The phase is split into two tiers of completion:
**Diagram and Icon generation (DIAG-01 through DIAG-05, ICON-01 through ICON-03): COMPLETE.** All server renderers are implemented, tested, and wired. The UI components are substantive and wired to the job hook. The content-job-runner dispatches all three job types.
**Theme engine (THEME-01 through THEME-07): NOT IMPLEMENTED.** This is the critical gap. The root cause is a single cascading failure: `server/src/services/renderers/theme-renderer.ts` was never implemented beyond a stub. Every THEME requirement depends on this function.
Secondary gaps compound the primary:
- `nexus-settings.ts` schema was not extended with `customTheme` (THEME-07 server persistence broken)
- `theme-renderer.test.ts` and `nexus-settings-custom-theme.test.ts` were never created
- All five theme UI components (`ThemeSeedInput`, `ThemePaletteGrid`, `ThemePreviewPanel`, `ThemeExportTabs`, `ThemeApplyConfirmDialog`) are well-written but completely orphaned — none are imported by `ContentStudio.tsx`, which instead renders a `"Theme engine coming soon."` placeholder
The fix requires: (1) implement the OKLCH palette engine in theme-renderer.ts, (2) extend nexus-settings schema, (3) create both missing test files, and (4) wire all five theme UI components into ContentStudio's Themes tab with a PATCH handler.
---
_Verified: 2026-04-04T21:30:58Z_
_Verifier: Claude (gsd-verifier)_