yadflow 3.18.1 → 4.0.0-next.1

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 (156) hide show
  1. package/CHANGELOG.md +355 -0
  2. package/README.md +79 -26
  3. package/bin/commands.mjs +41 -0
  4. package/bin/yad.mjs +437 -124
  5. package/cli/artifact-status.mjs +34 -15
  6. package/cli/checkpoint.mjs +69 -49
  7. package/cli/codeowners-command.mjs +170 -0
  8. package/cli/codeowners.mjs +397 -0
  9. package/cli/commit.mjs +13 -9
  10. package/cli/companion.mjs +2 -2
  11. package/cli/dial.mjs +183 -0
  12. package/cli/docs.mjs +88 -32
  13. package/cli/doctor.mjs +1472 -97
  14. package/cli/epic-state.mjs +3478 -232
  15. package/cli/epic.mjs +506 -0
  16. package/cli/errors.mjs +4 -1
  17. package/cli/gate.mjs +1002 -209
  18. package/cli/history.mjs +556 -0
  19. package/cli/hook.mjs +266 -55
  20. package/cli/hubcommit.mjs +6 -17
  21. package/cli/index-command.mjs +87 -0
  22. package/cli/ledger.mjs +57 -7
  23. package/cli/lib.mjs +184 -18
  24. package/cli/manifest.mjs +367 -56
  25. package/cli/migrate.mjs +726 -53
  26. package/cli/mode.mjs +170 -0
  27. package/cli/next.mjs +349 -90
  28. package/cli/openpr.mjs +191 -39
  29. package/cli/people.mjs +654 -0
  30. package/cli/plan.mjs +417 -132
  31. package/cli/platform.mjs +110 -129
  32. package/cli/product-index.mjs +287 -0
  33. package/cli/protection.mjs +706 -0
  34. package/cli/reconcile.mjs +38 -12
  35. package/cli/repo-publish.mjs +24 -26
  36. package/cli/repo.mjs +23 -14
  37. package/cli/report.mjs +21 -15
  38. package/cli/review.mjs +24 -27
  39. package/cli/riskmap-command.mjs +289 -0
  40. package/cli/riskmap.mjs +373 -0
  41. package/cli/setup.mjs +139 -287
  42. package/cli/ship.mjs +7 -6
  43. package/cli/skill.mjs +180 -0
  44. package/cli/skip.mjs +211 -30
  45. package/cli/thread.mjs +42 -17
  46. package/cli/tidy.mjs +20 -20
  47. package/cli/update-commit.mjs +22 -22
  48. package/cli/usage.mjs +115 -109
  49. package/package.json +3 -3
  50. package/skills/sdlc/config.yaml +166 -87
  51. package/skills/sdlc/module-help.csv +35 -35
  52. package/skills/yad-analysis/SKILL.md +125 -65
  53. package/skills/yad-architecture/SKILL.md +34 -23
  54. package/skills/yad-architecture/references/contract-format.md +10 -8
  55. package/skills/yad-backfill/SKILL.md +14 -8
  56. package/skills/yad-backfill/references/backfill.md +1 -1
  57. package/skills/yad-change/SKILL.md +127 -52
  58. package/skills/yad-change/references/triage.md +42 -28
  59. package/skills/yad-checks/SKILL.md +89 -45
  60. package/skills/yad-checks/references/check-gates.md +315 -92
  61. package/skills/yad-checks/templates/checks/build-test-lint.sh +25 -7
  62. package/skills/yad-checks/templates/checks/commit-message.sh +17 -3
  63. package/skills/yad-checks/templates/checks/contract-check.sh +58 -2
  64. package/skills/yad-checks/templates/checks/epic-open.sh +3 -3
  65. package/skills/yad-checks/templates/checks/install-deps.sh +46 -0
  66. package/skills/yad-checks/templates/checks/ledger-guard.sh +94 -18
  67. package/skills/yad-checks/templates/checks/lineage-check.sh +23 -9
  68. package/skills/yad-checks/templates/checks/package-manager.sh +140 -0
  69. package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +4 -4
  70. package/skills/yad-checks/templates/checks/risk-map-check.sh +438 -0
  71. package/skills/yad-checks/templates/checks/verified-commits.sh +20 -46
  72. package/skills/yad-checks/templates/github/yad-checks.yml +37 -5
  73. package/skills/yad-checks/templates/github/yad-hub-checks.yml +5 -5
  74. package/skills/yad-checks/templates/github/yad-update-guard.yml +3 -4
  75. package/skills/yad-checks/templates/github/yad-verified-commits.yml +4 -4
  76. package/skills/yad-checks/templates/gitlab/.gitlab-ci.yml +7 -1
  77. package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +22 -4
  78. package/skills/yad-checks/templates/gitlab/yad-hub-checks.gitlab-ci.yml +5 -5
  79. package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +4 -4
  80. package/skills/yad-checks/templates/hooks/ledger-guard-cursor.sh +91 -0
  81. package/skills/yad-checks/templates/hooks/ledger-guard.sh +38 -7
  82. package/skills/yad-commit/SKILL.md +6 -6
  83. package/skills/yad-connect-design/SKILL.md +6 -6
  84. package/skills/yad-connect-design/references/design-context.md +1 -1
  85. package/skills/yad-connect-design/references/design-registry.md +2 -2
  86. package/skills/yad-connect-docs/SKILL.md +12 -12
  87. package/skills/yad-connect-docs/references/docs-registry.md +1 -1
  88. package/skills/yad-connect-learning/SKILL.md +5 -5
  89. package/skills/yad-connect-learning/references/learning-registry.md +2 -2
  90. package/skills/yad-connect-repos/SKILL.md +92 -54
  91. package/skills/yad-connect-repos/references/code-context.md +6 -6
  92. package/skills/yad-connect-repos/references/hub-config.md +68 -58
  93. package/skills/yad-connect-repos/references/repos-registry.md +10 -9
  94. package/skills/yad-connect-repos/references/risk-map.md +81 -0
  95. package/skills/yad-connect-testing/SKILL.md +6 -6
  96. package/skills/yad-connect-testing/references/testing-context.md +3 -4
  97. package/skills/yad-connect-testing/references/testing-registry.md +2 -2
  98. package/skills/yad-defects/SKILL.md +8 -8
  99. package/skills/yad-discovery/SKILL.md +130 -94
  100. package/skills/yad-discovery/references/discovery-schema.md +23 -7
  101. package/skills/yad-discovery/references/foundation-schema.md +374 -0
  102. package/skills/yad-docs/SKILL.md +16 -11
  103. package/skills/yad-docs/references/data-mapping.md +9 -7
  104. package/skills/yad-docs/templates/app/package-lock.json +3 -3
  105. package/skills/yad-docs-overview/SKILL.md +32 -17
  106. package/skills/yad-docs-overview/references/pipeline-model.md +47 -28
  107. package/skills/yad-docs-sync/SKILL.md +10 -5
  108. package/skills/yad-docs-sync/references/staleness.md +8 -7
  109. package/skills/yad-engineer-review/SKILL.md +88 -24
  110. package/skills/yad-engineer-review/references/ship-and-record.md +25 -16
  111. package/skills/yad-epic/SKILL.md +178 -100
  112. package/skills/yad-epic/references/state-schema.md +626 -117
  113. package/skills/yad-hub-bridge/SKILL.md +66 -48
  114. package/skills/yad-hub-bridge/references/bridge.md +110 -83
  115. package/skills/yad-hub-bridge/references/login-roster.md +163 -70
  116. package/skills/yad-hub-bridge/templates/checks/hub-route.sh +22 -19
  117. package/skills/yad-hub-bridge/templates/github/yad-gate-sync.yml +34 -14
  118. package/skills/yad-hub-bridge/templates/gitlab/gitlab-ci.include-root.yml +2 -2
  119. package/skills/yad-hub-bridge/templates/gitlab/yad-gate-sync.gitlab-ci.yml +22 -12
  120. package/skills/yad-implement/SKILL.md +29 -15
  121. package/skills/yad-implement/references/implement-conventions.md +2 -2
  122. package/skills/yad-learn/SKILL.md +9 -9
  123. package/skills/yad-learn/references/learning-state.md +2 -2
  124. package/skills/yad-open-pr/SKILL.md +64 -29
  125. package/skills/yad-pair-review/SKILL.md +18 -16
  126. package/skills/yad-pair-review/references/session-state.md +4 -4
  127. package/skills/yad-pr-template/SKILL.md +48 -27
  128. package/skills/yad-pr-template/references/risk-routing.md +97 -24
  129. package/skills/yad-pr-template/templates/checks/pr-template.sh +37 -15
  130. package/skills/yad-pr-template/templates/checks/pr-title.sh +27 -13
  131. package/skills/yad-pr-template/templates/checks/risk-route.sh +107 -14
  132. package/skills/yad-pr-template/templates/github/pull_request_template.md +7 -5
  133. package/skills/yad-pr-template/templates/gitlab/merge_request_templates/Default.md +7 -5
  134. package/skills/yad-pr-template/templates/hub/github/pull_request_template.md +15 -14
  135. package/skills/yad-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +15 -13
  136. package/skills/yad-reconcile/SKILL.md +3 -3
  137. package/skills/yad-report/SKILL.md +5 -5
  138. package/skills/yad-review-companion/SKILL.md +12 -9
  139. package/skills/yad-review-gate/SKILL.md +198 -79
  140. package/skills/yad-review-gate/references/gating.md +230 -54
  141. package/skills/yad-run/SKILL.md +86 -56
  142. package/skills/yad-run/references/run-loop.md +67 -45
  143. package/skills/yad-ship/SKILL.md +18 -14
  144. package/skills/yad-spec/SKILL.md +31 -17
  145. package/skills/yad-spec/references/spec-handoff.md +17 -5
  146. package/skills/yad-status/SKILL.md +114 -56
  147. package/skills/yad-stories/SKILL.md +42 -27
  148. package/skills/yad-stories/references/story-schema.md +10 -9
  149. package/skills/yad-stub/SKILL.md +59 -48
  150. package/skills/yad-sync-repos/SKILL.md +3 -3
  151. package/skills/yad-test-cases/SKILL.md +37 -30
  152. package/skills/yad-test-cases/references/test-cases-schema.md +8 -5
  153. package/skills/yad-timeline/SKILL.md +8 -7
  154. package/skills/yad-ui/SKILL.md +46 -25
  155. package/cli/roster.mjs +0 -164
  156. package/skills/sdlc/install.sh +0 -68
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yad-status
3
- description: 'Read-only view of an SDLC epic: prints the current step, each step''s dials (assistance/automation) and status, and which approvals are still required at the active gate. For stories in the build half it also prints each back-half step''s automation dial, status, and trust record (runs / % approved-unchanged / whether it clears the threshold to be earned), plus the system-wide kill-switch state — so the team can see WHY a step is automated and reverse it with evidence. Also prints the cross-cutting personal skills-log roll-up from the LOCAL-ONLY learning ledger (gitignored, never committed/pushed — the local learner''s own learning, by stage). Surfaces the Phase 5 instrumentation signals: per-step "earned but manual" (nudge cost) and, across multiple epics, a fleet roll-up (scale of read). Use when the user says "yad status", "where is epic EP-...", "what is blocking the gate", "show the trust record", "team skills", or "fleet status".'
3
+ description: 'Read-only view of an SDLC epic: prints the current step, each step''s dials (driver/advance, under either spelling) and status, and which approvals are still required at the active gate. For stories in Build it also prints each Build step''s automation dial, status, and run record (runs / % approved-unchanged, as advice), plus the kill switch and the Shape author dials from .sdlc/automation.json — so the team can see WHY a step is automated and reverse it. Also prints the cross-cutting personal skills-log roll-up from the LOCAL-ONLY learning ledger (gitignored, never committed/pushed — the local learner''s own learning, by stage). Across multiple epics, prints a fleet roll-up (scale of read). Use when the user says "yad status", "where is epic EP-...", "what is blocking the gate", "show the trust record", "team skills", or "fleet status".'
4
4
  ---
