Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fca1ceb
docs(aidd-ui): frame the ui plugin rework
blafourcade Oct 30, 2026
67b659c
docs(aidd-ui): specify the ui plugin rework and its roadmap
blafourcade Oct 30, 2026
9db5c88
docs(aidd-ui): plan the ui foundation validator
blafourcade Oct 30, 2026
4c35090
feat(aidd-ui): validate ui records, tokens, renders and code links on…
blafourcade Oct 30, 2026
d15bb41
fix(aidd-ui): read real-world records and stylesheets without false a…
blafourcade Oct 30, 2026
df6b4da
fix(aidd-ui): reject code roots outside the project and report unread…
blafourcade Oct 30, 2026
125ad7c
feat(aidd-ui): fit the ui format to a real component library
blafourcade Oct 30, 2026
eecbe0b
fix(aidd-ui): fit the format to two real design systems
blafourcade Oct 30, 2026
1e1f076
fix(aidd-ui): hand problems back on Codex and Copilot, not only Claud…
blafourcade Oct 30, 2026
1ed8965
fix(aidd-ui): say the write was saved when handing problems back
blafourcade Oct 31, 2026
8920c9b
docs(aidd-ui): note that codex shows a handed-back problem as a block…
blafourcade Oct 31, 2026
645ba0c
fix(aidd-ui): hand problems back at turn end, one feedback shape per …
blafourcade Oct 31, 2026
37d93a7
fix(aidd-ui): declare the Stop hook the turn-end check runs on
blafourcade Oct 31, 2026
34137f5
docs(aidd-ui): state the hosts that get the feedback and the turn-end…
blafourcade Oct 31, 2026
71e422e
fix(aidd-ui): create the turn mark exclusively, never through a plant…
blafourcade Oct 31, 2026
6a4642d
docs(aidd-ui): state which hosts get the hook's answer in the roadmap
blafourcade Oct 31, 2026
2d1c432
docs(aidd-ui): settle the format decisions the later pull requests bu…
blafourcade Oct 31, 2026
47d5918
fix(aidd-ui): keep every check speaking when one fails
blafourcade Oct 31, 2026
231fa1c
feat(aidd-ui): separate design status from the version the code imple…
blafourcade Oct 31, 2026
f1a962d
feat(aidd-ui): read themes through the DTCG Resolver and every token …
blafourcade Oct 31, 2026
836b71f
feat(aidd-ui): give each problem its rule and severity, and scope wha…
blafourcade Oct 31, 2026
192368c
fix(aidd-ui): name alias cycles and prove the guards no test held
blafourcade Oct 31, 2026
dfe6e09
refactor(aidd-ui): give every check the record model instead of anoth…
blafourcade Oct 31, 2026
427b411
feat(aidd-ui): run every design system job through one engine command
blafourcade Oct 31, 2026
8c3f0c9
docs(aidd-ui): place the change flow and state the limits still unwri…
blafourcade Oct 31, 2026
3597a21
fix(aidd-ui): read a test file by folder or by name with two anchored…
blafourcade Oct 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ Feature flow, issue-to-PR automation, backlog
<a href="plugins/aidd-ui/README.md">
<img align="right" alt="alpha" src="https://img.shields.io/badge/alpha-cf222e?style=flat-square" />
<h3>🎨 aidd-ui</h3>
1 skill<br />
UI and UX design, smoke test only
1 skill Β· 3 hooks<br />
UI design system, checked on every write
</a>
</td>
<td width="33%" valign="top">
Expand Down
122 changes: 122 additions & 0 deletions aidd_docs/tasks/2026_10/2026_10_30_aidd-ui-foundation/phase-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
status: done
---

# Instruction: Records and history

## Architecture projection

> Tree of the final files. βœ… create Β· ✏️ modify Β· ❌ delete

