istqb-design — technique selection, justified
Follow the shared contract in ../README.md. Prerequisite: 02-understanding.md (else offer
need-understanding).
Every rule below states its own reason; you never need project history to apply this skill. To
find out which decision or measured failure introduced a given rule — to challenge it, or to
change it — see references/decision-trail.md.
Scope: black-box only, by design. No structure-based / white-box technique (statement,
branch, decision, MC-DC coverage) is in this palette or planned. QAIA proposes from the spec —
the acceptance criteria — never from the target application's implementation, which it never
reads; a structure-based technique would by construction require access to the target code, which
the architecture excludes. Exploratory / session-based testing is the symmetric exclusion.
Both are deliberate exclusions, not oversights — say so when a reader asks for them, rather than
treating them as gaps to fill.
Technique palette — Foundation + Test Analyst + CT-AI
Grouped by the official CTAL-TA v4.0 chapter 3 classification. Application notes for the four
techniques that are routinely applied wrongly, the classification's provenance, and the list of
what was considered and excluded: references/technique-notes.md.
Foundation Level (CTFL) — prerequisite, outside CTAL-TA v4.0's own ch.3 taxonomy
| Technique |
Fits when the AC involves |
| Equivalence partitioning |
input/state classes treated the same way |
| Boundary value analysis |
thresholds, limits, sizes, dates — test the exact wording, inclusive vs exclusive, using the answers recorded in step 02 |
Data-Based (§3.1)
| Technique |
Fits when the AC involves |
| Domain Testing (§3.1.1) |
several related variables each carrying their own boundaries, needing combined coverage — not plain BVA per variable |
| Combinatorial Testing (§3.1.2, incl. pairwise) |
many independent parameters where full combination explodes |
Behavior-Based (§3.2)
| Technique |
Fits when the AC involves |
| State Transition Testing (§3.2.2) |
lifecycle rules — statuses, allowed/forbidden transitions, events. Build the state × event table first |
| Scenario-Based Testing (§3.2.3) |
end-to-end user goals crossing several rules — at most one per US, tagged @smoke |
| CRUD Testing (§3.2.1) |
full entity lifecycle, create/read/update/delete + inverses |
Rule-Based (§3.3)
| Technique |
Fits when the AC involves |
| Decision Table Testing (§3.3.1) |
combinations of conditions → actions (roles × flags × states) |
| Metamorphic Testing (§3.3.2) |
the exact expected output cannot be stated — it depends on an unsourced parameter — but a relation between two inputs/outputs is known and checkable. Use it instead of asserting a fabricated precise value |
Experience-Based (§3.4)
| Technique |
Fits when the AC involves |
| Error guessing / checklist |
error handling, empty states, concurrency — anchored on the ambiguity log |
CT-AI (separate syllabus — never conflated with CTAL-TA)
| Technique |
Fits when the AC involves |
| AI/ML feature under test (CT-AI v2.0) |
a feature in the target application backed by an AI/ML/GenAI model. Never QAIA testing itself |
Steps
Map AC → techniques. For each AC from 01-extraction.md, select the applicable
technique(s) and write a one-sentence justification tied to the AC's shape — "AC2 sets a time
threshold → boundary value analysis on the 2h limit, inclusive per the answer recorded in
step 02".
Derive the test conditions. Per AC × technique, list the concrete conditions to cover:
partitions with representative values, boundaries (value, value±1), decision-table columns,
transition pairs (valid and at least one invalid). This list is the input contract of
testbook-generate — conditions, not scenarios yet.
2b. Assign each condition its test level, and justify it (ADR 0008).
Exactly one of e2e or api per condition, on the same criterion ADR 0004 already
uses for the scope boundary — the interface through which the promise is observable:
| Level |
The promise is observable… |
Typical source |
api |
in HTTP, without a browser — status, body, header, effect on a resource |
a clause of an OpenAPI/Swagger contract, a documented endpoint behavior |
e2e |
only through the user interface — a journey, a rendering, a visible screen state |
an AC phrased in terms of what the user sees or does |
Write it as [level: api] next to the condition in 03-design.md, with the one-sentence
justification. A condition that seems to need both is two conditions — split it here, where
it is cheap, rather than leaving testbook-generate to emit a scenario that cannot carry one
level tag.
This decision belongs here and nowhere else. Until 2026-08-11 it was made by automate, at the
far end of the chain, from the wording of the generated steps — so the test book could not say
what it covered per level, and the ADR 0001 gate below could count a contract refusal as covered
by a UI scenario that never touched the contract.
Negative pressure — the refusal-path coverage gate. For every rule that can refuse, error
or deny, mark the corresponding condition as a required-negative ([req-neg] in
03-design.md). These are what the coverage gate enforces downstream: not a percentage, a
checklist — every refusal, error and denial path must end up with a scenario at that
condition's own level (step 2b): a [req-neg] marked [level: api] is discharged by an
@api scenario, never by a UI scenario showing an error message. Rationale:
https://github.com/QAIA-Project/QAIA/blob/main/docs/adr/0001-negative-coverage-gate.md.
3b. Standardized domains → oracle (optional). If an AC touches a standardized domain
(card/Luhn, dates/ISO 8601, HTTP status, email/RFC 5322, currency/ISO 4217, IBAN…), invoke
oracle-generate to add grounded edge-case conditions with their correct expected results
rather than guessing them. Oracle conditions are tagged @oracle:<standard> and cited — they
strengthen negative-path coverage without fabrication.
3c. Systematic coverage expansion (recall — do not skip). Ten reflex patterns a mature
tester applies beyond the literal ACs: list views, full CRUD lifecycle, sibling collections,
conditional behavior, authorization and server-side enforcement, protocol surface, rendering
surface, account recovery, enumerating every list rather than the first, and the
interaction surface — double-submit, mid-flow navigation, two actors on one record,
unexpected text content, a dependency removed mid-session. The tenth pattern exists because a
competitor's design agent, run on the same story and judged blind, produced three classes none
of the other nine named — the measurement is cited in the reference.
Full patterns, their measured failures, and the ceiling that forbids hallucinating to chase
recall: references/coverage-expansion.md.
3d. Knowledge-driven conditions — the RAG in use. This is what breaks 3c's honest-recall
ceiling. Route through knowledge/index.md, decompose composite rules into their sub-clauses
before deriving, and emit one cited condition per sub-clause. Protocol and the measured
failure it closes: references/knowledge-conditions.md.
- ⚠ VALIDATION: present the AC → technique map with its justifications; the user amends or
approves.
- Checkpoint. Write
03-design.md: the approved map plus the derived conditions, each
numbered (AC2-C3), with the applied BR-KB-nnn rule IDs listed. Each of sub-steps 3b, 3c
and 3d must appear in the checkpoint with its outcome — applied, with what it derived, or
explicitly waived ("pattern X of 3c not triggered by this US: reason"). Never silently absent.
Update journey.md. Next step: prioritize.
Guardrails
Every technique choice cites its justification. An unjustified technique is a rubric defect
(dim. 4).
Prose in a description or a summary is a hint for a human reader, never an assertion. A
specification that is silent on a rule is easy to handle — the gap becomes # open: Qn. The
hard case is a specification that is chatty in the wrong field: the rule is written down, in
English, somewhere no machine reads it. Deriving a condition from it produces a test that looks
contract-grounded and is not.
Measured on the RealWorld API (12 paths, 19 operations): applying this rule surfaced that the
Authorization header's value format exists only in a description, which blocks 22 P1
conditions from being executable at all — a finding that reordered the whole priority list.
Without the rule, the design asserts Token <jwt> and asserts PUT /user {} → 422, and both are
fabrications dressed as derivations.
The same applies to default: — it documents what a client library sends, not what the server
does when the field is absent.
A sub-step of 3c with no mention at all in 03-design.md is a defect, not a non-event. A
sub-step that genuinely does not apply costs one line to record as such; silence is
indistinguishable from having forgotten it, and a reviewer cannot tell the two apart after the
fact. The pattern a US triggers most directly is the easiest one to skip, precisely because it
feels obvious — recording the others as not-applicable while leaving no trace of that one
produces a design that looks more complete than it is.
Conditions built on [open] ambiguities inherit an [open] flag — they surface in the
confidence report rather than silently asserting behavior.
1---2name: istqb-design3description: Choose and justify ISTQB test design techniques (Foundation + CTAL-TA v4.0 + CT-AI) per acceptance criterion of an understood user story - equivalence partitioning, boundary values, decision tables, state transitions, scenario-based testing, combinatorial testing, domain testing, metamorphic testing, CRUD, AI/ML-feature testing. Use when deciding which test technique fits a requirement, when asked to justify test coverage methodologically, or when a test set looks like it was written by intuition and needs a defensible technique behind each case. Fourth step of the QAIA journey.4---56# istqb-design — technique selection, justified78Follow the shared contract in `../README.md`. Prerequisite: `02-understanding.md` (else offer9`need-understanding`).1011Every rule below states its own reason; you never need project history to apply this skill. To12find out *which* decision or measured failure introduced a given rule — to challenge it, or to13change it — see `references/decision-trail.md`.1415**Scope: black-box only, by design.** No structure-based / white-box technique (statement,16branch, decision, MC-DC coverage) is in this palette or planned. QAIA proposes from the spec —17the acceptance criteria — never from the target application's implementation, which it never18reads; a structure-based technique would by construction require access to the target code, which19the architecture excludes. **Exploratory / session-based testing is the symmetric exclusion.**20Both are deliberate exclusions, not oversights — say so when a reader asks for them, rather than21treating them as gaps to fill.2223## Technique palette — Foundation + Test Analyst + CT-AI2425Grouped by the official **CTAL-TA v4.0 chapter 3** classification. Application notes for the four26techniques that are routinely applied wrongly, the classification's provenance, and the list of27what was considered and excluded: `references/technique-notes.md`.2829### Foundation Level (CTFL) — prerequisite, outside CTAL-TA v4.0's own ch.3 taxonomy3031| Technique | Fits when the AC involves |32|---|---|33| Equivalence partitioning | input/state classes treated the same way |34| Boundary value analysis | thresholds, limits, sizes, dates — test the exact wording, inclusive vs exclusive, using the answers recorded in step 02 |3536### Data-Based (§3.1)3738| Technique | Fits when the AC involves |39|---|---|40| Domain Testing (§3.1.1) | several **related** variables each carrying their own boundaries, needing *combined* coverage — not plain BVA per variable |41| Combinatorial Testing (§3.1.2, incl. pairwise) | many independent parameters where full combination explodes |4243### Behavior-Based (§3.2)4445| Technique | Fits when the AC involves |46|---|---|47| State Transition Testing (§3.2.2) | lifecycle rules — statuses, allowed/forbidden transitions, events. **Build the state × event table first** |48| Scenario-Based Testing (§3.2.3) | end-to-end user goals crossing several rules — **at most one per US**, tagged `@smoke` |49| CRUD Testing (§3.2.1) | full entity lifecycle, create/read/update/delete + inverses |5051### Rule-Based (§3.3)5253| Technique | Fits when the AC involves |54|---|---|55| Decision Table Testing (§3.3.1) | combinations of conditions → actions (roles × flags × states) |56| Metamorphic Testing (§3.3.2) | the exact expected output **cannot be stated** — it depends on an unsourced parameter — but a **relation** between two inputs/outputs is known and checkable. Use it **instead of** asserting a fabricated precise value |5758### Experience-Based (§3.4)5960| Technique | Fits when the AC involves |61|---|---|62| Error guessing / checklist | error handling, empty states, concurrency — anchored on the ambiguity log |6364### CT-AI (separate syllabus — never conflated with CTAL-TA)6566| Technique | Fits when the AC involves |67|---|---|68| AI/ML feature under test (CT-AI v2.0) | a feature **in the target application** backed by an AI/ML/GenAI model. Never QAIA testing itself |6970## Steps71721. **Map AC → techniques.** For each AC from `01-extraction.md`, select the applicable73 technique(s) and write a one-sentence justification tied to the AC's shape — "AC2 sets a time74 threshold → boundary value analysis on the 2h limit, inclusive per the answer recorded in75 step 02".762. **Derive the test conditions.** Per AC × technique, list the concrete conditions to cover:77 partitions with representative values, boundaries (value, value±1), decision-table columns,78 transition pairs (valid **and** at least one invalid). This list is the input contract of79 `testbook-generate` — conditions, not scenarios yet.802b. **Assign each condition its test level, and justify it** ([ADR 0008](https://github.com/QAIA-Project/QAIA/blob/main/docs/adr/0008-test-level-is-a-design-property.md)).81 Exactly one of `e2e` or `api` per condition, on the same criterion [ADR 0004](https://github.com/QAIA-Project/QAIA/blob/main/docs/adr/0004-test-level-boundary.md) already82 uses for the scope boundary — **the interface through which the promise is observable**:8384 | Level | The promise is observable… | Typical source |85 |---|---|---|86 | `api` | in HTTP, without a browser — status, body, header, effect on a resource | a clause of an OpenAPI/Swagger contract, a documented endpoint behavior |87 | `e2e` | only through the user interface — a journey, a rendering, a visible screen state | an AC phrased in terms of what the user sees or does |8889 Write it as `[level: api]` next to the condition in `03-design.md`, with the one-sentence90 justification. **A condition that seems to need both is two conditions** — split it here, where91 it is cheap, rather than leaving `testbook-generate` to emit a scenario that cannot carry one92 level tag.9394 This decision belongs here and nowhere else. Until 2026-08-11 it was made by `automate`, at the95 far end of the chain, from the wording of the generated steps — so the test book could not say96 what it covered per level, and the ADR 0001 gate below could count a contract refusal as covered97 by a UI scenario that never touched the contract.98993. **Negative pressure — the refusal-path coverage gate.** For every rule that can refuse, error100 or deny, mark the corresponding condition as a **required-negative** (`[req-neg]` in101 `03-design.md`). These are what the coverage gate enforces downstream: **not a percentage, a102 checklist** — every refusal, error and denial path must end up with a scenario **at that103 condition's own level** (step 2b): a `[req-neg]` marked `[level: api]` is discharged by an104 `@api` scenario, never by a UI scenario showing an error message. Rationale:105 `https://github.com/QAIA-Project/QAIA/blob/main/docs/adr/0001-negative-coverage-gate.md`.1061073b. **Standardized domains → oracle (optional).** If an AC touches a standardized domain108 (card/Luhn, dates/ISO 8601, HTTP status, email/RFC 5322, currency/ISO 4217, IBAN…), invoke109 `oracle-generate` to add grounded edge-case conditions with their correct expected results110 rather than guessing them. Oracle conditions are tagged `@oracle:<standard>` and cited — they111 strengthen negative-path coverage without fabrication.1121133c. **Systematic coverage expansion (recall — do not skip).** Ten reflex patterns a mature114 tester applies beyond the literal ACs: list views, full CRUD lifecycle, sibling collections,115 conditional behavior, authorization and server-side enforcement, protocol surface, rendering116 surface, account recovery, enumerating *every* list rather than the first, and the117 **interaction surface** — double-submit, mid-flow navigation, two actors on one record,118 unexpected text content, a dependency removed mid-session. The tenth pattern exists because a119 competitor's design agent, run on the same story and judged blind, produced three classes none120 of the other nine named — the measurement is cited in the reference.121 Full patterns, their measured failures, and the **ceiling that forbids hallucinating to chase122 recall**: `references/coverage-expansion.md`.1231243d. **Knowledge-driven conditions — the RAG in use.** This is what breaks 3c's honest-recall125 ceiling. Route through `knowledge/index.md`, **decompose composite rules into their sub-clauses126 before deriving**, and emit one cited condition per sub-clause. Protocol and the measured127 failure it closes: `references/knowledge-conditions.md`.1281294. ⚠ VALIDATION: present the AC → technique map with its justifications; the user amends or130 approves.1315. **Checkpoint.** Write `03-design.md`: the approved map plus the derived conditions, each132 numbered (`AC2-C3`), with the applied `BR-KB-nnn` rule IDs listed. **Each of sub-steps 3b, 3c133 and 3d must appear in the checkpoint with its outcome** — applied, with what it derived, or134 explicitly waived ("pattern X of 3c not triggered by this US: reason"). Never silently absent.135 Update `journey.md`. Next step: `prioritize`.136137## Guardrails138139- **Every technique choice cites its justification.** An unjustified technique is a rubric defect140 (dim. 4).141- **Prose in a `description` or a `summary` is a hint for a human reader, never an assertion.** A142 specification that is *silent* on a rule is easy to handle — the gap becomes `# open: Qn`. The143 hard case is a specification that is **chatty in the wrong field**: the rule is written down, in144 English, somewhere no machine reads it. Deriving a condition from it produces a test that looks145 contract-grounded and is not.146147 Measured on the RealWorld API (12 paths, 19 operations): applying this rule surfaced that the148 `Authorization` header's *value format* exists only in a `description`, which blocks **22 P1149 conditions** from being executable at all — a finding that reordered the whole priority list.150 Without the rule, the design asserts `Token <jwt>` and asserts `PUT /user {}` → 422, and both are151 fabrications dressed as derivations.152153 The same applies to `default:` — it documents what a client library sends, not what the server154 does when the field is absent.155- **A sub-step of 3c with no mention at all in `03-design.md` is a defect, not a non-event.** A156 sub-step that genuinely does not apply costs one line to record as such; silence is157 indistinguishable from having forgotten it, and a reviewer cannot tell the two apart after the158 fact. The pattern a US triggers most directly is the easiest one to skip, precisely because it159 feels obvious — recording the others as not-applicable while leaving no trace of that one160 produces a design that looks more complete than it is.161- **Conditions built on `[open]` ambiguities inherit an `[open]` flag** — they surface in the162 confidence report rather than silently asserting behavior.