codebyplan 1.13.49 → 1.13.50
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/dist/cli.js +2 -1
- package/package.json +1 -1
- package/templates/agents/cbp-round-executor.md +1 -6
- package/templates/agents/cbp-task-planner.md +2 -2
- package/templates/hooks/cbp-skill-context-guard.sh +52 -0
- package/templates/hooks/cbp-test-hooks.sh +144 -0
- package/templates/hooks/hooks.json +9 -0
- package/templates/rules/model-invocation-convention.md +40 -0
- package/templates/rules/parallel-waves.md +1 -1
- package/templates/rules/task-routing-recommendation.md +1 -1
- package/templates/settings.project.base.json +2 -1
- package/templates/skills/cbp-build-cc-settings/reference/cbp-permission-policy.md +42 -0
- package/templates/skills/cbp-clear-continue/SKILL.md +86 -0
- package/templates/skills/cbp-clear-prep/SKILL.md +121 -0
- package/templates/skills/cbp-round-start/SKILL.md +1 -1
- package/templates/skills/cbp-task-check/SKILL.md +12 -5
- package/templates/skills/cbp-task-complete/SKILL.md +9 -11
- package/templates/skills/cbp-task-complete/reference/checkpoint-done-branching.md +14 -21
- package/templates/skills/cbp-task-complete/reference/next-step-heuristic.md +4 -6
- package/templates/skills/cbp-task-testing/SKILL.md +9 -14
- package/templates/skills/cbp-frontend-a11y/SKILL.md +0 -108
- package/templates/skills/cbp-frontend-a11y/reference/aria-roles-states.md +0 -130
- package/templates/skills/cbp-frontend-a11y/reference/contrast-visual.md +0 -122
- package/templates/skills/cbp-frontend-a11y/reference/keyboard-patterns.md +0 -154
- package/templates/skills/cbp-frontend-a11y/reference/semantic-html.md +0 -111
|
@@ -120,7 +120,12 @@ Save agent output to task context: `codebyplan task update --id <taskId> --check
|
|
|
120
120
|
|
|
121
121
|
**READY + satisfied:**
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
Starting task testing...
|
|
124
|
+
|
|
125
|
+
Invoke `cbp-task-testing` via the Skill tool with the same `{chk-task}` argument. `cbp-task-testing`
|
|
126
|
+
is `allow`-tier — it auto-fires silently. If the `cbp-skill-context-guard.sh` hook detects the
|
|
127
|
+
context window is above the 200K threshold it will block the skill and direct you to run
|
|
128
|
+
`/cbp-clear-prep` first; otherwise testing starts immediately.
|
|
124
129
|
|
|
125
130
|
**NOT READY — fixable issues:**
|
|
126
131
|
|
|
@@ -130,7 +135,9 @@ Issues found that need addressing:
|
|
|
130
135
|
- [issue 2]
|
|
131
136
|
```
|
|
132
137
|
|
|
133
|
-
|
|
138
|
+
Invoking `cbp-round-input` to address the issues found during review...
|
|
139
|
+
|
|
140
|
+
Invoke `cbp-round-input` via the Skill tool. `cbp-round-input` is `allow`-tier — it auto-fires silently.
|
|
134
141
|
|
|
135
142
|
**NOT READY — needs new task:**
|
|
136
143
|
|
|
@@ -139,7 +146,7 @@ Scope issues identified that require a new task:
|
|
|
139
146
|
- [scope issue]
|
|
140
147
|
```
|
|
141
148
|
|
|
142
|
-
Suggest: `/cbp-task-create`. **STOP HERE** — wait for user.
|
|
149
|
+
Suggest: `/cbp-task-create`. **STOP HERE** — wait for user (creating a new task is a user scope decision — not auto-triggered).
|
|
143
150
|
|
|
144
151
|
**NOT READY — approvals missing:**
|
|
145
152
|
|
|
@@ -147,7 +154,7 @@ Suggest: `/cbp-task-create`. **STOP HERE** — wait for user.
|
|
|
147
154
|
Code review passed but [N] files need user approval.
|
|
148
155
|
```
|
|
149
156
|
|
|
150
|
-
Suggest: Approve files, then re-run `/cbp-task-check`. **STOP HERE** — wait for user.
|
|
157
|
+
Suggest: Approve files, then re-run `/cbp-task-check`. **STOP HERE** — wait for user (approval is a user action — not auto-triggered).
|
|
151
158
|
|
|
152
159
|
## Key Rules
|
|
153
160
|
|
|
@@ -161,5 +168,5 @@ Suggest: Approve files, then re-run `/cbp-task-check`. **STOP HERE** — wait fo
|
|
|
161
168
|
|
|
162
169
|
- **Reads**: `.codebyplan/state/checkpoints/*.json`, `checkpoints/<id>/tasks/*.json`, `checkpoints/<id>/tasks/<id>/rounds/*.json`, `todos.json` (local-first; `npx codebyplan sync` on miss; MCP `get_current_task`/`get_rounds` break-glass), plus all changed files (via agent)
|
|
163
170
|
- **Writes**: `codebyplan task update` (CLI write-through; MCP `update_task` break-glass)
|
|
164
|
-
- **Triggers**:
|
|
171
|
+
- **Triggers**: auto-triggers `cbp-task-testing` via Skill tool on READY + satisfied (`allow`-tier, fires silently; the 200K context guard handles oversized contexts via the cbp-clear-prep flow); auto-triggers `cbp-round-input` via Skill tool on NOT READY — fixable issues (`allow`-tier, fires silently)
|
|
165
172
|
- **Triggered by**: `/cbp-round-complete` (auto, when all files approved)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: cbp-task-complete
|
|
3
3
|
description: Complete current task
|
|
4
4
|
argument-hint: [chk-task]
|
|
5
|
+
triggers: [cbp-task-start, cbp-checkpoint-check]
|
|
5
6
|
effort: xhigh
|
|
6
7
|
---
|
|
7
8
|
|
|
@@ -155,7 +156,7 @@ Show the completion summary:
|
|
|
155
156
|
**Warnings**: [any QA / file-approval warnings from Step 3, or "none"]
|
|
156
157
|
```
|
|
157
158
|
|
|
158
|
-
Then route. Same-context transitions (next task in this checkpoint) auto-trigger via the Skill tool.
|
|
159
|
+
Then route. Same-context transitions (next task in this checkpoint) auto-trigger `cbp-task-start` via the Skill tool. Checkpoint-done (last task) also auto-triggers `cbp-checkpoint-check` via the Skill tool (`ask`-tier — the permission prompt is the human gate; the 200K context guard handles oversized contexts via the cbp-clear-prep flow). Only the no-task-anywhere session-end fallback surfaces as a single directive (`Next: Run /clear, then /cbp-session-end`) for the user to invoke.
|
|
159
160
|
|
|
160
161
|
#### 9a — Determine routing context
|
|
161
162
|
|
|
@@ -179,16 +180,13 @@ Use the Skill tool with `skill: cbp-task-start` and `args: "{NEXT_CHK}-{NEXT_TAS
|
|
|
179
180
|
|
|
180
181
|
If no next task is found (no pending work anywhere in the repo), emit directive and stop: `Next: Run /clear, then /cbp-session-end.`
|
|
181
182
|
|
|
182
|
-
#### 9c — Checkpoint-done
|
|
183
|
+
#### 9c — Checkpoint-done auto-trigger (last task in checkpoint)
|
|
183
184
|
|
|
184
|
-
The checkpoint has no remaining tasks.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
Do NOT use AskUserQuestion here — this is a directive, not a menu. The user runs whichever command fits their intent.
|
|
185
|
+
The checkpoint has no remaining tasks. Invoke `cbp-checkpoint-check` via the Skill tool.
|
|
186
|
+
`cbp-checkpoint-check` is `ask`-tier — the harness permission prompt IS the human gate; the
|
|
187
|
+
user confirms (or declines) before checkpoint verification and ship begins. If the context
|
|
188
|
+
window is above the 200K threshold the `cbp-skill-context-guard.sh` hook will block it and
|
|
189
|
+
direct you to run `/cbp-clear-prep` first; otherwise checkpoint-check starts on confirmation.
|
|
192
190
|
|
|
193
191
|
## Integration
|
|
194
192
|
|
|
@@ -197,5 +195,5 @@ Do NOT use AskUserQuestion here — this is a directive, not a menu. The user ru
|
|
|
197
195
|
- **Reads**: `.codebyplan/state/checkpoints/*.json`, `checkpoints/<id>/tasks/*.json`, `checkpoints/<id>/tasks/<id>/rounds/*.json`, `todos.json` (local-first; `npx codebyplan sync` on miss; MCP `get_current_task`/`get_rounds`/`get_tasks` break-glass)
|
|
198
196
|
- **Writes**: `codebyplan task update` for `files_changed` (CLI write-through; MCP `update_task` break-glass); MCP `complete_task` for task completion (kept MCP — CLI cannot forward `caller_worktree_id`)
|
|
199
197
|
- **Uses skills (inline, no sub-agent)**: `cleanup` (if deletions), `migration` (if exports renamed)
|
|
200
|
-
- **Triggers**: Same-context transitions auto-trigger via the Skill tool (next task in checkpoint →
|
|
198
|
+
- **Triggers**: Same-context transitions auto-trigger via the Skill tool (next task in checkpoint → `cbp-task-start {N}`, `allow`-tier, fires silently). Checkpoint-done → auto-triggers `cbp-checkpoint-check` via Skill tool (`ask`-tier, permission prompt IS the human gate). No-task-anywhere fallback → directive `Next: Run /clear, then /cbp-session-end.`
|
|
201
199
|
- **Checkpoint-bound only** — for standalone tasks use `/cbp-standalone-task-complete`
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Checkpoint-Done
|
|
1
|
+
# Checkpoint-Done Auto-Trigger in `/cbp-task-complete` Step 9
|
|
2
2
|
|
|
3
|
-
When the just-completed task was the LAST pending task in its checkpoint (every sibling task has `status === 'completed'`), Step 9c
|
|
3
|
+
When the just-completed task was the LAST pending task in its checkpoint (every sibling task has `status === 'completed'`), Step 9c auto-triggers `cbp-checkpoint-check` via the Skill tool — no routing menu, no manual `/clear` directive.
|
|
4
4
|
|
|
5
|
-
This file describes the detection logic, the
|
|
5
|
+
This file describes the detection logic, the auto-trigger form, and the standalone fall-through.
|
|
6
6
|
|
|
7
7
|
## Detection
|
|
8
8
|
|
|
@@ -10,39 +10,32 @@ The skill detects "checkpoint done" at Step 9 by:
|
|
|
10
10
|
|
|
11
11
|
1. Reading `current_task.checkpoint_id`. If `null` → standalone — see "Standalone Fall-Through" below.
|
|
12
12
|
2. Calling `get_tasks(checkpoint_id)` and checking that EVERY task other than the just-completed one has `status === 'completed'`.
|
|
13
|
-
3. If yes, the checkpoint has no pending or in-progress siblings —
|
|
13
|
+
3. If yes, the checkpoint has no pending or in-progress siblings — fire the Step 9c auto-trigger.
|
|
14
14
|
|
|
15
|
-
## Step 9c
|
|
15
|
+
## Step 9c Auto-Trigger Form
|
|
16
16
|
|
|
17
|
-
When all siblings are done, the skill
|
|
17
|
+
When all siblings are done, the skill invokes `cbp-checkpoint-check` via the Skill tool:
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Alternatives: /cbp-checkpoint-update {NNN} to expand the checkpoint with more tasks, or /cbp-session-end to wrap up here.
|
|
22
|
-
```
|
|
19
|
+
- `cbp-checkpoint-check` is `ask`-tier — the harness permission prompt IS the human gate. The user confirms (or declines) before checkpoint verification and the shipment chain begin.
|
|
20
|
+
- No `/clear` is emitted unconditionally. If the `cbp-skill-context-guard.sh` hook detects the context window is above the 200K threshold it blocks the skill and directs you to run `/cbp-clear-prep` first (which writes a handoff; the user then runs `/clear`, then `/cbp-clear-continue` resumes); otherwise checkpoint-check starts immediately on confirmation.
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- `/clear` then `/cbp-checkpoint-check` — verify deliverables and begin the shipment chain
|
|
27
|
-
- `/cbp-checkpoint-update {NNN}` — expand the checkpoint with more tasks (routes through `checkpoint-update` FIRST, not directly to `task-create`)
|
|
28
|
-
- `/cbp-session-end` — wrap up here
|
|
29
|
-
|
|
30
|
-
The skill does NOT auto-invoke any of these. Emit the directive, then stop.
|
|
22
|
+
There is no AskUserQuestion menu. Expanding the checkpoint with more tasks (`/cbp-checkpoint-update`) or wrapping up the session (`/cbp-session-end`) are no longer surfaced as inline alternatives — the deterministic next step on checkpoint-done is `cbp-checkpoint-check`. (The user can still invoke those other skills manually at any time; they are simply not part of the auto-flow.)
|
|
31
23
|
|
|
32
24
|
## Standalone Fall-Through
|
|
33
25
|
|
|
34
26
|
When the just-completed task is standalone (`checkpoint_id === null`):
|
|
35
27
|
|
|
36
|
-
- The Step 9c
|
|
28
|
+
- The Step 9c auto-trigger does NOT apply. There is no checkpoint to verify or ship.
|
|
37
29
|
- Step 9 falls through to next-task routing per `next-step-heuristic.md` "Standalone Variant":
|
|
38
30
|
- If a next pending task is found (standalone or in-progress checkpoint): auto-trigger via Skill tool — no AskUserQuestion, no /clear.
|
|
39
31
|
- If no pending tasks remain anywhere: emit single directive `**Next**: Run /clear, then /cbp-session-end.` — all known work complete.
|
|
40
32
|
|
|
41
33
|
## What the Skill Does NOT Do
|
|
42
34
|
|
|
43
|
-
Never
|
|
35
|
+
- Never combine the Step 9c auto-trigger (checkpoint done → `cbp-checkpoint-check`) with the Step 9b auto-trigger (next task in checkpoint → `cbp-task-start`) in the same response — fire one or the other based on detection, not both.
|
|
36
|
+
- Never present a multi-option AskUserQuestion menu for routing between known-next skills (per the close-out-routing rule — auto-trigger or a single directive, never an A/B/C menu).
|
|
44
37
|
|
|
45
38
|
## Pairs With
|
|
46
39
|
|
|
47
|
-
- `next-step-heuristic.md` — sibling reference for non-last-task-in-checkpoint case (Step 9b auto-trigger)
|
|
48
|
-
- `.claude/skills/cbp-checkpoint-
|
|
40
|
+
- `next-step-heuristic.md` — sibling reference for the non-last-task-in-checkpoint case (Step 9b auto-trigger)
|
|
41
|
+
- `.claude/skills/cbp-checkpoint-check/SKILL.md` — the auto-triggered destination on checkpoint-done
|
|
@@ -17,19 +17,17 @@ No AskUserQuestion, no `/clear`. The skill fires immediately.
|
|
|
17
17
|
|
|
18
18
|
## Case 2 — Cross-Context (checkpoint done, session end)
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Two sub-cases:
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
**Next**: Run /clear, then /cbp-checkpoint-check.
|
|
24
|
-
```
|
|
22
|
+
**Checkpoint done** (last task in the checkpoint complete): auto-trigger `cbp-checkpoint-check` via the Skill tool. `cbp-checkpoint-check` is `ask`-tier — the permission prompt is the human gate; the 200K context guard handles oversized contexts (via `cbp-clear-prep`) only when context is near the limit. No unconditional `/clear`. (See `checkpoint-done-branching.md`.)
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
**Session end** (no pending tasks anywhere): emit a single directive line at the end of skill output and stop:
|
|
27
25
|
|
|
28
26
|
```
|
|
29
27
|
**Next**: Run /clear, then /cbp-session-end.
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
The user runs
|
|
30
|
+
The user runs session-end after refreshing context. No menu, no options — just one directive.
|
|
33
31
|
|
|
34
32
|
## Rule
|
|
35
33
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: cbp-task-testing
|
|
3
3
|
description: Run comprehensive task-level testing after /cbp-task-check passes
|
|
4
4
|
argument-hint: [chk-task]
|
|
5
|
-
triggers: [cbp-task-complete]
|
|
5
|
+
triggers: [cbp-task-complete, cbp-round-input]
|
|
6
6
|
effort: xhigh
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -233,21 +233,16 @@ Collect failures from automated tests (Step 6), cross-round code review (Step 6.
|
|
|
233
233
|
All tests passed for TASK-[N]. Routing to task-complete...
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
-
|
|
236
|
+
Invoke `cbp-task-complete` via the Skill tool. `cbp-task-complete` is `ask`-tier — the harness
|
|
237
|
+
permission prompt IS the human gate; the user confirms (or declines) before task commit,
|
|
238
|
+
merge-main, and completion.
|
|
237
239
|
|
|
238
240
|
**Minor problems found:**
|
|
239
241
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
**Next:**
|
|
243
|
-
Run `/cbp-round-input` to:
|
|
244
|
-
|
|
245
|
-
- Address the minor issues found during testing
|
|
246
|
-
- Create a focused round for fixes
|
|
247
|
-
|
|
248
|
-
---
|
|
242
|
+
Invoking `cbp-round-input` to address the minor issues found during testing...
|
|
249
243
|
|
|
250
|
-
|
|
244
|
+
Invoke `cbp-round-input` via the Skill tool. `cbp-round-input` is `allow`-tier — it auto-fires
|
|
245
|
+
silently.
|
|
251
246
|
|
|
252
247
|
**Major problems found:**
|
|
253
248
|
|
|
@@ -278,5 +273,5 @@ Waiting for user to run `/cbp-task-create`.
|
|
|
278
273
|
|
|
279
274
|
- **Reads**: `.codebyplan/state/checkpoints/*.json`, `checkpoints/<id>/tasks/*.json`, `checkpoints/<id>/tasks/<id>/rounds/*.json`, `todos.json` (local-first; `npx codebyplan sync` on miss; MCP `get_current_task`/`get_rounds` break-glass), plus all aggregated files
|
|
280
275
|
- **Writes**: `codebyplan task update` (CLI write-through; MCP `update_task` break-glass)
|
|
281
|
-
- **Triggers**:
|
|
282
|
-
- **Triggered by**:
|
|
276
|
+
- **Triggers**: `cbp-task-complete` (auto via Skill tool, when ALL PASS — `ask`-tier, permission prompt IS the human gate); `cbp-round-input` (auto via Skill tool, on minor problems — `allow`-tier, fires silently)
|
|
277
|
+
- **Triggered by**: `cbp-task-check` auto-triggers this skill via Skill tool on READY verdict; `cbp-task-testing` is `allow`-tier and fires silently (no permission prompt)
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: cbp-frontend-a11y
|
|
3
|
-
description: Pre-implementation accessibility playbook loaded BEFORE writing UI / styling code. Produces a per-component checklist of WCAG 2.1 AA obligations from semantic HTML, ARIA roles/states, keyboard patterns, and contrast requirements.
|
|
4
|
-
effort: xhigh
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Frontend Accessibility (Pre-Implementation Playbook)
|
|
8
|
-
|
|
9
|
-
Loaded by `round-executor` Step 2.6 BEFORE any UI or styling file is written, AFTER `frontend-design` has committed to an aesthetic direction. Produces a concrete pre-write checklist — not a post-implementation audit.
|
|
10
|
-
|
|
11
|
-
## When this skill fires
|
|
12
|
-
|
|
13
|
-
Invoked when the wave's `skill_preloads[]` contains `"frontend-a11y"` (set by planner Phase 5.6 when `wave.files[]` includes UI-bearing paths). See `rules/frontend-accessibility-invocation.md` for the trigger gate.
|
|
14
|
-
|
|
15
|
-
If none of the wave files are UI-bearing, skip — proceed to Step 3.
|
|
16
|
-
|
|
17
|
-
## Phase 1: Read tokens and sibling components
|
|
18
|
-
|
|
19
|
-
1. Identify design tokens from the plan's context or `frontend-design` output — colour tokens are needed for contrast checks.
|
|
20
|
-
2. Glob for sibling components in the same directory as files being authored. Read 1-2 examples to understand existing `aria-*` usage, `role` attributes, keyboard handlers, focus management patterns.
|
|
21
|
-
3. Note the established a11y posture: does the codebase already use `role="dialog"` patterns? Does it trap focus in modals? Are there custom keyboard handlers?
|
|
22
|
-
|
|
23
|
-
## Phase 2: Detect the stack
|
|
24
|
-
|
|
25
|
-
Read the planner's `test_strategy.platform` or grep for signal files:
|
|
26
|
-
|
|
27
|
-
| Signal | Stack |
|
|
28
|
-
|--------|-------|
|
|
29
|
-
| `next.config.ts` | Next.js (App Router) |
|
|
30
|
-
| `expo` in deps | React Native / Expo |
|
|
31
|
-
| `tauri.conf.json` | Tauri web view |
|
|
32
|
-
|
|
33
|
-
Load the matching reference doc from `reference/` (relative to this SKILL.md):
|
|
34
|
-
|
|
35
|
-
- Next.js / web: read `reference/semantic-html.md`, `reference/aria-roles-states.md`, `reference/keyboard-patterns.md`, `reference/contrast-visual.md`
|
|
36
|
-
- React Native: read `reference/aria-roles-states.md`, `reference/contrast-visual.md` (semantic HTML n/a for RN)
|
|
37
|
-
- Tauri web view: same as Next.js / web
|
|
38
|
-
|
|
39
|
-
## Phase 3: Load reference docs
|
|
40
|
-
|
|
41
|
-
For the detected stack, read EACH applicable reference doc in sequence. Do not skip — the pre-write checklist is derived from their combined content.
|
|
42
|
-
|
|
43
|
-
Reference docs (paths relative to this SKILL.md):
|
|
44
|
-
|
|
45
|
-
- `reference/semantic-html.md` — landmark roles, heading hierarchy, element semantics, anti-patterns
|
|
46
|
-
- `reference/aria-roles-states.md` — role table, aria-label vs aria-labelledby, live regions, expanded/pressed/hidden
|
|
47
|
-
- `reference/keyboard-patterns.md` — focus management, tab order, Esc, arrow keys, focus traps, type-ahead
|
|
48
|
-
- `reference/contrast-visual.md` — WCAG 2.1 AA ratios, focus-visible, colour-only state, reduced-motion, touch targets
|
|
49
|
-
|
|
50
|
-
## Phase 4: Commit to per-component obligations
|
|
51
|
-
|
|
52
|
-
For each component or element type in `wave.files[]`, derive explicit obligations from the reference docs. Group by component:
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
Component: <ComponentName> (<path>)
|
|
56
|
-
- Semantic: [e.g. "use <button> not <div onClick>"]
|
|
57
|
-
- ARIA: [e.g. "aria-expanded on disclosure trigger"]
|
|
58
|
-
- Keyboard: [e.g. "Esc closes; focus returns to trigger"]
|
|
59
|
-
- Contrast: [e.g. "border token needs 3:1 vs background — verify"]
|
|
60
|
-
- Touch: [e.g. "min 44x44px tap target on mobile"]
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Unknown component types get the universal checklist from Phase 5.
|
|
64
|
-
|
|
65
|
-
## Phase 5: Universal guidelines (applied to every component)
|
|
66
|
-
|
|
67
|
-
Regardless of component type, every UI component must satisfy:
|
|
68
|
-
|
|
69
|
-
1. Every interactive element is keyboard-reachable and activatable (Enter/Space for buttons, Enter for links)
|
|
70
|
-
2. Focus-visible is never removed via `outline: none` without a custom indicator meeting 3:1 contrast
|
|
71
|
-
3. No state conveyed via colour alone — icon + text + colour
|
|
72
|
-
4. `prefers-reduced-motion` media query wraps any animation
|
|
73
|
-
5. Touch targets ≥ 44×44 CSS px
|
|
74
|
-
6. Images have `alt` text (decorative images use `alt=""`)
|
|
75
|
-
7. Form inputs have associated `<label htmlFor>` or `aria-label`
|
|
76
|
-
|
|
77
|
-
## Phase 6: Output pre-write checklist
|
|
78
|
-
|
|
79
|
-
Produce a flat checklist in `round.context.frontend_a11y_checklist`:
|
|
80
|
-
|
|
81
|
-
```yaml
|
|
82
|
-
frontend_a11y_checklist:
|
|
83
|
-
- component: "<ComponentName>"
|
|
84
|
-
file: "<path>"
|
|
85
|
-
items:
|
|
86
|
-
- "[Semantic] use <button> not <div onClick>"
|
|
87
|
-
- "[ARIA] aria-expanded on trigger; aria-controls referencing panel id"
|
|
88
|
-
- "[Keyboard] Esc closes panel; focus returns to trigger"
|
|
89
|
-
- "[Contrast] verify focus ring token meets 3:1 vs background"
|
|
90
|
-
- "[Touch] min 44x44px on mobile breakpoint"
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
The executor consults this checklist when authoring each component in Step 3.
|
|
94
|
-
|
|
95
|
-
## Output back to round-executor
|
|
96
|
-
|
|
97
|
-
```yaml
|
|
98
|
-
round.context.frontend_a11y_loaded: true
|
|
99
|
-
round.context.frontend_a11y_checklist: [per-component checklist items]
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Integration
|
|
103
|
-
|
|
104
|
-
- **Invoked by**: `round-executor` Step 2.6 (when `"frontend-a11y"` in `wave.skill_preloads[]`)
|
|
105
|
-
- **Reads**: `reference/semantic-html.md`, `reference/aria-roles-states.md`, `reference/keyboard-patterns.md`, `reference/contrast-visual.md`
|
|
106
|
-
- **Output consumed by**: `round-executor` Step 3 (implementation guidance)
|
|
107
|
-
- **Pairs with**: `frontend-design` (invoked first in Step 2.6), `frontend-ui` + `frontend-ux` (post-implementation Step 3.8)
|
|
108
|
-
- **Trigger rule**: `rules/frontend-accessibility-invocation.md`
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# ARIA Roles, States, and Properties Reference
|
|
2
|
-
|
|
3
|
-
**Golden rule**: Prefer native HTML semantics. ARIA fills gaps — it does not replace semantic elements. An `<input type="checkbox">` is always better than `<div role="checkbox">`.
|
|
4
|
-
|
|
5
|
-
## When to Add a Role
|
|
6
|
-
|
|
7
|
-
Use `role` ONLY when no native HTML element maps to the semantic need:
|
|
8
|
-
|
|
9
|
-
| Pattern | Native element | ARIA role (fallback) |
|
|
10
|
-
|---------|---------------|----------------------|
|
|
11
|
-
| Dialog / modal | — | `role="dialog"` + `aria-modal="true"` |
|
|
12
|
-
| Alerting status message | — | `role="status"` or `role="alert"` |
|
|
13
|
-
| Tab list | — | `role="tablist"`, `role="tab"`, `role="tabpanel"` |
|
|
14
|
-
| Custom listbox | — | `role="listbox"`, `role="option"` |
|
|
15
|
-
| Progress indicator | `<progress>` | `role="progressbar"` if `<progress>` unstyled |
|
|
16
|
-
| Tooltip | `title` attr (limited) | `role="tooltip"` + `aria-describedby` |
|
|
17
|
-
|
|
18
|
-
## aria-label vs aria-labelledby vs aria-describedby
|
|
19
|
-
|
|
20
|
-
| Attribute | Use when | Priority |
|
|
21
|
-
|-----------|----------|----------|
|
|
22
|
-
| `aria-labelledby` | A visible text element names this element | Highest — overrides aria-label and native label |
|
|
23
|
-
| `aria-label` | No visible text label exists (icon buttons, close buttons) | Medium |
|
|
24
|
-
| `aria-describedby` | Additional descriptive text supplements the label | Lowest — supplementary, not a primary name |
|
|
25
|
-
|
|
26
|
-
Examples:
|
|
27
|
-
```jsx
|
|
28
|
-
// Icon button — no visible label
|
|
29
|
-
<button aria-label="Close dialog">
|
|
30
|
-
<Icon name="x" aria-hidden="true" />
|
|
31
|
-
</button>
|
|
32
|
-
|
|
33
|
-
// Element labelled by visible heading
|
|
34
|
-
<section aria-labelledby="billing-heading">
|
|
35
|
-
<h2 id="billing-heading">Billing</h2>
|
|
36
|
-
</section>
|
|
37
|
-
|
|
38
|
-
// Field with hint text
|
|
39
|
-
<input id="password" aria-describedby="password-hint" />
|
|
40
|
-
<span id="password-hint">Must be at least 8 characters</span>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Live Regions
|
|
44
|
-
|
|
45
|
-
Announce dynamic content changes to screen readers without moving focus.
|
|
46
|
-
|
|
47
|
-
| Role / Attribute | Urgency | Use for |
|
|
48
|
-
|-----------------|---------|---------|
|
|
49
|
-
| `aria-live="polite"` | Waits for user to be idle | Status messages, form validation summaries, search result counts |
|
|
50
|
-
| `aria-live="assertive"` | Interrupts immediately | Critical errors, session timeout warnings |
|
|
51
|
-
| `role="status"` | Same as `aria-live="polite"` | Status messages (shorthand) |
|
|
52
|
-
| `role="alert"` | Same as `aria-live="assertive"` | Error alerts (shorthand) |
|
|
53
|
-
|
|
54
|
-
Anti-pattern: using `role="alert"` for non-urgent messages — screen reader interruptions are disruptive. Reserve for true emergencies.
|
|
55
|
-
|
|
56
|
-
```jsx
|
|
57
|
-
// Status (polite)
|
|
58
|
-
<div role="status" aria-live="polite">{statusMessage}</div>
|
|
59
|
-
|
|
60
|
-
// Error (assertive)
|
|
61
|
-
<div role="alert">{errorMessage}</div>
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Common State Attributes
|
|
65
|
-
|
|
66
|
-
| Attribute | Values | Use for |
|
|
67
|
-
|-----------|--------|---------|
|
|
68
|
-
| `aria-expanded` | `true` / `false` | Disclosure triggers (accordion, dropdown, menu) |
|
|
69
|
-
| `aria-pressed` | `true` / `false` / `"mixed"` | Toggle buttons (bold, like, mute) |
|
|
70
|
-
| `aria-hidden` | `true` | Decorative elements, icon-only images — removes from accessibility tree |
|
|
71
|
-
| `aria-checked` | `true` / `false` / `"mixed"` | Custom checkbox/radio when not using `<input type="checkbox">` |
|
|
72
|
-
| `aria-disabled` | `true` | Visually disabled but still focusable (use sparingly) |
|
|
73
|
-
| `aria-selected` | `true` / `false` | Selected tab, selected option in listbox |
|
|
74
|
-
| `aria-current` | `"page"` / `"step"` / `true` | Current item in nav, current step in wizard |
|
|
75
|
-
|
|
76
|
-
```jsx
|
|
77
|
-
// Accordion trigger
|
|
78
|
-
<button
|
|
79
|
-
aria-expanded={isOpen}
|
|
80
|
-
aria-controls="panel-1"
|
|
81
|
-
>
|
|
82
|
-
Section title
|
|
83
|
-
</button>
|
|
84
|
-
<div id="panel-1" hidden={!isOpen}>...</div>
|
|
85
|
-
|
|
86
|
-
// Toggle button
|
|
87
|
-
<button
|
|
88
|
-
aria-pressed={isBold}
|
|
89
|
-
onClick={() => setIsBold(!isBold)}
|
|
90
|
-
>
|
|
91
|
-
Bold
|
|
92
|
-
</button>
|
|
93
|
-
|
|
94
|
-
// Decorative icon
|
|
95
|
-
<svg aria-hidden="true" focusable="false">...</svg>
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## aria-hidden Usage Rules
|
|
99
|
-
|
|
100
|
-
- `aria-hidden="true"` removes element and ALL descendants from accessibility tree
|
|
101
|
-
- Never place `aria-hidden="true"` on a focusable element (keyboard users still reach it)
|
|
102
|
-
- Common correct uses: decorative icons, background images, duplicate visible text (when the accessible name comes from aria-label)
|
|
103
|
-
|
|
104
|
-
```jsx
|
|
105
|
-
// Correct: icon inside labelled button
|
|
106
|
-
<button aria-label="Delete">
|
|
107
|
-
<TrashIcon aria-hidden="true" />
|
|
108
|
-
</button>
|
|
109
|
-
|
|
110
|
-
// Wrong: aria-hidden on focusable element
|
|
111
|
-
<button aria-hidden="true">...</button> // users can still Tab to it
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Dialog Pattern
|
|
115
|
-
|
|
116
|
-
```jsx
|
|
117
|
-
<dialog
|
|
118
|
-
role="dialog"
|
|
119
|
-
aria-modal="true"
|
|
120
|
-
aria-labelledby="dialog-title"
|
|
121
|
-
aria-describedby="dialog-description"
|
|
122
|
-
>
|
|
123
|
-
<h2 id="dialog-title">Confirm deletion</h2>
|
|
124
|
-
<p id="dialog-description">This action cannot be undone.</p>
|
|
125
|
-
<button onClick={onConfirm}>Delete</button>
|
|
126
|
-
<button onClick={onClose}>Cancel</button>
|
|
127
|
-
</dialog>
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Focus must move INTO the dialog on open and RETURN to the trigger on close. See `keyboard-patterns.md` for focus trap implementation.
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# Contrast and Visual Accessibility Reference
|
|
2
|
-
|
|
3
|
-
## WCAG 2.1 AA Contrast Requirements
|
|
4
|
-
|
|
5
|
-
All text and UI components must meet these minimum contrast ratios:
|
|
6
|
-
|
|
7
|
-
| Content type | Minimum ratio | Standard |
|
|
8
|
-
|-------------|--------------|---------|
|
|
9
|
-
| Normal text (< 18pt / < 14pt bold) | **4.5:1** | WCAG 2.1 AA SC 1.4.3 |
|
|
10
|
-
| Large text (≥ 18pt / ≥ 14pt bold) | **3:1** | WCAG 2.1 AA SC 1.4.3 |
|
|
11
|
-
| UI components (borders, icons, form controls) | **3:1** | WCAG 2.1 AA SC 1.4.11 |
|
|
12
|
-
| Graphical objects (data chart elements, icons conveying meaning) | **3:1** | WCAG 2.1 AA SC 1.4.11 |
|
|
13
|
-
|
|
14
|
-
**Decorative** elements (purely ornamental, no meaning) are EXEMPT.
|
|
15
|
-
|
|
16
|
-
### Verification
|
|
17
|
-
|
|
18
|
-
Use design tokens from `packages/design-tokens/` to derive hex values, then verify with a contrast checker:
|
|
19
|
-
|
|
20
|
-
- Browser DevTools Accessibility panel
|
|
21
|
-
- `npx @accessibility-checker/cli` against the rendered component
|
|
22
|
-
- Design-tool plugins (Figma Contrast, Stark)
|
|
23
|
-
|
|
24
|
-
If a token pair is new, record the ratio in a comment in the SCSS: `/* contrast: 5.2:1 vs --color-surface */`.
|
|
25
|
-
|
|
26
|
-
## Focus Visible
|
|
27
|
-
|
|
28
|
-
Focus indicators must NEVER be suppressed via `outline: none` or `outline: 0` without providing a replacement that meets **3:1 contrast** against adjacent colour:
|
|
29
|
-
|
|
30
|
-
```scss
|
|
31
|
-
// Anti-pattern — removes all visible focus indicator
|
|
32
|
-
&:focus {
|
|
33
|
-
outline: none; // WCAG failure
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Correct — custom focus ring that meets 3:1 contrast
|
|
37
|
-
&:focus-visible {
|
|
38
|
-
outline: 2px solid var(--color-focus-ring); // 3:1 minimum
|
|
39
|
-
outline-offset: 2px;
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Use `:focus-visible` (not `:focus`) for the custom ring — `:focus-visible` suppresses the ring for mouse clicks while preserving it for keyboard navigation.
|
|
44
|
-
|
|
45
|
-
The WCAG 2.2 enhanced criterion (SC 2.4.11, AAA) requires 3:1 contrast + 2px outline area. Target this for new components.
|
|
46
|
-
|
|
47
|
-
## Colour-Only State Communication
|
|
48
|
-
|
|
49
|
-
State conveyed through colour alone is a WCAG 2.1 AA failure (SC 1.4.1). Always pair colour with at least one of: icon, text label, pattern, or shape.
|
|
50
|
-
|
|
51
|
-
| Anti-pattern | Fix |
|
|
52
|
-
|-------------|-----|
|
|
53
|
-
| Red border = error (colour only) | Red border + error icon + "Invalid email" text |
|
|
54
|
-
| Green = online (colour only) | Green dot + "Online" text label |
|
|
55
|
-
| Yellow = warning (colour only) | Yellow background + warning icon + descriptive text |
|
|
56
|
-
| Active nav item is blue (colour only) | Blue + `aria-current="page"` + underline or bold weight |
|
|
57
|
-
|
|
58
|
-
## prefers-reduced-motion
|
|
59
|
-
|
|
60
|
-
Users with vestibular disorders may configure `prefers-reduced-motion: reduce` in their OS. Honour it:
|
|
61
|
-
|
|
62
|
-
```scss
|
|
63
|
-
@keyframes slideIn {
|
|
64
|
-
from { transform: translateX(-100%); }
|
|
65
|
-
to { transform: translateX(0); }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.panel {
|
|
69
|
-
animation: slideIn 300ms ease-out;
|
|
70
|
-
|
|
71
|
-
@media (prefers-reduced-motion: reduce) {
|
|
72
|
-
animation: none;
|
|
73
|
-
// Provide instant appearance or a fade (no translate/scale/spin)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
For JavaScript-driven animations:
|
|
79
|
-
|
|
80
|
-
```ts
|
|
81
|
-
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
82
|
-
if (!prefersReduced) {
|
|
83
|
-
// run animation
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Transitions that solely affect `opacity` (fade) are generally safe — opacity changes do not trigger vestibular responses. Transforms (`translate`, `scale`, `rotate`) and large motion sweeps are the primary triggers.
|
|
88
|
-
|
|
89
|
-
## Touch Target Size
|
|
90
|
-
|
|
91
|
-
Interactive elements must have a minimum tap target of **44 × 44 CSS px** (Apple HIG / WCAG 2.5.5 AAA, de-facto standard):
|
|
92
|
-
|
|
93
|
-
```scss
|
|
94
|
-
.icon-button {
|
|
95
|
-
min-width: 44px;
|
|
96
|
-
min-height: 44px;
|
|
97
|
-
display: flex;
|
|
98
|
-
align-items: center;
|
|
99
|
-
justify-content: center;
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
When the visible icon is smaller (e.g. 24px), expand the tap target with padding:
|
|
104
|
-
|
|
105
|
-
```scss
|
|
106
|
-
.icon-button {
|
|
107
|
-
padding: 10px; // 24px icon + 2×10px padding = 44px touch target
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
On mobile breakpoints specifically, verify that adjacent interactive elements have at least 8px spacing between tap target edges to prevent accidental activation.
|
|
112
|
-
|
|
113
|
-
## Text Resizing
|
|
114
|
-
|
|
115
|
-
Users who increase browser text size up to 200% must be able to read and use all content without horizontal scroll (WCAG 1.4.4). Use relative units:
|
|
116
|
-
|
|
117
|
-
- `font-size`: `rem` (relative to browser root, respects user preference)
|
|
118
|
-
- `line-height`: unitless (e.g. `1.5`) or `em`
|
|
119
|
-
- Container widths: `max-width` in `ch` or `%`, never fixed `px` for reading columns
|
|
120
|
-
- Spacing: `em` for component-internal spacing; `rem` for layout spacing
|
|
121
|
-
|
|
122
|
-
Avoid `px` for font sizes on text elements that users may need to scale.
|