Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
2eb6880
fix(ai): added all skills, pipeline context and overview, and scripts…
ArtBlue May 19, 2026
dc9d423
docs(adr): add AI skills design system architecture decision record
ArtBlue May 19, 2026
023b852
fix(ai): added missing skills and scripts
ArtBlue May 21, 2026
f919f5a
fix(ai) added spec diff feature to isolate modification scope
ArtBlue May 21, 2026
502e309
chore(ai): updated progress on pipeline docs
ArtBlue May 28, 2026
a317128
chore(ai): combined static layer work under one skill, made improveme…
ArtBlue May 28, 2026
656042f
fix(ai): updated modification pipeline to remove gaps
ArtBlue May 29, 2026
3493de9
Merge branch 'main' of https://github.com/eBay/evo-web into ai-comp-p…
ArtBlue May 29, 2026
e26bb60
fix(ai): fixed inefficient spec diff mechanism
ArtBlue May 29, 2026
d2a200b
fix(ai): made explicit skill gating so agents do not veer off and do …
ArtBlue Jun 1, 2026
62625ef
fix(ai): closed more gaps using explicit guardrails to endorse more c…
ArtBlue Jun 2, 2026
a3ee58c
fix(ai): fixed additional gaps of missed qa and ensuring better a11y …
ArtBlue Jun 2, 2026
d496023
fix(ai): added instructions to avoid pipeline stopages and mixup for …
ArtBlue Jun 3, 2026
60a6ebb
chore(ai): updated skill with important details for better work outcomes
ArtBlue Jun 8, 2026
a8c0685
fix(ai): filled in the skill gaps for the icon rename scenario
ArtBlue Jun 9, 2026
9acc3e5
fix(ai): updated icon work to include legacy packages
ArtBlue Jun 9, 2026
511e39a
feat(ai): add state file init and resume logic to evo-component
ArtBlue Jun 10, 2026
cff38f3
fix(ai): address code quality issues in evo-component Step 2.5 state …
ArtBlue Jun 10, 2026
3cf6da0
feat(ai): add state file awareness and stall surfacing to evo-pipeline
ArtBlue Jun 10, 2026
e44b164
fix(ai): address quality issues in evo-pipeline pipeline-state detect…
ArtBlue Jun 10, 2026
3a7d0fc
feat(ai): add transition table, pre-flight validation, and post-step …
ArtBlue Jun 10, 2026
d7323eb
fix(ai): scope table, fast-forward write helper, step 14-15 boundary …
ArtBlue Jun 10, 2026
b3d606d
feat(ai): add completion record write to evo-static-component
ArtBlue Jun 10, 2026
fc98b2c
feat(ai): add completion record write to evo-static-storybook
ArtBlue Jun 10, 2026
88db090
feat(ai): add completion record write to evo-docs-hookup (both modes)
ArtBlue Jun 10, 2026
ce1a90d
feat(ai): add completion record write to evo-a11y (both passes)
ArtBlue Jun 10, 2026
07d0764
feat(ai): add completion record writes to all framework layer sub-skills
ArtBlue Jun 10, 2026
cf6d210
feat(ai): add micro-QA checkpoint 1 (static layer) with true Agent spawn
ArtBlue Jun 10, 2026
68ff1d0
feat(ai): add micro-QA checkpoint 2 (framework layer) with true Agent…
ArtBlue Jun 10, 2026
c46330f
feat(ai): replace Step 15 with true Agent spawn (evo-qa); add complet…
ArtBlue Jun 10, 2026
40e8ab7
docs(ai): add evo-pipeline reliability plan
ArtBlue Jun 10, 2026
6d904db
chore(ai): added hard token requirement for the pipeline to proceed
ArtBlue Jun 10, 2026
4950a55
chore(ai): updated icon skill with missing guardrails, added worktree…
ArtBlue Jun 15, 2026
1f19008
Merge branch 'main' of https://github.com/eBay/evo-web into ai-comp-p…
ArtBlue Jun 17, 2026
d490b1a
Merge branch 'main' of https://github.com/eBay/evo-web into ai-comp-p…
ArtBlue Jun 22, 2026
df5f3e7
feat(pipeline): escalate scope to full/interactive on variant add or …
ArtBlue Jun 22, 2026
a910d51
chore(ai): added an evo-pipeline readme for run instructions
ArtBlue Jun 23, 2026
072cd14
chore(ai): added better deterministic safeguards and modified system …
ArtBlue Jun 24, 2026
6b6c4d7
chore(ai): update ADR 0005 structure and add ephemeral file guidance
ArtBlue Jun 25, 2026
5e5a669
fix(ai): reverted rogue diffs
ArtBlue Jun 26, 2026
802c041
fix(ai): reverted rogue diffs
ArtBlue Jun 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "node -e \"const fs=require('fs'),path=require('path');const base='src/routes/_index/components';if(!fs.existsSync(base))process.exit(0);const comps=fs.readdirSync(base,{withFileTypes:true}).filter(d=>d.isDirectory()).map(d=>d.name);let found=false;comps.forEach(c=>{const p=path.join(base,c,'pipeline-state.json');if(!fs.existsSync(p))return;try{const s=JSON.parse(fs.readFileSync(p,'utf8'));const ip=Object.entries(s.steps||{}).filter(([,v])=>v.status==='in-progress');if(ip.length){found=true;process.stdout.write('\\n⚠️ PIPELINE IN-PROGRESS — do not stop.\\n Component: '+s.component+'\\n Step '+ip.map(([k])=>k).join(', ')+' is still in-progress.\\n Read pipeline-state.json and advance to the next step before stopping.\\n');}}catch(e){}});if(found)process.exit(2);\" 2>/dev/null"
}
]
}
]
}
}
283 changes: 283 additions & 0 deletions .claude/skills/evo-a11y/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
---
name: evo-a11y
description: >
Accessibility validation and incremental docs generation for evo-web components.
Runs in two passes: Pass 1 (Step 7, after static layer) validates HTML and
static storybook, then writes the static sections of accessibility+page.marko.
Pass 2 (Step 12, after all layers) validates Marko and React, then fills in
the interactive sections. The orchestrator explicitly declares which pass and
scope — never inferred from disk. Skipped entirely for style-only revisions.
Use this whenever the user says "run a11y", "validate accessibility", "generate
accessibility docs", "check ARIA", or when the orchestrator invokes Step 7
(Pass 1) or Step 12 (Pass 2).
---

