yadflow 3.18.1 → 4.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +355 -0
- package/README.md +79 -26
- package/bin/commands.mjs +41 -0
- package/bin/yad.mjs +437 -124
- package/cli/artifact-status.mjs +34 -15
- package/cli/checkpoint.mjs +69 -49
- package/cli/codeowners-command.mjs +170 -0
- package/cli/codeowners.mjs +397 -0
- package/cli/commit.mjs +13 -9
- package/cli/companion.mjs +2 -2
- package/cli/dial.mjs +183 -0
- package/cli/docs.mjs +88 -32
- package/cli/doctor.mjs +1472 -97
- package/cli/epic-state.mjs +3478 -232
- package/cli/epic.mjs +506 -0
- package/cli/errors.mjs +4 -1
- package/cli/gate.mjs +1002 -209
- package/cli/history.mjs +556 -0
- package/cli/hook.mjs +266 -55
- package/cli/hubcommit.mjs +6 -17
- package/cli/index-command.mjs +87 -0
- package/cli/ledger.mjs +57 -7
- package/cli/lib.mjs +184 -18
- package/cli/manifest.mjs +367 -56
- package/cli/migrate.mjs +726 -53
- package/cli/mode.mjs +170 -0
- package/cli/next.mjs +349 -90
- package/cli/openpr.mjs +191 -39
- package/cli/people.mjs +654 -0
- package/cli/plan.mjs +417 -132
- package/cli/platform.mjs +110 -129
- package/cli/product-index.mjs +287 -0
- package/cli/protection.mjs +706 -0
- package/cli/reconcile.mjs +38 -12
- package/cli/repo-publish.mjs +24 -26
- package/cli/repo.mjs +23 -14
- package/cli/report.mjs +21 -15
- package/cli/review.mjs +24 -27
- package/cli/riskmap-command.mjs +289 -0
- package/cli/riskmap.mjs +373 -0
- package/cli/setup.mjs +139 -287
- package/cli/ship.mjs +7 -6
- package/cli/skill.mjs +180 -0
- package/cli/skip.mjs +211 -30
- package/cli/thread.mjs +42 -17
- package/cli/tidy.mjs +20 -20
- package/cli/update-commit.mjs +22 -22
- package/cli/usage.mjs +115 -109
- package/package.json +3 -3
- package/skills/sdlc/config.yaml +166 -87
- package/skills/sdlc/module-help.csv +35 -35
- package/skills/yad-analysis/SKILL.md +125 -65
- package/skills/yad-architecture/SKILL.md +34 -23
- package/skills/yad-architecture/references/contract-format.md +10 -8
- package/skills/yad-backfill/SKILL.md +14 -8
- package/skills/yad-backfill/references/backfill.md +1 -1
- package/skills/yad-change/SKILL.md +127 -52
- package/skills/yad-change/references/triage.md +42 -28
- package/skills/yad-checks/SKILL.md +89 -45
- package/skills/yad-checks/references/check-gates.md +315 -92
- package/skills/yad-checks/templates/checks/build-test-lint.sh +25 -7
- package/skills/yad-checks/templates/checks/commit-message.sh +17 -3
- package/skills/yad-checks/templates/checks/contract-check.sh +58 -2
- package/skills/yad-checks/templates/checks/epic-open.sh +3 -3
- package/skills/yad-checks/templates/checks/install-deps.sh +46 -0
- package/skills/yad-checks/templates/checks/ledger-guard.sh +94 -18
- package/skills/yad-checks/templates/checks/lineage-check.sh +23 -9
- package/skills/yad-checks/templates/checks/package-manager.sh +140 -0
- package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +4 -4
- package/skills/yad-checks/templates/checks/risk-map-check.sh +438 -0
- package/skills/yad-checks/templates/checks/verified-commits.sh +20 -46
- package/skills/yad-checks/templates/github/yad-checks.yml +37 -5
- package/skills/yad-checks/templates/github/yad-hub-checks.yml +5 -5
- package/skills/yad-checks/templates/github/yad-update-guard.yml +3 -4
- package/skills/yad-checks/templates/github/yad-verified-commits.yml +4 -4
- package/skills/yad-checks/templates/gitlab/.gitlab-ci.yml +7 -1
- package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +22 -4
- package/skills/yad-checks/templates/gitlab/yad-hub-checks.gitlab-ci.yml +5 -5
- package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +4 -4
- package/skills/yad-checks/templates/hooks/ledger-guard-cursor.sh +91 -0
- package/skills/yad-checks/templates/hooks/ledger-guard.sh +38 -7
- package/skills/yad-commit/SKILL.md +6 -6
- package/skills/yad-connect-design/SKILL.md +6 -6
- package/skills/yad-connect-design/references/design-context.md +1 -1
- package/skills/yad-connect-design/references/design-registry.md +2 -2
- package/skills/yad-connect-docs/SKILL.md +12 -12
- package/skills/yad-connect-docs/references/docs-registry.md +1 -1
- package/skills/yad-connect-learning/SKILL.md +5 -5
- package/skills/yad-connect-learning/references/learning-registry.md +2 -2
- package/skills/yad-connect-repos/SKILL.md +92 -54
- package/skills/yad-connect-repos/references/code-context.md +6 -6
- package/skills/yad-connect-repos/references/hub-config.md +68 -58
- package/skills/yad-connect-repos/references/repos-registry.md +10 -9
- package/skills/yad-connect-repos/references/risk-map.md +81 -0
- package/skills/yad-connect-testing/SKILL.md +6 -6
- package/skills/yad-connect-testing/references/testing-context.md +3 -4
- package/skills/yad-connect-testing/references/testing-registry.md +2 -2
- package/skills/yad-defects/SKILL.md +8 -8
- package/skills/yad-discovery/SKILL.md +130 -94
- package/skills/yad-discovery/references/discovery-schema.md +23 -7
- package/skills/yad-discovery/references/foundation-schema.md +374 -0
- package/skills/yad-docs/SKILL.md +16 -11
- package/skills/yad-docs/references/data-mapping.md +9 -7
- package/skills/yad-docs/templates/app/package-lock.json +3 -3
- package/skills/yad-docs-overview/SKILL.md +32 -17
- package/skills/yad-docs-overview/references/pipeline-model.md +47 -28
- package/skills/yad-docs-sync/SKILL.md +10 -5
- package/skills/yad-docs-sync/references/staleness.md +8 -7
- package/skills/yad-engineer-review/SKILL.md +88 -24
- package/skills/yad-engineer-review/references/ship-and-record.md +25 -16
- package/skills/yad-epic/SKILL.md +178 -100
- package/skills/yad-epic/references/state-schema.md +626 -117
- package/skills/yad-hub-bridge/SKILL.md +66 -48
- package/skills/yad-hub-bridge/references/bridge.md +110 -83
- package/skills/yad-hub-bridge/references/login-roster.md +163 -70
- package/skills/yad-hub-bridge/templates/checks/hub-route.sh +22 -19
- package/skills/yad-hub-bridge/templates/github/yad-gate-sync.yml +34 -14
- package/skills/yad-hub-bridge/templates/gitlab/gitlab-ci.include-root.yml +2 -2
- package/skills/yad-hub-bridge/templates/gitlab/yad-gate-sync.gitlab-ci.yml +22 -12
- package/skills/yad-implement/SKILL.md +29 -15
- package/skills/yad-implement/references/implement-conventions.md +2 -2
- package/skills/yad-learn/SKILL.md +9 -9
- package/skills/yad-learn/references/learning-state.md +2 -2
- package/skills/yad-open-pr/SKILL.md +64 -29
- package/skills/yad-pair-review/SKILL.md +18 -16
- package/skills/yad-pair-review/references/session-state.md +4 -4
- package/skills/yad-pr-template/SKILL.md +48 -27
- package/skills/yad-pr-template/references/risk-routing.md +97 -24
- package/skills/yad-pr-template/templates/checks/pr-template.sh +37 -15
- package/skills/yad-pr-template/templates/checks/pr-title.sh +27 -13
- package/skills/yad-pr-template/templates/checks/risk-route.sh +107 -14
- package/skills/yad-pr-template/templates/github/pull_request_template.md +7 -5
- package/skills/yad-pr-template/templates/gitlab/merge_request_templates/Default.md +7 -5
- package/skills/yad-pr-template/templates/hub/github/pull_request_template.md +15 -14
- package/skills/yad-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +15 -13
- package/skills/yad-reconcile/SKILL.md +3 -3
- package/skills/yad-report/SKILL.md +5 -5
- package/skills/yad-review-companion/SKILL.md +12 -9
- package/skills/yad-review-gate/SKILL.md +198 -79
- package/skills/yad-review-gate/references/gating.md +230 -54
- package/skills/yad-run/SKILL.md +86 -56
- package/skills/yad-run/references/run-loop.md +67 -45
- package/skills/yad-ship/SKILL.md +18 -14
- package/skills/yad-spec/SKILL.md +31 -17
- package/skills/yad-spec/references/spec-handoff.md +17 -5
- package/skills/yad-status/SKILL.md +114 -56
- package/skills/yad-stories/SKILL.md +42 -27
- package/skills/yad-stories/references/story-schema.md +10 -9
- package/skills/yad-stub/SKILL.md +59 -48
- package/skills/yad-sync-repos/SKILL.md +3 -3
- package/skills/yad-test-cases/SKILL.md +37 -30
- package/skills/yad-test-cases/references/test-cases-schema.md +8 -5
- package/skills/yad-timeline/SKILL.md +8 -7
- package/skills/yad-ui/SKILL.md +46 -25
- package/cli/roster.mjs +0 -164
- package/skills/sdlc/install.sh +0 -68
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yad-review-gate
|
|
3
|
-
description: 'The reusable team review + approve gate for the SDLC. Shares an authored artifact for review, records reviewer comments and approvals as files, enforces the
|
|
3
|
+
description: 'The reusable team review + approve gate for the SDLC. Shares an authored artifact for review, records reviewer comments and approvals as files, enforces the approver count (1 distinct approver; contract/auth/payments raise the full count, advisory), and advances the epic state ONLY when approval is recorded. Use when the user says "review the analysis/epic/architecture/UI/stories/test-cases", "comment", "approve", or "advance the gate".'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# SDLC — Team Review Gate (build plan §3 piece 2, §4, §5)
|
|
@@ -8,18 +8,20 @@ description: 'The reusable team review + approve gate for the SDLC. Shares an au
|
|
|
8
8
|
**Goal:** One reusable step type that turns any authored artifact into a gated, human-approved
|
|
9
9
|
review. Every `review+approve` step in the workflow (the optional analysis, epic, architecture+contract,
|
|
10
10
|
UI, stories, test-cases) uses this exact gate. **No step advances until its review is approved** and
|
|
11
|
-
recorded as a file.
|
|
12
|
-
|
|
11
|
+
recorded as a file. Every review uses the same **count** rule: distinct approvers, base 1. A step's
|
|
12
|
+
`risk_tags` raise the full count. The engine caps that count at the number of active people less one
|
|
13
|
+
and shows it (E72), but only the base holds the gate; the risk step is advisory.
|
|
13
14
|
|
|
14
|
-
This gate is **swappable and file-driven**: it talks only through files. A
|
|
15
|
-
human act — recording an approval and `advance`, or (with
|
|
15
|
+
This gate is **swappable and file-driven**: it talks only through files. A Shape step advances only on a
|
|
16
|
+
human act — recording an approval and `advance`, or (with a verified ledger) **merging the approved,
|
|
16
17
|
fully-resolved review PR/MR**. It works the same whether a human or the `yad gate` CLI triggers it — the
|
|
17
18
|
trigger is a parameter, not a hardcoded human.
|
|
18
19
|
|
|
19
20
|
## Conventions
|
|
20
21
|
- `{project-root}` resolves from the project working directory.
|
|
21
|
-
- Operate on one epic: `{project-root}/epics/EP-<slug>/`.
|
|
22
|
-
-
|
|
22
|
+
- Operate on one epic: `{project-root}/epics/EP-<slug>/`. The Product level is the exception:
|
|
23
|
+
`EP-foundation` lives at `{project-root}/foundation/` (its `.sdlc/` and `reviews/` are there).
|
|
24
|
+
- State files: `.sdlc/state.json`, `.sdlc/approvals.json`, `.sdlc/comments.json`, and (when the verified ledger is
|
|
23
25
|
used) `.sdlc/hub-prs.json`. Review records: `reviews/`.
|
|
24
26
|
- The artifact base name drops the extension (`epic.md` → `epic`; story `stories/...S01.md` → `stories-S01`).
|
|
25
27
|
|
|
@@ -27,8 +29,8 @@ trigger is a parameter, not a hardcoded human.
|
|
|
27
29
|
- `epic`: the `EP-<slug>` to operate on.
|
|
28
30
|
- `artifact`: the file under the epic being reviewed (e.g. `epic.md`).
|
|
29
31
|
- `action`: one of `open` | `comment` | `approve` | `sync` | `advance` (default: `open`).
|
|
30
|
-
- For `comment` / `approve`: the reviewer
|
|
31
|
-
|
|
32
|
+
- For `comment` / `approve`: the reviewer's platform login (or the name they give, when there is no
|
|
33
|
+
platform). No role and no domain. Ask if not provided.
|
|
32
34
|
- `sync` needs no reviewer input — it reads the platform PR/MR review state (via `yad-hub-bridge`).
|
|
33
35
|
|
|
34
36
|
## On Activation
|
|
@@ -36,46 +38,94 @@ trigger is a parameter, not a hardcoded human.
|
|
|
36
38
|
### Step 1 — Load state
|
|
37
39
|
Read `.sdlc/state.json`. Find the `review+approve` step whose `artifact` matches the input (or the
|
|
38
40
|
step named `currentStep` if it is a review step). Read `.sdlc/approvals.json`. Read `epic.md` for the
|
|
39
|
-
epic's `repos` (the **touched domains**). Determine the **
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
epic's `repos` (the **touched domains**). Determine the **count** for this step. It counts people, not
|
|
42
|
+
roles — there are no roles, and yadflow keeps no list of people:
|
|
43
|
+
- **Base (enforced):** at least **1 distinct approver**, who should not be the author. The engine does
|
|
44
|
+
not check that: GitHub stops you approving your own PR, GitLab does only when the project's approval
|
|
45
|
+
settings say so, and on a local ledger nothing does — so do not record the author's own approval.
|
|
46
|
+
- **Full count, capped and reported (E72):** `needed = base 1 + risk step`. The risk step comes from the
|
|
47
|
+
step's `risk_tags`: `contract` +2, `auth`/`payments` +1 (the "high" tier). Take the highest tag, never
|
|
48
|
+
the sum. The engine then **caps** that ask at `active − 1`, with a floor of 1. `active` is the live
|
|
49
|
+
count of people who committed or approved lately (E71). Example: a contract gate asks 3; with 2 active
|
|
50
|
+
people the capped ask is 1, with 3 it is 2, with 4 or more all 3. The `− 1` is one seat left for the
|
|
51
|
+
author — a seat, not a check: the platform decides whether the author may approve.
|
|
52
|
+
- **The risk step is ADVISORY, capped or not.** Report the shortfall against the capped ask
|
|
53
|
+
(`short`); never block on it. Why: the count of people errs high in the normal case. A commit is
|
|
54
|
+
counted by its git name, an approval by its platform login, and yadflow never joins the two without
|
|
55
|
+
exact evidence — so a two-person team can read as four. At four the cap lowers nothing, and an enforced
|
|
56
|
+
contract gate would ask three approvals of a team with one person who is not the author. A later yadflow
|
|
57
|
+
change turns the capped count on together with `yad gate lower --reason`, the way out, once the count
|
|
58
|
+
is accurate.
|
|
59
|
+
- **Relay a warning line.** Under a team gate that has not passed, `yad gate status` and `yad gate sync`
|
|
60
|
+
print `! may not be met: …` (today's one required approval may have nobody but the author to give
|
|
61
|
+
it) or `! if the risk step were enforced: …` (a what-if about the extra approvals) when the count of
|
|
62
|
+
people suggests the gate may not pass (E73). Never block on it and never write it into the ledger. Tell the
|
|
63
|
+
reviewers while the review is open, because a merged review PR can no longer take approvals.
|
|
64
|
+
In solo mode, `yad gate status` prints `! solo mode is on, but …` instead when the count shows more than
|
|
65
|
+
one person may work on the Product (E74). Relay it as a suggestion to run `yad mode team`; never switch
|
|
66
|
+
the mode yourself, and never read it as a fault.
|
|
67
|
+
- **When the people cannot be counted** (`active: null` — for example Product CI, which checks out only
|
|
68
|
+
the hub, so the connected repos are not on disk): **no cap is computed or shown**, and the base holds as
|
|
69
|
+
always. `yad gate status` and `yad gate sync` print the arithmetic — read it from there rather than
|
|
70
|
+
recomputing it.
|
|
71
|
+
- **Touched domains** only name and label the review; they add no approvals. For a step with a risk
|
|
72
|
+
tag (the **architecture+contract** review) they are the epic's `repos`. For the **stories** review they
|
|
73
|
+
are the **union of every story's `repos`** under `stories/`. `stories-review` is an ordinary count gate.
|
|
74
|
+
|
|
75
|
+
This is **one gate** for every step — never a forked or copied gate. The tags change the full count
|
|
76
|
+
and nothing else.
|
|
54
77
|
|
|
55
78
|
### Step 2 — Dispatch on `action`
|
|
56
79
|
|
|
57
|
-
> **Check the mode first — in
|
|
58
|
-
> **
|
|
80
|
+
> **Check the mode first — in verified mode you write nothing to the ledger.** Read `.sdlc/hub.json`:
|
|
81
|
+
> **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. Under the verified ledger
|
|
59
82
|
> the ledger is CI-owned — `ledger-guard` rejects any non-bot commit touching
|
|
60
|
-
> `epics/*/.sdlc/{state,approvals,comments,hub-prs}.json` or `epics/*/reviews/*.md
|
|
83
|
+
> `epics/*/.sdlc/{state,approvals,comments,product-prs,hub-prs}.json` or `epics/*/reviews/*.md` (and the
|
|
84
|
+
> same files under `foundation/`), local `yad gate
|
|
61
85
|
> sync` is advisory, and `yad gate ci --merged` writes the whole transition when the review PR merges.
|
|
62
|
-
> So every "set / append / write" instruction below is the **
|
|
63
|
-
> gate-sync CI** path. In
|
|
64
|
-
>
|
|
86
|
+
> So every "set / append / write" instruction below is the **local, or a platform with no
|
|
87
|
+
> gate-sync CI** path. In verified mode do the human-facing half — present the artifact, say how many
|
|
88
|
+
> approvers the step needs, help the owner address comments — and let the platform PR/MR carry the review
|
|
65
89
|
> state; the approvals, comments, review records and the advance all land through CI at merge.
|
|
66
90
|
|
|
67
|
-
**`open`** — Present the artifact for review. Summarise what changed,
|
|
68
|
-
the
|
|
69
|
-
|
|
91
|
+
**`open`** — Present the artifact for review. Summarise what changed, say how many approvers the step
|
|
92
|
+
needs (base, and the full count from its risk tags), and tell reviewers how to comment/approve. Then
|
|
93
|
+
make the transition with the engine:
|
|
70
94
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
95
|
+
```bash
|
|
96
|
+
yad gate open <epic> <artifact>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Do not hand-write this one.** It does three things, and the second is the one a transcription keeps
|
|
100
|
+
forgetting:
|
|
101
|
+
|
|
102
|
+
1. marks the review step `in_review`;
|
|
103
|
+
2. **closes the paired authoring step as `done`** — a gate cannot open on an unauthored artifact, and
|
|
104
|
+
an author step left `in_progress` behind a passed gate blocks every step after it
|
|
105
|
+
(`YAD-STATE-005`, issue #131) until someone runs `yad gate repair`;
|
|
106
|
+
3. moves `currentStep` to the gate — **except** when the epic is already `ready-for-build`, where it
|
|
107
|
+
leaves it alone, so opening the parallel `test-cases` gate never pulls the epic back from Build.
|
|
108
|
+
|
|
109
|
+
With **no platform** configured it writes the ledger and simply opens no PR, so this works offline.
|
|
110
|
+
With a platform, the `review/<epic>/<artifact>` branch must already be **on origin** — cut it from the
|
|
111
|
+
authoring branch and push it, or run `yad open-pr` from it, which pushes first and then delegates here.
|
|
112
|
+
In **verified mode** the command deliberately writes nothing: CI owns the ledger and performs the whole
|
|
113
|
+
transition at merge.
|
|
114
|
+
|
|
115
|
+
Do not advance.
|
|
116
|
+
|
|
117
|
+
If `.sdlc/hub.json` has a non-null `platform` and `gh`/`glab` is authenticated, **`yad gate open` also
|
|
118
|
+
opens the review PR/MR on the Product** (the recipe is `yad-hub-bridge action: open`; do not open a
|
|
119
|
+
second one), and you report the URL. This holds for a verified ledger and for a local one. The PR
|
|
120
|
+
requests **no reviewers**; the command prints
|
|
121
|
+
`no reviewers were requested — ask them on the PR itself`, so tell the author to ask people on the PR.
|
|
122
|
+
The PR is recorded in `epics/<epic>/.sdlc/hub-prs.json` (`{step, artifact, platform, number, url, branch, lastSyncedAt}`):
|
|
123
|
+
**by CI at merge** in verified mode (`ledger: "verified"`, or, before `yad migrate`, `bridge_enabled: true` /
|
|
124
|
+
legacy `bridge: true` — `.sdlc/hub.json` is the only source the CLI reads, see `isVerifiedLedger` in
|
|
125
|
+
`cli/manifest.mjs`), and by `yad gate open` itself on a local ledger. Never write it by hand (see `sync`
|
|
126
|
+
below). With no platform, or when the PR cannot be opened on a local ledger, the step is still
|
|
127
|
+
`in_review` locally — no error. (In verified mode a failed open writes nothing; open the PR by hand and
|
|
128
|
+
CI records the gate at merge.) Opening the PR records no approvals and never advances.
|
|
79
129
|
|
|
80
130
|
**`comment`** — Capture reviewer feedback. Append/create a review file
|
|
81
131
|
`reviews/<artifact-base>--<YYYY-MM-DD>--comments.md` with a heading per reviewer:
|
|
@@ -83,7 +133,7 @@ advances.
|
|
|
83
133
|
```markdown
|
|
84
134
|
# Review comments — <artifact> — <YYYY-MM-DD>
|
|
85
135
|
|
|
86
|
-
## <reviewer>
|
|
136
|
+
## <reviewer>
|
|
87
137
|
- <comment>
|
|
88
138
|
- <comment>
|
|
89
139
|
```
|
|
@@ -92,40 +142,43 @@ Also append a **machine-readable** participation record to `.sdlc/comments.json`
|
|
|
92
142
|
absent — the markdown stays the human-readable record, this makes commenter names queryable, the
|
|
93
143
|
counterpart to `approvals.json`):
|
|
94
144
|
```json
|
|
95
|
-
{ "artifact": "<artifact>", "step": "<step id>", "commenter": "<
|
|
145
|
+
{ "artifact": "<artifact>", "step": "<step id>", "commenter": "<platform login, or the name given with no platform>", "round": <n>, "count": <comments this round>, "date": "<YYYY-MM-DD>" }
|
|
96
146
|
```
|
|
147
|
+
Write no `role` or `domain`. Older records may carry them; nothing reads them.
|
|
97
148
|
`round` increments each comment→address cycle for the artifact; upsert by `(step, commenter, round)`.
|
|
98
149
|
|
|
99
150
|
Then help the **owner address the comments** using the agent lens listed for this step
|
|
100
151
|
(analysis → `analyst`; epic → `pm`; architecture → `architect`; ui-design → `ux-designer`;
|
|
101
|
-
stories → `pm`, with `architect` for technical detail
|
|
102
|
-
Deviation 1; test-cases → `test architect` / Murat, `bmad-tea`). Update the authored artifact in place.
|
|
152
|
+
stories → `pm`, with `architect` for technical detail; test-cases → `test architect`). Update the authored artifact in place.
|
|
103
153
|
Repeat comment→address rounds until reviewers are satisfied. **Commenting never advances the gate.**
|
|
104
154
|
|
|
105
155
|
**`approve`** — Record an approval. Append to `.sdlc/approvals.json`:
|
|
106
156
|
```json
|
|
107
|
-
{ "artifact": "<artifact>", "step": "<step id>", "approver": "<
|
|
157
|
+
{ "artifact": "<artifact>", "step": "<step id>", "approver": "<platform login, or the name given with no platform>", "status": "approved", "date": "<YYYY-MM-DD>", "engagement": "<verified|none>" }
|
|
108
158
|
```
|
|
159
|
+
One record per person. Write no `role` or `domain`. The approver must not be the artifact's author.
|
|
160
|
+
A hand-written approval has no platform evidence and no `artifactHash`, so an edit to the artifact does not
|
|
161
|
+
revoke it — after a real change, remove it and record it again once the reviewer has seen the new content.
|
|
109
162
|
`engagement` records whether the approval came through the [Review Companion](../yad-review-companion/SKILL.md)
|
|
110
163
|
(a real trailer/cards/chat session = `verified`) or as a bare click (`none`). It is soft by default
|
|
111
164
|
(both count; a bare approve draws a friendly nudge) and only gates when `hub.review.requireEngagement`
|
|
112
165
|
is on — see `references/gating.md`. The signal is gameable by design ("visible, not impossible").
|
|
113
|
-
Also write/refresh `reviews/<artifact-base>--<YYYY-MM-DD>--approved.md` as a **named
|
|
166
|
+
Also write/refresh `reviews/<artifact-base>--<YYYY-MM-DD>--approved.md` as a **named record** with three
|
|
114
167
|
sections, so every participant is attributable in one place:
|
|
115
168
|
|
|
116
169
|
```markdown
|
|
117
170
|
# Approval record — <artifact> — <YYYY-MM-DD>
|
|
118
171
|
|
|
119
|
-
|
|
172
|
+
Count: **<have> distinct approver(s)** — <the sum, e.g. `3 approvers = base 1 + contract risk 2`>; <the engine's suffix, e.g. `capped to 1: 2 active people, less one seat for the author — base enforced, risk step advisory`, or just `base enforced, risk step advisory` when no cap lowered the ask; nothing after the sum when the step has no risk tag>[, short <N> — recorded here, never blocking].
|
|
120
173
|
|
|
121
174
|
## Approved by
|
|
122
|
-
- <
|
|
175
|
+
- <approver> — approved <date>[ (<source>)]
|
|
123
176
|
|
|
124
177
|
## Reviewed / commented by (participation, from comments.json)
|
|
125
|
-
- <
|
|
178
|
+
- <commenter> — <n> comment(s) across <r> round(s)
|
|
126
179
|
|
|
127
180
|
## Still required to pass the gate
|
|
128
|
-
- <
|
|
181
|
+
- <"1 approval(s)", or "none">
|
|
129
182
|
|
|
130
183
|
Gate status: **<PASSED | BLOCKED>** — <reason>.
|
|
131
184
|
```
|
|
@@ -133,22 +186,31 @@ Gate status: **<PASSED | BLOCKED>** — <reason>.
|
|
|
133
186
|
Then **re-evaluate the rule** (Step 3). Recording an approval does NOT itself advance — advancement is
|
|
134
187
|
a separate, explicit check.
|
|
135
188
|
|
|
136
|
-
**`sync`** — (the platform bridge input path) Pull the
|
|
189
|
+
**`sync`** — (the platform bridge input path) Pull the Product review PR/MR's review state into the ledger,
|
|
137
190
|
then re-evaluate the rule (Step 3). Read the PR for this step from `.sdlc/hub-prs.json` and use
|
|
138
191
|
`yad-hub-bridge`'s read recipes (`../yad-hub-bridge/references/bridge.md`) to fetch reviews + comments
|
|
139
192
|
via the local user's `gh`/`glab`. For each:
|
|
140
|
-
-
|
|
141
|
-
|
|
142
|
-
an unmapped login is a plain `reviewer`, flagged, never promoted);
|
|
193
|
+
- the platform `login` is the name written — `approver` / `commenter` is the login itself. There is no
|
|
194
|
+
lookup and no role (see `../yad-hub-bridge/references/login-roster.md`);
|
|
143
195
|
- an `APPROVED` review / MR approval → append an `approved` record to `approvals.json` tagged
|
|
144
|
-
`"source": "bridge"`; a `
|
|
145
|
-
`reviews/<artifact-base>--<YYYY-MM-DD>--comments.md` + `comments.json` (never an approval).
|
|
146
|
-
|
|
196
|
+
`"source": "bridge"`; a `CHANGES_REQUESTED` review or an unresolved thread → write to
|
|
197
|
+
`reviews/<artifact-base>--<YYYY-MM-DD>--comments.md` + `comments.json` (never an approval). A resolved
|
|
198
|
+
thread, and a companion comment marked `<!-- yad:noblock -->`, is not written.
|
|
199
|
+
**Idempotent:** upsert bridge approvals by `(step, approver)` — one record per person. An older record
|
|
200
|
+
that still carries `role`/`domain` and names a person by their old roster name is recognised as
|
|
201
|
+
`../yad-hub-bridge/references/login-roster.md` → "Older records" describes, and replaced by one
|
|
202
|
+
login-named record that keeps its fingerprint. Every sync write (`yad gate sync`, `yad gate ci`) also
|
|
203
|
+
records the login on the older records the roster can place for certain, on every step (same reference → "Recording the login on older records").
|
|
204
|
+
A bridge approval records the platform's evidence — `approvedAt`, and on GitHub `commit`, `url` and
|
|
205
|
+
`reviewId` — for the record only; the gate decides on the login and the fingerprint. Supersede revoked ones
|
|
147
206
|
**while the step is open** (a step already `done` keeps its approvals — they are the record of why it
|
|
148
|
-
passed)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
207
|
+
passed). Comment records are upserted by `(step, commenter, round)`: when the latest round already
|
|
208
|
+
has the same commenters and counts, it is rewritten in place, so re-running `sync` does not duplicate
|
|
209
|
+
it. **Manual approvals (no `source` tag) are never touched.** For the architecture+contract step, the
|
|
210
|
+
fingerprint a bridge approval is bound to is the contract surface, so a re-lock makes every approval of
|
|
211
|
+
the old surface stale: it stays on disk and no longer counts (re-lock invalidates platform approvals
|
|
212
|
+
too). Then refresh the `approved.md`
|
|
213
|
+
record, set the PR ledger's `lastSyncedAt`, and **re-evaluate Step 3**. **Never hand-write either PR-ledger file.** It lives under two names while the rename settles — `product-prs.json` and `hub-prs.json` — and the engine writes both together. Writing one leaves the pair disagreeing, and `yad doctor` will report it. Use `yad gate`, which keeps them in step. Under the PR-driven CLI (`yad
|
|
152
214
|
gate sync`), `sync` advances the step when Step 3 passes on a **merged**, fully-resolved, approved PR
|
|
153
215
|
(the merge is the human act); otherwise it records state and holds the step `in_review`.
|
|
154
216
|
|
|
@@ -156,9 +218,15 @@ gate sync`), `sync` advances the step when Step 3 passes on a **merged**, fully-
|
|
|
156
218
|
|
|
157
219
|
### Step 3 — Gate predicate (the only path that advances)
|
|
158
220
|
The step may advance **iff ALL hold**:
|
|
159
|
-
1. `
|
|
160
|
-
|
|
161
|
-
|
|
221
|
+
1. the advance dial is `human` (`automation: human_approve` — it always is for Shape steps) and the base
|
|
222
|
+
is met: **≥1 distinct approver** (counted by `approver`, so two records from one person are one).
|
|
223
|
+
If it is not, the missing line is `1 approval(s)`. **The risk step (Step 1) is NOT a condition
|
|
224
|
+
here, capped or not** — it is advisory. A step short of the capped ask still advances when
|
|
225
|
+
the base holds. Report the shortfall in the record; do not hold the step on it.
|
|
226
|
+
This matches `gatePredicate`, which returns `rule: "count"`, the count as `gateRule`/`have`/`short`,
|
|
227
|
+
`active`, and `cap` (null when `active` is null), and never puts the risk step in `missing`.
|
|
228
|
+
`active: null` means no source could be read, never "nobody". With `hub.review.requireEngagement`
|
|
229
|
+
on, only `verified` approvals count.
|
|
162
230
|
2. The artifact has not changed since the latest approval round (no newer authored edit than the
|
|
163
231
|
newest `approved` record). If it changed, approvals are stale → return to `comment`. For the
|
|
164
232
|
**architecture+contract** review, also recompute the contract-surface hash (see
|
|
@@ -169,32 +237,82 @@ If the predicate **fails**: report exactly which approvals are still missing and
|
|
|
169
237
|
`currentStep`.
|
|
170
238
|
|
|
171
239
|
If the predicate **passes**:
|
|
172
|
-
|
|
240
|
+
|
|
241
|
+
> **These rules are a TRANSCRIPTION of `advanceState`, and that is deliberate — it is the one
|
|
242
|
+
> transition with no engine verb behind it.** Everything else this skill does now calls the engine, and
|
|
243
|
+
> so do the authoring skills: `yad epic new` seeds a chain, `yad gate open` closes an authoring step and
|
|
244
|
+
> opens its gate. But there is no verb for *"an approval landed, advance the chain"* on a Product with
|
|
245
|
+
> **no platform**: `yad gate sync` and `yad gate ci` both return immediately without one, and
|
|
246
|
+
> `advanceState` — the function holding the rules below — has no other caller. So on a local-only
|
|
247
|
+
> Product these bullets ARE the engine's rules, written out. Keep them in step with `advanceState` in
|
|
248
|
+
> `cli/epic-state.mjs`, including the author-step close, until a local approve verb exists.
|
|
249
|
+
>
|
|
250
|
+
> With a platform, you do not perform them at all: `yad gate sync` (local ledger) or `yad gate ci`
|
|
251
|
+
> (verified) runs the same transition from that function.
|
|
252
|
+
>
|
|
253
|
+
> One other skill still writes a chain by hand, and it is not an oversight: `yad-backfill promote`
|
|
254
|
+
> rewrites one, and needs its own verb. (`yad-discovery` used to be one; since E75 it runs
|
|
255
|
+
> `yad foundation new`. `yad-change` used to seed a threaded chain by hand; since E42 it runs
|
|
256
|
+
> `yad epic new --parent`.)
|
|
257
|
+
|
|
258
|
+
- Mark this review step `status: "done"` **and give it a closing record** (E18):
|
|
259
|
+
`"closed": { "by": "<who performs this advance, or null>", "date": "<YYYY-MM-DD>", "via": "approved", "hash": "<the artifact hash the approvals bind to>" }`.
|
|
260
|
+
`approved`, not `merge`: nothing merged, so there is no `pr` or `commit` to write.
|
|
261
|
+
**In solo mode** (`solo: true` in `.sdlc/hub.json`, or the older `review_gate.solo: true`), add `"waived": "solo"` to that record: the gate passed
|
|
262
|
+
without counting approvals, and the record says so (E10). Only on the review step, never on its author step.
|
|
263
|
+
**In team mode, on a gate that counted approvals, when the cap lowered the ask** (E72), add
|
|
264
|
+
`"capped": { "needed": <full count>, "to": <capped ask>, "active": <people counted> }` — every cap is
|
|
265
|
+
recorded. Read `active` and the capped ask from `yad gate status` (its `active people:` line and the
|
|
266
|
+
step's `capped to N` suffix); write nothing when it prints `NOT COUNTED`. It records what the gate
|
|
267
|
+
ASKED, not what held it: the base held. `yad gate status` prints it back as
|
|
268
|
+
`count capped from 3 to 1 (2 active people)`. Absent in solo mode (nothing was counted), on a step that
|
|
269
|
+
passed by its skip or inherited shortcut (nothing was asked), and when the cap lowered nothing.
|
|
270
|
+
- **Close its paired authoring step if it is not `done` already.** `advanceState` does this defensively
|
|
271
|
+
(issue #131) because a passed gate can never leave its author step behind. Skipping it strands every
|
|
272
|
+
later step behind `YAD-STATE-005`. Give it `"closed": { "by": …, "date": …, "via": "review-passed" }`.
|
|
273
|
+
- **Never write a `closed` over one already on a step.** The first close wins.
|
|
173
274
|
- **`stories-review`** is the end of the gating chain: set `currentStep: "ready-for-build"` (the Phase 3
|
|
174
275
|
handoff sentinel; intentionally not a `steps[]` entry) **and** open the parallel **`test-cases`** track
|
|
175
|
-
(
|
|
276
|
+
(if its step is `todo`, set it to `in_progress`). Build can now start **and** the tester can work
|
|
176
277
|
`test-cases` at the same time.
|
|
177
278
|
- **`test-cases-review`** is the parallel track's gate: mark it `done` but **leave `currentStep` at
|
|
178
|
-
`ready-for-build`** — completing test cases must never pull the epic back from
|
|
179
|
-
-
|
|
180
|
-
|
|
279
|
+
`ready-for-build`** — completing test cases must never pull the epic back from Build.
|
|
280
|
+
- **`foundation-review`** (the Product level, `foundation/`) ends at its own sentinel: set
|
|
281
|
+
`currentStep: "foundation-done"`, never `ready-for-build` — the product level has no Build part. The
|
|
282
|
+
old spelling does the same: **`discovery-review`** sets `currentStep: "discovery-done"`.
|
|
283
|
+
- **On any review step that passes**, remove `"debt": true` from it, and from its author step once that
|
|
284
|
+
step is `done` — passing the review is what pays a debt back (E41), and nothing else clears the flag.
|
|
285
|
+
- A review step that passed **behind the chain** — a step re-opened with a late `yad undefer`, where
|
|
286
|
+
`currentStep` is already past it or is `ready-for-build` — changes nothing else: do not open the step
|
|
287
|
+
after it (that work is already finished) and do not move `currentStep`.
|
|
288
|
+
- Any **other** review step: find the next step in `steps[]` that has not already passed — not `skipped`,
|
|
289
|
+
`deferred`, `satisfied` (inherited from a parent epic) or `done` — set
|
|
290
|
+
it to `in_progress` (authoring) or `in_review` **only if it is `todo`**, and set `currentStep` to it. A
|
|
291
|
+
skipped step was marked N/A with `yad skip`, and a deferred one set aside for later with `yad defer`;
|
|
292
|
+
both stay as they are. A step already started or finished keeps its status.
|
|
293
|
+
If every later step is skipped or deferred, set `currentStep: "ready-for-build"`. A step waiting its turn is `todo` from shape 7 on. An older file may still say
|
|
294
|
+
`blocked` with no `record` on it, which means the same thing; a `blocked` step **with** a `record` is
|
|
295
|
+
waiting on someone outside the workflow, so leave it as it is.
|
|
296
|
+
- When a gate **opens** (the review starts), move `currentStep` to it only if it is not already past it:
|
|
297
|
+
opening the review of a re-opened step never pulls the chain back.
|
|
181
298
|
- Write `state.json`. Report the advance and what the next authored artifact is (or that the epic is
|
|
182
299
|
now `ready-for-build`, with `test-cases` running in parallel).
|
|
183
300
|
|
|
184
301
|
### PR-driven automation (the `yad gate` CLI)
|
|
185
|
-
When the
|
|
302
|
+
When the Product has a platform and a **verified** ledger, **CI is the sole writer of the ledger**. (With a
|
|
303
|
+
platform and a local ledger, `yad gate open` and `yad gate sync` write it instead.) `yad gate open` opens the review
|
|
186
304
|
PR only — against the `review/<epic>/<artifact>` branch, which must already exist (create it and run
|
|
187
305
|
`yad open-pr` from it, which pushes it first). CI (`yad gate ci`) writes the `.sdlc/` + `reviews/`
|
|
188
306
|
records this skill describes. The skill's
|
|
189
307
|
job is the human half: presenting the artifact, helping the owner address comments, and narrating the
|
|
190
|
-
gate. Local `yad gate sync` is advisory in
|
|
308
|
+
gate. Local `yad gate sync` is advisory in verified mode (reads the platform, prints status, writes
|
|
191
309
|
nothing); a human must never commit gate-state files (the `ledger-guard` check rejects it, and the
|
|
192
310
|
`hooks/ledger-guard.sh` harness hook refuses an agent the edit up front, naming `yad gate open`
|
|
193
311
|
instead — see `yad-checks`). The single
|
|
194
312
|
exception is an epic's **seed** — no CI path can create a ledger, so a brand-new epic's `.sdlc/` rides
|
|
195
313
|
its **first** review PR/MR, cut from the authoring branch (creation, not mutation, #162).
|
|
196
314
|
|
|
197
|
-
Under that CLI the gate **advances on merge**: a review PR/MR whose
|
|
315
|
+
Under that CLI the gate **advances on merge**: a review PR/MR whose base count is met, whose
|
|
198
316
|
comment threads are **all resolved**, and which has been **merged** auto-marks the step `done` and
|
|
199
317
|
unblocks the next step. (Until those three hold, the step stays `in_review`.)
|
|
200
318
|
|
|
@@ -210,22 +328,23 @@ platform PR/MR is the source of truth (native approvals + threads), and CI never
|
|
|
210
328
|
branch (so an in-flight approval is never dismissed and required checks never strand). On the human
|
|
211
329
|
**merge** CI re-reads approvals, advances the step, and flips the artifact `status:` on the **default
|
|
212
330
|
branch**. After a merge, `git checkout <default> && git pull` to see it. The predicate and the human
|
|
213
|
-
merge are unchanged — CI never approves and never merges.
|
|
331
|
+
merge are unchanged — CI never approves and never merges. Local mode (no platform) keeps the local
|
|
214
332
|
write path.
|
|
215
333
|
|
|
216
334
|
### Hard rules (build plan §1, §5)
|
|
217
|
-
- **The merge click is the human approval act.** A
|
|
335
|
+
- **The merge click is the human approval act.** A Shape step advances only when a human merges the
|
|
218
336
|
approved, fully-resolved review PR — there is no machine-driven advance. A step `locked: true` may not
|
|
219
|
-
be switched to `
|
|
337
|
+
be switched to `advance: auto`; refuse such a request.
|
|
220
338
|
- **Approvals are revoked when the reviewed artifact changes.** `sync` re-hashes the artifact (the locked
|
|
221
|
-
contract surface for architecture
|
|
339
|
+
contract surface for architecture; every other file without its frontmatter `status:` line, which the
|
|
340
|
+
gate and Build rewrite after review) and drops any approval bound to a stale hash, so a reviewer must
|
|
222
341
|
re-approve the new content. Unresolved comments / `CHANGES_REQUESTED` hold the gate `in_review`.
|
|
223
342
|
- The gate talks only through `.sdlc/` and `reviews/` files — never hidden state.
|
|
224
343
|
- **The platform is an input path only.** `open`/`sync` use the local user's own `gh`/`glab` (no stored
|
|
225
344
|
tokens), and the **file ledger remains the source of truth** — the Step 3 predicate is unchanged
|
|
226
|
-
whether approvals arrive manually or via `sync`. With no
|
|
345
|
+
whether approvals arrive manually or via `sync`. With no Product platform / no CLI, the gate runs local
|
|
227
346
|
with no error (record approvals manually and `advance`).
|
|
228
347
|
|
|
229
348
|
## Reference
|
|
230
349
|
- Gating details and worked example: `references/gating.md`.
|
|
231
|
-
- The platform PR/MR bridge (`open`/`sync` mechanics, read recipes,
|
|
350
|
+
- The platform PR/MR bridge (`open`/`sync` mechanics, read recipes, login attribution): `../yad-hub-bridge/SKILL.md`.
|