mandrel 2.50.0 → 2.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/audit-checklists/accessibility.md +1 -0
- package/.agents/audit-checklists/mobile.md +35 -0
- package/.agents/audit-checklists/ux-ui.md +0 -1
- package/.agents/docs/workflows.md +2 -1
- package/.agents/schemas/audit-rules.json +30 -0
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +1 -0
- package/.agents/workflows/audit-accessibility.md +13 -7
- package/.agents/workflows/audit-mobile.md +242 -0
- package/.agents/workflows/audit-ux-ui.md +11 -6
- package/docs/CHANGELOG.md +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!-- GENERATED FILE — do not edit by hand.
|
|
2
|
+
Source of truth: .agents/workflows/audit-mobile.md
|
|
3
|
+
Regenerate: node .agents/scripts/generate-lens-checklists.js
|
|
4
|
+
Drift is gated by: npm run docs:check
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
# Mobile & Tablet UX Audit — authoring checklist
|
|
8
|
+
|
|
9
|
+
> Audit mobile and tablet UX — layout and viewport correctness, touch ergonomics, responsive assets, and whether anything actually verifies them at a small viewport (static-first, with an optional runtime viewport pass)
|
|
10
|
+
|
|
11
|
+
Self-check your change against this lens's concerns before you ship:
|
|
12
|
+
|
|
13
|
+
- [ ] Breakpoint scale
|
|
14
|
+
- [ ] Viewport contract
|
|
15
|
+
- [ ] Declared device matrix
|
|
16
|
+
- [ ] Runtime target (optional)
|
|
17
|
+
- [ ] Viewport meta
|
|
18
|
+
- [ ] Fixed dimensions
|
|
19
|
+
- [ ] Viewport-height units
|
|
20
|
+
- [ ] Horizontal overflow
|
|
21
|
+
- [ ] Safe-area insets
|
|
22
|
+
- [ ] Hover-only interaction
|
|
23
|
+
- [ ] Control size and spacing
|
|
24
|
+
- [ ] Input ergonomics
|
|
25
|
+
- [ ] Gesture conflicts
|
|
26
|
+
- [ ] Images
|
|
27
|
+
- [ ] Media and embeds
|
|
28
|
+
- [ ] Typography and spacing
|
|
29
|
+
- [ ] Coverage — is anything exercised at a non-desktop viewport?
|
|
30
|
+
- [ ] Effectiveness — does that exercise assert anything mobile-specific?
|
|
31
|
+
- [ ] Resolve the target from config — never a hardcoded URL.
|
|
32
|
+
- [ ] Sample routes from the navigability SSOT.
|
|
33
|
+
- [ ] Drive two form factors per route.
|
|
34
|
+
- [ ] Median-of-3 or provisional.
|
|
35
|
+
- [ ] Leave the viewport as you found it.
|
|
@@ -32,7 +32,7 @@ by `node .agents/scripts/generate-workflows-doc.js`; `npm run docs:check`
|
|
|
32
32
|
fails when it drifts from the on-disk workflow set. To change a command’s
|
|
33
33
|
description, edit the workflow file’s front-matter and regenerate.
|
|
34
34
|
|
|
35
|
-
## Commands (
|
|
35
|
+
## Commands (29)
|
|
36
36
|
|
|
37
37
|
| Command | Description |
|
|
38
38
|
| --- | --- |
|
|
@@ -45,6 +45,7 @@ description, edit the workflow file’s front-matter and regenerate.
|
|
|
45
45
|
| `/audit-dependencies` | Audit `package.json` for unused, outdated, and major-version-stale dependencies; surface Node-engine drift and propose upgrade batches. |
|
|
46
46
|
| `/audit-devops` | Audit CI/CD workflows, container images, infrastructure-as-code, and deployment pipelines; surface failure modes and hardening gaps. |
|
|
47
47
|
| `/audit-documentation` | Audit the repository's main documentation for staleness, semantic drift, and completeness; emit a structured High/Medium/Low findings report. |
|
|
48
|
+
| `/audit-mobile` | Audit mobile and tablet UX — layout and viewport correctness, touch ergonomics, responsive assets, and whether anything actually verifies them at a small viewport (static-first, with an optional runtime viewport pass) |
|
|
48
49
|
| `/audit-navigability` | Audit the whole route tree against the consumer's nav-registry SSOT — every route has a persona nav door and no nav href is dead. A deliberately-global lens exempt from the cross-epic-leak guard and routed onto route-adding change sets. |
|
|
49
50
|
| `/audit-performance` | Audit performance by measuring first — profile hot paths, I/O, memory, and payload against the repo's own numbers — and audit interleaving/partial-failure correctness (TOCTOU, unawaited promises, non-atomic writes) as a first-class dimension. |
|
|
50
51
|
| `/audit-privacy` | Audit logs, telemetry, and persistence paths for PII leakage and retention violations; surface secrets exposure and consent gaps. |
|
|
@@ -299,6 +299,36 @@
|
|
|
299
299
|
"scope": "local",
|
|
300
300
|
"substitutionKeys": []
|
|
301
301
|
},
|
|
302
|
+
"audit-mobile": {
|
|
303
|
+
"triggers": {
|
|
304
|
+
"gates": ["gate2", "gate3"],
|
|
305
|
+
"keywords": [
|
|
306
|
+
"mobile",
|
|
307
|
+
"tablet",
|
|
308
|
+
"responsive",
|
|
309
|
+
"breakpoint",
|
|
310
|
+
"viewport",
|
|
311
|
+
"touch"
|
|
312
|
+
],
|
|
313
|
+
"filePatterns": [
|
|
314
|
+
"**/*.html",
|
|
315
|
+
"**/*.astro",
|
|
316
|
+
"**/*.css",
|
|
317
|
+
"**/*.{scss,sass,less}",
|
|
318
|
+
"**/styles/**",
|
|
319
|
+
"**/components/**/*.{js,jsx,ts,tsx,vue,svelte}",
|
|
320
|
+
"**/app/**/{page,layout,route,head,default,template,loading,error,not-found}.{js,jsx,ts,tsx}",
|
|
321
|
+
"**/pages/**/*.{js,jsx,ts,tsx,vue}",
|
|
322
|
+
"**/routes/**/*.{jsx,tsx,vue,svelte}",
|
|
323
|
+
"**/tailwind.config.{js,ts,cjs,mjs}",
|
|
324
|
+
"**/playwright.config.{js,ts,cjs,mjs}",
|
|
325
|
+
"**/cypress.config.{js,ts,cjs,mjs}"
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
"target": "web",
|
|
329
|
+
"scope": "local",
|
|
330
|
+
"substitutionKeys": []
|
|
331
|
+
},
|
|
302
332
|
"audit-navigability": {
|
|
303
333
|
"triggers": {
|
|
304
334
|
"gates": ["gate2", "gate3"],
|
|
@@ -31,9 +31,9 @@ on a project with no rendered frontend, since there are no components, templates
|
|
|
31
31
|
or routes to hold to WCAG. See the `target` key's schema description for how
|
|
32
32
|
applicability is probed from the consumer's checkout.
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Boundaries with the neighbouring web lenses
|
|
35
35
|
|
|
36
|
-
These
|
|
36
|
+
These lenses share a border with this one and must not double-report:
|
|
37
37
|
|
|
38
38
|
- **`audit-accessibility` (this lens)** owns **WCAG conformance** — the
|
|
39
39
|
standards question: does an assistive-technology user perceive, operate, and
|
|
@@ -41,11 +41,17 @@ These two web lenses share a border and must not double-report:
|
|
|
41
41
|
controls, text alternatives, and contrast against the WCAG ratio thresholds.
|
|
42
42
|
- **`audit-ux-ui`** owns **design-system adherence** — the consistency
|
|
43
43
|
question: do components and tokens match the project's own design system?
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
- **`audit-mobile`** owns **small-screen and touch behaviour** — layout at a
|
|
45
|
+
phone or tablet viewport, touch ergonomics, responsive assets, and mobile
|
|
46
|
+
test coverage. It may measure a control's rendered size as ergonomic
|
|
47
|
+
evidence, but the `2.5.8 Target Size (Minimum)` verdict on an undersized
|
|
48
|
+
target is reported here.
|
|
49
|
+
|
|
50
|
+
Contrast is the one axis accessibility and ux-ui both touch: **accessibility
|
|
51
|
+
owns the WCAG ratio verdict** (4.5:1 body / 3:1 large text / 3:1 non-text),
|
|
52
|
+
while ux-ui owns whether the colour came from a sanctioned token. When a
|
|
53
|
+
contrast defect is in scope for both, report the WCAG failure here and leave
|
|
54
|
+
the token-adherence note to ux-ui.
|
|
49
55
|
|
|
50
56
|
## Scope
|
|
51
57
|
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Audit mobile and tablet UX — layout and viewport correctness, touch ergonomics, responsive assets, and whether anything actually verifies them at a small viewport (static-first, with an optional runtime viewport pass)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Mobile & Tablet UX Audit
|
|
6
|
+
|
|
7
|
+
You are a Senior Mobile Web Engineer holding the frontend to its **small-screen
|
|
8
|
+
and touch contract**: does every surface lay out, scroll, and answer a finger on
|
|
9
|
+
a phone and a tablet — and does anything in the suite actually verify that it
|
|
10
|
+
does? Default to **static** detection over source; escalate to a **runtime**
|
|
11
|
+
viewport pass only when a live target is configured. The shared lens machinery —
|
|
12
|
+
read-only constraint, scope interpretation, report envelope + finding-block
|
|
13
|
+
skeleton, severity scale, self-cross-check, and execution strategy — lives in
|
|
14
|
+
[`helpers/audit-lens-core.md`](helpers/audit-lens-core.md). Write the report to
|
|
15
|
+
`{{auditOutputDir}}/audit-mobile-results.md`. Dimension values:
|
|
16
|
+
`Layout & Viewport | Touch Ergonomics | Responsive Assets | Mobile Verification`.
|
|
17
|
+
Extra finding field: **Evidence:** (`measured | static` + the observable;
|
|
18
|
+
single-run runtime numbers are tagged `provisional`).
|
|
19
|
+
The report adds a **Runtime Viewport Pass** section.
|
|
20
|
+
|
|
21
|
+
> **An emulated viewport is not a device.** Viewport emulation resizes and
|
|
22
|
+
> re-flows the page; it does not reproduce a real device's browser engine,
|
|
23
|
+
> input latency, font rendering, or OS chrome. Report what the emulator
|
|
24
|
+
> observed, never "verified on iPhone".
|
|
25
|
+
|
|
26
|
+
## Applicability
|
|
27
|
+
|
|
28
|
+
**Web targets only.** Registered with `target: "web"` in
|
|
29
|
+
[`audit-rules.json`](../schemas/audit-rules.json): the selector skips this lens
|
|
30
|
+
on a project with no rendered frontend, since there is no layout to re-flow and
|
|
31
|
+
no control to touch. See the `target` key's schema description for how
|
|
32
|
+
applicability is probed from the consumer's checkout.
|
|
33
|
+
|
|
34
|
+
## Boundaries with the neighbouring lenses
|
|
35
|
+
|
|
36
|
+
Four lenses border this one. Report a finding **here** only when it is a
|
|
37
|
+
small-screen or touch defect; defer the rest so the suite never double-reports:
|
|
38
|
+
|
|
39
|
+
- [`/audit-accessibility`](audit-accessibility.md) owns every **WCAG
|
|
40
|
+
success-criterion verdict**, including `2.5.8 Target Size (Minimum)`. This
|
|
41
|
+
lens may **measure** a control's rendered size as ergonomic evidence, but the
|
|
42
|
+
conformance verdict on an undersized target belongs there.
|
|
43
|
+
- [`/audit-ux-ui`](audit-ux-ui.md) owns **design-system adherence** — whether a
|
|
44
|
+
value came from a sanctioned token and whether a raw element should have
|
|
45
|
+
deferred to a design-system component. This lens asks only whether the result
|
|
46
|
+
works at a small viewport, whatever its provenance.
|
|
47
|
+
- [`/audit-performance`](audit-performance.md) owns **Core Web Vitals, bundle
|
|
48
|
+
weight, and network cost**, mobile ones included. An oversized hero image is
|
|
49
|
+
reported here only as a missing `srcset`/`sizes` **contract**, never as a
|
|
50
|
+
payload-weight verdict.
|
|
51
|
+
- [`/audit-quality`](audit-quality.md) owns the **generic** test verdicts —
|
|
52
|
+
pyramid balance, flake, and coverage gaps. This lens owns exactly one test
|
|
53
|
+
question: is any of it exercised at a non-desktop viewport, and does that
|
|
54
|
+
exercise assert something mobile-specific (Step 2).
|
|
55
|
+
|
|
56
|
+
## Scope
|
|
57
|
+
|
|
58
|
+
Interpret this lens's change-set fence per the core's Scope interpretation:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
{{changedFiles}}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Execution strategy
|
|
65
|
+
|
|
66
|
+
Run this lens as a single `subagent_type: auditor` dispatch returning the report
|
|
67
|
+
path + Executive Summary; sequential inline execution is the fallback (see the
|
|
68
|
+
core's Execution strategy).
|
|
69
|
+
|
|
70
|
+
## Step 0: Discover the responsive baseline (run first)
|
|
71
|
+
|
|
72
|
+
**You cannot audit responsiveness against a generic ideal — a 640px fixed width
|
|
73
|
+
is a defect only relative to the breakpoints the project actually claims to
|
|
74
|
+
support.** Before any detection, locate this lens's own sources of truth (they
|
|
75
|
+
are *not* ux-ui's design system, though they often live beside it) and record
|
|
76
|
+
what they declare:
|
|
77
|
+
|
|
78
|
+
- **Breakpoint scale:** the `screens` map in `tailwind.config.{js,ts}`, CSS
|
|
79
|
+
custom media / container queries, a `breakpoints` token file, or a
|
|
80
|
+
CSS-in-JS theme's media helpers. Census the `@media` / `container` queries
|
|
81
|
+
actually used in the stylesheets and note the narrowest one — that is the
|
|
82
|
+
smallest width the project has any evidence of supporting.
|
|
83
|
+
- **Viewport contract:** the `<meta name="viewport">` tag (or the framework
|
|
84
|
+
`viewport` export) and whether it sets `width=device-width` and leaves user
|
|
85
|
+
scaling enabled.
|
|
86
|
+
- **Declared device matrix:** any non-desktop viewport already configured in the
|
|
87
|
+
consumer's test tooling — Playwright `projects[]` using `devices[...]` or an
|
|
88
|
+
explicit `viewport`, a Cypress `viewportWidth`/`viewportHeight`, a
|
|
89
|
+
visual-regression viewport list. This is the project's own statement of which
|
|
90
|
+
form factors it holds itself to.
|
|
91
|
+
- **Runtime target (optional):** the `qa.environments` map (see
|
|
92
|
+
[*Runtime viewport pass*](#step-3-runtime-viewport-pass-optional-corroboration))
|
|
93
|
+
and the navigability route SSOT.
|
|
94
|
+
|
|
95
|
+
Record the breakpoints, the viewport contract, and the device matrix. Every
|
|
96
|
+
finding downstream is measured against *this discovered baseline*. If the
|
|
97
|
+
project declares **no** breakpoint scale and no device matrix, say so and
|
|
98
|
+
downgrade findings to "no responsive baseline declared — recommend establishing
|
|
99
|
+
a breakpoint scale and a phone/tablet test viewport first" rather than scoring
|
|
100
|
+
the tree against an invented one.
|
|
101
|
+
|
|
102
|
+
## Step 1: Static detection, then triage
|
|
103
|
+
|
|
104
|
+
Run the **mechanical detectors first** (cheap, deterministic greps over the
|
|
105
|
+
in-scope styles and components), then apply **LLM triage** to each candidate
|
|
106
|
+
against the Step 0 baseline — a mechanical hit is a *candidate*, not
|
|
107
|
+
automatically a finding.
|
|
108
|
+
|
|
109
|
+
### Layout & Viewport
|
|
110
|
+
|
|
111
|
+
- **Viewport meta:** absent `<meta name="viewport">`, a missing
|
|
112
|
+
`width=device-width`, or `user-scalable=no` / `maximum-scale=1` pinning the
|
|
113
|
+
page against pinch-zoom.
|
|
114
|
+
- **Fixed dimensions:** `width`/`min-width`/`height` px literals wider than the
|
|
115
|
+
narrowest declared breakpoint, outside token and container-query files — the
|
|
116
|
+
classic source of a page that cannot shrink.
|
|
117
|
+
- **Viewport-height units:** `100vh` (or `vh` arithmetic) with no `dvh`/`svh`
|
|
118
|
+
fallback, which cuts content off under a mobile browser's collapsing toolbar.
|
|
119
|
+
- **Horizontal overflow:** unconstrained wide content — tables, `<pre>` blocks,
|
|
120
|
+
code fences, flex rows with no `min-width: 0`, absolutely-positioned elements
|
|
121
|
+
extending past the viewport — and any `overflow-x: visible` on a container
|
|
122
|
+
holding them. A page whose body scrolls sideways on a phone is a defect
|
|
123
|
+
regardless of its cause.
|
|
124
|
+
- **Safe-area insets:** `position: fixed`/`sticky` elements pinned to a screen
|
|
125
|
+
edge (bottom bars, floating actions, drawers, modals) with no
|
|
126
|
+
`env(safe-area-inset-*)` allowance, so a notch or home indicator overlaps
|
|
127
|
+
them.
|
|
128
|
+
|
|
129
|
+
### Touch Ergonomics
|
|
130
|
+
|
|
131
|
+
- **Hover-only interaction:** a `:hover`/`hover:` state that reveals content or
|
|
132
|
+
is the only affordance for an action, with no touch-reachable equivalent
|
|
133
|
+
(a click/tap handler, a focus state, or an always-visible control). On a
|
|
134
|
+
touch device that interaction does not exist.
|
|
135
|
+
- **Control size and spacing:** interactive controls whose rendered box is
|
|
136
|
+
visibly under ~44×44 CSS px, or adjacent tap targets with no separating
|
|
137
|
+
spacing. Report the **measurement** as ergonomic evidence and leave the
|
|
138
|
+
WCAG `2.5.8` verdict to the accessibility lens.
|
|
139
|
+
- **Input ergonomics:** form inputs with a font-size under 16px (iOS Safari
|
|
140
|
+
zooms the whole page on focus), a missing or wrong `inputmode`/`type` for the
|
|
141
|
+
expected keyboard (numeric, email, tel), and `autocomplete` omitted on
|
|
142
|
+
identity or address fields where a small-screen user most needs it.
|
|
143
|
+
- **Gesture conflicts:** custom swipe/drag handlers that call
|
|
144
|
+
`preventDefault()` on `touchstart`/`touchmove` across a scrollable region, or
|
|
145
|
+
scroll containers nested inside a horizontal pager, which strand the user's
|
|
146
|
+
scroll.
|
|
147
|
+
|
|
148
|
+
### Responsive Assets
|
|
149
|
+
|
|
150
|
+
- **Images:** `<img>` with no `srcset`/`sizes` (or a framework image component
|
|
151
|
+
bypassed for a raw tag) where the same file serves every width; a missing
|
|
152
|
+
intrinsic `width`/`height` or `aspect-ratio`, which shifts the layout as
|
|
153
|
+
images land.
|
|
154
|
+
- **Media and embeds:** `<video>`, `<iframe>`, and map/chart embeds with fixed
|
|
155
|
+
pixel dimensions or no responsive container.
|
|
156
|
+
- **Typography and spacing:** a type or spacing scale with no small-viewport
|
|
157
|
+
step, so a desktop-tuned heading dominates a phone screen.
|
|
158
|
+
|
|
159
|
+
> **Detector output is candidates.** Triage each against the Step 0 baseline
|
|
160
|
+
> before promoting it to a finding — a fixed width inside a design-system
|
|
161
|
+
> primitive that its container query already re-flows, a `100vh` on a
|
|
162
|
+
> deliberately desktop-only admin surface, or a raw `<img>` for a fixed-size
|
|
163
|
+
> icon, is expected, not a defect.
|
|
164
|
+
|
|
165
|
+
## Step 2: Mobile verification coverage & effectiveness
|
|
166
|
+
|
|
167
|
+
A responsive surface with nothing holding it responsive regresses on the next
|
|
168
|
+
change. This lens owns that one test question, in two parts — report them as
|
|
169
|
+
separate findings, because the fixes differ:
|
|
170
|
+
|
|
171
|
+
1. **Coverage — is anything exercised at a non-desktop viewport?** Reconcile the
|
|
172
|
+
Step 0 device matrix against the suites that exist: an e2e config with only a
|
|
173
|
+
desktop project, a visual-regression suite with a single wide snapshot width,
|
|
174
|
+
or Gherkin features with no phone/tablet variant all mean the responsive
|
|
175
|
+
behaviour is unverified. Name the specific surfaces in scope that no
|
|
176
|
+
non-desktop run touches.
|
|
177
|
+
2. **Effectiveness — does that exercise assert anything mobile-specific?** A
|
|
178
|
+
suite that merely replays its desktop assertions at 390px wide proves the
|
|
179
|
+
page renders, not that it works. Look for assertions that could only pass on
|
|
180
|
+
a small viewport: the drawer or hamburger nav opening in place of the desktop
|
|
181
|
+
bar, the absence of horizontal document scroll, a bottom bar clearing the
|
|
182
|
+
safe area, an orientation change, a swipe or long-press gesture, a
|
|
183
|
+
viewport-conditional element being hidden or shown. A mobile project whose
|
|
184
|
+
assertions are viewport-agnostic is a **false-confidence** finding: it is
|
|
185
|
+
reported even though the suite is green, and it is usually more valuable than
|
|
186
|
+
a missing-coverage finding, because the project believes it is covered.
|
|
187
|
+
|
|
188
|
+
Keep the generic test verdicts out of this step — pyramid balance, flake, and
|
|
189
|
+
overall coverage gaps belong to [`/audit-quality`](audit-quality.md). Where a
|
|
190
|
+
fix is a new test, name the viewport and the assertion it should make, not just
|
|
191
|
+
"add mobile tests".
|
|
192
|
+
|
|
193
|
+
## Step 3: Runtime viewport pass (optional corroboration)
|
|
194
|
+
|
|
195
|
+
Static detection is the default and always runs. The runtime pass is
|
|
196
|
+
**conditional** — it runs only when a live target is configured; its absence
|
|
197
|
+
never blocks the static report.
|
|
198
|
+
|
|
199
|
+
1. **Resolve the target from config — never a hardcoded URL.** Resolve the
|
|
200
|
+
target through the consumer's `qa.environments.<env>.baseUrl` (via
|
|
201
|
+
[`resolveQaEnvironment`](../scripts/lib/qa/resolve-qa-contract.js), the same
|
|
202
|
+
resolver `/qa-run` uses): an `<env>` argument resolves by exact name or
|
|
203
|
+
origin match; with no argument, enumerate `name → baseUrl` and let the
|
|
204
|
+
operator pick. If **no** `qa.environments` target is configured, **skip this
|
|
205
|
+
step** and note in the report that runtime corroboration was unavailable —
|
|
206
|
+
do not invent a URL and do not start an arbitrary dev server.
|
|
207
|
+
2. **Sample routes from the navigability SSOT.** Draw the routes to exercise
|
|
208
|
+
from the consumer's route/nav registry (`planning.navigation.navRegistry` /
|
|
209
|
+
`routeGlobs` — the same SSOT [`/audit-navigability`](audit-navigability.md)
|
|
210
|
+
reads), sampling a representative set (key personas' landing routes plus any
|
|
211
|
+
route in the change-set scope) rather than a single hardcoded page.
|
|
212
|
+
3. **Drive two form factors per route.** Emulate a **phone** and a **tablet**
|
|
213
|
+
viewport — `mcp__chrome-devtools__emulate` for a device profile, or
|
|
214
|
+
`resize_page` for an explicit width/height — then, per route and viewport:
|
|
215
|
+
take a screenshot, and evaluate the two observables static analysis cannot
|
|
216
|
+
resolve — whether `document.scrollingElement.scrollWidth` exceeds the
|
|
217
|
+
viewport width (horizontal overflow), and the rendered box of the
|
|
218
|
+
interactive controls Step 1 flagged as candidates. Reload after switching
|
|
219
|
+
form factor so load-time device gates re-run.
|
|
220
|
+
4. **Median-of-3 or provisional.** Any runtime measurement is subject to
|
|
221
|
+
run-to-run variance: capture a **median-of-3** (three runs per route, report
|
|
222
|
+
the median) before treating a number as authoritative. A single-run value is
|
|
223
|
+
reported **provisional** and never drives a Critical/High verdict on its own.
|
|
224
|
+
5. **Leave the viewport as you found it.** Reset the emulation before finishing
|
|
225
|
+
so a following lens or QA run does not inherit a phone viewport.
|
|
226
|
+
|
|
227
|
+
Corroborate static findings against the runtime observations (a statically
|
|
228
|
+
flagged fixed width confirmed by a real horizontal overflow graduates from
|
|
229
|
+
provisional to confirmed), and surface runtime-only defects the static pass
|
|
230
|
+
could not see — an element clipped only once the toolbar collapses, a drawer
|
|
231
|
+
that opens off-screen.
|
|
232
|
+
|
|
233
|
+
## Report additions
|
|
234
|
+
|
|
235
|
+
Beyond the shared skeleton, the Executive Summary states the runtime mode's
|
|
236
|
+
status (ran against `<env>` / skipped — no target configured) and names the
|
|
237
|
+
narrowest breakpoint the project declares, so a reader can tell what "mobile"
|
|
238
|
+
meant for this run. The report ends with a **Runtime Viewport Pass** section:
|
|
239
|
+
per-route, per-form-factor observations when the runtime mode ran, or
|
|
240
|
+
"*Runtime corroboration unavailable — no `qa.environments` target configured.*"
|
|
241
|
+
Drop every claimed finding that names no concrete element, style rule, or test
|
|
242
|
+
file.
|
|
@@ -89,12 +89,17 @@ baseline — a mechanical hit is a *candidate*, not automatically a finding.
|
|
|
89
89
|
2. **Error States:** Are form errors clear and helpful, or generic and
|
|
90
90
|
frustrating?
|
|
91
91
|
3. **Loading States:** Are there skeletons or spinners for async operations?
|
|
92
|
-
4. **
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
contrast-ratio verdict are owned by [`/audit-accessibility`](audit-accessibility.md).
|
|
92
|
+
4. **Accessibility (UX-focused):** Focus on tab order and whether interaction
|
|
93
|
+
colours come from a sanctioned token. **WCAG conformance is out of scope
|
|
94
|
+
here** — semantic structure, ARIA correctness, keyboard/focus operability,
|
|
95
|
+
form labelling, media alternatives, and the WCAG contrast-ratio verdict are
|
|
96
|
+
owned by [`/audit-accessibility`](audit-accessibility.md).
|
|
98
97
|
This lens keeps token/component design-system adherence; defer every WCAG
|
|
99
98
|
success-criterion judgement to the accessibility lens so the two never
|
|
100
99
|
double-report.
|
|
100
|
+
|
|
101
|
+
> **Small-screen behaviour is out of scope here too.** Layout at a phone or
|
|
102
|
+
> tablet viewport, touch-target ergonomics, responsive assets, and whether any
|
|
103
|
+
> suite exercises a non-desktop viewport belong to [`/audit-mobile`](audit-mobile.md).
|
|
104
|
+
> This lens keeps the token/component question at whatever viewport the surface
|
|
105
|
+
> renders.
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,13 @@ All notable changes to this project will be documented in this file.
|
|
|
15
15
|
-->
|
|
16
16
|
<!-- markdownlint-disable-file MD004 MD012 MD037 -->
|
|
17
17
|
|
|
18
|
+
## [2.51.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.50.0...mandrel-v2.51.0) (2026-09-08)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
* **audit:** add the /audit-mobile lens for mobile and tablet UX (refs [#5233](https://github.com/dsj1984/mandrel/issues/5233)) ([#5234](https://github.com/dsj1984/mandrel/issues/5234)) ([eccd505](https://github.com/dsj1984/mandrel/commit/eccd50527f04a25e02d50f57e1c6d760345bc9e8))
|
|
24
|
+
|
|
18
25
|
## [2.50.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.49.0...mandrel-v2.50.0) (2026-09-08)
|
|
19
26
|
|
|
20
27
|
|
package/package.json
CHANGED