# evo-a11y

You run in two passes. The orchestrator tells you which pass and scope — do not
infer from disk state (fails on revisions where old files are already present).

The accessibility docs are built incrementally: Pass 1 writes the static
sections; Pass 2 fills in the interactive sections. For style-only revisions,
this skill is not invoked.

---

## Scope declaration from orchestrator

You will receive one of:

- `"Pass 1 — static layer only. Steps 4–6 have run."`
- `"Pass 2 — full scope. Steps 4–11 have run."`
- `"Pass 2 — interactive scope. Steps 8–11 have run."`

If invoked standalone without declaration, ask which pass and scope.

---

## Pass 1 — Static layer validation + static a11y docs

**Trigger:** Step 7, after static component + static storybook + css docs (Steps 4–6)

### Phase 1a: Validate

**HTML from `/evo-static-component` (in context):**

- `manifest.a11y.explicitRole: true` → `role="..."` on root element
- `manifest.a11y.labelStrategy === "aria-label-prop"` → `aria-label` present
- `manifest.a11y.labelStrategy === "aria-hidden"` → `aria-hidden="true"` present for null case
- Each entry in `manifest.a11y.ariaAttributes[]` represented in at least one variant
- Root element matches `manifest.rootElement.default`
- No `<div>` where a semantic element is correct

**Static storybook (read from disk):**

- `RTL` named export exists — 🔴 if missing
- `textSpacing` export with `demo-a11y-text-spacing` on root BEM element — 🔴 if missing

**Anti-patterns:**

