# Verification Layers — QA Architecture Reference

**Purpose:** Define the 3-tier verification model (SHARED / PER-PHASE / PER-TYPE) and map it to ISTQB test design process. Single source of truth for layer definitions, 5-phase vocabulary, and scope-conflict rules across all TAS test commands.

**Used by:**
- `/tas-TestChecklist` — Phase labels, scope declaration
- `/tas-functest` — Type-specific scope boundary (UI/observable black-box)
- `/tas-apitest-plan` — Layer-aware design, scope-conflict gate
- `/tas-release-plan` (Phase 1) — Group output by layer for release gate

**Do NOT redefine:** ISTQB technique routing → `test-design.md § TP Category → Test Approach Mapping`. TC-count expansion + dedup → `tc-generation-strategy.md § Layer 3`. This file coordinates; those files own the detail.

---

## 1. The 3-Tier Verification Model

Every TAS test command is structured around three tiers:

| Tier | Name | Definition | Where in command |
|---|---|---|---|
| **Tier 1** | SHARED | Logic/format used by ALL test types — SSoT refs, version policy, AI log, frontmatter base, `release_id` | `## Shared Foundation` block at top of each command |
| **Tier 2** | PER-PHASE | The 5-phase process sequence, uniform across all commands | Phase headings: Input → Design → Detail → Gate → Output |
| **Tier 3** | PER-TYPE | Test-type-specific logic (flow design vs. UI TC vs. API contract vs. integration) | `### Type-specific` subsections inside each phase |

**Why this structure:**
- Reviewer opens any of the 3 commands → same 5-phase skeleton → differences are visible and localized.
- Release-gate (Phase 1 of release plan) only needs to read `## Phase 4 — Gate` + `## Phase 5 — Output` across all commands to collect results.
- SSoT refs are in one block, never scattered.

---

## 2. The 5-Phase Vocabulary (PER-PHASE — Tier 2)

All TAS test commands use these 5 phase names **in this order**:

| Phase | Canonical Name | ISTQB Mapping | Purpose |
|---|---|---|---|
| **Phase 1** | **Input** | Test Planning (Ch 5.1) | Validate inputs, locate files, set flags, detect Feature ID |
| **Phase 2** | **Design** | Test Analysis + Design (Ch 4.1–4.2) | L1 scope inventory → L2 technique selection |
| **Phase 3** | **Detail** | Test Implementation (Ch 4.3) | L3 TC generation — concrete steps, assertions, test data |
| **Phase 4** | **Gate** | Test Completion Criteria (Ch 5.1.4) | Blocking checks before write — coverage, ID format, scope-conflict |
| **Phase 5** | **Output** | Test Monitoring + Control (Ch 5.3) | Write file, version bump, AI Usage Log append |

**Mapping existing command phases to this vocabulary:**

| Command | Current step labels | Maps to |
|---|---|---|
| `tas-TestChecklist` | Phase 0 (read-once), 1 (1.0–1.4 scope-gate), 2, 3, 3.5/3.6, 4/4.5, 5, 5.9 | Input(0 intake + 1 scope-gate closed at 1.4) → Design(2) → Detail(4.5) → Gate(Output Validation) → Output(5,5.9) |
| `tas-functest` | Step 1–9 | Input(1–1.6) → Design(2–3.5) → Detail(4) → Gate(8) → Output(5–7,9) |
| `tas-apitest-plan` | Step 1–9 | Restructured to 5 phases in upgrade |

---

## 3. Layer-Aware Design Model (L1 / L2 / L3)

Applied inside **Phase 2 (Design)** and **Phase 3 (Detail)**:

### Layer 1 — Test Basis Scope (ISTQB Ch 4.1: Identify test conditions)

**What:** Enumerate WHAT will be tested before designing HOW.

| Test Type | L1 = Scope inventory |
|---|---|
| Functional (checklist/functest) | Business flows from Feature ACs + System Business Flows from Feature-Technical — confirmed in Phase 1.3 |
| API Contract | Endpoint inventory: `{METHOD} {path}` per spec/code |
| API Integration | Integration points from Feature-Technical `## Integration Points` |
| API Backward-Compat | Breaking-change scenarios: removed fields, changed types, deprecated paths |
| API NFR | SLA thresholds (Perf), attack surfaces (Security), manual recon scope (Pentest) |

