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,10 +1,11 @@
1
- # `yad-run` — the loop, the trust verdict, the threshold
1
+ # `yad-run` — the loop and the trust verdict
2
2
 
3
3
  This is the detail behind `SKILL.md`. It restates the orchestration so the skill is self-contained,
4
- and pins down the two judgments the skill makes: **what trust verdict to record** and **when a step
5
- has earned `machine_advance`**.
4
+ and pins down the judgment the skill makes: **what trust verdict to record**. Whether a step advances on
5
+ its own is not a judgment any more — the team sets the dial with `yad dial` (E34), and the engine answers
6
+ what applies.
6
7
 
7
- ## The back-half steps
8
+ ## The Build steps
8
9
 
9
10
  From `config.yaml` `automation.back_steps` plus the human merge gate:
10
11
 
@@ -12,68 +13,93 @@ From `config.yaml` `automation.back_steps` plus the human merge gate:
12
13
  spec → tasks → implement → checks → engineer-review(locked)
13
14
  ```
14
15
 
15
- `spec` and `tasks` are the two legs of `yad-spec` (the heavy ceremony, then the atomic `tasks.md`).
16
- `implement` is one atomic task via `yad-implement`. `checks` is `yad-checks (action: run)`.
17
- `engineer-review` is the human gate at `yad-engineer-review` — always a stop, never automated.
16
+ **These names are the engine's DEFAULTS, not a fixed wiring.** Which skill runs a step is the
17
+ project's setting in `.sdlc/skills.json`, so the loop reads `yad skill list --json` once at Step 0 and
18
+ runs every entry of that step's `skills`, in order, when it is bound to more than one. Unbound: `spec` and `tasks` are the two legs of `yad-spec` (the heavy ceremony, then the atomic
19
+ `tasks.md`), `implement` is one atomic task via `yad-implement`, and `checks` is
20
+ `yad-checks (action: run)`. `engineer-review` is the human gate at `yad-engineer-review` — always a
21
+ stop, never automated, and bindable like any other step.
18
22
 
19
23
  ## The loop (pseudocode)
20
24
 
21
25
  ```
22
26
  cfg = config.yaml.automation
23
- bs = build-state/<story>.json.repos[<repo>] # create from defaults if absent
27
+ bs = build-state/<story>.json.repos[<repo>] # create the FILE from defaults if absent; if the file
28
+ # exists but has no entry for <repo>, add one from the
29
+ # defaults — never remove an entry you did not add
30
+ if bs.status == "skipped": # E39: the whole lane was set aside with
31
+ STOP — report bs.record.reason # `yad skip <epic> <story> --repo <repo>`; do not drive it.
32
+ # `yad unskip <epic> <story> --repo <repo>` puts it back.
33
+ # Never write a single Build step as skipped or deferred.
24
34
  step = from or bs.currentStep
25
35
 
26
- while step is a back step (not engineer-review):
27
- result = run_step_skill(step) # yad-spec | yad-implement | yad-checks
36
+ while step is a Build step (not engineer-review):
37
+ result = run_step_skill(step) # the skill(s) `yad next --json` names for this lane
28
38
 
29
39
  signals = derive_signals(step, result) # see "Deriving signals"
30
40
  verdict = derive_verdict(signals) # rejected | approved-with-edits | approved-unchanged
31
41
  uid = fresh_short_token() # e.g. `openssl rand -hex 4` — unique per run,
32
42
  # never reuse; a collision would fuse two runs
33
43
  write trust-log/<story>-<repo>-<step>-<uid>.json # ONE shard file = ONE entry (never append to a shared file)
34
- = { story, repo, step, uid, automation: bs.step.automation, verdict, signals, ranBy, date }
44
+ # `automation` is recorded in the OLD vocabulary (this is a history record, and `yad migrate`
45
+ # deliberately leaves it alone). Read the step's dial from EITHER spelling.
46
+ = { story, repo, step, uid, automation: bs.step.automation ?? old_name_for(bs.step.advance), verdict, signals, ranBy, date }
35
47
 
36
48
  eff = effective_dial(step, bs, cfg) # see "Effective dial"
37
49
 
38
50
  if result is a HALT (failed / scope overrun / contract touch / ambiguous):
