|
| 1 | +# REV-009: The style-token system is not connected to anything |
| 2 | + |
| 3 | +## Metadata |
| 4 | + |
| 5 | +| Field | Value | |
| 6 | +|-------|-------| |
| 7 | +| **ID** | REV-009 | |
| 8 | +| **Phase** | Phase 12 — Reanimation (Revival Horizon 0) | |
| 9 | +| **Priority** | 🟡 Medium — nothing is visibly broken, but a shipped subsystem does nothing and a live one writes invalid CSS | |
| 10 | +| **Difficulty** | 🟡 Medium — the code is small; the decision is a product one | |
| 11 | +| **Estimated Time** | 1–2 days | |
| 12 | +| **Prerequisites** | None. Found during REV-008 Stream D1. | |
| 13 | +| **Branch** | `task/rev-009-style-tokens` | |
| 14 | +| **Recommended executor** | 🟠 **Opus 4.8** — the work is small but the call on what the design system *is* is not mechanical | |
| 15 | + |
| 16 | +## Objective |
| 17 | + |
| 18 | +Decide whether the STYLE-001 / STYLE-002 design-token system is finished or |
| 19 | +retired, and make the code say so. Today it is neither: half of it is dead code, |
| 20 | +the other half is live and writing CSS values that resolve to nothing. |
| 21 | + |
| 22 | +## What was found |
| 23 | + |
| 24 | +REV-008 set out to verify the StyleTokens work that arrived with the |
| 25 | +`cline-dev-tara` merge — flagged in |
| 26 | +[MERGE-NOTES-cline-dev-tara.md](../../reviews/MERGE-NOTES-cline-dev-tara.md) as |
| 27 | +having zero automated coverage. It does not work, for three independent reasons. |
| 28 | + |
| 29 | +### 1. The injector is never constructed |
| 30 | + |
| 31 | +`packages/noodl-viewer-react/src/style-tokens-injector.ts` exports |
| 32 | +`StyleTokensInjector`, whose constructor injects a `<style>` element of CSS |
| 33 | +custom properties into the viewer document. Nothing anywhere calls `new |
| 34 | +StyleTokensInjector(...)`: |
| 35 | + |
| 36 | +```bash |
| 37 | +grep -rn "new StyleTokensInjector" packages/ # no matches |
| 38 | +``` |
| 39 | + |
| 40 | +Its only importer is itself. **No tokens are ever injected into a preview.** |
| 41 | + |
| 42 | +### 2. The two halves use different token vocabularies |
| 43 | + |
| 44 | +Even if it were wired up, the names would not line up. |
| 45 | + |
| 46 | +| Source | Tokens | |
| 47 | +|---|---| |
| 48 | +| `StyleTokensInjector.getDefaultTokens()` and `models/StyleTokens/DefaultTokens.ts` | `--primary --background --foreground --border --space-sm --space-md --space-lg --radius-md --shadow-sm --shadow-md` (10) | |
| 49 | +| `models/ElementConfigs/configs/*.ts` | `--font-sans --text-base --text-xs --font-normal --leading-normal --foreground --primary --primary-foreground --secondary --radius-md --space-3 --surface --space-4 --border-1 --border-subtle --radius-lg --shadow-md --muted …` | |
| 50 | + |
| 51 | +The overlap is `--foreground`, `--primary`, `--radius-md`, `--shadow-md`. The |
| 52 | +vocabulary the configs actually use — the Tailwind-style scale with `--space-4`, |
| 53 | +`--font-sans`, `--surface` — appears **only in the phase-9 task documents** |
| 54 | +(`dev-docs/tasks/phase-9-styles-overhaul/STYLE-001-token-system-enhancement/README.md`), |
| 55 | +never in shipped code. STYLE-002 was written against the token set STYLE-001's |
| 56 | +design document promised; STYLE-001 shipped a different, smaller one. |
| 57 | + |
| 58 | +### 3. ElementConfigs is live and stamping unresolvable values |
| 59 | + |
| 60 | +This is the part that is not merely dead. `NodePicker.utils.ts` calls |
| 61 | +`ElementConfigRegistry.applyDefaults(node, type.name)` on every node creation, and |
| 62 | +`TextConfig` is keyed on `'Text'`, which **is** the real node type. So every new |
| 63 | +Text node gets written into `project.json` with: |
| 64 | + |
| 65 | +```js |
| 66 | +fontFamily: 'var(--font-sans)', |
| 67 | +fontSize: 'var(--text-base)', |
| 68 | +fontWeight: 'var(--font-normal)', |
| 69 | +lineHeight: 'var(--leading-normal)', |
| 70 | +color: 'var(--foreground)', |
| 71 | +``` |
| 72 | + |
| 73 | +None of which are defined at runtime. The three `net.noodl.controls.*` configs |
| 74 | +are equally live and equally affected. |
| 75 | + |
| 76 | +Note this is *not* purely cosmetic: the values are persisted into the user's |
| 77 | +project file, so retiring the tokens later means those projects still carry them. |
| 78 | + |
| 79 | +### Already actioned in REV-008 |
| 80 | + |
| 81 | +`GroupConfig` keyed on `net.noodl.visual.group`, which is not a node type — the |
| 82 | +real one is `Group`. It had therefore never applied to anything, and was deleted |
| 83 | +rather than repointed, precisely because activating it would have stamped the |
| 84 | +undefined `var(--surface)` / `var(--space-4)` vocabulary onto the most-used node |
| 85 | +in the product. Tara's `ImageConfig` had the same defect and was not ported. |
| 86 | +`TextConfig`'s own identifier is correct, which is why it is live. |
| 87 | + |
| 88 | +## The decision to make |
| 89 | + |
| 90 | +Three coherent end states. Pick one deliberately; the current state is none of |
| 91 | +them. |
| 92 | + |
| 93 | +**A. Finish it.** Instantiate `StyleTokensInjector` in the viewer, and reconcile |
| 94 | +the vocabularies — most likely by expanding `DefaultTokens.ts` to the full scale |
| 95 | +the phase-9 design document specifies, since that is what the configs already |
| 96 | +expect. Largest option, and the one that makes the property panel's variant and |
| 97 | +size dropdowns actually mean something. |
| 98 | + |
| 99 | +**B. Retire STYLE-002's tokenisation, keep the layout fixes.** Strip the `var(…)` |
| 100 | +defaults from `TextConfig` and the control configs, leaving the parts that are |
| 101 | +real bug fixes — `TextConfig` documents `width: auto` + flex participation as |
| 102 | +fixing text pushing siblings off-screen in row layouts. Delete |
| 103 | +`style-tokens-injector.ts` and the StyleTokens model, or leave them clearly |
| 104 | +marked unused. |
| 105 | + |
| 106 | +**C. Retire the whole thing.** Remove ElementConfigs, its registry, and the |
| 107 | +property-panel variant/size UI that consumes it, along with the StyleTokens |
| 108 | +model. Smallest surface left behind. |
| 109 | + |
| 110 | +## Steps |
| 111 | + |
| 112 | +1. Confirm the finding in a running preview: create a project, add a Text node, |
| 113 | + and read `getComputedStyle` on the rendered element via |
| 114 | + `npm run cdp -- eval --target=viewer`. Expect the `var()` references to |
| 115 | + resolve to nothing. (REV-008 established this statically; a live confirmation |
| 116 | + costs one dev-loop launch and removes all doubt.) |
| 117 | +2. Make the call above. Record it here. |
| 118 | +3. Implement, with regression tests — `tests/models/ElementConfigRegistry.test.ts` |
| 119 | + and `tests/models/EmbeddedTemplate.test.ts` are the existing surface. |
| 120 | +4. If option A: verify token injection end-to-end in a preview, not just in a |
| 121 | + unit test. That is the specific gap that let this sit unnoticed. |
| 122 | + |
| 123 | +## Success criteria |
| 124 | + |
| 125 | +- [ ] One of A/B/C chosen, with the reasoning recorded |
| 126 | +- [ ] No shipped code references a CSS custom property that nothing defines |
| 127 | +- [ ] No exported class that nothing constructs |
| 128 | +- [ ] `npm run test:ci` green, `npm run typecheck:editor` clean |
| 129 | +- [ ] If tokens survive: injection verified in a running preview via CDP |
| 130 | + |
| 131 | +## References |
| 132 | + |
| 133 | +- `packages/noodl-viewer-react/src/style-tokens-injector.ts` — the uninstantiated injector |
| 134 | +- `packages/noodl-editor/src/editor/src/models/StyleTokens/DefaultTokens.ts` — the 10 shipped tokens |
| 135 | +- `packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/` — the configs, and the vocabulary they expect |
| 136 | +- `packages/noodl-editor/src/editor/src/views/NodePicker/NodePicker.utils.ts` — where `applyDefaults` fires |
| 137 | +- [MERGE-NOTES-cline-dev-tara.md](../../reviews/MERGE-NOTES-cline-dev-tara.md) — how this arrived unverified |
| 138 | +- [REV-008-DEV-LOOP-HARDENING.md](./REV-008-DEV-LOOP-HARDENING.md) — Stream D, which surfaced it |
| 139 | +- `dev-docs/tasks/phase-9-styles-overhaul/` — the original STYLE-001/002 design intent |
0 commit comments