**Rule:** L1 inventory must be complete and confirmed (with user if uncertain) before L2 begins. L1 is blocking.

#### System Business Flow (High-Level Test Basis)

**Source:** Feature-Technical.md sections:
- Data Flow (business process flow, not field-level)
- API Spec (endpoint × outcome, not per-status-code)
- ERD (entity lifecycle, not per-state-value)

**Derivation Rule (High-Level TP Coverage):**

| Test Basis Source | High-Level TP Category | Derivation Rule (Business Flow, NOT detailed) |
|---|---|---|
| Data Flow | Business Process Flow | 1 TP per major business process (e.g., "Order Creation Flow", "Payment Flow") |
| API Spec | API Endpoint Flow | 1 TP per endpoint × major outcome (success/failure), NOT per status code |
| ERD | Entity Lifecycle Flow | 1 TP per entity state transition (e.g., "Order Pending→Confirmed"), NOT per state value |

**Note:** Detailed field-level, status-code-level, state-value-level TPs belong to `/tas-functest` (Test Design refinement), NOT TestChecklist (High-Level Test Design).

### Layer 2 — Technique Selection (ISTQB Ch 4.2–4.9)

**What:** Assign the ISTQB technique per test condition identified in L1.

**Canonical source for functional/UI:** [test-design.md § TP Category → Test Approach Mapping](../common/test-design.md#tp-category--test-approach-mapping-istqb)

**API-specific technique routing:** [api-test-strategy.md § Layer 2](api-test-strategy.md)

| Technique | When | Canonical count (L3) |
|---|---|---|
| **BVA** (Boundary Value Analysis) | Numeric/date/length fields with min/max | → `istqb-techniques.md § BVA` |
| **EP** (Equivalence Partitioning) | Enums, categorical fields, valid/invalid partitions | → `istqb-techniques.md § EP` |
| **Decision Table** | 2+ conditions → different outcomes | → `istqb-techniques.md § Decision Table` |
| **State Transition** | Multi-step workflow, status progression | → `istqb-techniques.md § State Transition` |
| **Use Case Flow** | Happy path + alternatives + errors | → `istqb-techniques.md § Use Case Flow` |
| **Error Guessing** | Known error-prone areas (auth, concurrency) | → `istqb-techniques.md § Error Guessing` |

### Layer 3 — TC Count + Assertion Depth (ISTQB Ch 4.3)

**What:** How many TCs a technique generates + what each TC must assert.

**Canonical source:** [tc-generation-strategy.md § Layer 3](../common/tc-generation-strategy.md)

**API-specific count rules:** [api-test-strategy.md § Layer 3](api-test-strategy.md)

**Assertion depth principle:** One TC = one distinct assertion point. Do NOT split one assertion into 3 TCs; do NOT merge 3 distinct assertions into 1 TC.

---

## 4. Scope-Conflict Matrix (functest ↔ apitest-plan)

ISTQB distinguishes:
- **Black-box functional test** (ISTQB Ch 4.2) → **functest** owns this
- **Interface / component integration test** (ISTQB Ch 4.4) → **apitest-plan** owns this

| Test concern | Owner command | Excluded from |
|---|---|---|
| UI form submission, button click, screen state, layout | `tas-functest` | `tas-apitest-plan` |
| API contract: schema, status codes, headers, error codes | `tas-apitest-plan` | `tas-functest` |
| API integration: cross-service calls, external deps | `tas-apitest-plan §2` | `tas-functest` |
| API backward-compat: schema evolution, version negotiation | `tas-apitest-plan §3` | `tas-functest` |
| API NFR: perf thresholds, OWASP API, pentest recon | `tas-apitest-plan §4` | `tas-functest` |
| E2E user journey across multiple screens | `tas-e2e` | both above |

**Scope-conflict gate (in `tas-apitest-plan` Phase 2 — Design):**
When the same endpoint appears in both a FuncTest spec and the API test scope → BLOCK and ask user to choose resolution per [api-test-strategy.md § Scope Conflict Resolution](api-test-strategy.md).

**Scope declaration (in `tas-functest` Phase 2 — Design):**
`tas-functest` must emit: *"Scope: UI/observable black-box testing (ISTQB Ch 4.2). API contract and interface tests → /tas-apitest-plan."*

---

## 5. Shared Foundation Block Template

Every TAS test command must begin with this block (Tier 1 — SHARED):

```markdown
## Shared Foundation (read first)

| Concern | Canonical Source |
|---|---|
| ISTQB technique routing (functional) | `.tas/rules/qa/test-design.md § TP Category → Test Approach Mapping` |
| ISTQB technique routing (API) | `.tas/rules/qa/api-test-strategy.md` |
| TC-count expansion + dedup | `.tas/rules/qa/tc-generation-strategy.md § Layer 3` |
| TC ID convention | `.tas/rules/qa/test-id-convention.md` |
| 5-phase vocab + scope-conflict | `.tas/rules/qa/verification-layers.md` (this file) |
| **Authorship/audit metadata** (`created_by`, `updated_date`, Change Log `Author`) | `.tas/rules/qa/verification-layers.md § 5.1` (this file) |
| AI Usage Log format | `.tas/rules/common/token-logging.md` |
| Merge gate algorithm | `.tas/rules/common/test-report-protocol.md` |

**Frontmatter base (all test output files):**
- `feature_id` — links TC to Feature
- `release_id` — optional; links to release (enables future release-gate grouping)
- `status: Draft` — never auto-approve

**Version policy:** Feature changed → +1.0 MAJOR | PRD/spec changed → +0.1 MINOR | Audit-only → NO BUMP (no AI log row)
```

---

## 5.1 Authorship & Audit Metadata (CANONICAL ⭐)

> **Single source of truth** for frontmatter + audit metadata. Commands reference this section; never restate locally.

**Procedure (git user):**
1. Run `git config user.name` via Bash
2. Success + non-empty → use it
3. Fails or empty → fallback = `owner` (PE/SE from tas.yaml)

**Frontmatter fields:**
- `owner`: PE/SE name from `tas.yaml` (set at CREATE, never change)
- `author`: Result of procedure above (set at CREATE and UPDATE)
- `created_by`: Result of procedure above (set at CREATE only)
- `created_date`: Today `YYYY-MM-DD` (set at CREATE only)
- `updated_date`: Today `YYYY-MM-DD` (set at every write)

**Change Log `Author` column:** Result of procedure above, re-run per version-bump row (don't copy `created_by` forward).

---

## 7. Checkpoint & Resume

**Purpose:** Save execution state at each phase boundary so a run interrupted by token budget expiry can resume without re-reading documents or re-analysing scope. All verification-layer commands use this shared strategy.

**Scope:** Commands that opt in add a save hook at each phase boundary and a resume check at command start. No new rule files; no new commands.

### 7.1 — Checkpoint File Location

```
.tas/command-cache/{command}-{FEATURE_ID}-phase{N}.md
```

Examples:
```
.tas/command-cache/testchecklist-F002-phase1.md
.tas/command-cache/functest-F002-phase2.md
.tas/command-cache/apitest-plan-F002-phase2.md
```

### 7.2 — File Format (all commands)

```markdown
---
feature_id: F002
command: tas-TestChecklist          # | tas-functest | tas-apitest-plan
phase_completed: 1                  # last fully-completed phase number
timestamp: 2026-06-30T14:35:00Z
source_mtimes:                       # stale guard — mtime of EVERY source read this run
  feature: 2026-06-29T10:00:00Z
  prd:     2026-06-28T09:00:00Z      # omit if PRD not read
  sad:     2026-06-27T14:00:00Z      # omit if SAD not read
---

## Digests (Phase 0 — reuse across all phases; decision-state only, ≤200 tokens each)
- **feature_digest**: ac_count=N · flows=[{id, type, risk_tags}] · br_refs=[BR-…] · prd_read_mode · status
- **tech_digest**: endpoints=[{method, path}] · entities=[…] · context_refs=[…] · adr_ids=[…]
- **sad_digest**: read=yes|no · named_§§=[…] · lifecycle={ttl, retention} — present ONLY if SAD was read
- **conflict_list**: [{tag, item, sources}] from cross-doc scan — or "none"

## Phase-Specific State
{one block per completed phase: counts, flags, confirmed-flow IDs — never raw document text}
```

**Rule:** Store only decision state (digests, flags, counts, confirmed flows). Never copy raw document text into the checkpoint — digests are the SSoT.

### 7.3 — Where Each Command Saves

| Phase (canonical name) | Save condition | What to save |
|---|---|---|
| **Phase 1 — Input** | Scope gate PASS | feature_digest + tech_digest + sad_digest + scope boundary (in/out flows, prd_read_mode) |
| **Phase 2 — Design** | Technique map complete | L1 inventory counts + L2 technique-per-TP map |
| **Phase 5 — Output** | After output file written | Delete all checkpoint files for this feature+command (run is complete) |

> **No Phase 4 save point.** In these commands the gate validation is atomic with the output write (same step) — a checkpoint saved there would be deleted by the write that immediately follows, so it carries no resume value. Phase 2 is the last meaningful checkpoint before output.

Phase 1 checkpoint is the most valuable — it saves the blocking scope-gate decision and all digests, allowing Phase 2–5 to resume without any document re-reads.

### 7.4 — Save Notification (user-facing, printed once per save)

```
📌 Checkpoint saved → .tas/command-cache/{command}-{FEATURE_ID}-phase{N}.md
   Completed: Phase {N} ({canonical name}). Resume will skip to Phase {N+1}.
```

### 7.5 — Resume Logic (run at command start, before Phase 0/1)

```
IF .tas/command-cache/{command}-{FEATURE_ID}-phase{N}.md exists:
  → Load file; restore digests + phase-specific state
  → Print resume summary (see below)
  → Skip all completed phases; continue from Phase {N+1}
ELSE:
  → Execute full run from Phase 0/1
```

**Stale guard:** Compare each entry in `source_mtimes` vs the live file's mtime.
- If ANY source is newer → warn user + delete checkpoint + restart full run.
- Print: `⚠️ {source} changed since checkpoint (phase {N}) — restarting full run.`

**Resume summary (printed once):**
```
ℹ️ Resuming {COMMAND} — {FEATURE_ID}
  ✓ Phase 1 (Input):  {N} flows in-scope, scope gate PASS
  ✓ Phase 2 (Design): {M} techniques assigned
  → Continuing from Phase 3 (Detail)...
```

### 7.6 — Command Integration Checklist

When adding checkpoint support to a verification-layer command:

- [ ] Add "Resume Check" block at command start (before Phase 0/1) — load checkpoint if found
- [ ] Add save hook at end of Phase 1 (scope gate PASS only)
- [ ] Add save hook at end of Phase 2 (design complete) — last checkpoint before output
- [ ] Add cleanup step in Phase 5 (delete checkpoint files after output written)
- [ ] Stale guard: compare every `source_mtimes` entry on load; restart if ANY source newer

---

## 6. Release-Readiness Fields

> **Forward-compat only:** Prepares test outputs for future `/tas-release-gate` (Phase 1). Inert unless `release_id` is set.

Each test output file should expose:

| Field | Where | Required by |
|---|---|---|
| `release_id` | frontmatter | release grouping |
| `gate_result` | frontmatter or §Gate | merge-gate algorithm |
| `coverage_percentage` | frontmatter | pass-rate calculation |
| `priority` (per TC) | TC table column | P0/P1/P2 pass-rate |
| `autoable` (per TC) | TC table column | automation coverage metric |

These fields are **optional for feature-level runs** (backward-compatible). They become required only when a `release_id` is set.

---

## 8. Project Cache (`docs/qa-project-base.md`)

**Purpose:** Avoid re-reading PRD/SAD in full on every command run. Unlike [§7 Checkpoint & Resume](#7-checkpoint--resume) (per-Feature, per-run, deleted after output), this cache is **project-wide** and **persists across every Feature and every run** — it exists to skip document reads, not to resume an interrupted run.

**Location:** `docs/qa-project-base.md` (one file, project root, never per-Feature).

### 8.1 — Identity per Source Doc

Each source's identity = `{version, last_updated}`. **Where each field is read from is doc-specific — do not assume both docs use the same header shape:**

| Doc | `version` read from | `last_updated` read from |
|---|---|---|
| PRD | **Last row of `## Changelog` table**, `Version` column (PRD has no header `Version:` line) | Header blockquote `**Last Updated:**` line |
| SAD | Header blockquote `**Version:**` line | Header blockquote `**Last Updated:**` line |
| Design-Spec | Header blockquote `**Version:**` line if present, else file mtime | File mtime |
| CLAUDE.md | File mtime (no version header) | File mtime |

Never read `version`/`last_updated` from memory of a prior run — always re-derive from the doc on disk per this table before comparing to cache.

### 8.2 — Three-Step Logic

| Step | Condition | Action |
|---|---|---|
| **1** | `docs/qa-project-base.md` does not exist | Read PRD + SAD in full → extract tracked anchors (§8.3) into digests → **write `docs/qa-project-base.md` to disk now (via the Write tool), with each doc's current `{version, last_updated}` under `source_versions:`, before proceeding to any later phase.** Holding digests in scratchpad/context only is NOT a substitute — the file must exist on disk before Phase 0.1 begins. |
| **2** | Cache exists AND a doc's live `{version, last_updated}` == cached `{version, last_updated}` | Cache hit for that doc — do not re-read it; serve its digest straight from cache. |
| **3** | Cache exists BUT a doc's live `{version, last_updated}` ≠ cached value | Read that doc's `## Changelog` rows newer than the cached version. If any changed row touches a tracked anchor (§8.3) → re-read only that anchor's section, update the digest. If none touch a tracked anchor → leave the digest unchanged. Either way, **write the updated cache back to disk (via the Write tool)** for the changed doc's `{version, last_updated}`. |

Each doc (PRD, SAD) is evaluated independently — a version bump in one does not force a re-read of the other.

### 8.3 — Tracked Anchors (TestChecklist)

| Doc | Anchor | Digest field |
|---|---|---|
| PRD | `## Non-Functional Requirements` (or equivalent NFR section) | `prd_nfr_digest` |
| PRD | `## User Personas` | `project_roles[]` |
| PRD | `## User Flows` | `prd_usecase_digest` |
| SAD | `## Constraints & Assumptions` | `sad_digest` |
| SAD | FR→Module traceability (if present) | `sad_digest` |
| SAD | `## System Context (C4 Level 1)` — external actors placed on the diagram (name, `AT-NNN`, protocol) | `known_externals[]` |
| SAD | `## Integration Contract Registry` (`IC-NN` table) — endpoint/event, producer MOD, consumers, request/response shape | `integration_contracts[]` |
| SAD | Sequence / Runtime / Data-Flow section (system-flow steps, project-wide) | `sad_flow_digest` |
| Design-Spec | Component/screen inventory (feeds Layer-3 UX-gap screening in `/tas-TestChecklist`) | `design_spec_digest` |
| CLAUDE.md | `## Tech Stack` | `tech_stack_digest` |

**Extraction detail for the two SAD rows above (why they need different handling than a plain table anchor):**
- **System Context** is a Mermaid diagram, not a table. Extract every external-system node (edges labelled with a protocol, nodes representing systems other than the system-under-design and its human actors) → `{name, protocol}`. Cross-reference against BRD `AT-NNN` actors of type "External system" where resolvable; if the diagram names a system with no matching `AT-NNN`, keep it anyway (diagram is still ground truth) but do not fabricate an `AT-NNN` for it.
- **Integration Contract Registry** is a table — read directly, one row per `IC-NN` → `{ic_id, contract, producer_mod, consumers, request_response_shape, timeout}`.
- A system appearing in both (System Context AND an IC-NN row) is the same external — do not double-count; `integration_contracts[]` entries may reference a `known_externals[]` name instead of repeating its protocol.
- **`sad_flow_digest`** shape: `{module, action_signature: "step → step → step"}` — one entry per system-flow step, no per-Feature judgment baked in (whether a step needs a test is decided per-Feature at gap-detection time, not here).
- **`design_spec_digest`**/**`tech_stack_digest`** are plain section extracts (component/screen list; declared stack items) — no special parsing, unlike the two Mermaid/table SAD anchors above.

A tracked-anchor list is command-specific — `/tas-TestChecklist` uses the table above; a different command opting into this cache defines its own anchor subset without altering this file's identity/step logic.

### 8.4 — Cache File Format

Same discipline as [§7.2](#72--file-format-all-commands): store digests only, never raw document text.

```markdown
---
source_versions:
  prd: {version: "1.2", last_updated: "2026-07-10"}
  sad: {version: "1.0", last_updated: "2026-06-28"}
  design_spec: {version: "n/a", last_updated: "2026-07-01"}
  claude_md: {version: "n/a", last_updated: "2026-06-15"}
---

## Digests
- **prd_nfr_digest**: {…}
- **project_roles[]**: {…}
- **prd_usecase_digest**: {…}
- **sad_digest**: {…}
- **sad_flow_digest**: [{module, action_signature}, …]
- **known_externals[]**: [{name, protocol, at_id}, …]
- **integration_contracts[]**: [{ic_id, contract, producer_mod, consumers, timeout}, …]
- **design_spec_digest**: {…}
- **tech_stack_digest**: {…}
```

### 8.5 — Anchor Not Found

If a tracked anchor cannot be located in the doc (Step 1 build, or Step 3 re-read) → do not invent structure. Write `[ANCHOR-MISSING: {target}]` into that digest field and surface **once per project** (not once per Feature) as a `[TECH-COVERAGE]` risk, RC-BR, Owner=PE.

---

## 9. Effort Estimation (ROM — Agile priority-weighted × ISTQB test-level)

**Purpose:** Single formula for ETA (hours + person-days) across all verification-layer commands. `/tas-TestChecklist` is the **only writer** (§6 in its output, right after Gate) — it is the sole place where flow/TP/risk counts for the whole Feature are available in one pass. Downstream commands (`/tas-functest`, `/tas-apitest-plan`, `/tas-e2e`, `/tas-security`) do not re-estimate; they consume actuals against this baseline when they close out.

**Scope discipline:** TestChecklist is **high-level test design** (per §3 Layer 1) — its ETA is a **rough-order-of-magnitude (ROM)** estimate at Test-Point-count granularity, not a bottom-up per-TC estimate. Do not wait for `/tas-functest` TC expansion to produce this number.

**Model (two factors only — no PERT, no risk multiplier):**
1. **Agile priority-weight** — each TP costs by priority (P0>P1>P2), reflecting risk + business value (ISTQB Test Estimation Ch 5.1 accepts priority-weighted effort). This is the row's raw `M`.
2. **ISTQB stage-multiplier** — a layer executed at N SDLC stages pays execute-cost N times but writes the script once. Applied per row (9.2).

A flat **risk buffer** (registered mitigation/re-test hours) is added to `M` before the stage-multiplier. There is **no PERT three-point spread and no ×1.033 critical multiplier** — the buffer alone carries risk cost, keeping the number auditable by hand.

### 9.1 — Per-Row Formula

Each row splits its buffered base `B` into **Design** (write the test scenario/script — one pass, ISTQB Test Design/Implementation Ch 4.2–4.3) and **Execute** (run it — the DEV/STAG/PROD stage columns). `E` is the sum of Design + all stage columns, so every hour is visible where it lands and nothing is a magic multiplier.

| Term | Definition |
|---|---|
| **M** (raw) | Priority-weighted TP hours for the row's scope — `Σ(tp_count[prio] × HOURS_PER_TP[prio])`, per-row base in 9.3 |
| **risk_buffer** | `risks_critical × 1.0h + risks_high × 0.5h` — added once per executing row (weighted ×0.5 for Row 3 Test Data; full for all others). Source: §5 Risk Registry counts |
| **B** (buffered base) | `M + risk_buffer` |
| **Design** | `0.4 × B` — write scenario/script, one pass (ISTQB: design ≈ 40% of test effort) |
| **Execute** | `0.6 × B` — the execution cost, spent at the layer's **first** SDLC stage; each later stage re-runs at `0.4 × Execute` (9.2 stage map) |
| **E (Total ETA)** | `Design + Σ(DEV+STAG+PROD)`, rounded to nearest 0.5h. Equivalently `B × row_mult` where `row_mult = 0.4 + 0.6 × stage_mult` — the columns just show *where* the hours land |

> **No PERT.** Earlier revisions used `E = (O + 4M + P)/6` and a ×1.033 critical multiplier. Both are removed: risk cost now lives entirely in `risk_buffer`, confidence spread is only the ±30–50% ROM label on the total (9.5). Compute every E by hand — a script is never warranted.

**Design + Stage distribution rule (SSoT — turns the model into Design/DEV/STAG/PROD hours):**

| Layer | Design | DEV | STAG | PROD | row_mult (E/B) |
|---|---|---|---|---|---|
| TestChecklist Design | B (whole row IS design) | — | — | — | 1.0 |
| Functional | 0.4B | 0.6B | — | — | 1.0 |
| Test Data | 0.4B | 0.6B | — | — | 1.0 |
| API | 0.4B | 0.6B | 0.24B | 0.24B | 1.48 |
| E2E | 0.4B | — | 0.6B | 0.24B | 1.24 |
| Security/Pentest | 0.4B | — | 0.6B | — | 1.0 |
| Regression | — | 0.6B | — | — | 0.6 (see 9.3 Row 7) |

> **Where each later-stage number comes from:** a stage that re-runs pays `0.4 × Execute = 0.4 × 0.6B = 0.24B`. So API (DEV+STAG+PROD) = `0.4B design + 0.6B DEV + 0.24B STAG + 0.24B PROD = 1.48B`; E2E (STAG+PROD) = `0.4B + 0.6B STAG + 0.24B PROD = 1.24B`. Rows that run at a single stage have no re-run column. **TestChecklist Design (Row 1) is pure design** — its whole `B` is the Design cell, no execute stage.

### 9.2 — Constants (SSoT — do not restate in commands)

**Hours per TP, by priority** (covers write scenario/script + execute + log bugs found, ISTQB Ch 4.3 grain):

| Priority | Hours/TP | Rationale |
|---|---|---|
| P0 | 1.0h | Main flow / high risk — full script + execute + likely bug follow-up |
| P1 | 0.5h | Alt flow variants — lighter script, fewer surprises |
| P2 | 0.25h | Low-risk edge / optional NFR — quick check, rarely blocks |

**Execute stage map (ISTQB test level → which SDLC stages run):** each layer executes `0.6B` at its first stage, then `0.4 × 0.6B = 0.24B` at each later stage (re-run pays 40% of first-execute). Design (`0.4B`) is always a single write-pass regardless of stage count. The resulting per-row `row_mult` is tabulated in 9.1.

| Layer (ISTQB level) | Executes at | Later-stage re-runs |
|---|---|---|
| Functional (Component/System) | DEV | none |
| API (Integration) | DEV → STAG → PROD | STAG, PROD (0.24B each) |
| E2E (System) | STAG → PROD | PROD (0.24B) |
| Security/Pentest (Non-functional, gated) | STAG | none |

**Regression:** flat **20%** of the sum of all executed rows' `E` (Agile norm for a fix-verification pass, not a fresh TP count) — no separate Design split. Shared components add a bounded top-up (9.3 Row 7).

### 9.3 — Rows + Input Sources (one calculation each)

**LEAN SSoT:** Each row's `M` reads from TestChecklist sections already populated in Phases 1–3; no extra reads or derivations at §6 compute time.

| # | Row | M (raw) Formula | Input Source | Condition | row_mult (E/B) |
|---|---|---|---|---|---|
| 1 | TestChecklist Design | `flows_total × 0.5h + test_points_total × 0.15h` | §1.1 flow count + §2.1 TP count | Always | 1.0 (pure Design) |
| 2 | Functional Test (DEV) | `tp_p0×1.0h + tp_p1×0.5h + tp_p2×0.25h` | §2.1 TP priority breakdown | Always | 1.0 |
| 3 | Test Data (one-time) | `IF test_data_complex: api_item_count×1.0h + nfr_integration_count×0.5h + pentest_count×0.5h ELSE 0` | §1.2.1 API rows + §1.3 Integration/Perf NFRs + §1.2.2 pentest rows + Phase 1.3.4 ASK | Conditional: `test_data_complex = true` | 1.0 |
| 4 | API Test (DEV+STAG+PROD) | `api_item_count × 1.0h` | §1.2.1 API Contract + API Integration row count | If `api_item_count > 0` | 1.48 |
| 5 | E2E Test (STAG+PROD) | `(flows_main + flows_alt) × 1.0h` | §1.1 flow count (Main + Alt only; Edge → regression watch) | If flows > 0 | 1.24 |
| 6 | Security/Pentest (STAG) | `IF pentest_count > 0: pentest_count × 1.0h ELSE IF risks_critical>0 OR risks_high>0: 2h (baseline audit) ELSE 0` | §1.2.2 pentest count OR §5 risk count | If `pentest_count>0 OR risks_critical>0 OR risks_high>0` | 1.0 |
| 7 | Regression (20%) | `0.2 × Σ(E of rows 1–6 that executed) + shared_top_up` where `shared_top_up = IF shared_component_count>0: 0.1 × shared_component_count × (E_row4 + E_row5) ELSE 0` | §1.5 shared component count (0 if absent) + `bc_applicable` flag | If `bc_applicable=true OR shared_component_count>0` else base 20% only | 0.6 (DEV-only, no Design split) |

**Risk buffer application (per 9.1):** add `risks_critical×1.0h + risks_high×0.5h` to `M` to form `B`, before the Design/Execute split, on every executing row **except**:
- **Row 1 (Design)** — no buffer (design effort is flow/TP-count driven, not risk-driven)
- **Row 3 (Test Data)** — half buffer (`×0.5`): prep work, lighter re-test exposure
- **Row 7 (Regression)** — no buffer (already a % of buffered rows; adding again double-counts)

**Derived-input read rules (all from finalized TestChecklist sections — no Feature/Feature-Technical re-read):**
- `api_item_count` = count rows in §1.2.1 (API Contract + API Integration items)
- `nfr_integration_count` = count §1.3 rows where Category ∈ {Integration, API, Performance, Reliability}
- `pentest_count` = count §2.1 TPs tagged `[Security]` OR §1.2.2 pentest rows (whichever ≥)
- `shared_component_count` = count §1.5 rows (0 if section absent)
- `test_data_complex` = Phase 1.3.4 PE ASK answer (Y/N) — default N if unasked

**Gate Sequencing (Depends On — SSoT for the §6 Notes/Depends column):**
Row 1 (no dep) → Row 2 (DEV) → Row 3 (parallel w/ 2) → Row 4 (after Row 2 DEV pass) → Row 5 (after Row 4 DEV pass) → Row 6 (after Rows 4–5 STAG pass) → Row 7 (after all 1–6 pass).

### 9.4 — Token-Optimized Input Timing (Lean SSoT — single pass, zero re-read)

1. **Phases 1–3 (input reads, already happening):** Feature.md + Feature-Technical.md read once → digests hold flows, API Spec, Integration Points, risk tags, shared components.
2. **Phase 1.3.4 (Settings ASK — one question, reuses existing gap-ASK turn):** *"Complex test data setup needed (DB seed / mocks / 3rd-party accounts)?"* → `test_data_complex`.
3. **Phase 5 §6 compute (no additional reads):** all counts come from the now-complete output sections (§1.1, §2.1, §1.2, §1.3, §1.5, §5). Apply 9.1–9.3 by hand → write §6. Feature docs are **not** reopened.

**Result:** §6 computed in one pass from sections already on the page. Zero redundant reads, zero re-analysis.

### 9.5 — Output Format

Report each executing row across Design + DEV/STAG/PROD, then `Total ETA (h)` and `ETA (man-day)` (`E ÷ 8`, round up to nearest 0.5 MD). Total row sums every column. Label the grand total **ROM estimate (±30–50%)** — a planning input, refined once `/tas-functest`, `/tas-apitest-plan`, `/tas-e2e` produce actual TC counts. **Never** present it as committed.

**Template rendering (§6) — Design + stage-breakdown columns (show the work):**
- Column order: `Test Type | Design (h) | DEV (h) | STAG (h) | PROD (h) | Total ETA (h) | ETA (man-day) | Depends On`
- Per row: `B = M + risk_buffer`; fill cells per the **Design + Stage distribution rule** in 9.1 — `Design = 0.4B` (Row 1 = whole B; Regression = —), first execute stage = `0.6B`, each later stage = `0.24B`; a stage the layer doesn't run at = `—`
- `Total ETA (h)` = sum of that row's Design+DEV+STAG+PROD cells (self-proves `row_mult`)
- One row per §9.3 entry where Condition = true (skip false rows entirely — do not print a 0h row)
- Total row: sums each column (Design, DEV, STAG, PROD) **and** `Total ETA (h)` / `ETA (man-day)` → gives QA-hours per phase+environment for deploy-gate planning plus grand total
- Frontmatter: set `extensions.test_checklist.eta_total_hours` + `eta_total_pd` from the grand total

**Re-estimate trigger:** UPDATE-SYNC version bump (Feature or PRD changed) → recompute §6 from new counts. Audit-only sync (no bump) → §6 untouched.