- `role="presentation"` without justification
- `aria-hidden` and interactive elements mixed incorrectly

### Phase 1b: Write static sections of accessibility+page.marko

Write `src/routes/_index/components/<block>/accessibility+page.marko` with the
sections derivable from the static layer. Mark interactive sections as stubs.

```marko
import "../../../../sass/accessibility.scss";
import { urls } from "../../../../data";

<div class="a11y-pattern-content">
<h1><DisplayName> Accessibility</h1>

<h2>Best Practices</h2>
<!-- From manifest.a11y (label strategy, decorative vs informational)
and manifest.callerObligations[] (a11y-critical categories only) -->

<h2>Interaction Design</h2>
<p>This section provides detailed instructions for how different input types
should navigate and operate the pattern.</p>

<h3>Keyboard</h3>
<!-- STUB if interactive layers not yet generated:
<p>This section will be completed after the interactive layer is generated.</p>
OR fill with manifest.keyboardInteractions[] if present in manifest -->

<h3>Screen Reader</h3>
<!-- STUB or fill from manifest.a11y.screenReaderAnnouncement if static-only -->

<h3>Pointer</h3>
<!-- For non-interactive components: fill now.
For interactive: stub — "Updated after interactive layer generation." -->

<h2>ARIA Reference</h2>
<table>
<thead><tr><th>Attribute</th><th>Description</th></tr></thead>
<tbody>
<!-- One <tr> per manifest.a11y.ariaAttributes[] + a11yProps
This table is derivable entirely from the manifest — fill it now -->
</tbody>
</table>

<!-- <h2>Further Reading</h2> — only if contract/manifest references known a11y URLs -->
</div>
```

**What to fill vs. stub:**

| Section | Fill now | Reason |
| ------------------------- | ---------------------------------------- | ------------------------------------------------ |
| Best Practices | ✅ Always | Derivable from manifest.a11y + callerObligations |
| ARIA Reference table | ✅ Always | Derivable from manifest.a11y.ariaAttributes[] |
| Pointer (non-interactive) | ✅ If focusable === false | Fully static |
| Keyboard | ✅ If keyboardInteractions[] in manifest | Otherwise stub |
| Screen Reader | ✅ Static announcements from manifest | Stub interactive state changes |
| Pointer (interactive) | Stub | Needs active/pressed/hover from Marko/React |

**Non-interactive components:** Fill all sections completely in Pass 1 — there
is no Pass 2 for style/static-only scopes.

Also write `accessibility+meta.json` if the component is non-interactive (no
Pass 2 needed):

```json
{
"pageTitle": "<DisplayName> Accessibility Guidelines — <tagline>",
"pageDescription": "<2-3 sentence SEO description>"
}
```

For interactive components, mark meta as pending: write a stub meta.json and
complete it in Pass 2.

### Pass 1 output

```
## A11y Pass 1 — $COMPONENT

Validation:
[✅ HTML ARIA correct | 🔴 issue: description]
[✅ RTL story present | 🔴 Missing]
[✅ textSpacing story present | 🔴 Missing]

Docs written:
✅ accessibility+page.marko — static sections complete
[✅ all sections filled (non-interactive) | 🔒 interactive stubs pending Pass 2]

Result: [✅ PASSED — proceed to Marko | 🔴 BLOCKED — fix issues first]
```

---

## Pass 2 — Full validation + fill interactive a11y docs

**Trigger:** Step 12, after all layers (Steps 4–11) or interactive-scope layers (Steps 8–11)

### Phase 2a: Validate all layers

**Re-run Pass 1 checks** (confirm static is still clean).

**`index.marko`** — read from disk:

- `manifest.a11y.labelStrategy` correctly wired: conditional `aria-label`/`aria-hidden`
- a11yProps with `allowNull: true` have both branches
- Required a11yProps: no `?` in `Input` interface
- Each `manifest.a11y.ariaAttributes[]` entry in template
- Keyboard handlers: Marko 6 inline syntax — no `this.emit`, `$ let`, `<if(`
- If `manifest.keyboardModel`: `<let/>` for focus state, not class methods

