Skip to content

Commit 64d80ac

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
feat(design): derive contracts from snapshot source and unify findings
1 parent 19943bf commit 64d80ac

52 files changed

Lines changed: 2885 additions & 1139 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/skills/emcn-design-review/SKILL.md‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ argument-hint: "[scope] [fix=true|false]"
88

99
Review the requested product UI scope (default: current changes). When `fix=false`, explain proposed changes without applying them.
1010

11-
1. During UI work, run `bun run check:design --base origin/staging --working-tree` from the repo root, substituting the actual PR target for `origin/staging`. After committing, use `--head HEAD` for the immutable PR comparison. Exit 1 means findings to review; exit 2 means the check failed and must be repaired or reported. CI is warning-only for findings and fails on incomplete analysis.
12-
2. For each new finding or relevant review signal, inspect the cited source, the applicable public EMCN export in `packages/emcn/src/index.ts`, and tokens and recipes in `apps/sim/app/_styles/globals.css`. Reuse a suitable component, prop, variant, or global token when it expresses the design intent. Avoid near-duplicate local colours or overriding EMCN chrome merely for convenience.
13-
3. A genuinely new product treatment may remain an Extra. Explain its visual intent and why existing EMCN or global styling does not fit in the PR. The check does not decide design approval and must not be silenced by adding an arbitrary token, broad exclusion, or fake component wrapper. Ask the designer or engineer when changing a shared recipe would have broad or ambiguous effects.
14-
4. Keep unresolved `unchecked` inputs and inspection failures distinct from proven violations. A quiet diff means no *new detected* debt, not proof of complete visual conformance. Existing debt stays quiet; a new copy can warn. Landing and docs are out of product scope; Monaco presentation, provider branding, and block identity palettes have deliberate exclusions. See `scripts/design-conformance/README.md` for exact rule boundaries.
11+
1. When EMCN, global styles, recipes or design ownership metadata change, run `bun run design:generate` and commit `scripts/design-conformance/contracts.generated.json` with the source. `bun run check:design-generated` checks freshness without writing. Regeneration does not hide the originating design-system finding.
12+
2. During UI work, run `bun run check:design --base origin/staging --working-tree` from the repo root, substituting the actual PR target for `origin/staging`. After committing, use `--head HEAD` for the immutable PR comparison. Exit 1 means findings to review; exit 2 means the check failed and must be repaired or reported. CI is warning-only for findings and fails on incomplete analysis.
13+
3. For each new finding, inspect the cited source, the applicable public EMCN export in `packages/emcn/src/index.ts`, and tokens and recipes in `apps/sim/app/_styles/globals.css`. Reuse a suitable component, prop, variant, or global token when it expresses the design intent. Avoid near-duplicate local colours or overriding EMCN chrome merely for convenience.
14+
4. A genuinely new product treatment may remain an Extra. Explain its visual intent and why existing EMCN or global styling does not fit in the PR. The check does not decide design approval and must not be silenced by adding an arbitrary token, broad exclusion, or fake component wrapper. Ask the designer or engineer when changing a shared recipe would have broad or ambiguous effects.
15+
5. Keep unresolved `unchecked` inputs and inspection failures separate from findings. A quiet diff means no *new detected* debt, not proof of complete visual conformance. Existing debt stays quiet; a new copy can warn. Landing and docs are out of product scope; Monaco presentation, provider branding, and block identity palettes have deliberate exclusions. See `scripts/design-conformance/README.md` for exact rule boundaries.
1516

1617
Do not turn this review into an unrelated whole-codebase cleanup. Preserve intended appearance when migrating product UI and use before/after screenshots when a treatment changes.