```txt
.
β”œβ”€β”€ plugins/aidd-ui/hooks/lib/
β”‚ β”œβ”€β”€ markdown.cjs βœ…
β”‚ β”œβ”€β”€ project.cjs βœ…
β”‚ β”œβ”€β”€ records.cjs βœ…
β”‚ └── history.cjs βœ…
└── scripts/__tests__/
β”œβ”€β”€ aidd-ui-records.test.js βœ…
└── fixtures/
β”œβ”€β”€ README.md ✏️
└── aidd-ui/
└── project.js βœ…
```

## Test Scope

| Scenario | Action | Observable outcome | Actor |
| ------------ | ----------------------- | -------------------- | ------------------------------- |
| Setup | `writeProject(tmp)` from `fixtures/aidd-ui/project.js` | a complete valid project: every record kind, tokens, renders, code under `src/ui/` | system |
| Happy path | `records.check(load(tmp))` and `history.check(load(tmp))` | both return `[]` | system |
| Edge case | R1: a record without front matter, or a line that is neither `key: value` nor `key: [a, b]` | one problem naming the file and the line | system |
| Edge case | R2: `kind: widget`, or an atom under `screens/` | one problem: unknown kind, or kind outside its folder | system |
| Edge case | R3: a required key removed, per kind; `status: done`; `interactive: maybe`; asset `type: photo` | one problem naming the missing key or the bad value | system |
| Edge case | R4: `id` differs from the file name; two records with the same `id` | one problem each | system |
| Edge case | R5: `version: 0` or `v2` on an element; `version: 1.0` on `system.md` | one problem each: element integer from 1, system semver | system |
| Edge case | R6: `uses` names an absent id; an atom uses an atom; a molecule uses a composition; a screen uses a screen | one problem each | system |
| Edge case | R7: an interactive component without `hover`, `focus` or `disabled`; a component without `default`; a screen without `default`; an interactive component without `## Keyboard` | one problem each | system |
| Edge case | R8: `status: coded` without `code` | one problem | system |
| Edge case | R9: `deprecated` without `replaced-by`; `replaced-by` absent or deprecated; `replaced-by: none` without `## Deprecation` | one problem each | system |
| Edge case | R10: a non-deprecated record uses a deprecated one | one problem naming both | system |
| Edge case | R11: a screen breakpoint missing from `system.md` | one problem | system |
| Edge case | R12: a journey step naming an absent screen | one problem | system |
| Edge case | R13: a review missing a row for one screen state; `Verdict` not `ok`, `ko` or `pending` | one problem each | system |
| Edge case | R14: `brand.md` without one of its seven headings | one problem naming the heading | system |
| Edge case | R16: `system.md`, `brand.md` or a review with `status: coded` or `deprecated` | one problem: only `proposed` or `validated` | system |
| Edge case | R15: an asset whose `file` is absent | one problem | system |
| Edge case | H1: a versioned record without `## History` | one problem | system |
| Edge case | H2: two rows for version 2, as after a merge of two branches | one problem: two changes claim version 2, renumber | system |
| Edge case | H3: front matter `version` not the highest row; a gap from 1 to 3 | one problem each | system |
| Edge case | H4: `Breaking` neither `yes` nor `no` | one problem | system |
| Edge case | H5: a task with a breaking element row and no major bump in `system.md`; a task with only non-breaking rows whose `system.md` row raises nothing; a task in an element history with no `system.md` row | one problem each, naming the task | system |
| Edge case | H6: a `deprecated` record whose last history row says `Breaking: no` | one problem | system |
| Teardown | remove `tmp` | no file left | system |

## Tasks to do

### `1)` Fixture project

> One complete valid project every phase mutates.

