yadflow 4.0.0-next.3 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CHANGELOG.md +699 -0
  2. package/README.md +85 -22
  3. package/bin/commands.mjs +3 -1
  4. package/bin/yad.mjs +183 -29
  5. package/cli/capture.mjs +4 -2
  6. package/cli/checkpoint.mjs +10 -10
  7. package/cli/claims.mjs +4 -4
  8. package/cli/commit.mjs +48 -12
  9. package/cli/docs.mjs +15 -13
  10. package/cli/doctor.mjs +557 -141
  11. package/cli/epic-state.mjs +41 -18
  12. package/cli/errors.mjs +3 -2
  13. package/cli/find-product.mjs +197 -0
  14. package/cli/fold.mjs +4 -4
  15. package/cli/gate-local.mjs +13 -13
  16. package/cli/gate.mjs +111 -103
  17. package/cli/history.mjs +13 -13
  18. package/cli/hook.mjs +201 -30
  19. package/cli/index-command.mjs +6 -6
  20. package/cli/lib.mjs +91 -29
  21. package/cli/manifest.mjs +171 -104
  22. package/cli/migrate.mjs +208 -17
  23. package/cli/mode.mjs +22 -22
  24. package/cli/next.mjs +6 -6
  25. package/cli/openpr.mjs +32 -24
  26. package/cli/people.mjs +22 -10
  27. package/cli/plan.mjs +718 -45
  28. package/cli/platform.mjs +13 -7
  29. package/cli/product-index.mjs +4 -4
  30. package/cli/{hubcommit.mjs → productcommit.mjs} +11 -7
  31. package/cli/protection.mjs +19 -9
  32. package/cli/reconcile.mjs +98 -23
  33. package/cli/repo-publish.mjs +22 -16
  34. package/cli/repo.mjs +128 -33
  35. package/cli/report.mjs +4 -2
  36. package/cli/review.mjs +26 -19
  37. package/cli/setup.mjs +105 -36
  38. package/cli/ship.mjs +1 -1
  39. package/cli/skip.mjs +4 -4
  40. package/cli/tidy.mjs +7 -7
  41. package/cli/update-commit.mjs +22 -19
  42. package/cli/workspace.mjs +495 -0
  43. package/package.json +7 -4
  44. package/skills/sdlc/config.yaml +14 -13
  45. package/skills/sdlc/module-help.csv +8 -8
  46. package/skills/yad-analysis/SKILL.md +6 -4
  47. package/skills/yad-architecture/SKILL.md +4 -3
  48. package/skills/yad-backfill/SKILL.md +11 -5
  49. package/skills/yad-backfill/references/backfill.md +33 -3
  50. package/skills/yad-backfill/templates/checks/backfill-check.sh +200 -17
  51. package/skills/yad-change/SKILL.md +1 -1
  52. package/skills/yad-checks/SKILL.md +48 -27
  53. package/skills/yad-checks/references/check-gates.md +213 -53
  54. package/skills/yad-checks/templates/checks/commit-message.sh +39 -13
  55. package/skills/yad-checks/templates/checks/contract-check.sh +472 -23
  56. package/skills/yad-checks/templates/checks/epic-open.sh +398 -8
  57. package/skills/yad-checks/templates/checks/ledger-guard.sh +75 -25
  58. package/skills/yad-checks/templates/checks/lineage-check.sh +391 -7
  59. package/skills/yad-checks/templates/checks/product-checkout.sh +141 -0
  60. package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +399 -8
  61. package/skills/yad-checks/templates/checks/risk-map-check.sh +35 -3
  62. package/skills/yad-checks/templates/checks/spec-link.sh +36 -3
  63. package/skills/yad-checks/templates/checks/verified-commits.sh +26 -2
  64. package/skills/yad-checks/templates/github/yad-checks.yml +33 -13
  65. package/skills/yad-checks/templates/github/{yad-hub-checks.yml → yad-product-checks.yml} +14 -10
  66. package/skills/yad-checks/templates/github/yad-update-guard.yml +1 -1
  67. package/skills/yad-checks/templates/github/yad-verified-commits.yml +1 -1
  68. package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +12 -0
  69. package/skills/yad-checks/templates/gitlab/{yad-hub-checks.gitlab-ci.yml → yad-product-checks.gitlab-ci.yml} +16 -16
  70. package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +2 -2
  71. package/skills/yad-checks/templates/hooks/ledger-guard-cursor.mjs +130 -0
  72. package/skills/yad-checks/templates/hooks/ledger-guard.mjs +117 -0
  73. package/skills/yad-checks/templates/hooks/yad-capture.mjs +117 -0
  74. package/skills/yad-commit/SKILL.md +18 -7
  75. package/skills/yad-connect-design/SKILL.md +1 -1
  76. package/skills/yad-connect-design/references/design-registry.md +1 -1
  77. package/skills/yad-connect-docs/SKILL.md +16 -11
  78. package/skills/yad-connect-docs/references/docs-registry.md +8 -8
  79. package/skills/yad-connect-learning/SKILL.md +1 -1
  80. package/skills/yad-connect-learning/references/learning-registry.md +1 -1
  81. package/skills/yad-connect-repos/SKILL.md +31 -8
  82. package/skills/yad-connect-repos/references/code-context.md +1 -1
  83. package/skills/yad-connect-repos/references/{hub-config.md → product-config.md} +19 -11
  84. package/skills/yad-connect-repos/references/repos-registry.md +1 -1
  85. package/skills/yad-connect-testing/SKILL.md +1 -1
  86. package/skills/yad-connect-testing/references/testing-registry.md +1 -1
  87. package/skills/yad-discovery/SKILL.md +2 -2
  88. package/skills/yad-discovery/references/discovery-schema.md +1 -1
  89. package/skills/yad-docs/SKILL.md +1 -1
  90. package/skills/yad-docs/references/data-mapping.md +1 -1
  91. package/skills/yad-docs/templates/app/package-lock.json +8 -8
  92. package/skills/yad-docs/templates/app/package.json +1 -1
  93. package/skills/yad-docs/templates/app/src/components/Canvas/FlowCanvas.tsx +2 -2
  94. package/skills/yad-docs-overview/references/pipeline-model.md +3 -3
  95. package/skills/yad-engineer-review/SKILL.md +2 -2
  96. package/skills/yad-engineer-review/references/ship-and-record.md +3 -3
  97. package/skills/yad-epic/SKILL.md +6 -4
  98. package/skills/yad-epic/references/state-schema.md +13 -12
  99. package/skills/yad-open-pr/SKILL.md +1 -1
  100. package/skills/yad-pair-review/SKILL.md +5 -5
  101. package/skills/yad-pair-review/references/session-state.md +2 -2
  102. package/skills/yad-pr-template/SKILL.md +14 -12
  103. package/skills/yad-pr-template/templates/checks/pr-template.sh +18 -16
  104. package/skills/yad-pr-template/templates/checks/pr-title.sh +15 -13
  105. package/skills/yad-pr-template/templates/{hub → product}/github/pull_request_template.md +2 -2
  106. package/skills/yad-pr-template/templates/{hub → product}/gitlab/merge_request_templates/Default.md +2 -2
  107. package/skills/{yad-hub-bridge → yad-product-bridge}/SKILL.md +15 -15
  108. package/skills/{yad-hub-bridge → yad-product-bridge}/references/bridge.md +15 -10
  109. package/skills/{yad-hub-bridge → yad-product-bridge}/references/login-roster.md +2 -2
  110. package/skills/{yad-hub-bridge/templates/checks/hub-route.sh → yad-product-bridge/templates/checks/product-route.sh} +2 -2
  111. package/skills/{yad-hub-bridge → yad-product-bridge}/templates/github/yad-gate-sync.yml +29 -16
  112. package/skills/{yad-hub-bridge → yad-product-bridge}/templates/gitlab/gitlab-ci.include-root.yml +1 -1
  113. package/skills/{yad-hub-bridge → yad-product-bridge}/templates/gitlab/yad-gate-sync.gitlab-ci.yml +5 -3
  114. package/skills/yad-report/SKILL.md +1 -1
  115. package/skills/yad-review-companion/SKILL.md +3 -3
  116. package/skills/yad-review-gate/SKILL.md +22 -23
  117. package/skills/yad-review-gate/references/gating.md +13 -13
  118. package/skills/yad-run/SKILL.md +2 -2
  119. package/skills/yad-run/references/run-loop.md +2 -2
  120. package/skills/yad-spec/SKILL.md +2 -1
  121. package/skills/yad-spec/references/spec-handoff.md +19 -10
  122. package/skills/yad-stories/SKILL.md +2 -2
  123. package/skills/yad-sync-repos/SKILL.md +19 -3
  124. package/skills/yad-test-cases/SKILL.md +2 -2
  125. package/skills/yad-ui/SKILL.md +2 -2
  126. package/skills/yad-checks/templates/hooks/ledger-guard-cursor.sh +0 -91
  127. package/skills/yad-checks/templates/hooks/ledger-guard.sh +0 -100
  128. package/skills/yad-checks/templates/hooks/yad-capture.sh +0 -53