39
- bs.step.status = "blocked"; persist; checkpoint; STOP and report the human action needed
40
- elif eff == "machine_advance":
41
- bs.step.status = "done"; advance bs.currentStep to next; persist; checkpoint; continue # Step B advance
42
- else: # human_approve
43
- bs.step.status = "done"; persist; checkpoint; STOP and report "waiting for human at <next>"
51
+ # `blocked` needs its `record` (E38) — that is what separates a halted lane from one that has
52
+ # simply not started. `reason` is the halt cause you already have in hand.
53
+ bs.step.status = "blocked"
54
+ bs.step.record = { reason: "<check FAIL | scope overrun | contract touch | ambiguous>",
55
+ by: "<platform login, else git user.name, or null>", date: "<YYYY-MM-DD>" }
56
+ persist; checkpoint; STOP and report the human action needed
57
+ elif eff == "auto":
58
+ bs.step.status = "done"
59
+ bs.step.closed = { by: "<platform login, else git user.name, or null>", date: "<YYYY-MM-DD>", via: "auto", run: uid }
60
+ advance bs.currentStep to next; persist; checkpoint; continue # Step B advance
61
+ else: # "human"
62
+ bs.step.status = "done"
63
+ bs.step.closed = { by: "<platform login, else git user.name, or null>", date: "<YYYY-MM-DD>", via: "human", run: uid }
64
+ persist; checkpoint; STOP and report "waiting for human at <next>"
44
65
 
45
66
  # reached engineer-review: always stop, hand to yad-engineer-review (human gate, finalizes the verdict)
46
67
  ```
47
68
 
69
+ `closed` is the step's **closing record** (E18): who wrote it, when, and how the lane moved past the
70
+ step. `via: "auto"` means the dial let the run go on by itself; `via: "human"` means it stopped for a
71
+ person. `run` is the `uid` of the trust-log shard this run wrote, so the record points at the evidence.
72
+ `by` is the login `gh api user` / `glab api user` reports, else git `user.name`, else `null`
73
+ (`YAD_PLATFORM_LOGIN=0` turns the lookup off).
74
+ Write it only when you write `done`, and never over a `closed` already on the step.
75
+
48
76
  `ranBy` is `machine` when the *previous* step's effective dial caused this step to run without a human
49
77
  nudge; otherwise `human`. Persist build-state after every transition so a halt leaves an accurate,
50
78
  resumable record.
51
79
 
52
80
  `checkpoint` = run `yad checkpoint --push` from `{project-root}`. It commits the machine-written
53
- back-half ledgers (in this loop, the loose `trust-log/` shards this run wrote + `build-state/<story>.json`;
81
+ Build ledgers (in this loop, the loose `trust-log/` shards this run wrote + `build-state/<story>.json`;
54
82
  also the `build-log/` shards at engineer-review) — the shard dirs are what checkpoint stages, the same
55
83
  way `git gc` folds loose objects later (`yad tidy up` folds finished shards into the folded
56
84
  `trust-log.json` / `build-log.json`) — plus any story `status:` flip (→ in-build/shipped) once that
57
85
  story has a build-log ship (#112) — as one
58
- `chore(hub): sync back-half state — <epic>/<story> by @<login> [skip ci]`
59
- audit-trail commit, on the default branch only,
60
- staging *only* those files by an explicit allowlist (never a front-half gate file — so `ledger-guard`
86
+ `chore(hub): sync Build state — <epic>/<story> by @<login> [skip ci]`
87
+ audit-trail commit (`@<login>` when the platform login is known, else the git `user.name`, else `unknown`), on the default branch only,
88
+ staging *only* those files by an explicit allowlist (never a Shape gate file — so `ledger-guard`
61
89
  never trips). It is idempotent (a no-op when nothing changed), so calling it after every transition —
62
90
  including a halt — is safe and keeps the shared trust evidence current for CI, teammates, and
63
91
  `yad status` on other machines. It refuses to run off the default branch (an unsigned `[skip ci]`
64
92
  commit inside a future PR range would fail `verified-commits` and strand the PR).
65
93
 
66
- ## Effective dial (kill switch & locks always win)
94
+ ## Effective dial (the kill switch and gates always win)
67
95
 
68
96
  ```
