yadflow 3.19.0-next.2 → 4.0.0-next.3

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.
Files changed (158) hide show
  1. package/CHANGELOG.md +371 -0
  2. package/README.md +160 -22
  3. package/bin/commands.mjs +46 -0
  4. package/bin/yad.mjs +506 -117
  5. package/cli/artifact-status.mjs +30 -11
  6. package/cli/capture.mjs +417 -0
  7. package/cli/checkpoint.mjs +47 -27
  8. package/cli/claims.mjs +165 -0
  9. package/cli/codeowners-command.mjs +170 -0
  10. package/cli/codeowners.mjs +397 -0
  11. package/cli/commit.mjs +13 -9
  12. package/cli/dial.mjs +183 -0
  13. package/cli/docs.mjs +88 -32
  14. package/cli/doctor.mjs +1682 -90
  15. package/cli/epic-state.mjs +3460 -211
  16. package/cli/epic.mjs +506 -0
  17. package/cli/errors.mjs +3 -0
  18. package/cli/fold.mjs +247 -0
  19. package/cli/gate-local.mjs +296 -0
  20. package/cli/gate.mjs +977 -183
  21. package/cli/history.mjs +556 -0
  22. package/cli/hook.mjs +264 -53
  23. package/cli/hubcommit.mjs +9 -19
  24. package/cli/index-command.mjs +87 -0
  25. package/cli/ledger.mjs +54 -4
  26. package/cli/lib.mjs +161 -9
  27. package/cli/manifest.mjs +376 -38
  28. package/cli/migrate.mjs +683 -52
  29. package/cli/mode.mjs +170 -0
  30. package/cli/next.mjs +365 -86
  31. package/cli/openpr.mjs +193 -34
  32. package/cli/owners.mjs +266 -0
  33. package/cli/people.mjs +657 -0
  34. package/cli/plan.mjs +466 -125
  35. package/cli/platform.mjs +109 -128
  36. package/cli/product-index.mjs +287 -0
  37. package/cli/protection.mjs +706 -0
  38. package/cli/reconcile.mjs +40 -12
  39. package/cli/repo-publish.mjs +24 -26
  40. package/cli/repo.mjs +23 -14
  41. package/cli/report.mjs +24 -14
  42. package/cli/review.mjs +19 -22
  43. package/cli/riskmap-command.mjs +289 -0
  44. package/cli/riskmap.mjs +373 -0
  45. package/cli/setup.mjs +127 -279
  46. package/cli/ship.mjs +6 -5
  47. package/cli/skill.mjs +180 -0
  48. package/cli/skip.mjs +211 -30
  49. package/cli/thread.mjs +41 -16
  50. package/cli/tidy.mjs +18 -18
  51. package/cli/update-commit.mjs +21 -21
  52. package/cli/usage.mjs +115 -109
  53. package/package.json +3 -3
  54. package/skills/sdlc/config.yaml +149 -70
  55. package/skills/sdlc/module-help.csv +24 -24
  56. package/skills/yad-analysis/SKILL.md +121 -59
  57. package/skills/yad-architecture/SKILL.md +30 -18
  58. package/skills/yad-architecture/references/contract-format.md +8 -5
  59. package/skills/yad-backfill/SKILL.md +10 -4
  60. package/skills/yad-backfill/references/backfill.md +8 -1
  61. package/skills/yad-backfill/templates/checks/backfill-check.sh +10 -2
  62. package/skills/yad-change/SKILL.md +119 -42
  63. package/skills/yad-change/references/triage.md +42 -27
  64. package/skills/yad-checks/SKILL.md +68 -35
  65. package/skills/yad-checks/references/check-gates.md +310 -85
  66. package/skills/yad-checks/templates/checks/commit-message.sh +17 -3
  67. package/skills/yad-checks/templates/checks/contract-check.sh +130 -9
  68. package/skills/yad-checks/templates/checks/epic-open.sh +2 -2
  69. package/skills/yad-checks/templates/checks/ledger-guard.sh +55 -8
  70. package/skills/yad-checks/templates/checks/lineage-check.sh +23 -9
  71. package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +1 -1
  72. package/skills/yad-checks/templates/checks/risk-map-check.sh +438 -0
  73. package/skills/yad-checks/templates/checks/verified-commits.sh +20 -46
  74. package/skills/yad-checks/templates/github/yad-checks.yml +13 -2
  75. package/skills/yad-checks/templates/github/yad-hub-checks.yml +5 -5
  76. package/skills/yad-checks/templates/github/yad-update-guard.yml +7 -5
  77. package/skills/yad-checks/templates/github/yad-verified-commits.yml +4 -4
  78. package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +10 -1
  79. package/skills/yad-checks/templates/gitlab/yad-hub-checks.gitlab-ci.yml +5 -5
  80. package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +3 -3
  81. package/skills/yad-checks/templates/hooks/ledger-guard-cursor.sh +91 -0
  82. package/skills/yad-checks/templates/hooks/ledger-guard.sh +37 -6
  83. package/skills/yad-checks/templates/hooks/yad-capture.sh +53 -0
  84. package/skills/yad-commit/SKILL.md +4 -4
  85. package/skills/yad-connect-design/SKILL.md +5 -5
  86. package/skills/yad-connect-design/references/design-context.md +1 -1
  87. package/skills/yad-connect-design/references/design-registry.md +2 -2
  88. package/skills/yad-connect-docs/SKILL.md +11 -11
  89. package/skills/yad-connect-docs/references/docs-registry.md +1 -1
  90. package/skills/yad-connect-learning/SKILL.md +5 -5
  91. package/skills/yad-connect-learning/references/learning-registry.md +2 -2
  92. package/skills/yad-connect-repos/SKILL.md +66 -45
  93. package/skills/yad-connect-repos/references/code-context.md +4 -4
  94. package/skills/yad-connect-repos/references/hub-config.md +47 -51
  95. package/skills/yad-connect-repos/references/repos-registry.md +8 -7
  96. package/skills/yad-connect-repos/references/risk-map.md +81 -0
  97. package/skills/yad-connect-testing/SKILL.md +5 -5
  98. package/skills/yad-connect-testing/references/testing-context.md +3 -4
  99. package/skills/yad-connect-testing/references/testing-registry.md +2 -2
  100. package/skills/yad-defects/SKILL.md +7 -7
  101. package/skills/yad-discovery/SKILL.md +131 -94
  102. package/skills/yad-discovery/references/discovery-schema.md +22 -6
  103. package/skills/yad-discovery/references/foundation-schema.md +374 -0
  104. package/skills/yad-docs/SKILL.md +13 -8
  105. package/skills/yad-docs/references/data-mapping.md +9 -7
  106. package/skills/yad-docs/templates/app/package-lock.json +3 -3
  107. package/skills/yad-docs-overview/SKILL.md +30 -15
  108. package/skills/yad-docs-overview/references/pipeline-model.md +33 -20
  109. package/skills/yad-docs-sync/SKILL.md +10 -5
  110. package/skills/yad-docs-sync/references/staleness.md +8 -7
  111. package/skills/yad-engineer-review/SKILL.md +81 -17
  112. package/skills/yad-engineer-review/references/ship-and-record.md +17 -8
  113. package/skills/yad-epic/SKILL.md +173 -92
  114. package/skills/yad-epic/references/state-schema.md +610 -94
  115. package/skills/yad-hub-bridge/SKILL.md +57 -38
  116. package/skills/yad-hub-bridge/references/bridge.md +94 -67
  117. package/skills/yad-hub-bridge/references/login-roster.md +163 -70
  118. package/skills/yad-hub-bridge/templates/checks/hub-route.sh +22 -19
  119. package/skills/yad-hub-bridge/templates/github/yad-gate-sync.yml +34 -14
  120. package/skills/yad-hub-bridge/templates/gitlab/gitlab-ci.include-root.yml +2 -2
  121. package/skills/yad-hub-bridge/templates/gitlab/yad-gate-sync.gitlab-ci.yml +21 -11
  122. package/skills/yad-implement/SKILL.md +27 -13
  123. package/skills/yad-implement/references/implement-conventions.md +2 -2
  124. package/skills/yad-learn/SKILL.md +9 -9
  125. package/skills/yad-learn/references/learning-state.md +2 -2
  126. package/skills/yad-open-pr/SKILL.md +61 -26
  127. package/skills/yad-pair-review/SKILL.md +7 -5
  128. package/skills/yad-pair-review/references/session-state.md +1 -1
  129. package/skills/yad-pr-template/SKILL.md +47 -26
  130. package/skills/yad-pr-template/references/risk-routing.md +97 -24
  131. package/skills/yad-pr-template/templates/checks/pr-template.sh +34 -11
  132. package/skills/yad-pr-template/templates/checks/pr-title.sh +32 -9
  133. package/skills/yad-pr-template/templates/checks/risk-route.sh +107 -14
  134. package/skills/yad-pr-template/templates/github/pull_request_template.md +7 -5
  135. package/skills/yad-pr-template/templates/gitlab/merge_request_templates/Default.md +7 -5
  136. package/skills/yad-pr-template/templates/hub/github/pull_request_template.md +14 -13
  137. package/skills/yad-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +14 -12
  138. package/skills/yad-reconcile/SKILL.md +3 -3
  139. package/skills/yad-report/SKILL.md +5 -5
  140. package/skills/yad-review-companion/SKILL.md +6 -3
  141. package/skills/yad-review-gate/SKILL.md +203 -93
  142. package/skills/yad-review-gate/references/gating.md +232 -54
  143. package/skills/yad-run/SKILL.md +81 -51
  144. package/skills/yad-run/references/run-loop.md +61 -39
  145. package/skills/yad-ship/SKILL.md +15 -11
  146. package/skills/yad-spec/SKILL.md +21 -6
  147. package/skills/yad-spec/references/spec-handoff.md +17 -5
  148. package/skills/yad-status/SKILL.md +115 -50
  149. package/skills/yad-stories/SKILL.md +37 -21
  150. package/skills/yad-stories/references/story-schema.md +7 -6
  151. package/skills/yad-stub/SKILL.md +58 -47
  152. package/skills/yad-sync-repos/SKILL.md +2 -2
  153. package/skills/yad-test-cases/SKILL.md +32 -23
  154. package/skills/yad-test-cases/references/test-cases-schema.md +7 -4
  155. package/skills/yad-timeline/SKILL.md +8 -7
  156. package/skills/yad-ui/SKILL.md +41 -18
  157. package/cli/roster.mjs +0 -164
  158. package/skills/sdlc/install.sh +0 -68
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yad-stories
3
- description: 'Shape step 7 of the gated SDLC. With the pm, break the approved epic into user stories, each tagged with the repos that must implement it. Assigns zero-padded EP-<slug>-S0N IDs and writes one file per story under stories/. Reads epic + architecture + contract + UI as input. Never auto-advances — hands off to the team review gate (per-repo reviewer routing). Use when the user says "author the stories" or after the UI gate passes.'
3
+ description: 'Shape step 7 of the gated SDLC. With the pm, break the approved epic into user stories, each tagged with the repos that must implement it. Assigns zero-padded EP-<slug>-S0N IDs and writes one file per story under stories/. Reads epic + architecture + contract + UI as input. Never auto-advances — hands off to the team review gate (an ordinary approval-count gate). Use when the user says "author the stories" or after the UI gate passes.'
4
4
  ---