1. Export `writeProject(dir)` writing:
- Every record holds `id`, `kind`, `status`, `version` and a `## History` table (Version, Change, Breaking, Task); every element's first row is task `ds-init`.
- `aidd_docs/ui/system.md`: `id: system`, `kind: system`, `status: validated`, `version: 2.0.0`, `platforms: [web]`, `breakpoints: [mobile, desktop]`, `themes: [light, dark]`, `locales: [fr, ar]`, `directions: [ltr, rtl]`, `code-roots: [src/ui]`, `ignore: [src/ui/tokens.css]`, `libraries: [@radix-ui/react-dialog]`; a `## Breakpoints` table; `## History` rows `1.0.0` for task `ds-init`, `2.0.0` for task `retire-old-button`.
- `aidd_docs/ui/brand.md`: `id: brand`, `kind: brand`, `status: validated`, `version: 1`; headings `## Project`, `## Users`, `## Domain`, `## Platforms`, `## Personality and tone`, `## References`, `## Anti-references`, optional `## Imposed charter`.
- `aidd_docs/ui/tokens.json`: `color.brand.primary` (srgb, dark theme extension), `color.text.default` aliasing it, `space.md` (rem), `border.thin` (`0.0625rem`), `motion.fast` (ms), `font.body` (family list), `font.weight.bold` (700).
- `aidd_docs/ui/assets/icon-search.md` with `icon-search.svg`.
- `aidd_docs/ui/components/`, each with `tokens`, `variants`, `states`, `role` and its `.html` render carrying a `data-variant` per variant, a `data-state` per state, tokens through `var(--...)` only, logical properties only:
- atom `button`: interactive, `role: button`, coded `src/ui/Button.tsx#Button`, variants `primary`, `secondary`, states `default`, `hover`, `focus`, `disabled`, `## Keyboard`.
- molecule `search-field`: interactive, `role: search`, validated, uses `button`, `icon-search`, no code, variants `default`, states `default`, `hover`, `focus`, `disabled`, `## Keyboard`.
- composition `dialog`: interactive, `role: dialog`, coded `package:@radix-ui/react-dialog#Root`, uses `button`, variants `default`, states `default`, `hover`, `focus`, `disabled`, `## Keyboard`.
- atom `old-button`: not interactive, `role: button`, variants `default`, states `default`, deprecated, `replaced-by: button`, history row 2 `Breaking: yes` for task `retire-old-button`.
- `aidd_docs/ui/screens/home.md` (coded, `src/ui/HomePage.tsx#HomePage`, states `default`, `empty`, `loading`, `error`, breakpoints `mobile`, `desktop`, route `/`) with `home.html`.
- `aidd_docs/ui/journeys/onboarding.md` (`## Steps` table: Screen, Action).
- `aidd_docs/ui/reviews/first-pass.md` (`status: proposed`, `scope: system`, `screens: [home]`, `## Verdicts` table: Screen, State, Verdict, Comment, one row per state, one `pending`: the remaining screens are the `pending` rows).
- `src/ui/Button.tsx`, `src/ui/HomePage.tsx`, `src/ui/tokens.css` (ignored, holds hex values).
2. Add the fixture to `scripts/__tests__/fixtures/README.md`.

### `2)` Markdown reading

> Records read the same way everywhere.

1. `markdown.cjs`: front matter between the first two `---` lines into `{key: string | string[]}`, a problem per malformed line; `## ` headings into sections; a section's first table into rows keyed by header.

### `3)` Project loading

> One read of the tree every check shares.

1. `project.cjs`: `load(root)` returns `null` without `aidd_docs/ui/`, else every record with its file, folder, front matter and sections, the raw `tokens.json` text, and the render paths.

### `4)` Record rules

> R1 to R16 hold.

1. `records.cjs`: `check(project)` returns `{file, message}` per broken rule, in rule order.
2. Required keys: every record `id`, `kind`, `status`, `version`; `system.md` `platforms`, `breakpoints`, `themes`, `locales`, `directions`, `code-roots`, `ignore`, `libraries`; component `uses`, `tokens`, `variants`, `states`, `interactive`, `role`; screen `uses`, `states`, `breakpoints`, `route`; journey `persona`; asset `type`, `file`, `alt`; review `scope`, `screens`; `code` only when `coded`; `replaced-by` only when `deprecated`.
3. Folders: `components/` holds atom, molecule, composition; `screens/` screen; `journeys/` journey; `assets/` asset; `reviews/` review; the root holds `system.md`, `brand.md`.

### `5)` History rules

> H1 to H6 hold.

