### browser platform (enabled)
- **Use for**: UI / frontend scenarios driven through a real browser.
- **Server**: `browser-devtools` · **scenario tools**: the `bdt_scenario-*` tools
  (`bdt_scenario-add` / `-update` / `-delete` / `-list` / `-search` / `-run`).
- **Store**: project → `.ironbee/scenarios/bdt`, global → `~/.ironbee/scenarios/bdt` (the
  server's `SCENARIOS_DIR`; you pass `scope`, the server resolves the path).
- Scenario **scripts** call this platform's tools via `callTool('<bare-tool>', {...})` — discover
  the available `bdt_*` tool names from your connected MCP tool schemas; don't guess.

**What to test & how — capture the SAME evidence the verifier would** (a scenario runs FOR
verification, so its script must collect what the browser cycle collects). In the script:
1. **Navigate** — `bdt_navigation_go-to` to the affected page(s), then **actually interact** (click
   buttons, fill forms, submit data, trigger the workflow that changed). A click-through that asserts
   nothing verifies nothing — the interaction is what makes the evidence meaningful. **Target elements
   with the `selector`/`ref` the aria-snapshot returns for each** (e.g. `getByRole(...)` or `@e12`) —
   do NOT hand-parse the snapshot TEXT with regex/string-matching: embedded quotes or special chars in
   labels make that brittle (it silently misses elements). This includes deriving a positional
   **`.nth(i)`** index by parsing the snapshot — a quote or special char in any earlier label shifts
   every index, so the click lands on the wrong element (or none). Pick each element by its own
   `getByRole(...)`/`ref`, or scope it to the matching card/row with a CSS `:has()` selector (e.g.
   `.product-card:has(h4:has-text('Widget')) button:has-text('Add to cart')`). NOTE: the
   browser-devtools resolver accepts only a flat `getByXYZ(...)` expression OR a CSS string — Playwright
   locator chaining like `.filter({ hasText })` does NOT parse. Never compute element positions from
   snapshot text.
2. **Screenshot** — `bdt_content_take-screenshot` (or `includeScreenshot: true` on a nav/interaction
   call) **with `returnOutput: true`, and put the returned `filePath` (absolute path to the saved PNG)
   in your result**. The later verifier opens that file with its `Read` tool to judge the pixels
   (readability, layout, cut-off content, expected render). **Do NOT set `includeBase64`** — a nested
   scenario screenshot is NOT surfaced as an inline MCP image (`scenario-run` strips nested image data)
   and base64 only bloats the result; the returned `filePath` is how visual judging works.
3. **Accessibility** — `bdt_a11y_take-aria-snapshot` (or `includeSnapshot: true`), called with
   `returnOutput: true` — the snapshot TEXT is what the verifier reads to judge page structure.
4. **Console** — `bdt_o11y_get-console-messages` with `returnOutput: true` to surface errors.

`return` the evidence — aria-snapshot text, page text (`bdt_content_get-as-text`), console errors, the
screenshot `filePath`s — **plus explicit pass/fail assertions**. That returned result is what
`$ironbee-verify scenario:<name>` reads to judge the run: functional + structural from the text, and
**visual by `Read`ing the returned screenshot files**. Capture the evidence AFTER the interactions
whose state you want to assert; for an intermediate state (a modal that opens then closes) capture at
that point too.