@@ -7,9 +7,17 @@ no roles, no commit emails (E62). It is a single object for the Product itself
7
7
 
8
8
  ## Location
9
9
 
10
- `{project-root}/.sdlc/hub.json`
11
-
12
- (`config.yaml` `product.config` (older projects: `hub.config`).) Created/updated by `yad-connect-repos action: detect-hub`.
10
+ `{project-root}/.sdlc/product.json`, written together with its older name `{project-root}/.sdlc/hub.json`
11
+ (E122). Read `product.json` first; read `hub.json` only on an older Product that has only that name.
12
+ Every save writes both names with the same bytes, until v5 deletes `hub.json` (check gates an older
13
+ yadflow installed read `hub.json` by path). If both exist and their bytes differ, every yad command but
14
+ `yad doctor`, `yad migrate` and `yad report` refuses with `YAD-STATE-008`, and the CI gates FAIL;
15
+ `yad migrate --apply` (or `--apply --keep product` / `--keep hub`) chooses the copy to keep. To edit a
16
+ setting by hand, edit `product.json`, then run `yad migrate --apply --keep product` (it copies it over
17
+ `hub.json`). A Product that has only `hub.json` has not been migrated: edit `hub.json`, and never create a
18
+ `product.json` beside it by hand — `--keep product` would copy that one file over every other setting.
19
+
20
+ (`config.yaml` `product.config` (older projects: `hub.config`).) Created/updated by `yad-connect-repos action: detect-product` (older name: `detect-hub`).
13
21
 
14
22
  ## Schema
15
23
 
@@ -27,7 +35,7 @@ no roles, no commit emails (E62). It is a single object for the Product itself
27
35
  "solo": false, // SOLO MODE, and the one that decides: true waives the approval requirement on every review gate (the merge + resolved threads still gate). Set by `yad setup --solo` / `--team <n>` or `yad mode`
28
36
  "mode": "team", // the roadmap's name for the same switch (E10): "solo" | "team", written beside `solo` by `yad mode` and `yad setup`. NOT read by the gates this major — `yad doctor` warns `mode:disagree` when it contradicts `solo`. Not the ledger switch: "verified mode" elsewhere means `ledger`
29
37
  "mode_set": { "from": "solo", "to": "team", "by": "al", "date": "2026-09-15", "reason": null }, // the last change of mode (E10): who, when, why. `yad mode solo` requires the reason
30
- "detectedAt": "2026-06-08" // last detect-hub run (YYYY-MM-DD)
38
+ "detectedAt": "2026-06-08" // last detect-product run (YYYY-MM-DD)
31
39
  }