5
5
 
6
6
  # SDLC — Author Stories (Shape step 7)
@@ -8,8 +8,8 @@ description: 'Shape step 7 of the gated SDLC. With the pm, break the approved ep
8
8
  **Goal:** Break an approved epic into human-authored, AI-assisted user stories, each with a stable
9
9
  `EP-<slug>-S0N` ID and a `repos` tag listing which repos must implement it. This is a **Shape step**:
10
10
  human-authored with AI assist, **never auto-advances**. When the stories are drafted, control passes
11
- to `yad-review-gate`, which routes **per-repo reviewers** (each repo's engineer reviews the stories
12
- touching their repo).
11
+ to `yad-review-gate`, an ordinary count gate: at least 1 distinct approver, who should not be the author. The stories'
12
+ `repos` tags still say which repos a story touches, and the review PR is labelled with those repos.
13
13
 
14
14
  There is **no `sm` agent** (Phase 0 Deviation 1): the `pm` lens breaks down the epic; the `pm` or
15
15
  `architect` lens prepares each story's detail. IDs are engine-assigned and never renamed.
@@ -19,7 +19,7 @@ There is **no `sm` agent** (Phase 0 Deviation 1): the `pm` lens breaks down the
19
19
  - `{project-root}` resolves from the project working directory.
20
20
  - Stories live under `{project-root}/epics/EP-<slug>/stories/` (build plan §6).
21
21
  - Story files are named `EP-<slug>-S0N.md` (zero-padded, e.g. `EP-checkout-S01.md`).
22
- - Speak in the configured `communication_language`; write documents in `document_output_language`.
22
+ - Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
23
23
 
24
24
  ## On Activation
25
25
 
@@ -37,7 +37,8 @@ This passes when `stories` is the next runnable step per the state sequence —
37
37
  Open the stories authoring branch `stories/EP-<slug>` per the shared procedure
38
38
  (`../yad-epic/references/state-schema.md` → "Authoring branches"): git-safe (skip with a note
39
39
  if `{project-root}` is not a git work tree), check out the branch if it exists, else create it from the
40
- hub's default branch. Author and commit the story files under `stories/` on it. This is **distinct**
40
+ Product's default branch. Author the story files under `stories/` on it, and end the step with `yad fold EP-<slug> stories` — the
41
+ one commit the step keeps (E44). This is **distinct**
41
42
  from the verified ledger's `review/…` branch.
42
43
 
43
44
  ### Step 2 — Read inputs
@@ -48,7 +49,18 @@ must collectively satisfy the epic's acceptance signals and stay within the cont
48
49
  - **UI-optional-safe:** `ui-design.md` may be absent — the `ui-design` step is optional and can be
49
50
  marked N/A for an epic with no user-facing surface (state.json shows it `skipped`). When there is no
50
51
  UI design, proceed without UI screens; the epic's acceptance signals + contract remain the source of
