The skill scans a bot with subagents (never runs it) and writes HANDOVER.md, an 11-section ops guide in the operator's order: where is what, how to run, how long to wait, after the run, how to see an exception, exception list, how you will know, how to tell us, don'ts, issues seen before. Dev material (check against 12 failure classes from Tebra Auto Post, gaps with file:line, incidents) goes to HANDOVER-DEV.md. Also adds ADR-0004, glossary terms, five fixture bots and a handoff eval runner (--resume, --regrade) with results from 47 runs of the earlier 13-section version. The grader still expects that structure and must be updated before the next eval run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tests
Run everything from the repo root:
uv run --with pytest --with playwright pytest tests
-
test_*.py: assert-based self-checks for template logic (lint of unfilled Python templates, the custom palette, presets in step with the template). -
page_check/: Seam 1. Loads a dashboard page in headless Chromium with no backend, pushes contract envelopes throughwindow.__pyMsg, and asserts on what is visible. Every case runs in light, dark and narrow (800px) mode.- By default it checks the no-AI template, filled with test values. To check a
generated page instead, set
PAGE_CHECK_HTML=path/to/dashboard.html. - The page sees a fake Qt bridge. Every action the page sends is recorded in
window.__callsas[slot, ...args]. PAGE_CHECK_WIRED=1: the page is wired to a bot (sample data off). Sample-data cases skip, and a case checks that the page's actions go to the bot. With noPAGE_CHECK_HTML, the template is checked withSAMPLE_DATAswitched off.PAGE_CHECK_REPLAY=run.jsonl: replay a real bot run (the JSON lines thatpython dashboard/bot_runner.pyprints) instead of the built-in run.- To add a case, write a
test_*.pyfile inpage_check/that uses thepageandpush(event, data)fixtures fromconftest.py. - Optional-section cases (
test_optional_sections.py) skip on a generated page built without that section. The template must carry all of them. A page with the login section is signed in (login_result ok) before each case.
- By default it checks the no-AI template, filled with test values. To check a
generated page instead, set
-
test_sections.py: the optional-section strip tool keeps only the chosen sections, and a page with none of them still passes the page check. -
page_check_ai/: Seam 1, AI web page. Builds the React starter with npm (filled with test values, in a temp folder that keepsnode_modules), serves it with its ownserver_stub.py, and checks bands, band filters, drafts, the approve gate "page X of Y" and the cost page (spend tiles, coverage pill, month breakdown, by-hand assumptions), plus every no-AI case. Tests set run and review state on the stub directly (thestubfixture). To check a generated dashboard folder instead, setPAGE_CHECK_AI_DIR=path/to/dashboard. Needs npm on PATH, else it skips. -
page_check_ai_desktop/: Seam 1, AI desktop page. The no-AIdashboard.htmlwithai_sections.htmlpasted in, loaded fromfile://with a fake Qt bridge whoseai_requestslot goes toserver_stub.dispatch()in this process (whatai_bridge.pydoes). Runs the AI web page's review and cost cases and the no-AI cases unchanged, plus a tampered page calling the slot directly (still refused). To check a generated folder, setPAGE_CHECK_AI_DESKTOP_DIR=path/to/dashboard;PAGE_CHECK_WIRED=1as above.test_ai_fetch.pyruns the review cases on the same page with no Qt bridge (a plain-HTML web project): the AI sections fetch/api/..., routed toserver_stub.dispatch(). -
page_check_common.py: what the three page checks share (modes, test fill, fake Qt bridge, stub loader, page opener, the list of no-AI cases the AI pages rerun). -
test_pricing.py: the AI cost function (normal, long-context, thinking tokens, unknown model). -
test_reference_scan.py: no patient data, internal IPs, credentials or keys in any bundled file, and every Superbill extract carries anEXAMPLE ONLYbanner. -
evals/: Seam 2. Runs the skills on a fixture project withclaude -p, then grades the reply and runs the page check on the page it built:uv run --with pytest --with playwright python tests/evals/run_eval.py a-emptyResults go to
evals/results/<fixture>.json. To add a fixture, add an entry toFIXTURESinrun_eval.py. An entry with a"fixture"key reuses another fixture folder with different answers:c-keepandc-restyleboth run onc-web-existing-frontend, and also check what changed in the files it already had. An"ai": Trueentry (d-ai-extraction) expects the AI skill's React starter and runspage_check_ai/on the folder it built. An"ai_desktop": Trueentry (e-pyqt-ai) expects the desktop AI page and runspage_check/(with the bot replay) andpage_check_ai_desktop/on it. For a bot fixture (b-pyqt-bot), the eval also dry-runs the generatedbot_runner.py, saves its events toevals/results/<fixture>.run.jsonl, and replays them in the page check. -
fixtures/<letter>-<name>/: small test projects for the evals. -
page_check_run_tab/+test_run_tab.py: Run tab skill. The page filled with a test config and driven throughwindow.__pyMsg: Trigger states, sheet preview with masked passwords, checkpoints driving steps/boxes/progress, green/amber/red endings, the no-input mode, the dark toggle and no horizontal scroll, each in light, dark and narrow mode. The Python side covers line parsing, endings, the sample workbook andpalette.py --write. The end-to-end fake-bot check lives in the skill itself:python skills/rpa-run-tab/templates/run_tab.py --selfcheck.