1. `history.cjs`: `check(project)` reads each `## History` table (Version, Change, Breaking, Task) and returns `{file, message}` per broken rule.
2. Bumps: the system row of a task raises the major version over the previous row when any element row of that task says `yes`, else at least the minor.
3. A `deprecated` record's last row says `Breaking: yes`.

### `6)` Tests

> Each rule has the mutation that turns its test red.

1. `aidd-ui-records.test.js`: the Happy path, then one test per Edge case row, each asserting its own message.

## Test acceptance criteria

| Task | Acceptance criteria |
| ---- | -------------------------------- |
| 1 | `writeProject` output passes both checks; the fixture README lists it |
| 2 | a malformed front matter line comes back as a problem with its line |
| 3 | `load` returns `null` without `aidd_docs/ui/` and every record otherwise |
| 4 | each of R1 to R16 has its own message |
| 5 | each of H1 to H6 has its own message, H2 naming the claimed version |
| 6 | reverting any one rule turns exactly its test red |
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
status: done
---

# Instruction: Tokens and renders

## Architecture projection

> Tree of the final files. βœ… create Β· ✏️ modify Β· ❌ delete

```txt
.
β”œβ”€β”€ plugins/aidd-ui/hooks/lib/
β”‚ β”œβ”€β”€ tokens.cjs βœ…
β”‚ └── renders.cjs βœ…
└── scripts/__tests__/
└── aidd-ui-tokens-renders.test.js βœ…
```

## Test Scope

| Scenario | Action | Observable outcome | Actor |
| ------------ | ----------------------- | -------------------- | ------------------------------- |
| Setup | `writeProject(tmp)` | the valid project | system |
| Happy path | `tokens.check(load(tmp))`, `renders.check(load(tmp))` | both `[]` | system |
| Edge case | T1: `tokens.json` not JSON | one problem | system |
| Edge case | T2: a name starting with `$` that is not a reserved key; a name holding `.` | one problem each | system |
| Edge case | T3: a token without `$value`; without any `$type`; with `$type: colour` | one problem each | system |
| Edge case | T4: color `colorSpace: cmyk`; color with two components; `hex: #fff`; dimension `unit: em`; duration `unit: min`; fontWeight `1200`; cubicBezier x `1.5` | one problem each | system |
| Edge case | T5: `{color.missing}`; `{color.brand}` naming a group | one problem each | system |
| Edge case | T6: theme `sepia` absent from `system.md`; a theme value of the wrong shape | one problem each | system |
| Edge case | T7: a component `tokens` entry naming no token | one problem | system |
| Edge case | T8: a dimension token in `px` | one problem: sizes are in `rem` | system |
| Edge case | V1: a component or screen without its `.html` | one problem | system |
| Edge case | V2: a declared variant or state with no `data-variant` or `data-state` in the render | one problem each | system |
| Edge case | V3: `var(--color-missing)` in a render | one problem | system |
| Edge case | V4: `#336699`, `rgb(`, `hsl(` in a render | one problem each, with its line | system |
| Edge case | V6: `16px`, `1.5rem` or `200ms` written in a render | one problem each: only tokens carry values | system |
| Edge case | V5: `margin-left` in a render while `system.md` declares `rtl`; the same with only `ltr` | one problem; none | system |
| Teardown | remove `tmp` | no file left | system |

## Tasks to do

### `1)` Token rules

> T1 to T8 hold.

1. `tokens.cjs`: walk the tree; a key starting with `$` is a property, any other is a group or a token, a token being an object with `$value`.
2. Resolve `$type`: own, else the aliased token's, else the closest group's.
3. Check primitive shapes per the 2025.10 module; for composite types, check only that `$value` exists.
4. Read themes from `$extensions["dev.ai-driven.themes"]`; check names against `system.md` `themes`, values against the token's type.
5. Require `rem` on every dimension token.
6. Export the set of token paths and their CSS names for renders.

### `2)` Render rules

> V1 to V6 hold.

