Files
command-center/agent/managed-skills/static-page-headless-verify-traps/SKILL.md
T

2.6 KiB

name, description
name description
static-page-headless-verify-traps Verify a static HTML artifact headlessly after writing it: serve on a scratch port, assert structure, screenshot — with the omp JS-eval/browser API traps (browser.open options object, no tab.wait, tab.run is Node-isolated, log() swallowed in JS cells).

Headless verify of a static HTML file — traps that cost cells

Use after writing/rewriting a self-contained HTML artifact (guide, report, landing page) that must be proven to render before commit.

Loop

  1. Serve: Bun.spawn(["python3","-m","http.server","<port>","-d","<dir>"]) inside the eval cell; kill at cell end (proc.kill(9)), or pkill -f "http.server <port>" first if a prior cell died mid-run.
  2. Open + assert + screenshot in ONE cell; also cross-check anchors statically with node (regex href="#x" vs id="x") — no browser needed for that half.
  3. Entity/markup contamination sweep with grep on the FILE (&quot;, &#, raw < inside text): what renders small can hide real damage; conversely a suspicious screenshot is often just low-res misread — settle label text via tab.text("svg")/tab.text(selector) before "fixing" markup.

Eval/browser API traps (all hit live 2026-10-21)

  • browser.open({ url }) — options OBJECT; browser.open(url) is a TypeError.
  • tab.wait(...) does NOT exist — use await Bun.sleep(ms) or better tab.waitForSelector/waitForText.
  • tab.run(fnOrString) executes in the isolated Node-side runtime: document is undefined there. For page-world expressions use tab.evaluate("...string...") (expression, no top-level return; wrap a function IIFE when you need one) or the direct helpers (tab.text(sel), tab.count, tab.attr).
  • log() output from JS eval cells is silently swallowed — even after successful browser calls. Extract data by return-ing the value from the cell (Python cells log fine; JS cells must return). A cell that "ran but printed nothing" usually means it printed via log() — re-run returning the payload.
  • Screenshots come back as webp images in the tool result AND save via screenshot({path}); image text under ~13px is unreliable to read — verify exact strings via tab.text() instead of squinting.

Static anchor/claim audit before rendering

  • Counts, schema/table names, endpoint bodies: re-grep the SOURCE per claim; never trust numbers carried in from conversation memory (this caught "public vs franksign schema", "OR signer_user_id join that doesn't exist", wrong test-counts pre-commit).
  • git diff --stat regenerated binary fixtures (PDF CreationDate churn) before committing docs — don't commit fixture noise the setup script wrote.