5
5
 
6
6
  # SDLC — Status (read-only)
@@ -10,7 +10,8 @@ reads `.sdlc/` and `reviews/` and reports.
10
10
 
11
11
  ## Conventions
12
12
  - `{project-root}` resolves from the project working directory.
13
- - Operate on one epic: `{project-root}/epics/EP-<slug>/`.
13
+ - Operate on one epic: `{project-root}/epics/EP-<slug>/`. The Product level is the exception:
14
+ `EP-foundation` lives at `{project-root}/foundation/` (its `.sdlc/` and `reviews/` are there).
14
15
 
15
16
  ## On Activation
16
17
 
@@ -20,14 +21,16 @@ report all if the user asked for an overview).
20
21
 
21
22
  ### Step 2 — Read state
22
23
  Read `.sdlc/state.json`, `.sdlc/approvals.json`, `epic.md` frontmatter (for `repos`), and — if present
23
- — `.sdlc/contract-lock.json`. For the build half (Phase 4), also read — if present — every
24
+ — `.sdlc/contract-lock.json`. For Build (Phase 4), also read — if present — every
24
25
  `.sdlc/build-state/<story-id>.json`, and the trust ledger read as the **union** of the folded
25
26
  `.sdlc/trust-log.json` `runs` PLUS every loose `.sdlc/trust-log/` shard (concatenate — every shard is a
26
27
  distinct run; never dedup by story/repo/step — but DO skip a shard whose full identity
27
28
  `(story,repo,step,uid)` already appears in the folded `runs`, i.e. a half-applied `yad tidy up`). All are committed by `yad checkpoint` (so a fresh clone
28
29
  or another machine sees current evidence; `yad tidy up` folds finished shards into `trust-log.json`).
