yadflow 3.18.0 → 3.19.0-next.2

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 (106) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +11 -11
  3. package/bin/yad.mjs +8 -8
  4. package/cli/artifact-status.mjs +4 -4
  5. package/cli/checkpoint.mjs +25 -25
  6. package/cli/commit.mjs +1 -1
  7. package/cli/companion.mjs +2 -2
  8. package/cli/doctor.mjs +10 -10
  9. package/cli/epic-state.mjs +29 -29
  10. package/cli/errors.mjs +1 -1
  11. package/cli/gate.mjs +32 -33
  12. package/cli/hook.mjs +4 -4
  13. package/cli/hubcommit.mjs +1 -1
  14. package/cli/ledger.mjs +3 -3
  15. package/cli/lib.mjs +23 -9
  16. package/cli/manifest.mjs +42 -21
  17. package/cli/migrate.mjs +54 -12
  18. package/cli/next.mjs +5 -5
  19. package/cli/openpr.mjs +8 -8
  20. package/cli/plan.mjs +28 -9
  21. package/cli/platform.mjs +1 -1
  22. package/cli/report.mjs +1 -1
  23. package/cli/review.mjs +5 -5
  24. package/cli/setup.mjs +22 -10
  25. package/cli/ship.mjs +1 -1
  26. package/cli/skip.mjs +1 -1
  27. package/cli/thread.mjs +1 -1
  28. package/cli/tidy.mjs +2 -2
  29. package/cli/update-commit.mjs +1 -1
  30. package/package.json +1 -1
  31. package/skills/sdlc/config.yaml +30 -30
  32. package/skills/sdlc/module-help.csv +21 -21
  33. package/skills/yad-analysis/SKILL.md +10 -10
  34. package/skills/yad-architecture/SKILL.md +10 -10
  35. package/skills/yad-architecture/references/contract-format.md +2 -3
  36. package/skills/yad-backfill/SKILL.md +5 -5
  37. package/skills/yad-change/SKILL.md +13 -13
  38. package/skills/yad-change/references/triage.md +2 -3
  39. package/skills/yad-checks/SKILL.md +34 -16
  40. package/skills/yad-checks/references/check-gates.md +63 -19
  41. package/skills/yad-checks/templates/checks/build-test-lint.sh +25 -7
  42. package/skills/yad-checks/templates/checks/epic-open.sh +1 -1
  43. package/skills/yad-checks/templates/checks/install-deps.sh +46 -0
  44. package/skills/yad-checks/templates/checks/ledger-guard.sh +41 -12
  45. package/skills/yad-checks/templates/checks/package-manager.sh +140 -0
  46. package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +3 -3
  47. package/skills/yad-checks/templates/github/yad-checks.yml +24 -3
  48. package/skills/yad-checks/templates/github/yad-hub-checks.yml +2 -2
  49. package/skills/yad-checks/templates/github/yad-verified-commits.yml +1 -1
  50. package/skills/yad-checks/templates/gitlab/.gitlab-ci.yml +7 -1
  51. package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +12 -3
  52. package/skills/yad-checks/templates/gitlab/yad-hub-checks.gitlab-ci.yml +2 -2
  53. package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +1 -1
  54. package/skills/yad-checks/templates/hooks/ledger-guard.sh +1 -1
  55. package/skills/yad-commit/SKILL.md +2 -2
  56. package/skills/yad-connect-design/SKILL.md +1 -1
  57. package/skills/yad-connect-docs/SKILL.md +1 -1
  58. package/skills/yad-connect-repos/SKILL.md +32 -15
  59. package/skills/yad-connect-repos/references/code-context.md +2 -2
  60. package/skills/yad-connect-repos/references/hub-config.md +25 -11
  61. package/skills/yad-connect-repos/references/repos-registry.md +3 -3
  62. package/skills/yad-connect-testing/SKILL.md +1 -1
  63. package/skills/yad-defects/SKILL.md +1 -1
  64. package/skills/yad-discovery/SKILL.md +6 -6
  65. package/skills/yad-discovery/references/discovery-schema.md +1 -1
  66. package/skills/yad-docs/SKILL.md +3 -3
  67. package/skills/yad-docs/templates/app/package-lock.json +65 -51
  68. package/skills/yad-docs/templates/app/package.json +1 -1
  69. package/skills/yad-docs-overview/SKILL.md +3 -3
  70. package/skills/yad-docs-overview/references/pipeline-model.md +17 -11
  71. package/skills/yad-engineer-review/SKILL.md +9 -9
  72. package/skills/yad-engineer-review/references/ship-and-record.md +8 -8
  73. package/skills/yad-epic/SKILL.md +15 -15
  74. package/skills/yad-epic/references/state-schema.md +30 -30
  75. package/skills/yad-hub-bridge/SKILL.md +14 -14
  76. package/skills/yad-hub-bridge/references/bridge.md +17 -17
  77. package/skills/yad-hub-bridge/references/login-roster.md +3 -3
  78. package/skills/yad-hub-bridge/templates/checks/hub-route.sh +1 -1
  79. package/skills/yad-hub-bridge/templates/gitlab/yad-gate-sync.gitlab-ci.yml +1 -1
  80. package/skills/yad-implement/SKILL.md +3 -3
  81. package/skills/yad-open-pr/SKILL.md +4 -4
  82. package/skills/yad-pair-review/SKILL.md +12 -12
  83. package/skills/yad-pair-review/references/session-state.md +3 -3
  84. package/skills/yad-pr-template/SKILL.md +4 -4
  85. package/skills/yad-pr-template/references/risk-routing.md +1 -1
  86. package/skills/yad-pr-template/templates/checks/pr-template.sh +18 -10
  87. package/skills/yad-pr-template/templates/checks/pr-title.sh +7 -7
  88. package/skills/yad-pr-template/templates/hub/github/pull_request_template.md +1 -1
  89. package/skills/yad-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +1 -1
  90. package/skills/yad-reconcile/SKILL.md +1 -1
  91. package/skills/yad-report/SKILL.md +1 -1
  92. package/skills/yad-review-companion/SKILL.md +7 -7
  93. package/skills/yad-review-gate/SKILL.md +18 -18
  94. package/skills/yad-review-gate/references/gating.md +3 -3
  95. package/skills/yad-run/SKILL.md +10 -10
  96. package/skills/yad-run/references/run-loop.md +8 -8
  97. package/skills/yad-ship/SKILL.md +4 -4
  98. package/skills/yad-spec/SKILL.md +10 -11
  99. package/skills/yad-status/SKILL.md +13 -13
  100. package/skills/yad-stories/SKILL.md +12 -12
  101. package/skills/yad-stories/references/story-schema.md +3 -3
  102. package/skills/yad-stub/SKILL.md +3 -3
  103. package/skills/yad-sync-repos/SKILL.md +1 -1
  104. package/skills/yad-test-cases/SKILL.md +12 -13
  105. package/skills/yad-test-cases/references/test-cases-schema.md +1 -1
  106. package/skills/yad-ui/SKILL.md +10 -10
