# E2E Test Selection & Priority Strategy

**Version:** 3.0 | **Owner:** QA Leadership | **Framework:** ISTQB (Ch 5.2 risk-based + Ch 4.2 use-case) + TAS

**Purpose:** Canonical logic for selecting E2E test cases from Func-Test §4 and assigning E2E execution priority (P0/P1) — scored by **release-cycle relevance (E2E/SIT/Backward-Compat) + risk**, not by TC Type alone. Consumed by the `/tas-e2e` command and rendered by its `E2E-Test-Spec.md` template.

**E2E priority ≠ Func-Test priority.** Func-Test P0/P1/P2 = *automation capability* ("have tools?"). E2E P0/P1 = *release execution order* ("test this first, across E2E+SIT+UAT+Backward-Compat cycles"). Never copy Func-Test priorities into E2E.

**Inputs (all from Func-Test + TestChecklist only — no upstream reads):** Func-Test §4 (TC Type, Autoable) · TestChecklist §5 Risk Registry (TP → Risk Level, RC) · TestChecklist §1.1 (flow Main/Alt/Edge) · TestChecklist §1.5 (Shared Component Impact) · TestChecklist §5 backward-compat `RC-INT` row → `bc_apis[]` (Backward-Compat applicability — see C3 detection below).
**Related:** [test-design.md § Risk Scoring Formula](test-design.md#risk-scoring-formula) (risk source) · [test-id-convention.md](test-id-convention.md) (TC ID stable Func-Test → E2E) · [verification-layers.md §4](verification-layers.md) (scope-conflict / routing).

---

## Selection & Priority (canonical algorithm)

**Test-type gate (ISTQB Ch 4.2 use-case coverage — "đúng"):** E2E journey coverage is **HP + NEG only** — Happy Path proves the flow works, Negative proves it correctly rejects/handles failure. This is the minimal-but-sufficient pair for business-journey correctness; it is not a re-derivation of Func-Test's technique mix (DT/ST/BVA/EP stay Func-Test-owned and are never promoted into E2E scope). SEC/INT/PERF stay Tier-3 (never included — see Routing below).

For each Func-Test §4 TC of type **HP or NEG**, score 3 relevance criteria, combine with risk, then gate by Autoable. This is the **single** decision procedure — no other restatement exists.

### Step 1 — Relevance criteria (per TC)

| Criterion | Meaning | Detection (from digests only — no new reads) |
|---|---|---|
| **C1 — E2E journey-critical** | Sits on the core business-flow spine **and is the representative TC for that step** | TC Type ∈ {HP, NEG} **and** its TestChecklist §1.1 flow = **Main** (Alt/Edge score 0 on C1) **and** it passes the **journey-step representative gate** below |
| **C2 — SIT-relevant** | Crosses an integration boundary SIT must verify | Source TP's §5 `RC = RC-INT` **whose API is NOT in `bc_apis[]`** (a backward-compat contract is scored on C3, not C2 — prevents double-count), **or** §1.5 Shared-Component Impact lists the TP's component |
| **C3 — Backward-Compat-relevant** | Touches an existing contract this change modifies, that consumers depend on | **Only applicable when `bc_applicable=true`** (definition below). If net-new, C3 is **not applicable** — drop it from the denominator, do not score it 0. Per-TC: C3=true when the TC's source TP's component/API is **one of the APIs named in the §5 backward-compat row's Root Cause** (`bc_apis[]`) — *not* any generic `RC-INT` TP (a plain integration risk like a timeout is C2, not C3) |

**`bc_applicable` (Feature-level — set upstream by `/tas-TestChecklist`, read here):** `true` ⟺ TestChecklist **§5 has the backward-compat `RC-INT` row** (per [test-design.md § Backward-Compat Applicability Detection](test-design.md#backward-compat-applicability-detection) — that command only writes the row when *this change* modifies an existing contract). Its **Root Cause API list** (`bc_apis[]`) is the set of contracts E2E flags for regression in §2.3.1 and the sole per-TC C3 signal. No row ⟹ `false` (net-new — a feature merely *calling* an API is not backward-compat). Read from `risk_digest` — no extra read, no §1.2.1 inference, no Feature-Technical dependency.

**Applicable criteria count** = 3 if `bc_applicable=true`, else 2 (C1+C2 only, C3 n/a).

**Journey-step representative gate (VAL/BL dedup — prevents Func-Test-scale bloat into E2E):** E2E proves the *path* connects, not every rule Func-Test already isolated. Categories **VAL** and **BL** flood a single journey step with many per-field/per-rule TCs that all exercise the *same* step — C1 must not reward every one of them equally.

- Group Main-flow **HP** TCs of category VAL or BL by `(Flow ID, Category)` (Flow ID = TestChecklist §1.1 flow the TP maps to via its AC#).
- Within each group, exactly **one** TC — the lowest TC ID (stable, deterministic) — scores C1 on this basis; all other TCs in the same group score **C1=false from this rule**, regardless of flow=Main (they remain eligible for C2/C3, and for whatever P1 risk-only path Step 2 already provides).
- **This gate does not apply to:** GUI, EXC, SEC (already low-volume or separately routed), NEG of any category (NEG already proves the rejection path, one per rule is the point — do not dedup), or BL/VAL TCs on Alt/Edge flows (already excluded from C1 by the Main-flow requirement).
- **Rationale:** one HP pass through a journey step, with one valid representative input/rule, proves the step is reachable and wired end-to-end. Every other VAL/BL permutation on that same step is input/logic correctness — Func-Test's job, already proven in isolation — not a new journey fact.

### Step 2 — Priority (criteria + risk → P0/P1) then Autoable gate

| Match | Risk (TestChecklist §5) | E2E Priority | Then |
|---|---|---|---|
| Meets **ALL applicable criteria** | any | **P0** | Autoable=YES → §2.1. Autoable=NO → still P0, route to §2.2 Regression Watch (release-blocking manual case — flag `[MANUAL-BLOCKER]`) |
| Meets **1–2 of 3** (or 1 of 2 when C3 n/a) | ≥ MEDIUM | **P1** | Autoable=YES → §2.1. Autoable=NO → §2.2 Regression Watch |
| Meets **0 criteria** | ≥ MEDIUM (isolated risk, no journey/SIT/BC relevance) | **P1** | → §2.2 Regression Watch only (never §2.1 — §2.1 is reserved for criteria-matched rows; risk-only rows are a regression concern, not a journey step) |
| Meets **0 criteria** | < MEDIUM | **EXCLUDED** | No row in either section; count only |

**§2.1 vs §2.2 routing (unchanged principle, new trigger):** §2.1 = criteria-matched (C1/C2/C3) **and** Autoable=YES — the automatable journey/SIT/BC backbone. §2.2 Regression Watch = everything else that still warrants a human/regression look (criteria-matched-but-manual, or risk-only-no-criteria) — every §2.2 row carries an `Autoable` (Yes/No) column so SE knows what can still be scripted later.

**Risk lookup:** extract source TP ID from the TC ID (e.g. `F001_AC1_VAL_001` → TP `F001-VAL-001`), read Risk Level from TestChecklist §5. `≥ MEDIUM` means `{CRITICAL, HIGH, MEDIUM}`. If the source TP is absent from §5 → cannot score risk → treat as risk **LOW** (default-safe; never invent HIGH to force inclusion).

**GUI exception:** GUI-type TCs are out of the HP/NEG gate above; include as **P0 §2.1** only if PE marks it a release blocker for a core flow, else EXCLUDED.

**Routing (Tier-3, unchanged):** SEC → `/tas-security` · INT-as-contract-test (not journey-crossing) → `/tas-apitest-plan` · PERF → NFR tooling. These never enter §2.1/§2.2 — count only.

**Cost-optimization intent (ISTQB Ch 5.2 — "đủ" + "tối ưu chi phí"):** §2.1 is the minimal automatable set that is release-blocking across all applicable cycles (E2E/SIT/Backward-Compat) — this is what UAT/SIT execution budgets should be sized against. §2.2 is the regression-watch surplus: real risk, but not journey-blocking, so it can be scheduled or automated later without gating the release.

**Why this differs from TC-Type-only tiering:** a NEG case can be Func-Test-autoable yet touch only a Low-risk, Alt-flow, non-integration field — it scores 0 criteria and Risk<MEDIUM, so it is EXCLUDED even though Func-Test marked it P0-autoable. Conversely a HP case on the Main flow that also crosses an integration boundary and touches an existing API (all 3 criteria) is always P0, regardless of its own risk score.

**Why the representative gate matters:** without it, "flow=Main" alone made C1 true for nearly every VAL/BL HP case in a Feature (Main is, by definition, most of the flow), so Step 2's "meets ALL applicable criteria → P0" collapsed to "almost everything is P0" — E2E scope converged toward Func-Test's full HP+NEG count instead of a minimal-sufficient journey sample (ISTQB Ch 4.2). The gate keeps C1 meaning "this proves the step is reachable," not "this exists on the happy path."

---

## Metrics contract

Field names here are the SSoT for the E2E-Test-Spec frontmatter; the command and template use these exact names.

```yaml
metrics:
  total_tcs: {§2.1 count}        # P0+P1 in §2.1 only (Autoable=YES, criteria-matched)
  p0_count: {M}                  # §2.1 rows meeting ALL applicable criteria (C1+C2[+C3])
  p1_count: {K}                  # §2.1 rows meeting 1–2 criteria at Risk≥MEDIUM
  regression_watch_count: {R}    # §2.2 rows: criteria-matched-but-manual + risk-only-no-criteria
  excluded_count: {L}            # Tier-3 routed (SEC/INT/PERF) + 0-criteria & Risk<MEDIUM
  autoable_yes / autoable_no: {N}   # across §2.1 + §2.2 combined

# top-level frontmatter (outside metrics):
coverage_percentage: {(P0+P1)/FuncTest§4 HP+NEG count × 100}
```

---

## ISTQB alignment note

Test-type gate (HP+NEG only) mirrors ISTQB use-case flow coverage (Ch 4.2) at minimal-sufficient depth — DT/ST/BVA/EP stay Func-Test-owned, never re-derived here. Criteria+risk scoring mirrors ISTQB risk-based testing (Ch 5.2): items release-blocking across every applicable test cycle (E2E/SIT/Backward-Compat) are always tested (P0); partial-relevance or medium-risk items are prioritized but not release-blocking (P1); low-risk zero-relevance items are deferred (Excluded). Journey ordering (which the command applies) is use-case/flow-based (Ch 4.2). This scoring is the resource-cost optimization lever for UAT/SIT/Backward-Compat execution: §2.1 sizes the mandatory automatable pass, §2.2 sizes the regression-watch surplus.
