Files
Tommaso Casaburi 1a33f7dc88 chore(agents): add a machine-wide Playwright browser resource budget
Playwright disables normal background throttling, so a hidden 5chan page keeps
doing P2P and rendering work after a check finishes. Agents verifying in
parallel across worktrees stacked whole browser engines on one machine.

Add scripts/pw-session.sh, a wrapper that permits one active Playwright browser
at a time and records who holds it:

- The lock is machine-wide, not per-repository, because the contended resource
  is RAM and CPU. Every worktree and checkout shares one slot.
- Acquisition is an atomic mkdir. Stale locks clear themselves: `open` reclaims
  any slot whose recorded browser is no longer `status: open` in
  `playwright-cli list --all`, so an interrupted workflow cannot strand the
  budget. When that list cannot be read the lock is left alone, so a broken CLI
  never silently disables the budget.
- `open` exits 75 when the slot is busy; `--wait[=SECONDS]` blocks instead.
- `close` always stops the browser, even when the lock was already lost, and
  never releases a slot held by a different session.
- `status` reports the holder and whether its browser is still alive.

Agent policy now runs browser engines and profiler batches sequentially, uses
Chrome/Blink during iteration and the full engine matrix only for final
verification, and never uses `close-all` or `kill-all` while other agents may
own sessions.

Covered by scripts/pw-session.test.js.
2026-08-01 19:21:01 +02:00

4.2 KiB

name, description
name description
inspect-elements Resolve on-screen 5chan DOM elements to React source files, line numbers, component names, and ownership stacks using the app's dev-only element-source helpers and playwright-cli. Use when an agent needs to inspect a page element, map a snapshot ref to source code, confirm which component rendered a node, or follow up after $profile-browsing finds a rerender hotspot and needs file-level attribution.

Inspect Elements

Use this skill to jump from a concrete DOM node in the running 5chan app to the React file and component stack that produced it.

Prerequisites

  • Dev server running at https://5chan.localhost
  • playwright-cli installed
  • Use the local dev app, not production. The element-source helpers are only exposed in dev mode.

Quick workflow

  1. Open the target route with ./scripts/pw-session.sh so the shared browser slot is respected.
  2. Run playwright-cli snapshot and choose the relevant element ref.
  3. Resolve that ref through the app helper:
playwright-cli -s=inspect eval "async el => JSON.stringify(await window.__ELEMENT_SOURCE__.resolve(el))" e7

The result includes:

  • source: the most useful file/line match for the element
  • componentName: the nearest meaningful React component
  • stack: ownership stack from the concrete node upward
  • tagName: the underlying DOM tag

Session setup

./scripts/pw-session.sh open inspect https://5chan.localhost
playwright-cli -s=inspect goto https://5chan.localhost/all
playwright-cli -s=inspect eval "window.__ELEMENT_SOURCE__?.ready ?? false"
playwright-cli -s=inspect snapshot

If ready is false, wait a moment and evaluate again. If window.__ELEMENT_SOURCE__?.error is set, report that error instead of continuing.

Resolve strategies

Prefer snapshot refs because they target the exact live DOM node you just inspected.

Snapshot ref

playwright-cli -s=inspect eval "async el => JSON.stringify(await window.__ELEMENT_SOURCE__.resolve(el))" e7

Selector

Use this only when the element is easy to target and a snapshot ref is not practical.

playwright-cli -s=inspect eval "JSON.stringify(await window.__ELEMENT_SOURCE__.resolveBySelector('[data-testid=\"composer\"]'))"

Screen coordinates

Useful when you have a screenshot or a visually obvious hotspot.

playwright-cli -s=inspect eval "JSON.stringify(await window.__ELEMENT_SOURCE__.resolveAtPoint(320, 420))"

Format the ownership stack

playwright-cli -s=inspect eval "async el => { const info = await window.__ELEMENT_SOURCE__.resolve(el); return JSON.stringify({ ...info, formattedStack: window.__ELEMENT_SOURCE__.formatStack(info.stack, 5) }); }" e7

Use formattedStack when you need a short, readable trace for the final report.

Close the session immediately after collecting the needed source evidence, including when resolution fails:

./scripts/pw-session.sh close inspect

Profiling follow-up

When $profile-browsing reports a hot route or rerender-heavy area:

  1. Reopen the route in a fresh Playwright session through ./scripts/pw-session.sh.
  2. Snapshot the concrete list item, card, modal, or toolbar node that looks relevant.
  3. Resolve it with window.__ELEMENT_SOURCE__.resolve(...).
  4. Use source.filePath as the direct edit target and stack to understand parent ownership.

This is a complement to react-scan, not a replacement. react-scan tells you which components rerender too often. inspect-elements tells you which exact source file produced the node you are looking at.

Rules

  • Prefer snapshot refs over brittle selectors.
  • Inspect the actual node the user cares about, not a distant wrapper, unless wrappers are the suspected problem.
  • If source is null but stack exists, use the first useful stack frame rather than guessing.
  • If both source and stack are empty, report that the node could not be resolved and pick a nearby parent element instead.
  • If the browser slot is held, retry after the owning workflow finishes or block on ./scripts/pw-session.sh open --wait ...; do not bypass the lock or use close-all/kill-all.
  • Close the exact named session in a finally-style cleanup.