**`index.tsx`** — read from disk:

- a11yProps in TypeScript props type
- `aria-*` forwarded to correct DOM element
- Keyboard handlers match `manifest.keyboardInteractions[]`

**Marko storybook** — if `manifest.keyboardModel`: interactive story with `<let>` or `:=` — 🟡 if missing

**React storybook** — if `manifest.keyboardModel`: `Controlled` or `render`-based story — 🟡 if missing

### Phase 2b: Fill interactive sections of accessibility+page.marko

Read the existing `accessibility+page.marko` (written in Pass 1). Fill in or
replace the stubbed sections:

**Keyboard section** — from `manifest.keyboardModel` + `manifest.keyboardInteractions[]`:

- Use `<strong>KEY</strong>` for key names
- `<strong>must</strong>` for required behavior; `<em>may</em>` for optional

**Screen Reader section** — from `manifest.a11y.screenReaderAnnouncement`:

- Cover each usage mode (decorative, informational, interactive)
- Plain English — what gets announced, not implementation details

**Pointer section** — from manifest states + behaviors:

- Active/pressed/clicked behavior
- If inside interactive element: what clicking does

**Also complete `accessibility+meta.json`** (if written as stub in Pass 1).

### Pass 2 output

```
## A11y Pass 2 — $COMPONENT

Validation:
Static: [✅ Clean | 🔴 N issue(s)]
Marko: [✅ Passed | 🔴 N issue(s) | 🟡 N warnings]
React: [✅ Passed | 🔴 N issue(s) | 🟡 N warnings]
Marko storybook: [✅ Interactive story present | 🟡 Missing]
React storybook: [✅ Controlled story present | 🟡 Missing]

Docs updated:
✅ accessibility+page.marko — interactive sections filled
✅ accessibility+meta.json — complete

Result: [✅ PASSED | 🔴 BLOCKED — N issue(s)]
```

🔴 blocking issues in Pass 2 must be fixed before the build step.

---

## Completion record — mandatory final step

After all outputs are verified on disk, write the completion record.
The step ID depends on which pass was declared at invocation.
This is the signal the orchestrator reads to advance — do not skip this step.

### Pass 1 (Step 7)

> **Before running:** Substitute the actual component name for `$COMPONENT` and the actual BEM block name for `<BLOCK>`.

```bash
node -e "
const fs = require('fs');
const comp = '$COMPONENT';
const p = \`src/routes/_index/components/\${comp}/pipeline-state.json\`;
const s = JSON.parse(fs.readFileSync(p, 'utf8'));
const block = '<BLOCK>';
s.steps['7'] = {
status: 'complete',
completedAt: new Date().toISOString(),
outputs: [
\`src/routes/_index/components/\${block}/accessibility+page.marko\`,
]
};
s.updatedAt = new Date().toISOString();
fs.writeFileSync(p, JSON.stringify(s, null, 2));
console.log('Step 7 completion record written.');
"
```

### Pass 2 (Step 12)

> **Before running:** Substitute the actual component name for `$COMPONENT` and the actual BEM block name for `<BLOCK>`.

```bash
node -e "
const fs = require('fs');
const comp = '$COMPONENT';
const p = \`src/routes/_index/components/\${comp}/pipeline-state.json\`;
const s = JSON.parse(fs.readFileSync(p, 'utf8'));
const block = '<BLOCK>';
s.steps['12'] = {
status: 'complete',
completedAt: new Date().toISOString(),
outputs: [
\`src/routes/_index/components/\${block}/accessibility+page.marko\`,
\`src/routes/_index/components/\${block}/accessibility+meta.json\`,
]
};
s.updatedAt = new Date().toISOString();
fs.writeFileSync(p, JSON.stringify(s, null, 2));
console.log('Step 12 completion record written.');
"
```

If any blocking a11y failure was found that could not be fixed inline, write
`status: "failed"` with the failing check as the `error` field. Use the correct step ID
(`'7'` for Pass 1, `'12'` for Pass 2).
Loading
Loading