QA Fail: $ARGUMENTS
Convert a human failure observation into the exact artifact the fixing agent needs. Two
inputs arrive together or the report cannot be filed: a target ticket and the
tester's verbatim description (what they did, what they expected, what happened,
plus any screenshots).
Phase 1 — Resolve the target ticket
- Tied report (invoked from
lisa-qa-queue with a key): use it.
- Untied report ("I found something broken: …"): run duplicate-discovery BEFORE any
write, reusing the mandatory relationship-discovery searches defined by the configured
tracker's write skill (dispatched through
lisa-tracker-write): search open and
recently-closed tickets in the affected area, and the current QA-queue set. If an existing ticket
covers it, that ticket is the target — update it, never file a twin. Only when the
search documents no match, create a new Bug via lisa-tracker-write (which enforces
the full quality gates) with explicit build_ready: true per the ready-role-filing
rule — omitted is NOT build-ready on any tracker, and a rework Bug nothing claims is
an incomplete handoff — and treat it as the target. Report which path was taken.
Phase 2 — Structured failure report
Fetch the bundle via lisa-tracker-read. Post one comment:
[lisa-qa-fail] QA failure — <one-line summary>
Reported by: <tester> on <date>, against <environment>
Steps to reproduce: <numbered, from the tester's words>
Expected: <what the ticket/AC promised, quoted or paraphrased faithfully>
Actual: <what the tester observed, verbatim where possible>
Failed acceptance criterion: <AC number/text from the ticket — or "not covered by any AC" (see gap)>
Attachments: <screenshots if provided>
Preserve the tester's language in Actual — their words are the evidence; your job is
structure, not rewording.
Phase 3 — Expectation-gap diagnosis
Answer explicitly: why did the implementing agent believe this was done? Locate the
prior cycle's done-evidence — the build-evidence comment (lisa-tracker-evidence output),
the merged PR's verification section, and any codified regression test — and compare it
against the failure. Classify the gap (exactly one):
| Gap |
Meaning |
ac-mismatch |
The evidence verified a different reading of the AC than QA's — the criterion is ambiguous or the ticket distorted it. |
verification-weakness |
The evidence never actually exercised the failing path (asserted adjacent behavior, mocked the surface, or skipped the step). |
environment-difference |
Verified where it works (e.g. dev) but fails on the QA environment — config, data, or deployment drift. |
data-difference |
Behavior depends on data present in one environment and absent in the other. |
regression-since-merge |
The evidence was genuinely valid when produced; later merges broke it. |
not-covered-by-ac |
QA's expectation is real but no AC promises it — a spec gap, not an implementation failure. |
Append to the same comment:
Expectation gap: <classification>
Why the agent thought it was done: <2-3 lines citing the specific evidence artifact>
If no done-evidence exists at all, say so — Expectation gap: no-evidence-found is
itself a serious finding (the verification lifecycle was skipped) and must be surfaced,
not smoothed over.
For not-covered-by-ac, do NOT transition the ticket — the spec question goes to the
human product gate. Flag it in the response and stop after posting.
Phase 4 — Signal and transition
Apply the QA-failure signal label. Resolve its name — never hardcode one:
SIGNAL=$(node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/qa-signal-lifecycle.mjs" \
--vendor "<jira|linear|github>" --print-label) # `qa.labels.fail`, default `qa-fail`
This is the deterministic rework signal lisa-rework-triage keys on at next claim, and
the gap classification above becomes its primary evidence.
The signal is transient, and it says so. Two void conditions lift it, both with an
executable predicate in scripts/qa-signal-lifecycle.mjs: a later QA pass verdict
(qa-pass-recorded), or the item reaching the certified or a terminal role
(certified-role-reached). lisa-qa-queue clears it on the pass path and lisa-qa-clear
clears it when it certifies without a human, so the clear path is as reachable as this
one. Record that in the comment so nobody has to infer it:
Signal: <label> — voided by a later QA pass, or by reaching the certified/terminal role.
What is durable is the history: this [lisa-qa-fail] comment is never rewritten or
removed, so "failed QA twice before shipping" stays readable after the label is gone.
The label is the machine-read signal; the comment is the record.
Transition the ticket to the build-ready status (jira.workflow.ready, or the
configured tracker's equivalent ready label/state when tracker is GitHub or
Linear). The rework loop takes it from here: intake claims it, lisa-ticket-triage Phase 2.5 runs
lisa-rework-triage, and the fix proceeds with full context.
Confirm to the tester in one plain sentence: what was recorded, and that the fix is
queued — no further action needed from them.
Rules
- Never file a new ticket without the documented duplicate search (Phase 1).
- Never paraphrase away the tester's observation; structure around it.
- One
[lisa-qa-fail] comment per failure event — if the same tester reports the same
failure again before a fix ships, add a short "seen again " line to the existing
comment instead of a new block.
- The expectation gap must cite a specific evidence artifact or say
no-evidence-found —
a gap classification without a citation is a guess, and guesses are worse than
no-evidence-found.
- Never apply a signal whose clear path you cannot name. A durable mark with no inverse is
a defect class of its own (
state-changes-without-inverses): it stays correct at the
moment it fires and becomes wrong by outliving what it described.
1---2name: lisa-qa-fail3description: QA failure front door. Takes a human tester's plain-language failure description, finds the right ticket (the served ticket, or the original via duplicate-discovery when the report arrives untied), writes the structured failure report (repro / expected vs. actual / which acceptance criterion failed), diagnoses the EXPECTATION GAP — why the implementing agent's done-evidence said done when QA says it isn't — applies the qa-fail label that makes lisa-rework-triage detection deterministic, and transitions the ticket back to the build-ready status. QA never words a ticket again; agents never guess what QA meant.4---56# QA Fail: $ARGUMENTS78Convert a human failure observation into the exact artifact the fixing agent needs. Two9inputs arrive together or the report cannot be filed: a **target ticket** and the10**tester's verbatim description** (what they did, what they expected, what happened,11plus any screenshots).1213## Phase 1 — Resolve the target ticket1415- **Tied report** (invoked from `lisa-qa-queue` with a key): use it.16- **Untied report** ("I found something broken: …"): run duplicate-discovery BEFORE any17 write, reusing the mandatory relationship-discovery searches defined by the configured18 tracker's write skill (dispatched through `lisa-tracker-write`): search open and19 recently-closed tickets in the affected area, and the current QA-queue set. If an existing ticket20 covers it, that ticket is the target — update it, never file a twin. Only when the21 search documents no match, create a new Bug via `lisa-tracker-write` (which enforces22 the full quality gates) with explicit `build_ready: true` per the `ready-role-filing`23 rule — omitted is NOT build-ready on any tracker, and a rework Bug nothing claims is24 an incomplete handoff — and treat it as the target. Report which path was taken.2526## Phase 2 — Structured failure report2728Fetch the bundle via `lisa-tracker-read`. Post one comment:2930```text31[lisa-qa-fail] QA failure — <one-line summary>32Reported by: <tester> on <date>, against <environment>33Steps to reproduce: <numbered, from the tester's words>34Expected: <what the ticket/AC promised, quoted or paraphrased faithfully>35Actual: <what the tester observed, verbatim where possible>36Failed acceptance criterion: <AC number/text from the ticket — or "not covered by any AC" (see gap)>37Attachments: <screenshots if provided>38```3940Preserve the tester's language in `Actual` — their words are the evidence; your job is41structure, not rewording.4243## Phase 3 — Expectation-gap diagnosis4445Answer explicitly: **why did the implementing agent believe this was done?** Locate the46prior cycle's done-evidence — the build-evidence comment (`lisa-tracker-evidence` output),47the merged PR's verification section, and any codified regression test — and compare it48against the failure. Classify the gap (exactly one):4950| Gap | Meaning |51|-----|---------|52| `ac-mismatch` | The evidence verified a different reading of the AC than QA's — the criterion is ambiguous or the ticket distorted it. |53| `verification-weakness` | The evidence never actually exercised the failing path (asserted adjacent behavior, mocked the surface, or skipped the step). |54| `environment-difference` | Verified where it works (e.g. dev) but fails on the QA environment — config, data, or deployment drift. |55| `data-difference` | Behavior depends on data present in one environment and absent in the other. |56| `regression-since-merge` | The evidence was genuinely valid when produced; later merges broke it. |57| `not-covered-by-ac` | QA's expectation is real but no AC promises it — a spec gap, not an implementation failure. |5859Append to the same comment:6061```text62Expectation gap: <classification>63Why the agent thought it was done: <2-3 lines citing the specific evidence artifact>64```6566If no done-evidence exists at all, say so — `Expectation gap: no-evidence-found` is67itself a serious finding (the verification lifecycle was skipped) and must be surfaced,68not smoothed over.6970For `not-covered-by-ac`, do NOT transition the ticket — the spec question goes to the71human product gate. Flag it in the response and stop after posting.7273## Phase 4 — Signal and transition74751. Apply the QA-failure **signal** label. Resolve its name — never hardcode one:7677 ```bash78 SIGNAL=$(node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/qa-signal-lifecycle.mjs" \79 --vendor "<jira|linear|github>" --print-label) # `qa.labels.fail`, default `qa-fail`80 ```8182 This is the deterministic rework signal `lisa-rework-triage` keys on at next claim, and83 the gap classification above becomes its primary evidence.8485 The signal is **transient, and it says so.** Two void conditions lift it, both with an86 executable predicate in `scripts/qa-signal-lifecycle.mjs`: a later QA pass verdict87 (`qa-pass-recorded`), or the item reaching the certified or a terminal role88 (`certified-role-reached`). `lisa-qa-queue` clears it on the pass path and `lisa-qa-clear`89 clears it when it certifies without a human, so the clear path is as reachable as this90 one. Record that in the comment so nobody has to infer it:9192 ```text93 Signal: <label> — voided by a later QA pass, or by reaching the certified/terminal role.94 ```9596 What is durable is the **history**: this `[lisa-qa-fail]` comment is never rewritten or97 removed, so "failed QA twice before shipping" stays readable after the label is gone.98 The label is the machine-read signal; the comment is the record.992. Transition the ticket to the build-ready status (`jira.workflow.ready`, or the100 configured tracker's equivalent ready label/state when `tracker` is GitHub or101 Linear). The rework loop takes it from here: intake claims it, `lisa-ticket-triage` Phase 2.5 runs102 `lisa-rework-triage`, and the fix proceeds with full context.1033. Confirm to the tester in one plain sentence: what was recorded, and that the fix is104 queued — no further action needed from them.105106## Rules107108- Never file a new ticket without the documented duplicate search (Phase 1).109- Never paraphrase away the tester's observation; structure around it.110- One `[lisa-qa-fail]` comment per failure event — if the same tester reports the same111 failure again before a fix ships, add a short "seen again <date>" line to the existing112 comment instead of a new block.113- The expectation gap must cite a specific evidence artifact or say `no-evidence-found` —114 a gap classification without a citation is a guess, and guesses are worse than115 `no-evidence-found`.116- Never apply a signal whose clear path you cannot name. A durable mark with no inverse is117 a defect class of its own (`state-changes-without-inverses`): it stays correct at the118 moment it fires and becomes wrong by outliving what it described.