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
@@ -3,18 +3,18 @@
3
3
  `yad-docs-overview` reuses the per-epic shell, but the *content* is the **workflow itself** rather than
4
4
  one epic's flows. This file pins how the setup→ship pipeline maps onto the shell's primitives. The
5
5
  ordering source of truth is `skills/sdlc/module-help.csv` (`phase`, `preceded-by`, `followed-by`,
6
- `outputs`); the dials/thresholds come from `skills/sdlc/config.yaml`; the node classes come from
6
+ `outputs`); the dial defaults come from `skills/sdlc/config.yaml`; the node classes come from
7
7
  `docs/diagrams/sdlc-overview.mmd`.
8
8
 
9
9
  ## Primitive mapping
10
10
 
11
11
  | Shell primitive | Overview meaning |
12
12
  |-----------------|------------------|
13
- | `FlowPath` (`paths.ts`) | a **phase**: Setup, Front-zero (discovery), Front half, Build half, Automation, Change management (feature threads). |
13
+ | `FlowPath` (`paths.ts`) | a **phase**: Setup, Front-zero (discovery), Shape, Build, Automation, Change management (feature threads). |
14
14
  | `FlowStep` (within a path) | a **skill or gate** in order; `messages` = its `outputs`; `sideEffects` = the `.sdlc/` files it writes; `status`/`bookingStatus` annotate gated vs. enrichment vs. earned. |
15
- | `SystemComponent` (`components.ts`) | a **durable state object** (the hub, each `.sdlc/*.json`, code repos, the design/testing/learning tools, the platform). |
15
+ | `SystemComponent` (`components.ts`) | a **durable state object** (the Product, each `.sdlc/*.json`, code repos, the design/testing/learning tools, the platform). |
16
16
  | `RoleConfig` (`roles.ts`) | a **lens** → its relevant sections + paths. |
17
- | doc sections (`docSections.ts`/`referenceData.ts`) | the phase narratives + the dial/threshold reference tables (from `config.yaml` + the build-plan docs). |
17
+ | doc sections (`docSections.ts`/`referenceData.ts`) | the phase narratives + the dial reference tables (from `config.yaml` + the build-plan docs). |
18
18
 
19
19
  ## Flow paths = phases, with their skills in order
20
20
 
@@ -26,40 +26,59 @@ and never gates.
26
26
 
27
27
  | Step (skill) | Outputs / sideEffects |
28
28
  |--------------|------------------------|
29
- | `yad-connect-repos` | `repos.json`, `code-context/<repo>/pack.md` + `code-map.md` (+ `detect-hub`/`roster` → `hub.json`) |
29
+ | `yad-connect-repos` | `repos.json`, `code-context/<repo>/pack.md` + `code-map.md` (+ `detect-hub` → `hub.json`) |
30
30
  | `yad-connect-design` | `design.json` |
31
31
  | `yad-connect-testing` | `testing.json` |
32
32
  | `yad-connect-learning` | `learning.json` |
33
33
  | `yad-connect-docs` | `docs.json` |
34
34
 
35
35
  ### Path: Front-zero (`phase: 0-front`)
36
- The OPTIONAL once-per-project discovery phase, modelled as the reserved "epic zero" `EP-discovery`.
37
- Greenfield AND brownfield; a 2-step author→review chain whose review binds to the whole artifact set
38
- and terminates at `discovery-done` (no build half).
36
+ The OPTIONAL once-per-product **Foundation** (E75) — the Product level, in its own folder `foundation/`
37
+ under the fixed id `EP-foundation`. Greenfield AND brownfield; a 2-step author→review chain whose
38
+ review binds to the required sections and terminates at `foundation-done` (no Build). Its approval is
39
+ reported, not enforced, before feature work begins.
39
40
 
40
41
  | Step (skill) | Gate | Outputs / sideEffects |
41
42
  |--------------|------|------------------------|
42
- | `yad-discovery` *(optional)* | → `discovery-review` (base rule) | `market-research.md`, `competitor-analysis.md`, `current-state.md`, `feasibility.md`, `requirements.md`, `roadmap.md`; seeds `EP-discovery/.sdlc/state.json` |
43
+ | `yad foundation new` then `yad-discovery` *(optional)* | → `foundation-review` (base rule) | `purpose.md`, `scope.md`, `mvp.md`, `roadmap.md`, `stack.md`, `repos.md` (+ optional `market.md`, `risks.md`); seeds `foundation/.sdlc/state.json` |
43
44
 
44
45
  `roadmap.md` is the menu of features each `yad-epic` reads (Step 2c) — reference-only, never
45
- auto-seeds epics.
46
-
47
- ### Path: Front half (`phase: 1-front`)
46
+ auto-seeds epics. A product created before E75 may still hold the old spelling, `epics/EP-discovery/`
47
+ (six files, ending at `discovery-done`); `yad migrate --apply` converts it on a local ledger.
48
+
49
+ <!-- `1-front` and `3-build` are DATA — the `phase` column in skills/sdlc/module-help.csv, which
50
+ the overview build reads. The Shape/Build/Run rename deliberately left them alone: change-safety
51
+ rule 3 says a release may add but never rename, so a stored value moves in a major with a
52
+ migration, not in a wording sweep. The display names below are the new vocabulary; the ids are
53
+ the old one, on purpose. -->
54
+
55
+ <!-- Each skill's `phase` in module-help.csv agrees with where this model places it. `4-automate` holds
56
+ yad-run and the docs skills; `6-change` holds yad-change, yad-stub, yad-timeline, yad-defects and
57
+ yad-reconcile; yad-status (a read-only view) and yad-learn (a tutor for any stage) are `anytime`, the
58
+ value for a skill available at every stage — they are listed under
59
+ Automation below only because the site needs one place to draw them. yad-report has no phase: it is
60
+ a CLI helper, not a pipeline step.
61
+ Moving three of these from `1-front` needed no migration, and that does not contradict the note
62
+ above: module-help.csv is catalogue content the tool ships, read from the package's skills/sdlc/ folder
63
+ and never installed into a project. It is not state a user's project stores. The note above is about
64
+ the `1-front` / `3-build` ids as they are read back. -->
65
+
66
+ ### Path: Shape (`phase: 1-front`)
48
67
  The gated authoring chain + the reusable review gate (10 steps, or 12 with the optional analysis).