69
- eff = bs.step.automation # human_approve | machine_advance
70
- if cfg.kill_switch == true: eff = "human_approve"
71
- if bs.step.locked == true: eff = "human_approve"
72
- if step in cfg.locked_steps: eff = "human_approve"
97
+ eff = (yad dial <epic> <story> --repo <repo> <step> --json).advance # "human" | "auto"
73
98
  ```
74
99
 
75
- So a kill switch, a `locked` flag, or membership in `locked_steps` forces a stop no matter what the
76
- per-step dial says. `engineer-review` and the five front states are covered by `locked` / `locked_steps`.
100
+ The engine reads the lane step's dial under either spelling (the OLD name wins), and answers `human`
101
+ when the step is a gate (`engineer-review`) or the kill switch in `.sdlc/automation.json` is on — whatever
102
+ the dial says. Its `why` says which: `lane`, `gate`, `kill` or `unknown` (a step id this release does not know), and `automationError` is present when the file cannot be read.
77
103
 
78
104
  ## Deriving signals & the provisional verdict
79
105
 
@@ -93,7 +119,7 @@ finalizes the entry — a human always has the last word on the trust signal.
93
119
  - `contract_touch` — `true` if the diff touched the locked contract surface without an upstream
94
120
  re-lock (routes back to the architecture gate).
95
121
 
96
- `derive_verdict(signals)` — the same three-way shape for every back step:
122
+ `derive_verdict(signals)` — the same three-way shape for every Build step:
97
123
  ```
98
124
  edited = human_edited_diff or human_edited_spec or task_rescoped
99
125
  if checks == "fail" or scope_overrun or contract_touch: verdict = "rejected"
@@ -106,35 +132,31 @@ may also override it to `rejected` — e.g. the human discards/regenerates the s
106
132
  rejects the diff at the engineer review for a reason no signal captured. A human override always wins.
107
133
 
108
134
  Rationale: the trust log should count an output as fully trustworthy (`approved-unchanged`) only when
109
- the machine's work was accepted as-is. Any human correction is `approved-with-edits` (useful but not
110
- yet trustworthy enough to automate); any failure or boundary breach is `rejected`.
135
+ the machine's work was accepted as-is. Any human correction is `approved-with-edits` (useful, and a sign
136
+ the step still wants a person); any failure or boundary breach is `rejected`.
111
137
 
112
- ## The trust threshold (when a step is earned)
138
+ ## The run record as advice (E34)
113
139
 
114
- A step is a **candidate** for `machine_advance` only when its trust evidence clears
115
- `config.yaml` `automation.trust_threshold`. `set-dial` enforces this predicate before flipping a step
116
- to `machine_advance`:
140
+ `yad dial` prints a step's record when someone sets its dial, and whenever it is asked with no `--to`:
117
141
 
118
142
  ```
119
- # read the ledger by UNION: the folded trust-log.json `runs` array PLUS every loose trust-log/ shard
120
- # (concatenate — every shard is a distinct run; never dedup by story/repo/step, the threshold counts re-runs)
121
- all = trust-log.json.runs + [read each file in trust-log/]
122
- slice = entries in `all` for this step (this story's repo; widen to the project if you track it there)
143
+ all = trust-log.json.runs + [read each file in trust-log/] # UNION; every shard is a distinct run
144
+ slice = entries in `all` for this step in this repo
123
145
  runs = len(slice)
124
146
  unchanged = count(e.verdict == "approved-unchanged" in slice)
125
- earned = runs >= trust_threshold.min_runs
126
- AND (unchanged / runs) >= trust_threshold.min_approved_unchanged
127
147
  ```
128
148
 
129
- Defaults: `min_runs: 5`, `min_approved_unchanged: 0.8`. If `earned` is false, `set-dial` refuses and
130
- reports `runs`, the `unchanged/runs` fraction, and how far short of the bar it is.
149
+ It is **advice, never a rule.** There is no threshold and no refusal: the team decides whether a step
150
+ runs on auto, and the record is what they read to decide. A step with no runs says so — no evidence either
151
+ way is not evidence against.
131
152
 
132
- Reverting (`to: human_approve`) is never gated — automation must be reversible in one move.
153
+ Reverting (`--to human`) and the kill switch are always one move.
133
154
 
134
155
  ## What stays human, always
135
156
 
136
157
  - `engineer-review` — the merge gate. `yad-run` always stops here and hands to `yad-engineer-review`.