32
40
  ```
33
41
 
@@ -54,19 +62,19 @@ deletes them (`yad migrate`'s shape-3 step still adds a `product` role key besid
54
62
  an older project upgrades the same way it always did). `verified_authors` decides nothing — only `yad doctor`
55
63
  reads it, to warn. The roster is read for one thing only: its `name` →
56
64
  `login` pairs let a gate write record the login on older approval and comment records
57
- (`../../yad-hub-bridge/references/login-roster.md` → "Recording the login on older records"). `yad doctor`
65
+ (`../../yad-product-bridge/references/login-roster.md` → "Recording the login on older records"). `yad doctor`
58
66
  warns `people:roster-unused` and `people:verified-authors-unused` so nobody edits them believing they decide
59
67
  something. Delete `verified_authors` when convenient; delete `roster` when `people:roster-unused` says it
60
- can go — no older record needs it any more, or only records it cannot place are left and their reviews are
68
+ can go (edit the settings as the rule at the top of this page says) — no older record needs it any more, or only records it cannot place are left and their reviews are
61
69
  closed.
62
70
 
63
71
  ## Detection
64
72
 
65
- `detect-hub` reuses the same host-detection logic this skill already applies to code repos:
73
+ `detect-product` reuses the same host-detection logic this skill already applies to code repos:
66
74
  run `git remote get-url origin` **on the Product itself** and read the host —
67
75
  `github.com` → `github`, `gitlab.com`/self-hosted GitLab → `gitlab`, no remote → `platform: null`.
68
76
  Auth is the **local user's own** `gh`/`glab`/git credentials; **no tokens are ever stored** (same rule
69
- as the registry). `detect-hub` upserts `hub.json` in place — it is idempotent and safe to re-run.
77
+ as the registry). `detect-product` upserts the file in place: it writes `product.json`, then copies it byte for byte to `hub.json` (`cp`) — idempotent and safe to re-run.
70
78
 
71
79
  **`git_url` is required whenever `platform` is non-null.** `yad doctor` uses it to scope the auth
72
80
  probe to the Product's own host (an unscoped `glab auth status` fails on any unrelated broken instance),
@@ -90,7 +98,7 @@ Keep all three in step.
90
98
  review opens a PR/MR on the Product and `yad-review-gate action: sync` pulls platform state into the ledger.
91
99
  - `ledger: "local"`, `platform: null`, or no/unauthenticated CLI → the gate falls back to the
92
100
  existing **local** flow with no error. The file ledger is the source of truth in both modes.
93
- - The master switch `config.yaml` `product.bridge: false` (older projects: `hub.bridge`) disables the verified ledger globally regardless of `hub.json`.
101
+ - The master switch `config.yaml` `product.bridge: false` (older projects: `hub.bridge`) disables the verified ledger globally regardless of `product.json`.
94
102
 
95
103
  ## Review Companion engagement (`review.requireEngagement`)
96
104
 
@@ -103,12 +111,12 @@ read the artifact. Applies to both the Shape gate and the Build engineer review.
103
111
 
104
112
  ## Git tracking
105
113
 
106
- Commit `hub.json` — it is small, reviewable, and carries no secrets or tokens. The only people data in it is the login or git name in `mode_set.by`, plus
114
+ Commit `product.json` and `hub.json` together — it is small, reviewable, and carries no secrets or tokens. The only people data in it is the login or git name in `mode_set.by`, plus
107
115
  whatever an older `roster` still lists.
108
116
  This mirrors how `repos.json` and the per-epic `.sdlc/` state are committed.
109
117
 
110
118
  ## Greenfield
111
119
 
112
- A brand-new Product has no `hub.json`. That is valid — the Shape gate runs local until `detect-hub`
120
+ A brand-new Product has no `product.json` (and no `hub.json`). That is valid — the Shape gate runs local until `detect-product`
113
121
  records a platform. The verified ledger is purely additive; nothing about authoring or the gate predicate changes.
114
122
  ```
@@ -54,7 +54,7 @@ not under any `epics/EP-<slug>/.sdlc/`.
54
54
  Commit the **registry** (`repos.json`) and each repo's **`code-map.md`** — they are small, reviewable,
55
55
  and are what the Shape phases actually read (a diff on a code-map shows when a repo's surface moved).
56
56
  `yad repo refresh --push` commits and pushes exactly these (never `pack.md`) to the Product's default
57
- branch as one `chore(hub): sync code-context … [skip ci]` audit commit.
57
+ branch as one `chore(product): sync code-context … [skip ci]` audit commit.
58
58
  **Ignore** the full Repomix `pack.md` — it is large and regenerable (`action: refresh`). The Product
59
59
  's `.gitignore` carries `.sdlc/code-context/*/pack.md` for this. This mirrors how the per-epic
60
60
  `.sdlc/` state (state.json, approvals.json, build-log.json) is committed.
@@ -26,7 +26,7 @@ connected, `yad-test-cases` runs artifacts-only exactly as before.
26
26
  same shape as the design tool's MCP, not Repomix's `npx`. The skill detects the MCP and degrades when
27
27
  it is absent; it never installs an MCP server.
28
28
  - Registry: `{project-root}/.sdlc/testing.json` (project-wide, shared across all epics — NOT per-epic),
29
- the sibling of `.sdlc/repos.json`, `.sdlc/hub.json`, and `.sdlc/design.json`.
29
+ the sibling of `.sdlc/repos.json`, `.sdlc/product.json`, and `.sdlc/design.json`.
30
30
  - Per-epic test→suite links are written later by `yad-test-cases`
31
31
  (`epics/EP-<slug>/.sdlc/test-links.json`), not here.
32
32
  - Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
@@ -46,7 +46,7 @@ root, not under any `epics/EP-<slug>/.sdlc/`.
46
46
  ## Git tracking
47
47
 
48
48
  Commit the **registry** (`testing.json`) — it is small, reviewable, and holds no secrets (references
49
- only). This mirrors how `repos.json`, `hub.json`, and `design.json` are committed.
49
+ only). This mirrors how `repos.json`, `product.json`, and `design.json` are committed.
50
50
 
51
51
  ## Greenfield
52
52
 
@@ -45,7 +45,7 @@ reserved `EP-discovery` epic; that older spelling is still read (see Step 1).
45
45
  - on a **verified** ledger CI owns that ledger and it cannot be moved by hand — keep working in
46
46
  `epics/EP-discovery/`, and review it with `yad gate open EP-discovery discovery/`.
47
47
 
48
- Detect the project mode from `{project-root}/.sdlc/hub.json` `profile.codebase`
48
+ Detect the project mode from `{project-root}/.sdlc/product.json` (`.sdlc/hub.json` on an older Product that has only that name) `profile.codebase`
49
49
  (`greenfield` | `brownfield`, set by `yad setup`). If absent, ask the user; default `greenfield`.
50
50
 
51
51
  ### Step 2 — Shape with the field-expert lenses (assist: analyst + pm)
@@ -159,7 +159,7 @@ yad gate open EP-foundation foundation/
159
159
  the gate passes, the ledger moves to the `foundation-done` sentinel (not `ready-for-build` — the
160
160
  Foundation has no Build). From then on `foundation/roadmap.md` and `foundation/scope.md` are the inputs
161
161
  each `yad-epic` reads (its "Step 2c"). When the Product has a platform, the gate opens a review PR on the
162
- Product (via `yad-hub-bridge`) and `yad-review-gate action: sync` pulls platform approvals and comments
162
+ Product (via `yad-product-bridge`) and `yad-review-gate action: sync` pulls platform approvals and comments
163
163
  into the ledger; otherwise the review is recorded locally.
164
164
 
165
165
  ## Reference
@@ -15,7 +15,7 @@
15
15
 
16
16
  The project discovery phase ("epic zero") lives under `{project-root}/epics/EP-discovery/`. It reuses
17
17
  the per-epic ledger files (`.sdlc/state.json`, `approvals.json`, `comments.json`, `reviews/`,
18
- `hub-prs.json`) unchanged — `EP-discovery` is a valid epic id, so the existing gate, PR/MR bridge, CI
18
+ `product-prs.json` + `hub-prs.json`) unchanged — `EP-discovery` is a valid epic id, so the existing gate, PR/MR bridge, CI
19
19
  sync, and `yad next` all operate on it. What is special is the `kind: "discovery"` marker on the state
20
20
  object and the 2-step chain.