49
68
 
50
69
  | Step (skill) | Gate | Outputs / sideEffects |
51
70
  |--------------|------|------------------------|
52
71
  | `yad-analysis` *(optional)* | → `analysis-review` | `analysis.md`, seeds `state.json` |
53
72
  | `yad-epic` | → `epic-review` | `epic.md`, seeds `state.json` |
54
- | `yad-architecture` | → `architecture-review` (escalates on contract) | `architecture.md`, `contract.md`, `contract-lock.json` |
73
+ | `yad-architecture` | → `architecture-review` (contract tag raises the count) | `architecture.md`, `contract.md`, `contract-lock.json` |
55
74
  | `yad-ui` | → `ui-design-review` | `ui-design.md`, `DESIGN.md`, `design-links.json` |
56
- | `yad-stories` | → `stories-review` (per-repo routing) | `stories/EP-<slug>-S0N.md` |
75
+ | `yad-stories` | → `stories-review` (labelled with every touched repo) | `stories/EP-<slug>-S0N.md` |
57
76
  | `yad-test-cases` | → `test-cases-review` (parallel, non-blocking) | `test-cases.md`, `test-links.json` |
58
77
  | `yad-review-gate` | the shared gate | `reviews/*.md`, `approvals.json`, `comments.json` |
59
78
  | `yad-review-companion` | the fun/visible review layer (trailer/cards/chat + engagement) | `approvals.json` `engagement`, platform trailer/cards |
60
79
  | `yad-hub-bridge` | the platform PR/MR bridge | `hub-prs.json` |
61
80
 
62
- ### Path: Build half (`phase: 3-build`)
81
+ ### Path: Build (`phase: 3-build`)
63
82
  Per-story, per-repo: `spec → tasks → implement → checks → engineer-review`, plus the commit/PR helpers.
64
83
 
65
84
  | Step (skill) | Outputs / sideEffects |