‎.agents/skills/ship/SKILL.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ When the user runs `/ship`:
102102
103103
## Committed design check
104104
105+
When central EMCN sources, global styles, recipes or `@designAllow`/`@designProtect` metadata change, run `bun run design:generate`, review the result and commit `contracts.generated.json` alongside the source. `check:design-generated` is part of `check:audits`; stale output is an infrastructure error. Regeneration does not suppress the source finding.
106+
105107
During product UI work, run `bun run check:design --base origin/staging --working-tree` so staged, unstaged and nonignored new files are included. Review findings against EMCN and `globals.css`; explain intentional new Extras rather than weakening the checker. After committing and before **every push**, run this from the repository root with Bun 1.4.1:
106108
107109
```bash

‎.claude/rules/emcn-components.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,7 @@ Declare keyboard intent on the action-owning primitive; never add document-level
5757
- Use Radix UI primitives for accessibility. Export the component and its `variants` (when using CVA). Document with TSDoc + a usage example.
5858

5959
Color tokens and icon-size conventions are canonical in `.claude/rules/sim-styling.md` — follow it rather than restating.
60+
61+
## Generated design contracts
62+
63+
Run `bun run design:generate` after public API, styling, recipe or ownership changes and commit `scripts/design-conformance/contracts.generated.json` with the source. CI checks freshness through `check:design-generated`. Ownership is derived from implementation; intentional customization belongs in component TSDoc (`@designAllow <slot> <CSS properties or policy groups>`, `@designProtect` for ownership that cannot be inferred). Review the diff findings after generation; they retain originating central changes. Browser reports and captures remain local, outside the repository.

‎.cursor/rules/emcn-components.mdc‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,7 @@ Declare keyboard intent on the action-owning primitive; never add document-level
5858
- Use Radix UI primitives for accessibility. Export the component and its `variants` (when using CVA). Document with TSDoc + a usage example.
5959

6060
Color tokens and icon-size conventions are canonical in `.claude/rules/sim-styling.md` — follow it rather than restating.
61+
62+
## Generated design contracts
63+
64+
Run `bun run design:generate` after public API, styling, recipe or ownership changes and commit `scripts/design-conformance/contracts.generated.json` with the source. CI checks freshness through `check:design-generated`. Ownership is derived from implementation; intentional customization belongs in component TSDoc (`@designAllow <slot> <CSS properties or policy groups>`, `@designProtect` for ownership that cannot be inferred). Review the diff findings after generation; they retain originating central changes. Browser reports and captures remain local, outside the repository.

‎biome.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@
169169
{
170170
"includes": [
171171
"scripts/design-conformance/catalogue.json",
172-
"scripts/design-conformance/contracts.json"
172+
"scripts/design-conformance/contracts.json",
173+
"scripts/design-conformance/contracts.generated.json"
173174
],
174175
"formatter": {
175176
"enabled": false

‎package.json‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
"test:search-performance": "KNOWLEDGE_SEARCH_PERFORMANCE_TEST=true bun --no-env-file scripts/test-integration.ts search-latency",
2121
"format": "biome format --write scripts/design-conformance scripts/check-design-conformance*.ts && turbo run format",
2222
"format:check": "biome format scripts/design-conformance scripts/check-design-conformance*.ts && turbo run format:check",
23-
"lint": "biome check --write scripts/design-conformance scripts/design-scan scripts/design-studio tools/design-studio scripts/check-design-conformance*.ts && turbo run lint",
24-
"lint:check": "biome check scripts/design-conformance scripts/design-scan scripts/design-studio tools/design-studio scripts/check-design-conformance*.ts && turbo run lint:check",
23+
"lint": "biome check --write scripts/design-conformance scripts/design-scan scripts/design-studio tools/design-studio scripts/check-design-conformance*.ts scripts/generate-design-contracts*.ts && turbo run lint",
24+
"lint:check": "biome check scripts/design-conformance scripts/design-scan scripts/design-studio tools/design-studio scripts/check-design-conformance*.ts scripts/generate-design-contracts*.ts && turbo run lint:check",
2525
"lint:helm": "helm lint helm/sim --strict --values helm/sim/ci/default-values.yaml",
2626
"lint:all": "bun run lint && bun run lint:helm",
2727
"check": "bun run format:check",
@@ -129,7 +129,9 @@
129129
"studio:dev": "next dev tools/design-studio --hostname 127.0.0.1 --port 3001",
130130
"type-check:studio": "tsc --noEmit -p tools/design-studio/tsconfig.json",
131131
"type-check:design": "tsc --noEmit -p scripts/design-conformance/tsconfig.json",
132-
"check:agent-cli-boundary": "bun run scripts/check-agent-cli-boundary.ts"
132+
"check:agent-cli-boundary": "bun run scripts/check-agent-cli-boundary.ts",
133+
"design:generate": "bun --no-env-file scripts/generate-design-contracts.ts",
134+
"check:design-generated": "bun run --no-env-file scripts/generate-design-contracts.ts --check"
133135
},
134136
"overrides": {
135137
"react": "19.2.4",

‎packages/emcn/src/components/banner/banner.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface BannerProps
3232
textClassName?: string
3333
}
3434

35+
/** @designAllow textClassName typography */
3536
export function Banner({
3637
actionClassName,
3738
actionDisabled,

‎packages/emcn/src/components/chip-input/chip-input.tsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ export interface ChipInputProps extends Omit<React.InputHTMLAttributes<HTMLInput
5050
/**
5151
* Forwards its ref to the inner `<input>` so callers can focus or measure the
5252
* field directly, exactly like a native input.
53+
* @designProtect className colours font-family font-size padding height gap border-radius borders box-shadow
54+
* @designProtect style colours font-family font-size padding height gap border-radius borders box-shadow
55+
* @designAllow inputClassName typography
5356
*/
5457
export const ChipInput = React.forwardRef<HTMLInputElement, ChipInputProps>(
5558
(

‎packages/emcn/src/components/chip-textarea/chip-textarea.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ export interface ChipTextareaProps
3939
viewOnly?: boolean
4040
}
4141

42-
/** Forwards its ref to the underlying `<textarea>`, exactly like a native textarea. */
42+
/** Forwards its ref to the underlying `<textarea>`, exactly like a native textarea. * @designProtect className colours font-family font-size padding gap border-radius borders box-shadow
43+
* @designProtect style colours font-family font-size padding gap border-radius borders box-shadow
44+
*/
4345
export const ChipTextarea = React.forwardRef<HTMLTextAreaElement, ChipTextareaProps>(
4446
({ className, error, resizable = false, viewOnly = false, readOnly, ...props }, ref) => (
4547
<textarea

‎packages/emcn/src/components/input/input.tsx‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ const INPUT_CLASS =
3333

3434
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>
3535

36-
/** Minimal input component matching the textarea styling. */
36+
/**
37+
* Minimal input component matching the textarea styling.
38+
* @designProtect className height
39+
* @designProtect style height
40+
*/
3741
const Input = React.forwardRef<HTMLInputElement, InputProps>(
3842
({ className, type = 'text', ...props }, ref) => {
3943
return <input type={type} className={cn(INPUT_CLASS, className)} ref={ref} {...props} />

0 commit comments

Comments
 (0)