137
- - The five front states (`epic`, `architecture`, `ui-design`, `stories`, `test-cases`) — not in
138
- `back_steps`, in `locked_steps`; the dial-setter refuses them.
158
+ - The Shape steps — this loop never drives them. A Shape author step's dial may be set to auto for the
159
+ project (`yad dial <step> --to auto`), and is only recorded until the engine runs agents (E26); every
160
+ Shape review gate is a person.
139
161
  - Any contract-surface change — halts the loop and routes back to the architecture gate, regardless of
140
162
  the dial.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: yad-ship
3
- description: 'Build-half helper of the gated SDLC — commit AND open the task PR/MR in one step. A thin orchestration over yad-commit then yad-open-pr: commit the staged atomic change by the conventions (Conventional-Commits subject, Task → Contract-Change trailers, an OPTIONAL Co-Authored-By footer that is OFF by default and added only when --ai <id> is explicitly passed, ≤3-file atomic guard), then push the branch and open the PR/MR from the committed template with the roster auto-assigned. The PR step runs ONLY if the commit lands (a failed commit, tripped guard, or --dry-run stops before pushing). Drives the `yad ship` CLI; never merges. Use when the user says "ship this task", "commit and open the PR", or "commit and raise the MR". (For the engineer review + merge, use yad-engineer-review.)'
3
+ description: 'Build helper of the gated SDLC — commit AND open the task PR/MR in one step. A thin orchestration over yad-commit then yad-open-pr: commit the staged atomic change by the conventions (Conventional-Commits subject, Task → Contract-Change trailers, an OPTIONAL Co-Authored-By footer that is OFF by default and added only when --ai <id> is explicitly passed, ≤3-file atomic guard), then push the branch and open the PR/MR from the committed template, assigned to the logged-in gh/glab login with no reviewers requested. The PR step runs ONLY if the commit lands (a failed commit, tripped guard, or --dry-run stops before pushing). Drives the `yad ship` CLI; never merges. Use when the user says "ship this task", "commit and open the PR", or "commit and raise the MR". (For the engineer review + merge, use yad-engineer-review.)'
4
4
  ---
5
5
 
6
- # SDLC — Commit + Open PR/MR (build-half helper)
6
+ # SDLC — Commit + Open PR/MR (Build helper)
7
7
 
8
- **Goal:** Do the two routine build-half hand-actions for ONE atomic task in a single step — **commit by
8
+ **Goal:** Do the two routine Build hand-actions for ONE atomic task in a single step — **commit by
9
9
  convention, then open the task PR/MR** — so an implemented diff becomes a reviewable PR/MR without two
10
10
  separate invocations. It is a thin wrapper over `yad-commit` and `yad-open-pr`; it holds no logic of
11
11
  its own and **never merges**. The engineer review + merge are Step E (`yad-engineer-review`).
