$npx -y skills add AdamBien/airails --skill ears-testsGenerate parameterized (table-driven) tests from EARS requirement statements — the deterministic transform that turns an SBCE capability spec's ## Requirements into one parameterized test per requirement group and one labeled row per statement id. Stack-neutral; owns only the E
| 1 | Turn EARS requirement statements into parameterized tests. The leverage is structural: every |
| 2 | EARS pattern is a `(condition → response)` tuple, and an SBCE requirement **group** already |
| 3 | collects statements that share **one boundary operation** — same arrange/act skeleton, only the |
| 4 | data differs. That is the textbook precondition for parameterization, so the mapping is mechanical. |
| 5 | |
| 6 | Own only the **transform and the trace**. The concrete test syntax is the composed stack skill's |
| 7 | call — never name a runner or framework verb here. When the generated tests exercise the running |
| 8 | system, the system-tests skill owns the contract (black box, coordinates as configuration, total |
| 9 | verdict reporting). |
| 10 | |
| 11 | ## The mapping |
| 12 | |
| 13 | - One requirement **group `Rn` → one parameterized test method** (the shared boundary op is the body). |
| 14 | - One **statement `Rn.m` → one row** in the parameter source. |
| 15 | - The **statement id `Rn.m` is the row's display name** — so the spec↔test binding stays per-statement |
| 16 | and grep-visible, exactly as SBCE requires (a removed id retires its row; a row with no statement is drift). |
| 17 | - The EARS pattern fixes the row's **role and shape** — you do not invent the columns, you read them off the pattern. |
| 18 | |
| 19 | ## EARS pattern → row shape |
| 20 | |
| 21 | The system is always **the BC**. Each pattern decomposes into the arrange/act/assert columns of a row: |
| 22 | |
| 23 | | Pattern | Statement shape | Arrange (state) | Act (trigger) | Assert (response) | Role | |
| 24 | |---|---|---|---|---|---| |
| 25 | | Event-driven | `When <trigger>, the BC shall <response>` | — | trigger | response | happy | |
| 26 | | Unwanted-behaviour | `If <trigger>, then the BC shall <response>` | — | bad/invalid trigger | rejection / error | unhappy | |
| 27 | | State-driven | `While <precondition>, the BC shall <response>` | precondition | (implicit) | response | stateful | |
| 28 | | Complex | `While <precondition>, when <trigger>, the BC shall <response>` | precondition | trigger | response | full tuple | |
| 29 | | Optional-feature | `Where <feature>, the BC shall <response>` | feature enabled | trigger | response | gated | |
| 30 | | Ubiquitous | `The BC shall <response>` | — | — | invariant | single case (least parameterizable — a plain test is fine) | |
| 31 | |
| 32 | Mixing a happy `When` row and an unhappy `If…then` row in the same group's table is the norm — it is |
| 33 | how one parameterized method covers both the success and the rejection path of one boundary op. |
| 34 | |
| 35 | ## Deterministic vs. authored |
| 36 | |
| 37 | EARS hands you the *enumeration*, not the *data*. Keep the two honestly separated so the generated |
| 38 | test never silently asserts an assumption: |
| 39 | |
| 40 | - **Deterministic (generate without judgment):** the method-per-group, the row-per-statement, the |
| 41 | `Rn.m` row labels, which boundary op the body calls, the row role from the pattern, and the |
| 42 | bijection check (every `Rn.m` ↔ exactly one row). |
| 43 | - **Authored (leave a clearly marked stub for human/LLM):** the concrete input fixture and the |
| 44 | assertion that expresses `<response>`. EARS abstracts the response in prose ("create and confirm |
| 45 | an order") and carries no values — do not fabricate them. Emit a failing/`TODO` stub a human or a |
| 46 | later `/sbce apply` pass fills, so an unwritten assertion shows up red, not green. |
| 47 | |
| 48 | ## Realization is the stack skill's call |
| 49 | |
| 50 | This skill is stack-neutral. The parameter-source mechanism and display-name form belong to the |
| 51 | composed stack skill — read `references/realizations.md` for the per-stack shape (JUnit 5 |
| 52 | `@ParameterizedTest` + `@MethodSource`, zunit's table form, Playwright `test.describe` per group). |
| 53 | Pick the one the project already uses; never introduce a second test idiom. |
| 54 | |
| 55 | ## Composition |
| 56 | |
| 57 | - **`/sbce`** owns the spec and the stable `Rn.m` ids — this skill consumes them; it never edits the |
| 58 | spec or coins ids. During `/sbce apply`, this is how the *spec→code* "a traceable test per `Rn.m`" |
| 59 | step is realized when a group has ≥2 statements. |
| 60 | - **`/bce`** owns where tests and the BC live; the **stack skill** owns the test syntax and the |
| 61 | "are you green?" oracle. |
| 62 | - Prefer a parameterized method only when a group has **≥2 statements**; a lone statement is |