@nurix/etna 0.18.18 → 0.18.20
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/data/harness-index.json +1 -1
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/rules/general.md +2 -1
- package/data/harnesses/code/skills/design/SKILL.md +65 -0
- package/data/harnesses/code/skills/design/data/catalog/rules.csv +132 -0
- package/data/harnesses/code/skills/design/data/design-md/SCHEMA.md +317 -0
- package/data/harnesses/code/skills/design/data/design-md/library/airbnb.md +235 -0
- package/data/harnesses/code/skills/design/data/design-md/library/airtable.md +232 -0
- package/data/harnesses/code/skills/design/data/design-md/library/anthropic-claude.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/apple.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/binance.md +223 -0
- package/data/harnesses/code/skills/design/data/design-md/library/bmw.md +219 -0
- package/data/harnesses/code/skills/design/data/design-md/library/cal.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/clay.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/clickhouse.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/cohere.md +227 -0
- package/data/harnesses/code/skills/design/data/design-md/library/coinbase.md +237 -0
- package/data/harnesses/code/skills/design/data/design-md/library/composio.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/cursor.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/elevenlabs.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/expo.md +228 -0
- package/data/harnesses/code/skills/design/data/design-md/library/figma.md +221 -0
- package/data/harnesses/code/skills/design/data/design-md/library/framer.md +236 -0
- package/data/harnesses/code/skills/design/data/design-md/library/hashicorp.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/ibm.md +234 -0
- package/data/harnesses/code/skills/design/data/design-md/library/intercom.md +240 -0
- package/data/harnesses/code/skills/design/data/design-md/library/kraken.md +236 -0
- package/data/harnesses/code/skills/design/data/design-md/library/linear-app.md +237 -0
- package/data/harnesses/code/skills/design/data/design-md/library/lovable.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/meta.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/minimax.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/mintlify.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/miro.md +233 -0
- package/data/harnesses/code/skills/design/data/design-md/library/mistral-ai.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/mongodb.md +236 -0
- package/data/harnesses/code/skills/design/data/design-md/library/notion.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/nvidia.md +222 -0
- package/data/harnesses/code/skills/design/data/design-md/library/ollama.md +226 -0
- package/data/harnesses/code/skills/design/data/design-md/library/opencode-ai.md +223 -0
- package/data/harnesses/code/skills/design/data/design-md/library/posthog.md +234 -0
- package/data/harnesses/code/skills/design/data/design-md/library/raycast.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/replicate.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/resend.md +285 -0
- package/data/harnesses/code/skills/design/data/design-md/library/revolut.md +225 -0
- package/data/harnesses/code/skills/design/data/design-md/library/runwayml.md +219 -0
- package/data/harnesses/code/skills/design/data/design-md/library/sanity.md +251 -0
- package/data/harnesses/code/skills/design/data/design-md/library/sentry.md +244 -0
- package/data/harnesses/code/skills/design/data/design-md/library/shopify.md +227 -0
- package/data/harnesses/code/skills/design/data/design-md/library/slack.md +240 -0
- package/data/harnesses/code/skills/design/data/design-md/library/spacex.md +252 -0
- package/data/harnesses/code/skills/design/data/design-md/library/spotify.md +248 -0
- package/data/harnesses/code/skills/design/data/design-md/library/stripe.md +241 -0
- package/data/harnesses/code/skills/design/data/design-md/library/supabase.md +255 -0
- package/data/harnesses/code/skills/design/data/design-md/library/superhuman.md +226 -0
- package/data/harnesses/code/skills/design/data/design-md/library/tesla.md +233 -0
- package/data/harnesses/code/skills/design/data/design-md/library/theverge.md +248 -0
- package/data/harnesses/code/skills/design/data/design-md/library/together-ai.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/uber.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/vercel.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/voltagent.md +245 -0
- package/data/harnesses/code/skills/design/data/design-md/library/warp.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/webflow.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/wired.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/wise.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/x-ai.md +220 -0
- package/data/harnesses/code/skills/design/data/design-md/library/zapier.md +238 -0
- package/data/harnesses/code/skills/design/data/design-md/nurix.md +217 -0
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/command-center.tsx +249 -0
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/create-edit.tsx +249 -0
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/dashboard.tsx +248 -0
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/entity-detail.tsx +245 -0
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/list-detail.tsx +223 -0
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/log-stream.tsx +249 -0
- package/data/harnesses/code/skills/design/data/operator-pack/fixtures.md +88 -0
- package/data/harnesses/code/skills/design/data/operator-pack/surface-catalog.md +132 -0
- package/data/harnesses/code/skills/design/data/operator-pack/trust-rubric.md +76 -0
- package/data/harnesses/code/skills/design/references/create.md +126 -0
- package/data/harnesses/code/skills/design/references/diagnosis.md +108 -0
- package/data/harnesses/code/skills/design/references/hard-rules.md +155 -0
- package/data/harnesses/code/skills/design/references/improve.md +85 -0
- package/data/harnesses/code/skills/design/references/interaction.md +77 -0
- package/data/harnesses/code/skills/design/references/introspect.md +100 -0
- package/data/harnesses/code/skills/design/references/lifecycle.md +73 -0
- package/data/harnesses/code/skills/design/references/personality.md +504 -0
- package/data/harnesses/code/skills/design/references/structure.md +138 -0
- package/data/harnesses/code/skills/design/scripts/derive-personality.mjs +706 -0
- package/data/harnesses/code/skills/design/scripts/detector.mjs +898 -0
- package/data/harnesses/code/skills/design/scripts/generate-fixtures.mjs +551 -0
- package/data/harnesses/code/skills/design/scripts/hook-config.json +11 -0
- package/data/harnesses/code/skills/design/scripts/phase-gate.mjs +386 -0
- package/data/harnesses/code/skills/design/scripts/preship-sweep.mjs +280 -0
- package/data/harnesses/code/skills/design/scripts/render-rung.mjs +690 -0
- package/data/harnesses/code/skills/design/scripts/scaffold.mjs +552 -0
- package/data/harnesses/code/skills/design/scripts/self-integrity.mjs +432 -0
- package/data/harnesses/etna/CLAUDE.md +1 -1
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/rules/general.md +2 -1
- package/data/harnesses/mobile/harness.json +2 -2
- package/data/harnesses/mobile/rules/general.md +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Create — the gated phase spine
|
|
2
|
+
|
|
3
|
+
Create is the only workflow where taste is *made*: personality synthesis, structure derivation, emission. It runs **six gated phases** — intake, structure, scaffold, tokens, fixtures, surfaces — and closes on a **verification ladder**. Each of the six is closed by a phase gate: `phase-gate.mjs <phase>` validates that phase's exit preconditions, exits non-zero printing the exact fix, and **the next phase does not open until the gate is green**. Improve and introspect operate on UIs that already exist — see [improve.md](./improve.md) and [introspect.md](./introspect.md).
|
|
4
|
+
|
|
5
|
+
| Phase | Gate (must pass to open the next) | Produces |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| intake | `phase-gate.mjs intake` | confirmed intent digest; resolved `design.md` at project root |
|
|
8
|
+
| structure | `phase-gate.mjs structure` | `docs/design/structure.md` — the entity/surface map |
|
|
9
|
+
| scaffold | `phase-gate.mjs scaffold` | project shell: routes, nav, state-shells, fixture wiring |
|
|
10
|
+
| tokens | `phase-gate.mjs tokens` | `personality.css` + `globals.css`, full token surface |
|
|
11
|
+
| fixtures | `phase-gate.mjs fixtures` | seeded fixture modules in `src/fixtures/` |
|
|
12
|
+
| surfaces | `phase-gate.mjs surfaces` | composed surfaces, every lifecycle state filled |
|
|
13
|
+
| verification | the ladder (below) | a compiled, swept, rendered app |
|
|
14
|
+
|
|
15
|
+
The gate closing each phase runs the D21 rule classes decidable at that boundary — per-surface structural rules (states presence, token coverage, exemplar-in-context). A gate never waives: it prints the exact fix and the run resolves it before proceeding.
|
|
16
|
+
|
|
17
|
+
## intake
|
|
18
|
+
|
|
19
|
+
**Purpose.** Recognize the brief, decide pack coverage, extract intent, resolve the look.
|
|
20
|
+
**In → out.** the brief · the design.md library · router data → a confirmed intent digest · a `design.md` at project root (brand document + lever manifest).
|
|
21
|
+
**Work.** Front gate: a project-declared identity (product-type traits) wins; otherwise the signal checklist (audience is employees / agents / analysts; the metric is task throughput, not conversion; the surfaces are queues / tables / forms / monitors), router data as a lookup assist. Build a structured intent digest — entity list, archetype guesses, density tier, substrate — every inference marked as inferred, present it once for confirmation, and ask only strategic unknowns whose answers change the design. Resolve the look design.md-first: the project's own `design.md` wins; a library entry serves on propose-confirm (proposed from resemblance, never applied silently); zero input wears the Nurix default. Materialize the resolved document at project root against [SCHEMA.md](../data/design-md/SCHEMA.md).
|
|
22
|
+
**Gate — `phase-gate.mjs intake`.** The digest is confirmed and a schema-valid `design.md` exists at project root. A brief no pack covers is refused here — cleanly, with a redirect — never derived.
|
|
23
|
+
**Avoid.**
|
|
24
|
+
- Deriving on silently inferred facts instead of presenting the digest for one confirmation.
|
|
25
|
+
- Blanket-interviewing when the brief already declares its identity — ask only strategic unknowns.
|
|
26
|
+
- Attempting a marketing / storefront / mobile-native brief instead of refusing on pack coverage.
|
|
27
|
+
|
|
28
|
+
## structure
|
|
29
|
+
|
|
30
|
+
**Purpose.** Derive the app's structure from its domain objects — never guess it.
|
|
31
|
+
**In → out.** the confirmed intent digest → `docs/design/structure.md` with its fenced `yaml structure` block.
|
|
32
|
+
**Work.** The object pass: entities, attributes, relationships, cardinalities, lifecycle states; the operator's unit of work and core loop. The **temporal probe runs inside the pass** — intermediate states, read-model lag, deletion semantics, history, failure paths — because they are model facts, not later polish. Then assign each surface an archetype from the closed six-catalog (`list-detail`, `dashboard`, `entity-detail`, `create-edit`, `log-stream`, `command-center`) with its density modifier — see [surface-catalog.md](../data/operator-pack/surface-catalog.md). Navigation derives from the object model; it is never decorated onto it. The OOUX failure vocabulary (Shapeshifter / Masked / Broken / Isolated) is the judged diagnostic — see [structure.md](./structure.md).
|
|
33
|
+
**Gate — `phase-gate.mjs structure`.** The map parses; every surface carries an archetype from the catalog; the `temporal` block is present. `scaffold.mjs` consumes this block, so its shape is validated here.
|
|
34
|
+
**Avoid.**
|
|
35
|
+
- Skipping the object pass on a small brief — a small brief earns a proportionally small pass, never a skipped one; the skip is the characteristic failure.
|
|
36
|
+
- Decorating navigation onto the UI instead of deriving it from the object model.
|
|
37
|
+
- Omitting the temporal probe — intermediate states and failure paths are model facts, not afterthoughts.
|
|
38
|
+
- Inventing an archetype outside the closed six.
|
|
39
|
+
|
|
40
|
+
## scaffold
|
|
41
|
+
|
|
42
|
+
**Purpose.** Generate the non-creative substrate from the map — the model never freehands it.
|
|
43
|
+
**In → out.** `docs/design/structure.md` → the wired project shell.
|
|
44
|
+
**Work.** `scaffold.mjs docs/design/structure.md --out <project>` emits `index.html` (carrying the `<html>` data attributes), `src/main.tsx`, `src/App.tsx` (react-router-dom), route and navigation wiring per surface, per-surface state-shell stubs (loading / empty / error / degraded shells wired but unfilled), and fixture wiring — under `src/routes/<surface>/`, `src/components/<feature>/`, `src/types/`. These files are **generated**; the preservation contract forbids hand-editing them.
|
|
45
|
+
**Gate — `phase-gate.mjs scaffold`.** The shell exists, routes and nav match the map, every surface has its state-shells, and the `globals.css` import order is correct.
|
|
46
|
+
**Avoid.**
|
|
47
|
+
- Freehanding the route or navigation wiring the generator owns.
|
|
48
|
+
- Hand-editing a generated file after `scaffold.mjs` writes it — generated files are never written into.
|
|
49
|
+
- Getting the `globals.css` import order wrong — the cascade contract is in [personality.md](./personality.md).
|
|
50
|
+
|
|
51
|
+
## tokens
|
|
52
|
+
|
|
53
|
+
**Purpose.** Emit the complete token surface from the resolved `design.md`.
|
|
54
|
+
**In → out.** `design.md` → `src/styles/personality.css` + `src/styles/globals.css`.
|
|
55
|
+
**Work.** Derivation is hybrid: deterministic where the document states a value, judgment-with-recorded-rationale for gaps. The **coverage gate** `derive-personality.mjs design.md --check` fails — exit non-zero, naming the missing keys — if any of the 26 visual primitives, the 2 behavioral dials, or the emission tokens is unassigned and un-hinted. Only once it is green does `derive-personality.mjs design.md --emit src/styles/` write both files, defining the full surface — 26 primitives, 17 semantic tokens, and the 17 substrate tokens no consumable value is left to fall back to gray on — and hardening both cascade contracts (selector specificity, import order) with explanatory comments. See [personality.md](./personality.md).
|
|
56
|
+
**Gate — `phase-gate.mjs tokens`.** The coverage gate passed and both files carry the full token surface with the cascade-contract comments intact.
|
|
57
|
+
**Avoid.**
|
|
58
|
+
- Emitting before the coverage gate passes.
|
|
59
|
+
- Leaving any of the 17 substrate tokens to fall back to shadcn-gray defaults.
|
|
60
|
+
- Hardcoding a literal color, spacing, or radius instead of routing through a token.
|
|
61
|
+
- Dropping the cascade-contract comments from the emitted CSS.
|
|
62
|
+
|
|
63
|
+
## fixtures
|
|
64
|
+
|
|
65
|
+
**Purpose.** Produce the taste-bearing data every surface renders — before any surface exists.
|
|
66
|
+
**In → out.** `docs/design/structure.md` → `src/fixtures/*.ts`.
|
|
67
|
+
**Work.** `generate-fixtures.mjs docs/design/structure.md --seed <n> --out src/fixtures/` writes seeded, domain-shaped fixture modules: realistic volumes (queues in the hundreds), long strings, unhappy values, degraded payloads, and empty / error cases — see [fixtures.md](../data/operator-pack/fixtures.md). A fixed seed makes every run reproducible.
|
|
68
|
+
|
|
69
|
+
> **Fixture-before-surface.** Fixtures are generated before any surface is composed because realistic seeded data is taste-bearing design material — the density, overflow, and state thresholds are only bindable against real volumes, long strings, and unhappy values.
|
|
70
|
+
|
|
71
|
+
**Gate — `phase-gate.mjs fixtures`.** Seeded modules exist for every entity, cover the unhappy and empty / error cases, and no surface file has yet been written.
|
|
72
|
+
**Avoid.**
|
|
73
|
+
- Lorem-ipsum data or unseeded randomness.
|
|
74
|
+
- Composing a surface before its data exists.
|
|
75
|
+
- Happy-path-only rows — no volumes, long strings, degraded payloads, or empty / error cases.
|
|
76
|
+
|
|
77
|
+
## surfaces
|
|
78
|
+
|
|
79
|
+
**Purpose.** Compose each surface per its archetype, filling the pre-created shells.
|
|
80
|
+
**In → out.** the state-shells · the fixtures · the emitted tokens · the archetype exemplar → composed `src/routes/<surface>/` surfaces, every state present.
|
|
81
|
+
**Work.** For each surface, compose in the `@nurix/components` idiom (imported by subpath) against the resolved tokens — the look comes entirely from the cascade, never from literals. Fill every lifecycle state into its pre-created shell; states are composed with the surface, not bolted on after. AI-bearing surfaces clear the [trust rubric](../data/operator-pack/trust-rubric.md); microcopy follows the error and empty-state formulas in [lifecycle.md](./lifecycle.md); keyboard and focus discipline follow [interaction.md](./interaction.md).
|
|
82
|
+
|
|
83
|
+
> **Just-in-time exemplar.** Each archetype's token-pure exemplar ([exemplars/](../data/operator-pack/exemplars/)) loads just-in-time at that archetype's emission gate — never at boot — because imitation proximity is highest when the exemplar sits in context at the moment of composition. Composing a surface of archetype X without exemplar X in context is a **gate violation**. Imitate the composition; the look comes from the project's personality.
|
|
84
|
+
|
|
85
|
+
**Gate — `phase-gate.mjs surfaces`.** For each surface the archetype exemplar was in context, all lifecycle states are filled, and the per-surface structural rules pass (states presence, token coverage).
|
|
86
|
+
**Avoid.**
|
|
87
|
+
- Composing archetype X without exemplar X in context — a gate violation.
|
|
88
|
+
- Writing states as an afterthought instead of into the pre-created shells.
|
|
89
|
+
- Emitting a look disjoint from the resolved personality — literals or off-scale values instead of the cascade.
|
|
90
|
+
- Modals where side panels belong; a workflow a pointer alone can complete (floor P3 / P6).
|
|
91
|
+
|
|
92
|
+
## verification
|
|
93
|
+
|
|
94
|
+
**Purpose.** Prove the app compiles and clears the ladder.
|
|
95
|
+
**In → out.** the composed app → a verified app; any findings routed through the same fix-or-classify loop.
|
|
96
|
+
**Gate.** The verification ladder below — rung 0 is never skipped. Findings surface as the [canonical finding](./diagnosis.md) and resolve before ship.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## The preservation contract
|
|
101
|
+
|
|
102
|
+
Two disciplines protect what must never silently change.
|
|
103
|
+
|
|
104
|
+
**The fixed never-silently-changed list** — identical across every project, never negotiated:
|
|
105
|
+
|
|
106
|
+
- route slugs
|
|
107
|
+
- navigation labels
|
|
108
|
+
- form-field names and order
|
|
109
|
+
- analytics / event identifiers
|
|
110
|
+
- API / data-contract shapes
|
|
111
|
+
- generated files (never written into — the is-generated guard)
|
|
112
|
+
|
|
113
|
+
Changing any of these requires it to be the *named subject* of a finding; they are never collateral edits. Per-project preservation extensions, if ever needed, are entries in the project's `design.md` — data, not config machinery.
|
|
114
|
+
|
|
115
|
+
**Diff-scope discipline.** An improve run edits only the files its findings name; a run that touches a file outside its findings fails. Create writes the whole app — the discipline governs improve. See [improve.md](./improve.md).
|
|
116
|
+
|
|
117
|
+
## The verification ladder
|
|
118
|
+
|
|
119
|
+
| Rung | What | When |
|
|
120
|
+
| --- | --- | --- |
|
|
121
|
+
| 0 | Compile. | Always — never skipped. |
|
|
122
|
+
| 1 | Static whole-app checks — `preship-sweep.mjs`: the full catalog over all files, plus the mandatory procedures (viewport sweep at 375 / 768 / 1024 / 1440, copy self-audit, scope cross-check against the brief). | Every run. |
|
|
123
|
+
| 2 | Deterministic render rung — `render-rung.mjs`: key surfaces rendered headlessly, the detector re-running its render-only rules (real overflow at the four viewports, effective and pixel-measured contrast, rendered token drift, actual target geometry, and the `cod-12` runtime perf budgets LCP < 2.5s and CLS < 0.1 collected via `PerformanceObserver`; INP and frame time need the interactive rung); findings through the same fix-or-classify loop. | By default when a headless browser is importable; degrades to a one-line notice otherwise. |
|
|
124
|
+
| 3 | Interactive dev-server / browser audit of the user's own environment. | Consent-gated — asked for, never assumed. |
|
|
125
|
+
|
|
126
|
+
Model-judged screenshot self-critique is **not a rung** — no machine verdict rests on the model's own read of a screenshot. Pixel instruments (`inst-*`) supply evidence *inside* judged findings, never verdicts.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Diagnosis — the shared engine
|
|
2
|
+
|
|
3
|
+
> The one engine that turns a UI into findings. [improve.md](improve.md) runs it to decide what to change; [introspect.md](introspect.md) runs it to explain why a UI isn't working. Both get the same findings — improve applies them, introspect renders them per reader register. Diagnosis owns the finding format; the consumers own what they do with it.
|
|
4
|
+
|
|
5
|
+
Reads the rule catalog ([../data/catalog/rules.csv](../data/catalog/rules.csv)) and the AI-surface trust rubric ([../data/operator-pack/trust-rubric.md](../data/operator-pack/trust-rubric.md)). Emits a severity-ranked list of canonical findings, consumed by improve, introspect, the dated findings report, and the decay ledger — one schema across all four.
|
|
6
|
+
|
|
7
|
+
## The dimension taxonomy
|
|
8
|
+
|
|
9
|
+
Every finding names a dimension. The set is the sixteen dimensions across three meta-layers — **Perception** (what the operator sees), **Structure** (how it's built), **Behavior** (how it responds).
|
|
10
|
+
|
|
11
|
+
Perception — P1 Typography (font, scale, weight, rhythm, loading) · P2 Color (palette, contrast, neutrals, saturation) · P3 Spatial (spacing scale, grid, whitespace, rhythm) · P4 Depth & Elevation (shadow scale, z-index, layering) · P5 Visual Hierarchy (emphasis, de-emphasis, the squint test) · P6 Iconography & Imagery (icon sets, stroke, image treatment) · P7 Aesthetic Identity (personality, tone, anti-slop, consistency).
|
|
12
|
+
|
|
13
|
+
Structure — S1 Semantic Markup (elements, heading hierarchy, ARIA, landmarks) · S2 Component Architecture (composition, reuse, isolation, typed props) · S3 Design Tokens (semantic vs literal, two-layer naming, theming) · S4 Performance (GPU-safe animation, bundle, lazy load, CLS).
|
|
14
|
+
|
|
15
|
+
Behavior — B1 Interactive States (default/hover/focus/active/disabled/loading/empty/error) · B2 Motion & Animation (timing, easing, stagger, reduced-motion) · B3 Responsive Adaptation (breakpoints, targets, viewport units, input method) · B4 Navigation & Wayfinding (nav patterns, back behavior, deep links, modals) · B5 Content & Copy (microcopy, errors, empty states, labels, terminology).
|
|
16
|
+
|
|
17
|
+
## Causes-first: the walk order
|
|
18
|
+
|
|
19
|
+
Diagnosis walks the meta-layers **Structure → Behavior → Perception** — causes before symptoms. Badness is felt in Perception (the table looks noisy, the page feels heavy), but its cause almost always lives one layer down, in Structure or Behavior. Walking causes-first means a Perception symptom is diagnosed to its root and reported once, at the cause — never patched as a cluster of surface edits that leave the root standing.
|
|
20
|
+
|
|
21
|
+
Two orderings, do not confuse them. The **walk** is causes-first (analysis order). The **delivered list** is severity-ranked (below). [introspect.md](introspect.md) narrates each finding the other way — from the felt symptom down to the cause — because that is how a reader understands it; the diagnosis underneath is the same.
|
|
22
|
+
|
|
23
|
+
## The canonical finding
|
|
24
|
+
|
|
25
|
+
Eight fields, fixed. Every finding carries all eight, machine or judged.
|
|
26
|
+
|
|
27
|
+
- **dimension** — which of the sixteen. Names *what* is wrong.
|
|
28
|
+
- **cause layer** — Structure, Behavior, or Perception. Names *where the fix lives* — the meta-layer of the root, which often differs from the dimension's own layer (a felt Perception problem rooted in a Structure fact).
|
|
29
|
+
- **evidence** — the anchor in the code: `file:line`, a token name, or a measured value. Never a vibe.
|
|
30
|
+
- **before → after** — the current state → the corrected state. Numeric where machine-backed (a value → its threshold); a concrete, measurable state change where judged. Never "make it cleaner."
|
|
31
|
+
- **consequence** — what it costs the operator: lost throughput, eroded trust, an unreadable figure, an irreversible mistake.
|
|
32
|
+
- **tier** — `within-levers` (fixable inside the current lever manifest) or `lever-change` (needs a manifest change). The [improve.md](improve.md) jail reads this.
|
|
33
|
+
- **severity** — auto-critical → critical → major → minor. A rank, never a number.
|
|
34
|
+
- **provenance** — a catalog anchor id for a machine finding (e.g. `spc-01`), or the judged dimension / trust anchor for a judged one. This is the only field that says how the finding was established.
|
|
35
|
+
|
|
36
|
+
### Worked example
|
|
37
|
+
|
|
38
|
+
- **dimension** · P3 Spatial **cause layer** · Structure (the value bypasses the declared spacing scale — a token-discipline failure, not a raw sizing choice)
|
|
39
|
+
- **evidence** · `src/routes/queue/QueueToolbar.tsx:34` — `className="px-[15px]"`
|
|
40
|
+
- **before → after** · `15px` (off-scale) → `16px` (the nearest step on the manifest's 4/8 scale)
|
|
41
|
+
- **consequence** · a one-off gutter that breaks the toolbar's rhythm against the 16px-gridded rows beside it; proximity stops encoding structure
|
|
42
|
+
- **tier** · within-levers (16px is already in the manifest's spacing scale)
|
|
43
|
+
- **severity** · minor
|
|
44
|
+
- **provenance** · `spc-01` (machine, source-detected)
|
|
45
|
+
|
|
46
|
+
That is a machine finding with a numeric before→after. For a judged finding worked three ways see [introspect.md](introspect.md); for judged trust findings see [trust-rubric.md](../data/operator-pack/trust-rubric.md).
|
|
47
|
+
|
|
48
|
+
## Machine and judged findings are peers
|
|
49
|
+
|
|
50
|
+
There is no primary source and no secondary source. Machine and judged findings share the schema, sort into one severity-ranked list, and feed every consumer identically. Only **provenance** distinguishes them:
|
|
51
|
+
|
|
52
|
+
- A **machine** finding's provenance is its catalog anchor id. The id resolves in [rules.csv](../data/catalog/rules.csv) to the rule statement, its numbers, and its source tags (WCAG, HIG, `imp`, `stitch`, `axe`, `volt/<product>`, …). Its before→after is the offending value against the rule's threshold.
|
|
53
|
+
- A **judged** finding's provenance is the judged dimension — a taxonomy code, or a trust anchor (`trust-01`..`trust-04`) — with `detector=none` in the catalog. Its before→after is a concrete state change, measurable in kind though not numeric.
|
|
54
|
+
|
|
55
|
+
Neither kind outranks the other by *kind*. Severity ranks them; provenance only records the route. A judged P5 hierarchy finding can sort above a machine `typ-15` finding, and does when its severity is higher.
|
|
56
|
+
|
|
57
|
+
## Severity: a ranked scale, never a score
|
|
58
|
+
|
|
59
|
+
`auto-critical → critical → major → minor`. Ordering, comparability, and priority all come from the rank — never from a number.
|
|
60
|
+
|
|
61
|
+
- **auto-critical** — assigned *mechanically, by rule, never by judgment*. Two triggers: absence of `trust-01`, `trust-02`, or `trust-03` (AI presence undisclosed, no human override path, an irreversible AI action ungated by consent-and-preview); and any irreversible action lacking **both** a confirm step **and** an undo path (`int-05`). No waiver, and no judgment call can down-rank it — it sorts to the top of every list.
|
|
62
|
+
- **critical** — the surface fails at its purpose: data unreadable or wrong, a required state missing so the surface reads as broken, an accessibility block, a contract about to break.
|
|
63
|
+
- **major** — real loss of throughput or trust; the surface still works but taxes the operator on every use.
|
|
64
|
+
- **minor** — polish: an off-scale value, a tracking miss, a redundant separator. Correct, not costly.
|
|
65
|
+
|
|
66
|
+
## No numeric scores — a measurable before→after instead
|
|
67
|
+
|
|
68
|
+
The engine never emits a score. No 0–4, no 0–100, no percentage grade — runtime scores are false precision the best practitioners avoid; the catalog's own detector output is defect *evidence*, not a number to average. Comparability comes from two things that do not pretend to a decimal: the severity rank orders the list, and the **mandatory measurable before→after** on every finding says exactly what changes.
|
|
69
|
+
|
|
70
|
+
Machine-backed → numeric (`620ms → ≤500ms`; `12px → 14px`). Judged → a concrete before/after state (`AI draft renders identically to human messages → AI draft carries a disclosure chip and a muted treatment`). Banned always: "feels off," "make it cleaner," any adjective standing in for a change. `cod-13` is this contract; `self-integrity.mjs` checks that every finding carries a before→after.
|
|
71
|
+
|
|
72
|
+
## Instruments: numbers as evidence, never verdicts
|
|
73
|
+
|
|
74
|
+
The render rung computes deterministic numbers (`inst-*`) over the rendered surface. They enter findings **only as evidence inside a judged finding** — never as a gate, never as a verdict.
|
|
75
|
+
|
|
76
|
+
**Pixel-level instruments** (`inst-01`..`inst-10`): edge density, feature congestion, subband entropy, grid quality, white-space ratio, symmetry, figure-ground contrast, contour congestion, colorfulness, distinct-RGB count. A finding may cite one — *"edge density 0.31 vs the 0.18–0.24 typical of shipped operator surfaces"* — as evidence for a judged P5 or P2 finding. The verdict stays judged.
|
|
77
|
+
|
|
78
|
+
The load-bearing caution: **dense operator surfaces are dense on purpose.** "Lower visual complexity ⇒ better" was refuted 0–3 in adversarial verification; on an information-dense surface the sign of "good" can invert. A high instrument number is a prompt to *look*, never proof of a problem, and a threshold is never derived from an exemplar (circular). Start with edge density — cheapest, best-documented — and treat every reading as a signal.
|
|
79
|
+
|
|
80
|
+
**KLM operator-cost** (`inst-11`): a comparative throughput diagnosis, not ground truth. Sum the typed operators over a fixed core-loop path with the published constants — **P (point) 1.10s · H (home hand between keyboard and mouse) 0.40s · M (mental prep) 1.35s · K (keystroke) 0.20–0.28s** — counting clicks, keystrokes, tab-stops, and hand-homings. It compares two paths (before a redesign vs after, path A vs path B), pairing with the entity/surface map's core loop ([structure.md](structure.md)) and floor P1's throughput-first metric. It is a cost *model*: path selection is judgment, so the number is evidence for a judged B1/B4 finding, never a verdict.
|
|
81
|
+
|
|
82
|
+
## The AI-surface trust rubric
|
|
83
|
+
|
|
84
|
+
Any surface that shows AI-originated content or takes AI-initiated actions is diagnosed against the trust rubric ([../data/operator-pack/trust-rubric.md](../data/operator-pack/trust-rubric.md)) — four judged dimensions (`trust-01`..`trust-04`), fired inside every improve and introspect sweep, skipped on surfaces with no AI content. Its findings are judged findings on this schema, peers of every other. The rubric owns the four dimensions and their auto-critical gradings; diagnosis consumes them.
|
|
85
|
+
|
|
86
|
+
## The decay ledger
|
|
87
|
+
|
|
88
|
+
Quality is the skill's burden, never the user's — so decay is *observed*, not silently absorbed. A run appends to `docs/memory/design-decay.md` (a project memory file, per the CLAUDE.md memory convention) whenever its guidance failed to land. Three event classes:
|
|
89
|
+
|
|
90
|
+
1. **Machine violations surviving fix-or-classify** — a rule fired and the run resolved it by classifying the rule as inapplicable rather than fixing it (the classification is logged as the fix-or-classify directive requires), or a violation reached ship neither fixed nor classified.
|
|
91
|
+
2. **Judged findings recurring across runs** — the same judged finding reappears on a later run, evidence the guidance is not being absorbed.
|
|
92
|
+
3. **Guidance fought or produced wrong output** — the agent resisted a rule, or following the guidance yielded a worse result or collided with the user's workload.
|
|
93
|
+
|
|
94
|
+
The ledger is **maintainer-facing telemetry, not runtime state** — the emitted UI stays the only design record (floor P8). The skill never reads it back and **never self-modifies**. The maintainer reads it, diagnoses whether the failure is the skill's design or the project's circumstances, and closes it by hand — updating the skill, or going back to the user.
|
|
95
|
+
|
|
96
|
+
Entries are **dated, factual, and human-closed** — append-only, oldest at bottom:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
## YYYY-MM-DD — <topic>
|
|
100
|
+
|
|
101
|
+
- event: <machine-violation-classified | judged-finding-recurring | guidance-fought>
|
|
102
|
+
- anchor: <rule id or judged dimension>
|
|
103
|
+
- where: <surface / file:line>
|
|
104
|
+
- what happened: <one factual line — what fired, how it resolved, no editorializing>
|
|
105
|
+
- run: <create | improve:<verb> | introspect>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
No verdict, no severity, no remediation in the entry — it records what happened, not what to do about it. The closing is the maintainer's.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Hard rules — the boot-loaded floor
|
|
2
|
+
|
|
3
|
+
The hard-prose channel: every machine ban, deterministic threshold, and mandatory procedure the skill enforces, one imperative line each. This file loads into context before any design output.
|
|
4
|
+
|
|
5
|
+
The backticked anchor id is the shared key: the same id names the `rules.csv` row, the detector rule key, the fixture pair, and a finding's provenance. Machine rules are absolute — a violation is fixed now, or classified as inapplicable in `docs/memory/design-decay.md`; never ignored silently. No waivers, no inline suppressions. Lines tagged `· render` are decided on the rendered surface at the render rung (pixels or DOM), not from source at edit time. Judged dimensions are diagnosed, not gated — the index at the foot points at where their judgment lives.
|
|
6
|
+
|
|
7
|
+
## Typography
|
|
8
|
+
|
|
9
|
+
- `typ-01` Body text contrast ≥ 4.5:1; large text ≥ 3:1. · render
|
|
10
|
+
- `typ-02` Body ≥ 14px on operator surfaces; never below 11px anywhere.
|
|
11
|
+
- `typ-03` Form inputs ≥ 16px on touch/mobile surfaces; desktop operator inputs exempt.
|
|
12
|
+
- `typ-05` Prose measure 45–75ch; tables exempt.
|
|
13
|
+
- `typ-06` ≤ 2 font families per app; type scale holds ~6 distinct sizes.
|
|
14
|
+
- `typ-07` Tabular lining numerals (`font-variant-numeric`) on every numeric column, KPI, timer, ID.
|
|
15
|
+
- `typ-08` All-caps micro-labels: letter-spacing ≥ 0.02em (caps band 0.05–0.12em); tracking never below −0.04em.
|
|
16
|
+
- `typ-09` Font sizes from a fixed rem scale (step ratio 1.125–1.2); ban `vw`/`vh`/`clamp` on font-size; operator surfaces.
|
|
17
|
+
- `typ-10` Adjacent type-scale steps ≥ 25% apart.
|
|
18
|
+
- `typ-11` No UI font weight below 400.
|
|
19
|
+
- `typ-12` Never size type in `em`; px or rem only.
|
|
20
|
+
- `typ-14` Typographic characters: curly quotes/apostrophes, en-dash for ranges, real ellipsis/×/© glyphs, one space after punctuation; never underline non-links; bold XOR italic, never both.
|
|
21
|
+
- `typ-15` Zero em-dashes in UI copy.
|
|
22
|
+
- `typ-16` Ban serif faces in dashboards and software UIs.
|
|
23
|
+
- `typ-18` Uppercase-tracking (eyebrow/micro-label) instances ≤ ceil(sectionCount/3).
|
|
24
|
+
- `typ-19` Code/mono type fixed at 16px; long lines scroll horizontally, never wrap.
|
|
25
|
+
|
|
26
|
+
## Color
|
|
27
|
+
|
|
28
|
+
- `col-01` Non-text UI contrast ≥ 3:1 (input borders, icons, focus rings). · render
|
|
29
|
+
- `col-02` One accent, reserved for primary action / selection / state; accent saturation < 80%. Status palettes are additional, not accent violations.
|
|
30
|
+
- `col-03` Color never the only signal; status pairs with an icon or text. · render
|
|
31
|
+
- `col-04` Status colors only via semantic tokens: `--success`, `--warning`, `--destructive`.
|
|
32
|
+
- `col-05` Ban literal palette classes, hex/rgb/oklch literals, and `dark:` prefixes in JSX.
|
|
33
|
+
- `col-06` No pure `#000000` text or canvas, no pure `#ffffff` surfaces; start near `#111827`/`#1F2937`. Fires only when no brand token declares pure black.
|
|
34
|
+
- `col-07` No opacity- or `rgba()`-fabricated shades; every shade is an explicit hex or token.
|
|
35
|
+
- `col-08` Greys 8–10 shades; each accent family 5–10.
|
|
36
|
+
- `col-09` Disabled-state opacity 0.38–0.5.
|
|
37
|
+
- `col-10` Modal scrim 40–60% black.
|
|
38
|
+
- `col-13` Semantic price/status colors are text-only, never fills; never repurposed for generic success or error.
|
|
39
|
+
- `col-14` Data-viz: lines/bars ≥ 3:1 vs background; data labels ≥ 4.5:1. · render
|
|
40
|
+
|
|
41
|
+
## Spatial
|
|
42
|
+
|
|
43
|
+
- `spc-01` Every spacing value on the declared 4/8 scale (standard 4/8/12/16/24/32/48/64/96px; dense 2/4/8/12/16/24/32px). The monotony sub-check (≥ 10 identical) excludes operator surfaces.
|
|
44
|
+
- `spc-02` Adjacent spacing values ≥ 25% apart.
|
|
45
|
+
- `spc-03` Tap/click targets ≥ 24×24px (SC 2.5.8); ≥ 44px touch-primary; dense data rows 28px; undersized only via the ≥ 8px spacing exception (`int-11`). · render
|
|
46
|
+
- `spc-04` Numeric columns right-align, text left-aligns; ban center-aligned data columns.
|
|
47
|
+
- `spc-06` Corners on a fixed radius scale (2/4/6/8/12/9999), one scale per page.
|
|
48
|
+
- `spc-07` Dense table rows: 12px vertical cell padding + hairline dividers; buttons compact to 28px; mono numbers on every figure.
|
|
49
|
+
- `spc-08` Full-viewport height uses `min-h-[100dvh]`; never `h-screen` or `100vh`.
|
|
50
|
+
- `spc-09` Ban calc-percentage layout arithmetic (`calc(33% - 1rem)`); CSS Grid instead.
|
|
51
|
+
- `spc-10` No horizontal scroll at any viewport (375/768/1024/1440); any overflow means broken. · render
|
|
52
|
+
- `spc-15` Grid/bento integrity: N items fill exactly N cells; no orphan corners; spans interlock. · render
|
|
53
|
+
|
|
54
|
+
## Depth & hierarchy
|
|
55
|
+
|
|
56
|
+
- `dep-01` z-index only from the declared scale (0/10/20/40/100/1000); ban 999 and 9999.
|
|
57
|
+
- `dep-02` One h1 per view; heading levels never skip.
|
|
58
|
+
- `dep-04` Ban border and shadow doing the same separation job on one element.
|
|
59
|
+
|
|
60
|
+
## Interaction
|
|
61
|
+
|
|
62
|
+
- `int-01` Every interactive element ships a `:focus-visible` ring: ≥ 3:1 contrast, ≥ 2px (2–4px), with offset. · render (contrast)
|
|
63
|
+
- `int-02` Ban `outline: none` without a replacement focus style.
|
|
64
|
+
- `int-03` No pointer-only affordances; every hover-revealed control has a keyboard/focus path.
|
|
65
|
+
- `int-04` Modals use native `<dialog>` + `inert` focus containment; ban nested modals; side panel before modal.
|
|
66
|
+
- `int-08` Labels visible above the input; errors inline below the field (gap 4–8px); ban placeholder-as-label. Form fields only; a bare search input is exempt.
|
|
67
|
+
- `int-09` `aria-sort` on sortable headers; sticky header/first column beyond one viewport; 5–7 default visible columns with a picker; bounded pagination ("1–25 of 150"), never infinite scroll on work queues.
|
|
68
|
+
- `int-10` An `aria-live` region present wherever async status renders.
|
|
69
|
+
- `int-11` Target-to-target spacing ≥ 8px.
|
|
70
|
+
- `int-12` `cursor: pointer` on every clickable element (web).
|
|
71
|
+
- `int-14` All five button states present: default, hover, active, focus, disabled.
|
|
72
|
+
- `int-17` Discernible accessible name on every interactive element and image (`button-name`/`select-name`/`image-alt` Critical, `link-name` Serious). · render
|
|
73
|
+
- `int-18` ARIA spec-valid: `aria-allowed-attr`, `aria-required-attr`, `aria-required-children`, `aria-valid-attr-value`. · render
|
|
74
|
+
|
|
75
|
+
## Motion
|
|
76
|
+
|
|
77
|
+
- `mot-01` UI transitions 150–250ms default (micro 100–150, state 200–300, larger 300–500); hard ceiling 500ms.
|
|
78
|
+
- `mot-03` Every animation gated on `prefers-reduced-motion` (0.01ms reset).
|
|
79
|
+
- `mot-04` Ban spring/bounce easing on operator surfaces; ban linear everywhere; easing strings from the token set (ease-out `cubic-bezier(0,0,0.2,1)`); no orchestrated page-load sequences.
|
|
80
|
+
- `mot-05` Animate only `transform` and `opacity`; never top, left, width, height, or margin.
|
|
81
|
+
- `mot-06` `will-change` only on an in-progress `transform`/`opacity` animation; never blanket, never left dangling.
|
|
82
|
+
- `mot-07` Loading indicators skeleton the content shape; delay 150–300ms; nothing < 500ms, spinner/skeleton 500ms–2s, progress bar > 2s.
|
|
83
|
+
- `mot-09` Ban scroll-event listeners for animation (`window.addEventListener('scroll')`); observers or scrubbing only.
|
|
84
|
+
- `mot-10` Ban `useState` for continuous scroll/pointer values; motion values instead. React-scoped.
|
|
85
|
+
|
|
86
|
+
## States
|
|
87
|
+
|
|
88
|
+
- `sta-01` Every data surface ships loading, empty, error, and partial/degraded states; plus post-action, cancel, disconnection/timeout, and concurrent-edit where they exist.
|
|
89
|
+
- `sta-02` Empty states text-first, at most one action; never a dead-end on actionable surfaces, never a literal no-data message; copy 1–2 sentences.
|
|
90
|
+
- `sta-03` Error states never dead-end: what happened / why / how to recover; an error render must carry a recovery affordance (the machine shell), the three-part copy quality is judged.
|
|
91
|
+
- `sta-05` Toasts auto-dismiss 3–5s, `aria-live="polite"`, never steal focus.
|
|
92
|
+
|
|
93
|
+
## Code & tokens
|
|
94
|
+
|
|
95
|
+
- `cod-01` Emitted CSS defines every token the substrate consumes.
|
|
96
|
+
- `cod-02` On improve runs, every value stays inside the lever manifest's vocabulary.
|
|
97
|
+
- `cod-03` Every color, spacing, radius, and duration in a diff resolves to an emitted token.
|
|
98
|
+
- `cod-04` Ban elision comments (`// rest of code`, `// ...`, `// TODO`, "for brevity"); files compile before done.
|
|
99
|
+
- `cod-05` Anti-fabrication: no invented metrics, no fake round numbers (99.99%, 50%), no "BY THE NUMBERS" sections, no John Doe/Acme/Nexus names; fake-precise mock numbers carry a mock marker; unknowable values use a `[bracket]` placeholder.
|
|
100
|
+
- `cod-06` No emoji anywhere, no emoji-as-icons; inline SVG only, one icon family per app, strokeWidth 1.5 or 2; never hand-rolled icon paths.
|
|
101
|
+
- `cod-07` Check dependencies before importing; fonts self-hosted or `next/font` with `font-display: swap`; never a Google Fonts `<link>` in prod.
|
|
102
|
+
- `cod-08` Image placeholders deterministic (`picsum.photos/seed/{seed}/{w}/{h}`); images declare dimensions; `loading="lazy"` below the fold.
|
|
103
|
+
- `cod-09` Component line ceilings: < 120 ln table, < 80 ln section; never modify files outside scope.
|
|
104
|
+
- `cod-11` Every emitted component exports a typed Props interface; no HTML tags in React Native output.
|
|
105
|
+
- `cod-12` Runtime budgets: LCP < 2.5s, INP < 200ms, CLS < 0.1, 16ms frame. · render
|
|
106
|
+
|
|
107
|
+
## Mandatory procedures (never skip)
|
|
108
|
+
|
|
109
|
+
- `proc-01` Extract levers into a `design.md` before any improve run on a foreign UI.
|
|
110
|
+
- `proc-02` Ask the reader question before any introspect run — one question, every run, never a stored default.
|
|
111
|
+
- `proc-03` Run the object pass (six-archetype catalog) before screens; a small brief earns a small pass, never a skipped one.
|
|
112
|
+
- `proc-04` Declare the density tier per surface archetype before emission (global tier + per-archetype modifiers).
|
|
113
|
+
- `proc-05` Name the taste anchor before look decisions: project `design.md` > library entry > Nurix default.
|
|
114
|
+
- `proc-06` Run the self-critique pass against the brief and the ban list before declaring a create run done.
|
|
115
|
+
- `proc-07` Resolve the design system and persist it (`personality.css`) before any UI code.
|
|
116
|
+
- `proc-08` Token-lock at emission: after resolution, no value lands outside the emitted token file.
|
|
117
|
+
- `proc-09` Run the mechanical pre-flight self-count: count rule instances against thresholds; the output fails if over.
|
|
118
|
+
- `proc-10` Run the numeric-anchored self-audit passes, each with an exact-value criterion (canvas, corners-on-scale, shadows, link hover).
|
|
119
|
+
- `proc-11` Follow the fixed audit ordering — hierarchy → typography → palette → spacing → buttons → clutter → empty states → shadows → contrast → grouping — then consolidate, dedupe, severity-rank, report before → after.
|
|
120
|
+
- `proc-12` Run the copy self-audit: re-read every visible string, rewrite every flagged one.
|
|
121
|
+
- `proc-13` Sweep viewports (375/768/1024/1440) before done; any horizontal scroll means broken — fix, don't ship.
|
|
122
|
+
- `proc-14` Cross-check scope: compare deliverable count against scope count; add anything missing before responding.
|
|
123
|
+
|
|
124
|
+
## Judged dimensions
|
|
125
|
+
|
|
126
|
+
Not gated — diagnosed. Each names what the judgment covers; the mechanics live in [diagnosis.md](diagnosis.md).
|
|
127
|
+
|
|
128
|
+
- `typ-04` Line-height inverse to size (body 1.4–1.6, headings 1.1–1.3); prose only, dense tables run tighter.
|
|
129
|
+
- `typ-13` Dense-app type ladder is advisory; the declared scale wins.
|
|
130
|
+
- `typ-17` AI-default fonts (Inter-as-reflex, Roboto/Arial/system, Space Grotesk) are house-taste flags.
|
|
131
|
+
- `col-11` Hover darkens the base shade 10–15%; nearest token-ramp step wins.
|
|
132
|
+
- `col-12` AI-slop palette: purple/blue neon glows and gradients, purple-on-white, reflex `#3B82F6`.
|
|
133
|
+
- `col-15` One grey family per app; a deliberate warm/cool split is a brand decision.
|
|
134
|
+
- `spc-05` Group spacing > within-group spacing (within 4–16px, between 24–64px); what reads as a group is judged.
|
|
135
|
+
- `spc-11` Container max-width ~1400px / `max-w-7xl`; operator surfaces may be full-bleed.
|
|
136
|
+
- `spc-12` Section rhythm 80px dense vs 96px marketing; advisory.
|
|
137
|
+
- `spc-13` Cockpit rule above density 7: no card boxes, hairline dividers, tight padding, mono numbers.
|
|
138
|
+
- `spc-14` Content-overload ceilings (> 7 action areas, 15+ elements, 12+ required fields, nav 5–9); dense surfaces may exceed.
|
|
139
|
+
- `dep-03` Dashboard ≤ ~4 primary metrics above the fold; command centers may exceed.
|
|
140
|
+
- `int-05` Undo over confirm for reversible actions; irreversible without confirm + undo is auto-critical.
|
|
141
|
+
- `int-06` Optimistic updates only for low-stakes actions, always with rollback.
|
|
142
|
+
- `int-07` Validate on blur, not per keystroke; strength meters and counters are exempt.
|
|
143
|
+
- `int-13` One primary CTA per screen/region; one per pane on multi-pane surfaces.
|
|
144
|
+
- `int-15` Virtualize lists ≥ 50 items; bounded/paginated lists exempt.
|
|
145
|
+
- `int-16` Tactile press feedback (−1px translateY / scale 0.98, < 100–150ms); suppressed under reduced-motion.
|
|
146
|
+
- `mot-02` Per-interaction reference durations (button 100 / hover 150 / tooltip 200 / tab 250 / modal 300 / page 400ms) — reference, not a ban.
|
|
147
|
+
- `mot-08` Stagger 30–50ms/item, cap ~8 children, total < 1s; operator surfaces skip orchestration.
|
|
148
|
+
- `mot-11` Exit 60–70% of enter; press scale 0.95–1.05; ≤ 1–2 animated elements per view.
|
|
149
|
+
- `sta-04` Errors render inline near the field, not banner-only; system-wide failures may banner.
|
|
150
|
+
- `sta-06` Empty-state taxonomy: first-time / user-cleared / no-results / no-access / error, distinct copy each.
|
|
151
|
+
- `cod-10` No div-built fake product screenshots.
|
|
152
|
+
- `cod-13` Audit output carries a numeric before → after per finding; no vague "feels".
|
|
153
|
+
- `cod-14` One name per concept, one concept per name across UI copy, help text, and API names.
|
|
154
|
+
- `inst-01`–`inst-11` Render instruments (edge density, feature congestion, subband entropy, grid quality, white-space ratio, symmetry, figure-ground contrast, contour congestion, colorfulness, distinct-RGB count, KLM operator-cost) — evidence inside judged findings, never gates; see [diagnosis.md](diagnosis.md).
|
|
155
|
+
- `trust-01`–`trust-04` AI-surface trust rubric (disclosure, human override, consent-gated irreversible actions, auditability); the first three grade auto-critical when absent; see [../data/operator-pack/trust-rubric.md](../data/operator-pack/trust-rubric.md).
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Improve — the engine
|
|
2
|
+
|
|
3
|
+
> Loaded when the front gate routes to improve. Pairs with [diagnosis.md](diagnosis.md) (the finding source and format) and reuses [create.md](create.md)'s per-edit detector loop on apply. Improve is every change to a UI that **already exists**; [create.md](create.md) owns the case where nothing does.
|
|
4
|
+
|
|
5
|
+
Improve is one engine, not a set of commands. Every improvement — a review, a polish, a full redesign, a typography-only pass — is the same engine run at a different point on three axes. The familiar verbs are parameter bindings, not sibling workflows: there is no `review.md`, no `redesign.md`.
|
|
6
|
+
|
|
7
|
+
## The three axes
|
|
8
|
+
|
|
9
|
+
- **Scope** — what the run touches: one taxonomy dimension (e.g. `P1 Typography`), one surface, or the whole app. Scope is the diagnosis pass filter and the diff boundary at once.
|
|
10
|
+
- **Depth** — `diagnose-only ↔ apply`. Diagnose-only emits ranked findings and stops. Apply edits the files the findings name.
|
|
11
|
+
- **Authority** — `lever-jailed ↔ lever-consent`. Jailed (the default): emit only values inside the lever manifest's vocabulary. Lever-consent: the manifest itself may change — but only the changes the user has consented to.
|
|
12
|
+
|
|
13
|
+
Any point in the cube is reachable directly. The presets below are the common ones.
|
|
14
|
+
|
|
15
|
+
## Preset verbs
|
|
16
|
+
|
|
17
|
+
Bindings over the engine, in one table. Never restated as separate files.
|
|
18
|
+
|
|
19
|
+
| Verb | Scope | Depth | Authority | Run |
|
|
20
|
+
| --- | --- | --- | --- | --- |
|
|
21
|
+
| `review` | whole app | diagnose-only | jailed | Rank findings across the app; change nothing. |
|
|
22
|
+
| `polish` | whole app | apply | jailed | Fix everything reachable inside the current levers. |
|
|
23
|
+
| `redesign` | whole app | apply | lever-consent | Apply the consented lever changes, then polish within the new manifest. |
|
|
24
|
+
| `typeset` | `P1 Typography` | apply | jailed | Apply, scoped to the Typography dimension only. |
|
|
25
|
+
|
|
26
|
+
A narrower or wider pass — one surface, one other dimension — is the same table with the scope cell moved. Bind the parameters; do not author a verb.
|
|
27
|
+
|
|
28
|
+
## The golden rule: jailed to the lever manifest
|
|
29
|
+
|
|
30
|
+
A design skill improves a UI **using the levers already in it**. Emitting design disjoint from the surrounding UI is a failure, not a style choice.
|
|
31
|
+
|
|
32
|
+
The project's `design.md` is the **lever manifest** — its `lever-manifest` block (fonts, color tokens, spacing scale, radius scale, shadow levels, motion durations/easings, icon family, accent count). Read it **first**, before any diagnosis or edit.
|
|
33
|
+
|
|
34
|
+
### When the UI wasn't built by this skill: extract first
|
|
35
|
+
|
|
36
|
+
No `design.md` at project root ⇒ recover one from the code before touching anything.
|
|
37
|
+
|
|
38
|
+
1. **Scan the source for what IS** — the fonts actually in use, the literal color values that recur, the spacing steps, the radii, the durations, the icon family and stroke.
|
|
39
|
+
2. **Write them into a `design.md`** at project root with frontmatter `provenance: extracted`, `sourced: <date>`, populated `lever-manifest` and `design-primitives` blocks.
|
|
40
|
+
3. **Extraction records what IS, never what should be.** A UI running five fonts extracts five fonts. The reduction to two is a tier-two finding (below) — not an extraction edit.
|
|
41
|
+
4. Run the coverage gate over it (`derive-personality.mjs --check`) exactly as over any other `design.md`.
|
|
42
|
+
|
|
43
|
+
### The jail is mechanical
|
|
44
|
+
|
|
45
|
+
An improve run may emit only values inside the manifest's vocabulary — on-scale spacings, manifest fonts, manifest colors, manifest radii and durations. This is not advice. The detector's drift check reads the manifest (`detector.mjs <file> --manifest design.md`) and fails any edit that emits a value outside it, with the same fix-or-classify wall create runs into. There is no waiver.
|
|
46
|
+
|
|
47
|
+
## Tier-two escalation: when the levers themselves are wrong
|
|
48
|
+
|
|
49
|
+
Diagnosis may find the fundamentals wrong — five fonts where two would do, three competing accents, an off-scale spacing habit. Those are `tier: lever-change` findings (the diagnosis format's tier field). Fixing them means changing the manifest, which the jail forbids. The protocol:
|
|
50
|
+
|
|
51
|
+
1. **Finish the within-levers work first.** Polish everything reachable inside the current jail.
|
|
52
|
+
2. **Report the fundamentals as tier-two findings** — same canonical format, `tier: lever-change` — phrased as the change and its whole-UI payoff: *"these three changes would make the whole UI consistent."*
|
|
53
|
+
3. **Offer** a follow-up run with lever authority. Never change fundamentals unbidden.
|
|
54
|
+
|
|
55
|
+
Authority defaults to jailed; lever changes are consent-gated. The skill does not escalate itself — the user triggers the follow-up.
|
|
56
|
+
|
|
57
|
+
A lever-consent run (redesign-shaped) does **not** unjail emission. It rewrites the manifest first — the consented changes only — then proceeds jailed to the **new** vocabulary. The drift check reads the updated manifest, so there is never an unjailed emit; the jail moves, it never opens.
|
|
58
|
+
|
|
59
|
+
[introspect.md](introspect.md) runs this handshake in reverse: an introspect report's tier-two findings can seed a consented improve run.
|
|
60
|
+
|
|
61
|
+
## Findings come from the diagnosis engine
|
|
62
|
+
|
|
63
|
+
Improve does not diagnose on its own. It runs the shared diagnosis engine ([diagnosis.md](diagnosis.md)) scoped to the run's scope axis, causes-first (Structure → Behavior → Perception).
|
|
64
|
+
|
|
65
|
+
Findings use the canonical format verbatim — dimension · cause layer · evidence (file:line / token / value) · before→after (numeric where machine-backed) · consequence · tier · severity · provenance. The list is severity-ranked (auto-critical → critical → major → minor). No numeric scores, ever.
|
|
66
|
+
|
|
67
|
+
Diagnose-only depth stops here: the ranked list is the deliverable. Rendering it per reader register is [introspect.md](introspect.md)'s job, not improve's.
|
|
68
|
+
|
|
69
|
+
## Apply depth: the same wall as create
|
|
70
|
+
|
|
71
|
+
Every apply-depth edit passes through the **same per-edit detector loop create uses**: the default-on hook fires the detector plus the drift check on the write, injects the imperative fix-or-classify directive on any violation, and re-nudges until resolved. No improve edit is exempt. An apply run is create's emission discipline pointed at files that already exist.
|
|
72
|
+
|
|
73
|
+
## Diff-scope discipline
|
|
74
|
+
|
|
75
|
+
An improve run edits **only the files its findings name**. A run that writes a file outside its findings fails the pre-ship scope cross-check (`preship-sweep.mjs`).
|
|
76
|
+
|
|
77
|
+
The universal preservation list holds regardless of scope or depth — never silently changed: route slugs, navigation labels, form-field names and order, analytics/event identifiers, API and data-contract shapes, and generated files. Per-project additions to this list, if ever needed, are entries in the project's `design.md` — data, not run configuration.
|
|
78
|
+
|
|
79
|
+
## Run shape
|
|
80
|
+
|
|
81
|
+
1. **Read the lever manifest.** Extract one from the code first if absent.
|
|
82
|
+
2. **Diagnose** scoped to the run's scope, causes-first; rank; split `within-levers` from `lever-change`.
|
|
83
|
+
3. **Diagnose-only** → deliver the ranked findings and stop.
|
|
84
|
+
4. **Apply** → edit only the files the findings name, each through the detector loop, jailed to the manifest.
|
|
85
|
+
5. **Escalate** → report the tier-two findings and offer the consented lever-authority follow-up.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Interaction — keyboard-first control
|
|
2
|
+
|
|
3
|
+
The operator keeps both hands on the keyboard and all attention on the task. This file is the interaction floor that preserves both: the state contract, focus discipline, overlay policy, consequence design, and the keyboard-first operator patterns.
|
|
4
|
+
|
|
5
|
+
**Seams.** Element-level states (a button, a field, a row) live here. Surface-level lifecycle states — a data surface's loading / empty / error / degraded — and the error and empty-state copy formulas live in [lifecycle.md](lifecycle.md). Do not conflate a button's inline spinner with a surface's skeleton. Thresholds (ring contrast and width, target geometry, dialog mechanics) live in the catalog; this file names the contracts and cites the rule family by anchor prefix (`int-*` interaction, `sta-*` states, `mot-*` motion, `trust-*` AI trust) — it never restates the numbers. The boot-loaded imperative lines are in [hard-rules.md](hard-rules.md); the render-only checks run at the render rung (D32, [diagnosis.md](diagnosis.md)).
|
|
6
|
+
|
|
7
|
+
## The state contract
|
|
8
|
+
|
|
9
|
+
Every interactive element ships all its states, designed, never left to the substrate's defaults. Each state communicates one fact to the operator:
|
|
10
|
+
|
|
11
|
+
| State | Must communicate |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| default | the element is here and actionable |
|
|
14
|
+
| hover | the pointer is over an actionable target |
|
|
15
|
+
| focus | the keyboard is on this element right now |
|
|
16
|
+
| active | the press registered (tactile feedback) |
|
|
17
|
+
| disabled | present but not actionable, and legibly why-context |
|
|
18
|
+
| loading | the action is in flight; the element is busy, not broken |
|
|
19
|
+
| error | this element's input or action failed, stated inline |
|
|
20
|
+
| success | the action landed |
|
|
21
|
+
|
|
22
|
+
Hover and focus are **different states for different users** — a pointer user reads hover, a keyboard user reads focus. Designing hover without a focus state strands every keyboard operator; it is the characteristic failure this contract exists to stop. Button-tier states (default / hover / active / focus / disabled) are presence-checked machine rules (`int-*`); distinct button tiers hold, one primary per region.
|
|
23
|
+
|
|
24
|
+
The **error** state surfaces on blur, never per keystroke (`int-*`), and renders inline below the offending field — never banner-only for a field error. The error *copy* follows lifecycle.md's error formula. The **active** state's tactile press feedback rides the motion rules (`mot-*`, suppressed under reduced-motion); its timing tokens live in [personality.md](personality.md).
|
|
25
|
+
|
|
26
|
+
## Focus discipline
|
|
27
|
+
|
|
28
|
+
- **Visible focus, always.** Every focusable element carries a `:focus-visible` ring driven by the `--ring` token so it follows the look. `outline: none` without a replacement is banned (`int-*`). The ring meets the catalog's contrast and width floor — do not restate it, satisfy it.
|
|
29
|
+
- **Focus order follows task order.** Tab order is the sequence the operator works, not a DOM accident. Composite widgets — tables, listboxes, menus, toolbars — use roving tabindex: the widget is one tab-stop, arrow keys traverse inside it.
|
|
30
|
+
- **Focus is returned on overlay close.** Opening an overlay moves focus into it; closing returns focus to the element that opened it. Focus never drops to the top of the document.
|
|
31
|
+
- **Keyboard path parity.** Every pointer affordance has a keyboard equivalent — nothing is reachable by hover or click alone (floor P6). Hover-revealed row actions carry a focus path (`int-*`). `cursor: pointer` marks every clickable element on the web (`int-*`).
|
|
32
|
+
- **Skip links** jump to the primary work region on any surface with substantial navigation.
|
|
33
|
+
|
|
34
|
+
## Overlay policy
|
|
35
|
+
|
|
36
|
+
Escalate only as far as the interaction demands, cheapest rung first (floor P3):
|
|
37
|
+
|
|
38
|
+
1. **Inline expansion** — reveal detail in place; no overlay at all.
|
|
39
|
+
2. **Side panel** — detail and edit open *beside* the work, not on top of it (`--side-panel-width` / `--side-panel-width-rich`). This is the default for viewing and editing an entity.
|
|
40
|
+
3. **Modal** — last, and only when earned.
|
|
41
|
+
|
|
42
|
+
A modal is earned by exactly two cases: a **destructive or irreversible confirmation**, or a **self-contained one-to-two-field action** that must block the surface until answered. Anything larger — a full form, a multi-field edit, a record's detail — is a side panel or its own route, never a modal.
|
|
43
|
+
|
|
44
|
+
Modal mechanics are structural: a native `<dialog>` with the background marked `inert`, so focus containment comes from the platform, not a scripted trap (`int-*`). One modal at a time — **nested modals are banned** (`int-*`); a second decision is either a step inside the first or a side panel. `--modal-width-max` caps width; a modal that needs its own scroll is really a side panel or a page.
|
|
45
|
+
|
|
46
|
+
## Consequence design
|
|
47
|
+
|
|
48
|
+
Match the affordance to the action's reversibility:
|
|
49
|
+
|
|
50
|
+
- **Reversible action → undo, not confirm.** Perform it immediately; offer an undo affordance (`int-*`). A confirmation dialog on a reversible action is friction the operator pays on every repetition.
|
|
51
|
+
- **Destructive irreversible action → confirm, with the consequence stated**, plus undo wherever the substrate allows a window. An irreversible action with neither confirmation nor undo is graded **auto-critical** in diagnosis (`int-*`; severity per D22).
|
|
52
|
+
- **Consequence visible before commit.** Irreversible actions preview-then-commit: the operator sees what will happen — rows affected, records deleted, the exact scope — before the commit control.
|
|
53
|
+
- **Optimistic updates only for low-stakes actions, always with rollback** and a visible reconcile on failure (`int-*`). High-stakes writes await server confirmation; they do not fake success.
|
|
54
|
+
|
|
55
|
+
## Keyboard-first operator patterns
|
|
56
|
+
|
|
57
|
+
- **Command palette** (`cmdk`) is the power-user's front door — global verbs, entity jump, reachable by a single chord. Expected on any multi-surface operator tool.
|
|
58
|
+
- **Row-level keyboard actions in queues.** A queue row is focusable; the frequent verbs (open, assign, resolve, advance) bind to keys; the kebab overflow is keyboard-reachable, not pointer-only. Roving tabindex moves between rows, and the row's keyboard action set mirrors its pointer menu exactly — no verb is pointer-only.
|
|
59
|
+
- **Tab-stop economics on the core loop.** The operator's core loop ([structure.md](structure.md)) must complete in few keystrokes and homings. Every tab-stop on the hot path is a cost paid per item, per shift — prune stops that do not earn their place, and keep the primary verb one key away.
|
|
60
|
+
- **KLM is the diagnosis lens, not a gate.** Counting the keystrokes, pointer homings, and mental operators of a fixed core-loop path (the Keystroke-Level Model) turns "this feels slow" into a number. It rides [diagnosis.md](diagnosis.md) as a judged instrument against floor P1's throughput metric — evidence inside a finding, never a machine verdict.
|
|
61
|
+
|
|
62
|
+
## Assistive floors beyond keyboard
|
|
63
|
+
|
|
64
|
+
Presence-shaped, machine-checked wherever the rule holds universally (D26b; catalog plus render rung):
|
|
65
|
+
|
|
66
|
+
- `aria-live` region wherever async status renders (`int-*`); toasts announce politely and never steal focus.
|
|
67
|
+
- `aria-sort` on sortable headers (`int-*`).
|
|
68
|
+
- `<dialog>` / `inert` containment on every modal (`int-*`).
|
|
69
|
+
- The visible `:focus-visible` ring meeting the contrast and width floor (`int-*`).
|
|
70
|
+
- Labels visible and above the input; placeholder-as-label is banned on form fields (`int-*`).
|
|
71
|
+
- Accessible-name on every interactive element and image (axe `button-name` / `select-name` / `image-alt` / `link-name`); ARIA validity (`aria-allowed-attr` and family); minimum target geometry — all resolved at the render rung (`int-*`, D32).
|
|
72
|
+
|
|
73
|
+
**Judged, not machine:** reading order beyond raw DOM sequence, screen-reader narration quality, whether a live region's politeness matches the update's urgency, and cognitive load. These are diagnosis dimensions ([diagnosis.md](diagnosis.md)), not presence flags.
|
|
74
|
+
|
|
75
|
+
## AI surfaces
|
|
76
|
+
|
|
77
|
+
Interaction governance for embedded AI and copilot surfaces — presence disclosed, a human override path always visible, irreversible AI-initiated actions consent-gated with preview, actions auditable — defers wholesale to the trust rubric ([trust-rubric.md](../data/operator-pack/trust-rubric.md)); it is not restated here.
|