51
- truth for the stories.
52
+ truth for the stories. If state.json shows it `deferred` instead, the UI **will** come later: write the
53
+ stories so they do not assume there are no screens, and note in each story that touches the UI that
54
+ its screens are still to be designed.
55
+ - **Short-lane-safe:** `architecture.md` and `contract.md` may BOTH be absent, and on the `chore` and
56
+ `spike` routes they always are — those lanes carry no architecture step, so there is no locked
57
+ contract for this epic. Read `state.json`'s `profile` key first — an epic seeded before file shape 6
58
+ has no such key, so fall back to what its `steps[]` actually contains, which is the real answer
59
+ either way. On a short lane, write the stories
60
+ from `epic.md` alone and say so in each story's "Contract & design touchpoints" section. Because
61
+ there is no lock, a story on a short lane **must not change the shared cross-repo surface**: if the
62
+ work turns out to need that, stop and say so — the epic belongs on `classic`, which has the
63
+ architecture gate that locks the surface.
52
64
 
53
65
  ### Step 2b — Load existing-code context (make the brain code-aware)
54
66
  Read the registry `{project-root}/.sdlc/repos.json` (`config.yaml` `code_context`). For **each repo in
@@ -63,7 +75,7 @@ Phase 3 build (Spec Kit per repo) accurate anchors instead of invented ones.
63
75
  - **Traceability:** record the loaded maps in each story's `code-context:` frontmatter field.
64
76
 
65
77
  ### Step 3 — Break down the epic (assist: pm)
66
- Adopt the **pm** lens (`bmad-agent-pm`, John). Decompose the epic into the smallest set of
78
+ Adopt the **pm** lens. Decompose the epic into the smallest set of
67
79
  independently reviewable, independently buildable stories. For each story decide which repos it touches