@@ -19,12 +19,12 @@ its own and **never merges**. The engineer review + merge are Step E (`yad-engin
19
19
  `Task → Contract-Change → Co-Authored-By` (the footer **off by default** — added only via an explicit
20
20
  `--ai`), the ≤3-file atomic guard (`../yad-commit/SKILL.md`).
21
21
  - PR/MR: pushed branch, the committed template prefilled, title defaulting to the commit subject,
22
- roster auto-assign, risk routing (`../yad-open-pr/SKILL.md`).
22
+ the assignee set and no reviewers requested, risk routing (`../yad-open-pr/SKILL.md`).
23
23
  - **Order matters:** the PR/MR is opened **only if the commit lands**. A failed commit, a tripped
24
24
  atomic guard, or `--dry-run` stops the step before anything is pushed.
25
- - **Stage-aware on the product hub** (via `yad-open-pr`): on a `review/EP-*` branch `ship` opens the
26
- front-half **artifact-review** PR (delegating to `yad gate open` — `--title` is ignored); on any
27
- other hub branch it opens the **code-task** PR from the bundled code-task template. In a code repo
25
+ - **Stage-aware on the Product** (via `yad-open-pr`): on a `review/EP-*` branch `ship` opens the
26
+ Shape **artifact-review** PR (delegating to `yad gate open` — `--title` is ignored); on any
27
+ other Product branch it opens the **code-task** PR from the bundled code-task template. In a code repo
28
28
  it is unchanged.
29
29
 
30
30
  ## Inputs
@@ -33,11 +33,11 @@ its own and **never merges**. The engineer review + merge are Step E (`yad-engin
33
33
  - `ai` — co-author footer: `claude|copilot|cursor|coderabbit|none` (default `none` = **no
34
34
  footer**; the `Co-Authored-By` trailer appears only when this flag names a tool).
35
35
  - `task` — Task trailer (optional; derived from the branch when omitted).
36
- - `contractChange` — flag; marks the contract surface touched (commit trailer + PR escalation).
36
+ - `contractChange` — flag; marks the contract surface touched (commit trailer + a raised approver count on the PR).
37
37
  - `repo` / `risk` / `platform` / `title` — PR/MR options (see `yad-open-pr`).
38
38
  - `base` — override the PR/MR base. The default is the repo's own default branch, resolved
39
39
  by the full chain in **Base branch** (`yad-open-pr`) — the canonical description, including the
40
- hub rung — never a hardcoded `main`. A non-default base loses the AI first pass; `ship` warns and
40
+ Product rung — never a hardcoded `main`. A non-default base loses the AI first pass; `ship` warns and
41
41
  still opens.
42
42
 
43
43
  ## On Activation
@@ -53,12 +53,16 @@ yad ship --type <type> -m "<subject>" [--ai <id>] [--task <id>] [--contract-chan
53
53
  [--repo <name>] [--risk <level>] [--title "<subject>"]
54
54
  ```
55
55
  The CLI runs `yad commit` and, only if it succeeds, `yad open-pr` — committing the change, pushing the
56
- branch, and opening the PR/MR with the template prefilled and reviewers auto-assigned.
56
+ branch, and opening the PR/MR with the template prefilled and the assignee set. No reviewers are
57
+ requested: it prints `no reviewers were requested — ask them on the PR itself`.
57
58
 
58
59
  ### Step 3 — Route + stop (no merge)
59
- On `high` risk or a contract touch, run `bash checks/risk-route.sh <pr-body>` for the required
60
- domain-owner reviewers. Report the commit + the PR/MR URL. The PR now runs the check gates (Step C);
61
- the engineer review and merge are Step E (`yad-engineer-review`).
60
+ The open step prints how many approvers the PR asks for — the body's level and the base branch's risk
61
+ map, the larger step winning (E66). When it asks for more than one, `bash checks/risk-route.sh "<pr body>"`
62
+ lists the touched domains to ask; ask reviewers on the PR/MR itself. It also prints a reviewer
63
+ **suggestion** (E68): who has committed in the touched folders in the last 30 days, and what CODEOWNERS
64
+ lists — a hint about who may know the code, never a request and never a list of owners. Report the commit + the PR/MR URL. The PR now
65
+ runs the check gates (Step C); the engineer review and merge are Step E (`yad-engineer-review`).
62
66
 
63
67
  ## Hard rules
64
68
 
@@ -67,7 +71,7 @@ the engineer review and merge are Step E (`yad-engineer-review`).
67
71
  - **No AI footer by default.** The wrapped commit writes a `Co-Authored-By` trailer ONLY when `--ai <id>`
68
72
  is explicitly passed; never add it on the AI's own initiative.
69
73
  - **No PR without a landed commit.** A failed/`--dry-run` commit stops the step before pushing.
70
- - **High risk routes to domain owners** — the same escalation as the gate.
74
+ - **High risk raises the approver count** — the same count as the gate.
71
75
  - **Shipping here never merges.** The human owns the merge in `yad-engineer-review`.
72
76
 
73
77
  ## Reference
@@ -1,17 +1,17 @@
1
1
  ---
2
2
  name: yad-spec
3
- description: 'Build-half Step A of the gated SDLC. For one ready-for-build story and one of its repos, run the heavy Spec Kit ceremony ONCE (specify → clarify → plan → analyze → checklist → tasks) inside that code repo, writing specs/<story-id>/ in Spec Kit''s own layout. Drives /speckit.* as harness slash-commands when installed; authors the same files by hand and records speckit: not-installed when absent. References the locked contract — never re-invents the surface. Writes link.md back to the story. Never auto-advances. Use when the user says "spec story <id> in <repo>" or after a story is ready-for-build.'
3
+ description: 'Build Step A of the gated SDLC. For one ready-for-build story and one of its repos, run the heavy Spec Kit ceremony ONCE (specify → clarify → plan → analyze → checklist → tasks) inside that code repo, writing specs/<story-id>/ in Spec Kit''s own layout. Drives /speckit.* as harness slash-commands when installed; authors the same files by hand and records speckit: not-installed when absent. References the locked contract — never re-invents the surface. Writes link.md back to the story. Never auto-advances. Use when the user says "spec story <id> in <repo>" or after a story is ready-for-build.'
4
4
  ---
5
5
 
6
- # SDLC — Author Spec (build-half Step A)
6
+ # SDLC — Author Spec (Build Step A)
7
7
 
8
8
  **Goal:** Turn ONE `ready-for-build` story into a per-repo Spec Kit spec/plan/tasks inside that
9
9
  story's code repo. The heavy spec ceremony runs **once per story per repo**; the light
10
10
  tasks → implement loop is **Step B** (`yad-implement`). This step **never re-locks the contract** —
11
11
  the cross-repo surface is owned upstream by the architecture gate (build plan §A, Cross-cutting
12
- "Heavy spec once per story, light loop per task"). It does not advance the front-half state machine;
12
+ "Heavy spec once per story, light loop per task"). It does not advance the Shape state machine;
13
13
  when driven by the orchestrator (`yad-run`, Phase 4) it records a `spec`/`tasks` trust signal
14
- (Step 8) — but it never auto-advances a contract change or a front state.
14
+ (Step 8) — but it never auto-advances a contract change or a Shape step.
15
15
 
16
16
  Spec Kit is driven as **harness slash-commands** (`/speckit.*`), not a subprocess CLI (Phase 0
17
17
  Deviation 3). When Spec Kit is not installed, the same files are hand-authored in Spec Kit's exact
@@ -30,7 +30,7 @@ is the same graceful-degradation pattern `yad-ui` uses for Impeccable.
30
30
  `specs/<story-id>/`.
31
31
  - Spec Kit output layout (RESEARCH-NOTES §2): `specs/<feature-id>/spec.md` (+ `research.md`,
32
32
  `data-model.md`, `contracts/`), `plan.md`, `tasks.md`; constitution at `.specify/memory/constitution.md`.
33
- - 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`.
34
34
 
35
35
  ## Inputs
36
36
 
@@ -43,11 +43,10 @@ is the same graceful-degradation pattern `yad-ui` uses for Impeccable.
43
43
 
44
44
  ### Step 1 — Resolve the story and check readiness
45
45
  Read `{project-root}/epics/<epic>/.sdlc/state.json`. Proceed only when
46
- `currentStep == "ready-for-build"` (the gating front half — through the **stories** gate — is `done`).
47
- The **`test-cases` track may still be `in_progress`**: it is parallel and non-blocking, so the build
48
- half runs alongside it — its status does not affect readiness here. Read the story file
46
+ `currentStep == "ready-for-build"` (the gating Shape — through the **stories** gate — is `done`).
47
+ The **`test-cases` track may still be `in_progress`**: it is parallel and non-blocking, so Build runs alongside it — its status does not affect readiness here. Read the story file
49
48
  `epics/<epic>/stories/<story>.md`; confirm `repo` is in its `repos`. If the epic is not ready, STOP
50
- and point the user at `yad-status`. **Do not mutate front-half state** — `ready-for-build` semantics
49
+ and point the user at `yad-status`. **Do not mutate Shape state** — `ready-for-build` semantics
51
50
  stay intact.
52
51
 
53
52
  ### Step 2 — Resolve the target code repo
@@ -60,7 +59,20 @@ Read `epics/<epic>/contract.md` and `epics/<epic>/.sdlc/contract-lock.json`. The
60
59
  inputs (the API shapes, data-model entities, and events the story touches) are **quoted from the
61
60
  locked surface**, not re-authored. The spec MUST stay within that surface. If the story needs surface
62
61
  the contract does not define, STOP and route back to the **architecture gate** — never extend the
63
- contract here.
62
+ contract here. (On a route that HAS one; the short lanes do not — see below.)
63
+
64
+ - **Short-lane-safe:** read `epics/<epic>/.sdlc/state.json`'s `profile` first (an epic seeded before
65
+ file shape 6 has no such key — fall back to what its `steps[]` contains). On the `chore` and
66
+ `spike` routes there is no architecture step, so `contract.md` and `contract-lock.json` **never
67
+ exist** — that is the route's design, not a missing file to chase. Write the spec from the story and
68
+ `epic.md` alone, record `contract-lock: none` in Step 6's frontmatter, and say in the spec that this
69
+ epic defines no contract surface.
70
+ - A short lane has no architecture gate to route back to. So the rule above becomes stricter, not
71
+ looser: if the story turns out to need the shared cross-repo surface to CHANGE, **STOP and escalate
72
+ to a human** — the work belongs to a new epic on `classic`. Do not write the change into a spec on a
73
+ short lane. Do not create `specs/<story>/contracts/` at all on one — a short-lane story has no
74
+ surface to quote, and a slice folder under a lockless epic is what the CI gate refuses. (If one
75
+ already exists, a commit that only DELETES it is allowed through, which is the way back out.)
64
76
 
65
77
  ### Step 4 — Detect Spec Kit
66
78
  Check for `/speckit.*` slash-commands and/or `demo-repos/<repo>/.specify/`. Record the result for
@@ -84,17 +96,19 @@ to read. See `references/spec-handoff.md` for the exact file map and per-file de
84
96
  Write `demo-repos/<repo>/specs/<story>/link.md` (template in `references/spec-handoff.md`) with
85
97
  frontmatter linking the spec back to the product repo: `story`, `epic`, `repo`, `feature-id`,
86
98
  `product-repo` (path), `contract-lock` (the hash **copied** from `contract-lock.json`, NOT recomputed
87
- in the code repo), `speckit` (`installed | not-installed`), `generated` (date). This `link.md` plus the
99
+ in the code repo — or the literal `none` on a short-lane epic, which has no lock; never a made-up or
100
+ empty hash, which the CI gate reads as a broken lock and fails), `speckit`
101
+ (`installed | not-installed`), `generated` (date). This `link.md` plus the
88
102
  spec folder is the authoritative record that this story's spec exists.
