Skip to content
Back to skills

Qa

ASecurity

This skill should be used when the user wants quality assurance on the product itself — "QA the product", "QA the checkout flow", "run a QA pass", "build comprehensive e2e tests", "write regression tests", "test the running app", "what-if testing", or any request to empirically test the product and author end-to-end regression coverage. Seeds the guild's independent QA discipline: a qa-strategist maps the risk surface onto the board as coverage rows, then qa-testers run the app and author Pla...

  • 5 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 2, 2026
testingpythonrustgobashsqlnodetestingdatabase

Works with

  • cursor
  • cli

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add HirogaKatageri/hirokata --skill qa --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Qa?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Qa
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hirogakatageri-hirokata/badge)](https://www.skillsdirectory.com/skills/hirogakatageri-hirokata)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: qa
description: >
  This skill should be used when the user wants quality assurance on the product
  itself — "QA the product", "QA the checkout flow", "run a QA pass", "build
  comprehensive e2e tests", "write regression tests", "test the running app",
  "what-if testing", or any request to empirically test the product and author
  end-to-end regression coverage. Seeds the guild's independent QA discipline:
  a qa-strategist maps the risk surface onto the board as coverage rows, then
  qa-testers run the app and author Playwright specs while filing defects as bug rows.
version: 5.0.0
user-invocable: true
allowed-tools: Bash(tursodb *)
arguments:
  - name: scope
    description: "What to QA — 'product' for a full pass, or a named area/flow (e.g. 'checkout')"
    required: false
  - name: mode
    description: "'full' (default — plan + author) or 'cadence' (regression + focused exploratory pass)"
    required: false
---

# QA — independent quality discipline

Seed a QA pass onto the guild board. QA is a **discipline that produces work**, not a step in
the feature chain: the qa-strategist plans risk-based coverage, the qa-tester runs the actual
product and authors end-to-end regression specs, and any defect is filed back as a developer fix
task paired with a re-verify qa-tester task that empirically confirms the fix.

**QA's two durable outputs are board rows.** The qa-strategist writes the risk map as `coverage`
rows; the tester files defects as `bug` rows and stamps the areas it drove. That is what puts
QA's work in `v_brief`, in the dashboard's Bugs and Coverage views, and in reach of a cadence.
`.guild/qa/` still holds the charter, the missions, the session logs and the regression
manifest — the thinking, not the records.

Three skills carry the detail; load what you need:
- `guild:warehouse` — how to write SQL against the board at all. **Load it first.**
- `guild:qa-mindset` — the discipline (pillars, what-if catalog, hybrid oracle)
- `guild:qa-artifacts` — which output is a row, which is prose, and the exact SQL for each

## Step 1 — is there a guild

```bash
export PATH="$HOME/.turso:$PATH"
DB=.guild/guild.db
[ -f .guild/config.yaml ] || echo "no guild here"
q() { printf '%s\n' "$1" | tursodb -q -m list "$DB"; }
```

`-m list`, always — the default `pretty` mode truncates long values with an ellipsis, and a
clipped requirement body is a QA pass planned against the wrong oracle.

Not found:
```
No guild found. Run /guild:check-in to initialize first.
```
Stop here.

## Step 2 — ensure the QA workspace

```bash
mkdir -p .guild/qa/missions .guild/qa/sessions
```

## Step 3 — scope and mode

- **scope** — `product` (a full pass) or a named area/flow. If absent, ask:
  `What should QA cover? ("product" for a full pass, or a flow like "checkout")`
- **mode** — `full` (default) or `cadence`.

## Step 4 — the standing QA umbrella requirement

QA tasks anchor to a requirement, and there is **one** evergreen umbrella reused across every
pass. Look for it before creating it:

```sql
SELECT id, status FROM requirement WHERE title = 'Product QA & E2E Regression';
```

If it exists, use that id and skip to Step 5. If not, create it — and **write the whole document
in the one INSERT**. The body crosses as hex, because it contains `#`, `|` and lines that could
end in `;`. Full document text: `references/umbrella-body.md`.

```bash
hex=$(xxd -p < /tmp/qa-umbrella.md | tr -d '\n')       # never echo; never round-trip via $( )
```

```sql
PRAGMA foreign_keys = ON;
UPDATE guild_state SET value = 'orchestrator' WHERE key = 'actor';

INSERT INTO requirement (id, project_id, title, body, status, priority, created_at, updated_at)
SELECT 'REQ-' || printf('%03d', COALESCE(MAX(CAST(substr(id, instr(id,'-')+1) AS INTEGER)), 0) + 1),
       NULL, 'Product QA & E2E Regression', CAST(x'<hex-body>' AS TEXT), 'in-progress', 3,
       strftime('%Y-%m-%dT%H:%M:%SZ','now'), strftime('%Y-%m-%dT%H:%M:%SZ','now')
  FROM requirement
RETURNING id, status;
```

It opens `in-progress` and **stays there forever** — it is standing work, not a feature, and it
is deliberately never included in a release. `project_id` is NULL: QA is not part of any one project.

## Step 5 — seed the qa-strategist ticket

One ticket, whole body in the one INSERT — there is no ticket file to edit afterwards, and
anything you leave out stays out.

```sql
INSERT INTO task (id, requirement_id, title, objective, body, status, priority, agent,
                  created_at, updated_at)
SELECT 'TASK-' || printf('%03d', (SELECT COALESCE(MAX(CAST(substr(id, instr(id,'-')+1) AS INTEGER)),0)+1 FROM task)),
       r.id, CAST(x'<hex-title>' AS TEXT), CAST(x'<hex-objective>' AS TEXT),
       CAST(x'<hex-body>' AS TEXT), 'todo', 2, NULL,
       strftime('%Y-%m-%dT%H:%M:%SZ','now'), strftime('%Y-%m-%dT%H:%M:%SZ','now')
  FROM requirement r WHERE r.id = 'REQ-004'
RETURNING id, status;
```

The `FROM requirement r WHERE r.id = …` **is** the referential check: a bad requirement id
returns zero rows and writes nothing, which matters because a failing statement does not stop
the script.

Declare the capability rather than pinning the agent — that is what lets the dispatcher match
and what makes a roster gap visible if the qa-strategist is ever missing:

```sql
INSERT INTO task_capability (task_id, capability, required)
SELECT t.id, 'qa-planning', 1 FROM task t WHERE t.id = 'TASK-042'
ON CONFLICT DO NOTHING;
```

Ticket body:

```markdown
## Objective

Plan a {mode} QA pass for: {scope}. Map the risk surface onto the board as `coverage` rows,
write the charter, then create the qa-tester mission tickets.

## Context

- Requirement: {REQ id}
- Mode: {full | cadence}
- Scope: {product | named area}
- Existing risk surface: `SELECT id, area, risk, spec_path FROM coverage ORDER BY id`
  (upsert into it — never fork a new id for an area that already has one)
- Charter: .guild/qa/charter.md (create or update in place)

## Acceptance Criteria

- [ ] Oracle sources resolved (specs / board / code+app / user)
- [ ] One `coverage` row per quality area, with risk, spec path and reasoning
- [ ] Charter written with the quality definition and the oracle ledger
- [ ] qa-tester mission tickets created, prioritized by what `v_coverage_due` returns
```

Then check the words you used are real, because an unknown capability inserts fine and matches
nobody, silently. **The check is not SQL** — the vocabulary is the agent files:

```bash
python3 "${CLAUDE_PLUGIN_ROOT}/skills/check-in/scripts/roster.py" --covers qa-planning
```

At least one row back is the answer you want. No output means the ticket will go `blocked` at
the first dispatch that reaches it.

## Step 6 — confirm and offer to run

```
QA pass seeded.

  Requirement: REQ-NNN — Product QA & E2E Regression
  Task: TASK-NNN — QA strategy: {scope} (qa-planning)
  Mode: {full | cadence}

The qa-strategist will map risk and declare tester missions; testers then run the app,
author e2e specs, and file any bugs as developer fix tasks.

Run /guild:check-in to execute now, or I can start the work cycle for you.
```

If they want to proceed immediately, hand off to `guild:check-in`'s work cycle — QA tickets
dispatch like any other.

## How QA flows through the orchestrator

QA reuses all existing orchestration; nothing is special-cased.

1. `qa-strategist` runs → declares `qa-tester` missions as follow-up tickets.
2. The orchestrator dispatches `qa-tester` tickets **sequentially — one at a time, never in
   parallel.** Each tester drives its own dev server and Playwright instance, so concurrent
   testers collide on the same port. The schema says this too: `agent.serial = 1` on qa-tester.
   Honor it — nothing enforces it.
3. Each tester runs the app, authors specs, files each defect as a `bug` row, stamps the areas
   it genuinely drove (`coverage.last_inspected_at`), and for every bug declares a **pair** of
   follow-ups: a `developer` fix ticket, then a re-verify `qa-tester` ticket. Declared in that
   order, so the second gets the higher id and the cursor runs fix, then re-verify. Wire the
   order explicitly rather than trusting id order:

   ```sql
   INSERT INTO task_dependency (task_id, depends_on)
   SELECT 'TASK-051', 'TASK-050'
    WHERE EXISTS (SELECT 1 FROM task WHERE id = 'TASK-051')
      AND EXISTS (SELECT 1 FROM task WHERE id = 'TASK-050')
   RETURNING task_id || ' after ' || depends_on;
   ```
4. The re-verify qa-tester **is** the verification tail for QA fixes: it empirically confirms the
   fix, promotes the spec from `fixme` to passing, and closes the bug:

   ```sql
   UPDATE bug SET status = 'fixed' WHERE id = 'BUG-014' AND status IN ('open','fixing')
   RETURNING id, status;
   ```

   QA fixes get no test-writer or reviewer tickets — a reviewer on the standing umbrella would
   be gated behind every other pending QA ticket, forever.

After a pass, everything QA produced is one query away:

```sql
SELECT id, severity, status, found_by, requirement_id, fix_task_id, title FROM v_open_bugs;
SELECT id, risk, interval_days, days_since, spec_path, area FROM v_coverage_due;
SELECT fact, value FROM v_brief;
```

## Standing cadence — opt-in, per project

QA can run on a schedule so quality is checked continuously, via `/schedule`. **Opt-in per
project**; it does not auto-arm, and a shift never starts one. Full setup and what a `cadence`
pass does differently (skips full re-planning, asks `v_coverage_due` what's due, and ending
with nothing due is success, not failure): `references/cadence.md`.

## Verify against §10

Run `guild:validate qa` after seeding, and again after each cycle node closes. §10 of
`docs/expectations.md` covers the `maintenance` template: §10.a that a person triggered the
inspection, §10.c the **one tester board-wide** invariant, §10.d that only areas actually
exercised were stamped, §10.f that the graph is still six nodes, five edges and one gate.
**Run §10.c before every `qa-execute` dispatch** — nothing in the database will stop a second
Playwright run, and this is the only guard there is. Report every failure with its rows.

## Rules

- **Never overwrite** the charter or the regression manifest — update in place.
- **Defects are `bug` rows**, not markdown. There is no `.guild/qa/ledger.md`.
- **The risk map is `coverage` rows**, not a charter table. One id per area, upserted.
- **IDs are derived in the INSERT** — `MAX(n) + 1` in the same statement, never a counter you
  keep, never a read-then-write.
- **Status is a column.** Move it with a guarded `UPDATE … WHERE status = <expected>
  RETURNING`; zero rows back means somebody already moved it, which is information.
- **Committed specs live in the repo's e2e dir**, never under `.guild/`.
- **Only stamp `last_inspected_at` for an area actually exercised.** The stamp is a claim, and a
  trigger fires on that column alone so re-saving risk or notes must not make a stale area read
  as fresh.
- **Don't bake in bugs** — suspect behavior is filed or asked, never asserted as correct (the
  hybrid oracle rule).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…