1. `renders.cjs`: require `<id>.html` beside each component and screen record.
2. Find `data-variant="x"` and `data-state="x"` for each declared variant and state.
3. Flag each `var(--x)` with no token, each colour literal (`#` with 3, 4, 6 or 8 hex digits, `rgb(`, `rgba(`, `hsl(`, `hsla(`) with its line, and, when `rtl` is declared, each `margin-left`, `margin-right`, `padding-left`, `padding-right`, `border-left`, `border-right`, `left:`, `right:`, `text-align: left`, `text-align: right`, `float: left`, `float: right`.
4. Flag each number followed by `px`, `rem`, `em`, `ms` or `s` outside `var(...)`; `0` alone passes.
5. Export the colour, unit and physical-property patterns for the code checks.

### `3)` Tests

> Each rule has its mutation.

1. `aidd-ui-tokens-renders.test.js`: the Happy path, then one test per Edge case row.

## Test acceptance criteria

| Task | Acceptance criteria |
| ---- | -------------------------------- |
| 1 | each of T1 to T8 has its own message |
| 2 | each of V1 to V6 has its own message; `ltr` alone allows physical properties |
| 3 | reverting any one rule turns exactly its test red |
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
status: done
---

# Instruction: Code link

## Architecture projection

> Tree of the final files. βœ… create Β· ✏️ modify Β· ❌ delete

```txt
.
β”œβ”€β”€ plugins/aidd-ui/hooks/lib/
β”‚ └── code.cjs βœ…
└── scripts/__tests__/
└── aidd-ui-code.test.js βœ…
```

## Test Scope

| Scenario | Action | Observable outcome | Actor |
| ------------ | ----------------------- | -------------------- | ------------------------------- |
| Setup | `writeProject(tmp)` | the valid project | system |
| Happy path | `code.check(load(tmp))` | `[]` | system |
| Edge case | C1: `code` path absent; export name absent from the file; `code` without `#` | one problem each | system |
| Edge case | C2: `package:left-pad#Pad` not in `libraries` | one problem | system |
| Edge case | C3: `src/ui/Orphan.tsx` linked by no record and under no `ignore` | one problem naming the file | system |
| Edge case | C3: a `proposed` record whose `code` points at an existing file | no problem: the link is optional before `coded`, valid when present | system |
| Edge case | C4: `color: #ff0000` in `src/ui/Button.tsx`; the same in `src/ui/tokens.css` | one problem with its line; none, the file is ignored | system |
| Edge case | C4: `padding: 16px` in a `.css` file under `src/ui/`; the same in a `.tsx` file | one problem; none, units in script files are a stated limit | system |
| Edge case | C5: two records with the same `code` | one problem naming both | system |
| Edge case | C6: `margin-left` in a `.css` file under `src/ui/` while `rtl` is declared | one problem | system |
| Teardown | remove `tmp` | no file left | system |

## Tasks to do

### `1)` Link rules

> C1 and C2 hold.

1. `code.cjs`: split `code` on its last `#`; a `package:` link needs its name in `system.md` `libraries`; any other needs the file under the project root and the export as a whole word in it.

### `2)` Coverage and literals

> C3 to C6 hold.

1. Walk each `code-roots` prefix; flag each file no `code` names and no `ignore` prefix covers.
2. In files with extension `.css`, `.scss`, `.js`, `.jsx`, `.ts`, `.tsx`, `.vue`, `.svelte`, `.html`, outside `ignore`, flag colour literals with their line, with the render pattern.
3. In `.css` and `.scss` files only, flag unit literals and, when `rtl` is declared, physical properties, with the render patterns.
4. Flag two records sharing one `code`.

### `3)` Tests

> Each rule has its mutation.

1. `aidd-ui-code.test.js`: the Happy path, then one test per Edge case row.

## Test acceptance criteria

| Task | Acceptance criteria |
| ---- | -------------------------------- |
| 1 | an absent file, an absent export, a malformed link and an undeclared package each have their own message |
| 2 | an orphan file, a colour literal, a unit literal, a shared link and a physical property each have their own message; an ignored file and a unit in a script file have none |
| 3 | reverting any one rule turns exactly its test red |
Loading
Loading