21
21
 
@@ -88,7 +88,7 @@ Copy the shell from `templates/app/` **verbatim**, then:
88
88
  2. **Derive stakeholder roles** (`roles.ts`) from the yadflow lens set (analyst / pm / architect / ux /
89
89
  dev / tester / reviewer / engineer), kept only where the epic's artifacts give that lens something to
90
90
  read (which steps have artifacts, and the stories' `repos:` tags). No people or roles are read from
91
- `.sdlc/hub.json` — yadflow keeps no list of people. Each role → its relevant doc `sectionIds` +
91
+ `.sdlc/product.json` — yadflow keeps no list of people. Each role → its relevant doc `sectionIds` +
92
92
  `relevantPathIds` (`references/data-mapping.md`).
93
93
  3. **Theme the `:root` block of `src/index.css`** from the design tokens, by the 4-tier priority in
94
94
  `references/theme-map.md`: **DESIGN.md → design.json/design-links.json palette → code-map tokens →
@@ -54,7 +54,7 @@ contract is rendered exactly as locked — the docs are a *view* of the locked s
54
54
 
55
55
  A stakeholder role is generated for each lens that is **relevant to this epic** — that is, the epic's
56
56
  artifacts give the lens something to read. yadflow keeps no list of people, so no people or roles are
57
- read from `.sdlc/hub.json`.
57
+ read from `.sdlc/product.json`.
58
58
 
59
59
  1. Start from the **yadflow lens set**: `analyst`, `pm`, `architect`, `ux`, `dev`, `tester`, `reviewer`,
60
60
  `engineer`.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "yadflow-docs-site",
3
- "version": "0.0.0",
3
+ "version": "0.0.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "yadflow-docs-site",
9
- "version": "0.0.0",
9
+ "version": "0.0.2",
10
10
  "dependencies": {
11
11
  "framer-motion": "^12.34.4",
12
12
  "react": "^19.2.0",
@@ -1484,9 +1484,9 @@
1484
1484
  }
1485
1485
  },
1486
1486
  "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
1487
- "version": "5.0.9",
1488
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
1489
- "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
1487
+ "version": "5.0.12",
1488
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
1489
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
1490
1490
  "dev": true,
1491
1491
  "license": "MIT",
1492
1492
  "dependencies": {
@@ -1685,9 +1685,9 @@
1685
1685
  }
1686
1686
  },