89
103
 
90
- ### Step 7 — Stop (front-half state untouched)
104
+ ### Step 7 — Stop (Shape state untouched)
91
105
  Report: the spec folder path, the files written, whether Spec Kit was used, the task count from
92
106
  `tasks.md`, and that the next action is **Step B — `yad-implement`**. Do **not** edit the epic's
93
- `state.json`, `approvals.json`, or `contract-lock.json`. Step A is a generation step, not a front gate.
107
+ `state.json`, `approvals.json`, or `contract-lock.json`. Step A is a generation step, not a Shape gate.
94
108
 
95
109
  ### Step 8 — Record the `spec` trust signal (Phase 4b)
96
- When this step runs under the orchestrator (`yad-run`), the generated spec is a back-half run that the
97
- trust log measures (it is the evidence that could later earn the `spec` step a `machine_advance`). The
110
+ When this step runs under the orchestrator (`yad-run`), the generated spec is a Build run that the
111
+ trust log measures (part of the run record `yad dial` shows beside the `spec` dial). The
98
112
  verdict is **anchored to the human who accepts the spec**, never self-graded:
99
113
  - the human approves the generated `specs/<story>/` untouched → `approved-unchanged`;
100
114
  - the human edits the spec/plan/tasks before accepting → `approved-with-edits` (signal
@@ -105,8 +119,8 @@ pattern as the engineer review finalizing `implement` at `yad-engineer-review`).
105
119
  entry in its own shard `epics/<epic>/.sdlc/trust-log/<story>-<repo>-spec-<uid>.json` (a fresh `uid` per
106
120
  run; readers union the folded `trust-log.json` + the loose shards). Schema:
