yadflow 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: yad-connect-testing
3
+ description: 'Connects a testing tool (Playwright, or another tool — pluggable) to the product hub so the test-cases step can implement the actual automation tests, not just Markdown test cases. Registers the tool into the project-wide .sdlc/testing.json (local-user / MCP-session auth, no stored tokens), detecting whether a testing-tool MCP is available and degrading to artifacts-only when it is not. Run at setup or any time the testing tool changes. Reusable, idempotent, refreshable. Use when the user says "connect Playwright", "connect a testing tool", "refresh the testing connection", or "list the testing connection".'
4
+ ---
5
+
6
+ # SDLC — Connect a Testing Tool (make the test-cases step automation-aware)
7
+
8
+ **Goal:** Let the test-cases step (`yad-test-cases`) produce the **actual automation tests** — the
9
+ runnable specs in a connected code repo — alongside the Markdown artifact (`test-cases.md`). This skill
10
+ **connects** a testing tool such as **Playwright** to the product hub and records *how* to reach it (the
11
+ tool, the suite references, which MCP runs it) — never a credential.
12
+
13
+ This is **setup/maintenance**, not a gated front state — it never touches `.sdlc/state.json` or any
14
+ epic's approvals. It only writes the project-wide testing registry. `yad-test-cases` consumes it: when a
15
+ tool is connected and its MCP is available, the `test architect` lens **generates** automation tests
16
+ into the connected repo(s) (or **links** an existing suite and reads it back); when nothing is
17
+ connected, `yad-test-cases` runs artifacts-only exactly as before.
18
+
19
+ ## Conventions
20
+
21
+ - `{project-root}` resolves from the project working directory (the **product hub**).
22
+ - The integration is **Playwright-first but pluggable** (`config.yaml` `testing.tools`): a testing-tool
23
+ *adapter*, like the GitHub/GitLab platform adapter or the design-tool adapter. Playwright is the
24
+ primary provider; `cypress` and `pytest` are second providers; `none` → artifacts-only.
25
+ - **The testing tool is reached through its MCP** (a harness MCP server), NOT a subprocess CLI — the
26
+ same shape as the design tool's MCP, not Repomix's `npx`. The skill detects the MCP and degrades when
27
+ it is absent; it never installs an MCP server.
28
+ - Registry: `{project-root}/.sdlc/testing.json` (project-wide, shared across all epics — NOT per-epic),
29
+ the sibling of `.sdlc/repos.json`, `.sdlc/hub.json`, and `.sdlc/design.json`.
30
+ - Per-epic test→suite links are written later by `yad-test-cases`
31
+ (`epics/EP-<slug>/.sdlc/test-links.json`), not here.
32
+ - Speak in the configured `communication_language`; write documents in `document_output_language`.
33
+
34
+ ## Inputs
35
+
36
+ - `action` — `connect` (default) | `refresh` | `list` | `disconnect`.
37
+ - `tool` — `playwright` | `cypress` | `pytest` | another adapter id (`config.yaml` `testing.tools`).
38
+ `none` records a deliberate artifacts-only project.
39
+ - `project_url` — the testing tool's project/config reference (e.g. a `playwright.config.ts` path or a
40
+ test-runner project URL). Optional — a connection with no suite yet is valid; `yad-test-cases` can
41
+ create one on first generate.
42
+ - `suites` — optional default suite mapping per repo (`{ <repo>: <ref> }`).
43
+
44
+ ## On Activation
45
+
46
+ ### Step 1 — Resolve the tool and its MCP (the testing-tool adapter)
47
+ Determine which tool is being connected from `tool` (default `playwright`); reject a `tool` not in
48
+ `config.yaml` `testing.tools` (fall back to the configured `testing.primary` with a warning, the same
49
+ way `registerRepo` falls back on an unknown platform). Then **detect the tool's MCP** in this harness:
50
+
51
+ - **playwright** → a Playwright MCP server (drives a browser, generates/runs E2E + API specs).
52
+ - **cypress** → the Cypress MCP (generate/run Cypress specs).
53
+ - **pytest** → a pytest MCP (generate/run service-layer tests).
54
+ - another adapter → its named MCP.
55
+
56
+ Record `provider` (the concrete MCP, e.g. `playwright-mcp` | `cypress-mcp` | `pytest-mcp`) and whether
57
+ it is available. **Auth is the local user's own** — the user's authenticated MCP session. The skill
58
+ **stores no tokens**; `project_url`/`suites` are plain references, never credentials.
59
+
60
+ **Graceful degradation:** if no testing-tool MCP is available, record `source: "unavailable"` and report
61
+ that `yad-test-cases` will run **artifacts-only** until an MCP is connected (no error — the testing tool
62
+ is purely additive, exactly like the design tool being absent). Do **not** install an MCP server as part
63
+ of this step.
64
+
65
+ ### Step 2 — Record the connection in the registry
66
+ Upsert into `{project-root}/.sdlc/testing.json` (create the file + parent `.sdlc/` if absent):
67
+
68
+ ```json
69
+ {
70
+ "tool": "playwright",
71
+ "provider": "playwright-mcp",
72
+ "project_url": "tests/playwright.config.ts",
73
+ "auth": "user",
74
+ "suites": { "backend": null, "mobile": null },
75
+ "connectedAt": "<YYYY-MM-DD>",
76
+ "lastSyncedAt": "<YYYY-MM-DD>",
77
+ "source": "playwright-mcp"
78
+ }
79
+ ```
80
+
81
+ - `tool: "none"` records a deliberate artifacts-only project: `{ "tool": "none", "provider": null,
82
+ "source": "unavailable", ... }`.
83
+ - `connect` is **idempotent** — re-running it overwrites the single connection in place (a project has
84
+ one testing tool at a time; switching tools is just another `connect`).
85
+
86
+ ### Step 3 — Report (never auto-advance)
87
+ Report the connected `tool`, its `provider`, whether the MCP is available (or that `yad-test-cases` will
88
+ degrade to artifacts-only), the `project_url`, and that **`yad-test-cases` will now generate/link the
89
+ automation tests here**. Nothing auto-advances; this is setup.
90
+
91
+ ## Other actions
92
+
93
+ - **`refresh`** — re-detect the MCP and update `lastSyncedAt` (after the user authenticates a session or
94
+ changes tools). Same machinery as `connect`. Re-detection may flip `source` between an MCP id and
95
+ `unavailable` — report the change.
96
+ - **`list`** — print the current connection: `tool`, `provider`, `project_url`, the suite mapping, and a
97
+ **available/unavailable** flag for the MCP (best-effort, the user's own session). No testing tool
98
+ connected ⇒ "artifacts-only".
99
+ - **`disconnect`** — remove the registry file (or set `tool: "none"`). The testing tool's own
100
+ project/suites are **never touched** — only the hub's record of them.
101
+
102
+ ## Hard rules
103
+
104
+ - **Local-user / MCP-session auth only; store no tokens.** Connect through the user's authenticated MCP
105
+ session; never embed a token or any credential in the registry. `project_url`/`suites` are plain
106
+ references.
107
+ - **Degrade gracefully.** No testing tool / no MCP → `yad-test-cases` runs artifacts-only with no error.
108
+ The testing tool is additive, never a blocker — the same discipline as the design tool and Impeccable.
109
+ - **Setup, not a gate.** Never touch `.sdlc/state.json`, approvals, or the contract lock from here.
110
+ - **Idempotent + refreshable.** `connect`/`refresh` are safe to re-run; a project carries one testing
111
+ connection at a time.
112
+ - **Describe the connection; do not author tests here.** This skill records *how to reach* the tool. The
113
+ actual automation tests are generated/linked by `yad-test-cases`, per epic.
114
+
115
+ ## Reference
116
+ - Registry schema + freshness rule: `references/testing-registry.md`.
117
+ - MCP detection per provider, the generate-vs-link recipes, the degrade path, and the honest
118
+ write-vs-read-only MCP capability note: `references/testing-context.md`.
119
+ - The connect pattern this mirrors (design tool): `../yad-connect-design/SKILL.md`.
120
+ - The consumer — how `yad-test-cases` generates/links and writes `test-links.json`:
121
+ `../yad-test-cases/SKILL.md`.
@@ -0,0 +1,67 @@
1
+ # Testing context — MCP detection, generate vs link, and the degrade path
2
+
3
+ How a connected testing tool turns into the actual automation tests the test-cases step materializes.
4
+ The testing tool is reached through its **MCP** (a harness MCP server), the same shape as the design
5
+ tool — detect it, use it when present, degrade cleanly when absent. This is the testing-side analogue of
6
+ `yad-connect-design`'s design-context.
7
+
8
+ ## Provider detection
9
+
10
+ `connect`/`refresh` records `provider` (the concrete MCP) and `source` (the MCP id, or `unavailable`).
11
+ Detection is best-effort against the user's own authenticated MCP session:
12
+
13
+ | `tool` | MCP / provider | Capability |
14
+ |--------|----------------|------------|
15
+ | `playwright` | a Playwright MCP | **generate** — author + run E2E/API specs against the app |
16
+ | `cypress` | the Cypress MCP | **generate** — author + run Cypress specs |
17
+ | `pytest` | a pytest MCP | **generate** — author + run service-layer tests |
18
+ | any | a read-only runner MCP | **link** — reference an existing suite and read results back |
19
+ | other | the adapter's named MCP | per that adapter |
20
+
21
+ **Honest capability note:** not every testing-tool MCP can *write* tests. A read-only runner MCP
22
+ supports **link + read-back** only; *generate* needs a write-capable provider. `yad-test-cases` picks
23
+ the direction the connected provider actually supports and records which one it used
24
+ (`direction: generated | linked`). It never claims to have generated tests a read-only MCP cannot
25
+ produce.
26
+
27
+ ## Generate (write automation tests into the repo)
28
+
29
+ When the connected provider is write-capable, the `test architect` lens (Murat, `bmad-tea` +
30
+ `bmad-testarch-automate`) produces the epic's automation tests in the connected code repo(s), covering
31
+ the cases `test-cases.md` enumerates and the acceptance criteria the stories define:
32
+
33
+ - **Playwright** — the lens authors `*.spec.ts` E2E/API specs (reusing the repo's existing fixtures and
34
+ the code-maps from `yad-test-cases` Step 2b), one spec per high-priority (P0/P1) case, and runs them
35
+ via the MCP to confirm they execute.
36
+ - **Cypress / pytest** — the lens authors the equivalent specs in that framework's layout.
37
+
38
+ Reuse what already exists: load the connected code repos' code-maps (`yad-test-cases` Step 2b) so
39
+ generated tests target real endpoints/components, not invented ones, and prefer the lowest useful test
40
+ level (unit > integration > E2E) per Murat's principles.
41
+
42
+ ## Link (reference an existing suite)
43
+
44
+ When a suite already exists (or the provider is read-only), point `yad-test-cases` at it and **read the
45
+ suite back** so `test-cases.md` reflects the real tests: list each test as a case, capture its
46
+ path/name + URL, and map it to the story it covers.
47
+
48
+ ## Write back the linkage (done by `yad-test-cases`, per epic)
49
+
50
+ Either direction ends by writing `epics/EP-<slug>/.sdlc/test-links.json` — the machine-readable
51
+ case→test map — and a `## Automation (<tool>)` section in `test-cases.md` linking each case to its test.
52
+ The tests themselves live in the code repo; the hub keeps the *links* and the Markdown spec beside the
53
+ other epic artifacts.
54
+
55
+ ## Degrade path (no MCP / no tool)
56
+
57
+ If `testing.json` is absent, `tool: "none"`, or `source: "unavailable"`, `yad-test-cases` runs
58
+ **artifacts-only**: it authors `test-cases.md` exactly as before and records `testing: none` in the
59
+ frontmatter with a one-line note (mirroring the `design: none` degrade). No error — the testing tool is
60
+ purely additive.
61
+
62
+ ## Staleness / refresh
63
+
64
+ A re-generated or hand-edited suite is like a moved code repo: `yad-test-cases` **flags** a divergence
65
+ and lets a human decide (re-run the step, or `yad-connect-testing` action: refresh). It never silently
66
+ overwrites a hand-written suite — refreshing the automation is a human decision, the same discipline as
67
+ `code_context.refresh: human`.
@@ -0,0 +1,55 @@
1
+ # Testing registry — schema + freshness rule
2
+
3
+ The registry is the product hub's record of which testing tool is connected and how to reach it. It is
4
+ **project-wide** (one testing tool per project, shared across every epic), so it lives at the product
5
+ root, not under any `epics/EP-<slug>/.sdlc/`.
6
+
7
+ ## Location
8
+
9
+ `{project-root}/.sdlc/testing.json`
10
+
11
+ (`config.yaml` `testing.registry`.) Create the file and its parent `.sdlc/` on the first `connect`.
12
+
13
+ ## Schema
14
+
15
+ ```json
16
+ {
17
+ "tool": "playwright", // playwright | cypress | pytest | <adapter id> | none (artifacts-only)
18
+ "provider": "playwright-mcp", // the concrete MCP: playwright-mcp | cypress-mcp | pytest-mcp | null
19
+ "project_url": "tests/playwright.config.ts", // project/config reference; null if none yet
20
+ "auth": "user", // ALWAYS the user's own MCP session — never a token
21
+ "suites": { "backend": null, "mobile": null }, // optional default suite refs per repo
22
+ "connectedAt": "2026-06-13", // first connect (YYYY-MM-DD)
23
+ "lastSyncedAt": "2026-06-13", // last connect/refresh
24
+ "source": "playwright-mcp" // the MCP detected at connect | unavailable (degraded)
25
+ }
26
+ ```
27
+
28
+ ## Rules
29
+
30
+ - **`tool`** selects the adapter; it MUST be one of `config.yaml` `testing.tools` (or `none`). At
31
+ **connect** time an unknown tool is normalized to `testing.primary` with a warning (so the registry
32
+ never persists an unknown value); a registry hand-edited to an unknown or missing tool **fails
33
+ `doctor`** with `YAD-CFG-003` and must be fixed.
34
+ - **Auth is never stored.** No token, API key, or any credential in the registry. `project_url` and
35
+ `suites` are plain references; `connect` reaches the tool through the user's authenticated MCP session.
36
+ - **`connect` overwrites in place** — a project carries exactly one testing connection at a time;
37
+ switching tools is just another `connect`. There is no array (unlike `repos.json`).
38
+ - **`source`** is the authority for availability: an MCP id (`playwright-mcp` / `cypress-mcp` / …) means
39
+ `yad-test-cases` can generate/link; `unavailable` means `yad-test-cases` degrades to artifacts-only.
40
+ `refresh` re-detects and may flip it.
41
+ - **`tool: "none"`** is a valid, deliberate state: a project that has chosen artifacts-only.
42
+ `yad-test-cases` treats it exactly like an absent registry.
43
+ - **`disconnect`** removes the file (or sets `tool: "none"`). The testing tool's own project/suites are
44
+ never touched.
45
+
46
+ ## Git tracking
47
+
48
+ Commit the **registry** (`testing.json`) — it is small, reviewable, and holds no secrets (references
49
+ only). This mirrors how `repos.json`, `hub.json`, and `design.json` are committed.
50
+
51
+ ## Greenfield
52
+
53
+ A brand-new product hub has no `testing.json`. That is valid — `yad-test-cases` treats "no testing tool
54
+ connected" the same as `tool: "none"` and produces the Markdown test-case artifact only. The registry
55
+ appears the first time `connect` runs.
@@ -14,7 +14,7 @@ drafted, control passes to `yad-review-gate`.
14
14
  - **Analysis ran** — `.sdlc/state.json` already exists with `currentStep == "epic"`. The epic **reads
15
15
  `analysis.md`** as its shaped input and does not re-seed state.
16
16
  - **Analysis skipped** (the default) — no `state.json` yet. The epic is the entry point: it shapes the
17
- idea inline with the analyst, assigns `EP-<slug>`, and seeds the **8-step** chain.
17
+ idea inline with the analyst, assigns `EP-<slug>`, and seeds the **10-step** chain.
18
18
 
19
19
  This skill enforces the build plan's core rules: all state lives in files; IDs are generated by the
20
20
  engine (never typed by hand); front steps are locked to `human_approve`.
@@ -105,9 +105,9 @@ Fill the body with the user; leave `owner` / `technical_product_owner` for the u
105
105
  `repos` to the repos this epic will touch.
106
106
 
107
107
  ### Step 5 — Seed the state machine — analysis-skipped only
108
- *(Skip when analysis ran — `yad-analysis` already seeded the 10-step chain. Go to Step 5b.)*
109
- Create `{project-root}/epics/EP-<slug>/.sdlc/state.json` describing the full **8-step** front-state
110
- sequence (no analysis), all steps defaulting to `automation: human_approve`, with the four authoring
108
+ *(Skip when analysis ran — `yad-analysis` already seeded the 12-step chain. Go to Step 5b.)*
109
+ Create `{project-root}/epics/EP-<slug>/.sdlc/state.json` describing the full **10-step** front-state
110
+ sequence (no analysis), all steps defaulting to `automation: human_approve`, with the five authoring
111
111
  steps **locked**. Use this exact shape (see `references/state-schema.md`):
112
112
 
113
113
  ```json
@@ -123,7 +123,9 @@ steps **locked**. Use this exact shape (see `references/state-schema.md`):
123
123
  { "id": "ui-design", "type": "author", "artifact": "ui-design.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
124
124
  { "id": "ui-design-review", "type": "review+approve", "artifact": "ui-design.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
125
125
  { "id": "stories", "type": "author", "artifact": "stories/", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
126
- { "id": "stories-review", "type": "review+approve", "artifact": "stories/", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] }
126
+ { "id": "stories-review", "type": "review+approve", "artifact": "stories/", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
127
+ { "id": "test-cases", "type": "author", "artifact": "test-cases.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
128
+ { "id": "test-cases-review", "type": "review+approve", "artifact": "test-cases.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] }
127
129
  ]
128
130
  }
129
131
  ```
@@ -131,6 +133,9 @@ steps **locked**. Use this exact shape (see `references/state-schema.md`):
131
133
  Notes:
132
134
  - `architecture-review` carries `risk_tags: ["contract"]` so the gate escalates it by default
133
135
  (build plan §4): the contract review needs domain owners, not just owner + 1.
136
+ - `test-cases` / `test-cases-review` are a **parallel, non-blocking track**: they seed `blocked` and open
137
+ when `stories-review` passes — at which point the epic is already `ready-for-build`, so the build half
138
+ runs alongside the tester. They never gate `ready-for-build` (see `references/state-schema.md`).
134
139
  - Also create an empty approvals ledger `{project-root}/epics/EP-<slug>/.sdlc/approvals.json`
135
140
  and an empty comments ledger `{project-root}/epics/EP-<slug>/.sdlc/comments.json`, each containing
136
141
  `[]`, and the `reviews/` directory. (`comments.json` is the machine-readable counterpart to the
@@ -17,7 +17,7 @@ Each `steps[]` entry:
17
17
 
18
18
  | Field | Values | Meaning |
19
19
  |-------|--------|---------|
20
- | `id` | `analysis`, `analysis-review`, `epic`, `epic-review`, `architecture`, `architecture-review`, `ui-design`, `ui-design-review`, `stories`, `stories-review` | Step identity. |
20
+ | `id` | `analysis`, `analysis-review`, `epic`, `epic-review`, `architecture`, `architecture-review`, `ui-design`, `ui-design-review`, `stories`, `stories-review`, `test-cases`, `test-cases-review` | Step identity. |
21
21
 
22
22
  ### Two valid chain shapes (analysis is optional)
23
23
 
@@ -26,20 +26,37 @@ ran `yad-analysis` before the epic. The entry-point skill (whichever runs first)
26
26
  that assigns `EP-<slug>` and seeds `state.json` + the empty ledgers; the other skill detects an
27
27
  existing `state.json` and does **not** re-seed.
28
28
 
29
- - **With analysis** (10 steps — `yad-analysis` seeded the chain):
29
+ - **With analysis** (12 steps — `yad-analysis` seeded the chain):
30
30
  `analysis → analysis-review → epic → epic-review → architecture → architecture-review → ui-design →
31
- ui-design-review → stories → stories-review`. Seeded `currentStep` is `analysis-review`; `epic`
32
- starts `blocked`.
33
- - **Without analysis** (8 steps — `yad-epic` is the entry point, the default):
34
- `epic → epic-review → … → stories-review`. Seeded `currentStep` is `epic-review`.
35
-
36
- After `stories-review` passes, `currentStep` becomes the `ready-for-build` sentinel either way.
37
- `analysis-review` carries no `risk_tags` (base rule: owner + 1 reviewer).
31
+ ui-design-review → stories → stories-review test-cases test-cases-review`. Seeded `currentStep`
32
+ is `analysis-review`; `epic` starts `blocked`.
33
+ - **Without analysis** (10 steps — `yad-epic` is the entry point, the default):
34
+ `epic → epic-review → … → stories-review → test-cases → test-cases-review`. Seeded `currentStep` is
35
+ `epic-review`.
36
+
37
+ `analysis-review`, `ui-design-review`, and `test-cases-review` carry no `risk_tags` (base rule:
38
+ owner + 1 reviewer).
39
+
40
+ ### `test-cases` is a parallel, non-blocking track
41
+
42
+ `test-cases` (and its `test-cases-review` gate) sit in `steps[]` after `stories-review`, but they are a
43
+ **parallel track that does not gate the build half**. When `stories-review` passes, `advanceState`:
44
+ - sets `currentStep` to the **`ready-for-build`** sentinel — so the build half (`yad-spec` → … keyed off
45
+ `currentStep == "ready-for-build"`) can start **immediately**, and
46
+ - opens `test-cases` (`blocked` → `in_progress`) so the tester can work **in parallel**.
47
+
48
+ The `test-cases` track is therefore driven by its own step `status`, **not** by `currentStep`:
49
+ `yad-test-cases` proceeds when `test-cases.status == "in_progress"`, and neither it nor the
50
+ `test-cases-review` gate (`advanceState` / `markInReview`) ever moves `currentStep` away from
51
+ `ready-for-build`. So implementation and test-case authoring run at the same time; the epic is
52
+ `ready-for-build` the moment the **stories** gate passes, whether or not test cases are done. (For an old
53
+ epic seeded before this step existed, `stories-review` → `ready-for-build` with no test-cases track —
54
+ unchanged.)
38
55
 
39
56
  ### Authoring branches
40
57
 
41
58
  Each front **authoring** step opens its own git branch at the start of the step, named
42
- `<step>/EP-<slug>` where `<step>` ∈ `analysis | epic | architecture | ui-design | stories`
59
+ `<step>/EP-<slug>` where `<step>` ∈ `analysis | epic | architecture | ui-design | stories | test-cases`
43
60
  (`config.yaml` `defaults.front_authoring_branch`). This is **distinct** from the review branch
44
61
  `review/EP-<slug>/<artifact-base>` that `yad-hub-bridge` opens later for the review PR/MR.
45
62
 
@@ -86,6 +103,33 @@ PR/MR opened on the hub (sibling of `approvals.json`, so the locked `state.json`
86
103
  { "step": "<review step id>", "artifact": "<artifact>", "platform": "github|gitlab", "number": <n>, "url": "<pr/mr url>", "branch": "review/EP-<slug>/<artifact-base>", "lastSyncedAt": "<YYYY-MM-DD or null>" }
87
104
  ```
88
105
 
106
+ ## `design-links.json`
107
+ Present only when the `ui-design` step materialized the design in a connected design tool
108
+ (`yad-connect-design` → `.sdlc/design.json`). Written by `yad-ui`, the machine-readable screen→frame map
109
+ (sibling of `contract-lock.json`; the locked `state.json` step shape is untouched). The `ui-design` step
110
+ chain is unchanged — this is an *output enrichment*, mirrored by the `design:` frontmatter block and the
111
+ `## Design (<tool>)` section in `ui-design.md`. Absent when the step ran markdown-only (`design: none`).
112
+
113
+ ```json
114
+ { "tool": "figma", "fileUrl": "<url>", "generatedAt": "<YYYY-MM-DD>", "direction": "generated|linked",
115
+ "screens": [ { "name": "<screen>", "platform": "mobile|web", "nodeId": "<id>", "url": "<frame url>" } ],
116
+ "source": "<mcp id>" }
117
+ ```
118
+
119
+ ## `test-links.json`
120
+ Present only when the `test-cases` step materialized automation in a connected testing tool
121
+ (`yad-connect-testing` → `.sdlc/testing.json`). Written by `yad-test-cases`, the machine-readable
122
+ case→test map (sibling of `contract-lock.json` / `design-links.json`; the locked `state.json` step shape
123
+ is untouched). The `test-cases` step chain is unchanged — this is an *output enrichment*, mirrored by the
124
+ `testing:` frontmatter block and the `## Automation (<tool>)` section in `test-cases.md`. Absent when the
125
+ step ran artifacts-only (`testing: none`).
126
+
127
+ ```json
128
+ { "tool": "playwright", "suite": "<url/path>", "generatedAt": "<YYYY-MM-DD>", "direction": "generated|linked",
129
+ "tests": [ { "case": "<id>", "story": "EP-<slug>-S0N", "repo": "<name>", "level": "unit|integration|e2e", "path": "<test path>", "url": "<url>" } ],
130
+ "source": "<mcp id>" }
131
+ ```
132
+
89
133
  ## `reviews/`
90
134
  Human-readable review records, one file per round:
91
135
  `reviews/<artifact-base>--<YYYY-MM-DD>--<status>.md` where `status` ∈ `comments` | `approved`
@@ -93,7 +137,7 @@ and `<artifact-base>` is the artifact without extension (e.g. `epic`, `architect
93
137
 
94
138
  ## Dial defaults & locks
95
139
  - Every step defaults to `automation: human_approve` (build plan §2).
96
- - The four authoring front steps and their reviews are `locked: true` — the engine refuses to set
140
+ - The five authoring front steps and their reviews are `locked: true` — the engine refuses to set
97
141
  them to `machine_advance` in this version (build plan §1, §8.7). Only back states (build pipeline,
98
142
  steps 9–14) may move toward machine-advance in a later iteration.
99
143
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yad-hub-bridge
3
- description: 'The templated PR/MR bridge for the front-half review gate. When the product hub has a platform (.sdlc/hub.json), it opens a review PR/MR on the hub for an authored artifact (the optional analysis / epic / architecture+contract / ui-design / stories), sets the required reviewers/labels from the routing rule, and provides the read-only gh/glab recipes that yad-review-gate uses to pull platform comments + approvals back into the file ledger. Can also wire event-driven sync on the hub: a CI workflow that runs `yad gate ci` whenever a reviewer approves / requests changes / a human merges, committing the ledger to the default branch. Local-user auth only — no stored tokens. The file ledger stays the source of truth; degrades to the file-only gate when there is no platform / no CLI. Use when the user says "open the review PR", "route the review", "wire the gate sync", or it is invoked by yad-review-gate open/sync.'
3
+ description: 'The templated PR/MR bridge for the front-half review gate. When the product hub has a platform (.sdlc/hub.json), it opens a review PR/MR on the hub for an authored artifact (the optional analysis / epic / architecture+contract / ui-design / stories / test-cases), sets the required reviewers/labels from the routing rule, and provides the read-only gh/glab recipes that yad-review-gate uses to pull platform comments + approvals back into the file ledger. Can also wire event-driven sync on the hub: a CI workflow that runs `yad gate ci` whenever a reviewer approves / requests changes / a human merges, committing the ledger to the default branch. Local-user auth only — no stored tokens. The file ledger stays the source of truth; degrades to the file-only gate when there is no platform / no CLI. Use when the user says "open the review PR", "route the review", "wire the gate sync", or it is invoked by yad-review-gate open/sync.'
4
4
  ---
5
5
 
6
6
  # SDLC — Hub Review Bridge (the templated PR/MR bridge)
@@ -29,7 +29,7 @@ keeps platform mechanics out of the gate). `yad-review-gate` *calls* it; it neve
29
29
  ## Inputs
30
30
 
31
31
  - `epic` — the `EP-<slug>` under review.
32
- - `artifact` — the artifact file (`analysis.md` | `epic.md` | `architecture.md` | `ui-design.md` | `stories/`).
32
+ - `artifact` — the artifact file (`analysis.md` | `epic.md` | `architecture.md` | `ui-design.md` | `stories/` | `test-cases.md`).
33
33
  - `action` — `open` | `route` | `wire` (default `route`). (`sync`'s ledger writes live in
34
34
  `yad-review-gate`; this skill provides the read recipes `sync` calls — see `references/bridge.md`.)
35
35
 
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  name: yad-review-gate
3
- description: 'The reusable team review + approve gate for the SDLC. Shares an authored artifact for review, records reviewer comments and approvals as files, enforces the owner + 1 reviewer rule (escalating to domain owners on contract/auth/payments), and advances the epic state ONLY when approval is recorded. Use when the user says "review the analysis/epic/architecture/UI/stories", "comment", "approve", or "advance the gate".'
3
+ description: 'The reusable team review + approve gate for the SDLC. Shares an authored artifact for review, records reviewer comments and approvals as files, enforces the owner + 1 reviewer rule (escalating to domain owners on contract/auth/payments), and advances the epic state ONLY when approval is recorded. Use when the user says "review the analysis/epic/architecture/UI/stories/test-cases", "comment", "approve", or "advance the gate".'
4
4
  ---
5
5
 
6
6
  # SDLC — Team Review Gate (build plan §3 piece 2, §4, §5)
7
7
 
8
8
  **Goal:** One reusable step type that turns any authored artifact into a gated, human-approved
9
9
  review. Every `review+approve` step in the workflow (the optional analysis, epic, architecture+contract,
10
- UI, stories) uses this exact gate. **No step advances until its review is approved** and recorded as a
11
- file. The `analysis-review` and `epic`/`ui-design` reviews use the **base** rule (owner + 1 reviewer);
12
- escalation applies only where `risk_tags` or per-repo routing call for it.
10
+ UI, stories, test-cases) uses this exact gate. **No step advances until its review is approved** and
11
+ recorded as a file. The `analysis-review`, `epic`/`ui-design`, and `test-cases` reviews use the **base**
12
+ rule (owner + 1 reviewer); escalation applies only where `risk_tags` or per-repo routing call for it.
13
13
 
14
14
  This gate is **swappable and file-driven**: it talks only through files. A front step advances only on a
15
15
  human act — recording an approval and `advance`, or (with the bridge) **merging the approved,
@@ -87,7 +87,7 @@ counterpart to `approvals.json`):
87
87
  Then help the **owner address the comments** using the agent lens listed for this step
88
88
  (analysis → `analyst`; epic → `pm`; architecture → `architect`; ui-design → `ux-designer`;
89
89
  stories → `pm`, with `architect` for technical detail — there is **no `sm` agent**, Phase 0
90
- Deviation 1). Update the authored artifact in place.
90
+ Deviation 1; test-cases → `test architect` / Murat, `bmad-tea`). Update the authored artifact in place.
91
91
  Repeat comment→address rounds until reviewers are satisfied. **Commenting never advances the gate.**
92
92
 
93
93
  **`approve`** — Record an approval. Append to `.sdlc/approvals.json`:
@@ -153,13 +153,16 @@ If the predicate **fails**: report exactly which approvals are still missing and
153
153
 
154
154
  If the predicate **passes**:
155
155
  - Mark this review step `status: "done"`.
156
- - If there **is** a next step in `steps[]`: set it `status` from `blocked` to `in_progress`
157
- (authoring) or `in_review`, and set `currentStep` to that next step.
158
- - If this is the **last** step (`stories-review`, the final review): there is no further front step —
159
- set `currentStep: "ready-for-build"` (the Phase 3 handoff sentinel; it is intentionally not a
160
- `steps[]` entry). The front half is complete.
156
+ - **`stories-review`** is the end of the gating chain: set `currentStep: "ready-for-build"` (the Phase 3
157
+ handoff sentinel; intentionally not a `steps[]` entry) **and** open the parallel **`test-cases`** track
158
+ (set its step `blocked` `in_progress`). The build half can now start **and** the tester can work
159
+ `test-cases` at the same time.
160
+ - **`test-cases-review`** is the parallel track's gate: mark it `done` but **leave `currentStep` at
161
+ `ready-for-build`** — completing test cases must never pull the epic back from the build half.
162
+ - Any **other** review step: set the next step in `steps[]` from `blocked` to `in_progress` (authoring)
163
+ or `in_review`, and set `currentStep` to that next step.
161
164
  - Write `state.json`. Report the advance and what the next authored artifact is (or that the epic is
162
- now `ready-for-build`).
165
+ now `ready-for-build`, with `test-cases` running in parallel).
163
166
 
164
167
  ### PR-driven automation (the `yad gate` CLI)
165
168
  When the hub has a platform, the mechanical `open`/`sync`/`advance` is performed deterministically by the
@@ -18,7 +18,7 @@ touched `domain`, `|domainOwners[domain]| >= 1`.
18
18
  - Stories review: the touched domains are the **union of every story's `repos`** under `stories/`.
19
19
 
20
20
  So one gate, two option-shapes:
21
- - Epic / UI reviews: base rule (no risk tags, no per-repo routing).
21
+ - Epic / UI / test-cases reviews: base rule (no risk tags, no per-repo routing).
22
22
  - Architecture+contract review: escalated (`risk_tags: ["contract"]`) — owner + 1 reviewer + a
23
23
  `domain-owner` for **each** repo in `epic.repos`. (A small team may have one engineer own several
24
24
  repos — one person can supply several `domain-owner` records with different `domain` values.)
@@ -57,7 +57,7 @@ if step in cfg.locked_steps: eff = "human_approve"
57
57
  ```
58
58
 
59
59
  So a kill switch, a `locked` flag, or membership in `locked_steps` forces a stop no matter what the
60
- per-step dial says. `engineer-review` and the four front states are covered by `locked` / `locked_steps`.
60
+ per-step dial says. `engineer-review` and the five front states are covered by `locked` / `locked_steps`.
61
61
 
62
62
  ## Deriving signals & the provisional verdict
63
63
 
@@ -115,7 +115,7 @@ Reverting (`to: human_approve`) is never gated — automation must be reversible
115
115
  ## What stays human, always
116
116
 
117
117
  - `engineer-review` — the merge gate. `yad-run` always stops here and hands to `yad-ship`.
118
- - The four front states (`epic`, `architecture`, `ui-design`, `stories`) — not in `back_steps`, in
119
- `locked_steps`; the dial-setter refuses them.
118
+ - The five front states (`epic`, `architecture`, `ui-design`, `stories`, `test-cases`) — not in
119
+ `back_steps`, in `locked_steps`; the dial-setter refuses them.
120
120
  - Any contract-surface change — halts the loop and routes back to the architecture gate, regardless of
121
121
  the dial.
@@ -43,7 +43,9 @@ is the same graceful-degradation pattern `yad-ui` uses for Impeccable.
43
43
 
44
44
  ### Step 1 — Resolve the story and check readiness
45
45
  Read `{project-root}/epics/<epic>/.sdlc/state.json`. Proceed only when
46
- `currentStep == "ready-for-build"` (the whole front half is `done`). Read the story file
46
+ `currentStep == "ready-for-build"` (the gating front half — through the **stories** gate — is `done`).
47
+ The **`test-cases` track may still be `in_progress`**: it is parallel and non-blocking, so the build
48
+ half runs alongside it — its status does not affect readiness here. Read the story file
47
49
  `epics/<epic>/stories/<story>.md`; confirm `repo` is in its `repos`. If the epic is not ready, STOP
48
50
  and point the user at `yad-status`. **Do not mutate front-half state** — `ready-for-build` semantics
49
51
  stay intact.
@@ -30,12 +30,15 @@ Print, in this order:
30
30
 
31
31
  1. **Epic:** `epicId`, `status` from `epic.md` frontmatter, `currentStep`, and `repos` (the touched
32
32
  domains).
33
- 2. **Steps table** — for every front step in `steps[]` order (8, or 10 when the optional analysis step
33
+ 2. **Steps table** — for every front step in `steps[]` order (10, or 12 when the optional analysis step
34
34
  was run): `id`, `type`, `status`, `assistance`, `automation`, `locked`, and `risk_tags`. Mark the
35
- `currentStep` with `→`. The full front-state chain is `[analysis → analysis-review →] epic →
36
- epic-review → architecture → architecture-review → ui-design → ui-design-review → stories →
37
- stories-review` (then `ready-for-build`); the bracketed `analysis` prefix is present only when
38
- `yad-analysis` seeded it. Always render exactly the steps present in `steps[]`.
35
+ `currentStep` with `→`. The gating chain is `[analysis → analysis-review →] epic → epic-review →
36
+ architecture → architecture-review → ui-design → ui-design-review → stories → stories-review` →
37
+ **`ready-for-build`** (the bracketed `analysis` prefix is present only when `yad-analysis` seeded it).
38
+ `test-cases → test-cases-review` is a **parallel, non-blocking track**: it opens when `stories-review`
39
+ passes and runs alongside the build half, so when `currentStep` is `ready-for-build` the `test-cases`
40
+ step may still be `in_progress`/`in_review` — show its status, and note "parallel" so it is clear it
41
+ does not gate the build. Always render exactly the steps present in `steps[]`.
39
42
  3. **Active gate** — for the `currentStep` (if it is a `review+approve` step), compute and show:
40
43
  - the reviewer rule in force — **base** (`owner + 1 reviewer`), **escalated** (list the required
41
44
  domains), or **per-repo** for `stories-review` (list each repo needing sign-off),
@@ -97,7 +97,9 @@ In `state.json`: set `stories.status: "done"`, set `stories-review.status: "in_r
97
97
  ### Step 7 — Stop at the gate (do NOT advance)
98
98
  Report: the story IDs created, the repos each touches, and that the next action is **review** via
99
99
  `yad-review-gate`. Note that this review routes **per-repo reviewers**: owner + 1 reviewer **plus**, for
100
- each repo appearing in any story's `repos`, a `domain-owner` approval for that repo. **Never record
100
+ each repo appearing in any story's `repos`, a `domain-owner` approval for that repo. When this gate
101
+ passes the epic becomes **`ready-for-build`** — the build half can start **and** the parallel
102
+ **`test-cases`** track opens for the tester (`yad-test-cases`); the two run at the same time. **Never record
101
103
  approval here.** Front states do not auto-advance. When the hub has a platform, the gate opens a review
102
104
  PR on the hub (via `yad-hub-bridge`, with a `domain:<repo>` label per touched repo) and
103
105
  `yad-review-gate action: sync` pulls platform approvals/comments into the ledger; otherwise the review