29
30
  Also read the `automation` block of
30
- `skills/sdlc/config.yaml` (`back_steps`, `trust_threshold`, `locked_steps`, `kill_switch`). For the
31
+ `.sdlc/config.yaml` (`back_steps`), and `.sdlc/automation.json` if present — the kill switch and the
32
+ Shape author steps set to auto (absent = the switch off, every Shape step human). The effective dial of any
33
+ step is `yad dial … --json`, which applies the kill switch and gates for you. For the
31
34
  cross-cutting learning layer, also read — if present — the **local-only** `.sdlc/learning-records.json`
32
35
  (the per-epic learning ledger, gitignored) and the project-wide `{project-root}/.sdlc/learning-records.json`.
33
36
  Do not modify any of them.
@@ -35,72 +38,127 @@ Do not modify any of them.
35
38
  ### Step 3 — Report
36
39
  Print, in this order:
37
40
 
38
- 1. **Header:** render the kind noun from `epic.md` frontmatter `kind` — **Change request** (`change`),
39
- **Defect** (`defect`), **Hotfix** (`hotfix`), or **Epic** (`feature`, and the default when `kind` is
40
- absent) — followed by `epicId`, then `status` from `epic.md` frontmatter, `currentStep`, and `repos`
41
+ 1. **Header:** render the type noun from the `epic.md` frontmatter work-item type. Two names carry it,
42
+ `kind:` and `type:`; read `kind:` first, then `type:`. **Change request** (`change`),
43
+ **Defect** (`defect`), **Hotfix** (`hotfix`), **Chore** (`chore`), or **Epic** (`feature`, and the default when neither is
44
+ present) — followed by `epicId`, then `status` from `epic.md` frontmatter, `currentStep`, and `repos`
41
45
  (the touched domains). Example: `Defect EP-checkout-queue-filter — draft @ stories`. A bug is a defect