107
121
  `../yad-epic/references/state-schema.md`. **Run standalone, no trust entry is written** — the
108
- log measures orchestrated runs. `spec` stays `human_approve` until its slice clears the threshold;
109
- this step only *gathers* the evidence, it does not flip the dial.
122
+ log measures orchestrated runs. The record is advice: the `spec` dial is
123
+ whatever the team sets with `yad dial`, and this step never changes it.
110
124
 
111
125
  ## Hard rules (build plan §A, Cross-cutting)
112
126
 
@@ -33,6 +33,7 @@ demo-repos/<repo>/specs/<story-id>/
33
33
  research.md # decisions/unknowns resolved during clarify
34
34
  data-model.md # entities/fields THIS repo implements (quoting the shared ones from the contract)
35
35
  contracts/ # the API/event surface this repo implements (quoted from the locked contract)
36
+ # OMITTED ENTIRELY on a short-lane epic — see below
36
37
  plan.md # technical approach for this repo
37
38
  tasks.md # numbered atomic tasks (T01…), each scoped to the files it may touch
38
39
  link.md # back-pointer to the story in the product repo (Step A adds this; not a Spec Kit file)
@@ -54,6 +55,11 @@ comes from the story's acceptance criteria and the **locked contract surface**
54
55
  - **`contracts/`** — the slice of the API/event surface this repo implements, **quoted from the locked
