Prove one task's acceptance criteria with observable end-to-end tests against the real product, record a test plan and a test-gap ledger, and capture screenshots for the pull request. Use for the QA stage, after work and before review, when FACTORY.json enables stages.qa.
77
97%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Prove that one task does what its acceptance criteria say, from the outside. You test the product; you do not change it.
The prompt lists the task's acceptance criteria as AC1..ACn, in the order the task file gives them. Those ids are the keys of everything you write. It also gives you the worker's summary, the files the worker changed, and the work checks that already passed.
Read the task file, the project's end-to-end setup (for example playwright.config.ts and one or two existing end-to-end tests), and .factory/CONTEXT.md when it exists. Read product code only where a test needs a selector, a route, or a fixture. The worker already built the change and review will read the diff: do not re-derive the implementation.
Before you write anything, put each criterion in one of two groups:
- AC8: covered by the work check test (pnpm test) or - AC3: covered by src/lib/server/read.test.ts. Do not build a harness to watch internals from the outside. For example, do not parse a framework's serialized page data out of the HTML.When a task has no observable criterion, the ledger can hold every one of them. That is a valid result, not a failure.
Write the test first, straight from the criterion and the project's harness, and let its failures tell you what to read. For each observable criterion:
AC2: the filter survives a reload, and put it next to the project's existing end-to-end tests.A failure that shows the product misses the criterion is a finding, not something to fix: see below.
pnpm exec playwright test <file> --timeout=15000 --max-failures=1, so a wrong locator fails in seconds instead of minutes.curl. If you must start a process yourself, record its pid (cmd & pid=$!) and kill that pid. Never use pkill -f with a pattern that also appears in your own command line. Prefer localhost to 127.0.0.1, because dev servers often listen on IPv6 only.screenshots/ under the QA directory, named after the criterion, such as screenshots/ac2-filter-after-reload.png. Take one screenshot per distinct screen, and do not capture the same page again for a second criterion.Run the QA commands the prompt lists once, at the end. If a test fails because the product does not meet the criterion, keep the test as it is: the controller runs the QA commands and returns the task to work with the failure. Do not weaken the assertion and do not change product code.
Do not mutate product code, docs, or skills to show that your tests catch a regression. Review judges the tests. Restoring files by hand is how product changes leak into the diff.
Decide and act. A QA round should be a short loop of write, run, fix, not a long design exercise.
Write both files in the QA directory the prompt names:
test-plan.md: a table with one row per tested criterion. A row can list several screenshots, separated by commas.
| AC | Test | Screenshot |
| --- | -------------------------------------------------------- | -------------------------- |
| AC1 | tests/e2e/filter.spec.ts › AC1: filter applies | screenshots/ac1-filter.png |
| AC2 | tests/e2e/filter.spec.ts › AC2: filter survives a reload | none |ledger.md: what the tests do not prove, one line each, keyed by criterion where one applies.
- AC3: Email delivery needs the real provider; checked by hand in staging.
- Mobile layouts are not covered.Every criterion must have a row in the test plan or a ledger line with a reason. A screenshot path must point at a file you captured. The controller checks both, then runs the commands in FACTORY.json stages.qa.commands in the worktree.
Leave the work uncommitted. Do not edit factory state, start another stage, commit, or push.
Return only the factory.qa.v1 template in references/output.md. No JSON object, no recap after it.
After the template, call subagent_done once and emit nothing else. If it replies that the session is shutting down, stop. Do not call it again, do not call caller_ping, and do not send more text. caller_ping is the only other terminal call, and it replaces the template when you need a decision. Do not edit the controller database.
geut/factory-skills
6f119c3
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.