42
- (`kind: defect`) — there is no separate noun. This is presentation only; the artifact is still an epic.
43
- 2. **Steps table** — for every front step in `steps[]` order (10, or 12 when the optional analysis step
44
- was run): `id`, `type`, `status`, `assistance`, `automation`, `locked`, and `risk_tags`. Mark the
45
- `currentStep` with `→`. The gating chain is `[analysis → analysis-review →] epic → epic-review →
46
- architecture → architecture-review → ui-design → ui-design-review → stories → stories-review` →
47
- **`ready-for-build`** (the bracketed `analysis` prefix is present only when `yad-analysis` seeded it).
46
+ (type `defect`) — there is no separate noun. This is presentation only; the artifact is still an epic.
47
+ 2. **Steps table** — for every Shape step in `steps[]` order, however many there are: `id`, `type`,
48
+ `status`, the two dials (`driver`/`assistance` and `advance`/`automation` — read whichever the step carries, the OLD name wins), `locked`, and `risk_tags`. Mark the
49
+ `currentStep` with `→`. **The chain length is a fact about the epic's ROUTE, never a constant** —
50
+ read `profile` from `state.json`: `classic` is 10 steps, `analysis-first` 12, and the short lanes
51
+ `chore` 4 and `spike` 6 (E40). On `classic` the gating chain is `[analysis → analysis-review →]
52
+ epic → epic-review → architecture → architecture-review → ui-design → ui-design-review → stories →
53
+ stories-review` → **`ready-for-build`** (the bracketed `analysis` prefix is not on `classic`: it is
54
+ what makes `analysis-first`, the route `yad-analysis` seeds). A short lane runs `epic → epic-review → stories → stories-review` →
55
+ **`ready-for-build`**, with `analysis` in front on `spike`, and has no architecture, UI-design or
56
+ test-case rows at all — render what `steps[]` holds and never a step it lacks.
48
57
  `test-cases → test-cases-review` is a **parallel, non-blocking track**: it opens when `stories-review`
49
- passes and runs alongside the build half, so when `currentStep` is `ready-for-build` the `test-cases`
58
+ passes and runs alongside Build, so when `currentStep` is `ready-for-build` the `test-cases`
50
59
  step may still be `in_progress`/`in_review` — show its status, and note "parallel" so it is clear it
51
60
  does not gate the build. Always render exactly the steps present in `steps[]`.
