---
model: sonnet
---

# /tas-apitest-plan $ARGUMENTS

Role: SE - Software Engineer
Generate API Test Specification (Markdown) from API Spec (OpenAPI 3.0, Markdown, YAML) or analyze API code.

**Scope:** Per `qa/verification-layers.md § 4` (Scope-Conflict Matrix) — this command owns: API contract, integration, backward-compat/breaking-change, and API-tooling-verifiable NFR/security/pentest. Functional black-box/UI → `/tas-functest`. Test code authoring → `/tas-apitest`. **Receives `[TECH-COVERAGE]` handoff** from TestChecklist §5. Any coverage gap → **note in output's Risk section**.

**Priority assignment:** Per [test-design.md § Testing Priority Assignment](../../rules/qa/test-design.md#testing-priority-assignment-tool-availability) — P0/P1 tests use standard tools (Postman, DB Query, API Logger); P2 tests use specialized tools (Load testing, Security scanning) or are deferred.

## Always / Ask / Never

| | Action |
|---|---|
| **Always** | Read entire spec or analyze code before creating test spec |
| **Always** | Organize test cases by API version — each version separate section |
| **Always** | Append-only: don't modify sections in existing old version |
| **Ask** | When spec unclear about expected response schema or business rule |
| **Never** | Use version folder/syntax in test spec file (use section headers instead) |

Coverage minimums (≥1 happy + ≥1 error per endpoint, mandatory error paths) are owned by `qa/api-test-strategy.md § 3.1`. Test-code conventions (xUnit/HttpClient) belong to `/tas-apitest`, not this design step — do not read `csharp/api-testing.md` here.

**Authorship/audit metadata** (`created_by`, `updated_date`, Change Log `Author`) — run `git config user.name` (Bash tool) and use its stdout; procedure + fallback at [verification-layers.md § 5.1](../../rules/qa/verification-layers.md#51-authorship--audit-metadata-canonical-).

## Resume Check (before Phase 1)

Checkpoint strategy: [verification-layers.md §7](../../rules/qa/verification-layers.md#7-checkpoint--resume) (SSoT).

**Sources + Digests (per §7.5 table):**
- `source_mtimes` keys: **`feature`** · **`feature_technical`** · `testchecklist` (if Feature-linked) · `api_spec` (if separate spec)
- Phase 1 digests: base 4 (`feature_digest`, `tech_digest`, `sad_digest`, `conflict_list`) + command-specific: `scope_endpoints` (from L1 inventory), `scope_final` (after contract anchor + conflict checks)

**Check:** `.tas/command-cache/apitest-plan-{FEATURE_ID}-phase{N}.md`
- **Found + all sources unchanged** → load digests + scope, skip to Phase {N+1}.
- **Found + any source newer** → delete checkpoint, restart full run.
- **Not found** → proceed to Phase 1.

---

## Actions

### Phase 1 — Input (Read All Sources First)

**Read order is mandatory — do NOT begin scope determination until all sub-steps complete.**

- **1.1 Locate inputs** — `$ARGUMENTS` is one of:
  - API Spec file (OpenAPI 3.0 JSON/YAML, Markdown)
  - Feature ID → glob find `docs/features/{CODE}-Feature-{ID}-*/{CODE}-Feature-{ID}-*.md`
  - Path to API code project to analyze

  If not provided → ask user:
  ```
  Enter input for /tas-apitest-plan:
  1. Path to API Spec file (OpenAPI/Markdown/YAML)
  2. Feature ID (to find spec link in Feature/Feature-Technical)
  3. Path to API code to auto-analyze
  ```

- **1.2 Read Feature-Technical file only (if Feature-linked)** — Do **NOT** read Feature.md (business AC text is not needed for API test design). Read `{CODE}-Feature-{ID}-*-Technical.md` and extract:

  | From | Extract | Store as |
  |---|---|---|
  | API Spec | Endpoints, request/response schema, error codes | feeds `spec_baseline` (Phase 2.1) |
  | Context Diagram / `External systems` | 3rd-party services, queues, brokers touched | `integration_targets` |
  | Data Flow / Logic Flow (per stack) | State transitions, cross-field constraints, lifecycle rules | `business_rules` |
  | DO NOT CHANGE (IC-NN locked contracts) | Consumed contracts this Feature must not break | `locked_contracts` |
  | SAD Impact Matrix row `API Contract` | `Detected: Yes` → breaking/versioning change signal | feeds `bc_applicable` (backward-compat) |

  Store as digests; do not analyze yet. If Feature-Technical is missing/`plan_status: pending` → ask user for a raw API Spec file instead (per 1.1 option 1/3).

- **1.3 Read TestChecklist digests (if Feature-linked)** — Glob find `{FEAT}-TestChecklist.md` in Feature directory. **IF found**, smart-read API-relevant slices only:

  | From | Extract | Store as |
  |---|---|---|
  | §2.1 (`Stack=API` OR `Category=SEC`) | API/SEC test points | `inherited_tps` |
  | **§1.2.1 (API Test Scope, SE Owner)** | **ALL rows (Item, Source, Route To, Rationale)** — SE-scope items at category level | **`se_scope_raw`** |
  | **§1.3 (NFR Routing)** | **rows where Route To = `/tas-apitest-plan`** — carries the specific `NFR-XXX` ID | **`nfr_catalog`** |
  | §2.3 | BVA field constraints | `bva_constraints` |
  | §3 | TD-NNN concrete values | `test_data_catalog` |
  | §5 (Risk Registry — RC-INT / RC-SEC rows, incl. backward-compat row) | Inherited SE risks (3rd-party integration, backward-compat) | `inherited_risks` |
  | **§1.5 Shared Component Impact** (conditional — present only if detected) | Component, Type, Used By (Features), Risk Level, Regression Scope | `shared_components_digest` |

  > **§1.5 feeds Risk, not TC scope.** A shared component (e.g. Email Validator used by 3 Features) is a regression-risk signal for API/integration tests that reuse it — carry it into the output's `## Risk & Coverage Notes` (Phase 3) as `INHERITED` per `test-design.md § Detection Tag → RC Code`; do not generate a duplicate TC set per Feature that shares the component (dedup per `api-test-strategy.md § API-Specific Dedup Extensions`).

  > **§1.2.1 and §1.3 are complementary, not duplicates.** §1.2.1 names SE-scope items at **category** level (API Performance, API Security) with no NFR ID; §1.3 carries the specific **`NFR-XXX` ID** for each routed NFR. Read both: `nfr_catalog` (§1.3) provides ID-level traceability for the Performance/Security categories listed in `se_scope_raw` (§1.2.1). **Dedup rule (Phase 3 step 0):** an §1.2.1 Performance/Security row and its matching §1.3 `NFR-XXX` describe the *same* coverage — generate the TC **once**, citing the `NFR-XXX` ID; do not emit a second generic TC for the §1.2.1 category.

  All TC generation using these digests happens in Phase 3. Do NOT re-read TestChecklist later.

- **1.4 Detect existing test spec** — Glob find `docs/tests/API-Test-Spec-*.md`.
  - **Found**: Read file, detect existing versions (find section headers `## v{N}`)
  - **Not found**: Will create new at Phase 5

- **1.5 Detect input defects (gap-first)** — Scan **all digests read in 1.2–1.4** before generating; do not fabricate to fill a gap:
  - Endpoint missing response schema / error codes / business rule → ASK user, or note in Risk section if proceeding
  - Inherited `[TECH-COVERAGE]` risks from `inherited_risks` (1.3) — capture as risks here; coverage (TCs) is designed in Phase 3
  - `shared_components_digest` (1.3, TestChecklist §1.5) row with missing/ambiguous **Regression Scope** or **Risk Level** → do NOT infer a scope; log `INHERITED: {component} — Regression Scope unclear` to `## Risk & Coverage Notes`, Owner=PE (per `test-design.md § Detection Tag → RC Code`)
  - `locked_contracts` (1.2, DO NOT CHANGE) referenced by an endpoint in `spec_baseline` but the spec shows a signature change → BLOCK, this is a breaking-change conflict with a frozen contract — ask user before proceeding
  - Any coverage that **cannot be tested with API tooling** (heavy load infra, manual UI, etc.) → log to `## Risk & Coverage Notes` per `qa/api-test-strategy.md § Risk Classification`; do not silently drop
  - **Expert review escalation** — apply `qa/api-test-strategy.md § Expert Review Escalation` deterministic triggers (Security/Performance/Data-consistency) over the digests from 1.2/1.3. Zero matches → skip (no agent call). Matches found → ONE batched parallel dispatch (max 5, cap per that section) to `security-reviewer` / `architect` / `database-reviewer` with narrow excerpts only. Merge verdicts into `## Risk & Coverage Notes` per that section's Verdict table.

**Phase 1 checkpoint (after 1.5, on no blocking defects):** Save `.tas/command-cache/apitest-plan-{FEATURE_ID}-phase1.md` with source list read, inherited `[TECH-COVERAGE]` risk list, `feature_mtime`. Print: `📌 Checkpoint saved → .tas/command-cache/apitest-plan-{FEATURE_ID}-phase1.md`

---

### Phase 2 — Design (Scope Determination — L1 Gate)

**Scope is determined HERE from Phase 1 digests. No new source reads.**

- **2.1 Resolve spec_baseline** — Apply `qa/api-test-strategy.md § 1.0` (Source Priority table). Use `inherited_tps` from Phase 1.3 as Priority 1 source if available. Result: `spec_baseline` + `spec_endpoints`.

- **2.2 Endpoint inventory** — Apply `qa/api-test-strategy.md § 1.1` FROM `spec_baseline`. Build `endpoint_inventory`. Add AC mapping per `qa/test-id-convention.md`.

- **2.3 Contract↔Codebase anchor check** — If code path available: apply `qa/api-test-strategy.md § 1.2`. Detect orphan endpoints; ask [A]/[B]/[C] per orphan. Result: `scope_final`.

- **2.4 Scope-conflict gate** — Apply `qa/api-test-strategy.md § 1.3` — glob FuncTest spec for same Feature; if overlap found → BLOCK and resolve before continuing.

- **2.5 NFR scope gate** — Apply `qa/api-test-strategy.md § 1.6` — for each NFR in `nfr_catalog` (§1.3, with its `NFR-XXX` ID), set the **nfr_scope flag**: IN (generate TC), OUT (log risk), STUB (skeleton only), per the §1.6 Postman-testable table. Log OUT NFRs to Risk & Coverage Notes with rationale. (Category→technique mapping is applied once at Phase 3 step 0 — not restated here.) **Must complete before scope_final is confirmed.**

- **2.6 Cross-cutting error TC design** — Apply `qa/api-test-strategy.md § 2.5` — identify + reserve TC IDs for the shared Malformed JSON, DB failure, and Auth 401 scenarios (one set per spec file). TC bodies are written in Phase 3 step 7; per-endpoint TCs reference these IDs (do not regenerate at L3).

- **2.7 Detect API version** — Prioritize:
  1. `info.version` in OpenAPI
  2. Prefix in URL path (`v1/`, `v2/`)
  3. Ask user

  Version format: `v1`, `v2` (no dot).

- **2.8 Determine output path** — Output: `docs/tests/API-Test-Spec-{slug}.md`
  - From `api_name` in spec → lowercase, replace spaces with dashes
  - Or ask user for short slug (e.g., `users`, `orders`, `products`)

- **2.9 Determine update mode** — If spec file exists and version already exists:
  - **Append mode** (default): add new TCs to end of current version section
  - Ask user if new version wanted:
    ```
    Spec file already exists with version {current}. You want:
    1. Append test cases to version {current} (default)
    2. Create new version (v{next}) for test cases
    ```

⛔ **L1 Gate — `scope_final` must be confirmed before Phase 3 begins.** All required before Phase 3:
- [ ] Orphan endpoints resolved (§2.3)
- [ ] Scope-conflict resolved (§2.4)
- [ ] NFR scope gate complete (§2.5) — nfr_scope flags set (Performance IN/OUT, Security L1 IN/OUT, DAST OUT logged, Pentest IN/STUB)
- [ ] Cross-cutting error TCs designed (§2.6)

If any pending → BLOCK.

**Phase 2 checkpoint (after L1 Gate passes):** Save `.tas/command-cache/apitest-plan-{FEATURE_ID}-phase2.md` with `scope_final` endpoint list, update mode, version. Print: `📌 Checkpoint saved → .tas/command-cache/apitest-plan-{FEATURE_ID}-phase2.md`

---

### Phase 3 — Detail (TC Generation)

Read template `.tas/templates/API-Test-Spec.md` for structure. Apply coverage strategy + test techniques from:
- **Layer 1 Scope:** `qa/api-test-strategy.md § 1` — §1.0 Source priority · §1.1 Endpoint Inventory · §1.2 Contract↔Code Anchor · §1.3 Scope-Conflict · §1.4 Section Scope (Contract/Integration/**Backward-Compat**/NFR) · §1.5 Breaking-Change Detection · **§1.6 NFR Scope Gate** (confirms which NFR categories Postman can cover before scope_final is locked)
- **Layer 2 Technique Routing:** `qa/api-test-strategy.md § 2.1–2.4` (field-type, API-specific, error-code, security) + **§2.5 Cross-Cutting Error TC Scope** (Malformed JSON, DB failure, Auth 401 — design once per spec file)
- **Layer 3 TC Counts:** `qa/api-test-strategy.md § 3` — §3.1 Per-Endpoint Min · §3.4 Cross-Cutting (counts only, designed at §2.5) · §3.5 Integration · **§3.6 Backward-Compat** · §3.7 NFR

Use Phase 1 digests (`inherited_tps`, `se_scope_raw`, `nfr_catalog`, `bva_constraints`, `test_data_catalog`, `business_rules`, `integration_targets`, `locked_contracts`, `inherited_risks`, `shared_components_digest`) to populate specific TCs. Do NOT re-read TestChecklist or Feature-Technical again.

**Extract `template_structure_digest`** (reuse at Phase 5.0 — do not re-read the template file later): required section list (frontmatter keys, `## Test Environment & Data`, `## v{N} — Test Cases` → Endpoints Overview/Coverage Matrix/Test Case Details, `## AC Traceability`, `## Cross-Feature Regression Watch`, `## Risk & Coverage Notes`, `## Changelog`, `## AI Usage Log`), Coverage Matrix column order, TC ID/MOD format ref (`test-id-convention.md § 3`).

**TC Generation sequence** (apply in order):
0. **SE scope items + NFR** — From `se_scope_raw` (§1.2.1, category-level) and `nfr_catalog` (§1.3, ID-level). Generate ≥1 TC per item:
   - Item = "API Contract Tests" → Contract TCs (schema, status codes, error handling)
   - Item = "API Integration" → Integration TCs (happy / failure / retry) per `§ 3.5`
   - Item = "Token Validation" → State Transition TCs (valid / invalid / expired)
   - Category = Performance (nfr_scope=IN) → BVA TC (below / at / above threshold) per `§ 3.7`
   - Category = Security (nfr_scope=IN) → route to `security-test-matrix.md` Layer 1
   - **Dedup:** a §1.2.1 Performance/Security row and its matching `nfr_catalog` `NFR-XXX` are the *same* coverage → generate the TC **once**, cite the `NFR-XXX` ID in the TC source field. Do not emit a duplicate generic TC for the category.
   - Use **Source** reference to locate technical spec (Feature-Technical API Spec, §9.2, Integration Points); carry **Rationale** into TC description. Autoable = YES (Postman-only) / NO (external tool) per §2.5.
1. **State Transition** — Apply `qa/api-test-strategy.md § 2.2` (path params {token}/{secret}/{key}/{code} → State Transition TCs)
2. **Security surfaces** — Apply `qa/api-test-strategy.md § 2.4` (API-shape triggers → route to security-test-matrix.md):
   - String input persisted to DB → SQL injection TC
   - Returns user-supplied data → XSS TC
   - Path param {id} on user-owned resource → BOLA/IDOR TC
   - Admin-only endpoint → BFLA TC
   - POST/PUT extra fields → Mass Assignment TC
3. **Validation (single-field)** — From `bva_constraints` (Phase 1.3): for each field's own constraint → BVA/EP TCs:
   - Empty/null case (if not required)
   - Boundary min/max values
   - Invalid format/type
4. **Business Rules (cross-field / lifecycle)** — From `business_rules` (Phase 1.2): rules spanning ≥2 fields or entity state:
   - State transitions (e.g., draft → submitted → approved)
   - Cross-field constraints (e.g., no resume post-payment)
   - Lifecycle rules (e.g., draft deletion)
5. **Per-endpoint error codes (4xx)** — For each endpoint in `scope_final`, generate the applicable 4xx TCs per `qa/error-handling-strategy.md § Error Code → Technique Routing` (401 3-partition, 403 IDOR, 404, 422 business-rule). 401 is shared per auth group (do not regenerate per endpoint — reference the Phase 2.6 auth TC by ID).
6. **Error paths (infra/transient)** — From `inherited_risks` (Phase 1.3):
   - Mentions "DB failure" → DB failure TC
   - Mentions "transaction" or "rollback" → Transaction rollback TC
   - Mentions "timeout" → Timeout/retry TC
7. **Cross-cutting** — Reference shared TCs from Phase 2.6 (Malformed JSON, DB failure, Auth 401) by TC ID (do not regenerate)

**Coverage matrix:** per template § Coverage Matrix (canonical columns: Endpoint, Happy Path, error codes, Business Rule, Priority, Autoable). Assign **Priority** per [test-design.md § Testing Priority Assignment](../../rules/qa/test-design.md#testing-priority-assignment-tool-availability) (P0 main/high-risk, P1 alt-flow, P2 low-risk/optional NFR).

**Test case detail format:** per template § Test Case Details (endpoint, auth, preconditions, request, expected response, assertions, AC ref, method name).

**Risk & Coverage Notes:** `inherited_risks` + `shared_components_digest` from Phase 1.3 + any gap from Phase 1.5 (input-defect scan). Route non-Autoable TCs per `api-test-strategy.md § Risk Classification`.

8. **Populate Cross-Feature Regression Watch** — After Risk & Coverage Notes is drafted, scan (no re-read):
   - `se_scope_raw` (§1.2.1) rows whose Item/Rationale marks an endpoint as shared/reused-route across Features
   - `inherited_risks` (§5) rows tagged shared-contract regression (RC-INT, not the 3rd-party/external-API kind)
   - `bc_applicable` flag (from `locked_contracts` / SAD Impact Matrix, Phase 1.2) — `true` → this version has a real breaking/versioned change

   For each match: confirm the endpoint has ≥1 TC already generated in this spec (Contract or Backward-Compat TC) — if none, do NOT add a row here; log the gap in Risk & Coverage Notes instead (per template's out-of-scope rule). Row: `{Shared-Contract|Backward-Compat} | {endpoint} | {feature list from §1.2.1/§5} | {TC IDs} | {TestChecklist §1.2.1 or §5 risk ref}`.

   3rd-party/external-API integration risk is explicitly **not** routed here — it stays in Risk & Coverage Notes (operational dependency, not shared-contract regression). No triggers matched → omit the table body row entirely (leave template's single example row only if this section is otherwise unused — do not fabricate a placeholder).

**Phase 3 checkpoint (after TC generation):** Save `.tas/command-cache/apitest-plan-{FEATURE_ID}-phase3.md` with TC count per endpoint, coverage matrix summary, Risk & Coverage Notes count. Print: `📌 Checkpoint saved → .tas/command-cache/apitest-plan-{FEATURE_ID}-phase3.md`

---

### Phase 4 — Gate (inline)

Coverage gates are enforced inline: Phase 2 (L1 Gate — scope) + Phase 3 (per-endpoint coverage minimums per `§ 3.1`). No separate blocking phase.

**Release-readiness fields** (per `qa/verification-layers.md § 6` — write to frontmatter): set `gate_result` (PASS if every endpoint meets `§ 3.1` minimums, else FAIL) and `coverage_percentage` (endpoints meeting minimums ÷ total in `scope_final`). Required only when `release_id` is set; otherwise optional.

---

### Phase 5 — Output

- **5.0 Structure conformance check** — Before writing, validate the generated content against `template_structure_digest` (Phase 3, no re-read):
  - [ ] All required sections present in correct order
  - [ ] Frontmatter has all template keys (no missing/renamed field): `owner` = SE name from `tas.yaml` key `project.tech_lead` (immutable); `author`, `created_by` per [verification-layers.md § 5.1 Authorship & Audit Metadata](../../rules/qa/verification-layers.md#51-authorship--audit-metadata-canonical-) (git user, fallback to owner)
  - [ ] Coverage Matrix columns match template order
  - [ ] Change Log Author per [verification-layers.md § 5.1](../../rules/qa/verification-layers.md#51-authorship--audit-metadata-canonical-)
  - [ ] Every TC ID matches `test-id-convention.md § 3` format (MOD ∈ {H,E,S,N,B})

  Mismatch found → fix inline (mechanical, no ASK — this is conformance, not a judgment call). Do NOT proceed to 5.1 until all checks pass.

- **5.0a Auto-quote YAML-safe scalars** — Before writing (after conformance check passes):
  - `spec_source` + `code_path` fields MUST be double-quoted strings (per `API-Test-Spec.md` template comment)
  - **Mechanism:** escape any internal `"` as `\"`, then wrap value in `"..."`. Examples:
    - `spec_source: docs/feature/Feature-Technical.md (§API Spec)` → `spec_source: "docs/feature/Feature-Technical.md (§API Spec)"`
    - `code_path: app/api/[id]/route.ts, lib/schemas.ts` → `code_path: "app/api/[id]/route.ts, lib/schemas.ts"`
  - If either field is empty, leave as `""` (already quoted in template)
  - This is mechanical — no user input needed. Proceed to 5.1.

- **5.1 Write test spec file**

  **File doesn't exist:** Create new from template.

  **File exists (append mode):**
  - Read current file
  - Find section `## v{N}` being worked on
  - Append new test cases to end of section before `## Changelog`
  - Preserve all old content

  **Change Log (both CREATE and append/new-version):** append one row to `## Changelog` — Author = `git config user.name` output per [verification-layers.md § 5.1](../../rules/qa/verification-layers.md#51-authorship--audit-metadata-canonical-) procedure.

  **Checkpoint cleanup (after file written):** Delete `.tas/command-cache/apitest-plan-{FEATURE_ID}-phase*.md`. Print: `✅ Checkpoints cleaned. API Test Plan {FEATURE_ID} complete.`

- **5.2 Summary**

  Display:
  1. Output file path
  2. Number of endpoints in `scope_final`
  3. Number of test cases generated
  4. Coverage matrix
  5. Risk & Coverage Notes count (inherited + gaps)
  6. Cross-Feature Regression Watch row count (0 if no shared-contract/backward-compat trigger matched)
  7. Next steps:
     - Review test spec file
     - Run `/tas-apitest docs/tests/API-Test-Spec-{slug}.md` to generate code

  ```
  ## API Test Spec Generated

  **Output**: `docs/tests/API-Test-Spec-{slug}.md`
  **Version**: v{N}
  **Endpoints**: {N}
  **Test Cases**: {N}

  ### Coverage Matrix
  [Print coverage matrix]

  ### Next Steps
  1. Review test spec: `docs/tests/API-Test-Spec-{slug}.md`
  2. Generate test code: `/tas-apitest docs/tests/API-Test-Spec-{slug}.md`
  3. Run tests: `dotnet test tests/ApiTests/`
  ```

## Final Step — Token Log

Follow `.tas/rules/common/token-logging.md`: write AI Usage Log to test spec file.