68
80
  (must be a subset of the epic's `repos`). Prefer stories scoped to a clear slice of user value.
69
81
 
@@ -105,31 +117,35 @@ As a <role>, I want <capability>, so that <outcome>.
105
117
  **verified mode** is `platform` set AND `ledger: "verified"` — or, on a project that has not run `yad migrate` yet, `bridge_enabled` (or legacy `bridge`) `true`. `ledger` wins whenever it is present.
106
118
 
107
119
  **verified mode — do NOT write `state.json`.** The ledger is CI-owned: the `ledger-guard` check rejects
108
- any non-bot commit touching `epics/*/.sdlc/{state,approvals,comments,hub-prs}.json` or
120
+ any non-bot commit touching `epics/*/.sdlc/{state,approvals,comments,product-prs,hub-prs}.json` or
109
121
  `epics/*/reviews/*.md`, `yad gate open` deliberately skips this write for the same reason, and
110
122
  `yad gate ci --merged` performs the whole transition when the review PR merges. Making the edit here
111
123
  fails the gate if it rides the review PR, and desynchronises the ledger CI is about to rewrite if it
112
124
  is pushed around the gate. Commit **the story files under `stories/` only** — nothing else
113
- under `.sdlc/` — then hand off to `yad-review-gate`.
125
+ under `.sdlc/` (`yad fold EP-<slug> stories` takes exactly these) — then hand off to `yad-review-gate`.
114
126
 
115
- **Otherwise — local, or a platform with no gate-sync CI — write it.** In `state.json`: set
116
- `stories.status: "done"`, set `stories-review.status: "in_review"`, and set
117
- `currentStep: "stories-review"`. Write `state.json`. Do **not** touch `approvals.json`.
127
+ **Otherwise — local, or a platform with no gate-sync CI — the engine makes this edit, not you.**
128
+ `yad gate open <epic> stories/` marks `stories-review` `in_review`, closes `stories` as `done`, and moves `currentStep` to the gate
129
+ — the same transition, from the one function that owns it (`markInReview`, `cli/epic-state.mjs`).
130
+ `yad-review-gate action: open` runs that command; hand off to it rather than editing the ledger here.
118
131
 
119
- > **local branch only.** Since 3.11 the CLI also closes the authoring step when its review gate
120
- > opens or advances, so this edit is a no-op once `yad gate open` has run. A `stories` step left
121
- > `in_progress` behind a passed `stories-review` used to block the parallel `test-cases` track
122
- > (`YAD-STATE-005`). In verified mode `gate open` writes nothing and local `gate sync` is advisory —
123
- > `gate ci` closes the step at merge.
132
+ **With no platform configured** it writes the ledger and simply opens no PR, so this works offline.
133
+ **With a platform** the `review/EP-<slug>/stories` branch must already be **on origin** — the command
134
+ refuses and writes nothing otherwise. Cut it from the authoring branch and push it before handing off
135
+ (or run `yad open-pr` from that branch: it pushes the branch, then delegates).
136
+
137
+ Do **not** hand-edit `state.json`, and do **not** touch `approvals.json` — only real reviewers approve,
138
+ through the gate.
124
139
 
125
140
  ### Step 7 — Stop at the gate (do NOT advance)
126
141
  Report: the story IDs created, the repos each touches, and that the next action is **review** via
127
- `yad-review-gate`. Note that this review routes **per-repo reviewers**: owner + 1 reviewer **plus**, for
128
- each repo appearing in any story's `repos`, a `domain-owner` approval for that repo. When this gate
142
+ `yad-review-gate`. This review is an ordinary count gate: it passes with at least 1 distinct approver (who
143
+ should not be the author) and, with a platform, resolved threads and a merged review PR. It is not routed per repo, and it requests no
144
+ reviewers — the team asks them on the review PR itself. When this gate
129
145
  passes the epic becomes **`ready-for-build`** — Build can start **and** the parallel
130
146
  **`test-cases`** track opens for the tester (`yad-test-cases`); the two run at the same time. **Never record
131
- approval here.** Shape steps do not auto-advance. When the hub has a platform, the gate opens a review
132
- PR on the hub (via `yad-hub-bridge`, with a `domain:<repo>` label per touched repo) and
147
+ approval here.** Shape steps do not auto-advance. When the Product has a platform, the gate opens a review
148
+ PR on the Product (via `yad-hub-bridge`, with a `domain:<repo>` label per touched repo) and
133
149
  `yad-review-gate action: sync` pulls platform approvals/comments into the ledger; otherwise the review
134
150
  is recorded local.
135
151
 
@@ -11,7 +11,7 @@ Each story authored at Shape step 7 is one Markdown file under `epics/EP-<slug>/
11
11
  | `epic` | `EP-<slug>` | Parent epic ID — the unbroken link back to the epic. |
12
12
  | `owner` | name | Inherited from `epic.md` `owner` (the single source — not retyped per story). Carries the responsible owner through to Build. |
13
13
  | `status` | `draft` \| `in_review` \| `approved` | Story lifecycle within the stories gate. |
14
- | `repos` | subset of the epic's `repos` | Which repos must implement this story. **Drives per-repo review routing now and (Phase 3) where specs are scaffolded.** |
14
+ | `repos` | subset of the epic's `repos` | Which repos must implement this story. **Labels the stories review PR with the touched repos now and (Phase 3) decides where specs are scaffolded.** |
15
15
  | `code-context` | `{ repos: [<name@sha>], loaded: <date> }` | Optional. Which connected-repo code-maps anchored "Notes for build" (Shape step 7 Step 2b). The `@sha` (a repo's `syncedHead`) is recommended so freshness is recorded but may be omitted; the SKILL templates show the empty placeholder `{ repos: [], loaded: <date or none> }`. `none` / `[]` when no repos are connected. |
16
16
 
17
17
  ## Body
@@ -38,9 +38,10 @@ As a <role>, I want <capability>, so that <outcome>.
38
38
  - **Stay within the contract surface.** "Notes for build" should reference the contract elements a
39
39
  story touches; a story may not invent cross-repo surface that `contract.md` does not define.
40
40
 
41
- ## Per-repo review routing (the stories gate)
41
+ ## Review (the stories gate)
42
42
 
43
- `yad-review-gate` treats each repo's engineer as the `domain-owner` for the stories touching that repo.
44
- The gate passes only when, in addition to the base rule (owner + 1 reviewer), **every repo appearing in
45
- any story's `repos`** has at least one `domain-owner` approval scoped to that repo (`domain` = repo
46
- name). The gate's `approved.md` lists which repos still lack sign-off.
43
+ The stories gate is an ordinary count gate. It passes with at least 1 distinct approver (who should not
44
+ be the author) and, with a platform, resolved threads and a merged review PR. It is **not** routed per repo: no repo needs its own
45
+ sign-off, and no role is checked. The union of every story's `repos` still names the touched repos, and
46
+ the review PR carries a `domain:<repo>` label for each. The review PR requests no reviewers; the team
47
+ asks them on the PR itself.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yad-stub
3
- description: 'Phase 6 brownfield helper — mint a STUB genesis epic for an already-built feature that has no epic in the hub, so a defect/change can thread off it TODAY. In a brownfield repo not every feature has an epic; yad-change requires a real parent and dead-ends without one. This skill creates the smallest real thread anchor — a tiny epic.md (kind:feature, thread:self, verified:false, stub:backfill-pending) + a seeded state.json + empty ledgers — never inventing behaviour. Defects thread off it immediately (gates pass, the bug list is derived by the thread rollup), and yad-backfill + its promote step later fill/flip it into a real feature epic. Never auto-advances. Use when the user says "there is no epic for this feature", "file a bug on a legacy feature", "anchor a brownfield feature", or when yad-change / yad-reconcile point here because a parent epic is missing.'
3
+ description: 'Phase 6 brownfield helper — mint a STUB genesis epic for an already-built feature that has no epic in the Product, so a defect/change can thread off it TODAY. In a brownfield repo not every feature has an epic; yad-change requires a real parent and dead-ends without one. This skill creates the smallest real thread anchor — a tiny epic.md (type feature under both names, thread:self, verified:false, stub:backfill-pending) + a seeded state.json + empty ledgers — never inventing behaviour. Defects thread off it immediately (gates pass, the bug list is derived by the thread rollup), and yad-backfill + its promote step later fill/flip it into a real feature epic. Never auto-advances. Use when the user says "there is no epic for this feature", "file a bug on a legacy feature", "anchor a brownfield feature", or when yad-change / yad-reconcile point here because a parent epic is missing.'
4
4
  ---
5
5
 
6
6
  # SDLC — Stub Genesis Epic (Phase 6, the brownfield thread anchor)
@@ -13,19 +13,19 @@ stub is a **thread anchor, not a spec**: it invents no behaviour. It stays `veri
13
13
 
14
14
  This is the missing connective tissue in a brownfield adoption: `yad-backfill` produces a *draft spec in
15
15
  the code repo*, and `yad-reconcile` *detects* shipped code with no owning epic — but neither mints the
16
- hub epic a defect must thread from. `yad-stub` does exactly that, and only that.
16
+ Product epic a defect must thread from. `yad-stub` does exactly that, and only that.
17
17
 
18
18
  ## Conventions
19
19
 
20
- - `{project-root}` resolves from the product hub. Epic artifacts live under
20
+ - `{project-root}` resolves from the Product. Epic artifacts live under
21
21
  `{project-root}/epics/EP-<slug>/` (build plan §6), exactly like a normal genesis epic.
22
22
  - **A stub is NOT a reserved-empty id.** An epic in yad *is* a directory + `epic.md`; the tooling skips
23
23
  any epic dir lacking `epic.md` (`threadEpics`) and `lineage-check` rejects a parent that is not a real
24
24
  `epic.md`. So the stub is a real (if minimal) genesis — that is what makes it a valid parent.
25
- - The stub is a **genesis** (`kind: feature`, `thread == id`, no `parent`) — the root of a new thread.
25
+ - The stub is a **genesis** (type `feature` under both names, `thread == id`, no `parent`) — the root of a new thread.
26
26
  Lineage frontmatter, the sentinel state, and the `stub`/`verified` fields are defined in
27
27
  `../yad-epic/references/state-schema.md` (Phase 6 section).
28
- - Speak in the configured `communication_language`; write documents in `document_output_language`.
28
+ - Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
29
29
 
30
30
  ## Inputs
31
31
 
@@ -44,26 +44,43 @@ not a stub case either. Confirm the brownfield-no-epic situation with the human
44
44
 
45
45
  ### Step 2 — Derive the stub epic id (engine-assigned, never by hand)
46
46
  Derive `EP-<slug>` where `slug` is **2–4 lowercase words** from the feature name (e.g.
47
- `EP-legacy-billing`). `EP-discovery` is **reserved** — never use it. Check `epics/` for collisions;
47
+ `EP-legacy-billing`). `EP-foundation` and `EP-discovery` are **reserved** (the Product level) — never use either. Check `epics/` for collisions;
48
48
  append a distinguishing word if the slug exists. **The id is assigned once and never renamed** (a rename
49
49
  breaks every downstream link) — so pick from the best-known feature name and accept it as permanent.
50
50
 
51
51
  ### Step 3 — Open the authoring branch
52
52
  Open `epic/EP-<slug>` per the shared "Authoring branches" procedure
53
53
  (`../yad-epic/references/state-schema.md`): git-safe (skip with a note if `{project-root}` is not a git
54
- work tree), check out if it exists, else create from the hub's default branch.
54
+ work tree), check out if it exists, else create from the Product's default branch.
55
55
 
56
56
  ### Step 4 — Write the stub `epic.md` (thread anchor — never invent behaviour)
57
57
  Write `{project-root}/epics/EP-<slug>/epic.md` using EXACTLY this shape:
58
58
 