52
- - **Skipped (N/A) steps:** the optional `ui-design` step may be marked N/A for an epic with no
53
- user-facing surface. **Both** the `ui-design` author step **and** its `ui-design-review` gate stay
54
- in `steps[]`, each carrying `skipped: true`, `status: "done"`, and a `skipReason`. Render **each**
55
- as `<id> — SKIPPED (N/A: <skipReason>)` (with `skippedBy`/`skippedAt` if present) instead of the
56
- plain status, so the deliberate skip and its reason are visible and the gate does not appear to
57
- vanish. The chain then reads `… architecture-review → ui-design (N/A) → ui-design-review (N/A) →
61
+ - **Skipped (N/A) steps:** a step the epic's route marks optional — `ui-design`, on the routes that
62
+ ship — may be marked N/A with `yad skip`. **Both** the author step **and** its `-review` gate stay
63
+ in `steps[]`, each with `status: "skipped"` and a `record` (`{ reason, by, date }`). A file from
64
+ before shape 7 spells the same thing `status: "done"` with `skipped: true` and a `skipReason`
65
+ beside it; read either. Render **each** as `<id> — SKIPPED (N/A: <reason>)` (with who and when if
66
+ present) instead of the plain status, so the deliberate skip and its reason are visible and the
67
+ gate does not appear to vanish. The chain then reads `… architecture-review → ui-design (N/A) → ui-design-review (N/A) →
58
68
  stories → …`; the review gate never needs approvals.
69
+ - **Deferred steps:** `yad defer` sets an optional step aside to come back to later. Both the author
70
+ step and its `-review` gate carry `status: "deferred"` and a `record`. Render each as
71
+ `<id> — DEFERRED (later: <reason>)`, with who and when if present. A deferred step is still owed:
72
+ never render it as done or as N/A.
73
+ - **Debt:** a step carrying `"debt": true` (written by `yad defer … --debt`) is owed back and must be
74
+ reminded until paid. Add `· DEBT` to its line, and list every debt in a short **Owed** block under
75
+ the chain with the command that pays it: `yad undefer <epic> <id>` while it is still `deferred` (on a verified Product,
76
+ say that verb is refused once the ledger is on the default branch), or
77
+ "being paid back — clears when `<id>-review` passes" once it is back in progress. The flag is
78
+ removed only when that review passes. `yad doctor` reports the same list as `step:debt`.
79
+ - **Closed steps:** a `done` step may carry `closed` (E18) — `{ by, date, via, pr?, … }`. Add
80
+ `(closed <date>, via <via>, PR #<pr>)` to its line when it is there, and nothing when it is not: a
81
+ step closed before this release has none, and that is not a fault.
82
+ - **Re-opened steps:** an unfinished step with a later step `done` (not its own `-review` gate) was
83
+ put back after the chain built past it — a late `yad undefer`. Render it as
84
+ `<id> — RE-OPENED (beside finished work)`: it does not block the finished steps after it, and
85
+ `currentStep` stays where it is. `yad next <epic>` prints it as a `re-opened lane`.
86
+ - **Blocked steps:** a step with `status: "blocked"` **and** a `record` is waiting on someone outside
87
+ the workflow. Render it as `<id> — BLOCKED (<reason>)`, with who recorded it and when, and say it is
88
+ cleared with `yad unblock <epic> <id>` once the wait is over — on a verified Product that verb refuses
89
+ once the ledger is on the default branch, so say so. A `blocked` with no record is the older
90
+ word for `todo`: render it as not started.
59
91
  3. **Active gate** — for the `currentStep` (if it is a `review+approve` step), compute and show:
60
- - the reviewer rule in force — **base** (`owner + 1 reviewer`), **escalated** (list the required
61
- domains), or **per-repo** for `stories-review` (list each repo needing sign-off),
62
- - approvals **recorded so far** (from `approvals.json`), and
63
- - approvals **still required** to pass the gate (name the missing domains/repos).
92
+ - the count in force — **distinct approvers** recorded, against the **base** (1, enforced) and the
93
+ **full count** from the step's risk tags (advisory),
94
+ - approvals **recorded so far** (from `approvals.json`, one line per approver), and
95
+ - approvals **still required** to pass the gate (`1 approval(s)`, or none).
64
96
  Do not advance — just state whether the gate would pass right now.
65
97
 
66
98
  Apply the same predicate `yad-review-gate` uses (restated here so this skill is
67
99
  self-contained). From the `approved` records in `approvals.json` for the current step:
68
- - `owners` = records with `role == "owner"`; `reviewers` = distinct `role == "reviewer"`;
69
- `domainOwners` = `role == "domain-owner"`, grouped by `domain`.
70
- - **Base pass:** `|owners| >= 1` AND `|reviewers| >= 1` (the configured `default_reviewers`).
71
- - **Escalated pass** (step `risk_tags` ∩ `{contract, auth, payments}` ≠ ∅): base pass AND, for
72
- every touched domain, `|domainOwners[domain]| >= 1`. Touched domains = `epic.repos` for
73
- `architecture-review`; the union of every story's `repos` for `stories-review`.
74
- - Approvals are **stale** (gate fails) if the artifact was edited after the newest `approved`
75
- record. For `architecture-review`, also flag staleness if the contract-surface hash no longer
76
- matches `.sdlc/contract-lock.json`.
100
+ - `approvers` = the distinct, non-empty `approver` values of the approvals that are not stale (below).
101
+ A record that names nobody counts as nobody. When `requireEngagement` is on in the Product config,
102
+ only approvals with `engagement: verified` count. There are no roles; a `role` or `domain` an older
103
+ record carries is legacy data, and it counts for nothing.
104
+ - **Pass (team mode):** `|approvers| >= 1` — the base — plus, with a platform, resolved review threads and a merged
105
+ review PR/MR. Solo mode waives approvals entirely.
106
+ - **The full count, reported on every step that is not inherited, skipped or deferred:** `needed = base 1 + risk step` — plus `2` when the
107
+ step's `risk_tags` carry `contract`, or `1` when they carry `auth`/`payments` (the highest tag,
108
+ never the sum). The engine **caps** that ask at `active − 1` (floor 1) and prints it (E72) — for
109
+ example a contract gate asks 3, and with 2 active people the capped ask is 1. The risk step is
110
+ ADVISORY, capped or not — it never decides whether the gate would pass, because the count
111
+ of people can read high (a git name and a platform login are two people until proven one). When the
112
+ people could not be counted, no cap is shown. `yad gate status` prints the sum and the shortfall
113
+ (`; count: 3 approvers = base 1 + contract risk 2 — capped to 1: 2 active people, less one seat
114
+ for the author — base enforced, risk step advisory — 1 short`, or without the `capped to …` part
115
+ when the cap lowered nothing) — read it from there rather than recomputing it, and say "short N"
116
+ rather than "blocked" when it is short. A closed team gate whose ask was lowered says
117
+ `count capped from 3 to 1 (2 active people)`. In solo mode it prints no shortfall.
118
+ - **A gate that may not pass (E73):** under a team gate that has not passed, `yad gate status` can
119
+ print a warning line. Relay it as stated, as a warning and never as "blocked": it holds nothing.
120
+ A line starting `! may not be met:` means there is no approval in the counting window and the one
121
+ required approval may have nobody but the author to give it; another person's approval settles it.
122
+ A line starting `! if the risk step were enforced:` is a what-if: the extra approvals that risk
123
+ tags add could not all be given by the people counted. The gate can still pass today, and the line
124
+ says so.
125
+ - **How many people there are to ask (E71), printed once per epic and not per step:** `active people:
126
+ 4 in the last 90 days — caps each gate's count at 3 approvers (one seat is left for the author);
127
+ reported, only the base is enforced`, with the window's basis on the line under it. It is
128
+ the count the cap (E72) uses, so never report a step as blocked by it. A source that could not be
129
+ read prints `active people: NOT COUNTED — <which source> — no cap can be shown, and only the base
130
+ holds each gate`: report that wording as it stands and NEVER as a number or as "no people" — an
131
+ unreadable input is not a small team.
132
+ - **Solo mode may be wrong (E74):** in solo mode, under the `active people:` line, `yad gate status`
133
+ can print `! solo mode is on, but … so more than one person may work on this Product`. Relay it as
134
+ a suggestion to run `yad mode team`, never as a fault and never as switched: nothing changes until
135
+ a person runs it. It never suggests solo mode.
136
+ - Touched domains (`epic.repos` for a step with a risk tag; the union of every story's `repos` for
137
+ `stories-review`) only label the review. They add no approvals.
138
+ - An approval is **stale** (it no longer counts) when the `artifactHash` it recorded no longer
139
+ matches the artifact's current fingerprint — the content changed after that person approved. For
140
+ `architecture-review` the fingerprint is the contract surface in `contract.md`. An approval with no
141
+ `artifactHash` is never stale. `yad gate status` prints the stale count. For `architecture-review`,
142
+ also flag when the contract-surface hash no longer matches `.sdlc/contract-lock.json`.
77
143
  4. **Contract lock** — if `.sdlc/contract-lock.json` exists, show the locked hash and `lockedAt`