55
56
  `contract.md`** (e.g. `POST /orders` request/response). Add a one-line note that this is a quote of
56
57
  the locked surface, not a new definition.
58
+ **Do NOT create this folder on a short-lane epic** (`profile: chore` or `spike`). Those routes have
59
+ no architecture step, so there is no locked `contract.md` to quote and no lock for CI to check the
60
+ quote against — the gate refuses a slice under a lockless epic. A short-lane story consumes the
61
+ shared surface through the code it calls; it never restates it. If one already exists, a commit
62
+ that only DELETES it is allowed through, which is the way back out.
57
63
  - **`plan.md`** — the technical approach for this repo at story altitude (components, sequence,
58
64
  test approach). No new cross-repo surface.
59
65
  - **`tasks.md`** — numbered atomic tasks. Each task: an ID (`T01`, `T02`, …), a one-line goal, and an
@@ -69,7 +75,9 @@ epic: EP-<slug>
69
75
  repo: <repo>
70
76
  feature-id: EP-<slug>-S0N
71
77
  product-repo: <path to the product repo — absolute, or relative to THIS file's dir (specs/<story>/)>
72
- contract-lock: sha256:<hex copied from epics/EP-<slug>/.sdlc/contract-lock.json>
78
+ contract-lock: sha256:<hex copied from epics/EP-<slug>/.sdlc/contract-lock.json> # or the literal
79
+ # `none` on a short-lane epic, which has no lock. Never an empty or invented hash:
80
+ # CI reads an unparseable value as a broken lock and fails.
73
81
  speckit: installed | not-installed
74
82
  generated: <YYYY-MM-DD>
75
83
  ---
@@ -89,12 +97,16 @@ back to the architecture gate in the product repo — it is never widened from t
89
97
  `product-repo` is the one field CI resolves on disk (contract-check, lineage-check, epic-open,
90
98
  reconcile-debt all read it). Every gate resolves it the SAME way: an **absolute** path is used as-is; a
91
99
  **relative** path is joined to this `link.md`'s own directory, `specs/<story>/` — `../../` climbs out
92
- of the story dir and out of `specs/` to the code-repo root, so a hub checked out beside the code repo
93
- is `../../../<hub-dir>`. A relative value that only resolves from the **repo root** still works too
100
+ of the story dir and out of `specs/` to the code-repo root, so a Product checked out beside the code repo
101
+ is `../../../<product-dir>`. A relative value that only resolves from the **repo root** still works too
94
102
  (what contract-check historically did), so older `link.md` files keep gating. Write it as an
95
103
  **unquoted scalar** — `"..."` or `'...'` is taken literally, and a leading `~`/`$VAR` is never
96
- expanded. An unreachable path degrades the hub-reading gates to a PASS-with-note rather than failing
97
- them, and each one now says so in its output.
104
+ expanded. An unreachable path degrades the Product-reading gates to a PASS-with-note rather than failing
105
+ them, and each one now says so in its output. **Reachable-but-lockless is a different case and does
106
+ NOT degrade:** when the Product resolves and `epics/<epic>/.sdlc/` is there with no
107
+ `contract-lock.json` in it, a claimed `Contract-Change: yes` FAILS, because nothing exists for the
108
+ claim to be true of. That is the ordinary state of a short-lane epic, of a stub, and of a classic epic
109
+ that has not reached its architecture gate yet.
98
110
 
99
111
  ## Do not re-invent the contract
100
112