Skip to content
Back to skills

Requirements Analysis

ASecurity

Reference only — the single definition of how requirements are analyzed before tests or stories are written — intake (text, issue, enhanced story, spec, exploration session, approved test plan) into one requirements model, the readiness gate (Missing Information, vague wording), requirement IDs (AC-NN from stories, R-NN derived from plain text), the scenario categories and tag mapping, and the per-element test checklists. Applied inline by e2e-session, write-tests, integration-tests and trace...

  • 5 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 11, 2026
testinggosqlapibackendsecurityperformance

Works with

  • api

Security analysis

A100/100

Scanned November 11, 2026

npx -y skills add GhassenAZZOUZ/claude-qa-agent --skill requirements-analysis --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Requirements Analysis?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Requirements Analysis
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ghassenazzouz-requirements-analysis/badge)](https://www.skillsdirectory.com/skills/ghassenazzouz-requirements-analysis)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: requirements-analysis
description: Reference only — the single definition of how requirements are analyzed before tests or stories are written — intake (text, issue, enhanced story, spec, exploration session, approved test plan) into one requirements model, the readiness gate (Missing Information, vague wording), requirement IDs (AC-NN from stories, R-NN derived from plain text), the scenario categories and tag mapping, and the per-element test checklists. Applied inline by e2e-session, write-tests, integration-tests and traceability; read by test-writer, user-story-enhancer and user-story-format. Not a workflow on its own.
---

# requirements-analysis

One set of rules for turning requirements into something testable. Skills
apply it inline; agents `Read` `${CLAUDE_PLUGIN_ROOT}/.claude/skills/requirements-analysis/SKILL.md`.
When a rule changes, change it here only.

## 1. Intake → requirements model

| Source | Requirement IDs | Scenario hints | Open questions |
|---|---|---|---|
| **Enhanced story**: a `user-story-format` body with an `## Acceptance Criteria` table | `AC-NN`, as written | its Gherkin ACs (and a legacy Test Scenarios table, if the story predates WAY 19) | its `## Missing Information` section |
| **Approved test plan** (`test-plan` skill format) | its `## Requirements` table, as written | its Planned tests rows: these **are** the scenarios, nothing is added | none: the plan passed the gate when it was designed |
| **Issue without an AC table** | `R-NN`, derived (§3) | — | derived (§2) |
| **Plain text** | `R-NN`, derived (§3) | — | derived (§2) |
| **OpenAPI spec only** | none: operations are the units, tests are `**Covers:** untraced` | the spec's operations; each request property and parameter is an element whose schema keywords are its stated limits (§5, OpenAPI schema constraints) | — |
| **Exploration session** (WAY 18 `session.yaml`) | `R-NN`, derived: one per completed flow not already covered, one per field's group of `validations`. They describe the app's **current** behavior, so the user confirms each is intended (§3) | the flow's steps and checkpoints, the validation inputs | none beyond that confirmation; anomalies are handled like bug reports |
| **Bug report** (WAY 3 regression test) | none: the one requirement is the bug's expected result, tests are `**Covers:** untraced` | the reproduction steps | `bug-report`'s own checks (it asks when Observe or the expected result is missing) |

A spec given **with** a story or text adds API context. The IDs still come from the story or text.

Extract, whatever the source:
- **Actors / roles** (guest, user, admin, another user…)
- **Data elements**: input fields, ID-based resources, file uploads, numeric fields, auth/session. From a spec: every request-body property, path, query and header parameter, with its schema keywords (`minLength`, `maximum`, `enum`, `pattern`, `required`…) as `limits`
- **Non-functional statements** with numbers (latency, size limits, browsers). Without a number, a statement goes to §2
- **Constraints** (business rules, limits, formats)

The model the caller passes to `test-writer`:

```yaml
source: "#148"          # or: text
ids: AC                 # AC | R | none
requirements:
  - id: AC-01
    text: A valid discount code reduces the order total
    priority: must      # AC: as written. R: must, unless the text marks it optional
actors: [shopper, guest]
elements:
  - { kind: input, name: discount code, limits: "1–20 chars" }
  - { kind: id, name: orderId }
nfr: [ "apply responds in < 1 s" ]
open_questions: []      # must be empty before tests are written (§2)
```

## 2. Readiness gate

Tests are not written on guesses. The gate applies to stories, issues and plain text; specs and bug reports skip it (§1). The requirements are **not ready** while any of these hold:

- The story's `## Missing Information` has an item other than `- none`
- An expected outcome can't be asserted ("works correctly", "is handled")
- A **vague word** decides an outcome without a measurable value: fast, quick, slow, easy, simple, intuitive, user-friendly, some, various, several, appropriate, reasonable, good, nice, normally, as needed, etc.
- Two statements contradict each other
- A permission rule names no actor ("only allowed users")

Each item becomes one question in `open_questions`. Missing non-functional requirements are **noted, not blocking**.

Who asks:
- **The WAY skill** (`e2e-session`, `write-tests`, `integration-tests` with `Issue:`) builds the model inline and asks the user **before** starting `test-writer`. One message holds the questions and, for `R-NN`, the requirements table (§3). Wait for answers, update the model, then start `test-writer`
- **`test-writer`** checks again. If it receives requirements that aren't ready (or plain text / an issue with no confirmed model), it doesn't write tests. It returns the questions and its proposed `R-NN` table to the caller
- **`user-story-enhancer`** (WAY 6) writes the questions into the story's `## Missing Information`. That's where they belong for a tracker story

## 3. Requirement IDs

**`AC-NN`**: owned by the story (`user-story-format`). Use them as written. Never renumber or invent one. A test that matches no AC is `**Covers:** untraced`.

**`R-NN`**: derived from plain text, or from an issue without ACs:
- One `R-NN` per **independently testable statement**: one actor, one action or condition, one observable outcome. Split "and" when the parts have different outcomes ("the link is emailed **and** expires after 1 hour" → two)
- Number from `R-01` in text order. Keep the user's wording. Don't add requirements the text doesn't state: those are open questions (§2) or `untraced` tests
- **Confirmed before use**: show the table with the gate questions, and apply the user's corrections
- **Persisted** in the test plan's `## Requirements` table and the test folder's index `.md`, right under the `**Source:**` line:

  ```markdown
  ## Requirements
  | ID | Requirement | Priority |
  |---|---|---|
  | R-01 | A user can request a reset link from the login page | must |
  | R-02 | The reset link is sent by email | must |
  | R-03 | The reset link expires after 1 hour | must |
  ```
- **Scoped to that folder**: `R-03` means R-03 of that folder's index
- **Stable**: when tests are added to a folder that already has a Requirements table, keep its IDs and append new ones
- **Never mixed with ACs**: a folder uses one scheme. If the source story later gets ACs (WAY 6), the ACs win. `traceability` then reports the R-NN tests as untraced against the story, and offers `write it <ref>` to re-trace them

Tests cite IDs the same way in both schemes: `**Covers:** R-01, R-03` in `Test#<nn>.md`, and `# Test#<nn> | R-03: <short title>` above the Gherkin scenario.

## 4. Scenario categories

One list, used by test-writer's scenarios **and** the test plan's Category column (`test-plan` skill):

| Category | Meaning | Gherkin tags | When it's required |
|---|---|---|---|
| `happy_path` | the primary success flow | `@positive` | every requirement |
| `negative` | invalid input or a forbidden action, with the rejection asserted | `@negative` | every requirement that takes input or an action |
| `edge_case` | valid but extreme input or state | `@edge-case` | when §5 lists one for an element involved |
| `boundary` | at and just beyond a stated limit, on **both** sides (min and max) | `@boundary` (often an Outline) | every stated limit, including each spec schema keyword in §5 |
| `security` | injection, XSS, IDOR, auth bypass, data exposure | `@security @negative` | any input field, ID-based resource, or authenticated action |
| `permissions` | each actor/role gets exactly its access | `@auth` (`@negative` for the denials) | more than one actor, or a resource with an owner |
| `performance` | a stated latency or load target | `@performance` | only when a non-functional statement gives a number |

Each scenario becomes one `Test#<nn>`, or one `Examples` row when ≥ 2 variants share a flow.

## 5. Checklists by element

For every element in the model, cover each applicable line. Each is a scenario (or an `Examples` row) in `test-writer`, and a gap to report in `user-story-enhancer` when the story's ACs leave it unspecified.

| Element | Cover |
|---|---|
| **Input field** | empty · whitespace only · min length - 1 · min length (when a minimum is stated) · max length · max length + 1 · special characters / unicode · unexpected format · SQL injection · XSS payload |
| **ID-based resource** | valid · invalid format · non-existent · another user's (IDOR) · deleted |
| **File upload** | valid · empty file · oversized · wrong MIME type · malicious filename |
| **Numeric field** | min - 1 · min (0 and -1 when no minimum is stated) · max · max + 1 · decimal where an integer is expected · non-numeric |
| **Auth / session** | guest · expired session or token mid-flow · insufficient role |
| **Concurrency**: only when two actors or tabs can change the same resource | double submit · simultaneous edit (last write, or a conflict error, as specified) |
| **Failure of a backend call**: only for actions that call one (submit, pay, save) | a failed or slow response shows an error and doesn't hang · retrying creates no duplicate |

### OpenAPI schema constraints

For a spec, each request property and parameter is an element, and each keyword it carries is a stated limit. One `@boundary` Scenario Outline per property, with an `expected status` column: values inside the limit → the documented 2xx, values outside → 4xx (400 or 422, as documented), **never 5xx**.

| Keyword | Rows |
|---|---|
| `minLength` / `maxLength` | min - 1 · min · max · max + 1 characters (no min - 1 when min is 0) |
| `minimum` / `maximum` | min - 1 step · min · max · max + 1 step (step = 1 for `integer`, `multipleOf` or 0.01 for `number`) |
| `exclusiveMinimum` / `exclusiveMaximum` | the bound itself (rejected) · one step inside (accepted). OAS 3.0 sets it as a boolean on `minimum`/`maximum`, 3.1 as the bound's value |
| `minItems` / `maxItems` | min - 1 · min · max · max + 1 items |
| `pattern` | one matching value · one value that is valid in every way except the pattern |
| `enum` | every allowed value (one row each) · one value outside the set · a case variant of an allowed value |
| `format` (`email`, `date`, `date-time`, `uuid`, `uri`) | one valid value · one malformed value |
| `required` | absent · `null` · empty (`""`, `[]` or `{}`, by type): three separate rows, because APIs often treat them differently |
| not `nullable` (no `null` in `type`) | `null` → 4xx |
| `type` | one value of the wrong type |
| `default` | property absent → the default applies (assert it on the response or a read) |
| `additionalProperties: false` | one unknown property → 4xx |

Put JSON literals in the Examples column (`"AB"`, `91`, `null`) and the placeholder unquoted in the body (`{ "code": <code> }`), so `null` and numbers keep their type. The `required` "absent" row is its own Scenario, since an Outline row can't drop a key. Change only the property under test per row: every other property stays at a valid value.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in testing →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.