59
+ **Every key below is read by a machine, so write them BARE — no trailing `#` comment.** The
60
+ frontmatter readers keep the whole rest of the line, so a comment becomes part of the value: a
61
+ commented `stub:` stops `yad thread` and `yad-status` seeing the stub at all, and a commented `kind:`
62
+ makes `lineage-check` refuse every commit that links a story to this epic. What they mean:
63
+
64
+ | Key | Why it is here |
65
+ |---|---|
66
+ | `title` | the feature's one-line name, as the code shows it (such as `Order checkout`) — the name a list of work items shows for this stub. No invented behaviour. One line; no `#` comment; no YAML block (`>` or `\|`); quotes are optional. A title that begins with `[` and ends with `]` goes in double quotes (write an inner `"` as `\"`), or it is read as a list. The full rules are the `title` row of the `epic.md` frontmatter table in `../yad-epic/references/state-schema.md`. Leave it empty if you cannot name it from the code: the stub is then shown by its id |
67
+ | `kind` + `type` | the work-item type, the same value under both names — `feature`, because a stub is a genesis / thread root and a valid parent for `lineage-check` |
68
+ | `thread` | `thread == id` for a genesis |
69
+ | `theme` | the optional grouping tag — one word or short phrase, in any language, shared by every epic in the group. Usually **empty here**: a stub is minted from code that already exists, not shaped in conversation, so there is normally nobody to say which group it is in. Fill it only if the user names one, and then copy an existing spelling exactly — `yad doctor` reports one theme spelled two ways, because two spellings group as two. One tag, never a list, and no `#` (the readers keep the whole rest of the line; the `#` the commands print is decoration on the screen) |
70
+ | `verified` | `false` — not a real, human-authored epic yet, a stub awaiting backfill |
71
+ | `stub` | `backfill-pending` — the honest marker; cleared on promote |
72
+
59
73
  ```markdown
60
74
  ---
61
75
  id: EP-<slug>
76
+ title: <the feature's one-line name>
62
77
  status: draft
63
- kind: feature # genesis / thread root — a valid parent for lineage-check + threads
64
- thread: EP-<slug> # thread == id for a genesis
65
- verified: false # not a real, human-authored epic yet — a stub awaiting backfill
66
- stub: backfill-pending # the honest marker; cleared on promote
78
+ kind: feature
79
+ type: feature
80
+ thread: EP-<slug>
81
+ theme:
82
+ verified: false
83
+ stub: backfill-pending
67
84
  origin: brownfield
68
85
  owner:
69
86
  repos: [<the code repos this feature lives in>]
@@ -84,46 +101,40 @@ created: <YYYY-MM-DD>
84
101
 
85
102
  Leave `owner` for the human to set. Set `repos` to the code repo(s) the feature lives in.
86
103
 
87
- ### Step 5 — Seed the stub `state.json` (a `backfill-pending` sentinel)
88
- Create `{project-root}/epics/EP-<slug>/.sdlc/state.json`. It carries the top-level marker
89
- `kind: "stub"` and the sentinel `currentStep: "backfill-pending"`, and the **same 10-step Shape chain**
90
- as a normal epic (`yad-epic` Step 5) but with **every step `status: "blocked"`** — so the state is valid
91
- (`validateState` needs a non-empty `steps` + a string `currentStep`) and `promote` can later "wake" it
92
- into normal authoring with zero re-seeding.
93
-
94
- ```json
95
- {
96
- "schemaVersion": 1,
97
- "epicId": "EP-<slug>",
98
- "createdAt": "<YYYY-MM-DD>",
99
- "kind": "stub",
100
- "currentStep": "backfill-pending",
101
- "steps": [
102
- { "id": "epic", "type": "author", "artifact": "epic.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
103
- { "id": "epic-review", "type": "review+approve", "artifact": "epic.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
104
- { "id": "architecture", "type": "author", "artifact": "architecture.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
105
- { "id": "architecture-review","type": "review+approve", "artifact": "architecture.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": ["contract"] },
106
- { "id": "ui-design", "type": "author", "artifact": "ui-design.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
107
- { "id": "ui-design-review", "type": "review+approve", "artifact": "ui-design.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
108
- { "id": "stories", "type": "author", "artifact": "stories/", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
109
- { "id": "stories-review", "type": "review+approve", "artifact": "stories/", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
110
- { "id": "test-cases", "type": "author", "artifact": "test-cases.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
111
- { "id": "test-cases-review", "type": "review+approve", "artifact": "test-cases.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] }
112
- ]
113
- }
114
- ```
104
+ ### Step 5 — Seed the stub ledger (a `backfill-pending` sentinel)
115
105
 
116
- Also create the empty ledgers `{.sdlc/approvals.json}` and `{.sdlc/comments.json}` (each `[]`) and the
117
- `reviews/` directory. **Do NOT** write a `contract-lock.json` — a stub has no locked surface yet.
106
+ **Run the engine. Do not hand-write the chain.**
107
+
108
+ ```bash
109
+ yad epic new EP-<slug> --stub
110
+ ```
118
111
 
119
- Commit the seed on this step's authoring branch; it reaches the hub's default branch through the
120
- epic's **first** review PR/MR (or, for a stub, the PR that carries the stub itself). In verified mode
121
- `ledger-guard` exempts a new epic's ledger — creation, not mutation (#162) — while every later change
122
- to it stays CI's. See `../yad-epic/references/state-schema.md`, "Authoring branches".
112
+ That writes `{project-root}/epics/EP-<slug>/.sdlc/state.json` with the **same 10-step `classic` chain**
113
+ a normal epic walks, but with **every step `todo`** (nobody is running it yet), the top-level marker
114
+ `kind: "stub"`, and
115
+ `currentStep: "backfill-pending"`. It also writes the empty `approvals.json` and `comments.json` and
116
+ the `reviews/` directory. It writes no `epic.md`, no branch and no commit, and it refuses an epic that
117
+ already has a `state.json`.
118
+
119
+ **Do NOT** write a `contract-lock.json` — a stub has no locked surface yet.
120
+
121
+ Notes:
122
+ - **`kind` and `type` are different things and a stub carries both.** `kind: "stub"` is the lifecycle
123
+ marker the engine keys off; `type: "feature"` is the work-item type, copied from `epic.md`. A stub is
124
+ always a `feature` and always `classic` — `--type` and `--profile` are refused here, because
125
+ `yad-backfill promote` wakes the chain at its `epic` step and upkeep leaves nothing to backfill.
126
+ - The blocked chain is what makes the state valid (`validateState` needs a non-empty `steps` and a
127
+ string `currentStep`) and what lets `promote` **wake** it into normal authoring with zero re-seeding.
128
+ - Nothing in the chain is runnable until then: `preconditionsMet` refuses every step of an anchor, and
129
+ `yad next` routes the epic to `yad-backfill` rather than to authoring.
130
+ - Commit the seed on this step's authoring branch; it reaches the Product's default branch through the
131
+ epic's **first** review PR/MR (or, for a stub, the PR that carries the stub itself). In verified mode
132
+ `ledger-guard` exempts a new epic's ledger — creation, not mutation (#162) — while every later change
133
+ to it stays CI's. See `../yad-epic/references/state-schema.md`, "Authoring branches".
123
134
 
124
135
  ### Step 6 — Stop; hand off (NO auto-advance)
125
136
  Report the new `EP-<slug>`, that it is a **stub (backfill pending)**, and the two next moves:
126
- - **File bugs now:** `yad-change` (`--parent EP-<slug>`, `kind: defect|change`) — the defect threads off
137
+ - **File bugs now:** `yad-change` (`--parent EP-<slug>`, type `defect|change`) — the defect threads off
127
138
  the stub, its gates pass, and `yad thread EP-<slug>` lists it. A defect off a stub inherits only what
128
139
  exists (the stub `epic.md`), re-authors its own stories/test-cases, and locks no contract (there is no
129
140
  surface yet — see `../yad-change/SKILL.md`).
@@ -143,7 +154,7 @@ Shape steps do not auto-advance. Suggest `yad next EP-<slug>` (prints the backfi
143
154
  - **You never implement directly against a stub.** It owns no `stories/`, so there is nothing to
144
155
  implement against directly — real work threads off it as a change/defect epic (which has its own
145
156
  stories). (This is a convention of the empty stub, not a hard gate: `lineage-check` passes a
146
- `kind: feature` genesis and `epic-open` treats a story-less epic as un-sealed, so neither blocks a
157
+ `feature`-type genesis and `epic-open` treats a story-less epic as un-sealed, so neither blocks a
147
158
  story mistakenly linked to the stub — keep the stub story-less.)
148
159
  - **Never auto-advances.** This skill seeds the anchor and stops; humans thread changes and run backfill.
149
160
 
@@ -15,7 +15,7 @@ tree (branch + fast-forward). It writes **nothing** back to the registry.
15
15
 
16
16
  ## Conventions
17
17
 
18
- - `{project-root}` resolves from the project working directory (the **product hub**).
18
+ - `{project-root}` resolves from the project working directory (the **Product**).
19
19
  - Registry: `{project-root}/.sdlc/repos.json` (project-wide; the same file `yad-connect-repos` writes).
20
20
  Each repo entry supplies `path` (local path, relative to `{project-root}` or absolute) and
21
21
  `default_branch` (the branch to land on).
@@ -64,7 +64,7 @@ Per repo: `switched to <branch>, pulled (ff)` / `already current` / `SKIPPED (..
64
64
  so any repo whose `HEAD` now differs from its registry `syncedHead` has a **stale code-context pack** —
65
65
  the command ends by pointing the human at `yad repo refresh` to repack (that is a separate human
66
66
  decision; this skill never repacks or writes the registry). After the repack + AI code-map
67
- regeneration, `yad repo refresh --push` publishes the refreshed code-maps + registry to the hub's
67
+ regeneration, `yad repo refresh --push` publishes the refreshed code-maps + registry to the Product's
68
68
  default branch as a `chore(hub): sync code-context … [skip ci]` audit commit.
69
69
 
70
70
  ## Hard rules
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yad-test-cases
3
- description: 'Shape step 9 of the gated SDLC — a PARALLEL, non-blocking track. Opens when the stories gate passes (the epic is already ready-for-build, so Build can start at the same time) and runs alongside implementation. With the test architect (Murat), author test-cases.md for the approved stories, and — when a testing tool is connected — generate/link the actual automation tests in it; otherwise produce the test-case artifact only. Reads epic + architecture + contract + UI + stories as input. Never auto-advances — hands off to the team review gate. Use when the user says "author the test cases" or after the stories gate passes.'
3
+ description: 'Shape step 9 of the gated SDLC — a PARALLEL, non-blocking track. Opens when the stories gate passes (the epic is already ready-for-build, so Build can start at the same time) and runs alongside implementation. With the test architect, author test-cases.md for the approved stories, and — when a testing tool is connected — generate/link the actual automation tests in it; otherwise produce the test-case artifact only. Reads epic + architecture + contract + UI + stories as input. Never auto-advances — hands off to the team review gate. Use when the user says "author the test cases" or after the stories gate passes.'
4
4
  ---
5
5
 
6
6
  # SDLC — Author Test Cases (Shape step 9 — parallel, non-blocking)
@@ -9,7 +9,7 @@ description: 'Shape step 9 of the gated SDLC — a PARALLEL, non-blocking track.
9
9
  test cases that cover the stories' acceptance criteria — **and**, when a testing tool is connected, the
10
10
  **actual automation tests** inside the connected code repo(s), linked back from the artifact. This is a
11
11
  **Shape step**: human-authored with AI assist, **never auto-advances**. When the test cases are
12
- drafted, control passes to `yad-review-gate` (base rule: owner + 1 reviewer).
12
+ drafted, control passes to `yad-review-gate` (base rule: 1 distinct approver, who should not be the author).
13
13
 
14
14
  **This step does NOT block Build.** It opens when the **stories** gate passes — at which point
15
15
  the epic is already `ready-for-build`, so implementation (`yad-spec` → `yad-implement` → …) can start
@@ -17,8 +17,7 @@ the epic is already `ready-for-build`, so implementation (`yad-spec` → `yad-im
17
17
  (it opens to `in_progress` when `stories-review` passes) and its review **never moves `currentStep`
18
18
  away from `ready-for-build`**, so the two run in parallel.
19
19
 
20
- Test work is shaped by the **test architect** lens — **Murat** (`bmad-tea`), driving
21
- `bmad-testarch-test-design` for the cases and `bmad-testarch-automate` for the automation. The
20
+ Test work is shaped by the **test architect** lens, which designs the cases and writes the automation. The
22
21
  automation is materialized in the **testing tool connected via `yad-connect-testing`**
23
22
  (`.sdlc/testing.json`), reached through its MCP. When a tool is connected the lens **generates** tests
24
23
  into it (or **links** an existing suite and reads it back); when none is connected, the step degrades to
@@ -31,7 +30,7 @@ the Markdown artifact only — the testing tool is additive, exactly like the de
31
30
  - The connected testing tool is recorded in `{project-root}/.sdlc/testing.json` (`config.yaml`
32
31
  `testing`), written by `yad-connect-testing`. The per-epic case→test map is `test-links.json`
33
32
  (Step 4b).
34
- - Speak in the configured `communication_language`; write documents in `document_output_language`.
33
+ - Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
35
34
 
36
35
  ## On Activation
37
36
 
@@ -44,14 +43,15 @@ it passes. The check is track-aware: it keys off the `test-cases` step's predece
44
43
  `currentStep` (this is a parallel track — `currentStep` stays at `ready-for-build`).
45
44
 
46
45
  This passes once the `test-cases` step is runnable — its predecessor `stories-review` is `done` (so the
47
- step has opened to `in_progress`) and `test-cases` is not already `done`. While it is still `blocked`,
48
- the stories review has not passed.
46
+ step has opened to `in_progress`) and `test-cases` is not already `done`. While it is still `todo` (or
47
+ `blocked`, in a file written before shape 7), the stories review has not passed.
49
48
 
50
49
  ### Step 1b — Open the authoring branch
51
50
  Open the test-cases authoring branch `test-cases/EP-<slug>` per the shared procedure
52
51
  (`../yad-epic/references/state-schema.md` → "Authoring branches"): git-safe (skip with a note if
53
52
  `{project-root}` is not a git work tree), check out the branch if it exists, else create it from the
54
- hub's default branch. Author and commit `test-cases.md` on it. This is **distinct** from the verified ledger's
53
+ Product's default branch. Author `test-cases.md` on it, and end the step with `yad fold EP-<slug> test-cases` — the one commit the
54
+ step keeps (E44). This is **distinct** from the verified ledger's
55
55
  `review/…` branch.
56
56
 
57
57
  ### Step 2 — Read inputs
@@ -62,7 +62,9 @@ for the cases — the test cases must collectively verify every story's criteria
62
62
 
63
63
  - **UI-optional-safe:** `ui-design.md` may be absent — the `ui-design` step is optional and can be
64
64
  marked N/A for a UI-less epic (state.json shows it `skipped`). When there is no UI design, there are
65
- simply no screens to exercise; the stories' acceptance criteria remain the source of truth.
65
+ simply no screens to exercise; the stories' acceptance criteria remain the source of truth. If it
66
+ shows `deferred`, the screens are still to be designed: cover the stories' criteria now, and leave the
67
+ screen-level cases for when the UI design lands.
66
68
 
67
69
  ### Step 2b — Load existing-code context (make the brain code-aware)
68
70
  Read the registry `{project-root}/.sdlc/repos.json` (`config.yaml` `code_context`). For **each repo in
@@ -77,11 +79,11 @@ inventing parallel ones.
77
79
  - **Traceability:** record the loaded maps in the `test-cases.md` `code-context:` frontmatter field.
78
80
 
79
81
  ### Step 3 — Author the test cases (assist: test architect)
80
- Adopt the **test architect** lens (`bmad-tea`, Murat), driving `bmad-testarch-test-design`. For each
82
+ Adopt the **test architect** lens. For each
81
83
  story / user flow shape risk-based test cases:
82
84
 
83
85
  - **Risk assessment** — categorize and score what can fail (probability × impact); depth scales with
84
- impact (Murat's "risk-based testing" principle).
86
+ impact (risk-based testing).
85
87
  - **Coverage plan** — assign each case a priority **P0 (critical) / P1 (high) / P2 (medium) / P3 (low)**
86
88
  and a level, preferring the lowest useful level (unit > integration > E2E).
87
89
  - **Entry/exit criteria** and any **NFR** thresholds (security, performance, reliability) in scope.
@@ -95,8 +97,8 @@ Read `{project-root}/.sdlc/testing.json` (`config.yaml` `testing.registry`). Dec
95
97
  (mirrors the `design: none` degrade). Skip to Step 4.
96
98
  - **A tool is connected and its MCP is available:** adopt the `test architect` lens and, using the
97
99
  provider recorded in `testing.json` (Playwright via a Playwright MCP, Cypress/pytest/Maestro via
98
- theirs — Maestro authors mobile flows where Playwright has no reach) drive
99
- `bmad-testarch-automate`:
100
+ theirs — Maestro authors mobile flows where Playwright has no reach) write the
101
+ automation:
100
102
  - **Generate** — when the provider is write-capable, author one automation test per high-priority
101
103
  (P0/P1) case into the connected code repo(s) for the repos in `epic.repos`, reusing the code-maps
102
104
  (Step 2b) and existing fixtures so tests target built endpoints/components, then run them via the MCP
@@ -166,27 +168,34 @@ degraded (`testing: none`), do **not** write `test-links.json`.
166
168
  **verified mode** is `platform` set AND `ledger: "verified"` — or, on a project that has not run `yad migrate` yet, `bridge_enabled` (or legacy `bridge`) `true`. `ledger` wins whenever it is present.
167
169
 
168
170
  **verified mode — do NOT write `state.json`.** The ledger is CI-owned: the `ledger-guard` check rejects
169
- any non-bot commit touching `epics/*/.sdlc/{state,approvals,comments,hub-prs}.json` or
171
+ any non-bot commit touching `epics/*/.sdlc/{state,approvals,comments,product-prs,hub-prs}.json` or
170
172
  `epics/*/reviews/*.md`, `yad gate open` deliberately skips this write for the same reason, and
171
173
  `yad gate ci --merged` performs the whole transition when the review PR merges. Making the edit here
172
174
  fails the gate if it rides the review PR, and desynchronises the ledger CI is about to rewrite if it
173
175
  is pushed around the gate. Commit the artifact set — **`test-cases.md` and, when a testing
174
- tool was used, `.sdlc/test-links.json`** (artifact-side, not ledger; generated tests live in their
176
+ tool was used, `.sdlc/test-links.json`** (artifact-side, not ledger; `yad fold EP-<slug> test-cases` takes exactly these; generated tests live in their
175
177
  own code repo, not here) — then hand off to `yad-review-gate`.
176
178
 
177
- **Otherwise — local, or a platform with no gate-sync CI — write it.** In `state.json`: set
178
- `test-cases.status: "done"` and set `test-cases-review.status: "in_review"`. **Leave `currentStep` at
179
- `ready-for-build`** — this is the parallel track; moving `currentStep` would pull it back from Build. Write `state.json`. Do **not** touch `approvals.json`. On this branch `yad gate open`
180
- makes the same edit — `markInReview` leaves `currentStep` alone once it is `ready-for-build`
181
- (`cli/epic-state.mjs`) — so it is a no-op once the gate has run.
179
+ **Otherwise — local, or a platform with no gate-sync CI — the engine makes this edit, not you.**
180
+ `yad gate open <epic> test-cases.md` marks `test-cases-review` `in_review`, closes `test-cases` as `done`, and **leaves `currentStep` at `ready-for-build`** — this is the parallel track, and moving it would pull the epic back from Build
181
+ — the same transition, from the one function that owns it (`markInReview`, `cli/epic-state.mjs`).
182
+ `yad-review-gate action: open` runs that command; hand off to it rather than editing the ledger here.
183
+
184
+ **With no platform configured** it writes the ledger and simply opens no PR, so this works offline.
185
+ **With a platform** the `review/EP-<slug>/test-cases` branch must already be **on origin** — the command
186
+ refuses and writes nothing otherwise. Cut it from the authoring branch and push it before handing off
187
+ (or run `yad open-pr` from that branch: it pushes the branch, then delegates).
188
+
189
+ Do **not** hand-edit `state.json`, and do **not** touch `approvals.json` — only real reviewers approve,
190
+ through the gate.
182
191
 
183
192
  ### Step 6 — Stop at the gate (do NOT advance)
184
193
  Report: the path to `test-cases.md`, the connected testing tool and what it produced (e.g. "Playwright —
185
194
  6 tests generated", the suite path + `test-links.json` path, or "no testing tool — artifacts-only"), that
186
195
  Build may already be underway in parallel, and that the next action is **review** via
187
- `yad-review-gate` (base rule: owner + 1 reviewer). **Never record approval here.** Shape steps do not
188
- auto-advance. When the hub has a platform, the gate opens a review
189
- PR on the hub (via `yad-hub-bridge`) and `yad-review-gate action: sync` pulls platform approvals/comments
196
+ `yad-review-gate` (base rule: 1 distinct approver, who should not be the author). **Never record approval here.** Shape steps do not
197
+ auto-advance. When the Product has a platform, the gate opens a review
198
+ PR on the Product (via `yad-hub-bridge`) and `yad-review-gate action: sync` pulls platform approvals/comments
190
199
  into the ledger; otherwise the review is recorded local.
191
200
 
192
201
  ## Reference
@@ -56,15 +56,18 @@ Written by `yad-test-cases` Step 4b. Absent when the step ran artifacts-only (`t
56
56
  - **Cover every story.** The "Coverage & traceability" section must map each story's acceptance criteria
57
57
  to at least one case — an unmapped criterion is a gap the reviewer should catch.
58
58
  - **Priorities are risk-based.** P0 = critical (run on every commit) … P3 = low (on-demand); depth
59
- scales with impact (Murat's principle).
59
+ scales with impact.
60
60
  - **Prefer the lowest useful level.** unit > integration > E2E when a case can be verified lower.
61
61
  - **`repos` is a subset of `epic.repos`.** Automation cannot target a repo the epic does not declare.
62
62
  - **Single-file, not a folder.** `test-cases.md` resolves through the gate's default content-hash path
63
- (the file's bytes), so the review gate, revoke-on-change, and review-PR machinery work unchanged.
63
+ (the file without its frontmatter `status:` line), so the review gate, revoke-on-change, and review-PR machinery work unchanged.
64
64
  - **Automation is additive.** When no testing tool is connected, the step still produces a complete
65
65
  `test-cases.md`; `testing: none` and no `test-links.json`.
66
66
 
67
67
  ## Review routing (the test-cases gate)
68
68
 
69
- The test-cases gate uses the **base rule** (owner + 1 reviewer) — it is not escalated. The natural
70
- reviewer is the test architect / QA owner, but the gate predicate requires only owner + 1.
69
+ The test-cases gate uses the **base rule**: at least 1 distinct approver, who should not be the author.
70
+ The step carries no risk tags, so its full count is also 1. The natural reviewer is the test architect /
71
+ QA owner, but the gate names no role — any approver counts. yadflow does not itself check that the
72
+ approver is not the author (see `yad-review-gate`). The review PR requests no reviewers; the team asks
73
+ them on the PR itself.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yad-timeline
3
- description: 'Phase 6 output enrichment (never a gate) — render a feature THREAD as an evolution view AND resolve its current truth. Walks the thread (genesis -> changes -> defects, linked by parent: frontmatter), renders the evolution as the vendored React/Vite/Tailwind shell HTML + a TIMELINE.md summary (each node: kind, what it re-authored vs inherited, ship events, contract re-lock history, open debt), and emits thread-resolved.md — the composed CURRENT-TRUTH map (the latest epic that owns each artifact + the resolved contract-lock hash). That resolved map is the source-of-truth AI/humans read to plan the next change, instead of a stale genesis epic. Degrades to markdown-only when no docs target is connected. Use when the user says "show the feature timeline", "how did this feature evolve", "resolve the current truth", or "render the thread".'
3
+ description: 'Phase 6 output enrichment (never a gate) — render a feature THREAD as an evolution view AND resolve its current truth. Walks the thread (genesis -> changes -> defects, linked by parent: frontmatter), renders the evolution as the vendored React/Vite/Tailwind shell HTML + a TIMELINE.md summary (each node: type, what it re-authored vs inherited, ship events, contract re-lock history, open debt), and emits thread-resolved.md — the composed CURRENT-TRUTH map (the latest epic that owns each artifact + the resolved contract-lock hash). That resolved map is the source-of-truth AI/humans read to plan the next change, instead of a stale genesis epic. Degrades to markdown-only when no docs target is connected. Use when the user says "show the feature timeline", "how did this feature evolve", "resolve the current truth", or "render the thread".'
4
4
  ---
5
5
 
6
6
  # SDLC — Feature Timeline + Current-Truth Resolver (Phase 6, output enrichment)
@@ -14,9 +14,9 @@ It is an **output enrichment**, exactly like `yad-docs` — **never a gate**: it
14
14
 
15
15
  ## Conventions
16
16
 
17
- - `{project-root}` resolves from the product hub.
17
+ - `{project-root}` resolves from the Product.
18
18
  - Reuses the **`yad-docs` shell** verbatim (`../yad-docs/templates/app/`) — generated `src/data/*.ts`,
19
- themed, deployed via `yad docs deploy`; build-only / markdown-only when no docs target
19
+ themed; build-only / markdown-only (`yad docs deploy` does not build `timeline-site/` yet)
20
20
  (`.sdlc/docs.json`). The resolver part drives the **`yad thread` CLI** (`cli/thread.mjs`).
21
21
  - The thread is **derived** from `parent:` frontmatter (no registry). The thread report lives under the
22
22
  **genesis** epic (`thread == genesis id`).
@@ -32,7 +32,8 @@ It is an **output enrichment**, exactly like `yad-docs` — **never a gate**: it
32
32
 
33
33
  ### Step 1 — Resolve the thread
34
34
  Run `yad thread <thread> --json` (`resolveThread` + `threadEpics` + `resolveCurrentArtifacts`). This
35
- gives the genesis-first chain, each epic's lineage (`kind`, `parent`, `inherits`), the resolved
35
+ gives the genesis-first chain, each epic's lineage (`type`, and `kind` holding the same value under
36
+ the older name, plus `parent` and `inherits`), the resolved
36
37
  current-truth map, and any open reconcile debt. **STOP** and report if the lineage is broken (point at
37
38
  `yad doctor` / `yad-reconcile`).
38
39
 
@@ -54,9 +55,9 @@ deterministically; theme from the design system). The thread maps onto the shell
54
55
  = what it re-authored, its side-effects = the ships it produced + any contract re-lock.
55
56
  - **System components** = the artifacts (epic/architecture/contract/ui/stories/test-cases), each labelled
56
57
  with the epic that currently **owns** it (from the resolved map).
57
- - Label and colour nodes by `kind` — render each node's kind noun (**Change request** / **Defect** /
58
+ - Label and colour nodes by `type` — render each node's type noun (**Change request** / **Defect** /
58
59
  **Hotfix** / **Epic** for feature) alongside its id, not the generic word "epic"; mark sealed epics and
59
- open debt. (A bug is a defect — `kind: defect`. Presentation only; every node is still an epic.)
60
+ open debt. (A bug is a defect — type `defect`. Presentation only; every node is still an epic.)
60
61
 
61
62
  ### Step 4 — Emit `thread-resolved.md` (the current-truth map — derived, non-authoritative)
62
63
  Write `epics/<thread>/thread-resolved.md`: for each artifact base, the **owning epic** (the latest in the
@@ -66,7 +67,7 @@ is the file the next `yad-change` / `yad-epic` reads as "the feature's current t
66
67
 
67
68
  ### Step 5 — Emit `TIMELINE.md` + (optional) deploy
68
69
  Write a short `epics/<thread>/TIMELINE.md` (the chain, what each node changed, ships, open debt) for a
69
- plain-text read — head each node with its kind noun (Change request / Defect / Hotfix / Epic) + id. On `action: deploy`, `yad docs deploy` the site (build-only when no target).
70
+ plain-text read — head each node with its type noun (Change request / Defect / Hotfix / Chore / Epic) + id. On `action: deploy`, note that `yad docs deploy` does not build this folder yet (it builds only the epic `docs-site/` and the overview) — build it with `npm ci` (or `npm install` when it has no lockfile) and `npm run build` inside the folder, and report it as build-only; a failed npm build is reported as a failure, never as a deploy.
70
71
 
71
72
  ## Hard rules
72
73