yadflow 2.18.1 → 3.1.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.
- package/CHANGELOG.md +11 -2
- package/README.md +1 -1
- package/bin/yad.mjs +30 -5
- package/cli/companion.mjs +61 -0
- package/cli/doctor.mjs +11 -0
- package/cli/epic-state.mjs +13 -3
- package/cli/gate.mjs +87 -5
- package/cli/manifest.mjs +13 -4
- package/cli/openpr.mjs +5 -1
- package/cli/plan.mjs +45 -6
- package/cli/platform.mjs +149 -23
- package/cli/reconcile.mjs +7 -6
- package/cli/review.mjs +145 -0
- package/cli/setup.mjs +17 -2
- package/package.json +2 -2
- package/skills/sdlc/config.yaml +8 -0
- package/skills/sdlc/install.sh +18 -1
- package/skills/sdlc/module-help.csv +1 -1
- package/skills/yad-connect-repos/references/hub-config.md +10 -0
- package/skills/yad-docs-overview/references/pipeline-model.md +1 -1
- package/skills/yad-engineer-review/SKILL.md +13 -2
- package/skills/yad-engineer-review/references/ship-and-record.md +15 -2
- package/skills/yad-hub-bridge/references/bridge.md +34 -0
- package/skills/yad-open-pr/SKILL.md +10 -0
- package/skills/yad-pr-template/templates/checks/pr-template.sh +9 -0
- package/skills/yad-review-companion/SKILL.md +89 -0
- package/skills/yad-review-gate/SKILL.md +5 -1
- package/skills/yad-review-gate/references/gating.md +18 -0
- package/skills/yad-review-comments/SKILL.md +0 -63
- package/skills/yad-review-comments/references/comment-conventions.md +0 -55
- package/skills/yad-review-comments/templates/github/REVIEW_COMMENTS.md +0 -49
- package/skills/yad-review-comments/templates/gitlab/REVIEW_COMMENTS.md +0 -49
|
@@ -39,11 +39,22 @@ a **second set of eyes, never the authority**: it cannot approve or merge. Where
|
|
|
39
39
|
(no remote), run an equivalent AI first-pass by hand and capture its notes. Record that the AI review
|
|
40
40
|
ran; surface its findings to the engineer. Do **not** treat AI approval as a gate.
|
|
41
41
|
|
|
42
|
+
Also run the **Review Companion** so the human review is easy and fun: post the 60-sec trailer
|
|
43
|
+
(`yad review trailer --repo <r> --pr <n> --body "<text>"`) and deal the swipe cards / open the grounded
|
|
44
|
+
chat from the bundle (`yad review context --repo <r> --pr <n>` → [yad-review-companion](../yad-review-companion/SKILL.md)).
|
|
45
|
+
Companion comments carry `<!-- yad:noblock -->` (history-only, never block); genuine concerns are posted
|
|
46
|
+
unflagged and block normally.
|
|
47
|
+
|
|
42
48
|
### Step 2 — `approve` (the engineer review — the human gate)
|
|
43
49
|
A human engineer reads the diff **against the spec** (`specs/<story>/`) and the acceptance criteria,
|
|
44
50
|
and records an approval. Determine the rule from the PR's Impact & Risk block (run
|
|
45
51
|
`../yad-pr-template/templates/checks/risk-route.sh` on the PR body): base, or escalated to a
|
|
46
52
|
domain-owner per touched domain. Record each approval; re-evaluate whether the rule is satisfied.
|
|
53
|
+
Record `engagement: verified` when the engineer reviewed through the companion (else `none` for a bare
|
|
54
|
+
approve); `yad review reconcile --epic <id> --repo <r> --pr <n>` stamps it onto the ship record from the
|
|
55
|
+
platform. Soft by default (both count; a bare approve draws `yad review nudge`); only gates when
|
|
56
|
+
`hub.review.requireEngagement: true`. The signal is gameable by design and sits **beside** the CI gates,
|
|
57
|
+
never above them.
|
|
47
58
|
Recording an approval does **not** ship — shipping is a separate, explicit step. Front-half discipline:
|
|
48
59
|
the gate talks only through files; refuse to treat AI review as a human approval.
|
|
49
60
|
|
|
@@ -55,8 +66,8 @@ engineer-review rule is satisfied (Step 2). Then:
|
|
|
55
66
|
```json
|
|
56
67
|
{ "story": "<story>", "task": "<task>", "repo": "<repo>", "branch": "feat/<story>-<task>-…",
|
|
57
68
|
"pr": "<url|#>", "mergeCommit": "<sha>", "gates": ["spec-link","contract-check","build-test-lint"],
|
|
58
|
-
"ai_review": "coderabbit (advisory)", "engineer_review": [{"approver":"<name>","role":"<role>","domain":"<opt>"}],
|
|
59
|
-
"risk": "<low|medium|high>", "shippedAt": "<YYYY-MM-DD>" }
|
|
69
|
+
"ai_review": "coderabbit (advisory)", "engineer_review": [{"approver":"<name>","role":"<role>","domain":"<opt>","engagement":"<verified|none>"}],
|
|
70
|
+
"companion": {"trailer":true,"cards":true,"chat":false}, "risk": "<low|medium|high>", "shippedAt": "<YYYY-MM-DD>" }
|
|
60
71
|
```
|
|
61
72
|
- **Update the story state** — when **every** task in `specs/<story>/tasks.md` has a ship record, set
|
|
62
73
|
the story frontmatter `status: shipped`; otherwise `status: in-build`. The chain
|
|
@@ -33,9 +33,10 @@ Append-only. One record per shipped task:
|
|
|
33
33
|
"gates": ["spec-link", "contract-check", "build-test-lint"],
|
|
34
34
|
"ai_review": "coderabbit (advisory)",
|
|
35
35
|
"engineer_review": [
|
|
36
|
-
{ "approver": "amelia", "role": "owner" },
|
|
37
|
-
{ "approver": "carol", "role": "reviewer" }
|
|
36
|
+
{ "approver": "amelia", "role": "owner", "engagement": "verified" },
|
|
37
|
+
{ "approver": "carol", "role": "reviewer", "engagement": "none" }
|
|
38
38
|
],
|
|
39
|
+
"companion": { "trailer": true, "cards": true, "chat": false },
|
|
39
40
|
"risk": "low",
|
|
40
41
|
"shippedAt": "2026-06-06"
|
|
41
42
|
}
|
|
@@ -46,6 +47,18 @@ Append-only. One record per shipped task:
|
|
|
46
47
|
This is the back-half analogue of the front half's `approvals.json` — files only, no hidden state, so a
|
|
47
48
|
future service can drive ship by writing the same records.
|
|
48
49
|
|
|
50
|
+
**Engagement (the Review Companion).** Each `engineer_review` entry carries `engagement: verified | none`
|
|
51
|
+
— `verified` when the engineer reviewed through the [companion](../../yad-review-companion/SKILL.md)
|
|
52
|
+
(`yad review trailer/context/nudge`, a real trailer/cards/chat session over the diff), `none` for a bare
|
|
53
|
+
approve. The optional `companion` block records which faces ran. It is **soft by default** (both count;
|
|
54
|
+
a bare approve draws a friendly `yad review nudge`); it only gates ship when
|
|
55
|
+
`hub.review.requireEngagement: true`. `yad review reconcile --epic <id> --repo <r> --pr <n>` reads the
|
|
56
|
+
code PR's approvals (with the engagement signal) and stamps them onto the matching ship record — the
|
|
57
|
+
back-half **bridge**, the analogue of `yad gate sync`. The signal is gameable by design ("visible, not
|
|
58
|
+
impossible"): it makes engineer-review quality visible, it does not prove a human read the diff. It sits
|
|
59
|
+
**beside** the CI gates (build/test/lint/contract/verified-commits) — never above them; CI still
|
|
60
|
+
decides machine safety, the merge is still the human act.
|
|
61
|
+
|
|
49
62
|
## Story state
|
|
50
63
|
|
|
51
64
|
The story frontmatter `status` reflects build progress:
|
|
@@ -35,6 +35,40 @@ glab api projects/:id/merge_requests/:iid/notes # discussion notes (com
|
|
|
35
35
|
All commands run as the **local user**; the bridge stores no tokens. If the CLI is missing/unauthenticated
|
|
36
36
|
or the remote is unreachable, the bridge stops and the gate falls back to file-only (no error).
|
|
37
37
|
|
|
38
|
+
> **GitLab read parity (GAP-6).** `readPrGitLab` reads approvals (`approved_by[]`) and discussions but
|
|
39
|
+
> does **not** map a "Request changes" reviewer state to `CHANGES_REQUESTED` — on GitLab the blocking
|
|
40
|
+
> signal is an **unresolved discussion**. So on GitLab the gate is held by unresolved threads, not by a
|
|
41
|
+
> reviewer state. (GitHub maps both.) If you need GitLab "Request changes" honored, read
|
|
42
|
+
> `reviewers[].state` from the MR and map it to `CHANGES_REQUESTED`.
|
|
43
|
+
|
|
44
|
+
## Open recipes (request the reviewers — used by `yad gate open` / `yad open-pr`)
|
|
45
|
+
|
|
46
|
+
Opening the review PR/MR must **request the required reviewers**, or an escalated gate is opened with
|
|
47
|
+
nobody asked. The CLI (`createPr` in `cli/platform.mjs`) does this; an agent opening a PR by hand uses:
|
|
48
|
+
|
|
49
|
+
**GitHub** — create, then add each reviewer (a bad/non-collaborator login WARNS instead of aborting the
|
|
50
|
+
whole create):
|
|
51
|
+
```bash
|
|
52
|
+
gh pr create --title "review: <artifact> (<epic>)" --body <body> --base <default> --head <branch> \
|
|
53
|
+
--assignee @me --label domain:<repo>
|
|
54
|
+
gh pr edit <n> --add-reviewer <login> # once per required reviewer
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**GitLab** — a Free/Core MR carries a **single** reviewer field (multiple reviewers is Premium), so
|
|
58
|
+
assign the first required reviewer and **@-mention the rest in a note** so they are still notified/routed:
|
|
59
|
+
```bash
|
|
60
|
+
glab mr create --title "review: <artifact> (<epic>)" --description <body> \
|
|
61
|
+
--target-branch <default> --source-branch <branch> --reviewer <first-login> --label domain:<repo> --yes
|
|
62
|
+
glab mr note <iid> -m "Review requested (owner + reviewer rule): @<l2> @<l3> — please review and approve/comment on this MR (this drives the gate)."
|
|
63
|
+
```
|
|
64
|
+
The read side counts a mentioned reviewer normally: their eventual **approval** still appears in
|
|
65
|
+
`…/approvals → approved_by[]`, and their **note** in `…/discussions` — so the single-reviewer-field cap
|
|
66
|
+
loses only the native "Reviewers" UI chip, not the gate routing.
|
|
67
|
+
|
|
68
|
+
Required reviewers = the hub's `reviewer`/`domain-owner` roster logins for the touched scopes, PLUS any
|
|
69
|
+
repo whose ownership lives only in `repos.json` `domain_owner`/`domain_owners` (those are resolved to a
|
|
70
|
+
login and requested too — otherwise an escalated step is structurally unsatisfiable through routing).
|
|
71
|
+
|
|
38
72
|
## Login → role resolution (order)
|
|
39
73
|
|
|
40
74
|
1. Roster (`.sdlc/hub.json`) maps `login` → `name` + base `role` (owner/reviewer).
|
|
@@ -62,6 +62,16 @@ PR/MR with the auto-assigned assignee + reviewers.
|
|
|
62
62
|
On `high` risk or a contract touch, run `bash checks/risk-route.sh <pr-body>` to print the required
|
|
63
63
|
domain-owner reviewers — the same escalation `yad-engineer-review` enforces.
|
|
64
64
|
|
|
65
|
+
### Step 3b — Post the review trailer (optional, recommended)
|
|
66
|
+
Make the reviewer's job easy: generate the 60-sec briefing and post it to the new PR/MR so it greets
|
|
67
|
+
every reviewer in the UI (idempotent; safe to re-run after a push):
|
|
68
|
+
```bash
|
|
69
|
+
yad review trailer --repo <name> --pr <n> --body "<companion-generated briefing>"
|
|
70
|
+
```
|
|
71
|
+
The full fun-review flow (cards + grounded chat + engagement) is driven by the
|
|
72
|
+
[Review Companion](../yad-review-companion/SKILL.md) during `yad-engineer-review`. Non-blocking by
|
|
73
|
+
design — companion comments carry `<!-- yad:noblock -->`.
|
|
74
|
+
|
|
65
75
|
### Step 4 — Stop (no merge)
|
|
66
76
|
Report the PR/MR URL and the requested reviewers. The PR now runs the check gates (Step C); the human
|
|
67
77
|
engineer review and merge happen in `yad-engineer-review` (Step E).
|
|
@@ -45,6 +45,15 @@ if [ -z "$BODY" ] || [ ! -f "$BODY" ]; then
|
|
|
45
45
|
exit 1
|
|
46
46
|
fi
|
|
47
47
|
|
|
48
|
+
# The Review Companion injects a `<!-- yad:trailer --> … <!-- /yad:trailer -->` briefing block (and
|
|
49
|
+
# `<!-- yad:noblock -->` notes) into the description. Strip those before the template check so the
|
|
50
|
+
# AI-generated prose can never hide a required section heading or be mistaken for the `Risk level:`
|
|
51
|
+
# value (the trailer is prepended, so an unstripped "risk level" mention would win `head -1`).
|
|
52
|
+
STRIPPED="$(mktemp)"
|
|
53
|
+
trap 'rm -f "$STRIPPED"' EXIT
|
|
54
|
+
sed '/<!-- yad:trailer -->/,/<!-- \/yad:trailer -->/d; /<!-- yad:noblock -->/d' "$BODY" > "$STRIPPED"
|
|
55
|
+
BODY="$STRIPPED"
|
|
56
|
+
|
|
48
57
|
rc=0
|
|
49
58
|
require_heading() {
|
|
50
59
|
if ! grep -qiE "^[[:space:]]*$1[[:space:]]*$" "$BODY"; then
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yad-review-companion
|
|
3
|
+
description: 'The fun, easy, transparent review companion for the SDLC review gates. Generates a 60-second AI "trailer" of what changed and where the risk is, deals a swipe-through deck of small review "cards", and runs a grounded chat where a reviewer asks anything and their questions become the review record — then records an engagement signal on the approval (verified vs none) and posts a friendly public nudge on a bare rubber-stamp. Works on the front-half artifact-review PR/MR (yad gate) and the back-half code PR/MR (yad review). Use when the user says "review this", "run the companion", "give me the trailer/cards", or wants reviewing to be less of a chore.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Review Companion (fun & easy, transparent review)
|
|
7
|
+
|
|
8
|
+
**Goal:** make the honest review the *easiest, most enjoyable* path, and make laziness **visible**, not
|
|
9
|
+
blocked. This companion does **not** try to prove a human read something — no quiz, no un-fakeable
|
|
10
|
+
proof (a quiz is answerable by AI, swipes can be spammed). Instead it removes the friction that makes
|
|
11
|
+
reviewers skip, and it makes review *quality* visible to the whole team.
|
|
12
|
+
|
|
13
|
+
> **Philosophy — "visible, not impossible."** Every engagement signal here is gameable by design. It
|
|
14
|
+
> raises the cost of a bare rubber-stamp and shines a light on it; it never claims certainty. State that
|
|
15
|
+
> openly — do not oversell it.
|
|
16
|
+
|
|
17
|
+
This companion is the AI layer on top of [`yad-review-gate`](../yad-review-gate/SKILL.md) (front half)
|
|
18
|
+
and [`yad-engineer-review`](../yad-engineer-review/SKILL.md) (back half). The **gate** still owns the
|
|
19
|
+
predicate and advancement; the companion only enriches the *input* and records the *engagement* field.
|
|
20
|
+
The CLI never calls an LLM — **you** (this skill) generate the text and post it via the platform.
|
|
21
|
+
|
|
22
|
+
## The four faces
|
|
23
|
+
|
|
24
|
+
1. **🎬 Trailer (A)** — a 60-second briefing: what this change does, where the risk is (from the step's
|
|
25
|
+
`risk_tags`), and an honest read-time estimate. Posted to the **PR/MR description** as a delimited
|
|
26
|
+
`<!-- yad:trailer --> … <!-- /yad:trailer -->` block so everyone sees it in the UI. Regenerated when
|
|
27
|
+
the artifact changes (it must never lie about the current content).
|
|
28
|
+
2. **🃏 Cards (B)** — split the change into small **atomic claims**, one per card, each anchored to real
|
|
29
|
+
line numbers / hunks and tagged with risk. Posted as PR/MR comment threads the reviewer skims 👍/🤔.
|
|
30
|
+
3. **💬 Chat (C)** — a grounded Q&A: the reviewer asks anything; you answer **only from real material**
|
|
31
|
+
(the artifact + diff + contract + the repo `code-map.md`/`pack.md` + sister docs). The reviewer's
|
|
32
|
+
questions and flagged concerns become the review record. If you **cannot** answer from the material,
|
|
33
|
+
say so — that gap is itself a finding (post it as a genuine, blocking comment).
|
|
34
|
+
4. **🏆 Social (E)** — a verified-engagement mark on a real companion review, a friendly public
|
|
35
|
+
@-mention nudge on a bare approve, and light read-only gamification surfaced by `yad status`.
|
|
36
|
+
|
|
37
|
+
## Markers (the contract with the gate — all live in PLATFORM data, never a ledger file)
|
|
38
|
+
|
|
39
|
+
- `<!-- yad:trailer -->` / `<!-- /yad:trailer -->` — the trailer block in the PR/MR description.
|
|
40
|
+
- `<!-- yad:noblock -->` — on **every** companion-posted comment (card deck, chat log) and the nudge.
|
|
41
|
+
The gate **excludes** these threads from the blocking check, so they stay unresolved as a permanent
|
|
42
|
+
PR/MR history trail and never hold the gate. A reviewer's *genuine* concern is posted **without** this
|
|
43
|
+
marker, so it blocks normally.
|
|
44
|
+
- `<!-- yad:engagement verified -->` — embedded in the body of a companion-driven **Approve** review.
|
|
45
|
+
A bare UI click has no marker → `engagement: none`. (Definitions live in `cli/companion.mjs`.)
|
|
46
|
+
|
|
47
|
+
## On activation
|
|
48
|
+
|
|
49
|
+
Inputs: `epic` + `artifact` (front half) **or** `repo` + `pr` (back half); and the `action`
|
|
50
|
+
(`trailer` | `cards` | `chat` | `approve` | `nudge`, default the full flow).
|
|
51
|
+
|
|
52
|
+
1. **Get the grounding bundle.** Front half: `yad gate review <epic> [artifact]` prints JSON with the
|
|
53
|
+
artifact path, risk tags, PR number, contract path, touched domains, repo code-map paths, and
|
|
54
|
+
`requireEngagement`. Back half: `yad review chat --repo <r>` (see `yad-engineer-review`) provides the
|
|
55
|
+
diff + code-map grounding. Read the named files yourself — never invent content.
|
|
56
|
+
2. **Trailer.** Generate ≤6 lines (what / risk / read-time), grounded only in the bundle. Post it:
|
|
57
|
+
`yad gate trailer <epic> <artifact> --body "<text>" [--pr <n>]` (idempotent; re-run after edits).
|
|
58
|
+
3. **Cards.** Produce atomic claims, each citing real lines. Post the deck as a single comment carrying
|
|
59
|
+
`<!-- yad:noblock -->`. A reviewer's 🤔 with a real concern → re-post as a **normal, unflagged**
|
|
60
|
+
comment so it blocks.
|
|
61
|
+
4. **Chat.** Answer from the material with cited lines. Append the Q&A log as a `<!-- yad:noblock -->`
|
|
62
|
+
comment so it persists in history without blocking. Turn genuine concerns into unflagged comments.
|
|
63
|
+
5. **Approve.** When the reviewer is satisfied, submit an Approve whose body carries
|
|
64
|
+
`<!-- yad:engagement verified -->` (so the gate records `engagement: verified`). GitHub:
|
|
65
|
+
`gh pr review <n> --approve --body "<note>\n\n<!-- yad:engagement verified -->"`. GitLab: approve,
|
|
66
|
+
then post the marker as a note (`glab mr approve <n>` + `glab mr note <n> -m "…<!-- yad:engagement verified -->"`).
|
|
67
|
+
6. **Nudge.** A bare approve (engagement `none`) still counts under the soft default; `yad gate sync`
|
|
68
|
+
posts the friendly @-mention automatically. You may also post it directly with the
|
|
69
|
+
`<!-- yad:noblock -->` marker.
|
|
70
|
+
|
|
71
|
+
## Hard rules
|
|
72
|
+
|
|
73
|
+
- **Never write a ledger file.** Post comments / the trailer / the approval to the PLATFORM (the
|
|
74
|
+
reviewer's own `gh`/`glab`). CI writes `approvals.json`/`comments.json`; the `ledger-guard` check
|
|
75
|
+
rejects a human ledger edit on a review PR. The markers ride in platform data only.
|
|
76
|
+
- **Trailer/cards/chat are grounded ONLY in real material.** If the material does not answer a
|
|
77
|
+
question, say so and record the gap — do not fabricate.
|
|
78
|
+
- **Companion comments never block; genuine concerns always do.** Flag the former with `yad:noblock`;
|
|
79
|
+
leave the latter unflagged.
|
|
80
|
+
- **The engagement signal is gameable and you say so.** It makes review quality visible; it is not
|
|
81
|
+
proof. The strict-mode switch is `hub.review.requireEngagement` (off by default).
|
|
82
|
+
- **The companion never approves on a human's behalf and never merges.** It assists; the human acts.
|
|
83
|
+
|
|
84
|
+
## File-only mode (no platform)
|
|
85
|
+
|
|
86
|
+
With no hub platform, there is no PR to post to: write the trailer to
|
|
87
|
+
`reviews/<artifact-base>--<date>--trailer.md` and the card/chat notes alongside the existing
|
|
88
|
+
`reviews/*.md`, and the reviewer records approval the manual way (`yad-review-gate` `approve`). The same
|
|
89
|
+
generation logic applies; only the surface changes.
|
|
@@ -92,8 +92,12 @@ Repeat comment→address rounds until reviewers are satisfied. **Commenting neve
|
|
|
92
92
|
|
|
93
93
|
**`approve`** — Record an approval. Append to `.sdlc/approvals.json`:
|
|
94
94
|
```json
|
|
95
|
-
{ "artifact": "<artifact>", "step": "<step id>", "approver": "<name>", "role": "<owner|reviewer|domain-owner>", "domain": "<optional>", "status": "approved", "date": "<YYYY-MM-DD>" }
|
|
95
|
+
{ "artifact": "<artifact>", "step": "<step id>", "approver": "<name>", "role": "<owner|reviewer|domain-owner>", "domain": "<optional>", "status": "approved", "date": "<YYYY-MM-DD>", "engagement": "<verified|none>" }
|
|
96
96
|
```
|
|
97
|
+
`engagement` records whether the approval came through the [Review Companion](../yad-review-companion/SKILL.md)
|
|
98
|
+
(a real trailer/cards/chat session = `verified`) or as a bare click (`none`). It is soft by default
|
|
99
|
+
(both count; a bare approve draws a friendly nudge) and only gates when `hub.review.requireEngagement`
|
|
100
|
+
is on — see `references/gating.md`. The signal is gameable by design ("visible, not impossible").
|
|
97
101
|
Also write/refresh `reviews/<artifact-base>--<YYYY-MM-DD>--approved.md` as a **named roster** with three
|
|
98
102
|
sections, so every participant is attributable in one place:
|
|
99
103
|
|
|
@@ -12,6 +12,15 @@ Let `A` = the set of `approved` records in `.sdlc/approvals.json` for this step.
|
|
|
12
12
|
**Escalated pass** (step `risk_tags` ∩ `{contract, auth, payments}` ≠ ∅): base pass AND, for every
|
|
13
13
|
touched `domain`, `|domainOwners[domain]| >= 1`.
|
|
14
14
|
|
|
15
|
+
**Engagement (the Review Companion).** Each approval carries `engagement: verified | none` —
|
|
16
|
+
`verified` when it was recorded through the companion (a real trailer/cards/chat session), `none` for a
|
|
17
|
+
bare UI click. By **default (soft)** both count: a bare approve still passes the gate but is recorded
|
|
18
|
+
`none` and draws a friendly public @-mention nudge, so review *quality* is visible without blocking
|
|
19
|
+
anyone. When `hub.review.requireEngagement: true`, only `verified` approvals are counted toward the
|
|
20
|
+
sets above (a determined faker can still run an empty session — the signal is **gameable by design**;
|
|
21
|
+
it raises the cost of a rubber-stamp and makes laziness visible, it does not prove a human read the
|
|
22
|
+
artifact). Philosophy: *visible, not impossible.*
|
|
23
|
+
|
|
15
24
|
**Touched domains** are resolved from files, not hardcoded:
|
|
16
25
|
- Architecture+contract review: the touched domains are the epic's `repos` (every repo shares the
|
|
17
26
|
contract surface).
|
|
@@ -55,6 +64,15 @@ counterpart to the `reviews/*--comments.md` markdown). It does **not** feed the
|
|
|
55
64
|
alone decide the gate — but it makes the `approved.md` roster's "Reviewed / commented by" section
|
|
56
65
|
attributable, and it is the same shape a future service or the platform bridge can write.
|
|
57
66
|
|
|
67
|
+
## Non-blocking companion comments (`<!-- yad:noblock -->`)
|
|
68
|
+
The Review Companion posts scaffolding comments (the card deck, the chat log) and the social nudge.
|
|
69
|
+
These are fun/interactive aids, **not** review objections, so they must never hold the PR/MR — yet they
|
|
70
|
+
are deliberately **left unresolved** so they remain in the PR/MR history forever (anyone can scroll back
|
|
71
|
+
to see the trailer, cards, chat, and nudges). Every such comment carries a `<!-- yad:noblock -->`
|
|
72
|
+
marker, and the gate **excludes marked threads** from the unresolved-thread blocking check (so it does
|
|
73
|
+
not "resolve to pass" — it ignores them). A reviewer's *genuine* concern is posted **without** the
|
|
74
|
+
marker and blocks normally, exactly as a `CHANGES_REQUESTED` or any unresolved human thread does.
|
|
75
|
+
|
|
58
76
|
## Platform-backed input (the bridge)
|
|
59
77
|
When the hub has a platform (`.sdlc/hub.json`) and the bridge is enabled, reviewers can approve/comment
|
|
60
78
|
on a real PR/MR instead of (or as well as) the skill recording it directly. `action: sync`
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: yad-review-comments
|
|
3
|
-
description: 'Installs platform-matched PR/MR review-comment scaffolds into a repo so reviewers leave structured, attributable feedback that maps cleanly into the SDLC file ledger. Works for code repos and the product hub. GitHub has no repo-level multi-comment template, so the scaffold is a committed REVIEW_COMMENTS.md reviewers copy from (saved as Saved Replies on GitHub / comment templates on GitLab). Each canned comment carries an attributable `**<name> (<role>)**` header that matches the `## <name> (<role>)` headings yad-review-gate writes. Use when the user says "add the comment templates" or "set up review comments" for a repo.'
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# SDLC — Review Comment Templates
|
|
7
|
-
|
|
8
|
-
**Goal:** Give reviewers a consistent, **attributable** set of canned PR/MR comments so review feedback
|
|
9
|
-
reads the same across repos and **maps cleanly into the file ledger** the gate keeps. The headers match
|
|
10
|
-
the `## <name> (<role>)` shape `yad-review-gate` writes into `reviews/<artifact>--<date>--comments.md`
|
|
11
|
-
and the per-commenter record in `comments.json`, so a synced or copy-pasted comment lands without
|
|
12
|
-
reformatting.
|
|
13
|
-
|
|
14
|
-
## Platform reality (why this is a committed doc, not a config file)
|
|
15
|
-
|
|
16
|
-
Neither GitHub nor GitLab has a **repo-level** multi-comment template convention: GitHub *Saved Replies*
|
|
17
|
-
are per-account and GitLab *comment templates* are per-user/group, both set in the UI — there is no
|
|
18
|
-
`.github/comment_templates/` or `.gitlab/comment_templates/` the repo can ship. The pragmatic mechanism
|
|
19
|
-
on **both** is a single committed doc reviewers copy from (and optionally paste once into their personal
|
|
20
|
-
Saved Replies / comment templates). This skill ships that doc.
|
|
21
|
-
|
|
22
|
-
## Conventions
|
|
23
|
-
|
|
24
|
-
- `{project-root}` resolves from the project working directory — the **product** repo (holds the
|
|
25
|
-
canonical templates under this skill).
|
|
26
|
-
- Canonical sources live in this skill's `templates/`:
|
|
27
|
-
- `templates/github/REVIEW_COMMENTS.md` → installs to `<repo>/.github/REVIEW_COMMENTS.md`
|
|
28
|
-
- `templates/gitlab/REVIEW_COMMENTS.md` → installs to `<repo>/.gitlab/REVIEW_COMMENTS.md`
|
|
29
|
-
- The two variants are identical except a footer line (GitHub: "save these as Saved Replies"; GitLab:
|
|
30
|
-
"save these as comment templates").
|
|
31
|
-
|
|
32
|
-
## Inputs
|
|
33
|
-
|
|
34
|
-
- `repo` — the repo to add the scaffold to (one of an epic's repos), or `hub` for the product hub.
|
|
35
|
-
- `action` — `wire` (install the matching scaffold). Default `wire`.
|
|
36
|
-
|
|
37
|
-
## On Activation
|
|
38
|
-
|
|
39
|
-
### Step 1 — Resolve the repo and detect the platform
|
|
40
|
-
Map `repo` → its path (`{project-root}/demo-repos/<repo>/` or the registry `path`); for `repo: hub` the
|
|
41
|
-
target is `{project-root}` and the platform comes from `.sdlc/hub.json`. Detect the platform: a GitHub
|
|
42
|
-
remote or `.github/` → GitHub; a GitLab remote or `.gitlab/` → GitLab. If ambiguous, ask.
|
|
43
|
-
|
|
44
|
-
### Step 2 — `wire` (drop only the matching scaffold)
|
|
45
|
-
Copy the matching `templates/<platform>/REVIEW_COMMENTS.md` into the repo's `.github/` or `.gitlab/`.
|
|
46
|
-
Do not clobber an existing non-SDLC file of the same name — back it up / ask. Commit on the repo's
|
|
47
|
-
default branch (shared infrastructure, not a task diff). Idempotent — re-running refreshes in place.
|
|
48
|
-
|
|
49
|
-
### Step 3 — Stop (no auto-advance)
|
|
50
|
-
Report what was committed. The scaffold is an aid to human review; it approves nothing and touches no
|
|
51
|
-
`.sdlc/` state.
|
|
52
|
-
|
|
53
|
-
## Hard rules
|
|
54
|
-
|
|
55
|
-
- **Drop only the matching scaffold** for the detected platform.
|
|
56
|
-
- **Attributable headers** — every canned comment keeps the `**<name> (<role>)**` form so the gate's
|
|
57
|
-
ledger and the PR thread agree.
|
|
58
|
-
- **Nothing auto-advances.** Comments feed the human review and (via the bridge) `yad-review-gate`.
|
|
59
|
-
|
|
60
|
-
## Reference
|
|
61
|
-
- Comment conventions + the full scaffold contents: `references/comment-conventions.md`.
|
|
62
|
-
- The ledger headings these match: `../yad-review-gate/SKILL.md` (comment action) and `references/gating.md`.
|
|
63
|
-
- The review bridge that syncs platform comments into the ledger: `../yad-hub-bridge/SKILL.md`.
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Review comment conventions
|
|
2
|
-
|
|
3
|
-
The scaffold (`REVIEW_COMMENTS.md`) groups canned comments into **blocking** (a gate would fail / must
|
|
4
|
-
be fixed before merge) and **non-blocking** (suggestions, nits, questions). Every comment starts with an
|
|
5
|
-
attributable header:
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
**<name> (<role>)**
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
`<role>` is one of `owner | reviewer | domain-owner` — the same roles `yad-review-gate` records. This
|
|
12
|
-
header matches the `## <name> (<role>)` headings the gate writes into
|
|
13
|
-
`reviews/<artifact>--<date>--comments.md`, so a comment copied from the PR thread (or synced by
|
|
14
|
-
`yad-hub-bridge`) needs no reformatting to land in the ledger.
|
|
15
|
-
|
|
16
|
-
## Blocking comments (a gate or rule says stop)
|
|
17
|
-
|
|
18
|
-
These map to the code-repo check gates (`yad-checks`) and the file-boundary / contract rules:
|
|
19
|
-
|
|
20
|
-
- **spec-link** — "This commit has no `Task: <story>-<task>` trailer; the spec-link gate will fail. Add
|
|
21
|
-
the trailer (and ensure `specs/<story>/link.md` exists)."
|
|
22
|
-
- **contract-check** — "This diff changes the contract surface without `Contract-Change: yes` + a
|
|
23
|
-
re-locked contract. Route back to the architecture gate and re-lock before this can merge."
|
|
24
|
-
- **build-test-lint** — "Lint/build/test is red (or the test doesn't exercise the new behavior). The
|
|
25
|
-
build-test-lint gate must pass with a test that actually exercises the acceptance criterion."
|
|
26
|
-
- **file-boundary** — "This diff touches files the task's `Files:` list didn't declare. Re-scope the
|
|
27
|
-
task (re-run `yad-spec`) rather than widening the diff silently."
|
|
28
|
-
|
|
29
|
-
## Escalation / routing comment
|
|
30
|
-
|
|
31
|
-
- **routing** — "Risk is `high` / a contract|auth|payments surface is touched — this needs a
|
|
32
|
-
domain-owner approval per touched repo (the same escalation `yad-review-gate` applies). Run
|
|
33
|
-
`bash checks/risk-route.sh <body>` (code repo) or `bash checks/hub-route.sh <body>` (hub)."
|
|
34
|
-
|
|
35
|
-
## Non-blocking comments
|
|
36
|
-
|
|
37
|
-
- **suggestion** — "Suggestion (non-blocking): …"
|
|
38
|
-
- **nit** — "Nit: …"
|
|
39
|
-
- **question** — "Question: … (not blocking — just want to understand)."
|
|
40
|
-
|
|
41
|
-
## Approval note
|
|
42
|
-
|
|
43
|
-
- **approve** — "Approving as `<role>`. Recorded in `approvals.json` (code-repo ship: `build-log.json`).
|
|
44
|
-
On the hub, your approval here is pulled in by `yad-review-gate action: sync`."
|
|
45
|
-
|
|
46
|
-
## Hub front-artifact review
|
|
47
|
-
|
|
48
|
-
The hub scaffold adds a **Front-artifact review** section whose headers mirror the gate's comment file
|
|
49
|
-
exactly, so reviewing an `epic.md` / `architecture.md` / `ui-design.md` / `stories/` PR produces comments
|
|
50
|
-
that drop straight into `reviews/<artifact>--<date>--comments.md`:
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
**<name> (<role>)**
|
|
54
|
-
- <comment about scope / contract surface / acceptance signals / story split>
|
|
55
|
-
```
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# Review comments — canned replies
|
|
2
|
-
|
|
3
|
-
Copy a block below into a PR review comment. Keep the `**<name> (<role>)**` header — it matches the
|
|
4
|
-
SDLC review ledger (`reviews/<artifact>--<date>--comments.md`) so feedback stays attributable.
|
|
5
|
-
`<role>` is one of `owner | reviewer | domain-owner`.
|
|
6
|
-
|
|
7
|
-
## Blocking (a gate or rule says stop — must be fixed before merge)
|
|
8
|
-
|
|
9
|
-
**<name> (<role>)**
|
|
10
|
-
- spec-link: this range has no `Task: <story>-<task>` trailer — the spec-link gate will fail. Add the
|
|
11
|
-
trailer and make sure `specs/<story>/link.md` exists.
|
|
12
|
-
|
|
13
|
-
**<name> (<role>)**
|
|
14
|
-
- contract-check: this diff changes the contract surface without `Contract-Change: yes` + a re-locked
|
|
15
|
-
contract. Route back to the architecture gate and re-lock before merge.
|
|
16
|
-
|
|
17
|
-
**<name> (<role>)**
|
|
18
|
-
- build-test-lint: lint/build/test is red, or the test doesn't exercise the new behavior. The gate must
|
|
19
|
-
pass with a test that actually exercises the acceptance criterion.
|
|
20
|
-
|
|
21
|
-
**<name> (<role>)**
|
|
22
|
-
- file-boundary: this touches files the task's `Files:` list didn't declare. Re-scope the task (re-run
|
|
23
|
-
`yad-spec`) instead of widening the diff.
|
|
24
|
-
|
|
25
|
-
## Routing / escalation
|
|
26
|
-
|
|
27
|
-
**<name> (<role>)**
|
|
28
|
-
- routing: risk is `high` / a contract|auth|payments surface is touched — needs a domain-owner approval
|
|
29
|
-
per touched repo (same escalation as `yad-review-gate`). Run `bash checks/risk-route.sh <body>`.
|
|
30
|
-
|
|
31
|
-
## Non-blocking
|
|
32
|
-
|
|
33
|
-
**<name> (<role>)**
|
|
34
|
-
- Suggestion (non-blocking): …
|
|
35
|
-
|
|
36
|
-
**<name> (<role>)**
|
|
37
|
-
- Nit: …
|
|
38
|
-
|
|
39
|
-
**<name> (<role>)**
|
|
40
|
-
- Question: … (not blocking — just want to understand).
|
|
41
|
-
|
|
42
|
-
## Approval
|
|
43
|
-
|
|
44
|
-
**<name> (<role>)**
|
|
45
|
-
- Approving as `<role>`. Recorded in `approvals.json` (ship: `build-log.json`).
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
> Tip (GitHub): paste the blocks you use most into your personal **Saved Replies**
|
|
49
|
-
> (Settings → Saved replies) so they are one click away in any PR.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# Review comments — canned replies
|
|
2
|
-
|
|
3
|
-
Copy a block below into an MR review comment. Keep the `**<name> (<role>)**` header — it matches the
|
|
4
|
-
SDLC review ledger (`reviews/<artifact>--<date>--comments.md`) so feedback stays attributable.
|
|
5
|
-
`<role>` is one of `owner | reviewer | domain-owner`.
|
|
6
|
-
|
|
7
|
-
## Blocking (a gate or rule says stop — must be fixed before merge)
|
|
8
|
-
|
|
9
|
-
**<name> (<role>)**
|
|
10
|
-
- spec-link: this range has no `Task: <story>-<task>` trailer — the spec-link gate will fail. Add the
|
|
11
|
-
trailer and make sure `specs/<story>/link.md` exists.
|
|
12
|
-
|
|
13
|
-
**<name> (<role>)**
|
|
14
|
-
- contract-check: this diff changes the contract surface without `Contract-Change: yes` + a re-locked
|
|
15
|
-
contract. Route back to the architecture gate and re-lock before merge.
|
|
16
|
-
|
|
17
|
-
**<name> (<role>)**
|
|
18
|
-
- build-test-lint: lint/build/test is red, or the test doesn't exercise the new behavior. The gate must
|
|
19
|
-
pass with a test that actually exercises the acceptance criterion.
|
|
20
|
-
|
|
21
|
-
**<name> (<role>)**
|
|
22
|
-
- file-boundary: this touches files the task's `Files:` list didn't declare. Re-scope the task (re-run
|
|
23
|
-
`yad-spec`) instead of widening the diff.
|
|
24
|
-
|
|
25
|
-
## Routing / escalation
|
|
26
|
-
|
|
27
|
-
**<name> (<role>)**
|
|
28
|
-
- routing: risk is `high` / a contract|auth|payments surface is touched — needs a domain-owner approval
|
|
29
|
-
per touched repo (same escalation as `yad-review-gate`). Run `bash checks/risk-route.sh <body>`.
|
|
30
|
-
|
|
31
|
-
## Non-blocking
|
|
32
|
-
|
|
33
|
-
**<name> (<role>)**
|
|
34
|
-
- Suggestion (non-blocking): …
|
|
35
|
-
|
|
36
|
-
**<name> (<role>)**
|
|
37
|
-
- Nit: …
|
|
38
|
-
|
|
39
|
-
**<name> (<role>)**
|
|
40
|
-
- Question: … (not blocking — just want to understand).
|
|
41
|
-
|
|
42
|
-
## Approval
|
|
43
|
-
|
|
44
|
-
**<name> (<role>)**
|
|
45
|
-
- Approving as `<role>`. Recorded in `approvals.json` (ship: `build-log.json`).
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
> Tip (GitLab): paste the blocks you use most into your personal/group **Comment templates**
|
|
49
|
-
> (Preferences → Comment templates) so they are one click away in any MR.
|