baldart 4.77.0 → 4.78.1
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 +33 -0
- package/README.md +14 -13
- package/VERSION +1 -1
- package/framework/.claude/agents/REGISTRY.md +2 -1
- package/framework/.claude/agents/markup-fidelity-verifier.md +239 -0
- package/framework/.claude/agents/prd-card-writer.md +6 -1
- package/framework/.claude/agents/visual-fidelity-verifier.md +22 -0
- package/framework/.claude/skills/ds-edit/SKILL.md +9 -0
- package/framework/.claude/skills/ds-new/SKILL.md +8 -0
- package/framework/.claude/skills/e2e-review/SKILL.md +196 -27
- package/framework/.claude/skills/new/references/codex-gate.md +15 -1
- package/framework/.claude/skills/new/references/completeness.md +2 -0
- package/framework/.claude/skills/new/references/review-cycle.md +14 -1
- package/framework/agents/design-system-protocol.md +78 -0
- package/framework/templates/overlays/e2e-review.fidelity-example.md +74 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,39 @@ 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.78.1] - 2026-06-29
|
|
9
|
+
|
|
10
|
+
**`/ds-new` + `/ds-edit` now close the closed-loop (the `DS_MIRROR_STALE` nudge).** The mirror advisory — check #6 of the Post-Intervention Coherence Check, which nudges `/design-sync publish` when the in-repo registry has moved ahead of its Claude Design satellite — was cited by **every** UI-touching surface (`code-reviewer`, `ui-design`, `/design-review`, `/new` implement, `/prd` ui-design-phase, the `ds-drift` backstop) **except the two skills whose whole job is to create/modify a canonical element**: `/ds-new` and `/ds-edit`. So creating a primitive with `/ds-new` on a satellite-bound project never reminded the user to publish it — the one event that most directly makes the mirror stale was the one that skipped the nudge. This release adds the citation to both skills' step-8 coherence report.
|
|
11
|
+
|
|
12
|
+
**PATCH** — doc-only completion of an existing advisory check; no new capability, no agent, **no `baldart.config.yml` key** (the check rides on the already-present `features.has_design_system` + the satellite-bound gate). The definition stays the single SSOT in `design-system-protocol.md` § Post-Intervention Coherence Check check #6 — the skills **cite, never redefine** it. Skipped when no satellite is bound (the vast majority of consumers → no-op); never blocks creation/edit.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **`/ds-new`** (`framework/.claude/skills/ds-new/SKILL.md`) — step 8 coherence report now surfaces `DS_MIRROR_STALE` (advisory, non-blocking) nudging `/design-sync publish` when a Claude Design satellite is bound (`.baldart/design-sync.json` has a `project_id`); added a `See Also` pointer to `/design-sync`.
|
|
17
|
+
- **`/ds-edit`** (`framework/.claude/skills/ds-edit/SKILL.md`) — same step-8 mirror advisory, with the breaking-edit note that satellite drift is the same class as the migration; added the `/design-sync` `See Also` pointer.
|
|
18
|
+
|
|
19
|
+
## [4.78.0] - 2026-06-29
|
|
20
|
+
|
|
21
|
+
**Route-independent per-card mockup fidelity + graphics fast-lane.** On a `/new` run a desktop "Edit product" page shipped as **1 column** against a **2-column** mockup, marked DONE: the fidelity gate never ran on a rendered page because the auth-gated route returned 500 under the empty-Supabase demo lane, the views were "soft-skipped", and the verdict came back `ACCEPTED (harness limit)` — **a skip masked as a pass**. Two adversarial passes found this is not one bug but two distinct holes hitting two cards, plus the fact that the fidelity check depended on rendering a live, data-bearing route at all. This release inverts the priority: per-card UI fidelity is verified **route-independently, before proceeding** — a code-structural diff first, an isolated render as confirmation — and an un-runnable required check now **blocks instead of silently passing**. Bets validated against 2026 best practice (structural TED + perceptual diff as complementary dimensions; MLLM-as-judge reliable at comparison, weak at absolute scoring → fidelity gates, quality stays advisory).
|
|
22
|
+
|
|
23
|
+
**MINOR** — adds an agent (`markup-fidelity-verifier`, 30→31) + capability. **No new `baldart.config.yml` key** (rides on `features.has_e2e_review` + `features.has_design_system`), so the schema-change propagation rule does NOT apply. Claude + Codex portable (the structural pass is Read-only; the image-load/isolated-render degrade to no-op where unavailable).
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **`markup-fidelity-verifier` agent** (`framework/.claude/agents/markup-fidelity-verifier.md`, `model: sonnet`) — the **route-independent structural twin** of `visual-fidelity-verifier`. Compares the implementation's code structure against the mockup expressed as code (`links.design` HTML or `links.design_src`/`mockups/_src/`) with no browser/auth/data — the DOM tree-edit-distance analogue, complementary to the visual verifier's pixel/perceptual diff. Deterministically catches the **2-column-mockup → 1-column-build** class of divergence. READS code (mockup-vs-impl, no assertion-fitting risk); same canonical taxonomy + JSON output; fixes route to `ui-expert`.
|
|
28
|
+
- **`/e2e-review` Phase 2.7 — Structural Fidelity (route-free)** — runs the `markup-fidelity-verifier` BEFORE the browser passes, on every card with an HTML/`design_src` mockup. The workhorse of per-card fidelity.
|
|
29
|
+
- **`/e2e-review` Phase 3.8 — Comparable-render gate (state-aware)** — the reviewer never accepts "opened it, it's empty, skip". Detects a degenerate render (non-2xx / empty-state / wrong tenant) and runs a bounded **reach-state loop** (overlay recipes `seed_data` / `select_populated_context` / `goto_populated_entity`, with generic fallbacks: real auth, MSW/API-mock, deterministic factory/snapshot, heuristic context auto-seek) before diffing. New `data-state-mismatch` (Critical) finding.
|
|
30
|
+
- **Coverage obligation** — new `coverage-gap` (Critical) finding synthesized when an image-only mockup route could not be rendered in any lane and its state could not be reached; maps to the existing `blocked` verdict, bypasses the self-heal loop. Guards exclude `skip`/`harness-render`/`compliance-only`/mobile-pass. This turns the FEAT-0061 "skip masked as pass" into a real block.
|
|
31
|
+
- **Starter overlay** `framework/templates/overlays/e2e-review.fidelity-example.md` — schema for project-specific reach-state recipes.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- **`visual-fidelity-verifier`** — `coverage-gap` + `data-state-mismatch` added to the canonical severity taxonomy (SSOT); new "Data-State Awareness" rule: never compare a degenerate render, emit `data-state-mismatch` instead of a silent skip/pass.
|
|
36
|
+
- **`/e2e-review` Phase 2** ingests **HTML mockups** (`links.design` `.html` → headless `file://` render to PNG for the visual pass + retained as code for the structural pass) and recognizes `links.design_src`. **Phase 5b self-heal** routes ALL fidelity fixes (structural/presentational/quality) to `ui-expert`; `coder` only for genuine wiring.
|
|
37
|
+
- **`/new` graphics fast-lane** — a **pure-graphics card** (`owner_agent: ui-expert` + `review_profile: light` + `areas == [ui]` + zero Step-A triggers) skips Simplify (Phase 2.55) and per-card Codex (Phase 3.7); qa is the build/lint/tsc floor; the `/e2e-review` fidelity trio is the review. Safety net preserved by the batch-wide Final FULL Codex gate. Wired in `review-cycle.md`, `codex-gate.md`, `prd-card-writer.md` (emit `owner_agent: ui-expert` on Rule C branch-(b) cards).
|
|
38
|
+
- **`/new` no cross-card fidelity deferral** — `completeness.md` Phase 2.5b Step 4 fidelity-AC carve-out: a visual-fidelity AC cannot be silently deferred ("Approva il deferral" withheld) — only implement-now (→ `ui-expert`), explicit follow-up card, or halt. `review-cycle.md` Phase 2.6: a fidelity AC closes only on a real `passed`, never a `skipped`.
|
|
39
|
+
- **`design-system-protocol.md`** — new SSOT section "Route-Independent Fidelity & Coverage Obligation" (structural fidelity, visual confirmation, state-aware fidelity, coverage obligation, graphics-card rule, gating calibration) cited by `/e2e-review`, `/new`, `/design-review`.
|
|
40
|
+
|
|
8
41
|
## [4.77.0] - 2026-06-29
|
|
9
42
|
|
|
10
43
|
**TS-aware design-system extractor + the `variant_prop` HEAD field.** The component-manifest extractor was pure-regex (zero-dep) and could not resolve TypeScript: a `type Variant = 'a'|'b'; variant: Variant` captured the alias *name* `"Variant"`, not its members, so on a TS-strict consumer (mayo) every HEAD came out with `variants: []` and ~25 with `props: {}`. Since the HEAD is the SSOT every UI agent reads for discovery, `variants: []` on a 6-variant Button induces wrong code. Separately, the variant axis was **hardcoded** to the prop name `variant` in three places — wrong for a `Chip`/`Pill` whose axis is `tone`. This release makes the extractor **optionally TS-aware** (it borrows the consumer's own `typescript`, resolved from the repo root) and adds a deterministic **`variant_prop`** field naming the real axis.
|
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ No additional activation steps needed — once installed, Claude Code (and Codex
|
|
|
85
85
|
- **agents/**: 26 domain modules (architecture, workflows, testing, security, card-schema, i18n-protocol, return-contract-protocol, component-manifest-schema, etc.)
|
|
86
86
|
- **Routing**: If you touch X, read Y - minimize context loading
|
|
87
87
|
|
|
88
|
-
### AI Agents (
|
|
88
|
+
### AI Agents (32 specialized agents)
|
|
89
89
|
|
|
90
90
|
**Core (required for every project)**
|
|
91
91
|
1. **codebase-architect**: MANDATORY before planning/implementation - understands codebase structure
|
|
@@ -108,22 +108,23 @@ No additional activation steps needed — once installed, Claude Code (and Codex
|
|
|
108
108
|
16. **hyper-gamification-designer**: Game mechanics, retention loops, economy balance
|
|
109
109
|
17. **remotion-animator-orchestrator**: Video/motion graphics with Remotion
|
|
110
110
|
18. **visual-fidelity-verifier** (v3.18.0): Stateless multimodal worker auto-invoked by `/e2e-review` Phase 4 — compares an implemented UI route against its mockup (or design-system spec) and returns a severity-tagged JSON report. Never reads source code (anti assertion-fitting bias), never edits, never declares done
|
|
111
|
-
19. **
|
|
111
|
+
19. **markup-fidelity-verifier** (v4.78.0): Route-INDEPENDENT structural twin of `visual-fidelity-verifier`, auto-invoked by `/e2e-review` Phase 2.7 — compares the implementation's code structure against the mockup expressed as code (`links.design` HTML or `links.design_src`) with no browser/auth/data, catching the 2-column-mockup → 1-column-build class of divergence. READS code (mockup-vs-impl, no assertion-fitting risk); same canonical taxonomy + JSON output; fixes route to `ui-expert`
|
|
112
|
+
20. **ui-quality-critic** (v4.61.0): Stateless multimodal worker auto-invoked by `/e2e-review` Phase 4b — judges the **intrinsic design quality** of an implemented UI (10-dimension scientific rubric: hierarchy, rhythm, color, density, composition, states, motion, polish, brand) and returns a severity-tagged JSON report + per-dimension scores. The design twin of `code-reviewer`, the quality complement of `visual-fidelity-verifier` (needs no mockup). Never reads source, never grades its own design; fixes route to `ui-expert` in the bounded self-heal loop
|
|
112
113
|
|
|
113
114
|
**Product & Marketing**
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
21. **onboarding-architect-lead**: User onboarding flow design and experimentation
|
|
116
|
+
22. **marketing-conversion-strategist**: High-converting copy and messaging
|
|
117
|
+
23. **seo-analytics-strategist**: SEO strategy, metadata, GA4/GTM event planning
|
|
118
|
+
24. **email-deliverability-architect**: Transactional/informational email design + SPF/DKIM/DMARC
|
|
119
|
+
25. **website-orchestrator**: Multi-agent website development coordination
|
|
119
120
|
|
|
120
121
|
**Specialized**
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
26. **hybrid-ml-architect**: ML/DL system design (recommenders, ranking, embeddings)
|
|
123
|
+
27. **legal-counsel-gdpr**: GDPR compliance, privacy policies, data governance
|
|
124
|
+
28. **deep-human-insight**: Psychological / sociological analysis for B2C UX and adoption
|
|
125
|
+
29. **skill-improver**: Weekly auto-improvement of skills/agents based on review/QA findings
|
|
126
|
+
30. **i18n-translator** (v4.52.0): Context-aware label translation into native locale files (Sonnet, low-effort, flag-not-guess) — invoked by `/i18n` + the `i18n-align` routine
|
|
127
|
+
31. **merge-conflict-resolver** (v4.64.0): Resolves the final-merge **code** conflicts OFF the orchestrator context — auto-spawned by `/new` Phase 6 / `/mw` only when the deterministic `merge-worktree.sh` pauses on a code/test conflict. Adjudicates additive-vs-semantic hunks (semantic → STOP), then lets the script land. Runs in a fresh isolated context so the conflict churn never re-enters the bloated end-of-batch orchestrator
|
|
127
128
|
|
|
128
129
|
REGISTRY.md is the single source of truth for agent routing and capabilities.
|
|
129
130
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.
|
|
1
|
+
4.78.1
|
|
@@ -25,7 +25,8 @@ Quick-reference for all custom agents. Use this to route tasks to the right spec
|
|
|
25
25
|
| **hybrid-ml-architect** | ML | Design/implement ML systems end-to-end | Recommender, ranking, embeddings | Yes | Model design, evaluation, monitoring |
|
|
26
26
|
| **i18n-translator** | Localization | Translate user-facing labels into the maintained target languages (invoked by `/i18n` + the `i18n-align` routine). Gated on `features.has_i18n`. | Context-aware translation using the per-key registry context, ICU/placeholder preservation, glossary adherence; bounded "flag-not-guess" self-healing (`needs-attention`) | Yes (writes native locale files ONLY — never app code, never the registry) | Native locale files, optional bulk backends (lingo.dev/languine) |
|
|
27
27
|
| **ui-expert** | Design | Design, implement, and review UI/UX | Mobile-first, accessibility, registry-first protocol gate (when `features.has_design_system: true`) — BLOCKING reads on `${paths.design_system}/INDEX.md` + `tokens-reference.md` + `components/<Name>.md` per `framework/agents/design-system-protocol.md`, Component Discovery cascade before any design | Yes (generates UI / HTML mockups in `ui-design` Step C; a separate fresh instance acts as design-quality evaluator in Step D) | ui-ux-pro-max, Playwright |
|
|
28
|
-
| **visual-fidelity-verifier** | Design | Compare an implemented UI route against its mockup (or design-system spec) and return a severity-tagged JSON report. Auto-invoked by `/e2e-review` skill (Phase 4) — never spawned ad-hoc. Stateless. Strict severity taxonomy (Critical / Major / Minor) — never reads source code (anti assertion-fitting bias), never edits, never declares done. | Visual diff, severity taxonomy, design-system compliance check via registry cascade | No | Vision (multimodal), Read (screenshots + registry only), Playwright screenshots passed in by orchestrator |
|
|
28
|
+
| **visual-fidelity-verifier** | Design | Compare an implemented UI route against its mockup (or design-system spec) and return a severity-tagged JSON report. Auto-invoked by `/e2e-review` skill (Phase 4) — never spawned ad-hoc. Stateless. Strict severity taxonomy (Critical / Major / Minor) — never reads source code (anti assertion-fitting bias), never edits, never declares done. Emits `data-state-mismatch` when the render is in the wrong data state. | Visual diff, severity taxonomy, design-system compliance check via registry cascade | No | Vision (multimodal), Read (screenshots + registry only), Playwright screenshots passed in by orchestrator |
|
|
29
|
+
| **markup-fidelity-verifier** | Design | **Route-INDEPENDENT structural twin** of `visual-fidelity-verifier`: compare the implementation's code structure against the mockup expressed as code (`links.design` HTML or `links.design_src`/`mockups/_src/`) and return a severity-tagged JSON report — no browser, no auth, no data. Catches the 2-column-mockup → 1-column-build class of divergence (FEAT-0061). Auto-invoked by `/e2e-review` (Phase 2.7) — never spawned ad-hoc. Stateless. READS code (mockup-vs-impl, no assertion-fitting risk), never renders, never edits, never declares done. Same canonical severity taxonomy + JSON output as `visual-fidelity-verifier`. Fixes route to `ui-expert`. | Code-structural diff (DOM tree-edit-distance analogue), layout/grid/order/token-bypass, design-to-code fidelity | No | Read (mockup markup + implementation source) |
|
|
29
30
|
| **ui-quality-critic** | Design | Judge the **intrinsic design quality** of an implemented UI screenshot against a scientific 10-dimension rubric (hierarchy, typographic & spacing rhythm, color/contrast, density, composition, states, motion, polish, brand) and return a severity-tagged JSON report + per-dimension scores. The design twin of `code-reviewer`; the fidelity complement of `visual-fidelity-verifier` (quality vs conformance — needs no mockup). Auto-invoked by `/e2e-review` (Phase 4b) — never spawned ad-hoc. Stateless, never reads source (anti assertion-fitting bias), never grades its own design, never edits, never declares done. Fixes route to `ui-expert`. Return Contract: JSON (already COMPACT). | Design-quality critique, rubric scoring, calibration anchors per dimension | No | Vision (multimodal), Read (screenshots + registry/guidelines only) |
|
|
30
31
|
| **visual-designer** | Design | Generate visual assets via Kie.ai | Illustrations, icons, hero images | Yes | Kie.ai API, WebP optimization |
|
|
31
32
|
| **motion-expert** | Design | Design animations and micro-interactions | Transitions, timing, easing | No | Animation specs, a11y fallbacks |
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: markup-fidelity-verifier
|
|
3
|
+
description: "Compare an implemented UI's CODE STRUCTURE against its design mockup expressed as code (the HTML of `links.design`, or the finished-code of `links.design_src` / `mockups/_src/`) and return a severity-tagged JSON report. Route-INDEPENDENT structural twin of `visual-fidelity-verifier` — needs no browser, no auth, no live data. Reads both the mockup markup and the implementation source; reports layout/structure divergence (the 2-column-mockup → 1-column-build class of failure). Stateless worker invoked by the /e2e-review skill (Phase 2.7) — never edits code, never renders, never declares done."
|
|
4
|
+
model: sonnet
|
|
5
|
+
color: orange
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the **Markup Fidelity Verifier**. You exist for one purpose: compare the
|
|
9
|
+
**code structure** of an implemented UI against the **code structure of its design
|
|
10
|
+
mockup** and return a deterministic, severity-tagged JSON report.
|
|
11
|
+
|
|
12
|
+
You are the **route-independent, structural twin** of `visual-fidelity-verifier`.
|
|
13
|
+
That agent compares *pixels* of a rendered screenshot against a mockup *image* — it
|
|
14
|
+
needs a working render (browser, auth, data). You compare *markup/CSS structure*
|
|
15
|
+
of the implementation source against the *markup structure of the mockup expressed
|
|
16
|
+
as code* — you need **neither a browser nor a live render**. This is the analogue of
|
|
17
|
+
**tree-edit-distance (TED) over the DOM** (the *structural* dimension of design-to-code
|
|
18
|
+
evaluation), complementary to the visual verifier's SSIM/CLIP/LPIPS *perceptual*
|
|
19
|
+
dimension. You catch the **2-column-mockup → 1-column-build** class of divergence
|
|
20
|
+
that a pixel diff never sees because the page never rendered.
|
|
21
|
+
|
|
22
|
+
You are stateless. You do not iterate. You do not fix. You do not render. You report
|
|
23
|
+
what the implementation's code says structurally versus what the mockup's code says,
|
|
24
|
+
with a severity tag and an actionable fix hint per finding. The orchestrating skill
|
|
25
|
+
(`/e2e-review`) decides what to do with your output.
|
|
26
|
+
|
|
27
|
+
**Scope vs the sibling verifiers.** You answer *"does the implementation's
|
|
28
|
+
layout/structure match the mockup's layout/structure, as expressed in code?"* —
|
|
29
|
+
**structural fidelity**. You do NOT judge pixel/perceptual match (`visual-fidelity-verifier`,
|
|
30
|
+
which needs a render) and you do NOT judge whether the design is *good*
|
|
31
|
+
(`ui-quality-critic`). Stay in your lane: structure derivable from code, cited at
|
|
32
|
+
`file:line`.
|
|
33
|
+
|
|
34
|
+
## Project Context
|
|
35
|
+
|
|
36
|
+
**Reads from `baldart.config.yml`:**
|
|
37
|
+
`paths.design_system`, `paths.components_primitives`, `paths.components_root`,
|
|
38
|
+
`paths.app_dir`, `paths.global_styles`,
|
|
39
|
+
`features.has_design_system`, `features.e2e_review.fidelity_tolerance`.
|
|
40
|
+
|
|
41
|
+
**Gated by features:** `features.has_e2e_review`. The agent refuses to run when
|
|
42
|
+
`false` — it exists only to support the `/e2e-review` skill.
|
|
43
|
+
|
|
44
|
+
**On missing/empty keys:** report the gap in the output JSON `gaps[]` and downgrade
|
|
45
|
+
gracefully (skip the check you lack inputs for). Do not assume defaults. See
|
|
46
|
+
`framework/agents/project-context.md` § 3.
|
|
47
|
+
|
|
48
|
+
## Hard Prohibitions (non-negotiable)
|
|
49
|
+
|
|
50
|
+
- **NEVER edit any file.** You produce a JSON report only. The orchestrator delegates
|
|
51
|
+
fixes to `ui-expert` (layout/structure is UI domain) in a self-heal loop.
|
|
52
|
+
- **NEVER render or screenshot.** You read code. If a divergence can only be confirmed
|
|
53
|
+
visually (color shade, anti-aliasing, sub-pixel offset), it is **out of your scope** —
|
|
54
|
+
leave it to `visual-fidelity-verifier`. Do not speculate about rendered appearance.
|
|
55
|
+
- **NEVER propose architectural refactors.** Your scope is structural fidelity to the
|
|
56
|
+
mockup, not component API design (that is `ui-expert`'s job).
|
|
57
|
+
- **NEVER declare a task "done" or "passed".** You return findings. The strict gate
|
|
58
|
+
logic lives in the `/e2e-review` skill — it decides pass/block/override.
|
|
59
|
+
|
|
60
|
+
**Note on reading source.** Unlike `visual-fidelity-verifier` (which is forbidden from
|
|
61
|
+
reading source to avoid assertion-fitting against a screenshot), reading code **is your
|
|
62
|
+
job**: you compare *mockup code* (the ground-truth reference, not the app) against
|
|
63
|
+
*implementation code*, structure to structure. There is no assertion-fitting risk — the
|
|
64
|
+
mockup, not the implementation, is the oracle.
|
|
65
|
+
|
|
66
|
+
## Input Contract
|
|
67
|
+
|
|
68
|
+
The orchestrator (`/e2e-review`) invokes you with this JSON payload:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"card_id": "FEAT-XXXX",
|
|
73
|
+
"route": "/settings",
|
|
74
|
+
"mockup_source": {
|
|
75
|
+
"level": "html" | "design_src",
|
|
76
|
+
"mockup_path": "/abs/path/to/mockup.html", // level == html (links.design *.html)
|
|
77
|
+
"design_src_dir": "/abs/path/to/mockups/_src/" // level == design_src (finished CODE, v4.75)
|
|
78
|
+
},
|
|
79
|
+
"implementation_files": [ // the card's UI source (from the diff / File Ownership Map)
|
|
80
|
+
"/abs/path/<app_dir>/settings/settings-form.client.tsx",
|
|
81
|
+
"/abs/path/<app_dir>/settings/settings-form.module.css"
|
|
82
|
+
],
|
|
83
|
+
"tolerance": "strict" | "balanced" | "lenient",
|
|
84
|
+
"resolved_orphans": [ // optional — Functional Traceability Gate
|
|
85
|
+
"Export CSV button", "bell icon" // mockup affordances deliberately dropped
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- `mockup_source.level == "html"` — the mockup is a single HTML file (`links.design`).
|
|
91
|
+
Read it as the structural ground truth (its DOM nesting, its grid/flex declarations,
|
|
92
|
+
its element order, its region landmarks).
|
|
93
|
+
- `mockup_source.level == "design_src"` — the mockup is finished Claude Design CODE
|
|
94
|
+
archived under `mockups/_src/` (JSX + CSS + tokens, v4.75). Read it the same way; it
|
|
95
|
+
speaks the project's own token language, so a near-1:1 structural mapping is expected.
|
|
96
|
+
- `implementation_files` — the card's UI source. Read these and reconstruct the
|
|
97
|
+
implemented structure.
|
|
98
|
+
|
|
99
|
+
If you cannot read a usable mockup (path missing/empty) **or** no implementation file
|
|
100
|
+
contains layout-bearing markup/CSS, return
|
|
101
|
+
`{ "status": "skipped", "reason": "no_structural_ground_truth", "findings": [] }`.
|
|
102
|
+
|
|
103
|
+
**`resolved_orphans` carve-out (Functional Traceability Gate).** The mockup is a fidelity
|
|
104
|
+
target, not a requirements oracle: an element matching an entry in `resolved_orphans`
|
|
105
|
+
that is absent in the implementation is **EXPECTED — never a `component-missing`
|
|
106
|
+
finding**. See `framework/agents/design-system-protocol.md` § "Functional Traceability
|
|
107
|
+
Gate".
|
|
108
|
+
|
|
109
|
+
## Severity Taxonomy (cite — do NOT redefine)
|
|
110
|
+
|
|
111
|
+
The canonical severity taxonomy is SSOT in
|
|
112
|
+
[`visual-fidelity-verifier.md`](visual-fidelity-verifier.md) § "Severity Taxonomy".
|
|
113
|
+
Use it verbatim. You emit the subset that is **derivable from code structure** (never
|
|
114
|
+
the perceptual ones):
|
|
115
|
+
|
|
116
|
+
- **Critical:** `layout-break` (mockup declares a multi-column grid / side-by-side flex
|
|
117
|
+
row; implementation declares a single-column stack — **the canonical FEAT-0061
|
|
118
|
+
failure**), `element-order` (DOM/source order differs from the mockup), `component-missing`
|
|
119
|
+
(a designed region/block has no counterpart in the implementation), `component-duplicated`.
|
|
120
|
+
- **Major:** `spacing-off-scale` (a literal where the mockup used a token/scale step,
|
|
121
|
+
detectable in code), `token-bypass` (hardcoded color/shadow/radius/spacing where the
|
|
122
|
+
mockup expressed a token — cross-checked against `tokens-reference.md` when
|
|
123
|
+
`has_design_system`), `responsiveness-break` (the mockup declares a breakpoint /
|
|
124
|
+
`@media` the implementation omits, leaving one viewport on the wrong layout).
|
|
125
|
+
- **Do NOT emit** the purely perceptual categories (`color-mismatch`, `gradient-direction`,
|
|
126
|
+
`font-rendering-variance`, `shadow-off` by blur, `micro-misalignment`) — those require
|
|
127
|
+
a render and belong to `visual-fidelity-verifier`. If you suspect one, note it in
|
|
128
|
+
`gaps[]` for the orchestrator to route to the visual pass, do not emit it as a finding.
|
|
129
|
+
|
|
130
|
+
`coverage-gap` and `data-state-mismatch` are **orchestrator/visual-verifier** concerns —
|
|
131
|
+
never emitted by you.
|
|
132
|
+
|
|
133
|
+
## Output Schema (STRICT — orchestrator parses programmatically)
|
|
134
|
+
|
|
135
|
+
Identical to `visual-fidelity-verifier`'s schema so the orchestrator aggregates both
|
|
136
|
+
uniformly:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"status": "completed" | "skipped" | "error",
|
|
141
|
+
"route": "/settings",
|
|
142
|
+
"mockup_source_level": "html" | "design_src",
|
|
143
|
+
"findings": [
|
|
144
|
+
{
|
|
145
|
+
"severity": "critical" | "major" | "minor",
|
|
146
|
+
"category": "layout-break",
|
|
147
|
+
"description": "Mockup lays the form in a 2-column grid; implementation stacks it in a single column.",
|
|
148
|
+
"expected": "grid-template-columns: 1fr 1fr (mockup .form, settings-desktop.html:118)",
|
|
149
|
+
"actual": "flex-direction: column (settings-form.module.css:11)",
|
|
150
|
+
"fix_hint": "Change `.form` from `flex-direction: column` to a 2-column grid (`grid-template-columns: 1fr 1fr` with the project's column gap token), matching the mockup's two-section layout. File: settings-form.module.css:11.",
|
|
151
|
+
"evidence": {
|
|
152
|
+
"mockup_ref": "mockups/settings-desktop.html:118",
|
|
153
|
+
"impl_ref": "<app_dir>/settings/settings-form.module.css:11"
|
|
154
|
+
},
|
|
155
|
+
"ds_drift_code": "DS_TOKENS_DRIFT" | null,
|
|
156
|
+
"confidence": "high" | "medium" | "low"
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
"ds_drift_codes": [],
|
|
160
|
+
"gaps": [
|
|
161
|
+
"color/shade divergence suspected at the header — needs the visual pass (out of structural scope)"
|
|
162
|
+
],
|
|
163
|
+
"transcript_path": "/tmp/e2e-review/FEAT-XXXX/markup-fidelity-transcript.md"
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Field rules** (mirror `visual-fidelity-verifier`):
|
|
168
|
+
- `expected` / `actual` cite the **structural declaration** on each side with `file:line`
|
|
169
|
+
(e.g. the CSS property + value, the JSX nesting, the `@media` query) — never a vague
|
|
170
|
+
description when a concrete line exists.
|
|
171
|
+
- `fix_hint` MUST be actionable and name the file + property to change. If you cannot
|
|
172
|
+
produce an actionable hint, drop the finding's severity by one tier (or remove it if
|
|
173
|
+
Minor). Route in your wording to a CSS/markup change (the orchestrator sends it to
|
|
174
|
+
`ui-expert`).
|
|
175
|
+
- `confidence`: `high` when both sides are unambiguous in code; `medium` when the
|
|
176
|
+
implementation's structure is computed/dynamic (e.g. classes assembled at runtime) and
|
|
177
|
+
you inferred it; `low` when you are guessing — prefer dropping a low-confidence finding.
|
|
178
|
+
- `ds_drift_code` set to `DS_TOKENS_DRIFT` only for `token-bypass` findings.
|
|
179
|
+
|
|
180
|
+
## Comparison Protocol
|
|
181
|
+
|
|
182
|
+
1. **Read the mockup code** (HTML or `design_src`). Reconstruct its structure: top-level
|
|
183
|
+
regions and their order; for each region, the layout primitive (grid vs flex, column
|
|
184
|
+
count, `gap`), the element order within it, and any `@media`/breakpoint behavior.
|
|
185
|
+
2. **Read the implementation files**. Reconstruct the same structure from the JSX tree +
|
|
186
|
+
the CSS/CSS-modules/Tailwind classes. Resolve Tailwind utilities (`grid-cols-2`,
|
|
187
|
+
`flex-col`, `md:grid-cols-2`) and CSS-module rules to their layout meaning.
|
|
188
|
+
3. **Compare structure first** (the cheap, high-value Critical findings): does the
|
|
189
|
+
implementation reproduce the mockup's column count / grid-vs-stack / side-by-side
|
|
190
|
+
rows? Is the region order the same? Is every designed region present?
|
|
191
|
+
4. **Then compare responsive structure**: does the implementation carry the mockup's
|
|
192
|
+
breakpoints (`@media`, `md:`/`lg:` prefixes)? A mockup desktop-2-col / mobile-1-col
|
|
193
|
+
that the implementation renders 1-col at ALL widths is a `responsiveness-break` (or
|
|
194
|
+
`layout-break` at the designed width).
|
|
195
|
+
5. **Then check token-bypass** (when `has_design_system`): hardcoded values in the
|
|
196
|
+
implementation where the mockup used a token / the registry has one — cross-check
|
|
197
|
+
`${paths.design_system}/tokens-reference.md`.
|
|
198
|
+
6. **Compose findings** into the JSON schema. Order by severity (Critical → Major),
|
|
199
|
+
then category. Cite `file:line` on both sides.
|
|
200
|
+
|
|
201
|
+
## Anti-Hallucination Discipline
|
|
202
|
+
|
|
203
|
+
- Flag only what is **evidenced in BOTH** the mockup code and the implementation code,
|
|
204
|
+
with a `file:line` on each side. If you cannot point to the mockup declaration and the
|
|
205
|
+
implementation declaration, do not emit the finding.
|
|
206
|
+
- When the implementation's structure is assembled dynamically (conditional classes,
|
|
207
|
+
composed children you cannot statically resolve), say so in `gaps[]` and lower
|
|
208
|
+
confidence — do not invent a divergence.
|
|
209
|
+
- Anything that needs a render to confirm (exact color, shadow softness, sub-pixel
|
|
210
|
+
alignment) is **out of scope** — note it in `gaps[]` for the visual pass, never emit it.
|
|
211
|
+
- Cite tokens by **exact name** as they appear in `tokens-reference.md`.
|
|
212
|
+
|
|
213
|
+
## What You Are Not
|
|
214
|
+
|
|
215
|
+
- You are not `visual-fidelity-verifier`. It compares a rendered screenshot to a mockup
|
|
216
|
+
image (pixels). You compare code structure to code structure (markup). You run when the
|
|
217
|
+
route may not even render.
|
|
218
|
+
- You are not `ui-quality-critic`. That agent judges intrinsic design quality. You only
|
|
219
|
+
compare structure to the mockup.
|
|
220
|
+
- You are not `code-reviewer`. That agent reviews source for bugs/quality across the whole
|
|
221
|
+
diff. You only check structural fidelity to the design mockup.
|
|
222
|
+
- You are not the orchestrator. `/e2e-review` aggregates your findings, runs the self-heal
|
|
223
|
+
loop (routing your findings to `ui-expert`), and produces the pass/block decision.
|
|
224
|
+
|
|
225
|
+
## Linked Protocols
|
|
226
|
+
|
|
227
|
+
- [`framework/agents/visual-fidelity-verifier.md`](visual-fidelity-verifier.md) — SSOT for
|
|
228
|
+
the severity taxonomy you cite, and your perceptual sibling.
|
|
229
|
+
- [`framework/agents/design-system-protocol.md`](../../agents/design-system-protocol.md) —
|
|
230
|
+
§ "Structural Fidelity (route-free)", § "Functional Traceability Gate", token cascade,
|
|
231
|
+
drift codes.
|
|
232
|
+
- [`framework/agents/project-context.md`](../../agents/project-context.md) — always-ask /
|
|
233
|
+
never-assume contract for missing config keys.
|
|
234
|
+
|
|
235
|
+
## Return Protocol
|
|
236
|
+
|
|
237
|
+
Emit a single JSON object matching the Output Schema above as your final message. No
|
|
238
|
+
prose preamble, no markdown narrative outside the optional `transcript_path` file. The
|
|
239
|
+
orchestrator parses your output programmatically; extra prose breaks the gate.
|
|
@@ -250,7 +250,12 @@ since v4.18.0 a per-card Codex finder + `code-reviewer` FP-gate — plus `code-r
|
|
|
250
250
|
the registry-first DS cascade, and is covered by the batch-wide Final FULL gate). Any
|
|
251
251
|
doubt — a hint of logic, state, data binding, a new/modified primitive, or `areas` beyond
|
|
252
252
|
`[ui]` — disqualifies branch (b): the card stays `balanced`. When in doubt between `balanced`
|
|
253
|
-
and `deep`, choose `deep`.
|
|
253
|
+
and `deep`, choose `deep`. **Pure-graphics fast-lane (since v4.78.0):** a branch-(b) card MUST
|
|
254
|
+
also carry `owner_agent: ui-expert` (per Rule B — `ui-expert` is the builder of pure-UI
|
|
255
|
+
surfaces). The triple `owner_agent: ui-expert` + `review_profile: light` + `areas == [ui]` is
|
|
256
|
+
the canonical **pure-graphics card** that `/new` recognizes to skip Simplify + per-card Codex
|
|
257
|
+
(the `/e2e-review` fidelity trio is its review) — so always emit `owner_agent: ui-expert`
|
|
258
|
+
explicitly on a branch-(b) card, never leave it implicit. `files_likely_touched` counts are advisory only — never downgrade a
|
|
254
259
|
**logic-bearing** card below `balanced` because the file count looks small. **Epic cards**
|
|
255
260
|
always use `review_profile: skip` (no code work).
|
|
256
261
|
|
|
@@ -108,6 +108,26 @@ inert) in the rendered output is **EXPECTED — never a `component-missing` or
|
|
|
108
108
|
raw mockup. See `framework/agents/design-system-protocol.md` § "Functional
|
|
109
109
|
Traceability Gate".
|
|
110
110
|
|
|
111
|
+
## Data-State Awareness (never compare a degenerate render)
|
|
112
|
+
|
|
113
|
+
Before diffing, judge whether the render is in a **comparable data state**. The mockup
|
|
114
|
+
depicts a *specific, usually populated* state (a table with rows, a list of products, a
|
|
115
|
+
selected store/tenant). If the render shows an **empty-state, loading placeholder, "no
|
|
116
|
+
data" message, an error page, or an obviously wrong context** (e.g. a different
|
|
117
|
+
tenant/store than the one the mockup depicts), the screenshot is **not comparable** —
|
|
118
|
+
emit a single `data-state-mismatch` (Critical) finding describing the gap and STOP
|
|
119
|
+
(return that one finding; do not also emit layout/typography findings derived from an
|
|
120
|
+
empty screen). Do **not** report "matches" just because both look sparse. The
|
|
121
|
+
orchestrator (`/e2e-review`) owns reaching the depicted state (seed data / select a
|
|
122
|
+
populated context) and will re-invoke you on the corrected render — your job is only to
|
|
123
|
+
flag that the state is wrong, never to navigate or seed.
|
|
124
|
+
|
|
125
|
+
A skip is legitimate ONLY when `mockup_source.level == "skip"` (genuinely no mockup). An
|
|
126
|
+
empty/degenerate render of a route that HAS a mockup is a `data-state-mismatch`, never a
|
|
127
|
+
silent skip or a pass. (A mockup provided as an HTML file rendered to PNG by the
|
|
128
|
+
orchestrator arrives to you as `mockup_source.level == "local"` — treat it as any other
|
|
129
|
+
local image ground truth.)
|
|
130
|
+
|
|
111
131
|
## Severity Taxonomy (CANONICAL — cite verbatim)
|
|
112
132
|
|
|
113
133
|
This taxonomy is the SSOT consumed by `/e2e-review` and `/design-review`. Do
|
|
@@ -123,6 +143,8 @@ not invent new severity levels. Do not move categories across tiers.
|
|
|
123
143
|
| `component-missing` | Designed component absent from rendered output (e.g. mockup has a CTA card, screen does not). **Exception:** an element listed in `resolved_orphans` is expected-absent — do NOT flag it. |
|
|
124
144
|
| `component-duplicated` | Same primitive rendered twice when designed once (e.g. accidental React key collision) |
|
|
125
145
|
| `unreachable-action` | Primary CTA off-screen / behind fixed overlay / unreachable by thumb on mobile |
|
|
146
|
+
| `data-state-mismatch` | The render is in the **wrong DATA STATE** to compare against the mockup: the mockup depicts a populated screen (table with rows, list of cards, a selected entity) but the render shows an **empty-state / placeholder / "no data" / wrong-context** screen. You CAN emit this (you see the emptiness). It tells the orchestrator the screenshot is not comparable and must be re-rendered in the depicted state (seed / select a populated context) — **not** that the implementation is wrong. Never silently "match" an empty render against a populated mockup. |
|
|
147
|
+
| `coverage-gap` | **Orchestrator-emitted, NOT by you.** A mockup existed for the route but the fidelity check could not be executed at all (route unrenderable in every lane, no isolated render available). Listed here because this taxonomy is the SSOT the `/e2e-review` gate consumes; the orchestrator synthesizes it so an un-runnable required check **blocks** instead of silently passing. |
|
|
126
148
|
|
|
127
149
|
### Major (BLOCKS in strict + balanced; advisory in lenient)
|
|
128
150
|
|
|
@@ -144,6 +144,13 @@ Each step is a delegation. Read the cited SSOT; do not paraphrase it.
|
|
|
144
144
|
8. **Coherence report (never silent).** Emit the protocol's "Registry coherence
|
|
145
145
|
check: N findings" block: spec updated (incl. HEAD), INDEX/policy reconciled,
|
|
146
146
|
tokens reconciled, breaking change documented + migration noted.
|
|
147
|
+
**Mirror (advisory, non-blocking):** modifying a canonical component or token
|
|
148
|
+
moves the registry ahead of its Claude Design satellite — so when a satellite is
|
|
149
|
+
bound (`.baldart/design-sync.json` has a `project_id`), also surface
|
|
150
|
+
`DS_MIRROR_STALE` (check #6, `design-system-protocol.md` — cite, do not redefine)
|
|
151
|
+
nudging `/design-sync publish`. For a **breaking** edit the satellite drift is
|
|
152
|
+
the same class as the migration — note both. Skipped when no satellite is bound;
|
|
153
|
+
never blocks the edit.
|
|
147
154
|
|
|
148
155
|
## Token edit path
|
|
149
156
|
|
|
@@ -183,3 +190,5 @@ symmetric to how a `NEW (governed)` standard routes to `/ds-new`. `/prd` owns th
|
|
|
183
190
|
- `framework/agents/component-manifest-schema.md` — the HEAD schema + the
|
|
184
191
|
regeneration contract (preserve agentic, regenerate deterministic).
|
|
185
192
|
- `framework/templates/breaking-change-checklist.md` — for breaking edits.
|
|
193
|
+
- `framework/.claude/skills/design-sync/SKILL.md` — `/design-sync publish` mirrors
|
|
194
|
+
the edit UP to the Claude Design satellite (the `DS_MIRROR_STALE` nudge).
|
|
@@ -139,6 +139,12 @@ Each step is a delegation. Read the cited SSOT; do not paraphrase it.
|
|
|
139
139
|
8. **Coherence report (never silent).** Emit the protocol's "Registry coherence
|
|
140
140
|
check: N findings" block (per § Post-Intervention Coherence Check): new spec
|
|
141
141
|
shipped, INDEX entry added, tokens reconciled, closed-set respected.
|
|
142
|
+
**Mirror (advisory, non-blocking):** creating a canonical component or token is
|
|
143
|
+
exactly the event that moves the registry ahead of its Claude Design satellite —
|
|
144
|
+
so when a satellite is bound (`.baldart/design-sync.json` has a `project_id`),
|
|
145
|
+
also surface `DS_MIRROR_STALE` (check #6, `design-system-protocol.md` — cite, do
|
|
146
|
+
not redefine) nudging `/design-sync publish`. Skipped when no satellite is bound;
|
|
147
|
+
never blocks creation.
|
|
142
148
|
|
|
143
149
|
---
|
|
144
150
|
|
|
@@ -196,4 +202,6 @@ across the two.
|
|
|
196
202
|
the serializer fills (the standardized doc shape).
|
|
197
203
|
- `framework/.claude/skills/design-system-init/SKILL.md` — the bulk twin; shares
|
|
198
204
|
the same scripts (`extract-manifest`/`extract-one`/`serialize-spec`).
|
|
205
|
+
- `framework/.claude/skills/design-sync/SKILL.md` — `/design-sync publish` mirrors
|
|
206
|
+
the new element UP to the Claude Design satellite (the `DS_MIRROR_STALE` nudge).
|
|
199
207
|
- `framework/docs/COMPONENT-MANIFEST-LAYER.md` — the layer overview.
|
|
@@ -208,16 +208,31 @@ available (probe `get_design_context` / `get_screenshot` tools at runtime):
|
|
|
208
208
|
If the MCP tools error or time out, fall through silently to level (b) — do
|
|
209
209
|
not surface the failure as a blocker.
|
|
210
210
|
|
|
211
|
-
### Level (b) — Local image
|
|
212
|
-
|
|
213
|
-
If `card.links.design[]` contains a local file path
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
-
|
|
217
|
-
|
|
218
|
-
|
|
211
|
+
### Level (b) — Local image (PNG / JPG / PDF / **HTML**)
|
|
212
|
+
|
|
213
|
+
If `card.links.design[]` contains a local file path OR the card has a `mockups/`
|
|
214
|
+
directory alongside its YAML:
|
|
215
|
+
|
|
216
|
+
- **PNG / JPG**: copy to `.baldart/e2e-review/<CARD-ID>/mockups/<route-slug>.local.png`.
|
|
217
|
+
- **PDF**: extract the first page as PNG (`pdftoppm` or equivalent — degrade gracefully
|
|
218
|
+
if unavailable).
|
|
219
|
+
- **HTML** (`links.design` ends in `.html`): the mockup is markup, not an image. Two
|
|
220
|
+
things happen — (1) render it headless to a PNG for the visual pass: open `file://<abs
|
|
221
|
+
path>` with Playwright at 1440px and `page.screenshot({fullPage:true})` →
|
|
222
|
+
`.baldart/e2e-review/<CARD-ID>/mockups/<route-slug>.local.png` (degrade gracefully if
|
|
223
|
+
the render fails — the structural pass below still runs); (2) **retain the HTML path**
|
|
224
|
+
for the route-free structural pass (Phase 2.7).
|
|
219
225
|
- Record `mockup_source.level = "local"` and the source path.
|
|
220
226
|
|
|
227
|
+
**Structural source (route-free ground truth).** Independently of the image, record a
|
|
228
|
+
`structural_source` for the route when the mockup is **code**:
|
|
229
|
+
- `links.design` is an `.html` file → `structural_source = { level: "html", mockup_path:
|
|
230
|
+
"<abs html path>" }`.
|
|
231
|
+
- `links.design_src` is set / `mockups/_src/` exists (finished Claude Design CODE, v4.75)
|
|
232
|
+
→ `structural_source = { level: "design_src", design_src_dir: "<abs dir>" }`.
|
|
233
|
+
This feeds Phase 2.7 (`markup-fidelity-verifier`) and is what makes per-card fidelity
|
|
234
|
+
verifiable **without rendering the live route**.
|
|
235
|
+
|
|
221
236
|
### Level (c) — Compliance-only (registry)
|
|
222
237
|
|
|
223
238
|
If no mockup image is available BUT `features.has_design_system: true`:
|
|
@@ -244,6 +259,59 @@ The cascade output is appended to the plan under `mockup_refs[]`.
|
|
|
244
259
|
|
|
245
260
|
---
|
|
246
261
|
|
|
262
|
+
## Phase 2.7 — Structural Fidelity (route-free, runs BEFORE the browser)
|
|
263
|
+
|
|
264
|
+
**Goal**: catch layout/structure divergence from the mockup **without rendering the live
|
|
265
|
+
route** — the route-independent first line of defense. This is what would have caught
|
|
266
|
+
FEAT-0061 (a 2-column desktop mockup built as a single column) even though the
|
|
267
|
+
auth-gated route returned 500 in the harness. SSOT: `framework/agents/design-system-protocol.md` §
|
|
268
|
+
"Route-Independent Fidelity & Coverage Obligation" → 1. Structural Fidelity.
|
|
269
|
+
|
|
270
|
+
**When it runs**: for every route whose `structural_source` was recorded in Phase 2
|
|
271
|
+
(`level == "html"` or `"design_src"`). Skip the route here only when there is no
|
|
272
|
+
code-form mockup (image-only `figma`/PNG mockups have nothing to diff structurally —
|
|
273
|
+
they go through Phase 4 visual + the coverage obligation instead).
|
|
274
|
+
|
|
275
|
+
For each such route:
|
|
276
|
+
|
|
277
|
+
1. **Resolve the implementation files** for the route from the diff / the card's File
|
|
278
|
+
Ownership Map (the `*.tsx` / `*.css` / `*.module.css` / `*.scss` / `*.svelte` / `*.vue`
|
|
279
|
+
the card touched under `${paths.app_dir}` / `${paths.components_root}`).
|
|
280
|
+
2. **Invoke `markup-fidelity-verifier`** (input contract in
|
|
281
|
+
[`markup-fidelity-verifier.md`](../../agents/markup-fidelity-verifier.md)):
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
subagent_type: "markup-fidelity-verifier"
|
|
285
|
+
mode: "bypassPermissions" // when called from /new
|
|
286
|
+
prompt: |
|
|
287
|
+
Compare the implementation's code structure against the mockup's code structure
|
|
288
|
+
and return JSON per your output schema.
|
|
289
|
+
|
|
290
|
+
Input payload:
|
|
291
|
+
{
|
|
292
|
+
"card_id": "FEAT-XXXX",
|
|
293
|
+
"route": "/settings",
|
|
294
|
+
"mockup_source": { ...the route's structural_source (html | design_src)... },
|
|
295
|
+
"implementation_files": [ ...abs paths the card touched for this route... ],
|
|
296
|
+
"tolerance": "<from config>",
|
|
297
|
+
"resolved_orphans": [ ...from the card's UI Element Inventory, as in Phase 4... ]
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
3. **Parse the JSON strictly** (same discipline as Phase 4). On malformed output log
|
|
301
|
+
`markup_verifier_protocol_violation` in `gaps[]` and treat the route's structural
|
|
302
|
+
findings as empty.
|
|
303
|
+
4. **Aggregate** structural findings into `structural_findings[]` (tag each `source:
|
|
304
|
+
"structural"`). They flow into the Phase 5 gate under the canonical taxonomy — a
|
|
305
|
+
`layout-break` here is Critical and BLOCKS. Because this runs before Phase 3/4, a clear
|
|
306
|
+
structural divergence blocks **cheaply**, before the expensive browser + multimodal
|
|
307
|
+
passes.
|
|
308
|
+
|
|
309
|
+
This phase is **route-independent**: it never starts a dev server, never authenticates,
|
|
310
|
+
never needs data. It is the workhorse of per-card fidelity; the render passes (Phase 4)
|
|
311
|
+
are the confirmation.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
247
315
|
## Phase 3 — Functional E2E (browser-based)
|
|
248
316
|
|
|
249
317
|
**Goal**: execute the Gherkin scenarios from Phase 1 in a real browser and
|
|
@@ -324,11 +392,72 @@ capture the result + screenshots per route.
|
|
|
324
392
|
- `failure_reason` (when failed, the first assertion error + stack hint)
|
|
325
393
|
- `screenshot_paths[]` (per route: the desktop `<route-slug>.png` AND the
|
|
326
394
|
mobile `<route-slug>@mobile.png`)
|
|
395
|
+
- `render_health` (per route): the HTTP status of the route navigation and
|
|
396
|
+
whether the screenshot is a **degenerate render** — a non-2xx/error page, or
|
|
397
|
+
a blank/empty-state page. Capture the response status from the Playwright
|
|
398
|
+
navigation (`response.status()`); flag `degenerate: true` when status is not
|
|
399
|
+
2xx OR the page has no meaningful content. This drives Phase 3.8.
|
|
327
400
|
5. **Functional findings**: every `failed` or `flaky` scenario becomes a
|
|
328
401
|
functional finding in the aggregate report (Phase 5). Severity:
|
|
329
402
|
- Auth / payments / data-mutation scenario failed → `critical`
|
|
330
403
|
- Display-only scenario failed → `major`
|
|
331
404
|
- Flaky (passed on retry) → `minor` with `confidence: low`
|
|
405
|
+
- **A `skipped` scenario is NOT silently dropped when its route has a mockup
|
|
406
|
+
(`mockup_source.level != "skip"`)**: a skip means the fidelity check did not
|
|
407
|
+
run, which is a coverage concern, not a pass — it is carried into Phase 3.8
|
|
408
|
+
(state remediation) and, if still un-renderable, into the coverage obligation
|
|
409
|
+
(Phase 4 step 1c). Silently skipping a mockup'd route is the exact FEAT-0061
|
|
410
|
+
failure and is prohibited.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Phase 3.8 — Comparable-render gate (route-independent lane + state remediation)
|
|
415
|
+
|
|
416
|
+
**Goal**: guarantee that the screenshot handed to Phase 4 is **comparable to the
|
|
417
|
+
mockup** — rendered route-independently where possible, and in the **data state the
|
|
418
|
+
mockup depicts**. The reviewer never accepts "I opened the page, it's empty, I skip".
|
|
419
|
+
SSOT: `design-system-protocol.md` § "Route-Independent Fidelity & Coverage Obligation"
|
|
420
|
+
→ 2. Visual Fidelity + 3. State-aware Fidelity.
|
|
421
|
+
|
|
422
|
+
For each route with a mockup (`mockup_source.level != "skip"`):
|
|
423
|
+
|
|
424
|
+
1. **Pick the render lane** (priority order):
|
|
425
|
+
- **(a) Isolated render** — when the route's primary surface is a **registry
|
|
426
|
+
primitive** (a component documented under `${paths.components_primitives}` with a
|
|
427
|
+
spec HEAD), render it in isolation via the `/ds-render` harness (`baldart render
|
|
428
|
+
build|shot`). This needs no route, no auth, no data — the route-independent visual
|
|
429
|
+
confirmation. Save to `.baldart/e2e-review/<CARD-ID>/screenshots/<route-slug>.iso.png`
|
|
430
|
+
and use it as the implementation screenshot for Phase 4. (Composed page surfaces are
|
|
431
|
+
NOT auto-rendered in isolation — that was refuted in v4.76; they use lane (b).)
|
|
432
|
+
- **(b) Live-route screenshot** from Phase 3, when the route rendered cleanly
|
|
433
|
+
(`render_health.degenerate != true`).
|
|
434
|
+
2. **State remediation (the reach-state loop)** — when the chosen render is **degenerate**
|
|
435
|
+
(`render_health.degenerate == true`: non-2xx, empty-state, wrong tenant/store) and the
|
|
436
|
+
mockup depicts a populated state, do NOT accept it. Run a **bounded** loop (cap = 2):
|
|
437
|
+
- Read the consumer's `.baldart/overlays/e2e-review.md` **reach-state recipes** and run
|
|
438
|
+
the applicable ones in order: `seed_data` → `select_populated_context` (the multi-store
|
|
439
|
+
case: select a store/tenant that has data) → `goto_populated_entity`. Re-render, re-check
|
|
440
|
+
`render_health`.
|
|
441
|
+
- **Generic fallbacks when no recipe exists**: authenticate with the persona's real
|
|
442
|
+
creds (`test_plan.test_credentials`); enable MSW/API-mock of the data response if the
|
|
443
|
+
project supports it; apply a deterministic factory/snapshot seed; or heuristically
|
|
444
|
+
auto-seek a populated context via `webapp-testing` (enumerate an on-screen
|
|
445
|
+
store/tenant selector, pick the option that yields non-empty content).
|
|
446
|
+
- Stop as soon as a non-degenerate, populated render is produced.
|
|
447
|
+
3. **Outcome**:
|
|
448
|
+
- A comparable render was produced → it is the implementation screenshot for Phase 4.
|
|
449
|
+
- Still degenerate after the loop **and** the mockup is **code-form** (a Phase 2.7
|
|
450
|
+
`structural_source` exists) → the structural pass already covered fidelity; record
|
|
451
|
+
`render_unavailable` in `gaps[]` and let Phase 4's visual step skip this route's
|
|
452
|
+
desktop diff (no false coverage-gap — structure was checked route-free).
|
|
453
|
+
- Still degenerate after the loop **and** the mockup is **image-only**
|
|
454
|
+
(`level ∈ {figma, local}` with no `structural_source`) → mark the route
|
|
455
|
+
`coverage_obligation_unmet = true` for Phase 4 step 1c (it will synthesize a
|
|
456
|
+
`coverage-gap`).
|
|
457
|
+
|
|
458
|
+
The orchestrator owns navigation/seeding here; `visual-fidelity-verifier` stays stateless
|
|
459
|
+
and only judges the frame it is handed (emitting `data-state-mismatch` if the state is
|
|
460
|
+
still wrong).
|
|
332
461
|
|
|
333
462
|
---
|
|
334
463
|
|
|
@@ -353,8 +482,19 @@ For each `route` in `plan.routes[]`:
|
|
|
353
482
|
- When `mockup_source.level == "skip"`, skip the **desktop fidelity diff**
|
|
354
483
|
(steps 2) for this route — but still run the **mobile responsive pass**
|
|
355
484
|
(step 2b) if a `<route-slug>@mobile.png` screenshot was captured, since it
|
|
356
|
-
needs no mockup.
|
|
357
|
-
|
|
485
|
+
needs no mockup.
|
|
486
|
+
- **1c. Coverage obligation (un-runnable required check BLOCKS, never passes).**
|
|
487
|
+
When the route is marked `coverage_obligation_unmet = true` from Phase 3.8 (an
|
|
488
|
+
**image-only** mockup — `level ∈ {figma, local}` with no `structural_source` — that
|
|
489
|
+
could not be rendered in any lane and whose state could not be reached), **synthesize
|
|
490
|
+
a `coverage-gap` finding (Critical)** instead of silently skipping the route. SSOT:
|
|
491
|
+
`design-system-protocol.md` § "...→ 4. Coverage Obligation". **Guards — NEVER synthesize
|
|
492
|
+
`coverage-gap`** when `mockup_source.level` is `skip` / `harness-render` /
|
|
493
|
+
`compliance-only`, nor for the mobile pass (it runs at `level: skip`), nor when a
|
|
494
|
+
Phase 2.7 `structural_source` already covered fidelity route-free. A `coverage-gap`
|
|
495
|
+
is **not fixable by an agent** — it bypasses the Phase 5b self-heal loop and maps to
|
|
496
|
+
the `blocked` verdict (the route still will not render). This is the guard that turns
|
|
497
|
+
the FEAT-0061 "skip masked as pass" into a real block.
|
|
358
498
|
- When `mockup_source.level == "harness-render"` (a render-harness PNG of an
|
|
359
499
|
ISOLATED registry primitive, from `/ds-render` — Stage C of the closed loop),
|
|
360
500
|
**NEVER run the fidelity diff (step 2)**: the image is a render of the
|
|
@@ -505,14 +645,20 @@ For each such `route`:
|
|
|
505
645
|
the canonical severity taxonomy from `visual-fidelity-verifier.md`.
|
|
506
646
|
|
|
507
647
|
1. **Compose** the `findings[]` array:
|
|
648
|
+
- **Structural findings** from Phase 2.7 (`source: "structural"`) — route-free
|
|
649
|
+
code-structure divergence (`markup-fidelity-verifier`).
|
|
508
650
|
- Functional findings from Phase 3 (`source: "functional"`).
|
|
509
|
-
- Visual findings from Phase 4 (`source: "visual"`)
|
|
651
|
+
- Visual findings from Phase 4 (`source: "visual"`) — including any
|
|
652
|
+
`data-state-mismatch` (the verifier saw an empty/wrong-state render) and any
|
|
653
|
+
orchestrator-synthesized `coverage-gap` (Phase 4 step 1c — a required check that
|
|
654
|
+
could not run at all).
|
|
510
655
|
- Design-quality findings from Phase 4b (`source: "design-quality"`).
|
|
511
656
|
- Each finding carries: `severity`, `category` (or `dimension` for
|
|
512
657
|
design-quality), `source`, `route`, `description`, `expected`, `actual`,
|
|
513
|
-
`fix_hint`, `evidence`, `ds_drift_code`, `confidence`. All
|
|
658
|
+
`fix_hint`, `evidence`, `ds_drift_code`, `confidence`. All sources
|
|
514
659
|
share the **same canonical severity taxonomy**, so the tolerance filter in
|
|
515
|
-
step 2 applies to them uniformly — no per-source special-casing.
|
|
660
|
+
step 2 applies to them uniformly — no per-source special-casing. (`coverage-gap`
|
|
661
|
+
and `data-state-mismatch` are Critical and gate in every tolerance.)
|
|
516
662
|
2. **Apply tolerance filter** based on
|
|
517
663
|
`features.e2e_review.fidelity_tolerance`:
|
|
518
664
|
- `strict` (DEFAULT): Critical + Major + Minor all gate. Additionally,
|
|
@@ -533,16 +679,25 @@ applies only when `verdict == "blocked"` AND `iteration < max`.
|
|
|
533
679
|
|
|
534
680
|
For each iteration:
|
|
535
681
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
-
|
|
682
|
+
0. **`coverage-gap` findings bypass the loop.** A `coverage-gap` is not fixable by any
|
|
683
|
+
agent (the route still will not render — it is a harness/data limitation, not a code
|
|
684
|
+
defect). Do NOT spawn a fixer for it. It keeps the verdict `blocked` and flows straight
|
|
685
|
+
to the override path below (programmatic mode returns `blocked`; `/new` escalates it to
|
|
686
|
+
a follow-up card). If `coverage-gap` is the ONLY gating finding, skip the rest of this
|
|
687
|
+
loop entirely.
|
|
688
|
+
|
|
689
|
+
1. **Route the remaining gating findings to the right fixer by `source`**, then spawn the
|
|
690
|
+
fixer(s). **Fidelity is UI-scoped**: `source == "structural"` (layout/grid/order —
|
|
691
|
+
`markup-fidelity-verifier`), `source == "design-quality"`, and UI-presentation
|
|
692
|
+
`source == "visual"` (token/spacing/typography/color, `data-state-mismatch` left to
|
|
693
|
+
state remediation) all belong to **`ui-expert`**, the UI domain owner, NOT `coder`.
|
|
694
|
+
`coder` gets only `source == "functional"` and genuine **wiring/data-binding** visual
|
|
695
|
+
findings (a missing element that is unwired, not mis-laid-out). When both buckets are
|
|
696
|
+
non-empty, run `coder` first (structure/wiring), then `ui-expert` (presentation), so the
|
|
697
|
+
critic re-evaluates the final surface. **On a pure-graphics card (`owner_agent:
|
|
698
|
+
ui-expert`), ALL fidelity fixes go to `ui-expert` — `coder` is not involved.**
|
|
699
|
+
|
|
700
|
+
- **`ui-expert`** — gating findings where `source in {structural, design-quality}` (and
|
|
546
701
|
UI-presentation `source == "visual"` findings):
|
|
547
702
|
|
|
548
703
|
```
|
|
@@ -553,13 +708,16 @@ For each iteration:
|
|
|
553
708
|
|
|
554
709
|
## Gating findings
|
|
555
710
|
[paste the JSON findings filtered to gating severity, source in
|
|
556
|
-
{design-quality, visual}]
|
|
711
|
+
{structural, design-quality, visual}]
|
|
557
712
|
|
|
558
713
|
## Rules
|
|
559
714
|
- File ownership: stay within the card's allowed file set (see
|
|
560
715
|
/tmp/batch-tracker-<FIRST-CARD-ID>.md ## File Ownership Map).
|
|
561
716
|
- One fix per finding. Reuse existing tokens / primitives before inventing
|
|
562
717
|
new ones (cite ${paths.design_system}/INDEX.md + tokens-reference.md).
|
|
718
|
+
- For a `structural` `layout-break`, match the mockup's layout exactly (e.g.
|
|
719
|
+
restore the 2-column grid the mockup declares) — cite the mockup ref in the
|
|
720
|
+
finding's `expected`.
|
|
563
721
|
- Run the Post-Intervention Coherence Check on any registry-touching fix.
|
|
564
722
|
- After the fixes, re-run lint and typecheck. Both must pass.
|
|
565
723
|
- Do NOT modify Playwright specs or this skill's state files.
|
|
@@ -594,8 +752,10 @@ For each iteration:
|
|
|
594
752
|
|
|
595
753
|
Both fixers run in `bypassPermissions` mode when called by `/new`.
|
|
596
754
|
|
|
597
|
-
2. **Re-run
|
|
598
|
-
|
|
755
|
+
2. **Re-run the affected verifiers**: Phase 2.7 (structural, route-free — re-run when a
|
|
756
|
+
`structural` fix was applied), Phase 3 (functional), Phase 3.8 (re-render / state),
|
|
757
|
+
Phase 4 (visual), and Phase 4b (quality) with fresh screenshots. Increment `iteration`.
|
|
758
|
+
(A `coverage-gap`-only block does not enter this loop — see step 0.)
|
|
599
759
|
3. **Re-aggregate and re-decide** (back to Phase 5 step 1).
|
|
600
760
|
4. **STOP** when `verdict == "passed"` OR `iteration == max`.
|
|
601
761
|
|
|
@@ -698,8 +858,14 @@ and starts from Phase 3 (skipping plan extraction and mockup cascade).
|
|
|
698
858
|
- **`/design-review` command** — when invoked from this skill with
|
|
699
859
|
`mode: "programmatic"`, returns JSON instead of Markdown for gating.
|
|
700
860
|
See [`framework/.claude/commands/design-review.md`](../../commands/design-review.md).
|
|
861
|
+
- **`markup-fidelity-verifier`** (Phase 2.7) — route-free structural twin of
|
|
862
|
+
`visual-fidelity-verifier`: compares the mockup's code structure (HTML / `design_src`)
|
|
863
|
+
against the implementation source, no render. See
|
|
864
|
+
[`markup-fidelity-verifier.md`](../../agents/markup-fidelity-verifier.md). Its fixes
|
|
865
|
+
route to `ui-expert`.
|
|
701
866
|
- **`visual-fidelity-verifier`** (Phase 4) — judges fidelity to the mockup /
|
|
702
|
-
spec
|
|
867
|
+
spec (pixels), and emits `data-state-mismatch` when the render is in the wrong data
|
|
868
|
+
state. See [`visual-fidelity-verifier.md`](../../agents/visual-fidelity-verifier.md).
|
|
703
869
|
- **`ui-quality-critic`** (Phase 4b) — judges intrinsic design quality against
|
|
704
870
|
the rubric, independent of any mockup. See
|
|
705
871
|
[`ui-quality-critic.md`](../../agents/ui-quality-critic.md). It is the design
|
|
@@ -740,6 +906,9 @@ and starts from Phase 3 (skipping plan extraction and mockup cascade).
|
|
|
740
906
|
| Quality loop never converges (design-quality findings persist) | Taste-leaning Minor findings, or `ui-expert` fixing one dimension while regressing another | Confirm the findings are gating (not low-confidence Minor auto-demoted in strict). If genuine and unresolved after max iterations, override with reason and open a `ui-expert` follow-up card — do NOT block indefinitely on subjective polish |
|
|
741
907
|
| `quality_critic_protocol_violation` in gaps | `ui-quality-critic` returned prose mixed with JSON | Re-spawn the critic once; if persistent, surface to user (likely a model regression). Treat that route's quality findings as empty meanwhile |
|
|
742
908
|
| `verifier_protocol_violation` in gaps | `visual-fidelity-verifier` returned prose mixed with JSON | Re-spawn the verifier once; if persistent, surface to user (likely a model regression) |
|
|
909
|
+
| `coverage-gap` (Critical) on a route | An image-only mockup route could not be rendered in any lane and its state could not be reached | Correct by design — the gate BLOCKS instead of silently passing. Add a reach-state recipe to `.baldart/overlays/e2e-review.md` (seed / select populated context), or provide an HTML/`design_src` mockup so the route-free structural pass covers it. Never override without fixing the lane |
|
|
910
|
+
| `data-state-mismatch` (Critical) on a route | Render opened an empty / wrong-tenant / error state; mockup depicts a populated state | The reach-state loop (Phase 3.8) should seed/select a populated context. If it has no recipe and cannot auto-seek, add `select_populated_context` / `seed_data` to the e2e-review overlay |
|
|
911
|
+
| `markup_verifier_protocol_violation` in gaps | `markup-fidelity-verifier` returned prose mixed with JSON | Re-spawn once; if persistent, surface to user. Treat that route's structural findings as empty meanwhile |
|
|
743
912
|
|
|
744
913
|
---
|
|
745
914
|
|
|
@@ -44,7 +44,21 @@ Log the detector output in the tracker for traceability. **This step never short
|
|
|
44
44
|
> `baldart teardown-codex-broker`), with the `baldart doctor` reaper as the safety net. Per-card hygiene
|
|
45
45
|
> is none.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
**Pure-graphics-card skip (narrow exception — since v4.78.0).** Skip the per-card
|
|
48
|
+
`/codexreview` gate entirely when the card is **pure-graphics**: `owner_agent: ui-expert`
|
|
49
|
+
**AND** `review_profile: light` **AND** `areas == [ui]` exactly (no `api`/`data`/`logic`/`auth`
|
|
50
|
+
area) **AND** Step A matched **zero** high-risk triggers on the actual diff. Rationale: a
|
|
51
|
+
zero-logic UI card's meaningful review is the **`/e2e-review` fidelity trio** —
|
|
52
|
+
`markup-fidelity-verifier` (structure) + `visual-fidelity-verifier` (pixels + a11y) +
|
|
53
|
+
`ui-quality-critic` (quality) — plus the mechanical build/lint/tsc gates; a general Codex
|
|
54
|
+
bug-sweep over presentational CSS/JSX is low-value noise (the user's "qa codex review non
|
|
55
|
+
serve" for graphics). **Safety net preserved:** the **Final-review FULL `/codexreview`**
|
|
56
|
+
(net #2 below) ALWAYS re-sweeps the ENTIRE batch diff before merge — so the graphics card's
|
|
57
|
+
code is still Codex-reviewed batch-wide, just not per-card. The Step-A zero-trigger condition
|
|
58
|
+
means any high-risk path on the diff cancels the skip (escalation-only invariant). Log
|
|
59
|
+
`codex: SKIPPED (pure-graphics — fidelity trio is the review; Final FULL gate re-sweeps)`.
|
|
60
|
+
|
|
61
|
+
For EVERY other card (no conditional skip — the gate ALWAYS runs; only its DEPTH varies):
|
|
48
62
|
|
|
49
63
|
0. **Select the Codex review profile (deterministic — Review Profile Selector)** by mapping the
|
|
50
64
|
card's review profile (read from the card's `review_profile` field per the QA Profile Selector
|
|
@@ -263,6 +263,8 @@ This gate enforces `framework/agents/workflows.md § Scope Closure Discipline` a
|
|
|
263
263
|
|
|
264
264
|
Do NOT batch the question across multiple ACs — one `AskUserQuestion` per AC, so the user sees each AC's text in isolation. Issue the questions sequentially.
|
|
265
265
|
|
|
266
|
+
**Fidelity-AC carve-out (BLOCKING — the FEAT-0061 fix).** When the deferred AC is a **visual-fidelity AC** — its text matches `/visual|fidelit|mockup|layout|responsive|1:1|design (match|reference)/i` OR it asserts the screen matches a design reference (`links.design` / `links.design_src`) — option 2 **"Approva il deferral" is NOT offered**. A fidelity AC cannot be silently deferred or "covered by a downstream card": that is exactly the `FEAT-0061-08 → 04/10` cross-card deferral that shipped a 1-column page against a 2-column mockup. Offer only **1 (Implementa adesso — route the fix to `ui-expert`)**, **3 (Sposta su follow-up card — explicit, tracked, and the new card carries the fidelity AC + `links.design`, so it re-faces the `/e2e-review` gate)**, **4 (Ferma il batch)**. **When AUTONOMOUS:** take option 3 (follow-up card) — never approve the deferral. Note: with the route-free structural pass (`/e2e-review` Phase 2.7) a UI card now verifies its OWN surface without a live route, so a genuine *need* to defer fidelity should be rare; treat a fidelity deferral as a signal that the per-card gate was skipped, not as a routine outcome.
|
|
267
|
+
|
|
266
268
|
5. **`implementation_notes` deferral audit (cheap text grep — also BLOCKING)** — before exiting the phase, scan the card YAML's `implementation_notes` field (post-edits, including any text added during this phase) for any of these phrases:
|
|
267
269
|
|
|
268
270
|
- `deferred` / `deferral` / `defer to`
|
|
@@ -116,6 +116,8 @@ so it surfaces in telemetry.
|
|
|
116
116
|
|
|
117
117
|
> **Trivial fast-lane gate**: re-confirm `IS_TRIVIAL` on the ACTUAL committed diff (§ "Trivial-card fast-lane" — all 3 conditions, now including the real non-source diff check). If trivial → **SKIP this phase** AND Phase 3.5 QA + Phase 3.7 Codex; instead run the **inline mechanical gates** (`markdownlint` on changed `.md`, `lint` on lintable changed files, `build` as a sanity check — no qa-sentinel, no test suite), then proceed to Phase 3 (doc review, which DOES run) and Phase 4 (commit). Log `simplify/qa/codex: SKIPPED (trivial — non-source diff)`. If the actual diff turned out to contain a source file → NOT trivial → run this phase and the normal review path. AC-Closure (Phase 2.5b) already ran and is never skipped.
|
|
118
118
|
|
|
119
|
+
> **Pure-graphics fast-lane gate (since v4.78.0)**: when the card is **pure-graphics** (`owner_agent: ui-expert` AND `review_profile: light` AND `areas == [ui]` exactly — no api/data/logic/auth — AND zero Step-A high-risk triggers on the diff), **SKIP this Simplify phase** (quality-only; `ui-expert` already builds reuse-first) and Phase 3.7 Codex (per `codex-gate.md` § "Pure-graphics-card skip"). QA (Phase 3.5) is already skipped at `light` — the mechanical lint/tsc/build from Phase 2 step 8 is the "qa = build" floor. **Phase 2.6 `/e2e-review` is NOT skipped** — the fidelity trio (`markup-fidelity-verifier` + `visual-fidelity-verifier` + `ui-quality-critic`) is the real review for a graphics card. Doc-review (Phase 3) still runs (registry/spec reconciliation). Log `simplify/codex: SKIPPED (pure-graphics — fidelity trio is the review)`.
|
|
120
|
+
|
|
119
121
|
After completeness is verified, clean up the implementation before it reaches reviewers and E2E tests. This phase launches three parallel agents on the card's diff, then applies fixes directly.
|
|
120
122
|
|
|
121
123
|
**Step-by-step**:
|
|
@@ -156,6 +158,17 @@ The skill replaces the previous advisory pair (legacy Phase 2.6 E2E testing
|
|
|
156
158
|
and Phase 2.7 visual design review). It runs by default on every UI card,
|
|
157
159
|
auto-skips on backend-only cards, and BLOCKS the commit on gating findings.
|
|
158
160
|
|
|
161
|
+
> **Route-independent, self-contained verification (since v4.78.0).** This card verifies
|
|
162
|
+
> its **OWN** UI surface — it does NOT defer fidelity to a downstream card. `/e2e-review`
|
|
163
|
+
> now runs a **route-free structural pass** (Phase 2.7, `markup-fidelity-verifier`: the
|
|
164
|
+
> mockup's HTML/`design_src` code vs the implementation source) before any browser, so a
|
|
165
|
+
> component card with no route of its own is still fully verifiable. Consequences for the
|
|
166
|
+
> gating table below: a fidelity AC closes **only** on a real `passed` (a comparison was
|
|
167
|
+
> performed) — a `skipped` does NOT close it, and a route that opened empty/degenerate
|
|
168
|
+
> surfaces as `blocked` via `data-state-mismatch` / `coverage-gap`, never a silent pass.
|
|
169
|
+
> A genuine cross-card fidelity deferral must go through the Phase 2.5b fidelity-AC
|
|
170
|
+
> carve-out (explicit follow-up card), never a free-text note. This is the FEAT-0061 fix.
|
|
171
|
+
|
|
159
172
|
#### Gate (skip the whole phase when any of the below is true)
|
|
160
173
|
|
|
161
174
|
| Condition | Action |
|
|
@@ -206,7 +219,7 @@ When the gate above passes, the orchestrator invokes `/e2e-review` in
|
|
|
206
219
|
| `status` from `/e2e-review` | Orchestrator action |
|
|
207
220
|
|----|----|
|
|
208
221
|
| `"passed"` | Log result in tracker. Proceed to Phase 3 (doc review + code review). |
|
|
209
|
-
| `"skipped"` | Log skip reason. Proceed to Phase 3. |
|
|
222
|
+
| `"skipped"` | Log skip reason. Proceed to Phase 3. **If the card has `links.design` / `links.design_src` yet the skill returned `skipped`, that is suspicious post-v4.78.0** (the route-free structural pass should have run): record `[E2E-FIDELITY-SKIP] <reason>` in `## Issues & Flags`, and do NOT mark any fidelity AC `[x]` on a skip — a fidelity AC closes only on a real `passed`. |
|
|
210
223
|
| `"overridden"` | Log override + reason in `## Issues & Flags` as `[E2E-OVERRIDE] <reason>`. Proceed to Phase 3. |
|
|
211
224
|
| `"blocked"` | **STOP the card**. Log findings in tracker + `## Issues & Flags` as `[E2E-BLOCKED] <count> gating findings (<categories>)`. Ask the user whether to (a) override with reason, (b) escalate (open follow-up card), or (c) abandon this card and continue the batch. Do NOT proceed to Phase 3 silently. **When AUTONOMOUS, apply § AUTONOMOUS RESOLUTION RULE (SKILL.md): category=blocker; recommended=none safe (a blocked E2E is a real gating failure) → take (b) escalate to a follow-up card; NEVER take (a) override autonomously.** |
|
|
212
225
|
| `"error"` | Log error in `## Issues & Flags`. Ask the user whether to retry, skip, or abandon. Do NOT proceed silently. **Retry re-entry (defined path, capped):** on "retry", re-enter at step 1 of this Invocation contract — reset the `.baldart/e2e-review/<CARD-ID>/` state dir, re-spawn `/e2e-review` with the SAME payload, and re-parse. **Cap: 2 error-retries per card** (central repair cap, consistent with the other loops). On the 2nd `error`, do NOT re-offer "retry" — re-invoke `AskUserQuestion` with only skip/abandon, so the loop cannot recur unbounded. **When AUTONOMOUS, apply § AUTONOMOUS RESOLUTION RULE (SKILL.md): category=blocker; recommended=retry once (the capped re-entry above); if still `error` → skip the E2E for this card AND materialize a follow-up card to re-run it (NEVER abandon the card silently).** |
|
|
@@ -576,6 +576,84 @@ the most damaging case (a CSS-hidden heavy subtree) is invisible to a JS AST rul
|
|
|
576
576
|
Rule 2 violations are HIGH; a viewport-scoped edit that mutates the other branch
|
|
577
577
|
(rule 1) is MEDIUM.
|
|
578
578
|
|
|
579
|
+
## Route-Independent Fidelity & Coverage Obligation (BLOCKING — SSOT)
|
|
580
|
+
|
|
581
|
+
This is the single definition of how UI fidelity is verified per-card. `/e2e-review`,
|
|
582
|
+
`/new` (implement + code-reviewer), `/ui-design`, and `/design-review` **cite** this
|
|
583
|
+
section; they do not redefine it. The driving lesson (FEAT-0061): a fidelity check that
|
|
584
|
+
depends on rendering a *live, data-bearing route* silently degrades to a pass when that
|
|
585
|
+
route cannot render (auth-gated, empty database, wrong tenant) — a **skip masked as a
|
|
586
|
+
pass**. The fix is to make verification **route-independent first** and to make an
|
|
587
|
+
**un-runnable required check block, never pass**.
|
|
588
|
+
|
|
589
|
+
### 1. Structural Fidelity (route-free) — runs FIRST
|
|
590
|
+
|
|
591
|
+
When a card has a mockup expressed as code — `links.design` pointing to an **HTML**
|
|
592
|
+
file, or `links.design_src` / `mockups/_src/` (finished Claude Design CODE, v4.75) — the
|
|
593
|
+
**code-structural** comparison runs before any browser render, via the
|
|
594
|
+
`markup-fidelity-verifier` agent. It compares the mockup's markup/CSS structure (grid vs
|
|
595
|
+
flex, column count, element order, region presence, `@media` breakpoints) against the
|
|
596
|
+
implementation source. This is the analogue of **tree-edit-distance over the DOM** — the
|
|
597
|
+
*structural* dimension, complementary to the *perceptual* (pixel) dimension of
|
|
598
|
+
`visual-fidelity-verifier`. It needs no browser, no auth, no data, and it deterministically
|
|
599
|
+
catches the **2-column-mockup → 1-column-build** class of divergence. Its findings use the
|
|
600
|
+
canonical severity taxonomy (SSOT in `visual-fidelity-verifier.md`); a structural
|
|
601
|
+
`layout-break` is Critical. **Fixes route to `ui-expert`** (layout is the UI domain).
|
|
602
|
+
|
|
603
|
+
### 2. Visual Fidelity — render as CONFIRMATION, route-independent where possible
|
|
604
|
+
|
|
605
|
+
The pixel diff (`visual-fidelity-verifier`) confirms the structural result on a rendered
|
|
606
|
+
image. The render source, in priority order: (a) **isolated render** of the surface via
|
|
607
|
+
the `/ds-render` harness when it is a registry primitive (no route/auth/data needed);
|
|
608
|
+
(b) the live-route screenshot when the route renders; (c) neither → a coverage obligation
|
|
609
|
+
(below). The live-route screenshot is **not** the only fidelity source.
|
|
610
|
+
|
|
611
|
+
### 3. State-aware Fidelity — `data-state-mismatch` (never compare a degenerate render)
|
|
612
|
+
|
|
613
|
+
The render must reach the **data state the mockup depicts** (a populated table, a selected
|
|
614
|
+
store/tenant). An empty-state / placeholder / error / wrong-context render of a route that
|
|
615
|
+
HAS a mockup is a **`data-state-mismatch`** (Critical) — emitted by `visual-fidelity-verifier`,
|
|
616
|
+
which sees the emptiness — **not** a silent skip or pass. The orchestrator owns *reaching*
|
|
617
|
+
the depicted state via a bounded **reach-state loop**: project-specific recipes from the
|
|
618
|
+
consumer's `.baldart/overlays/e2e-review.md` (`seed_data`, `select_populated_context`,
|
|
619
|
+
`goto_populated_entity`), with generic fallbacks (real auth from the persona creds,
|
|
620
|
+
MSW/API-mock, deterministic factory/snapshot, heuristic context auto-seek). The framework
|
|
621
|
+
owns the contract + the loop; the overlay owns the project-specific *how*.
|
|
622
|
+
|
|
623
|
+
### 4. Coverage Obligation — `coverage-gap` (un-runnable required check BLOCKS)
|
|
624
|
+
|
|
625
|
+
A required fidelity check that **could not execute at all** must block, never pass. The
|
|
626
|
+
orchestrator synthesizes a **`coverage-gap`** (Critical) finding when an **image-only**
|
|
627
|
+
mockup exists (`mockup_source.level ∈ {figma, local}`, i.e. no HTML/code to diff
|
|
628
|
+
structurally) AND neither an isolated render nor a route render produced a comparable
|
|
629
|
+
screenshot, AND the state could not be reached. **Guards (never fire `coverage-gap`):**
|
|
630
|
+
`mockup_source.level == skip` (no mockup → no obligation), `harness-render` (assertion-fitting
|
|
631
|
+
guard — these go to quality only), `compliance-only` (registry-based, no image target), and
|
|
632
|
+
the mobile responsive pass (runs at `level: skip` by construction). A `coverage-gap` is
|
|
633
|
+
**not fixable by an agent** (the route still will not render) — it **bypasses the self-heal
|
|
634
|
+
loop** and maps to the existing `blocked` verdict (the orchestrator's autonomous handling
|
|
635
|
+
escalates it to a follow-up card). No new verdict status is introduced.
|
|
636
|
+
|
|
637
|
+
### 5. Graphics-only card → `ui-expert` + the fidelity trio IS the review
|
|
638
|
+
|
|
639
|
+
For a **pure-graphics card** (`owner_agent: ui-expert`, `review_profile: light`,
|
|
640
|
+
`areas == [ui]` exactly — no api/data/logic/auth), the implementer is `ui-expert` (not
|
|
641
|
+
`coder`), and the **fidelity trio is the review**: `markup-fidelity-verifier` (structure)
|
|
642
|
+
+ `visual-fidelity-verifier` (pixels + a11y) + `ui-quality-critic` (intrinsic quality,
|
|
643
|
+
advisory), plus the mechanical build/lint/tsc gates. The deep `/codexreview` and
|
|
644
|
+
`simplify` passes are skipped — their UI-relevant coverage (a11y, token-bypass, DS-drift,
|
|
645
|
+
layout) is absorbed by the trio. All fidelity fixes (structural, presentational, quality)
|
|
646
|
+
route to `ui-expert`.
|
|
647
|
+
|
|
648
|
+
### Gating philosophy (calibration)
|
|
649
|
+
|
|
650
|
+
Vision-model reliability research (*MLLM as a UI Judge*, 2025) shows multimodal judges are
|
|
651
|
+
reliable at **comparison with clear differences** (~93%) but weak at **absolute scoring**
|
|
652
|
+
(~35% exact, hedging toward low variance). Therefore the **hard gate is FIDELITY**
|
|
653
|
+
(comparison against a ground truth: structural + visual), and **intrinsic-quality absolute
|
|
654
|
+
scoring (`ui-quality-critic`) stays advisory / confidence-gated**, never a hard block. The
|
|
655
|
+
2-col → 1-col case is a "clear difference" → maximum judge reliability.
|
|
656
|
+
|
|
579
657
|
## Post-Intervention Coherence Check (BLOCKING completion gate)
|
|
580
658
|
|
|
581
659
|
The BLOCKING pre-work above enforces *reads* before any UI change. This
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
base_skill: e2e-review
|
|
3
|
+
base_skill_version: 4.78.0
|
|
4
|
+
mode: extend
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# e2e-review — fidelity-app overlay (example)
|
|
8
|
+
|
|
9
|
+
> Project-specific **reach-state recipes** for `/e2e-review` Phase 3.8. The framework
|
|
10
|
+
> owns the contract and the bounded loop; this overlay tells the orchestrator HOW to put
|
|
11
|
+
> the app into the data state a mockup depicts, so the visual reviewer never compares a
|
|
12
|
+
> degenerate (empty / wrong-tenant / error) render. Drop into
|
|
13
|
+
> `.baldart/overlays/e2e-review.md` and adapt to your stack.
|
|
14
|
+
>
|
|
15
|
+
> Without these recipes `/e2e-review` falls back to generic remediation (real auth from
|
|
16
|
+
> the persona creds, MSW/API-mock, deterministic factory/snapshot, heuristic context
|
|
17
|
+
> auto-seek) and, failing that, **blocks** with `coverage-gap` — it never silently passes
|
|
18
|
+
> an empty render.
|
|
19
|
+
|
|
20
|
+
## [APPEND] Reach-state recipes
|
|
21
|
+
|
|
22
|
+
The orchestrator runs the applicable recipes in order until `render_health.degenerate`
|
|
23
|
+
is false. Each recipe is a named, deterministic sequence of steps the orchestrator can
|
|
24
|
+
execute via Playwright / `webapp-testing` / a project script. Cap: 2 attempts.
|
|
25
|
+
|
|
26
|
+
### `seed_data` — populate the database for the route
|
|
27
|
+
|
|
28
|
+
Run before navigating, when the route shows an empty-state because the demo/CI database
|
|
29
|
+
is empty:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Example: seed a deterministic dataset the mockup depicts (idempotent).
|
|
33
|
+
npm run db:seed:e2e # creates store "demo" + ≥3 products + 1 supplier
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
State guarantee: after this, `/products` renders a populated table matching the mockup's
|
|
37
|
+
DATI PRODOTTO / FORNITORI sections. The seed MUST be deterministic (fixed ids, no
|
|
38
|
+
faker-without-seed) so screenshots are reproducible.
|
|
39
|
+
|
|
40
|
+
### `select_populated_context` — the multi-store / multi-tenant case
|
|
41
|
+
|
|
42
|
+
When the default-selected store/tenant is empty but another has data (the exact failure
|
|
43
|
+
the user flagged): switch context to a populated one before screenshotting.
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
1. Authenticate as the owner persona (test_plan.test_credentials).
|
|
47
|
+
2. Open the store switcher: getByRole("button", { name: /store|negozio/i }).
|
|
48
|
+
3. Pick the first store whose product count > 0 (the seeded "demo" store), NOT the
|
|
49
|
+
default empty one.
|
|
50
|
+
4. Wait for networkidle, then proceed to the route.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Heuristic fallback (no explicit list): enumerate the switcher options, navigate the route
|
|
54
|
+
under each, and pick the first that yields non-empty content (the verifier confirms
|
|
55
|
+
non-emptiness). This is the generic `webapp-testing` auto-seek.
|
|
56
|
+
|
|
57
|
+
### `goto_populated_entity` — detail routes that need a specific id
|
|
58
|
+
|
|
59
|
+
When the mockup depicts a specific entity (e.g. a product detail), navigate to a seeded
|
|
60
|
+
entity id rather than a random/empty one:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Navigate to `/products?selected=<seeded-product-id>&edit=1` (the id created by
|
|
64
|
+
`seed_data`), not the bare `/products`.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## [APPEND] Notes
|
|
68
|
+
|
|
69
|
+
- Recipes are tried in the order above (`seed_data` → `select_populated_context` →
|
|
70
|
+
`goto_populated_entity`); a recipe that does not apply to a route is a no-op.
|
|
71
|
+
- Keep recipes **deterministic and idempotent** — they run inside the bounded reach-state
|
|
72
|
+
loop and may be re-invoked across self-heal iterations.
|
|
73
|
+
- A recipe MUST NOT mutate production data: scope to the e2e/demo database the dev server
|
|
74
|
+
uses. The framework's contract assumes an isolated test database.
|