# @axaraaudit/runtime
Headless **runtime** checks that static analysis can't do: real keyboard focus
behavior (focus traps) via Playwright, and a **Figma Variables** connector to
compare the design source of truth against the code's tokens.
## Focus-trap detection
```ts
import { auditFocusOrder } from '@axaraaudit/runtime';
const report = await auditFocusOrder('Two');
// { isTrap, trapKind: 'none'|'stuck'|'cycle', reachedExit, focusOrder, message }
```
The component is mounted in isolation between two sentinel buttons; `Tab` is
pressed up to `maxTabs` times while `document.activeElement` is snapshotted. The
pure {@link analyzeFocusOrder} then decides:
- **`cycle`** — focus loops back inside the component before escaping → trap.
- **`stuck`** — focus never moves → trap.
- reaching the trailing sentinel → focus escaped normally (no trap).
- otherwise `inconclusive` (raise `maxTabs`) — never a false positive.
Requires a browser: `pnpm exec playwright install chromium`. The detection logic
itself is pure and unit-tested without a browser.
## Figma Variables connector
```ts
import { FigmaClient, normalizeFigmaVariables, compareTokens } from '@axaraaudit/runtime';
import { parseDtcgString } from '@axaraaudit/core';
const figma = new FigmaClient({ token: process.env.FIGMA_TOKEN! });
const { meta } = await figma.getLocalVariables(fileKey); // GET /v1/files/:key/variables/local
const { tokens: figmaTokens } = normalizeFigmaVariables(meta);
const { tokens: codeTokens } = parseDtcgString(dtcgJson);
const diff = compareTokens(figmaTokens, codeTokens);
// { matches, mismatches, missingInCode, missingInFigma, summary: { inSync } }
```
- Resolves variable **aliases** (cycle-safe) and selects a collection **mode**.
- Converts COLOR → canonical hex and FLOAT → `px`, reusing core's color/dimension
utilities so Figma and code share one canonical form (e.g. `0.5rem` ≡ `8px`).
- The HTTP `fetch` is injectable, so normalization/compare are tested without network.
## Demo
```bash
pnpm --filter @axaraaudit/runtime build
node packages/runtime/scripts/runtime-smoke.mjs
```