baldart 4.69.1 → 4.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +2 -2
- package/VERSION +1 -1
- package/framework/.claude/agents/code-reviewer.md +9 -0
- package/framework/.claude/agents/visual-fidelity-verifier.md +17 -1
- package/framework/.claude/skills/ds-edit/SKILL.md +184 -0
- package/framework/.claude/skills/e2e-review/SKILL.md +58 -6
- package/framework/.claude/skills/new/references/implement.md +6 -1
- package/framework/.claude/skills/prd/references/ui-design-phase.md +11 -0
- package/framework/agents/component-manifest-schema.md +3 -0
- package/framework/agents/design-review.md +3 -0
- package/framework/agents/design-system-protocol.md +32 -0
- package/framework/agents/index.md +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ All notable changes to BALDART will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.71.0] - 2026-06-25
|
|
9
|
+
|
|
10
|
+
**Responsive-awareness in UI review — catch a viewport-scoped edit that regresses the *other* viewport.** When an agent works on one viewport (fix the mobile header, tweak the desktop table), nothing today catches it silently shifting the viewport it was *not* editing. The obvious fix — cloning the i18n ESLint gate into a `responsive-gate` that bans raw `matchMedia`/breakpoint literals — was **refuted** by an adversarial pass: that gate is blind to where responsiveness actually lives (Tailwind `md:` classes, CSS, CSS-in-JS — not `window.matchMedia`), so it is mayo-specific opinion, not a distributable mechanism. The real driver is served by **reactivating machinery that already exists and was inert**: `visual-fidelity-verifier` has had a `responsiveness-break` finding all along, but `/e2e-review` only ever screenshotted **one** viewport (1440px), so it could never fire.
|
|
11
|
+
|
|
12
|
+
**MINOR** — adds review capability; **no new config key** (rides on `features.has_e2e_review` + `features.has_design_system`), no schema-change propagation. The mobile viewport is fixed at 375px (the canonical small-screen audit width). Degrades to no-op on consumers without e2e-review. The per-route cost was **measured** on a real verifier run before shipping default-on: ~one extra verifier call per renderable route (~0.3% of a card run — the 375px screenshot is lighter than the 1440px one, and only renderable routes incur it).
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **`/e2e-review` captures both viewports + runs a mobile responsive-integrity pass** (`framework/.claude/skills/e2e-review/SKILL.md`). Phase 3 now captures `<route-slug>.png` (desktop 1440×900, **unchanged path** — all existing consumers intact) AND `<route-slug>@mobile.png` (375×812), setting the viewport before navigating so SSR/responsive hooks render for that width. Phase 4 adds a second verifier invocation per route with `viewport_role: "mobile"` (step 2b), and the `skip`-level pre-filter no longer suppresses it (the mobile pass needs no mockup). Findings aggregate with `viewport_role` in the dedup key so a mobile `responsiveness-break` stays distinct and the Phase 5 gate / self-heal report show which viewport broke.
|
|
17
|
+
- **`visual-fidelity-verifier` gains a `viewport_role: "mobile"` responsive-integrity mode** (`framework/.claude/agents/visual-fidelity-verifier.md`). When set, it does NOT diff against the (desktop) mockup — the mobile layout reflows by design — and emits ONLY genuine breakage findings (`responsiveness-break`, `unreachable-action`, `layout-break`), conservatively. Reuses the existing taxonomy + output schema; no new finding codes.
|
|
18
|
+
- **`design-system-protocol.md` adds a "Responsive Scope Discipline" section** — the textual SSOT: (1) a viewport-scoped edit MUST NOT alter the other viewport's branch; (2) a structural/heavy component MUST NOT be swapped across viewports via `display:none`/`visibility`/`hidden`/`@media` CSS hiding (mounts both branches, runs both effect/query sets, ships dead DOM). Stated abstractly — concrete primitive names / breakpoints / any project-local gate live in the consumer's own files, never in the framework. Enforced as a **review check** (the CSS-hidden case is invisible to a JS AST rule), not a lint.
|
|
19
|
+
- **`code-reviewer` enforces it** (rule 9) — structural `display:none` swap = HIGH; viewport-scoped edit that mutates the other branch = MEDIUM. **`design-review.md`** checklist points to the same section. This is the surviving, generalized slice of the responsive work; everything stack-specific (a project's `eslint.responsive.config.mjs`, primitive names) stays a consumer-side project file, never in `.framework/`.
|
|
20
|
+
|
|
21
|
+
## [4.70.0] - 2026-06-25
|
|
22
|
+
|
|
23
|
+
**`/ds-edit` — the deliberate-edit twin of `/ds-new`, completing the single-element lifecycle.** `/ds-new` creates (its reuse-first step STOPS if the element exists); there was no symmetric guided entry to *change* an existing canonical element. "Update a component" decomposes into three cases — two were already covered: the **mechanical doc-resync** after a code change is automatic (serializer regenerates the HEAD from source, preserving agentic + prose; the BLOCKING `DS_COMPONENT_STALE` gate enforces it), and **agentic re-curation** is `doc-reviewer`'s domain. The gap was the **deliberate change with a decision** — add a variant/prop, a breaking change, or re-governing a closed-set role.
|
|
24
|
+
|
|
25
|
+
**MINOR** — adds a skill; no new config key (rides on `features.has_design_system`). A pure orchestrator over the same scripts as `/ds-new` — zero rule duplication, and the SAME canonical template (`framework/templates/component-spec.template.md`).
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- **`/ds-edit` skill** (`framework/.claude/skills/ds-edit/SKILL.md`) — update ONE existing canonical component or token. Pre-flight locates the element (refuses + suggests `/ds-new` if it doesn't exist), then classifies the change via the edit decision tree: **resync** (spec catches up to changed source) / **extend** (new variant/prop — within the role contract, else it's a NEW role = `/ds-new`) / **breaking** (removed/renamed variant or prop → migration + spec Changelog) / **re-govern** (the edit changes `canonical_for`/`use_when`/closure). Delegates the source change to `ui-expert`, the agentic re-verify to `doc-reviewer`, and regenerates the spec via the serializer — which **preserves the existing prose + non-empty agentic fields** (`source_sha` anchor) and fills the canonical template only when a spec is missing, so an edited spec keeps the SAME standardized shape as a created one. Verifies via `ds-gate` + `DS_COMPONENT_STALE`. Codex-portable (deterministic spine zero-subagent; agentic/scaffold steps degrade to TODO). Token edits follow the Token Cascade (rename/removal is breaking — migrate the affected `token_bindings`).
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **`/prd` routes a REUSE+VARIANT extension to `/ds-edit`** (`ui-design-phase.md`, new step 7b) — when the reconciliation gate finds a region maps to an existing component but needs a variant/prop not yet in its spec and the user confirms extending, route to `/ds-edit` (create-now) or a "modify Component X" card (defer) — symmetric to the NEW→`/ds-new` routing. A "variant" that is really a new role is a `NEW (governed)` case, not an extend.
|
|
34
|
+
- **`/new` (ui-expert Post-Intervention) follows the `/ds-edit` discipline for a MODIFIED primitive** (`implement.md`) — re-run the serializer to regenerate the HEAD from the new source (preserving agentic + prose), never hand-edit; a breaking change adds a spec Changelog entry. Registered in `design-system-protocol.md` (Consumers), `component-manifest-schema.md` (Producers), and `agents/index.md` routing. Propagates to `new2` (shared reference modules).
|
|
35
|
+
|
|
8
36
|
## [4.69.1] - 2026-06-24
|
|
9
37
|
|
|
10
38
|
**`/prd` and `/new` now actually USE `/ds-new` when a new STANDARDIZED component is detected** (v4.69.0 only wired it as an opt-in arm + left `/new`'s spec production unspecified). A new canonical element should be materialized through the one discipline, not hand-rolled per surface.
|
package/README.md
CHANGED
|
@@ -211,14 +211,14 @@ Skills always-ask when required keys are missing — never silently default.
|
|
|
211
211
|
never overwrites your file. Full guide:
|
|
212
212
|
[`framework/docs/PROJECT-CONFIGURATION.md`](framework/docs/PROJECT-CONFIGURATION.md).
|
|
213
213
|
|
|
214
|
-
### Skills (
|
|
214
|
+
### Skills (37 portable skills)
|
|
215
215
|
|
|
216
216
|
Skills live under `.claude/skills/` and are auto-discovered by Claude Code.
|
|
217
217
|
Bundled skills:
|
|
218
218
|
|
|
219
219
|
- **Workflow**: `new`, `new2` (v4.16.0 — EXPERIMENTAL workflow-hosted `/new`, Claude-only, for A/B testing context economy), `prd`, `prd-add`, `bug`, `simplify`, `worktree-manager`, `issue-review`, `context-primer`
|
|
220
220
|
- **Code quality**: `skill-creator`, `find-skills`, `webapp-testing`, `playwright-skill`, `lsp-bootstrap` (v3.10.0), `graphify-bootstrap` (v4.21.0 — code knowledge graph), `graph-align` (v4.21.0 — doc↔graph alignment), `toolchain-bootstrap` (v4.41.0 — curated dev toolchain), `e2e-review` (v3.18.0)
|
|
221
|
-
- **Design**: `frontend-design`, `ui-design`, `motion-design`, `gamification-design`, `design-system-init` (v3.11.0 — bulk registry bootstrap/upgrade), `ds-new` (v4.69.0 — single-element guided creation: one component or token, reuse-first → optional scaffold → document + register + govern + verify; the on-the-fly twin of `design-system-init`)
|
|
221
|
+
- **Design**: `frontend-design`, `ui-design`, `motion-design`, `gamification-design`, `design-system-init` (v3.11.0 — bulk registry bootstrap/upgrade), `ds-new` (v4.69.0 — single-element guided creation: one component or token, reuse-first → optional scaffold → document + register + govern + verify; the on-the-fly twin of `design-system-init`), `ds-edit` (v4.70.0 — deliberate edit of one existing element: resync / extend-variant / breaking / re-govern; regenerates the spec preserving agentic fields + prose, same canonical template)
|
|
222
222
|
- **Product**: `seo-audit`, `copywriting`, `api-design-principles`
|
|
223
223
|
- **Knowledge**: `doc-writing-for-rag`, `capture` (LLM wiki overlay)
|
|
224
224
|
- **Internationalization**: `i18n` (v4.52.0 — audit the context registry + context-aware translation into native locale files), `i18n-adopt` (v4.52.0 — one-shot migration that externalizes all hardcoded strings on an existing codebase); both gated on `features.has_i18n`
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.
|
|
1
|
+
4.71.0
|
|
@@ -115,6 +115,15 @@ Concrete enforcement contract for the review pass:
|
|
|
115
115
|
HEAD is NOT `DS_COMPONENT_STALE` merely for that; empty deterministic HEAD
|
|
116
116
|
fields (non-TS stack, unresolved prop) are advisory, never blocking. The HEAD
|
|
117
117
|
is an upgrade target — see `component-manifest-schema.md` § Transition leniency.
|
|
118
|
+
9. **Responsive Scope Discipline** — per [`design-system-protocol.md`](../../agents/design-system-protocol.md)
|
|
119
|
+
§ "Responsive Scope Discipline": (a) a structural/heavy component swapped
|
|
120
|
+
across viewports via `display:none` / `visibility:hidden` / `hidden` / `@media`
|
|
121
|
+
CSS hiding (mounts both branches, runs both effect/query sets, ships dead DOM)
|
|
122
|
+
is **HIGH**; (b) a viewport-scoped edit that also mutates the *other* viewport's
|
|
123
|
+
branch (e.g. a "mobile only" change that shifts the desktop layout) is
|
|
124
|
+
**MEDIUM**. Token-level per-breakpoint restyling of a single element is fine —
|
|
125
|
+
only whole-tree `display:none` swaps trip (a). This is a review judgement, not a
|
|
126
|
+
lint (the CSS-hidden case is invisible to a JS AST rule).
|
|
118
127
|
|
|
119
128
|
When `features.has_design_system: false`, the registry reads are skipped but
|
|
120
129
|
the review still flags hardcoded values and inconsistencies against
|
|
@@ -63,6 +63,7 @@ The orchestrator (`/e2e-review`) invokes you with this JSON payload:
|
|
|
63
63
|
"card_id": "FEAT-XXXX",
|
|
64
64
|
"route": "/dashboard",
|
|
65
65
|
"viewport": { "width": 1440, "height": 900 },
|
|
66
|
+
"viewport_role": "desktop" | "mobile", // optional, default "desktop"
|
|
66
67
|
"implementation_screenshot_path": "/abs/path/to/impl.png",
|
|
67
68
|
"mockup_source": {
|
|
68
69
|
"level": "figma" | "local" | "compliance-only" | "skip",
|
|
@@ -81,7 +82,22 @@ The orchestrator (`/e2e-review`) invokes you with this JSON payload:
|
|
|
81
82
|
```
|
|
82
83
|
|
|
83
84
|
If `mockup_source.level == "skip"`, return immediately with
|
|
84
|
-
`{ "status": "skipped", "reason": "no_mockup_available", "findings": [] }
|
|
85
|
+
`{ "status": "skipped", "reason": "no_mockup_available", "findings": [] }` —
|
|
86
|
+
**unless** `viewport_role == "mobile"`, in which case run the responsive-integrity
|
|
87
|
+
pass below (it needs no mockup).
|
|
88
|
+
|
|
89
|
+
**`viewport_role: "mobile"` — responsive-integrity pass.** When set, you are
|
|
90
|
+
looking at the **mobile render** (a narrow viewport, typically 375px). Mobile
|
|
91
|
+
mockups are rarely provided, and the mobile layout *correctly* reflows away from
|
|
92
|
+
any desktop mockup — so in this mode you **do NOT diff against a mockup** and you
|
|
93
|
+
do **NOT** emit fidelity findings (`element-order`, `spacing-off-scale`,
|
|
94
|
+
`typography-*`, `color-*` relative to a desktop design). Evaluate the mobile
|
|
95
|
+
screenshot on its own and flag **only genuine viewport breakage**:
|
|
96
|
+
`responsiveness-break` (horizontal scroll past the viewport, content cut off,
|
|
97
|
+
elements overlapping/unreadable), `unreachable-action` (primary CTA off-screen or
|
|
98
|
+
behind a fixed overlay), and `layout-break` (a container that genuinely collapsed,
|
|
99
|
+
not an intended stack). Be conservative: a dense-but-legible layout is **not** a
|
|
100
|
+
break — flag only hard failures a user would hit. Return the same output schema.
|
|
85
101
|
|
|
86
102
|
**`resolved_orphans` carve-out (Functional Traceability Gate).** The mockup is a
|
|
87
103
|
fidelity target, not a requirements oracle: it may contain interactive chrome that
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ds-edit
|
|
3
|
+
effort: medium
|
|
4
|
+
description: >
|
|
5
|
+
Update ONE existing canonical design-system element correctly — the deliberate
|
|
6
|
+
edit twin of /ds-new. Classifies the change (resync the spec to changed source /
|
|
7
|
+
extend with a new variant or prop / breaking change with migration / re-govern
|
|
8
|
+
the closed-set role) and runs it end to end: apply the source change (delegated
|
|
9
|
+
to ui-expert), regenerate the spec via the serializer (HEAD from source, agentic
|
|
10
|
+
+ prose PRESERVED, the canonical template
|
|
11
|
+
framework/templates/component-spec.template.md filled if a spec is missing),
|
|
12
|
+
re-govern if needed, verify. A THIN orchestrator — delegates every rule to the
|
|
13
|
+
existing SSOTs, never hand-writes a spec HEAD. Use when the user says /ds-edit,
|
|
14
|
+
"aggiorna un componente", "modifica una primitive", "aggiungi una variante",
|
|
15
|
+
"estendi il componente", "resync dello spec", "breaking change su un
|
|
16
|
+
componente", or when `/prd` confirms a REUSE+VARIANT extension. The pure
|
|
17
|
+
mechanical doc-resync after a code change is ALREADY automatic (serializer +
|
|
18
|
+
`DS_COMPONENT_STALE` gate) — this skill is for the DELIBERATE change. Gated on
|
|
19
|
+
features.has_design_system.
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# DS Edit — update one existing canonical element
|
|
23
|
+
|
|
24
|
+
The deliberate-edit twin of `/ds-new`. `/ds-new` creates (its reuse-first step
|
|
25
|
+
STOPS if the element exists); this skill takes an element that **already exists**
|
|
26
|
+
and changes it with the right discipline. It is a conductor: each step DELEGATES
|
|
27
|
+
to an existing module and cross-pointers to it — **no schema/closed-set/token rule
|
|
28
|
+
is re-described here**, and the spec is always **serializer-emitted, never
|
|
29
|
+
hand-written**.
|
|
30
|
+
|
|
31
|
+
**What this skill is NOT for.** The *mechanical doc-resync* after a code change
|
|
32
|
+
(props/variants changed, no decision) is already automatic: the serializer
|
|
33
|
+
regenerates the deterministic HEAD from the new source (preserving agentic +
|
|
34
|
+
prose) and the BLOCKING `DS_COMPONENT_STALE` gate (Post-Intervention Coherence
|
|
35
|
+
Check) enforces it. Use this skill for a **deliberate** change with a decision.
|
|
36
|
+
|
|
37
|
+
## Project Context
|
|
38
|
+
|
|
39
|
+
**Reads from `baldart.config.yml`:** `paths.design_system`,
|
|
40
|
+
`paths.components_primitives`, `paths.components_root`, `paths.design_tokens`,
|
|
41
|
+
`design_tokens.outputs`, `paths.ui_guidelines`, `identity.brand_name`,
|
|
42
|
+
`git.trunk_branch`.
|
|
43
|
+
|
|
44
|
+
**Writes:** the changed source (via `ui-expert`), the regenerated
|
|
45
|
+
`${paths.design_system}/components/<Name>.md` + INDEX + Selection Policy, and —
|
|
46
|
+
when tokens change — the DTCG source + regenerated outputs. Source-read-only by
|
|
47
|
+
default; source edits are delegated to `ui-expert`.
|
|
48
|
+
|
|
49
|
+
**Schema + template:** the frontmatter HEAD is defined in
|
|
50
|
+
`framework/agents/component-manifest-schema.md` and is **emitted by the
|
|
51
|
+
serializer, never hand-written**. The standardized prose body is the canonical
|
|
52
|
+
template `framework/templates/component-spec.template.md` — the SAME template
|
|
53
|
+
`/ds-new` uses. On regeneration the serializer **preserves existing prose +
|
|
54
|
+
non-empty agentic fields** (`source_sha` anchor) and only fills the template when
|
|
55
|
+
a component has no prose body yet. The edit rules are the SSOT in
|
|
56
|
+
`framework/agents/design-system-protocol.md` (Post-Intervention Coherence Check,
|
|
57
|
+
§ Closed-Set Selection Policy, § Token Contract).
|
|
58
|
+
|
|
59
|
+
**Gated by features:** `features.has_design_system` (BLOCKING). When `false`,
|
|
60
|
+
REFUSE.
|
|
61
|
+
|
|
62
|
+
**Overlay:** loads `.baldart/overlays/ds-edit.md` if present.
|
|
63
|
+
|
|
64
|
+
**On missing keys:** ask the user; do not assume defaults. See
|
|
65
|
+
`framework/agents/project-context.md` § 3.
|
|
66
|
+
|
|
67
|
+
## Effort
|
|
68
|
+
|
|
69
|
+
**Baseline:** `effort: medium` (frontmatter). **Inline override:** pass
|
|
70
|
+
`effort=<low|medium|high|xhigh|max>` anywhere in the invocation. Mapping +
|
|
71
|
+
parsing contract: `framework/agents/effort-protocol.md`.
|
|
72
|
+
|
|
73
|
+
## Invocation
|
|
74
|
+
|
|
75
|
+
`/ds-edit <Name>` (component) · `/ds-edit token <id>` (token) · `/ds-edit` (ask).
|
|
76
|
+
Optionally state the change (e.g. "add variant `compact`", "remove `size=xl`",
|
|
77
|
+
"resync"). When called by `/prd` (the reconciliation gate's REUSE+VARIANT branch),
|
|
78
|
+
the target component + intended variant are pre-resolved.
|
|
79
|
+
|
|
80
|
+
## Pre-flight
|
|
81
|
+
|
|
82
|
+
- **P0 — gate.** `features.has_design_system: false` → REFUSE.
|
|
83
|
+
- **P1 — locate.** Resolve the existing component (`${paths.design_system}/components/<Name>.md`
|
|
84
|
+
+ its `source`). If it does NOT exist → STOP and suggest `/ds-new` (this skill
|
|
85
|
+
edits; it does not create).
|
|
86
|
+
- **P2 — classify the change** (the edit decision tree; ask the user when unclear):
|
|
87
|
+
- **resync** — the source already changed (props/variants/a11y); only the spec
|
|
88
|
+
needs to catch up. (Often you don't even need this skill — see "What this skill
|
|
89
|
+
is NOT for".)
|
|
90
|
+
- **extend** — add a variant / prop / slot. Decide: does it stay WITHIN the
|
|
91
|
+
component's role contract (→ extend in place), or is it really a NEW role (→
|
|
92
|
+
that is `/ds-new` + a governance/closed-set decision, not an in-place edit)?
|
|
93
|
+
- **breaking** — remove/rename a variant or prop, or change a default. Requires a
|
|
94
|
+
migration plan + a spec Changelog entry (DELEGATE `templates/breaking-change-checklist.md`).
|
|
95
|
+
- **re-govern** — the change alters `canonical_for` / `use_when` / closure.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Component edit path
|
|
100
|
+
|
|
101
|
+
Each step is a delegation. Read the cited SSOT; do not paraphrase it.
|
|
102
|
+
|
|
103
|
+
1. **Read the current spec + source.** Read the component HEAD (agentic fields to
|
|
104
|
+
PRESERVE) + prose body + its `source`. Establish the baseline before changing.
|
|
105
|
+
2. **Apply the source change (conditional).** *extend / breaking* → DELEGATE
|
|
106
|
+
`ui-expert` (Task tool) to modify the source under
|
|
107
|
+
`${paths.components_primitives}/<Name>` (tokens-compliant; its Token Contract +
|
|
108
|
+
Functional Traceability pre-work apply). *resync* → the source already changed;
|
|
109
|
+
skip. The skill itself NEVER writes component source. Codex (no subagents) →
|
|
110
|
+
describe the required source change as a TODO and require the user to apply it.
|
|
111
|
+
3. **Re-extract the deterministic HEAD.**
|
|
112
|
+
`node .framework/framework/.claude/skills/design-system-init/scripts/extract-one.mjs --source <path.tsx> --json`
|
|
113
|
+
→ the updated `props` / `variants` / `composes` / `source_sha` from the new source.
|
|
114
|
+
4. **Re-verify the agentic fields.** DELEGATE `doc-reviewer` to update ONLY what the
|
|
115
|
+
change affects (`must_rules` / `a11y` / `token_bindings` / `purpose`) and keep the
|
|
116
|
+
rest. Existing values are preserved by the serializer; never blank a field you
|
|
117
|
+
did not deliberately change. Codex → carry the existing values forward + TODO.
|
|
118
|
+
5. **Re-govern (conditional).** When the edit changes the role: update
|
|
119
|
+
`canonical_for` / `use_when` / `selection_closed` per `design-system-protocol.md`
|
|
120
|
+
§ Closed-Set Selection Policy + § Governance. **A variant added to a `closed`
|
|
121
|
+
family member is fine IF it stays within the role; a change that creates a NEW
|
|
122
|
+
role/standard is a governance decision** — flag it, don't self-approve.
|
|
123
|
+
For a **breaking** change, add a spec Changelog entry + a migration note.
|
|
124
|
+
6. **Regenerate the spec (standardized, agentic preserved).** Build a 1-component
|
|
125
|
+
bundle with the updated fields, merged with the HEADs of ALL existing components
|
|
126
|
+
(so the regenerated `--index` + Selection Policy stay complete), and run:
|
|
127
|
+
```
|
|
128
|
+
node .framework/framework/.claude/skills/design-system-init/scripts/serialize-spec.mjs \
|
|
129
|
+
--bundle <bundle.json> --out-dir ${paths.design_system}/components \
|
|
130
|
+
--index ${paths.design_system}/INDEX.md --brand "${identity.brand_name}" \
|
|
131
|
+
--tokens ${paths.design_tokens} --verify-usage
|
|
132
|
+
```
|
|
133
|
+
The serializer regenerates the valid-YAML HEAD from the new fields, **preserves
|
|
134
|
+
the existing prose body verbatim** (no clobber), and fills the canonical template
|
|
135
|
+
`framework/templates/component-spec.template.md` ONLY if this component had no
|
|
136
|
+
prose yet — the SAME standardized shape as `/ds-new`. Self-validates, fails closed.
|
|
137
|
+
Review `droppedBindings` / `unverifiedBindings`.
|
|
138
|
+
7. **Verify.** Serializer exit 0. Run `npx baldart ds-gate --json` — a closed-set
|
|
139
|
+
edit that introduced a new canonical must NOT trip `DS_CLOSED_SET_VIOLATION`. The
|
|
140
|
+
change + the regenerated spec ship in the SAME commit (the `DS_COMPONENT_STALE`
|
|
141
|
+
gate is satisfied by the resync). If a closure changed, the INDEX (with the
|
|
142
|
+
updated Selection Policy) must be committed for `ds-gate` to enforce it.
|
|
143
|
+
8. **Coherence report (never silent).** Emit the protocol's "Registry coherence
|
|
144
|
+
check: N findings" block: spec updated (incl. HEAD), INDEX/policy reconciled,
|
|
145
|
+
tokens reconciled, breaking change documented + migration noted.
|
|
146
|
+
|
|
147
|
+
## Token edit path
|
|
148
|
+
|
|
149
|
+
Edit the DTCG node in `${paths.design_tokens}` → `npx baldart tokens build` →
|
|
150
|
+
round-trip diff surfaced (never auto-accepted) → if a token's id/semantics
|
|
151
|
+
changed, update affected components' `token_bindings` and re-serialize → coherence
|
|
152
|
+
report. A token **rename/removal** is breaking (consumers reference the id) — list
|
|
153
|
+
the affected component bindings + migrate them. DELEGATE `design-system-protocol.md`
|
|
154
|
+
§ Token Cascade + Token Contract; never hand-edit generated output.
|
|
155
|
+
|
|
156
|
+
## Inline fallbacks (portability + fail-safe)
|
|
157
|
+
|
|
158
|
+
- No `Workflow` tool needed (prose-orchestrated).
|
|
159
|
+
- Codex (no subagents): the deterministic spine (`extract-one` → `serialize-spec` →
|
|
160
|
+
`tokens build` → `ds-gate`) runs unchanged; the `ui-expert` source edit + agentic
|
|
161
|
+
re-verify degrade to TODO + a clear note.
|
|
162
|
+
- Older CLI: `baldart ds-gate` / `baldart tokens build` absent → SKIP-with-reason,
|
|
163
|
+
never block. Surface the SKIP.
|
|
164
|
+
|
|
165
|
+
## /prd integration
|
|
166
|
+
|
|
167
|
+
`/prd`'s reconciliation gate (`prd/references/ui-design-phase.md`) classifies a
|
|
168
|
+
region as **REUSE+VARIANT** when an existing component covers it but the mockup
|
|
169
|
+
needs a prop/variant not yet in its spec. On user confirmation, `/prd` routes that
|
|
170
|
+
to **`/ds-edit`** (create-now extend) or a "modify Component X" card (defer) —
|
|
171
|
+
symmetric to how a `NEW (governed)` standard routes to `/ds-new`. `/prd` owns the
|
|
172
|
+
*decision* (reuse-as-is vs extend vs new role); `/ds-edit` executes the *edit*.
|
|
173
|
+
|
|
174
|
+
## See Also
|
|
175
|
+
|
|
176
|
+
- `framework/.claude/skills/ds-new/SKILL.md` — the create twin (shared scripts +
|
|
177
|
+
the SAME canonical template).
|
|
178
|
+
- `framework/templates/component-spec.template.md` — the canonical prose template
|
|
179
|
+
the serializer fills/preserves (the standardized doc shape).
|
|
180
|
+
- `framework/agents/design-system-protocol.md` — Post-Intervention Coherence Check,
|
|
181
|
+
Closed-Set Selection Policy, Token Contract.
|
|
182
|
+
- `framework/agents/component-manifest-schema.md` — the HEAD schema + the
|
|
183
|
+
regeneration contract (preserve agentic, regenerate deterministic).
|
|
184
|
+
- `framework/templates/breaking-change-checklist.md` — for breaking edits.
|
|
@@ -273,14 +273,27 @@ capture the result + screenshots per route.
|
|
|
273
273
|
- Use `page.getByRole()`, `page.getByText()`, `page.getByTestId()` —
|
|
274
274
|
never CSS selectors that depend on Tailwind class strings.
|
|
275
275
|
- Use `expect(locator)` with auto-waiting.
|
|
276
|
-
- For each route in the scenario,
|
|
276
|
+
- For each route in the scenario, capture BOTH viewports (set the viewport
|
|
277
|
+
BEFORE navigating so SSR / responsive hooks render for that width):
|
|
278
|
+
// Desktop — existing path, consumed by Phase 4 / 4b. DO NOT change it.
|
|
279
|
+
await page.setViewportSize({ width: 1440, height: 900 });
|
|
277
280
|
await page.goto(route);
|
|
278
281
|
await page.waitForLoadState("networkidle");
|
|
279
282
|
await page.screenshot({
|
|
280
283
|
path: ".baldart/e2e-review/<CARD-ID>/screenshots/<route-slug>.png",
|
|
281
284
|
fullPage: true
|
|
282
285
|
});
|
|
283
|
-
|
|
286
|
+
// Mobile — additive, enables the responsiveness-break check (Phase 4).
|
|
287
|
+
await page.setViewportSize({ width: 375, height: 812 });
|
|
288
|
+
await page.goto(route);
|
|
289
|
+
await page.waitForLoadState("networkidle");
|
|
290
|
+
await page.screenshot({
|
|
291
|
+
path: ".baldart/e2e-review/<CARD-ID>/screenshots/<route-slug>@mobile.png",
|
|
292
|
+
fullPage: true
|
|
293
|
+
});
|
|
294
|
+
Both screenshot paths are consumed by the visual-fidelity-verifier in
|
|
295
|
+
Phase 4 — do not change them. 375px is the canonical small-screen audit
|
|
296
|
+
width (design-system-protocol Reference Tables); it is fixed, not a config key.
|
|
284
297
|
- For OTP-driven personas (test_plan.test_credentials.auth_method == "otp"),
|
|
285
298
|
use `await page.pause()` between phone-entry and code-entry. Document
|
|
286
299
|
the manual step in a test.step block.
|
|
@@ -309,7 +322,8 @@ capture the result + screenshots per route.
|
|
|
309
322
|
- `status`: `passed` | `failed` | `flaky` | `skipped`
|
|
310
323
|
- `duration_ms`
|
|
311
324
|
- `failure_reason` (when failed, the first assertion error + stack hint)
|
|
312
|
-
- `screenshot_paths[]` (
|
|
325
|
+
- `screenshot_paths[]` (per route: the desktop `<route-slug>.png` AND the
|
|
326
|
+
mobile `<route-slug>@mobile.png`)
|
|
313
327
|
5. **Functional findings**: every `failed` or `flaky` scenario becomes a
|
|
314
328
|
functional finding in the aggregate report (Phase 5). Severity:
|
|
315
329
|
- Auth / payments / data-mutation scenario failed → `critical`
|
|
@@ -336,7 +350,11 @@ For each `route` in `plan.routes[]`:
|
|
|
336
350
|
latency / cost saver — most routes pass pixel diff cleanly.
|
|
337
351
|
- When `mockup_source.level == "compliance-only"`, skip pre-filter (no
|
|
338
352
|
image to compare against) and proceed directly to step 2.
|
|
339
|
-
- When `mockup_source.level == "skip"`, skip
|
|
353
|
+
- When `mockup_source.level == "skip"`, skip the **desktop fidelity diff**
|
|
354
|
+
(steps 2) for this route — but still run the **mobile responsive pass**
|
|
355
|
+
(step 2b) if a `<route-slug>@mobile.png` screenshot was captured, since it
|
|
356
|
+
needs no mockup. Skip the route entirely only when no screenshot exists
|
|
357
|
+
(route unrenderable).
|
|
340
358
|
2. **Invoke `visual-fidelity-verifier`** with the input contract documented
|
|
341
359
|
in [`visual-fidelity-verifier.md`](../../agents/visual-fidelity-verifier.md):
|
|
342
360
|
|
|
@@ -365,12 +383,46 @@ For each `route` in `plan.routes[]`:
|
|
|
365
383
|
verifier from flagging a deliberately-removed orphan affordance as
|
|
366
384
|
`component-missing`. Omit the field (or pass `[]`) when the inventory has no
|
|
367
385
|
resolved orphans.
|
|
386
|
+
2b. **Mobile responsive-integrity pass.** Invoke the verifier a **second** time
|
|
387
|
+
for the same route with the mobile screenshot, so its `responsiveness-break`
|
|
388
|
+
check (which never fires on a desktop-only screenshot) can run. This is what
|
|
389
|
+
catches a viewport-scoped edit that regresses the *other* viewport:
|
|
390
|
+
|
|
391
|
+
```
|
|
392
|
+
subagent_type: "visual-fidelity-verifier"
|
|
393
|
+
prompt: |
|
|
394
|
+
Compare the implementation against the mockup and return JSON per your
|
|
395
|
+
output schema.
|
|
396
|
+
|
|
397
|
+
Input payload:
|
|
398
|
+
{
|
|
399
|
+
"card_id": "FEAT-XXXX",
|
|
400
|
+
"route": "/dashboard",
|
|
401
|
+
"viewport": { "width": 375, "height": 812 },
|
|
402
|
+
"viewport_role": "mobile",
|
|
403
|
+
"implementation_screenshot_path": ".baldart/e2e-review/FEAT-XXXX/screenshots/<route-slug>@mobile.png",
|
|
404
|
+
"mockup_source": { "level": "skip" },
|
|
405
|
+
"tolerance": "<from config>"
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
`viewport_role: "mobile"` puts the verifier in responsive-integrity mode: it
|
|
409
|
+
does NOT diff against the desktop mockup (the mobile layout reflows by design)
|
|
410
|
+
and emits ONLY genuine breakage findings (`responsiveness-break`,
|
|
411
|
+
`unreachable-action`, `layout-break`). Run this pass on every renderable route
|
|
412
|
+
(a desktop screenshot exists); skip it only when the route is explicitly marked
|
|
413
|
+
desktop-only in the plan. Cost is ~one extra verifier call per route — measured
|
|
414
|
+
marginal (~0.3% of a card run) because the 375px screenshot is lighter than the
|
|
415
|
+
1440px one and only renderable routes incur it.
|
|
368
416
|
3. **Parse the agent's JSON response** strictly. If the response is malformed
|
|
369
417
|
or contains prose outside the JSON, log
|
|
370
418
|
`verifier_protocol_violation` in `gaps[]` and treat the route's findings
|
|
371
419
|
as empty (do not invent findings from prose).
|
|
372
|
-
4. **Aggregate** visual findings across all routes into a single
|
|
373
|
-
`visual_findings[]` array, deduplicating by `(route, category,
|
|
420
|
+
4. **Aggregate** visual findings from BOTH passes across all routes into a single
|
|
421
|
+
`visual_findings[]` array, deduplicating by `(route, viewport_role, category,
|
|
422
|
+
region)` — `viewport_role` keeps a mobile `responsiveness-break` distinct from
|
|
423
|
+
any desktop finding on the same route. Tag each mobile-pass finding with
|
|
424
|
+
`viewport_role: "mobile"` so the Phase 5 gate and self-heal report show which
|
|
425
|
+
viewport broke.
|
|
374
426
|
|
|
375
427
|
---
|
|
376
428
|
|
|
@@ -209,7 +209,12 @@
|
|
|
209
209
|
`use_when` / `selection_closed` per `design-system-protocol.md § Closed-Set
|
|
210
210
|
Selection Policy` (a closure is a governance decision — flag it, don't self-approve).
|
|
211
211
|
A genuinely surface-specific one-off (`scope: local`) may use a lighter spec, but
|
|
212
|
-
still tokens-compliant + INDEX-registered.
|
|
212
|
+
still tokens-compliant + INDEX-registered. **A MODIFIED existing primitive (you
|
|
213
|
+
changed its props/variants/visual) follows the `/ds-edit` discipline**
|
|
214
|
+
(`framework/.claude/skills/ds-edit/SKILL.md`): re-run the serializer to regenerate
|
|
215
|
+
the HEAD from the new source — it **preserves the existing agentic fields + prose**
|
|
216
|
+
and only fills the template when a spec is missing — never hand-edit the HEAD. A
|
|
217
|
+
breaking change (removed/renamed variant or prop) adds a spec Changelog entry.
|
|
213
218
|
- `${paths.design_system}/tokens-reference.md` — add / update token entries
|
|
214
219
|
when introducing new semantic tokens. Drift code: `DS_TOKENS_DRIFT`.
|
|
215
220
|
|
|
@@ -206,6 +206,17 @@ Before invoking `ui-design`:
|
|
|
206
206
|
the *creation* — no rule is duplicated. (Offline / non-interactive `/prd`: record
|
|
207
207
|
the `/ds-new` create-now intent for the standard so it is not silently deferred.)
|
|
208
208
|
|
|
209
|
+
7b. **Extend an existing element — `REUSE+VARIANT`.** When the mockup maps to an
|
|
210
|
+
existing component but needs a prop/variant not yet in its spec, and the user
|
|
211
|
+
confirmed extending it (rather than reuse-as-is or a new role): route to
|
|
212
|
+
**`/ds-edit`** (create-now extend) with the target + intended variant, OR a
|
|
213
|
+
"modify Component X: add variant Y" card (bind-and-defer) — symmetric to 7's
|
|
214
|
+
NEW→`/ds-new` routing. `/ds-edit` applies the source change (via `ui-expert`) +
|
|
215
|
+
regenerates the standardized spec (serializer, agentic preserved) + re-governs if
|
|
216
|
+
the role changes. If the "variant" is really a NEW role, it is a `NEW (governed)`
|
|
217
|
+
case (step 7), not an extend. A pure doc-resync (source already changed, no
|
|
218
|
+
decision) needs no skill — the `DS_COMPONENT_STALE` gate + serializer handle it.
|
|
219
|
+
|
|
209
220
|
Pass the resolved inventory to `ui-design`:
|
|
210
221
|
|
|
211
222
|
```
|
|
@@ -196,6 +196,9 @@ This keeps consumers that have not yet upgraded (and non-TS stacks) from becomin
|
|
|
196
196
|
- **Single-element create**: `/ds-new` (one component or token, on-the-fly or
|
|
197
197
|
called by `/prd`; same scripts — `extract-one`/`serialize-spec` — as the bulk
|
|
198
198
|
skill, so the HEAD it writes is identical).
|
|
199
|
+
- **Single-element edit**: `/ds-edit` (update one existing component/token —
|
|
200
|
+
resync / extend / breaking / re-govern; regenerates the HEAD from the new source
|
|
201
|
+
via the same scripts, **preserving non-empty agentic fields + prose**).
|
|
199
202
|
- **Per-task write**: `ui-expert` / `ui-design` / `frontend-design` in the
|
|
200
203
|
Post-Intervention Coherence Check — a new/modified primitive regenerates its
|
|
201
204
|
HEAD in the same change.
|
|
@@ -73,6 +73,9 @@ recommend `/design-system-init`.
|
|
|
73
73
|
- [ ] No horizontal scroll on mobile
|
|
74
74
|
- [ ] Touch targets minimum 44x44px
|
|
75
75
|
- [ ] Content hierarchy clear
|
|
76
|
+
- [ ] Responsive Scope Discipline (design-system-protocol.md § "Responsive Scope
|
|
77
|
+
Discipline"): no structural component swapped via `display:none`; a
|
|
78
|
+
viewport-scoped change does not regress the other viewport
|
|
76
79
|
|
|
77
80
|
### Interaction Design
|
|
78
81
|
|
|
@@ -545,6 +545,37 @@ implemented (or is about to be) without a traceable function. HIGH severity:
|
|
|
545
545
|
it ships dead code and erodes the minimalism contract. The fix is always one of
|
|
546
546
|
the three outcomes above, never "leave it, it matches the mockup".
|
|
547
547
|
|
|
548
|
+
## Responsive Scope Discipline
|
|
549
|
+
|
|
550
|
+
A UI surface usually renders across viewports (mobile / tablet / desktop). Two
|
|
551
|
+
rules keep responsive work from regressing the viewport you are *not* editing —
|
|
552
|
+
the framework states them abstractly; the concrete primitive names, breakpoint
|
|
553
|
+
values and any project-specific gate live in the consumer's own files (CLAUDE.md,
|
|
554
|
+
overlays, a project-local linter), never here.
|
|
555
|
+
|
|
556
|
+
1. **Viewport-scoped edits stay scoped.** When a change targets one viewport
|
|
557
|
+
(e.g. "fix the mobile header"), it MUST NOT alter the other viewport's branch.
|
|
558
|
+
Editing the mobile path and silently shifting the desktop layout — or vice
|
|
559
|
+
versa — is a regression even when the targeted viewport looks correct. Verify
|
|
560
|
+
both viewports before declaring the task done (`/e2e-review` renders at 1440px
|
|
561
|
+
and 375px and runs the `responsiveness-break` check at each).
|
|
562
|
+
|
|
563
|
+
2. **No structural component swapped via `display:none`.** A DOM-structural or
|
|
564
|
+
heavy component (one that mounts a non-trivial subtree, fetches data, or has
|
|
565
|
+
expensive children) MUST NOT be shown/hidden across viewports via
|
|
566
|
+
`display:none` / `visibility:hidden` / a `hidden` attribute / `@media` CSS
|
|
567
|
+
hiding. Mounting both branches and hiding one ships dead DOM, runs *both*
|
|
568
|
+
components' effects and queries, and doubles the work on every render. Render
|
|
569
|
+
only the active branch (a viewport hook / conditional render) instead.
|
|
570
|
+
Token-level responsive styling — a single element restyled per breakpoint
|
|
571
|
+
(padding, font-size, direction) — is fine; it is *swapping whole component
|
|
572
|
+
trees* via `display:none` that this rule rejects.
|
|
573
|
+
|
|
574
|
+
Enforcement is a **review check** (`code-reviewer`, `/design-review`), not a lint:
|
|
575
|
+
the most damaging case (a CSS-hidden heavy subtree) is invisible to a JS AST rule.
|
|
576
|
+
Rule 2 violations are HIGH; a viewport-scoped edit that mutates the other branch
|
|
577
|
+
(rule 1) is MEDIUM.
|
|
578
|
+
|
|
548
579
|
## Post-Intervention Coherence Check (BLOCKING completion gate)
|
|
549
580
|
|
|
550
581
|
The BLOCKING pre-work above enforces *reads* before any UI change. This
|
|
@@ -658,6 +689,7 @@ The following files reference this module instead of duplicating its rules:
|
|
|
658
689
|
- `framework/.claude/skills/frontend-design/SKILL.md`
|
|
659
690
|
- `framework/.claude/skills/design-system-init/SKILL.md` (bulk registry bootstrap/upgrade)
|
|
660
691
|
- `framework/.claude/skills/ds-new/SKILL.md` (single-element guided creation)
|
|
692
|
+
- `framework/.claude/skills/ds-edit/SKILL.md` (single-element guided edit — resync / extend / breaking / re-govern)
|
|
661
693
|
- `framework/.claude/commands/design-review.md`
|
|
662
694
|
- `framework/agents/design-review.md`
|
|
663
695
|
|
|
@@ -22,6 +22,7 @@ Route agents to the right module with minimal reading.
|
|
|
22
22
|
- If touching ANY visual surface (component, page, mockup, design review) and `features.has_design_system: true` -> read `agents/design-system-protocol.md` and treat the BLOCKING cascade (`${paths.design_system}/INDEX.md` + `tokens-reference.md` + `components/<Name>.md`) as mandatory pre-work. When the flag is `false`, recommend `/design-system-init` to scaffold a registry.
|
|
23
23
|
- If a UI change might INTRODUCE a component (designing from a mockup, building a new primitive) and `features.has_design_system: true` -> read `agents/design-system-protocol.md` § "Closed-Set Selection Policy": query the registry by ROLE (`INDEX.md` § Selection Policy), reuse the canonical member of any `closed` family, honor the card's `component_bindings`, and run `baldart ds-gate` (a `DS_CLOSED_SET_VIOLATION` — a new canonical in a closed family, the "third header" failure mode — BLOCKS). A new member of a closed family is a governance decision (`/prd` reconciliation + ADR), never an implementation act.
|
|
24
24
|
- If creating ONE new canonical design-system element on-the-fly (a component or a token) and `features.has_design_system: true` -> use the `/ds-new` skill (reuse-first → optional scaffold via `ui-expert` → document + register + govern + verify); it produces the standardized spec by filling `framework/templates/component-spec.template.md` via the serializer, never hand-writing a HEAD. The bulk analogue (whole registry) is `/design-system-init`.
|
|
25
|
+
- If EDITING one existing design-system element (add a variant/prop, breaking change, re-govern, or resync the spec) and `features.has_design_system: true` -> use the `/ds-edit` skill (classify the change → apply source via `ui-expert` → regenerate the spec via the serializer, PRESERVING agentic fields + prose, same canonical template as `/ds-new` → verify). The pure mechanical doc-resync after a code change is already automatic (serializer + `DS_COMPONENT_STALE` gate); `/ds-edit` is for the deliberate change.
|
|
25
26
|
- If CREATING, UPDATING, or READING a per-component spec (`${paths.design_system}/components/<Name>.md`) -> read `agents/component-manifest-schema.md` for the machine-readable frontmatter HEAD (deterministic-from-TS + agentic fields) and the on-demand read contract (INDEX router → frontmatter-first, prose only when modifying). The drift codes + gate stay in `design-system-protocol.md`.
|
|
26
27
|
- If touching design-review workflows or UI guidelines -> read `agents/design-review.md` and project-specific UI guidelines.
|
|
27
28
|
- If touching architecture, auth, or tech stack -> read `agents/architecture.md`.
|