78
144
  (and, when at/after `architecture-review`, whether the current surface still matches it).
79
145
  5. **Stories** — if `stories/` has files, list each story `id` and its `repos` tags.
80
146
  6. **Files** — list the review records present under `reviews/` for the current artifact.
81
- 7. **Build half (per story, per repo)** — if any `.sdlc/build-state/<story-id>.json` exists, then for
82
- each such story and each of its repos print the back-half chain
147
+ 7. **Build (per story, per repo)** — if any `.sdlc/build-state/<story-id>.json` exists, then for
148
+ each such story and each of its repos print the Build chain
83
149
  `spec → tasks → implement → checks → engineer-review`, marking each step's `status`, its
84
- `automation` dial, and `locked`. Mark that repo's `currentStep` with `→`. This shows, at a glance,
85
- which back steps are automated and where a run is waiting. (For the single *next* build sub-step to
150
+ `advance` dial (or `automation`, whichever the step carries), and `locked`. Mark that repo's `currentStep` with `→`. A repo whose lane is `status: skipped` (a whole lane set aside with `yad skip <epic> <story> --repo <repo>`, E39) prints `skipped (N/A)` and its `record.reason` instead of the chain. This shows, at a glance,
151
+ which Build steps are automated and where a run is waiting. (For the single *next* build sub-step to
86
152
  take per story/repo — rather than this full status view — point the user at `yad next <epic>`, which
87
153
  reads the same `build-state` files.)
88
- 8. **Automation & trust** — print the system-wide **kill switch** state from `config.yaml`
89
- `automation.kill_switch` (when `on`, note that every step is forced to `human_approve`). Then, for
90
- each back-half step that has entries in the trust ledger — the **union** of the folded
91
- `.sdlc/trust-log.json` `runs` plus every loose `.sdlc/trust-log/` shard — print its **trust record**:
92
- number of runs, the fraction with `verdict == "approved-unchanged"`, and whether that clears
93
- `automation.trust_threshold` (`min_runs`, `min_approved_unchanged`) — i.e. whether the step is
94
- **earned** (eligible to be flipped to `machine_advance`) or still **gathering evidence**. Restate
95
- the predicate (self-contained): `earned = runs >= min_runs AND unchanged/runs >= min_approved_unchanged`.
96
- Never recommend flipping a locked step or a front state — those can never be `machine_advance`.
97
-
98
- **Nudge-cost signal (Phase 5 instrumentation).** For each back step that is **earned but its dial
99
- is still `human_approve`** (and it is not locked / not a front state), flag it:
100
- `⚠ earned but manual — could be machine_advance`. This is the *nudge cost* the Phase 5 trigger
101
- watches: automation that is proven safe but still hand-started. It is a read-only observation, not a
102
- recommendation to flip — earning the evidence and flipping the dial stay deliberate human acts
103
- (`yad-run action: set-dial`). See `docs/phase-5-build-plan.md` §"What to instrument now".
154
+ 8. **Automation & run record** — print the **kill switch** from `.sdlc/automation.json` (when on, who
155
+ turned it on, when and why, and that every step is held at `advance: human`), and the Shape author
156
+ steps the project set to `auto` — noting that a Shape `auto` is recorded only: nothing drives a Shape
157
+ step on its own yet. Then, for each Build step that has entries in the trust ledger — the **union** of
158
+ the folded `.sdlc/trust-log.json` `runs` plus every loose `.sdlc/trust-log/` shard — print its **run
159
+ record**: number of runs and the fraction with `verdict == "approved-unchanged"`. It is **advice**:
160
+ there is no threshold and nothing is "earned" (E34). Do not recommend flipping a dial; the team sets
161
+ dials with `yad dial`. A review gate is never auto.
104
162
 
105
163
  9. **My skills (the learning layer — local-only).** If `.sdlc/learning-records.json` exists for the epic
106
164
  (or the project-wide ledger does), print the **personal skills-log** roll-up from it — read-only. These
@@ -117,10 +175,10 @@ Print, in this order:
117
175
 
118
176
  10. **Fleet roll-up (overview only).** When the user asked for an overview, or more than one epic exists
119
177
  under `{project-root}/epics/`, print a one-line-per-epic roll-up across the fleet: each epic's
120
- `currentStep` (front gate) and, for stories in the build half, a count of back-half steps **waiting
121
- at a human gate** and of steps flagged **earned-but-manual**, plus a **local skills-log** count (records
178
+ `currentStep` (Shape gate) and, for stories in Build, a count of Build steps **waiting
179
+ at a human gate**, plus a **local skills-log** count (records
122
180
  in the local-only `learning-records.json`: learned / in-progress). Close with fleet totals (epics at
123
- each front gate; total earned-but-manual back steps; total concepts learned locally across the fleet).
181
+ each Shape gate; total concepts learned locally across the fleet).
124
182
  This is the
125
183
  *scale-of-read* signal the Phase 5 trigger watches — when this roll-up stops fitting in one glance,
126
184
  that is the measured bottleneck. Still strictly read-only; it only scans the per-epic files.
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  name: yad-stories
3
- description: 'Front state 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
- # SDLC — Author Stories (front state 7)
6
+ # SDLC — Author Stories (Shape step 7)
7
7
 
8
8
  **Goal:** Break an approved epic into human-authored, AI-assisted user stories, each with a stable
9
- `EP-<slug>-S0N` ID and a `repos` tag listing which repos must implement it. This is a **front state**:
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,8 +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**
41
- from the bridge's `review/…` branch.
40
+ Product's default branch. Author and commit the story files under `stories/` on it. This is **distinct**
41
+ from the verified ledger's `review/…` branch.
42
42
 
43
43
  ### Step 2 — Read inputs
44
44
  Read `epic.md` (scope, acceptance signals, `repos`), `architecture.md` (components by repo, flows),
@@ -48,7 +48,18 @@ must collectively satisfy the epic's acceptance signals and stay within the cont
48
48
  - **UI-optional-safe:** `ui-design.md` may be absent — the `ui-design` step is optional and can be
49
49
  marked N/A for an epic with no user-facing surface (state.json shows it `skipped`). When there is no
50
50
  UI design, proceed without UI screens; the epic's acceptance signals + contract remain the source of
51
- truth for the stories.
51
+ truth for the stories. If state.json shows it `deferred` instead, the UI **will** come later: write the
52
+ stories so they do not assume there are no screens, and note in each story that touches the UI that
53
+ its screens are still to be designed.
54
+ - **Short-lane-safe:** `architecture.md` and `contract.md` may BOTH be absent, and on the `chore` and
55
+ `spike` routes they always are — those lanes carry no architecture step, so there is no locked
56
+ contract for this epic. Read `state.json`'s `profile` key first — an epic seeded before file shape 6
57
+ has no such key, so fall back to what its `steps[]` actually contains, which is the real answer
58
+ either way. On a short lane, write the stories
59
+ from `epic.md` alone and say so in each story's "Contract & design touchpoints" section. Because
60
+ there is no lock, a story on a short lane **must not change the shared cross-repo surface**: if the
61
+ work turns out to need that, stop and say so — the epic belongs on `classic`, which has the
62
+ architecture gate that locks the surface.
52
63
 
53
64
  ### Step 2b — Load existing-code context (make the brain code-aware)
54
65
  Read the registry `{project-root}/.sdlc/repos.json` (`config.yaml` `code_context`). For **each repo in
@@ -63,7 +74,7 @@ Phase 3 build (Spec Kit per repo) accurate anchors instead of invented ones.
63
74
  - **Traceability:** record the loaded maps in each story's `code-context:` frontmatter field.
64
75
 
65
76
  ### 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
77
+ Adopt the **pm** lens. Decompose the epic into the smallest set of
67
78
  independently reviewable, independently buildable stories. For each story decide which repos it touches
68
79
  (must be a subset of the epic's `repos`). Prefer stories scoped to a clear slice of user value.
69
80
 
@@ -102,36 +113,40 @@ As a <role>, I want <capability>, so that <outcome>.
102
113
 
103
114
  ### Step 6 — Advance the authoring step (NOT the gate)
104
115
  **Check the mode first — the two modes have opposite instructions here.** Read `.sdlc/hub.json`:
105
- **bridge mode** is `platform` set AND `bridge_enabled` (or legacy `bridge`) `true`.
116
+ **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
117
 
107
- **Bridge 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
118
+ **verified mode — do NOT write `state.json`.** The ledger is CI-owned: the `ledger-guard` check rejects
119
+ any non-bot commit touching `epics/*/.sdlc/{state,approvals,comments,product-prs,hub-prs}.json` or
109
120
  `epics/*/reviews/*.md`, `yad gate open` deliberately skips this write for the same reason, and
110
121
  `yad gate ci --merged` performs the whole transition when the review PR merges. Making the edit here
111
122
  fails the gate if it rides the review PR, and desynchronises the ledger CI is about to rewrite if it
112
123
  is pushed around the gate. Commit **the story files under `stories/` only** — nothing else
113
124
  under `.sdlc/` — then hand off to `yad-review-gate`.
114
125
 
115
- **Otherwise — file-only, 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`.
126
+ **Otherwise — local, or a platform with no gate-sync CI — the engine makes this edit, not you.**
127
+ `yad gate open <epic> stories/` marks `stories-review` `in_review`, closes `stories` as `done`, and moves `currentStep` to the gate
128
+ — the same transition, from the one function that owns it (`markInReview`, `cli/epic-state.mjs`).
129
+ `yad-review-gate action: open` runs that command; hand off to it rather than editing the ledger here.
118
130
 
119
- > **File-only 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 bridge mode `gate open` writes nothing and local `gate sync` is advisory —
123
- > `gate ci` closes the step at merge.
131
+ **With no platform configured** it writes the ledger and simply opens no PR, so this works offline.
132
+ **With a platform** the `review/EP-<slug>/stories` branch must already be **on origin** — the command
133
+ refuses and writes nothing otherwise. Cut it from the authoring branch and push it before handing off
134
+ (or run `yad open-pr` from that branch: it pushes the branch, then delegates).
135
+
136
+ Do **not** hand-edit `state.json`, and do **not** touch `approvals.json` — only real reviewers approve,
137
+ through the gate.
124
138
 
125
139
  ### Step 7 — Stop at the gate (do NOT advance)
126
140
  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
129
- passes the epic becomes **`ready-for-build`** — the build half can start **and** the parallel
141
+ `yad-review-gate`. This review is an ordinary count gate: it passes with at least 1 distinct approver (who
142
+ 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
143
+ reviewers — the team asks them on the review PR itself. When this gate
144
+ passes the epic becomes **`ready-for-build`** — Build can start **and** the parallel
130
145
  **`test-cases`** track opens for the tester (`yad-test-cases`); the two run at the same time. **Never record
131
- approval here.** Front states 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
146
+ approval here.** Shape steps do not auto-advance. When the Product has a platform, the gate opens a review
147
+ PR on the Product (via `yad-hub-bridge`, with a `domain:<repo>` label per touched repo) and
133
148
  `yad-review-gate action: sync` pulls platform approvals/comments into the ledger; otherwise the review
134
- is recorded file-only.
149
+ is recorded local.
135
150
 
136
151
  ## Reference
137
152
  - Story frontmatter and body template: `references/story-schema.md`.
@@ -1,6 +1,6 @@
1
1
  # Story schema
2
2
 
3
- Each story authored at front state 7 is one Markdown file under `epics/EP-<slug>/stories/`, named
3
+ Each story authored at Shape step 7 is one Markdown file under `epics/EP-<slug>/stories/`, named
4
4
  `EP-<slug>-S0N.md` (zero-padded, never renamed).
5
5
 
6
6
  ## Frontmatter
@@ -9,10 +9,10 @@ Each story authored at front state 7 is one Markdown file under `epics/EP-<slug>
9
9
  |-------|--------|---------|
10
10
  | `id` | `EP-<slug>-S0N` | Stable story ID. Engine-assigned, zero-padded, never renamed. |
11
11
  | `epic` | `EP-<slug>` | Parent epic ID — the unbroken link back to the epic. |
12
- | `owner` | name | Inherited from `epic.md` `owner` (the single source — not retyped per story). Carries the responsible owner through to the build half. |
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.** |
15
- | `code-context` | `{ repos: [<name@sha>], loaded: <date> }` | Optional. Which connected-repo code-maps anchored "Notes for build" (front state 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. |
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
+ | `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
18
18
 
@@ -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,53 +101,47 @@ 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 front 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 bridge 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`).
130
141
  - **Make it real later:** `yad-backfill` for the code repo, then `yad-backfill promote EP-<slug>` to flip
131
142
  the stub to `verified: true`.
132
143
 
133
- Front states do not auto-advance. Suggest `yad next EP-<slug>` (prints the backfill-pending guidance) and
144
+ Shape steps do not auto-advance. Suggest `yad next EP-<slug>` (prints the backfill-pending guidance) and
134
145
  `yad thread EP-<slug>` to see the anchor and everything threaded off it.
135
146
 
136
147
  ## Hard rules
@@ -143,7 +154,7 @@ Front states do not auto-advance. Suggest `yad next EP-<slug>` (prints the backf
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