1687
1687
  "node_modules/brace-expansion": {
1688
- "version": "1.1.18",
1689
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
1690
- "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
1688
+ "version": "1.1.21",
1689
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
1690
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
1691
1691
  "dev": true,
1692
1692
  "license": "MIT",
1693
1693
  "dependencies": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "yadflow-docs-site",
3
3
  "private": true,
4
- "version": "0.0.0",
4
+ "version": "0.0.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -77,11 +77,11 @@ export const FlowCanvas: React.FC = () => {
77
77
 
78
78
  // Optional loop-back arc, swept below the canvas to read as "the pipeline repeats".
79
79
  // Rendered only when both endpoint nodes exist (e.g. the SDLC-overview's
80
- // trust-log → product-hub cycle); a no-op for diagrams without them.
80
+ // trust-log → product cycle); a no-op for diagrams without them.
81
81
  const loopBack = useMemo(() => {
82
82
  if (dims.width === 0) return null;
83
83
  const a = COMPONENTS.find((c) => c.id === 'trust-log');
84
- const b = COMPONENTS.find((c) => c.id === 'product-hub');
84
+ const b = COMPONENTS.find((c) => c.id === 'product');
85
85
  if (!a || !b) return null;
86
86
  const x1 = (a.position.x / 100) * dims.width;
87
87
  const y1 = (a.position.y / 100) * dims.height;
@@ -26,7 +26,7 @@ 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` → `hub.json`) |
29
+ | `yad-connect-repos` | `repos.json`, `code-context/<repo>/pack.md` + `code-map.md` (+ `detect-product` → `product.json` + `hub.json`) |
30
30
  | `yad-connect-design` | `design.json` |
31
31
  | `yad-connect-testing` | `testing.json` |
32
32
  | `yad-connect-learning` | `learning.json` |
@@ -76,7 +76,7 @@ The gated authoring chain + the reusable review gate (10 steps, or 12 with the o
76
76
  | `yad-test-cases` | → `test-cases-review` (parallel, non-blocking) | `test-cases.md`, `test-links.json` |
77
77
  | `yad-review-gate` | the shared gate | `reviews/*.md`, `approvals.json`, `comments.json` |
78
78
  | `yad-review-companion` | the fun/visible review layer (trailer/cards/chat + engagement) | `approvals.json` `engagement`, platform trailer/cards |
79
- | `yad-hub-bridge` | the platform PR/MR bridge | `hub-prs.json` |
79
+ | `yad-product-bridge` | the platform PR/MR bridge | `product-prs.json` + `hub-prs.json` |
80
80
 
81
81
  ### Path: Build (`phase: 3-build`)
82
82
  Per-story, per-repo: `spec → tasks → implement → checks → engineer-review`, plus the commit/PR helpers.
@@ -123,7 +123,7 @@ runs the sweep. The three thread gates ride in the Build `yad-checks` set above.
123
123
  ## System components = the durable state objects
124
124
 
125
125
  `components.ts` renders these on the canvas (deterministic positions): the **Product**; each
126
- `.sdlc/*.json` (`state.json`, `approvals.json`, `comments.json`, `hub.json`, `repos.json`, `design.json`,
126
+ `.sdlc/*.json` (`state.json`, `approvals.json`, `comments.json`, `product.json`, `repos.json`, `design.json`,
127
127
  `testing.json`, `learning.json`, `docs.json`, `contract-lock.json`, `build-state/*`, `trust-log.json`,
128
128
  and the change-thread ledgers `change.json`, `reconcile-debt.json`, `build-log.json`);
129
129
  the **connected code repos**; the **design / testing / learning tools**; and the **platform**
@@ -118,7 +118,7 @@ as one list: someone who has worked in ANY of them meets the ask. Nothing says w
118
118
  Record `engagement: verified` when the engineer reviewed through the companion (else `none` for a bare
119
119
  approve); `yad review reconcile --epic <id> --repo <r> --pr <n>` stamps it onto the ship record from the
120
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
121
- `hub.review.requireEngagement: true`. The signal is gameable by design and sits **beside** the CI gates,
121
+ `review.requireEngagement: true` in the Product settings. The signal is gameable by design and sits **beside** the CI gates,
122
122
  never above them.
123
123
  Recording an approval does **not** ship — shipping is a separate, explicit step. Shape discipline:
124
124
  the gate talks only through files; refuse to treat AI review as a human approval.
@@ -153,7 +153,7 @@ engineer-review rule is satisfied (Step 2). Then:
153
153
  (it never weakens the merge gate — the engineer still owns the merge).
154
154
  - **Commit the machine-written ledgers.** Run `yad checkpoint --push` from `{project-root}` to commit
155
155
  the Build ledgers just written (the `build-log/` shard, and the `trust-log/` shard /
156
- `build-state/<story>.json` if the story ran through `yad-run`) as one `chore(hub): …` audit-trail
156
+ `build-state/<story>.json` if the story ran through `yad-run`) as one `chore(product): …` audit-trail
157
157
  commit — default branch only, staging the shard dirs (`yad tidy up` folds finished shards later),
158
158
  never a Shape gate file. It is the Build analogue of the Shape `yad gate` sync. The
159
159
  same commit also **carries the story `status:` flip** you just wrote (`approved → in-build/shipped`,
@@ -70,7 +70,7 @@ This is the Build analogue of Shape's `approvals.json` — files only, no hidden
70
70
  future service can drive ship by writing the same records. Like the trust log and build-state, it is a
71
71
  machine-written ledger committed by **`yad checkpoint`** (the Build analogue of `yad gate` sync),
72
72
  not by hand: after recording the ship, `yad checkpoint --push` lands the new `build-log/` shard as a
73
- `chore(hub): …` audit-trail commit on the default branch (allowlist-scoped to the Build ledgers,
73
+ `chore(product): …` audit-trail commit on the default branch (allowlist-scoped to the Build ledgers,
74
74
  never a Shape gate file); `yad tidy up` folds finished shards into `build-log.json` later.
75
75
 
76
76
  ### Retroactive ship — a pre-tracking story (#142)
@@ -134,7 +134,7 @@ reclaimed after 30s, and a live one reports `YAD-STATE-006` rather than writing
134
134
  (`yad review trailer/context/nudge`, a real trailer/cards/chat session over the diff), `none` for a bare
135
135
  approve. The optional `companion` block records which faces ran. It is **soft by default** (both count;
136
136
  a bare approve draws a friendly `yad review nudge`); it only gates ship when
137
- `hub.review.requireEngagement: true`. `yad review reconcile --epic <id> --repo <r> --pr <n>` reads the
137
+ `review.requireEngagement: true` in the Product settings. `yad review reconcile --epic <id> --repo <r> --pr <n>` reads the
138
138
  code PR's approvals (with the engagement signal) and stamps them onto the matching ship record — writing
139
139
  back into the ship's shard where it lives (or its folded entry if the story was already tidied) — the
140
140
  Build **bridge**, the analogue of `yad gate sync`. The signal is gameable by design ("visible, not
@@ -151,7 +151,7 @@ The story frontmatter `status` reflects build progress:
151
151
  - `shipped` — **every** task in `tasks.md` has a ship record.
152
152
 
153
153
  You write this flip into `stories/<story>.md`, but **do not hand-commit it** — the next
154
- `yad checkpoint --push` carries it in the same `chore(hub)` commit as the ledgers (the story now has a
154
+ `yad checkpoint --push` carries it in the same `chore(product)` commit as the ledgers (the story now has a
155
155
  build-log ship, so checkpoint stages it; #112). This is what keeps the story artifact from drifting
156
156
  from the build ledger, so there is never a reason to fall back to a raw `git push origin main`.
157
157
 
@@ -19,7 +19,9 @@ drafted, control passes to `yad-review-gate`.
19
19
  inline with the analyst, assigns `EP-<slug>`, and seeds the **10-step** chain.
20
20
 
21
21
  This skill enforces the build plan's core rules: all state lives in files; IDs are generated by the
22
- engine (never typed by hand); Shape steps are locked to `advance: human`.
22
+ engine (never typed by hand); every Shape step starts at `advance: human`. A review gate is always
23
+ human; only the team can set a Shape author step to auto (`yad dial`, recorded in
24
+ `.sdlc/automation.json`; nothing acts on it yet).
23
25
 
24
26
  ## Conventions
25
27
 
@@ -186,7 +188,7 @@ yad epic new EP-<slug> --profile chore # the short upkeep lane — see below
186
188
 
187
189
  That writes `{project-root}/epics/EP-<slug>/.sdlc/state.json`, the empty `approvals.json` and
188
190
  `comments.json`, and the `reviews/` directory. Without `--profile` the chain is the full **10-step**
189
- `classic` route (no analysis). Every step is `advance: human` and locked; `epic` is open and the rest
191
+ `classic` route (no analysis). Every step starts at `advance: human`; `epic` is open and the rest
190
192
  are blocked. The chain comes from the step catalogue and the lifecycle profile in the engine
191
193
  (`references/state-schema.md`), so there is one definition of it and no copy here to drift from it.
192
194
 
@@ -236,7 +238,7 @@ Notes:
236
238
  *(**Always run this**, on both entry modes. The chain is seeded by now either way — by `yad-analysis`,
237
239
  by `yad epic new` in Step 5, or by `yad epic new` before this skill was invoked — and `epic.md` is
238
240
  written. This is the step that closes the authoring step and opens its gate.)*
239
- **Check the mode first — the two modes have opposite instructions here.** Read `.sdlc/hub.json`:
241
+ **Check the mode first — the two modes have opposite instructions here.** Read `.sdlc/product.json` (`.sdlc/hub.json` on an older Product that has only that name):
240
242
  **verified mode** is `platform` set AND `ledger: "verified"` — or, on a project that has not run `yad migrate` yet, `bridge_enabled` (or legacy `bridge`) `true`. `ledger` wins whenever it is present.
241
243
 
242
244
  **verified mode — do NOT write `state.json`.** The ledger is CI-owned: the `ledger-guard` check rejects
@@ -281,7 +283,7 @@ reviewers approve, through the gate.
281
283
  Report: epic ID, the path to `epic.md`, and that the next action is **review** via
282
284
  `yad-review-gate`. **Never mark the epic-review step approved here** — only real reviewers do that
283
285
  through the gate. Shape steps do not auto-advance. When the Product has a platform, the gate opens a review
284
- PR on the Product (via `yad-hub-bridge`) and `yad-review-gate action: sync` pulls platform approvals/
286
+ PR on the Product (via `yad-product-bridge`) and `yad-review-gate action: sync` pulls platform approvals/
285
287
  comments into the ledger; otherwise the review is recorded local.
286
288
 
287
289
  ## Reference
@@ -28,8 +28,8 @@ Three rules go with it, and they are permanent (`docs/roadmap-idea-1.md`, Part 2
28
28
  1. **A file with no version counts as version 1.** Nothing has to be rewritten to be readable. Files
29
29
  written before the stamp existed are read as shape 1, and get the key the next time the engine
30
30
  writes them.
31
- 2. **The list files never carry it.** `approvals.json`, `comments.json`, `hub-prs.json` (also written
32
- as `product-prs.json`) and `reconcile-debt.json` are JSON arrays at the top level, and an array cannot hold a key. Rule 1
31
+ 2. **The list files never carry it.** `approvals.json`, `comments.json`, `product-prs.json` (also written
32
+ under its older name `hub-prs.json`) and `reconcile-debt.json` are JSON arrays at the top level, and an array cannot hold a key. Rule 1
33
33
  covers them: no version means version 1.
34
34
  3. **`schemaVersion` is not the CLI version.** `.sdlc/cli-version.json` records which release of the
35
35
  `yad` CLI set the project up, and changes on every release. `schemaVersion` describes the file's
@@ -206,7 +206,7 @@ A chain missing steps still matches — dropping `ui-design` is normal. An epic
206
206
  nothing gets NO `profile` key from the migration: inventing one would silence `step:off-route` by
207
207
  making the file agree with itself.
208
208
 
209
- > **Two different things are called a profile.** This one is the lifecycle route. `hub.json.profile` is
209
+ > **Two different things are called a profile.** This one is the lifecycle route. `product.json.profile` is
210
210
  > the unrelated setup record `yad setup` writes: `{ codebase, repo_layout, team_size }`.
211
211
 
212
212
  ### The six phases
@@ -556,7 +556,7 @@ unchanged.)
556
556
  Each front **authoring** step opens its own git branch at the start of the step, named
557
557
  `<step>/EP-<slug>` where `<step>` ∈ `analysis | epic | architecture | ui-design | stories | test-cases`
558
558
  (`config.yaml` `defaults.shape_authoring_branch`). This is **distinct** from the review branch
559
- `review/EP-<slug>/<artifact-base>` that `yad-hub-bridge` opens later for the review PR/MR.
559
+ `review/EP-<slug>/<artifact-base>` that `yad-product-bridge` opens later for the review PR/MR.
560
560
 
561
561
  The shared procedure (run once the `EP-<slug>` is known):
562
562
  1. **Git-safe / greenfield-safe:** if `{project-root}` is not a git work tree
@@ -596,10 +596,10 @@ name. The gate never reads the role. While the roster is on disk, the next sync
596
596
  `yad gate ci`) records the login on such an entry when the roster places it for certain, removes `role`
597
597
  and `domain`, and keeps the old name in `rosterName` (E64). Some entries are left as they are — a name two
598
598
  logins share, or several records that do not prove they are one review (most GitLab role records); see
599
- `yad-hub-bridge/references/login-roster.md`. The dated `approved.md` still prints the roles as recorded.
599
+ `yad-product-bridge/references/login-roster.md`. The dated `approved.md` still prints the roles as recorded.
600
600
 
601
601
  `source: "bridge"` marks an approval synced from a Product review PR/MR by `yad-review-gate action: sync`
602
- (via `yad-hub-bridge`). Manual approvals omit `source` and are never altered by `sync`, except for the
602
+ (via `yad-product-bridge`). Manual approvals omit `source` and are never altered by `sync`, except for the
603
603
  login recorded on an older entry (above). A manual approval written by `yad gate approve` (E112, a
604
604
  Product with no platform) carries `artifactHash`, so an edit to the artifact revokes it as it revokes a
605
605
  bridge approval; one written by hand before E112 has none, so an edit does not revoke it.
@@ -614,7 +614,7 @@ rather than *who approved*:
614
614
  | `pr` | the PR/MR number the approval arrived on. The second proof of a genuine re-approval, and the only one available on GitLab: a re-opened review is always a new PR, so an approval on a different number cannot be the old one re-read. Records written before this field existed are stamped once, from the `hub-prs.json` pointer they were recorded against. |
615
615
  | `commit`, `url`, `reviewId` | the platform's evidence for the review (E64): the commit it was given on, its link, and its node id. GitHub only, and only when the read gave them — never written `null`. An MR approval on GitLab is not tied to a commit, so none is recorded there. For the record only; the gate never reads them. |
616
616
  | `rosterName` | on an older entry whose login was recorded from the roster (E64), the name it had. The gate lets an exact submission time move such an entry to the person who really submitted that review. |
617
- | `engagement` | `verified` when the approval carried the companion's engagement marker, else `none`. Advisory unless `hub.review.requireEngagement` is on. |
617
+ | `engagement` | `verified` when the approval carried the companion's engagement marker, else `none`. Advisory unless `review.requireEngagement` (Product settings) is on. |
618
618
 
619
619
  `date` is when the sync **recorded** the approval, not when it was given — it is preserved across an
620
620
  unchanged re-sync so that re-reading a review never churns the ledger.
@@ -632,7 +632,7 @@ Append-only ledger (an array), the machine-readable counterpart to the `reviews/
632
632
  written by `yad gate comment` (E112, no platform) also carries `artifactHash`, the fingerprint of the
633
633
  artifact its round was opened with (a late record joining the round carries the same one): a round is one version, so `--new-round` opens the next only after an edit. An older entry may still carry `role` and `domain`; the gate never reads them, and while the roster is on disk the next sync write records the login on it, keeping the old name in `rosterName` — unless two records in one round would then name the same login (E64).
634
634
 
635
- ## `hub-prs.json`
635
+ ## `product-prs.json` (and `hub-prs.json`)
636
636
  Present only when the Shape review runs through the platform bridge. Per review step, the review
637
637
  PR/MR opened on the Product (sibling of `approvals.json`, so the locked `state.json` step shape is untouched):
638
638
 
@@ -640,8 +640,9 @@ PR/MR opened on the Product (sibling of `approvals.json`, so the locked `state.j
640
640
  { "step": "<review step id>", "artifact": "<artifact>", "platform": "github|gitlab", "number": <n>, "url": "<pr/mr url>", "branch": "review/EP-<slug>/<artifact-base>", "lastSyncedAt": "<YYYY-MM-DD or null>" }
641
641
  ```
642
642
 
643
- The same array is written under two names: `product-prs.json` (the name from shape 3) and `hub-prs.json`
644
- (the old name, kept for one major). `yad gate sync` may add `nudged`, the logins it has already asked to
643
+ The same array is written under two names, with identical bytes: `product-prs.json` (the name from shape 3,
644
+ read first) and `hub-prs.json` (the old name, written until v5 and read only when `product-prs.json` is
645
+ absent — E122). `yad gate sync` may add `nudged`, the logins it has already asked to
645
646
  use the review companion, so it never asks them twice.
646
647
 
647
648
  ## `design-links.json`
@@ -693,10 +694,10 @@ whether to advance on its own. Two new files under `.sdlc/` do this.
693
694
  > **Who commits these.** `build-state/<story-id>.json`, `trust-log.json`, and `build-log.json` are
694
695
  > **machine-written** by Build (`yad-run`, `yad-engineer-review`) and committed by
695
696
  > **`yad checkpoint`** — the Build analogue of the Shape `yad gate ci` sync. It lands them as
696
- > one `chore(hub): sync Build state — <epic>/<story> by @<login>` audit-trail commit, on the
697
+ > one `chore(product): sync Build state — <epic>/<story> by @<login>` audit-trail commit, on the
697
698
  > default branch, staging **only** these three ledgers by an explicit allowlist (never a Shape
698
699
  > gate file — `state/approvals/comments/product-prs/hub-prs.json`, `reviews/*.md` — so `ledger-guard` never trips).
699
- > Teammates don't review these machine writes; the commit exists so CI, `yad status`, and other
700
+ > Teammates don't review these machine writes; the commit exists so CI, the `yad-status` skill, and other
700
701
  > machines always see current trust evidence.
701
702
 
702
703
  ## `build-state/<story-id>.json`
@@ -32,7 +32,7 @@ the Product.
32
32
  `pull_request_template.md`, so the Product `pr-template` gate passes.
33
33
  In a code repo nothing changes — it reads the repo's own committed code-task template.
34
34
  - **Base branch** — **resolved, never assumed.** In order: `--base` → the repo's `default_branch` in
35
- `.sdlc/repos.json` → (for a PR against the Product itself) `hub.json`'s `default_branch` → what the
35
+ `.sdlc/repos.json` → (for a PR against the Product itself) `product.json`'s `default_branch` (`hub.json` on an older Product) → what the
36
36
  platform reports (`gh repo view --json defaultBranchRef` / `glab api projects/:id`) → local
37
37
  `origin/HEAD` → `main`. The same **configuration-outranks-the-remote** order `yad repo sync` and the
38
38
  contract-check gate already use (they stop at `origin/HEAD`; only this chain also asks the platform).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yad-pair-review
3
- description: 'The guided, two-way, teaching pair-review walkthrough for the SDLC review gates — the AI-driven companion face. The human opens a PR/MR with an AI session and the AI walks them through the change ONE STOP AT A TIME (highest-risk first), giving comprehensive context per change, then asking the human a Socratic question about it; the human answers and asks back, and both keep going until BOTH declare satisfied. The session doubles as a learning session: it demonstrates a transferable review method, scores the engineer against it, and records their review-skill growth in the local-only yad-learn ledger (rolled up by yad status). Works on the Build code PR/MR (yad review) and the Shape artifact-review PR/MR (yad gate). Soft and additive — it NEVER blocks a merge or gate; it rides the existing engagement signal and surfaces genuine concerns as normal blocking comments. Use when the user says "pair review this", "walk me through the PR/MR", "review with me", "co-review", or "teach me to review".'
3
+ description: 'The guided, two-way, teaching pair-review walkthrough for the SDLC review gates — the AI-driven companion face. The human opens a PR/MR with an AI session and the AI walks them through the change ONE STOP AT A TIME (highest-risk first), giving comprehensive context per change, then asking the human a Socratic question about it; the human answers and asks back, and both keep going until BOTH declare satisfied. The session doubles as a learning session: it demonstrates a transferable review method, scores the engineer against it, and records their review-skill growth in the local-only yad-learn ledger (rolled up by the yad-status skill). Works on the Build code PR/MR (yad review) and the Shape artifact-review PR/MR (yad gate). Soft and additive — it NEVER blocks a merge or gate; it rides the existing engagement signal and surfaces genuine concerns as normal blocking comments. Use when the user says "pair review this", "walk me through the PR/MR", "review with me", "co-review", or "teach me to review".'
4
4
  ---
5
5
 
6
6
  # SDLC — Pair Review (the guided, two-way, teaching walkthrough)
@@ -99,7 +99,7 @@ addresses them) — nothing advances on a half-finished session.
99
99
 
100
100
  ### Step 5 — Record the session (twice) — see `references/session-state.md`
101
101
  1. **Session comment (PR/MR history).** Post one comment built by the CLI helper `pairSessionBody`
102
- (carries `<!-- yad:pair -->` so `yad status` can count paired reviews, and `<!-- yad:noblock -->` so it
102
+ (carries `<!-- yad:pair -->` so the `yad-status` skill can count paired reviews, and `<!-- yad:noblock -->` so it
103
103
  never holds the gate): the transcript summary, the **review-skill scorecard**, your AI verdict, and
104
104
  both sign-offs. Post it with the platform CLI (`gh pr comment` / `glab mr note`).
105
105
  2. **Learning record (local-only).** Append a `yad-learn` record for the `member`: `concept` =
@@ -108,14 +108,14 @@ addresses them) — nothing advances on a half-finished session.
108
108
  comprehension), `comprehension` = the scorecard roll-up, `tutorial` = a rendered
109
109
  `learning/<member>--review-<pr>.md` capturing the method as applied to this PR + the engineer's gaps.
110
110
  **First ensure the Product `.gitignore` covers the learning paths** (reuse yad-learn's guard), then write —
111
- these are personal, gitignored, **never committed or pushed**. The growth rolls up under `yad status`
112
- "My skills".
111
+ these are personal, gitignored, **never committed or pushed**. The growth rolls up under the `yad-status`
112
+ skill's "My skills".
113
113
 
114
114
  ## Hard rules
115
115
 
116
116
  - **Never a gate.** This skill never moves `currentStep`, never records an approval on the human's
117
117
  behalf, and never merges. It enriches the input and rides the existing soft `engagement` signal only.
118
- Strict mode (`hub.review.requireEngagement`) is the gate's switch, not this skill's.
118
+ Strict mode (`review.requireEngagement` (Product settings)) is the gate's switch, not this skill's.
119
119
  - **The CLI never calls an LLM.** The sequencer (`stops[]`) and the markers are deterministic; *you*
120
120
  generate every briefing, question, and answer. Same split as the companion.
121
121
  - **Grounded only in real material.** Briefings/answers come from the diff + artifact + contract +
@@ -8,7 +8,7 @@ of which ever blocks the gate. The gate's predicate (approvals + resolved thread
8
8
  Built by the CLI helper `pairSessionBody({ summary, scorecard, verdict, humanSignoff, aiSignoff })` in
9
9
  `cli/companion.mjs`. It carries **both** markers:
10
10
 
11
- - `<!-- yad:pair -->` — so this is countable as a *paired review* in the `yad status` 🏆 roll-up.
11
+ - `<!-- yad:pair -->` — so this is countable as a *paired review* in the `yad-status` skill's 🏆 roll-up.
12
12
  - `<!-- yad:noblock -->` — so the thread is excluded from the gate's blocking check and persists as
13
13
  permanent history (a deliberate, unresolved trail), exactly like the companion's card/chat threads.
14
14
 
@@ -71,7 +71,7 @@ Field notes:
71
71
  Also render the tutorial artifact `epics/EP-<slug>/learning/<member>--review-<pr>.md` (front-matter:
72
72
  `member`, `concept`, `stage`, `tool`, `requestedAt`) — the review method as applied to *this* PR plus the
73
73
  engineer's specific gaps and how to close them. Both files are **local-only, gitignored, never committed
74
- or pushed, and never written into a code repo** — they are a private personal skills log. `yad status`
74
+ or pushed, and never written into a code repo** — they are a private personal skills log. The `yad-status` skill
75
75
  rolls them up by stage (e.g. "engineer-review: 3").
76
76
 
77
77
  ## Optional: stamp the build-log (Build)
@@ -23,21 +23,21 @@ routing helper.
23
23
  - `templates/gitlab/merge_request_templates/Default.md` → installs to
24
24
  `<repo>/.gitlab/merge_request_templates/Default.md`
25
25
  - `templates/checks/risk-route.sh` → installs to `<repo>/checks/risk-route.sh` (advisory routing helper)
26
- - **Product variants** (`repo: hub`) — Shape artifact-review PR/MR bodies:
27
- `templates/hub/github/pull_request_template.md` → `{project-root}/.github/pull_request_template.md`;
28
- `templates/hub/gitlab/merge_request_templates/Default.md` →
26
+ - **Product variants** (`repo: product`) — Shape artifact-review PR/MR bodies:
27
+ `templates/product/github/pull_request_template.md` → `{project-root}/.github/pull_request_template.md`;
28
+ `templates/product/gitlab/merge_request_templates/Default.md` →
29
29
  `{project-root}/.gitlab/merge_request_templates/Default.md`. The Product body carries no `Task:` trailer
30
- (Product PRs change artifacts, not code); its routing helper is `yad-hub-bridge`'s
31
- `templates/checks/hub-route.sh`, run from the skill (nothing installs it into the Product's `checks/`).
30
+ (Product PRs change artifacts, not code); its routing helper is `yad-product-bridge`'s
31
+ `templates/checks/product-route.sh`, run from the skill (nothing installs it into the Product's `checks/`).
32
32
  - **GitLab reads a truncated description.** The `pr-template` gate is fed
33
33
  `$CI_MERGE_REQUEST_DESCRIPTION`, which GitLab cuts at **2700 characters** — a required section below
34
34
  that cutoff is invisible to the gate even though the MR shows it, and the failure reads "does not use
35
35
  the template" (#164). Both GitLab templates say so in a comment and keep `## Summary` /
36
- `## Impact & Risk` / `## Checklist` (hub: `## Artifact under review` / `## Impact & Risk (front-half)`
36
+ `## Impact & Risk` / `## Checklist` (Product: `## Artifact under review` / `## Impact & Risk (front-half)`
37
37
  / `## Checklist`) early, so a truncated body still passes. Long narrative goes **after** them.
38
38
  Sections may be reordered freely; deleting one fails the gate. GitHub is unaffected.
39
39
  - **Installed code-repo templates are yad-managed.** `yad update` rewrites them on upgrade (the Product
40
- variants under `templates/hub/` are copied by hand in Step 2 and are not managed). An edit yad can
40
+ variants under `templates/product/` are copied by hand in Step 2 and are not managed). An edit yad can
41
41
  prove — the file's sha differs from the one it recorded when it wrote the template — is reported as
42
42
  `modified` and left alone; a copy it has no record of is replaced after a `.yad-orig` backup (see
43
43
  `docs/CLI.md` → *Managed files*). Either way, put knowledge that must survive an upgrade in an ADR
@@ -54,7 +54,8 @@ routing helper.
54
54
 
55
55
  ## Inputs
56
56
 
57
- - `repo` — the code repo to add the template to (one of an epic's repos), or `hub` for the Product.
57
+ - `repo` — the code repo to add the template to (one of an epic's repos), or `product` for the Product (`hub`, the old name, still works). A code repo that is itself named
58
+ `product`: give its registered path instead (for example `repos/product`), so it is not taken for the Product.
58
59
  - `action` — `wire` (commit the matching template + helper) | `route` (print the approver count from a
59
60
  PR body). Default `wire`.
60
61
  - `body` — for `route`: a file holding the PR/MR description to evaluate.
@@ -62,17 +63,18 @@ routing helper.
62
63
  ## On Activation
63
64
 
64
65
  ### Step 1 — Resolve the repo and detect the platform
65
- Map `repo` → `{project-root}/demo-repos/<repo>/` (or the registry `path`). Detect the platform: a GitHub
66
+ Map `repo` → `{project-root}/demo-repos/<repo>/` (or the registry `path`). A `repo` value with a `/` in it is a registry `path`, not a name: match it against each entry's `path`
67
+ (so a code repo named `product` is reached as, for example, `repos/product`). Detect the platform: a GitHub
66
68
  remote or `.github/` → GitHub; a GitLab remote or `.gitlab/` → GitLab. If ambiguous, ask. For
67
- `repo: hub`, the target is `{project-root}` itself and the platform comes from `.sdlc/hub.json`.
69
+ `repo: product`, the target is `{project-root}` itself and the platform comes from `.sdlc/product.json` (`.sdlc/hub.json` on an older Product that has only that name).
68
70
 
69
71
  ### Step 2 — `wire` (drop only the matching template)
70
72
  Copy from this skill's `templates/`:
71
73
  - GitHub → `templates/github/pull_request_template.md` to `<repo>/.github/pull_request_template.md`.
72
74
  - GitLab → `templates/gitlab/merge_request_templates/Default.md` to
73
75
  `<repo>/.gitlab/merge_request_templates/Default.md`.
74
- - **`repo: hub`** → use the `templates/hub/<platform>/…` variants, installed into `{project-root}`'s own
75
- `.github/`/`.gitlab/`. The Product's routing helper (`hub-route.sh`) stays in `yad-hub-bridge`'s
76
+ - **`repo: product`** → use the `templates/product/<platform>/…` variants, installed into `{project-root}`'s own
77
+ `.github/`/`.gitlab/`. The Product's routing helper (`product-route.sh`) stays in `yad-product-bridge`'s
76
78
  `templates/checks/`; neither this skill nor `yad setup` / `yad check --fix` installs it.
77
79
  Drop **only the matching** template (drop both only if the repo genuinely uses both). For code repos also
78
80
  install `templates/checks/risk-route.sh` to `<repo>/checks/` (`chmod +x`), beside