package/CHANGELOG.md CHANGED
@@ -1,3 +1,49 @@
1
+ # [3.19.0-next.2](https://github.com/abdelrahmannasr/yadflow/compare/v3.19.0-next.1...v3.19.0-next.2) (2026-09-07)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **release:** let a pre-release publish past its own test suite ([70286ce](https://github.com/abdelrahmannasr/yadflow/commit/70286ce833b300d02d2781ac589d727481f5e7eb))
7
+
8
+ # [3.19.0-next.1](https://github.com/abdelrahmannasr/yadflow/compare/v3.18.1...v3.19.0-next.1) (2026-09-07)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **checks:** accept every integrity algorithm Corepack accepts in packageManager ([367947d](https://github.com/abdelrahmannasr/yadflow/commit/367947d8d9856138b531061e4b686057ee9f715f))
14
+ * **checks:** cache the Corepack home alongside the dependency cache ([23d92bc](https://github.com/abdelrahmannasr/yadflow/commit/23d92bc8204063bbd7754bfd038585eeb6f705bb))
15
+ * **checks:** close configurable CI review findings ([6d90018](https://github.com/abdelrahmannasr/yadflow/commit/6d900183bbee5785f4ff0d5c868a6a55ce01a9b7))
16
+ * **checks:** fail with guidance when corepack is missing for a declared packageManager ([3a9f576](https://github.com/abdelrahmannasr/yadflow/commit/3a9f5760bcca050d87008e414b856d5b307f30b8))
17
+ * **checks:** give the same guidance when Corepack is present but stale ([0cdf4d1](https://github.com/abdelrahmannasr/yadflow/commit/0cdf4d157946d9185bfcc286ebddcdfb5d65a6aa))
18
+ * **checks:** keep a yarn/bun-declared repo with an npm lockfile on the npm path ([713e707](https://github.com/abdelrahmannasr/yadflow/commit/713e7074b6813de0e0fd6e12e970e8372a1309eb))
19
+ * **checks:** keep the gate jobs' variables off the host GitLab pipeline ([7cb2c35](https://github.com/abdelrahmannasr/yadflow/commit/7cb2c35a3011dbd8bf8d048f7aa02578ac54a1db))
20
+ * **checks:** keep the npm path when a repo carries both lockfiles ([67fbdb4](https://github.com/abdelrahmannasr/yadflow/commit/67fbdb4e2c82188b37b1d175260b48da17d5e051))
21
+ * **checks:** make build-test-lint fail closed on a rejected package.json ([83241ee](https://github.com/abdelrahmannasr/yadflow/commit/83241eed61e4306853151e6105c0b7c8bdd06d55))
22
+ * **checks:** pass the worker cap to jest/vitest under pnpm without npm's `--` ([55db7ee](https://github.com/abdelrahmannasr/yadflow/commit/55db7eed85173472a17e7591636d7fc830a5a5b6))
23
+ * **checks:** read package.json the way npm does before judging it ([8021c78](https://github.com/abdelrahmannasr/yadflow/commit/8021c7850d4f7d0887923165adc585fc27da260a))
24
+ * **checks:** require lowercase Corepack digests ([4750b8b](https://github.com/abdelrahmannasr/yadflow/commit/4750b8b597bfdd4d7d2739a0525f91a2002e41a3))
25
+ * **checks:** restore dependency caching in the GitHub quality job, for pnpm too ([21c92f0](https://github.com/abdelrahmannasr/yadflow/commit/21c92f026aa590ec464eec7152af27ad2be9a49d))
26
+ * **checks:** run the gate's lint/build/test through the pinned npm too ([8404da3](https://github.com/abdelrahmannasr/yadflow/commit/8404da326f8a19ae807c58808b6203572aadb9b4))
27
+ * **checks:** support configurable CI toolchains ([30557e4](https://github.com/abdelrahmannasr/yadflow/commit/30557e419a9fec5adca06a3ecb8ca09469b2a58a))
28
+ * **checks:** validate Corepack integrity metadata ([a6c3fd3](https://github.com/abdelrahmannasr/yadflow/commit/a6c3fd3d84a370f81477ed9b551bc29f5765296f))
29
+ * **skills:** teach the skill layer that `ledger` is the switch ([d4622ab](https://github.com/abdelrahmannasr/yadflow/commit/d4622ab2293cfe49a36791f6cf51472b4d5701ad)), closes [#186](https://github.com/abdelrahmannasr/yadflow/issues/186)
30
+ * **state:** read an unstamped file as shape 1, not as the engine's shape ([6d8c608](https://github.com/abdelrahmannasr/yadflow/commit/6d8c608215175fac98933ffee6f714471454a8d9))
31
+ * **update:** install templates newly added to a wired repo on `yad update` ([8e8d92f](https://github.com/abdelrahmannasr/yadflow/commit/8e8d92f1265e2ed375bf0a53307270a25d8c33f3))
32
+ * **update:** take only yad's own wiring as proof a repo is wired ([3c90134](https://github.com/abdelrahmannasr/yadflow/commit/3c90134985eebb3b7faa91be2c45387d54851324))
33
+
34
+
35
+ ### Features
36
+
37
+ * **state:** record who writes the ledger as `ledger: verified | local` ([6623199](https://github.com/abdelrahmannasr/yadflow/commit/66231997156bb1ffa446ebb5edd28d8ebf8def91)), closes [#186](https://github.com/abdelrahmannasr/yadflow/issues/186)
38
+
39
+ ## [3.18.1](https://github.com/abdelrahmannasr/yadflow/compare/v3.18.0...v3.18.1) (2026-09-05)
40
+
41
+
42
+ ### Bug Fixes
43
+
44
+ * **docs:** raise the template's react-router-dom floor to the patched version ([ca510d4](https://github.com/abdelrahmannasr/yadflow/commit/ca510d40d42600254aa39821de99ae5990698605))
45
+ * **docs:** ship the docs template with a patched react-router-dom ([28b6ff7](https://github.com/abdelrahmannasr/yadflow/commit/28b6ff768fb6b11799ab28e4e4d780aa6bfca5bc)), closes [hi#severity](https://github.com/hi/issues/severity)
46
+
1
47
  # [3.18.0](https://github.com/abdelrahmannasr/yadflow/compare/v3.17.3...v3.18.0) (2026-09-05)
2
48
 
3
49
 
package/README.md CHANGED
@@ -38,11 +38,11 @@ one product hub + many code repos, solo or team.
38
38
  ## How the workflow looks
39
39
 
40
40
  <!-- Source: docs/diagrams/sdlc-overview.mmd — edit the .mmd and run `npm run diagrams` to regenerate -->
41
- ![Yadflow SDLC overview — setup, human-gated front half, per-story build half, earned automation](https://raw.githubusercontent.com/abdelrahmannasr/yadflow/main/docs/diagrams/sdlc-overview.svg)
41
+ ![Yadflow SDLC overview — setup, human-gated Shape, per-story Build, earned automation](https://raw.githubusercontent.com/abdelrahmannasr/yadflow/main/docs/diagrams/sdlc-overview.svg)
42
42
 
43
43
  **Legend:** 🟨 **artifact** (a step writes a file and stops) · 🟧 **gate** (a human review that must
44
- pass) · 🟦 **earns automation** (a back step that can later auto-advance once it proves itself) ·
45
- ⬜ **locked** (the engineer review and every front state — permanently human).
44
+ pass) · 🟦 **earns automation** (a Build step that can later auto-advance once it proves itself) ·
45
+ ⬜ **locked** (the engineer review and every Shape step — permanently human).
46
46
 
47
47
  ## Quickstart
48
48
 
@@ -56,7 +56,7 @@ Then, in your AI IDE, drive the lifecycle by invoking skills by name:
56
56
 
57
57
  ```text
58
58
  run yad-epic # 2. author + gate the "thinking": epic → architecture → UI → stories
59
- run yad-spec … # 3. build half: spec → implement → checks → ship (per story, per repo)
59
+ run yad-spec … # 3. Build: spec → implement → checks → ship (per story, per repo)
60
60
  ```
61
61
 
62
62
  Every step stops at a gate until a human approves. New here? **Walk it lesson-by-lesson in the
@@ -89,7 +89,7 @@ In one pass it produces:
89
89
  push-on-main **`yad-update-guard`** (which re-checks any direct-to-default commit — e.g. from
90
90
  `yad update --push` — with just `verified-commits` + `commit-message`), shipped as CI-agnostic bash
91
91
  under `checks/`.
92
- - **An agent guardrail** on a bridge hub — `hooks/ledger-guard.sh`, a harness hook that refuses an
92
+ - **An agent guardrail** on a verified hub — `hooks/ledger-guard.sh`, a harness hook that refuses an
93
93
  agent the CI-owned gate-ledger write at the moment it tries it and names the command that owns the
94
94
  transition, instead of letting it surface as a CI failure twenty minutes later. Harness-agnostic
95
95
  (stdin payload, exit 0 allows / 2 denies) and fails open — the CI gate stays the authority.
@@ -109,21 +109,21 @@ setup → AI drafts an artifact → ⛔ gate waits → you approve → next step
109
109
  1. **`npx yadflow setup`** — the wizard installs skills, connects your repo, and wires the gates.
110
110
  2. **Run `yad-epic`** in your assistant — it drafts the epic, then **stops** and writes it to a file.
111
111
  3. **A gate waits.** Nothing advances until you review it.
112
- 4. **You approve** — file-only, or by merging the review PR/MR.
112
+ 4. **You approve** — local, or by merging the review PR/MR.
113
113
  5. **The workflow continues** to the next step, which stops again.
114
114
 
115
115
  Every step is the same contract: *AI proposes → a human decides → the trail is recorded.*
116
116
 
117
117
  ## How it works (in five points)
118
118
 
119
- - **Front half = decide.** Once per epic, in the product hub: epic, architecture + a locked contract,
119
+ - **Shape = decide.** Once per epic, in the product hub: epic, architecture + a locked contract,
120
120
  UI, stories, test cases. Always human-gated — nothing auto-advances.
121
- - **Build half = build.** Once per story per code repo: spec → implement → checks → ship.
122
- - **Every step stops at a gate.** A human moves it forward (file-only, or by merging a review PR/MR).
121
+ - **Build = make it real.** Once per story per code repo: spec → implement → checks → ship.
122
+ - **Every step stops at a gate.** A human moves it forward (local, or by merging a review PR/MR).
123
123
  <!-- IMAGE: docs/media/pr-gate.png — "The review gate rides a real PR/MR: approve to advance, comment to block." -->
124
- - **Automation is opt-in and earned.** A safe back-half step can earn auto-advance after it proves
124
+ - **Automation is opt-in and earned.** A safe Build step can earn auto-advance after it proves
125
125
  itself — and a one-command kill switch reverts everything to manual. The engineer review and all
126
- front states are never automatable.
126
+ Shape steps are never automatable.
127
127
  - **Everything is files.** State, approvals, the contract lock, the build log — all plain files under
128
128
  `epics/EP-<slug>/`. No database. The audit trail *is* the repo.
129
129
 
package/bin/yad.mjs CHANGED
@@ -59,7 +59,7 @@ ${c.bold('Setup & maintenance')}
59
59
  (no paths/hosts/repo names/logins/flag values). Also offered
60
60
  automatically after an unexpected failure. YAD_NO_REPORT=1 disables.
61
61
  yad hook ledger-guard ${c.dim('harness-invoked, not typed')} — refuse an agent's edit to the
62
- CI-owned gate ledger in bridge mode and name the command that owns
62
+ CI-owned gate ledger in verified mode and name the command that owns
63
63
  the transition. Reads a tool-call payload on stdin (or --path <p>);
64
64
  exit 0 allows, exit 2 denies with the reason on stderr. Wired into
65
65
  .claude/settings.json by setup / check --fix. YAD_HOOK_DISABLE=1 skips.
@@ -91,14 +91,14 @@ ${c.bold('Where am I / what next')}
91
91
  Stays visible & auditable (pre-done, gate short-circuited);
92
92
  --undo reverses it until the stories review opens
93
93
 
94
- ${c.bold('Review gate (front half)')}
94
+ ${c.bold('Review gate (Shape)')}
95
95
  yad gate open <epic> <artifact> Open the review PR/MR; mark the step in_review. The review
96
96
  branch must already be on origin (it is never created here)
97
97
  yad gate sync <epic> [artifact] [--pr <n>]
98
98
  Pull PR state -> ledger; advance on approved+resolved+merged.
99
99
  With no recorded PR, resolves it from the review branch; --pr
100
100
  names one (and overrides a stale recorded pointer). Advisory
101
- in bridge mode — there, recover with 'yad gate ci' below
101
+ in verified mode — there, recover with 'yad gate ci' below
102
102
  yad gate comments <epic> [artifact] Fetch unresolved review comments to address
103
103
  yad gate status <epic> Show each review step + approvals
104
104
  yad gate repair <epic> [--push] Close an author step stranded behind a passed review gate
@@ -117,11 +117,11 @@ ${c.bold('Build helpers')}
117
117
  yad commit --type <t> -m <subject> Commit by convention (trailers, atomic guard)
118
118
  yad open-pr [--repo <name>] Open a task PR/MR against the repo's DEFAULT branch (never a
119
119
  hardcoded main; --base overrides) — stage-aware on the hub: a
120
- review/EP-* branch opens the front-half artifact-review PR
120
+ review/EP-* branch opens the Shape artifact-review PR
121
121
  (delegates to gate open), any other hub branch uses the
122
122
  code-task template
123
123
  yad ship --type <t> -m <subject> Commit AND open the task PR/MR in one step (stage-aware)
124
- yad checkpoint [--push] Commit the machine-written back-half hub state
124
+ yad checkpoint [--push] Commit the machine-written Build hub state
125
125
  (trust-log/build-log/build-state) — plus any story
126
126
  status: flip (→ in-build/shipped) backed by a build-log
127
127
  ship — as one audit-trail chore(hub) commit; default
@@ -131,7 +131,7 @@ ${c.bold('Build helpers')}
131
131
  (merged before ledger tracking), then carry its status: shipped
132
132
  flip in the same commit (--merge-commit <sha>, --task <t> opt.);
133
133
  one repo per run — re-run per --repo for a multi-repo story
134
- yad tidy up [<epic>] [--push] Fold FINISHED back-half shards (a shipped story's
134
+ yad tidy up [<epic>] [--push] Fold FINISHED Build shards (a shipped story's
135
135
  trust-log/build-log entries) back into the single folded
136
136
  ledger, as one chore(hub) commit — the manual "pack it up"
137
137
  for the shard files; a no-op when nothing is foldable
@@ -320,9 +320,9 @@ async function main() {
320
320
  if (!epic) { log(c.red('usage: yad gate <open|sync|comments|status|repair|review|walkthrough|trailer|ci> <epic> [artifact]')); process.exitCode = 1; break; }
321
321
  // The epic id becomes a path segment under epics/ — reject anything but EP-<slug> outright.
322
322
  if (!isValidEpicId(epic)) { log(c.red(`invalid epic id: ${epic} (expected EP-<slug>, [a-z0-9-] only)`)); process.exitCode = 1; break; }
323
- // In bridge mode CI is the sole ledger writer: `open` only opens the PR, and local `sync` is
323
+ // In verified mode CI is the sole ledger writer: `open` only opens the PR, and local `sync` is
324
324
  // advisory (reads the platform, prints status, writes nothing). The artifact status flip is
325
- // CI's job at merge — never wired into the local gate. File-only mode keeps local writes.
325
+ // CI's job at merge — never wired into the local gate. Local mode keeps local writes.
326
326
  if (action === 'open') await gateOpen(o.dir, { epic, artifact });
327
327
  else if (action === 'sync') await gateSync(o.dir, { epic, artifact, today, number: o.pr, local: true });
328
328
  else if (action === 'comments') await gateComments(o.dir, { epic, artifact, today });
@@ -9,20 +9,20 @@ import { c, log, ok, info, readJSONStrict } from './lib.mjs';
9
9
  import { epicRoot, artifactBase, artifactFromBase, findReviewStep, DISCOVERY_FILES } from './epic-state.mjs';
10
10
  import { epicFiles } from './manifest.mjs';
11
11
 
12
- // The front-gate lifecycle this command manages. Forward-only: a status is only ever moved UP this
12
+ // The Shape gate lifecycle this command manages. Forward-only: a status is only ever moved UP this
13
13
  // ladder, so a re-run never regresses anything.
14
14
  const RANK = { draft: 0, 'in-review': 1, approved: 2 };
15
15
 
16
16
  // Values owned by other parts of the workflow — left untouched. `locked` is the contract surface;
17
- // `in-build` / `shipped` are set by the build half (engineer-review) per story; `ready-for-build`,
18
- // `done`, `blocked` are roll-ups/states we must not overwrite from the front-gate view.
17
+ // `in-build` / `shipped` are set by Build (engineer-review) per story; `ready-for-build`,
18
+ // `done`, `blocked` are roll-ups/states we must not overwrite from the Shape gate view.
19
19
  const PRESERVE = new Set(['locked', 'in-build', 'shipped', 'ready-for-build', 'done', 'blocked']);
20
20
 
21
21
  // The per-epic artifact files this command considers (bases). Story files are handled separately
22
22
  // because they live under stories/ and all map to the single stories / stories-review step pair.
23
23
  const ARTIFACT_FILES = ['analysis.md', 'epic.md', 'architecture.md', 'contract.md', 'ui-design.md', 'test-cases.md'];
24
24
 
25
- // The desired front-gate status for an artifact base, derived purely from state.json. Returns null
25
+ // The desired Shape gate status for an artifact base, derived purely from state.json. Returns null
26
26
  // when the chain has no steps for this base (nothing to manage) — e.g. contract has no own step.
27
27
  export function desiredStatus(state, base) {
28
28
  if (!state?.steps) return null;
@@ -1,19 +1,19 @@
1
- // `yad checkpoint` — commit the machine-written back-half hub state (trust-log / build-log /
2
- // build-state) as one audit-trail commit. This is the back-half analogue of the front-half gate sync
3
- // (cli/gate.mjs): the SDLC back half (yad-run, yad-engineer-review) WRITES these ledgers into the
1
+ // `yad checkpoint` — commit the machine-written Build hub state (trust-log / build-log /
2
+ // build-state) as one audit-trail commit. This is the Build analogue of the Shape gate sync
3
+ // (cli/gate.mjs): the SDLC's Build part (yad-run, yad-engineer-review) WRITES these ledgers into the
4
4
  // working tree but never commits them, so teammates/CI/`yad status` on other machines see stale trust
5
5
  // evidence. checkpoint lands them with a `chore(hub): ...` message.
6
6
  //
7
- // It also carries the back-half story `status:` flip (approved → in-build/shipped) that
7
+ // It also carries the Build story `status:` flip (approved → in-build/shipped) that
8
8
  // yad-engineer-review writes into stories/<id>.md but no command committed — the #112 drift where
9
9
  // build-log said shipped while the story artifact still said approved. Only story files with build-log
10
10
  // ship evidence are carried (storyStatusPathspecs), AND only when their staged change is the `status:`
11
- // line alone (stagedStoryIsStatusOnly) — so it stays a back-half record, never a raw edit that would
11
+ // line alone (stagedStoryIsStatusOnly) — so it stays a Build record, never a raw edit that would
12
12
  // slip prose onto the default branch under a `[skip ci]` commit that bypasses review.
13
13
  //
14
14
  // Two invariants keep it out of the gates' way:
15
- // 1. It stages ONLY the back-half ledgers + build-log-backed story flips by an explicit allowlist —
16
- // never `git add -A`, which would sweep the CI-owned front-half ledger (state/approvals/
15
+ // 1. It stages ONLY the Build ledgers + build-log-backed story flips by an explicit allowlist —
16
+ // never `git add -A`, which would sweep the CI-owned Shape ledger (state/approvals/
17
17
  // comments/hub-prs.json, reviews/*.md) and trip the ledger-guard gate. (ledger-guard does NOT
18
18
  // protect stories/*.md, and this commits to the default branch, never a PR range, so the carried
19
19
  // story flip is safe.)
@@ -30,7 +30,7 @@ import { hubGit, resolveDefaultBranch, guardDefaultBranch } from './hubcommit.mj
30
30
  import { readShips, writeRetroShip } from './ledger.mjs';
31
31
  import { readFrontmatter } from './epic-state.mjs';
32
32
 
33
- // The machine-written back-half ledgers, relative to an epic's dir. The two append-only logs are
33
+ // The machine-written Build ledgers, relative to an epic's dir. The two append-only logs are
34
34
  // shard-then-fold (cli/ledger.mjs): each is a folded file PLUS a shard dir of loose per-entry files —
35
35
  // both are allowlisted so a checkpoint commits new shards and any `yad tidy up` fold. `build-state` is
36
36
  // the whole dir (one JSON per story). Keep in sync with cli/manifest.mjs epicFiles.
@@ -40,9 +40,9 @@ const BACK_HALF = [
40
40
  '.sdlc/build-state',
41
41
  ];
42
42
 
43
- // PURE — the repo-relative pathspecs to stage: every back-half ledger that exists under any epic.
43
+ // PURE — the repo-relative pathspecs to stage: every Build ledger that exists under any epic.
44
44
  // Explicit allowlist by design (see invariant 1 above).
45
- export function backHalfPathspecs(root) {
45
+ export function buildLedgerPathspecs(root) {
46
46
  const epicsDir = path.join(root, 'epics');
47
47
  if (!fs.existsSync(epicsDir)) return [];
48
48
  const out = [];
@@ -55,17 +55,17 @@ export function backHalfPathspecs(root) {
55
55
  return out;
56
56
  }
57
57
 
58
- // The two back-half story statuses. `in-build` = some of a story's tasks shipped; `shipped` = all did.
59
- // Both are set ONLY by the build half (yad-engineer-review), never by the front-gate ladder
58
+ // The two Build story statuses. `in-build` = some of a story's tasks shipped; `shipped` = all did.
59
+ // Both are set ONLY by Build (yad-engineer-review), never by the Shape gate ladder
60
60
  // (cli/artifact-status.mjs PRESERVEs them). See #112.
61
61
  const BACK_HALF_STATUSES = new Set(['in-build', 'shipped']);
62
62
 
63
- // The repo-relative pathspecs for story files whose back-half `status:` flip we carry alongside the
63
+ // The repo-relative pathspecs for story files whose Build `status:` flip we carry alongside the
64
64
  // ledgers (#112). The flip is authored by yad-engineer-review into the working tree but no command
65
65
  // committed it, so it drifted (build-log said shipped, stories/<id>.md still said approved) and the
66
66
  // only recovery was a raw git-to-main push. A story is a CANDIDATE iff BOTH hold:
67
- // 1. it has >=1 ship recorded in build-log (the build-half evidence), and
68
- // 2. its current frontmatter `status:` is a back-half value (in-build | shipped).
67
+ // 1. it has >=1 ship recorded in build-log (the Build evidence), and
68
+ // 2. its current frontmatter `status:` is a Build value (in-build | shipped).
69
69
  // A candidate is only actually carried when its staged diff is the `status:` line ALONE — runCheckpoint
70
70
  // drops any candidate whose working tree also changed prose/other frontmatter (stagedStoryIsStatusOnly),
71
71
  // so an unrelated edit can never ride into a `chore(hub) … [skip ci]` commit that bypasses review.
@@ -74,7 +74,7 @@ const BACK_HALF_STATUSES = new Set(['in-build', 'shipped']);
74
74
  //
75
75
  // A corrupt build-log in one epic must not block checkpointing every OTHER epic's ledgers, so a
76
76
  // readShips throw is caught per epic (that epic simply carries no story flip; its corrupt ledger is
77
- // still staged by backHalfPathspecs for a human to see).
77
+ // still staged by buildLedgerPathspecs for a human to see).
78
78
  export function storyStatusPathspecs(root) {
79
79
  const epicsDir = path.join(root, 'epics');
80
80
  if (!fs.existsSync(epicsDir)) return [];
@@ -107,7 +107,7 @@ export function summarizeStaged(files = []) {
107
107
  const epics = new Set();
108
108
  const basenames = [];
109
109
  for (const f of files) {
110
- // A back-half ledger (…/.sdlc/…) or a carried story-status flip (…/stories/<id>.md, #112).
110
+ // A Build ledger (…/.sdlc/…) or a carried story-status flip (…/stories/<id>.md, #112).
111
111
  const m = f.match(/^epics\/([^/]+)\/(?:\.sdlc\/(.+)|stories\/(.+\.md))$/);
112
112
  if (!m) continue;
113
113
  const [, epic] = m;
@@ -143,7 +143,7 @@ export function checkpointAuthor(login, name) {
143
143
  // Co-Authored-By footer: this is human-owned machine state, not an authored code change. `label` and
144
144
  // `author` are collapsed to one line so nothing can split the subject or forge a trailer.
145
145
  export function buildCheckpointMessage({ label, author, basenames = [] }) {
146
- const subject = `chore(hub): sync back-half state — ${oneLine(label)} by ${oneLine(author)} [skip ci]`;
146
+ const subject = `chore(hub): sync Build state — ${oneLine(label)} by ${oneLine(author)} [skip ci]`;
147
147
  const body = basenames.length ? `Updated: ${basenames.join(', ')}` : '';
148
148
  return body ? `${subject}\n\n${body}` : subject;
149
149
  }
@@ -170,7 +170,7 @@ export function stagedStoryIsStatusOnly(git, file) {
170
170
  // normal checkpoint path carries the story's already-made `status:` flip. Returns { ok, file } — ok:false
171
171
  // (with a printed reason) aborts the commit; `file` is the shard just written, so a dry run can delete it
172
172
  // and leave no side effect. Does NOT author the story frontmatter — it only supplies the missing
173
- // evidence, and the human must have ALREADY flipped `status:` to a back-half value in the working tree.
173
+ // evidence, and the human must have ALREADY flipped `status:` to a Build value in the working tree.
174
174
  //
175
175
  // ONE repo per run (#166). A story that shipped in several repos is backfilled by re-running with each
176
176
  // `--repo`; the second run finds the flip already committed, so it lands only the new ship shard.
@@ -201,7 +201,7 @@ export function recordRetroShip(root, { epic, story, repo, task, mergeCommit, to
201
201
  if (!exists(storyFile)) { fail(`no story ${story} under epics/${epic}/stories/`); return { ok: false }; }
202
202
 
203
203
  // Evidence and the flip must land TOGETHER — the #112 no-drift invariant. Refuse unless the human has
204
- // already flipped the story frontmatter to a back-half status in the working tree; otherwise the ship
204
+ // already flipped the story frontmatter to a Build status in the working tree; otherwise the ship
205
205
  // shard would commit while the artifact still says e.g. `approved` — the very drift #112 prevents.
206
206
  const storyStatus = readFrontmatter(storyFile).status;
207
207
  if (!BACK_HALF_STATUSES.has(storyStatus)) {
@@ -290,7 +290,7 @@ export async function runCheckpoint(root, opts = {}) {
290
290
  log(c.bold('\nyad checkpoint'));
291
291
  if (!exists(path.join(root, '.git'))) { fail('not a git repo'); process.exitCode = 1; return; }
292
292
  if (!exists(path.join(root, PROJECT_FILES.hubConfig))) {
293
- fail('no .sdlc/hub.json — checkpoint commits the hub back-half ledger; run it from the product hub');
293
+ fail('no .sdlc/hub.json — checkpoint commits the hub Build ledger; run it from the product hub');
294
294
  process.exitCode = 1;
295
295
  return;
296
296
  }
@@ -304,7 +304,7 @@ export async function runCheckpoint(root, opts = {}) {
304
304
  if (!guardDefaultBranch(branch, defaultBranch, { allowBranch: opts.allowBranch, cmd: 'yad checkpoint' })) return;
305
305
 
306
306
  // --retro-ship (#142): record a retroactive build-log ship for a PRE-TRACKING story (merged before
307
- // the back-half ledger existed, so it has no ship and its `status:` flip can't be carried). Done
307
+ // the Build ledger existed, so it has no ship and its `status:` flip can't be carried). Done
308
308
  // AFTER the branch guard so we never leave a dangling shard on the wrong branch; the flip the human
309
309
  // already wrote is then carried by the normal storyStatusPathspecs path below — no raw git needed.
310
310
  let retroFile;
@@ -324,8 +324,8 @@ export async function runCheckpoint(root, opts = {}) {
324
324
 
325
325
  // The machine ledgers PLUS any build-log-backed story `status:` flip (#112) — one commit records
326
326
  // both, so the story artifact never drifts from build-log and no raw git-to-main push is needed.
327
- const pathspecs = [...backHalfPathspecs(root), ...storyStatusPathspecs(root)];
328
- if (!pathspecs.length) { rollbackRetro(); info('no back-half ledgers found — nothing to checkpoint'); return; }
327
+ const pathspecs = [...buildLedgerPathspecs(root), ...storyStatusPathspecs(root)];
328
+ if (!pathspecs.length) { rollbackRetro(); info('no Build ledgers found — nothing to checkpoint'); return; }
329
329
 
330
330
  // Stage the allowlist. `git add -- <spec>` picks up new + modified files, and deletions of tracked
331
331
  // files WITHIN a still-present spec (e.g. a removed build-state/<story>.json). A wholesale-deleted
@@ -348,7 +348,7 @@ export async function runCheckpoint(root, opts = {}) {
348
348
 
349
349
  if (git('diff', '--cached', '--quiet', '--', ...pathspecs).ok) {
350
350
  rollbackRetro();
351
- info('back-half state unchanged — nothing to commit');
351
+ info('Build state unchanged — nothing to commit');
352
352
  return;
353
353
  }
354
354
  // The exact files staged from the allowlist — all known to git by construction, so they are the
package/cli/commit.mjs CHANGED
@@ -62,7 +62,7 @@ export async function runCommit(root, opts = {}) {
62
62
  const task = opts.task || taskFromBranch(branch);
63
63
  if (!task) {
64
64
  // spec-link is a code-repo gate (REPO_WIRING.common), not a hub gate — so a missing Task trailer
65
- // is expected on a hub PR (front-half artifact review or hub tooling) and only matters on a repo.
65
+ // is expected on a hub PR (Shape artifact review or hub tooling) and only matters on a repo.
66
66
  const onHub = exists(path.join(root, PROJECT_FILES.hubConfig));
67
67
  warn(onHub
68
68
  ? 'no Task trailer (none given and branch has no -S0N-T0N) — fine for a hub PR; required on code-repo tasks (spec-link gate)'
package/cli/companion.mjs CHANGED
@@ -1,5 +1,5 @@
1
- // cli/companion.mjs — pure, perspective-neutral helpers for the Review Companion, shared by the front
2
- // half (yad gate …) and the back half (yad review …). The CLI never calls an LLM — generation happens
1
+ // cli/companion.mjs — pure, perspective-neutral helpers for the Review Companion, shared by Shape
2
+ // (yad gate …) and Build (yad review …). The CLI never calls an LLM — generation happens
3
3
  // in the skill/harness layer (like yad-learn/yad-docs). This module owns the platform MARKERS, the
4
4
  // engagement parsing, the trailer-block upsert, and the message text the skill and the gate share.
5
5
  //
package/cli/doctor.mjs CHANGED
@@ -6,7 +6,7 @@
6
6
  import path from 'node:path';
7
7
  import fs from 'node:fs';
8
8
  import { c, log, ok, info, warn, fail, hand, run, has, exists, readJSON, readJSONStrict } from './lib.mjs';
9
- import { VERSION, PROJECT_FILES, DESIGN_TOOLS, TESTING_TOOLS, LEARNING_TOOLS, HOOK_SETTINGS, HOOK_TOOL_MATCHER, isBridgeHub } from './manifest.mjs';
9
+ import { VERSION, PROJECT_FILES, DESIGN_TOOLS, TESTING_TOOLS, LEARNING_TOOLS, HOOK_SETTINGS, HOOK_TOOL_MATCHER, isVerifiedLedger } from './manifest.mjs';
10
10
  import { mergeHookSettings, hookMatcherFires, ideTargetsFor } from './plan.mjs';
11
11
  import { planMigration } from './migrate.mjs';
12
12
  import { loadLedger, epicRoot, isValidEpicId, epicLineage, resolveThread, stateInvariants, contractSurfaceHash, artifactHash } from './epic-state.mjs';
@@ -67,7 +67,7 @@ export function projectChecks(checks, root) {
67
67
  // version stamp
68
68
  const ver = readJSON(verPath, null);
69
69
  if (!ver) check(checks, 'cli-version', 'project', 'warn', `${PROJECT_FILES.version} missing or unreadable`, 'run `yad check --fix`');
70
- // The stamp is not only cosmetic: in bridge mode the wired gate-sync job resolves the yadflow it
70
+ // The stamp is not only cosmetic: in verified mode the wired gate-sync job resolves the yadflow it
71
71
  // RUNS from it — unless hub.json pins `gate_sync_version`, a YAD_VERSION variable overrides, or the
72
72
  // stamp is not an exact release of the current major (then the job skips it and floats). So a stale
73
73
  // stamp can mean CI is running an old gate; say so, or the warning reads as bookkeeping.
@@ -77,7 +77,7 @@ export function projectChecks(checks, root) {
77
77
  // hub.json: parse + shape
78
78
  let hub = null;
79
79
  if (!exists(hubPath)) {
80
- check(checks, 'hub', 'project', 'warn', `${PROJECT_FILES.hubConfig} absent — file-only gate`, 'run `yad setup` to configure a platform + roster');
80
+ check(checks, 'hub', 'project', 'warn', `${PROJECT_FILES.hubConfig} absent — local gate`, 'run `yad setup` to configure a platform + roster');
81
81
  } else {
82
82
  let hubBroken = false;
83
83
  try {
@@ -92,13 +92,13 @@ export function projectChecks(checks, root) {
92
92
  // Mirror gate.mjs's roster shape check so doctor never reports "ok" on a hub the gate would reject.
93
93
  else if (hub.roster !== undefined && !Array.isArray(hub.roster)) check(checks, 'hub', 'project', 'fail', `${PROJECT_FILES.hubConfig}: \`roster\` must be an array [YAD-STATE-002]`, 'fix the file or re-run `yad setup`');
94
94
  else {
95
- check(checks, 'hub', 'project', 'ok', `hub: ${hub.platform || 'file-only'}, ${(hub.roster || []).length} reviewer(s)`);
95
+ check(checks, 'hub', 'project', 'ok', `hub: ${hub.platform || 'local'}, ${(hub.roster || []).length} reviewer(s)`);
96
96
  if (isSolo(hub)) check(checks, 'solo', 'project', 'ok', 'mode: solo — approval waived; the PR merge + resolved threads gate the step');
97
97
  // platform CLI + auth (best-effort; auth probing is the user's own session)
98
98
  const cli = cliFor(hub.platform);
99
99
  if (cli) {
100
100
  // git_url is required whenever a platform is set — doctor needs it to scope the auth probe
101
- // and the bridge/PR flow needs it to open PRs. Warn on its absence directly (not on the
101
+ // and the verified ledger/PR flow needs it to open PRs. Warn on its absence directly (not on the
102
102
  // resolved host), so it fires even when an origin remote can substitute: the field itself
103
103
  // is required regardless.
104
104
  if (!hostFromGitUrl(hub.git_url)) {
@@ -113,7 +113,7 @@ export function projectChecks(checks, root) {
113
113
  // rather than run the flaky unscoped form.
114
114
  const host = hostFromGitUrl(hub.git_url)
115
115
  || hostFromGitUrl(run('git', ['remote', 'get-url', 'origin'], { cwd: root }).stdout);
116
- if (!has(cli)) check(checks, 'platform-cli', 'project', 'warn', `${cli} not found on PATH [YAD-ENV-002]`, `install ${cli} — the gate degrades to file-only without it`);
116
+ if (!has(cli)) check(checks, 'platform-cli', 'project', 'warn', `${cli} not found on PATH [YAD-ENV-002]`, `install ${cli} — the gate degrades to local without it`);
117
117
  else if (!host) check(checks, 'platform-cli', 'project', 'warn', 'auth check skipped — hub host unknown (no git_url / origin)', 'add git_url to hub.json so the auth probe can target the right host');
118
118
  else if (!run(cli, ['auth', 'status', '--hostname', host]).ok) check(checks, 'platform-cli', 'project', 'warn', `${cli} present but not authenticated for ${host} [YAD-ENV-002]`, `run \`${cli} auth login --hostname ${host}\``);
119
119
  else {
@@ -155,12 +155,12 @@ export function projectChecks(checks, root) {
155
155
  }
156
156
  }
157
157
 
158
- // The harness ledger guard (#171). Only meaningful in bridge mode: there the ledger is CI-owned and
158
+ // The harness ledger guard (#171). Only meaningful in verified mode: there the ledger is CI-owned and
159
159
  // an agent's hand-edit is always rejected later by `ledger-guard`, so the local hook that refuses it
160
- // up front should be installed. Without the bridge the ledger is locally owned and the hand-edit the
160
+ // up front should be installed. With a local ledger nothing guards it, and the hand-edit the
161
161
  // authoring skills describe is correct — nothing to report, so the check is silent rather than `ok`.
162
162
  const hubForHooks = readJSON(hubPath, null);
163
- if (isBridgeHub(hubForHooks)) {
163
+ if (isVerifiedLedger(hubForHooks)) {
164
164
  const unwired = [];
165
165
  const broken = [];
166
166
  if (!exists(path.join(root, 'hooks', 'ledger-guard.sh'))) unwired.push('hooks/ledger-guard.sh');
@@ -322,7 +322,7 @@ export function ciTagsChecks(checks, root, hub, registry) {
322
322
  } catch { return false; } // absent fragment is not this check's concern
323
323
  };
324
324
  const fragments = [];
325
- if (hub?.platform === 'gitlab' && (hub.bridge_enabled === true || hub.bridge === true)) {
325
+ if (hub?.platform === 'gitlab' && isVerifiedLedger(hub)) {
326
326
  fragments.push(
327
327
  { scope: 'hub', file: '.gitlab/ci/yad-gate-sync.yml', path: path.join(root, '.gitlab/ci/yad-gate-sync.yml') },
328
328
  { scope: 'hub', file: '.gitlab/ci/yad-verified-commits.yml', path: path.join(root, '.gitlab/ci/yad-verified-commits.yml') },