@@ -70,15 +89,15 @@ Per-story, per-repo: `spec → tasks → implement → checks → engineer-revie
70
89
  | `yad-pr-template` | PR/MR template + routing helpers |
71
90
  | `yad-commit` / `yad-open-pr` / `yad-ship` | one commit / one PR/MR |
72
91
  | `yad-engineer-review` | engineer review + ship recorded as a `build-log/` shard |
73
- | `yad-backfill` | DRAFT specs for legacy features |
92
+ | `yad-backfill` | DRAFT specs for legacy features — its own step in the Build path (Step G, brownfield) |
74
93
 
75
- ### Path: Automation (the second dial + observation)
94
+ ### Path: Automation (`phase: 4-automate`) — the second dial + observation
76
95
  The orchestrator + the trust evidence + the read-only views. Maps the **earns** / **locked** / **sentinel**
77
96
  node classes from the diagram.
78
97
 
79
98
  | Step (skill) | Outputs / sideEffects |
80
99
  |--------------|------------------------|
81
- | `yad-run` | drives the back-half loop; `build-state/<story>.json`, `trust-log.json`, kill switch |
100
+ | `yad-run` | drives the Build loop; `build-state/<story>.json`, `trust-log.json`; dials and kill switch through `yad dial` / `yad kill` (`.sdlc/automation.json`) |
82
101
  | `yad-learn` | tutoring; `learning-records.json` (LOCAL-ONLY, gitignored) |
83
102
  | `yad-status` | read-only view (no writes) |
84
103
  | `yad-docs` / `yad-docs-overview` / `yad-docs-sync` | the docs sites + their `docs-build.json` manifests |
@@ -86,24 +105,24 @@ node classes from the diagram.
86
105
  ### Path: Change management — feature threads (`phase: 6-change`)
87
106
  The post-lock evolution layer. Once an epic is **sealed** (all stories shipped), behaviour can no longer
88
107
  be mutated in place — a change request becomes a **new epic threaded to its parent** (genesis → change →
89
- defect), inheriting unchanged front artifacts **by reference** and re-authoring only what changes, so
108
+ defect), inheriting unchanged Shape artifacts **by reference** and re-authoring only what changes, so
90
109
  locked artifacts are never mutated and never go stale, only superseded. Three CI gates enforce the thread
91
- (`lineage-check`, `epic-open`, `reconcile-debt`). This path never gates the front chain; `yad-change` is
110
+ (`lineage-check`, `epic-open`, `reconcile-debt`). This path never gates the Shape chain; `yad-change` is
92
111
  the intake, then it hands off to the normal authoring skills + the review gate.
93
112
 
94
113
  | Step (skill) | Outputs / sideEffects |
95
114
  |--------------|------------------------|
96
- | `yad-change` | intake + triage depth (defect-fix / behavioral-no-surface / contract-surface / new-capability); seeds a threaded change-epic — lineage frontmatter, inherited-step `state.json`, pointer-lock `contract-lock.json`, `change.json`, and `reconcile-debt.json` for hotfixes |
115
+ | `yad-change` | intake + triage depth (defect-fix / behavioral-no-surface / contract-surface / new-capability); writes a threaded change-epic's lineage frontmatter and `change.json`, seeds its ledger with `yad epic new --parent` (inherited-step `state.json`, pointer-lock `contract-lock.json` — E42), and opens `reconcile-debt.json` for hotfixes |
97
116
  | `yad-timeline` | `TIMELINE.md` (the thread evolution view) + `thread-resolved.md` (the resolved current truth) |
98
117
  | `yad-defects` | `DEFECTS.md` (quality-gap report by `escape_stage` + root cause) |
99
118
  | `yad-reconcile` | advisory drift / orphan / debt sweep (read-only; mirrors `yad-docs-sync`) |
100
119
 
101
120
  CLI: `yad thread [<epic>]` prints a thread + its resolved current truth + open debt; `yad reconcile`
102
- runs the sweep. The three thread gates ride in the build-half `yad-checks` set above.
121
+ runs the sweep. The three thread gates ride in the Build `yad-checks` set above.
103
122
 
104
123
  ## System components = the durable state objects
105
124
 
106
- `components.ts` renders these on the canvas (deterministic positions): the **product hub**; each
125
+ `components.ts` renders these on the canvas (deterministic positions): the **Product**; each
107
126
  `.sdlc/*.json` (`state.json`, `approvals.json`, `comments.json`, `hub.json`, `repos.json`, `design.json`,
108
127
  `testing.json`, `learning.json`, `docs.json`, `contract-lock.json`, `build-state/*`, `trust-log.json`,
109
128
  and the change-thread ledgers `change.json`, `reconcile-debt.json`, `build-log.json`);
@@ -121,13 +140,13 @@ The eight yadflow lenses, each to its relevant phase sections + paths:
121
140
 
122
141
  | Lens | Relevant phases / sections |
123
142
  |------|----------------------------|
124
- | analyst | Setup intent, project discovery (front-zero), analysis step, front-half discovery |
125
- | pm | project discovery (market/feasibility/roadmap), epic, stories; the front gates |
126
- | architect | architecture + the locked contract; escalation |
143
+ | analyst | Setup intent, the Foundation (the Product level), analysis step, Shape discovery |
144
+ | pm | the Foundation (purpose/scope/MVP/roadmap), epic, stories; the Shape gates |
145
+ | architect | architecture + the locked contract; the contract risk step |
127
146
  | ux | UI design, design tool connection, the design system |
128
- | dev | build half: spec → implement, the per-repo loop |
147
+ | dev | Build: spec → implement, the per-repo loop |
129
148
  | tester | test-cases (parallel track), the testing tool, checks |
130
- | reviewer | the review gate, comments, the hub bridge |
149
+ | reviewer | the review gate, comments, the Product bridge |
131
150
  | engineer | engineer review + ship, the merge gate, automation dial/trust |
132
151
 
133
152
  ## Determinism + theme
@@ -16,14 +16,14 @@ silent (the same discipline as `yad repo refresh`).
16
16
 
17
17
  ## Conventions
18
18
 
19
- - `{project-root}` resolves from the project working directory (the **product hub**).
19
+ - `{project-root}` resolves from the project working directory (the **Product**).
20
20
  - Per-epic baseline: `epics/EP-<slug>/.sdlc/docs-build.json` (written by `yad-docs`). Overview baseline:
21
21
  `docs/sdlc-site/.docs-build.json` (written by `yad-docs-overview`).
22
22
  - The hashing + build + deploy is the **`yad docs sync` CLI**'s job; the regeneration of a stale site is
23
23
  delegated back to `yad-docs` / `yad-docs-overview` (the AI generation step). This skill orchestrates
24
24
  the reconcile.
25
25
  - The docs target is `.sdlc/docs.json` (`yad-connect-docs`).
26
- - Speak in the configured `communication_language`; write documents in `document_output_language`.
26
+ - Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
27
27
 
28
28
  ## Inputs
29
29
 
@@ -50,17 +50,22 @@ Read each `docs-build.json` and compare. A site is **stale** when **any** of:
50
50
  - any `repoHeads[<repo>]` differs from the repo's current HEAD (the code the components cite advanced —
51
51
  the same head-sha staleness as `repos.json`), or
52
52
  - for the overview, `config.yaml` / `module-help.csv` / the `.mmd` / `skillCount` moved, or
53
- - its `templateVersion` < the current shell template version (the shell was upgraded).
53
+ - for a per-epic site, its `shellVersion` differs from the `version` in `skills/yad-docs/templates/app/package.json`
54
+ (the shell was upgraded). The overview has no shell version: it is updated in place, not re-copied. An
55
+ older manifest records only `templateVersion` (the yad CLI version, which changed on every release). That
56
+ value is never compared; such a manifest counts as built on shell `0.0.0`, the only version before this.
54
57
 
55
58
  A missing `docs-build.json` (a site never generated) counts as **stale → needs generate**.
56
59
 
57
60
  ### Step 3 — Act on `action`
58
61
  - **`check`** (default, **read-only**) — print which sites are stale and **WHY**, in `yad check` drift
59
62
  style: *which artifact moved* (name it), *which repo HEAD advanced* (`<repo>: <old>→<new>`), *config /
60
- manifest / diagram / skill-count changed*, or *shell upgraded* (`templateVersion`). Writes nothing.
63
+ manifest / diagram / skill-count changed*, or *shell upgraded* (`shellVersion`, per-epic only). Writes nothing.
61
64
  - **`refresh`** — for each stale site, re-run the generator (`yad-docs` for an epic site, `yad-docs-overview`
62
65
  for the overview) to regenerate `src/data/*.ts` + theme + manifest, then redeploy via `yad docs deploy`
63
- (degrading to build-only when no platform CLI). Report every site refreshed. **Never silent** — refresh
66
+ (degrading to build-only when no platform CLI). Report every site refreshed, and every site whose
67
+ rebuild failed: `yad docs sync --refresh` exits 1 when a stale site's npm install or build fails, and
68
+ its `--json` `sites` rows say which (`built: false` with an `error`). **Never silent** — refresh
64
69
  is a deliberate human/CI act, surfaced exactly like `yad repo refresh`.
65
70
  - **`wire`** — commit the CI workflow (Step 4) that automates the check + rebuild.
66
71
 
@@ -16,7 +16,7 @@ the current inputs, or its shell template is out of date. This mirrors the `repo
16
16
  "artifactHash": "<sha256 of epic.md + architecture.md + contract.md CONTRACT-SURFACE + ui-design.md + each story>",
17
17
  "repoHeads": { "<repo>": "<HEAD sha>" },
18
18
  "deployUrl": "<url or null>",
19
- "templateVersion": "<shell template version>"
19
+ "shellVersion": "<the `version` in templates/app/package.json>"
20
20
  }
21
21
  ```
22
22
 
@@ -28,8 +28,7 @@ the current inputs, or its shell template is out of date. This mirrors the `repo
28
28
  "theme": "yadflow-brand",
29
29
  "artifactHash": "<sha256 of config.yaml + module-help.csv + docs/diagrams/sdlc-overview.mmd>",
30
30
  "skillCount": <number of yad-* skills>,
31
- "deployUrl": "<url or null>",
32
- "templateVersion": "<shell template version>"
31
+ "deployUrl": "<url or null>"
33
32
  }
34
33
  ```
35
34
 
@@ -55,10 +54,12 @@ A site is **stale** when ANY holds:
55
54
  repo is *flagged*, never auto-refreshed: the `code-context` itself is refreshed by a human via
56
55
  `yad repo refresh`, and the docs are regenerated only on an explicit `refresh`/CI decision;
57
56
  3. (overview) `config.yaml` / `module-help.csv` / the `.mmd` moved — the pipeline changed (this is what
58
- enforces "the overview regenerates whenever the workflow definition or skill set changes"); or the
59
- `templateVersion` (the yad CLI version) advanced — the doc shell upgraded;
60
- 4. manifest `templateVersion` < the current shell template version — the `templates/app/` shell was
61
- upgraded, so every site should re-copy it;
57
+ enforces "the overview regenerates whenever the workflow definition or skill set changes");
58
+ 4. (per-epic) manifest `shellVersion` ≠ the `version` in `templates/app/package.json` — the shell was
59
+ upgraded, so the site should re-copy it. The overview has no shell version (it is updated in place).
60
+ A manifest's older `templateVersion` field held the yad CLI version, which moved on every release, so
61
+ it is never compared: a manifest with only that field counts as built on shell `0.0.0`, the one version
62
+ the shell had before `shellVersion` existed. It reads fresh today, and a real shell upgrade still shows;
62
63
  5. the `docs-build.json` is **missing** — the site was never generated (treat as stale → generate).
63
64
 
64
65
  `check` reports which of these tripped and why; `refresh` regenerates + redeploys; neither blocks any
@@ -1,38 +1,41 @@
1
1
  ---
2
2
  name: yad-engineer-review
3
- description: 'Build-half Step E of the gated SDLC — AI review, engineer review, then merge. Wire an advisory AI first-pass (CodeRabbit) on the PR/MR; record the human engineer review with the same human_approve discipline as the front gates (owner + 1 reviewer, escalating to domain owners on high risk / contract / auth / payments — the Step D routing); and on merge, record the ship in the epic build-log and update the story state so the epic → story → task → PR chain is traceable. Never auto-advances — the human owns the merge. Use when the user says "record the engineer review", "merge this task", or "wire the AI review". (To commit + open the PR/MR, use yad-ship.)'
3
+ description: 'Build Step E of the gated SDLC — AI review, engineer review, then merge. Wire an advisory AI first-pass (CodeRabbit) on the PR/MR; record the human engineer review with the same advance-human discipline as the Shape gates (1 distinct approver, who should not be the author; high risk / contract raise the full count, advisory, not enforced — the Step D routing); and on merge, record the ship in the epic build-log and update the story state so the epic → story → task → PR chain is traceable. Never auto-advances — the human owns the merge. Use when the user says "record the engineer review", "merge this task", or "wire the AI review". (To commit + open the PR/MR, use yad-ship.)'
4
4
  ---
5
5
 
6
- # SDLC — Engineer Review & Merge (build-half Step E)
6
+ # SDLC — Engineer Review & Merge (Build Step E)
7
7
 
8
8
  **Goal:** Take a task PR/MR that has passed the **check gates** (Step C) through two sets of eyes and
9
9
  out to production: an **AI first-pass** (advisory) and a **human engineer review** (the authority),
10
- then **ship** — merge, record the ship, and update the story state. This is the last build-half step
11
- (build plan §E). It is a **human gate**, the same `human_approve` discipline as the front states:
10
+ then **ship** — merge, record the ship, and update the story state. This is the last Build step
11
+ (build plan §E). It is a **human gate**, the same `advance: human` discipline as the Shape steps:
12
12
  **nothing auto-advances**; the engineer owns the merge.
13
13
 
14
14
  ## Conventions
15
15
 
16
16
  - `{project-root}` resolves from the project working directory — the **product** repo (the source of
17
17
  truth: it holds the story and the build ledger).
18
- - Code repos are separate git repos under `{project-root}/demo-repos/<repo>/`.
18
+ - Code repos are separate git repos under `{project-root}/demo-repos/<repo>/` (or the registry `path` in
19
+ `.sdlc/repos.json`).
19
20
  - The build ledger uses **shard-then-fold** storage: each ship is its own shard file
20
21
  `{project-root}/epics/<epic>/.sdlc/build-log/<story>-<task>-<repo>.json`, so concurrent shippers never
21
22
  conflict; readers UNION the folded `build-log.json` with every loose shard, and `yad tidy up` folds
22
23
  finished shards back into `build-log.json`. It — like the trust log and build-state — is committed by
23
24
  `yad checkpoint` (see Step 3), not by hand.
24
- - The engineer-review rule reuses `yad-review-gate`: base = at least one `owner` AND one distinct
25
- `reviewer`; **escalated** (the PR's Impact & Risk is `high`, or it touches contract/auth/payments) =
26
- base PLUS one `domain-owner` per touched domain — the same routing `yad-pr-template`'s
27
- `risk-route.sh` prints.
25
+ - The engineer-review rule reuses `yad-review-gate`'s count: `needed = base 1 + risk step` distinct
26
+ approvers. The risk step comes from the PR's Impact & Risk block — `high` risk +1, a touched contract
27
+ surface +2 — and from the code repo's risk map on the **base branch**: a change touching a `high`
28
+ directory +1 (E66). The largest step wins, never the sum. The count is reported, not enforced: branch protection holds the merge (at least 1
29
+ distinct approver, who should not be the author), and the risk step is advisory. `yad open-pr` shows
30
+ the count capped by the active people (E72); the check scripts cannot cap it. This is what `yad-pr-template`'s `risk-route.sh`
31
+ prints. The real merge protection is the platform's branch protection.
28
32
  - AI review wiring: `templates/.coderabbit.yaml` → `<repo>/.coderabbit.yaml`.
29
33
 
30
34
  ## Inputs
31
35
 
32
36
  - `epic` / `story` / `task` / `repo` — the PR under review (the task branch `feat/<story>-<task>-…`).
33
37
  - `action` — `ai-review` | `approve` | `ship` (default `ai-review`).
34
- - For `approve`: the reviewer `name` and `role` (`owner` | `reviewer` | `domain-owner`), and for a
35
- domain owner the `domain`.
38
+ - For `approve`: the reviewer's platform login. No role and no domain.
36
39
 
37
40
  ## On Activation
38
41
 
@@ -58,29 +61,84 @@ never gates. When a pair session backs the approve, you may set `companion.pair:
58
61
 
59
62
  ### Step 2 — `approve` (the engineer review — the human gate)
60
63
  A human engineer reads the diff **against the spec** (`specs/<story>/`) and the acceptance criteria,
61
- and records an approval. Determine the rule from the PR's Impact & Risk block (run
62
- `../yad-pr-template/templates/checks/risk-route.sh` on the PR body): base, or escalated to a
63
- domain-owner per touched domain. Record each approval; re-evaluate whether the rule is satisfied.
64
+ and records an approval. Determine the count with `bash checks/risk-route.sh <pr-body-file> origin/<base>`,
65
+ run **in the code repo with the PR's branch checked out** — it reads the body's Impact & Risk block and
66
+ the base branch's `.sdlc/risk-map`, and the larger step wins. On the base branch the change is empty and
67
+ the map adds nothing, so check out the PR branch first. If the repo has no `checks/risk-route.sh`, it is
68
+ not wired yet: run `yad update` for it (that installs `checks/risk-route.sh` and
69
+ `checks/risk-map-check.sh` together). Until then, count from the body alone and say that the map was not
70
+ counted. It prints e.g.
71
+ `ROUTE: 3 approvers = base 1 + contract risk 2 (contract surface touched)`, says branch protection holds the
72
+ merge, not this count (the risk step is advisory and not capped there), and lists the touched domains as a hint for whom to ask. With no risk it
73
+ prints `ROUTE: 1 approver = base 1 (no risk step).` When the map raises a body that says `low`, it
74
+ names the `high` directories and says the two disagree — tell the engineer, and ask the author to fix the
75
+ body if the body is wrong. Record each approval; re-evaluate whether the base
76
+ is met, and report any shortfall against the full count without blocking on it.
77
+
78
+ **Proven history (E67).** When the change touches a `high` directory, `risk-route.sh` also prints the
79
+ people who have **committed there in the last 30 days**, read from the base branch and with this
80
+ change's own authors left out:
81
+
82
+ ```
83
+ This change touches src/payments/, so it asks for an approval from someone who has
84
+ committed there in the last 30 days (its own authors left out):
85
+ - Alice (@alice)
86
+ - @carol
87
+ ```
88
+
89
+ A person whose git name holds an `@` is printed as their bare login (`- @carol`), or, when there is no
90
+ login, as `a name that is an e-mail address` or `a name written like a login` — both have NO login. No
91
+ address is ever printed, and a printed `@word` is always a real login, never a git name. A bare `@login`
92
+ counts exactly like a `(@login)` below.
93
+
94
+ Report it as an ask, never as a block, and use exactly these three answers:
95
+
96
+ Work down these rows in order and stop at the first that fits — a mixed list, where one person has a
97
+ login and another does not, fits more than one:
98
+
99
+ | In order | What you see | What to report |
100
+ |---|---|---|
101
+ | 1 | A recorded approver's login is one of the printed logins — a `(@login)` after a name, or a bare `@login` — ignoring upper and lower case | **met** |
102
+ | 2 | The printer says `not read` (a shallow clone, or git could not read the history) | **could not confirm** |
103
+ | 3 | No approver matches, and at least one named person has no login (neither `(@login)` nor a bare `@login`) | **could not confirm** — name everyone printed, and say the names could not be compared |
104
+ | 4 | No approver matches, and every named person has a login (`(@login)` or a bare `@login`) | **short** — name who could meet it |
105
+
106
+ Rows 2 and 3 matter: an approval records a platform login, while git history records a name, and a login
107
+ only comes from a `noreply` address. Different spellings of a name prove nothing either way, so say the
108
+ ask could not be confirmed rather than inventing a shortfall. Logins are compared without case, because
109
+ a platform login is case-insensitive and the printer shows it as the address wrote it.
110
+
111
+ With nobody printed at all — `nobody else has committed there in the last 30 days` — there is nobody to
112
+ ask for, and the count stands on its own. That line, and `not read`, are printed higher up in the
113
+ `Risk map (…)` section, not inside the `ROUTE` paragraph above.
114
+
115
+ **One list, not one per directory.** When a change touches two `high` directories, the people are printed
116
+ as one list: someone who has worked in ANY of them meets the ask. Nothing says which person worked where.
117
+
64
118
  Record `engagement: verified` when the engineer reviewed through the companion (else `none` for a bare
65
119
  approve); `yad review reconcile --epic <id> --repo <r> --pr <n>` stamps it onto the ship record from the
66
120
  platform (mutating the ship's shard where it lives, or its folded entry if already tidied). Soft by default (both count; a bare approve draws `yad review nudge`); only gates when
67
121
  `hub.review.requireEngagement: true`. The signal is gameable by design and sits **beside** the CI gates,
68
122
  never above them.
69
- Recording an approval does **not** ship — shipping is a separate, explicit step. Front-half discipline:
123
+ Recording an approval does **not** ship — shipping is a separate, explicit step. Shape discipline:
70
124
  the gate talks only through files; refuse to treat AI review as a human approval.
71
125
 
72
126
  ### Step 3 — `ship` (merge + record + update state)
73
127
  Ship **iff ALL hold**: the check gates pass (Step C), the AI review has run (advisory), and the
74
128
  engineer-review rule is satisfied (Step 2). Then:
75
129
  - **Merge** the task branch into the repo's default branch (the human performs/authorises the merge).
130
+ - **Check the lane is not skipped (E39)** — read `build-state/<story>.json`. If this repo's lane is
131
+ `status: skipped`, it was set aside as needing no change: stop, and run
132
+ `yad unskip <epic> <story> --repo <repo>` before recording a ship, so the two records never say opposite
133
+ things (`yad doctor` fails that as `lane:…:contradiction`; `yad checkpoint --retro-ship` refuses it).
76
134
  - **Record the ship** — write the ship to its own shard
77
135
  `epics/<epic>/.sdlc/build-log/<story>-<task>-<repo>.json` (readers union the folded `build-log.json` +
78
136
  the loose shards, deduping by (story, task, repo) so a shard wins over a stale folded ship):
79
137
  ```json
80
138
  { "story": "<story>", "task": "<task>", "repo": "<repo>", "branch": "feat/<story>-<task>-…",
81
139
  "pr": "<url|#>", "mergeCommit": "<sha>", "gates": ["spec-link","contract-check","build-test-lint"],
82
- "ai_review": "coderabbit (advisory)", "engineer_review": [{"approver":"<name>","role":"<role>","domain":"<opt>","engagement":"<verified|none>"}],
83
- "companion": {"trailer":true,"cards":true,"chat":false}, "risk": "<low|medium|high>", "shippedAt": "<YYYY-MM-DD>" }
140
+ "ai_review": "coderabbit (advisory)", "engineer_review": [{"approver":"<platform login>","engagement":"<verified|none>"}],
141
+ "companion": {"trailer":true,"cards":true,"chat":false}, "risk": "<low|medium|high — the BODY's level>", "shippedAt": "<YYYY-MM-DD>" }
84
142
  ```
85
143
  - **Update the story state** — when **every** task in `specs/<story>/tasks.md` has a ship record, set
86
144
  the story frontmatter `status: shipped`; otherwise `status: in-build`. The chain
@@ -91,30 +149,36 @@ engineer-review rule is satisfied (Step 2). Then:
91
149
  `epics/<epic>/.sdlc/trust-log/<story>-<repo>-implement-<uid>.json` (or, if the run was already folded
92
150
  by `yad tidy up`, into its entry in the folded `trust-log.json`). The human has the last word on the trust signal: a diff merged
93
151
  as authored is `approved-unchanged`; one the engineer edited before merge is `approved-with-edits`;
94
- a rejected one is `rejected`. This is the evidence that later earns a step its `machine_advance`
152
+ a rejected one is `rejected`. This is the run record `yad dial` shows the team beside a step's dial
95
153
  (it never weakens the merge gate — the engineer still owns the merge).
96
154
  - **Commit the machine-written ledgers.** Run `yad checkpoint --push` from `{project-root}` to commit
97
- the back-half ledgers just written (the `build-log/` shard, and the `trust-log/` shard /
155
+ the Build ledgers just written (the `build-log/` shard, and the `trust-log/` shard /
98
156
  `build-state/<story>.json` if the story ran through `yad-run`) as one `chore(hub): …` audit-trail
99
157
  commit — default branch only, staging the shard dirs (`yad tidy up` folds finished shards later),
100
- never a front-half gate file. It is the back-half analogue of the front-half `yad gate` sync. The
158
+ never a Shape gate file. It is the Build analogue of the Shape `yad gate` sync. The
101
159
  same commit also **carries the story `status:` flip** you just wrote (`approved → in-build/shipped`,
102
160
  #112) — because that story now has a build-log ship, checkpoint stages `stories/<story>.md` alongside
103
161
  the ledgers, so the artifact never drifts from build-log and you never fall back to a raw git-to-main
104
162
  push. (The code-repo `tasks.md` is committed in its own repo as usual.)
105
163
 
106
164
  ### Step 4 — Stop
107
- Report what shipped and the story's state. Do not advance anything else; the front-half `state.json`
108
- stays as it was (`ready-for-build`). The build half is recorded in `build-log.json` + the story status.
165
+ Report what shipped and the story's state. Do not advance anything else; the Shape `state.json`
166
+ stays as it was (`ready-for-build`). Build is recorded in `build-log.json` + the story status.
109
167
 
110
168
  ## Hard rules (build plan §E, Cross-cutting)
111
169
 
112
170
  - **AI review is advisory, never the authority.** Only a human engineer approval counts toward the gate.
113
- - **High risk routes to domain owners** — the same escalation as `yad-review-gate` / `risk-route.sh`.
171
+ - **High risk raises the count** — the same count as `yad-review-gate` / `risk-route.sh`, and a `high`
172
+ directory on the base branch's risk map raises it too; that directory also asks for an approver who has
173
+ worked there in the last 30 days (E67), reported in the same three states as everything else here:
174
+ met, short, or could not confirm. The count is advisory — branch protection holds the
175
+ merge; `yad open-pr` shows the count capped by the active people. There are no domain owners to route to.
176
+ - **The ship record's `risk` is the body's level**, as the author wrote it — not the level the map raised
177
+ it to. The count is worked out live each time and never stored (the user's decision, 2026-09-18).
114
178
  - **Ship only after gates + engineer review.** No gate skipped; the human owns the merge.
115
179
  - **Nothing auto-advances.** Step E records human decisions in files; it never machine-advances.
116
180
 
117
181
  ## Reference
118
182
  - The build ledger + story-state rules: `references/ship-and-record.md`.
119
- - The escalation reused: `../yad-review-gate/SKILL.md`; the routing helper: `../yad-pr-template/`.
183
+ - The count reused: `../yad-review-gate/SKILL.md`; the routing helper: `../yad-pr-template/`.
120
184
  - The gates that must pass first: `../yad-checks/references/check-gates.md`.
@@ -1,6 +1,6 @@
1
1
  # Ship — the build ledger and the story state
2
2
 
3
- Step E (`yad-engineer-review`) closes the build half: AI review (advisory) → engineer review (the human gate) →
3
+ Step E (`yad-engineer-review`) closes Build: AI review (advisory) → engineer review (the human gate) →
4
4
  ship. Shipping records the merge and updates the story state so the whole chain is traceable.
5
5
 
6
6
  ## Two sets of eyes
@@ -10,10 +10,17 @@ ship. Shipping records the merge and updates the story state so the whole chain
10
10
  gate. Where CodeRabbit can't run (no remote), an equivalent AI first-pass is run by hand and its
11
11
  notes captured.
12
12
  2. **Engineer review (the authority).** A human reads the diff against the spec and the acceptance
13
- criteria and records an approval. The rule is `yad-review-gate`'s:
14
- - **base:** at least one `owner` AND one distinct `reviewer`.
15
- - **escalated:** when the PR's Impact & Risk is `high`, or it touches contract/auth/payments — base
16
- PLUS one `domain-owner` per touched domain (exactly what `risk-route.sh` prints).
13
+ criteria and records an approval. The rule is `yad-review-gate`'s count, in distinct approvers:
14
+ - **base (enforced):** 1 distinct approver, who should not be the author. This holds the merge.
15
+ - **full count (advisory):** base 1 + a risk step from the PR's Impact & Risk block — `high` risk
16
+ +1, a touched contract surface +2 — or from the base branch's risk map, where a change touching a
17
+ `high` directory adds +1 (E66). The largest step, never the sum. Exactly what `risk-route.sh` prints,
18
+ run in the code repo on the PR's branch.
19
+ The risk step holds nothing on a code PR: branch protection holds the merge. `yad open-pr` shows
20
+ the count capped by the active people (E72), for information only. The touched domains it lists are a hint
21
+ for whom to ask.
22
+
23
+ The actual merge protection is the platform's branch protection.
17
24
 
18
25
  ## The build ledger — shard-then-fold (`epics/<epic>/.sdlc/build-log/` → `build-log.json`)
19
26
 
@@ -48,8 +55,8 @@ without the `{ epic, ships }` wrapper):
48
55
  "gates": ["spec-link", "contract-check", "build-test-lint"],
49
56
  "ai_review": "coderabbit (advisory)",
50
57
  "engineer_review": [
51
- { "approver": "amelia", "role": "owner", "engagement": "verified" },
52
- { "approver": "carol", "role": "reviewer", "engagement": "none" }
58
+ { "approver": "amelia-dev", "engagement": "verified" },
59
+ { "approver": "carol-k", "engagement": "none" }
53
60
  ],
54
61
  "companion": { "trailer": true, "cards": true, "chat": false },
55
62
  "risk": "low",
@@ -59,16 +66,16 @@ without the `{ epic, ships }` wrapper):
59
66
  }
60
67
  ```
61
68
 
62
- This is the back-half analogue of the front half's `approvals.json` — files only, no hidden state, so a
69
+ This is the Build analogue of Shape's `approvals.json` — files only, no hidden state, so a
63
70
  future service can drive ship by writing the same records. Like the trust log and build-state, it is a
64
- machine-written ledger committed by **`yad checkpoint`** (the back-half analogue of `yad gate` sync),
71
+ machine-written ledger committed by **`yad checkpoint`** (the Build analogue of `yad gate` sync),
65
72
  not by hand: after recording the ship, `yad checkpoint --push` lands the new `build-log/` shard as a
66
- `chore(hub): …` audit-trail commit on the default branch (allowlist-scoped to the back-half ledgers,
67
- never a front-half gate file); `yad tidy up` folds finished shards into `build-log.json` later.
73
+ `chore(hub): …` audit-trail commit on the default branch (allowlist-scoped to the Build ledgers,
74
+ never a Shape gate file); `yad tidy up` folds finished shards into `build-log.json` later.
68
75
 
69
76
  ### Retroactive ship — a pre-tracking story (#142)
70
77
 
71
- A story that was merged and shipped **before** the back-half ledger existed has no build-log ship, so
78
+ A story that was merged and shipped **before** the Build ledger existed has no build-log ship, so
72
79
  `yad checkpoint` can't carry its `status: shipped` flip (the flip is only carried when a ship backs it,
73
80
  #112) — leaving a raw `git push origin main` as the only way to land it, against the never-raw-git
74
81
  convention. To reconcile it through yad, record a **retroactive** ship, then checkpoint carries the flip
@@ -83,7 +90,7 @@ It writes ONE minimal ship shard marked `retroactive: true` (`task` defaults to
83
90
  the normal checkpoint so the story's already-made `status:` flip rides along in the **same** commit. It
84
91
  refuses when the story already has a ship **in that repo** (then it isn't pre-tracking there — use the
85
92
  normal flow). It does **not** author the story frontmatter — and to keep evidence and the flip atomic (the no-drift
86
- invariant), it **refuses** unless you have already set a back-half `status:` (`in-build` or `shipped`) in
93
+ invariant), it **refuses** unless you have already set a Build `status:` (`in-build` or `shipped`) in
87
94
  `stories/<story>.md`, so a ship shard is never committed while the artifact still says `approved`.
88
95
 
89
96
  **Where the record lands — it is a shard, not an append to `build-log.json`.** Like every other ship, a
@@ -121,7 +128,8 @@ writing the same ledger at once would otherwise both read "no ship yet" and both
121
128
  empty directory (`build-log.json.lock`), so git never sees it; one held by a process that died is
122
129
  reclaimed after 30s, and a live one reports `YAD-STATE-006` rather than writing over the other's work.
123
130
 
124
- **Engagement (the Review Companion).** Each `engineer_review` entry carries `engagement: verified | none`
131
+ **Engagement (the Review Companion).** Each `engineer_review` entry names the approver by platform login
132
+ (no role or domain) and carries `engagement: verified | none`
125
133
  — `verified` when the engineer reviewed through the [companion](../../yad-review-companion/SKILL.md)
126
134
  (`yad review trailer/context/nudge`, a real trailer/cards/chat session over the diff), `none` for a bare
127
135
  approve. The optional `companion` block records which faces ran. It is **soft by default** (both count;
@@ -129,7 +137,7 @@ a bare approve draws a friendly `yad review nudge`); it only gates ship when
129
137
  `hub.review.requireEngagement: true`. `yad review reconcile --epic <id> --repo <r> --pr <n>` reads the
130
138
  code PR's approvals (with the engagement signal) and stamps them onto the matching ship record — writing
131
139
  back into the ship's shard where it lives (or its folded entry if the story was already tidied) — the
132
- back-half **bridge**, the analogue of `yad gate sync`. The signal is gameable by design ("visible, not
140
+ Build **bridge**, the analogue of `yad gate sync`. The signal is gameable by design ("visible, not
133
141
  impossible"): it makes engineer-review quality visible, it does not prove a human read the diff. It sits
134
142
  **beside** the CI gates (build/test/lint/contract/verified-commits) — never above them; CI still
135
143
  decides machine safety, the merge is still the human act.
@@ -156,6 +164,7 @@ trailer → story → epic). Resolve that ship by the union rule, not from `buil
156
164
 
157
165
  1. The three **check gates** pass (Step C) — re-run them on the PR branch if unsure.
158
166
  2. The **AI review** has run (advisory; findings surfaced to the engineer).
159
- 3. The **engineer review** rule is satisfied (base or escalated per the Impact & Risk block).
167
+ 3. The **engineer review** base is met (1 distinct approver); any shortfall against the full count from
168
+ the Impact & Risk block is reported, not blocking.
160
169
 
161
170
  Only then does the human merge and `yad-engineer-review` record it. Nothing auto-advances.