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,10 +1,11 @@
|
|
|
1
|
-
# `yad-run` — the loop
|
|
1
|
+
# `yad-run` — the loop and the trust verdict
|
|
2
2
|
|
|
3
3
|
This is the detail behind `SKILL.md`. It restates the orchestration so the skill is self-contained,
|
|
4
|
-
and pins down the
|
|
5
|
-
|
|
4
|
+
and pins down the judgment the skill makes: **what trust verdict to record**. Whether a step advances on
|
|
5
|
+
its own is not a judgment any more — the team sets the dial with `yad dial` (E34), and the engine answers
|
|
6
|
+
what applies.
|
|
6
7
|
|
|
7
|
-
## The
|
|
8
|
+
## The Build steps
|
|
8
9
|
|
|
9
10
|
From `config.yaml` `automation.back_steps` plus the human merge gate:
|
|
10
11
|
|
|
@@ -12,68 +13,93 @@ From `config.yaml` `automation.back_steps` plus the human merge gate:
|
|
|
12
13
|
spec → tasks → implement → checks → engineer-review(locked)
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
`
|
|
16
|
+
**These names are the engine's DEFAULTS, not a fixed wiring.** Which skill runs a step is the
|
|
17
|
+
project's setting in `.sdlc/skills.json`, so the loop reads `yad skill list --json` once at Step 0 and
|
|
18
|
+
runs every entry of that step's `skills`, in order, when it is bound to more than one. Unbound: `spec` and `tasks` are the two legs of `yad-spec` (the heavy ceremony, then the atomic
|
|
19
|
+
`tasks.md`), `implement` is one atomic task via `yad-implement`, and `checks` is
|
|
20
|
+
`yad-checks (action: run)`. `engineer-review` is the human gate at `yad-engineer-review` — always a
|
|
21
|
+
stop, never automated, and bindable like any other step.
|
|
18
22
|
|
|
19
23
|
## The loop (pseudocode)
|
|
20
24
|
|
|
21
25
|
```
|
|
22
26
|
cfg = config.yaml.automation
|
|
23
|
-
bs = build-state/<story>.json.repos[<repo>] # create from defaults if absent
|
|
27
|
+
bs = build-state/<story>.json.repos[<repo>] # create the FILE from defaults if absent; if the file
|
|
28
|
+
# exists but has no entry for <repo>, add one from the
|
|
29
|
+
# defaults — never remove an entry you did not add
|
|
30
|
+
if bs.status == "skipped": # E39: the whole lane was set aside with
|
|
31
|
+
STOP — report bs.record.reason # `yad skip <epic> <story> --repo <repo>`; do not drive it.
|
|
32
|
+
# `yad unskip <epic> <story> --repo <repo>` puts it back.
|
|
33
|
+
# Never write a single Build step as skipped or deferred.
|
|
24
34
|
step = from or bs.currentStep
|
|
25
35
|
|
|
26
|
-
while step is a
|
|
27
|
-
result = run_step_skill(step) #
|
|
36
|
+
while step is a Build step (not engineer-review):
|
|
37
|
+
result = run_step_skill(step) # the skill(s) `yad next --json` names for this lane
|
|
28
38
|
|
|
29
39
|
signals = derive_signals(step, result) # see "Deriving signals"
|
|
30
40
|
verdict = derive_verdict(signals) # rejected | approved-with-edits | approved-unchanged
|
|
31
41
|
uid = fresh_short_token() # e.g. `openssl rand -hex 4` — unique per run,
|
|
32
42
|
# never reuse; a collision would fuse two runs
|
|
33
43
|
write trust-log/<story>-<repo>-<step>-<uid>.json # ONE shard file = ONE entry (never append to a shared file)
|
|
34
|
-
|
|
44
|
+
# `automation` is recorded in the OLD vocabulary (this is a history record, and `yad migrate`
|
|
45
|
+
# deliberately leaves it alone). Read the step's dial from EITHER spelling.
|
|
46
|
+
= { story, repo, step, uid, automation: bs.step.automation ?? old_name_for(bs.step.advance), verdict, signals, ranBy, date }
|
|
35
47
|
|
|
36
48
|
eff = effective_dial(step, bs, cfg) # see "Effective dial"
|
|
37
49
|
|
|
38
50
|
if result is a HALT (failed / scope overrun / contract touch / ambiguous):
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
bs.step.status = "
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
# `blocked` needs its `record` (E38) — that is what separates a halted lane from one that has
|
|
52
|
+
# simply not started. `reason` is the halt cause you already have in hand.
|
|
53
|
+
bs.step.status = "blocked"
|
|
54
|
+
bs.step.record = { reason: "<check FAIL | scope overrun | contract touch | ambiguous>",
|
|
55
|
+
by: "<platform login, else git user.name, or null>", date: "<YYYY-MM-DD>" }
|
|
56
|
+
persist; checkpoint; STOP and report the human action needed
|
|
57
|
+
elif eff == "auto":
|
|
58
|
+
bs.step.status = "done"
|
|
59
|
+
bs.step.closed = { by: "<platform login, else git user.name, or null>", date: "<YYYY-MM-DD>", via: "auto", run: uid }
|
|
60
|
+
advance bs.currentStep to next; persist; checkpoint; continue # Step B advance
|
|
61
|
+
else: # "human"
|
|
62
|
+
bs.step.status = "done"
|
|
63
|
+
bs.step.closed = { by: "<platform login, else git user.name, or null>", date: "<YYYY-MM-DD>", via: "human", run: uid }
|
|
64
|
+
persist; checkpoint; STOP and report "waiting for human at <next>"
|
|
44
65
|
|
|
45
66
|
# reached engineer-review: always stop, hand to yad-engineer-review (human gate, finalizes the verdict)
|
|
46
67
|
```
|
|
47
68
|
|
|
69
|
+
`closed` is the step's **closing record** (E18): who wrote it, when, and how the lane moved past the
|
|
70
|
+
step. `via: "auto"` means the dial let the run go on by itself; `via: "human"` means it stopped for a
|
|
71
|
+
person. `run` is the `uid` of the trust-log shard this run wrote, so the record points at the evidence.
|
|
72
|
+
`by` is the login `gh api user` / `glab api user` reports, else git `user.name`, else `null`
|
|
73
|
+
(`YAD_PLATFORM_LOGIN=0` turns the lookup off).
|
|
74
|
+
Write it only when you write `done`, and never over a `closed` already on the step.
|
|
75
|
+
|
|
48
76
|
`ranBy` is `machine` when the *previous* step's effective dial caused this step to run without a human
|
|
49
77
|
nudge; otherwise `human`. Persist build-state after every transition so a halt leaves an accurate,
|
|
50
78
|
resumable record.
|
|
51
79
|
|
|
52
80
|
`checkpoint` = run `yad checkpoint --push` from `{project-root}`. It commits the machine-written
|
|
53
|
-
|
|
81
|
+
Build ledgers (in this loop, the loose `trust-log/` shards this run wrote + `build-state/<story>.json`;
|
|
54
82
|
also the `build-log/` shards at engineer-review) — the shard dirs are what checkpoint stages, the same
|
|
55
83
|
way `git gc` folds loose objects later (`yad tidy up` folds finished shards into the folded
|
|
56
84
|
`trust-log.json` / `build-log.json`) — plus any story `status:` flip (→ in-build/shipped) once that
|
|
57
85
|
story has a build-log ship (#112) — as one
|
|
58
|
-
`chore(hub): sync
|
|
59
|
-
audit-trail commit, on the default branch only,
|
|
60
|
-
staging *only* those files by an explicit allowlist (never a
|
|
86
|
+
`chore(hub): sync Build state — <epic>/<story> by @<login> [skip ci]`
|
|
87
|
+
audit-trail commit (`@<login>` when the platform login is known, else the git `user.name`, else `unknown`), on the default branch only,
|
|
88
|
+
staging *only* those files by an explicit allowlist (never a Shape gate file — so `ledger-guard`
|
|
61
89
|
never trips). It is idempotent (a no-op when nothing changed), so calling it after every transition —
|
|
62
90
|
including a halt — is safe and keeps the shared trust evidence current for CI, teammates, and
|
|
63
91
|
`yad status` on other machines. It refuses to run off the default branch (an unsigned `[skip ci]`
|
|
64
92
|
commit inside a future PR range would fail `verified-commits` and strand the PR).
|
|
65
93
|
|
|
66
|
-
## Effective dial (kill switch
|
|
94
|
+
## Effective dial (the kill switch and gates always win)
|
|
67
95
|
|
|
68
96
|
```
|
|
69
|
-
eff =
|
|
70
|
-
if cfg.kill_switch == true: eff = "human_approve"
|
|
71
|
-
if bs.step.locked == true: eff = "human_approve"
|
|
72
|
-
if step in cfg.locked_steps: eff = "human_approve"
|
|
97
|
+
eff = (yad dial <epic> <story> --repo <repo> <step> --json).advance # "human" | "auto"
|
|
73
98
|
```
|
|
74
99
|
|
|
75
|
-
|
|
76
|
-
|
|
100
|
+
The engine reads the lane step's dial under either spelling (the OLD name wins), and answers `human`
|
|
101
|
+
when the step is a gate (`engineer-review`) or the kill switch in `.sdlc/automation.json` is on — whatever
|
|
102
|
+
the dial says. Its `why` says which: `lane`, `gate`, `kill` or `unknown` (a step id this release does not know), and `automationError` is present when the file cannot be read.
|
|
77
103
|
|
|
78
104
|
## Deriving signals & the provisional verdict
|
|
79
105
|
|
|
@@ -93,7 +119,7 @@ finalizes the entry — a human always has the last word on the trust signal.
|
|
|
93
119
|
- `contract_touch` — `true` if the diff touched the locked contract surface without an upstream
|
|
94
120
|
re-lock (routes back to the architecture gate).
|
|
95
121
|
|
|
96
|
-
`derive_verdict(signals)` — the same three-way shape for every
|
|
122
|
+
`derive_verdict(signals)` — the same three-way shape for every Build step:
|
|
97
123
|
```
|
|
98
124
|
edited = human_edited_diff or human_edited_spec or task_rescoped
|
|
99
125
|
if checks == "fail" or scope_overrun or contract_touch: verdict = "rejected"
|
|
@@ -106,35 +132,31 @@ may also override it to `rejected` — e.g. the human discards/regenerates the s
|
|
|
106
132
|
rejects the diff at the engineer review for a reason no signal captured. A human override always wins.
|
|
107
133
|
|
|
108
134
|
Rationale: the trust log should count an output as fully trustworthy (`approved-unchanged`) only when
|
|
109
|
-
the machine's work was accepted as-is. Any human correction is `approved-with-edits` (useful
|
|
110
|
-
|
|
135
|
+
the machine's work was accepted as-is. Any human correction is `approved-with-edits` (useful, and a sign
|
|
136
|
+
the step still wants a person); any failure or boundary breach is `rejected`.
|
|
111
137
|
|
|
112
|
-
## The
|
|
138
|
+
## The run record as advice (E34)
|
|
113
139
|
|
|
114
|
-
|
|
115
|
-
`config.yaml` `automation.trust_threshold`. `set-dial` enforces this predicate before flipping a step
|
|
116
|
-
to `machine_advance`:
|
|
140
|
+
`yad dial` prints a step's record when someone sets its dial, and whenever it is asked with no `--to`:
|
|
117
141
|
|
|
118
142
|
```
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
all = trust-log.json.runs + [read each file in trust-log/]
|
|
122
|
-
slice = entries in `all` for this step (this story's repo; widen to the project if you track it there)
|
|
143
|
+
all = trust-log.json.runs + [read each file in trust-log/] # UNION; every shard is a distinct run
|
|
144
|
+
slice = entries in `all` for this step in this repo
|
|
123
145
|
runs = len(slice)
|
|
124
146
|
unchanged = count(e.verdict == "approved-unchanged" in slice)
|
|
125
|
-
earned = runs >= trust_threshold.min_runs
|
|
126
|
-
AND (unchanged / runs) >= trust_threshold.min_approved_unchanged
|
|
127
147
|
```
|
|
128
148
|
|
|
129
|
-
|
|
130
|
-
|
|
149
|
+
It is **advice, never a rule.** There is no threshold and no refusal: the team decides whether a step
|
|
150
|
+
runs on auto, and the record is what they read to decide. A step with no runs says so — no evidence either
|
|
151
|
+
way is not evidence against.
|
|
131
152
|
|
|
132
|
-
Reverting (
|
|
153
|
+
Reverting (`--to human`) and the kill switch are always one move.
|
|
133
154
|
|
|
134
155
|
## What stays human, always
|
|
135
156
|
|
|
136
157
|
- `engineer-review` — the merge gate. `yad-run` always stops here and hands to `yad-engineer-review`.
|
|
137
|
-
- The
|
|
138
|
-
`
|
|
158
|
+
- The Shape steps — this loop never drives them. A Shape author step's dial may be set to auto for the
|
|
159
|
+
project (`yad dial <step> --to auto`), and is only recorded until the engine runs agents (E26); every
|
|
160
|
+
Shape review gate is a person.
|
|
139
161
|
- Any contract-surface change — halts the loop and routes back to the architecture gate, regardless of
|
|
140
162
|
the dial.
|
package/skills/yad-ship/SKILL.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yad-ship
|
|
3
|
-
description: 'Build
|
|
3
|
+
description: 'Build helper of the gated SDLC — commit AND open the task PR/MR in one step. A thin orchestration over yad-commit then yad-open-pr: commit the staged atomic change by the conventions (Conventional-Commits subject, Task → Contract-Change trailers, an OPTIONAL Co-Authored-By footer that is OFF by default and added only when --ai <id> is explicitly passed, ≤3-file atomic guard), then push the branch and open the PR/MR from the committed template, assigned to the logged-in gh/glab login with no reviewers requested. The PR step runs ONLY if the commit lands (a failed commit, tripped guard, or --dry-run stops before pushing). Drives the `yad ship` CLI; never merges. Use when the user says "ship this task", "commit and open the PR", or "commit and raise the MR". (For the engineer review + merge, use yad-engineer-review.)'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# SDLC — Commit + Open PR/MR (
|
|
6
|
+
# SDLC — Commit + Open PR/MR (Build helper)
|
|
7
7
|
|
|
8
|
-
**Goal:** Do the two routine
|
|
8
|
+
**Goal:** Do the two routine Build hand-actions for ONE atomic task in a single step — **commit by
|
|
9
9
|
convention, then open the task PR/MR** — so an implemented diff becomes a reviewable PR/MR without two
|
|
10
10
|
separate invocations. It is a thin wrapper over `yad-commit` and `yad-open-pr`; it holds no logic of
|
|
11
11
|
its own and **never merges**. The engineer review + merge are Step E (`yad-engineer-review`).
|
|
@@ -19,12 +19,12 @@ its own and **never merges**. The engineer review + merge are Step E (`yad-engin
|
|
|
19
19
|
`Task → Contract-Change → Co-Authored-By` (the footer **off by default** — added only via an explicit
|
|
20
20
|
`--ai`), the ≤3-file atomic guard (`../yad-commit/SKILL.md`).
|
|
21
21
|
- PR/MR: pushed branch, the committed template prefilled, title defaulting to the commit subject,
|
|
22
|
-
|
|
22
|
+
the assignee set and no reviewers requested, risk routing (`../yad-open-pr/SKILL.md`).
|
|
23
23
|
- **Order matters:** the PR/MR is opened **only if the commit lands**. A failed commit, a tripped
|
|
24
24
|
atomic guard, or `--dry-run` stops the step before anything is pushed.
|
|
25
|
-
- **Stage-aware on the
|
|
26
|
-
|
|
27
|
-
other
|
|
25
|
+
- **Stage-aware on the Product** (via `yad-open-pr`): on a `review/EP-*` branch `ship` opens the
|
|
26
|
+
Shape **artifact-review** PR (delegating to `yad gate open` — `--title` is ignored); on any
|
|
27
|
+
other Product branch it opens the **code-task** PR from the bundled code-task template. In a code repo
|
|
28
28
|
it is unchanged.
|
|
29
29
|
|
|
30
30
|
## Inputs
|
|
@@ -33,11 +33,11 @@ its own and **never merges**. The engineer review + merge are Step E (`yad-engin
|
|
|
33
33
|
- `ai` — co-author footer: `claude|copilot|cursor|coderabbit|none` (default `none` = **no
|
|
34
34
|
footer**; the `Co-Authored-By` trailer appears only when this flag names a tool).
|
|
35
35
|
- `task` — Task trailer (optional; derived from the branch when omitted).
|
|
36
|
-
- `contractChange` — flag; marks the contract surface touched (commit trailer + PR
|
|
36
|
+
- `contractChange` — flag; marks the contract surface touched (commit trailer + a raised approver count on the PR).
|
|
37
37
|
- `repo` / `risk` / `platform` / `title` — PR/MR options (see `yad-open-pr`).
|
|
38
38
|
- `base` — override the PR/MR base. The default is the repo's own default branch, resolved
|
|
39
39
|
by the full chain in **Base branch** (`yad-open-pr`) — the canonical description, including the
|
|
40
|
-
|
|
40
|
+
Product rung — never a hardcoded `main`. A non-default base loses the AI first pass; `ship` warns and
|
|
41
41
|
still opens.
|
|
42
42
|
|
|
43
43
|
## On Activation
|
|
@@ -53,12 +53,16 @@ yad ship --type <type> -m "<subject>" [--ai <id>] [--task <id>] [--contract-chan
|
|
|
53
53
|
[--repo <name>] [--risk <level>] [--title "<subject>"]
|
|
54
54
|
```
|
|
55
55
|
The CLI runs `yad commit` and, only if it succeeds, `yad open-pr` — committing the change, pushing the
|
|
56
|
-
branch, and opening the PR/MR with the template prefilled and reviewers
|
|
56
|
+
branch, and opening the PR/MR with the template prefilled and the assignee set. No reviewers are
|
|
57
|
+
requested: it prints `no reviewers were requested — ask them on the PR itself`.
|
|
57
58
|
|
|
58
59
|
### Step 3 — Route + stop (no merge)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
the
|
|
60
|
+
The open step prints how many approvers the PR asks for — the body's level and the base branch's risk
|
|
61
|
+
map, the larger step winning (E66). When it asks for more than one, `bash checks/risk-route.sh "<pr body>"`
|
|
62
|
+
lists the touched domains to ask; ask reviewers on the PR/MR itself. It also prints a reviewer
|
|
63
|
+
**suggestion** (E68): who has committed in the touched folders in the last 30 days, and what CODEOWNERS
|
|
64
|
+
lists — a hint about who may know the code, never a request and never a list of owners. Report the commit + the PR/MR URL. The PR now
|
|
65
|
+
runs the check gates (Step C); the engineer review and merge are Step E (`yad-engineer-review`).
|
|
62
66
|
|
|
63
67
|
## Hard rules
|
|
64
68
|
|
|
@@ -67,7 +71,7 @@ the engineer review and merge are Step E (`yad-engineer-review`).
|
|
|
67
71
|
- **No AI footer by default.** The wrapped commit writes a `Co-Authored-By` trailer ONLY when `--ai <id>`
|
|
68
72
|
is explicitly passed; never add it on the AI's own initiative.
|
|
69
73
|
- **No PR without a landed commit.** A failed/`--dry-run` commit stops the step before pushing.
|
|
70
|
-
- **High risk
|
|
74
|
+
- **High risk raises the approver count** — the same count as the gate.
|
|
71
75
|
- **Shipping here never merges.** The human owns the merge in `yad-engineer-review`.
|
|
72
76
|
|
|
73
77
|
## Reference
|
package/skills/yad-spec/SKILL.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yad-spec
|
|
3
|
-
description: 'Build
|
|
3
|
+
description: 'Build Step A of the gated SDLC. For one ready-for-build story and one of its repos, run the heavy Spec Kit ceremony ONCE (specify → clarify → plan → analyze → checklist → tasks) inside that code repo, writing specs/<story-id>/ in Spec Kit''s own layout. Drives /speckit.* as harness slash-commands when installed; authors the same files by hand and records speckit: not-installed when absent. References the locked contract — never re-invents the surface. Writes link.md back to the story. Never auto-advances. Use when the user says "spec story <id> in <repo>" or after a story is ready-for-build.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# SDLC — Author Spec (
|
|
6
|
+
# SDLC — Author Spec (Build Step A)
|
|
7
7
|
|
|
8
8
|
**Goal:** Turn ONE `ready-for-build` story into a per-repo Spec Kit spec/plan/tasks inside that
|
|
9
9
|
story's code repo. The heavy spec ceremony runs **once per story per repo**; the light
|
|
10
10
|
tasks → implement loop is **Step B** (`yad-implement`). This step **never re-locks the contract** —
|
|
11
11
|
the cross-repo surface is owned upstream by the architecture gate (build plan §A, Cross-cutting
|
|
12
|
-
"Heavy spec once per story, light loop per task"). It does not advance the
|
|
12
|
+
"Heavy spec once per story, light loop per task"). It does not advance the Shape state machine;
|
|
13
13
|
when driven by the orchestrator (`yad-run`, Phase 4) it records a `spec`/`tasks` trust signal
|
|
14
|
-
(Step 8) — but it never auto-advances a contract change or a
|
|
14
|
+
(Step 8) — but it never auto-advances a contract change or a Shape step.
|
|
15
15
|
|
|
16
16
|
Spec Kit is driven as **harness slash-commands** (`/speckit.*`), not a subprocess CLI (Phase 0
|
|
17
17
|
Deviation 3). When Spec Kit is not installed, the same files are hand-authored in Spec Kit's exact
|
|
@@ -30,7 +30,7 @@ is the same graceful-degradation pattern `yad-ui` uses for Impeccable.
|
|
|
30
30
|
`specs/<story-id>/`.
|
|
31
31
|
- Spec Kit output layout (RESEARCH-NOTES §2): `specs/<feature-id>/spec.md` (+ `research.md`,
|
|
32
32
|
`data-model.md`, `contracts/`), `plan.md`, `tasks.md`; constitution at `.specify/memory/constitution.md`.
|
|
33
|
-
- Speak in the
|
|
33
|
+
- Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
|
|
34
34
|
|
|
35
35
|
## Inputs
|
|
36
36
|
|
|
@@ -43,11 +43,10 @@ is the same graceful-degradation pattern `yad-ui` uses for Impeccable.
|
|
|
43
43
|
|
|
44
44
|
### Step 1 — Resolve the story and check readiness
|
|
45
45
|
Read `{project-root}/epics/<epic>/.sdlc/state.json`. Proceed only when
|
|
46
|
-
`currentStep == "ready-for-build"` (the gating
|
|
47
|
-
The **`test-cases` track may still be `in_progress`**: it is parallel and non-blocking, so the
|
|
48
|
-
half runs alongside it — its status does not affect readiness here. Read the story file
|
|
46
|
+
`currentStep == "ready-for-build"` (the gating Shape — through the **stories** gate — is `done`).
|
|
47
|
+
The **`test-cases` track may still be `in_progress`**: it is parallel and non-blocking, so Build runs alongside it — its status does not affect readiness here. Read the story file
|
|
49
48
|
`epics/<epic>/stories/<story>.md`; confirm `repo` is in its `repos`. If the epic is not ready, STOP
|
|
50
|
-
and point the user at `yad-status`. **Do not mutate
|
|
49
|
+
and point the user at `yad-status`. **Do not mutate Shape state** — `ready-for-build` semantics
|
|
51
50
|
stay intact.
|
|
52
51
|
|
|
53
52
|
### Step 2 — Resolve the target code repo
|
|
@@ -60,7 +59,20 @@ Read `epics/<epic>/contract.md` and `epics/<epic>/.sdlc/contract-lock.json`. The
|
|
|
60
59
|
inputs (the API shapes, data-model entities, and events the story touches) are **quoted from the
|
|
61
60
|
locked surface**, not re-authored. The spec MUST stay within that surface. If the story needs surface
|
|
62
61
|
the contract does not define, STOP and route back to the **architecture gate** — never extend the
|
|
63
|
-
contract here.
|
|
62
|
+
contract here. (On a route that HAS one; the short lanes do not — see below.)
|
|
63
|
+
|
|
64
|
+
- **Short-lane-safe:** read `epics/<epic>/.sdlc/state.json`'s `profile` first (an epic seeded before
|
|
65
|
+
file shape 6 has no such key — fall back to what its `steps[]` contains). On the `chore` and
|
|
66
|
+
`spike` routes there is no architecture step, so `contract.md` and `contract-lock.json` **never
|
|
67
|
+
exist** — that is the route's design, not a missing file to chase. Write the spec from the story and
|
|
68
|
+
`epic.md` alone, record `contract-lock: none` in Step 6's frontmatter, and say in the spec that this
|
|
69
|
+
epic defines no contract surface.
|
|
70
|
+
- A short lane has no architecture gate to route back to. So the rule above becomes stricter, not
|
|
71
|
+
looser: if the story turns out to need the shared cross-repo surface to CHANGE, **STOP and escalate
|
|
72
|
+
to a human** — the work belongs to a new epic on `classic`. Do not write the change into a spec on a
|
|
73
|
+
short lane. Do not create `specs/<story>/contracts/` at all on one — a short-lane story has no
|
|
74
|
+
surface to quote, and a slice folder under a lockless epic is what the CI gate refuses. (If one
|
|
75
|
+
already exists, a commit that only DELETES it is allowed through, which is the way back out.)
|
|
64
76
|
|
|
65
77
|
### Step 4 — Detect Spec Kit
|
|
66
78
|
Check for `/speckit.*` slash-commands and/or `demo-repos/<repo>/.specify/`. Record the result for
|
|
@@ -84,17 +96,19 @@ to read. See `references/spec-handoff.md` for the exact file map and per-file de
|
|
|
84
96
|
Write `demo-repos/<repo>/specs/<story>/link.md` (template in `references/spec-handoff.md`) with
|
|
85
97
|
frontmatter linking the spec back to the product repo: `story`, `epic`, `repo`, `feature-id`,
|
|
86
98
|
`product-repo` (path), `contract-lock` (the hash **copied** from `contract-lock.json`, NOT recomputed
|
|
87
|
-
in the code repo
|
|
99
|
+
in the code repo — or the literal `none` on a short-lane epic, which has no lock; never a made-up or
|
|
100
|
+
empty hash, which the CI gate reads as a broken lock and fails), `speckit`
|
|
101
|
+
(`installed | not-installed`), `generated` (date). This `link.md` plus the
|
|
88
102
|
spec folder is the authoritative record that this story's spec exists.
|
|
89
103
|
|
|
90
|
-
### Step 7 — Stop (
|
|
104
|
+
### Step 7 — Stop (Shape state untouched)
|
|
91
105
|
Report: the spec folder path, the files written, whether Spec Kit was used, the task count from
|
|
92
106
|
`tasks.md`, and that the next action is **Step B — `yad-implement`**. Do **not** edit the epic's
|
|
93
|
-
`state.json`, `approvals.json`, or `contract-lock.json`. Step A is a generation step, not a
|
|
107
|
+
`state.json`, `approvals.json`, or `contract-lock.json`. Step A is a generation step, not a Shape gate.
|
|
94
108
|
|
|
95
109
|
### Step 8 — Record the `spec` trust signal (Phase 4b)
|
|
96
|
-
When this step runs under the orchestrator (`yad-run`), the generated spec is a
|
|
97
|
-
trust log measures (
|
|
110
|
+
When this step runs under the orchestrator (`yad-run`), the generated spec is a Build run that the
|
|
111
|
+
trust log measures (part of the run record `yad dial` shows beside the `spec` dial). The
|
|
98
112
|
verdict is **anchored to the human who accepts the spec**, never self-graded:
|
|
99
113
|
- the human approves the generated `specs/<story>/` untouched → `approved-unchanged`;
|
|
100
114
|
- the human edits the spec/plan/tasks before accepting → `approved-with-edits` (signal
|
|
@@ -105,8 +119,8 @@ pattern as the engineer review finalizing `implement` at `yad-engineer-review`).
|
|
|
105
119
|
entry in its own shard `epics/<epic>/.sdlc/trust-log/<story>-<repo>-spec-<uid>.json` (a fresh `uid` per
|
|
106
120
|
run; readers union the folded `trust-log.json` + the loose shards). Schema:
|
|
107
121
|
`../yad-epic/references/state-schema.md`. **Run standalone, no trust entry is written** — the
|
|
108
|
-
log measures orchestrated runs.
|
|
109
|
-
|
|
122
|
+
log measures orchestrated runs. The record is advice: the `spec` dial is
|
|
123
|
+
whatever the team sets with `yad dial`, and this step never changes it.
|
|
110
124
|
|
|
111
125
|
## Hard rules (build plan §A, Cross-cutting)
|
|
112
126
|
|
|
@@ -33,6 +33,7 @@ demo-repos/<repo>/specs/<story-id>/
|
|
|
33
33
|
research.md # decisions/unknowns resolved during clarify
|
|
34
34
|
data-model.md # entities/fields THIS repo implements (quoting the shared ones from the contract)
|
|
35
35
|
contracts/ # the API/event surface this repo implements (quoted from the locked contract)
|
|
36
|
+
# OMITTED ENTIRELY on a short-lane epic — see below
|
|
36
37
|
plan.md # technical approach for this repo
|
|
37
38
|
tasks.md # numbered atomic tasks (T01…), each scoped to the files it may touch
|
|
38
39
|
link.md # back-pointer to the story in the product repo (Step A adds this; not a Spec Kit file)
|
|
@@ -54,6 +55,11 @@ comes from the story's acceptance criteria and the **locked contract surface**
|
|
|
54
55
|
- **`contracts/`** — the slice of the API/event surface this repo implements, **quoted from the locked
|
|
55
56
|
`contract.md`** (e.g. `POST /orders` request/response). Add a one-line note that this is a quote of
|
|
56
57
|
the locked surface, not a new definition.
|
|
58
|
+
**Do NOT create this folder on a short-lane epic** (`profile: chore` or `spike`). Those routes have
|
|
59
|
+
no architecture step, so there is no locked `contract.md` to quote and no lock for CI to check the
|
|
60
|
+
quote against — the gate refuses a slice under a lockless epic. A short-lane story consumes the
|
|
61
|
+
shared surface through the code it calls; it never restates it. If one already exists, a commit
|
|
62
|
+
that only DELETES it is allowed through, which is the way back out.
|
|
57
63
|
- **`plan.md`** — the technical approach for this repo at story altitude (components, sequence,
|
|
58
64
|
test approach). No new cross-repo surface.
|
|
59
65
|
- **`tasks.md`** — numbered atomic tasks. Each task: an ID (`T01`, `T02`, …), a one-line goal, and an
|
|
@@ -69,7 +75,9 @@ epic: EP-<slug>
|
|
|
69
75
|
repo: <repo>
|
|
70
76
|
feature-id: EP-<slug>-S0N
|
|
71
77
|
product-repo: <path to the product repo — absolute, or relative to THIS file's dir (specs/<story>/)>
|
|
72
|
-
contract-lock: sha256:<hex copied from epics/EP-<slug>/.sdlc/contract-lock.json>
|
|
78
|
+
contract-lock: sha256:<hex copied from epics/EP-<slug>/.sdlc/contract-lock.json> # or the literal
|
|
79
|
+
# `none` on a short-lane epic, which has no lock. Never an empty or invented hash:
|
|
80
|
+
# CI reads an unparseable value as a broken lock and fails.
|
|
73
81
|
speckit: installed | not-installed
|
|
74
82
|
generated: <YYYY-MM-DD>
|
|
75
83
|
---
|
|
@@ -89,12 +97,16 @@ back to the architecture gate in the product repo — it is never widened from t
|
|
|
89
97
|
`product-repo` is the one field CI resolves on disk (contract-check, lineage-check, epic-open,
|
|
90
98
|
reconcile-debt all read it). Every gate resolves it the SAME way: an **absolute** path is used as-is; a
|
|
91
99
|
**relative** path is joined to this `link.md`'s own directory, `specs/<story>/` — `../../` climbs out
|
|
92
|
-
of the story dir and out of `specs/` to the code-repo root, so a
|
|
93
|
-
is `../../../<
|
|
100
|
+
of the story dir and out of `specs/` to the code-repo root, so a Product checked out beside the code repo
|
|
101
|
+
is `../../../<product-dir>`. A relative value that only resolves from the **repo root** still works too
|
|
94
102
|
(what contract-check historically did), so older `link.md` files keep gating. Write it as an
|
|
95
103
|
**unquoted scalar** — `"..."` or `'...'` is taken literally, and a leading `~`/`$VAR` is never
|
|
96
|
-
expanded. An unreachable path degrades the
|
|
97
|
-
them, and each one now says so in its output.
|
|
104
|
+
expanded. An unreachable path degrades the Product-reading gates to a PASS-with-note rather than failing
|
|
105
|
+
them, and each one now says so in its output. **Reachable-but-lockless is a different case and does
|
|
106
|
+
NOT degrade:** when the Product resolves and `epics/<epic>/.sdlc/` is there with no
|
|
107
|
+
`contract-lock.json` in it, a claimed `Contract-Change: yes` FAILS, because nothing exists for the
|
|
108
|
+
claim to be true of. That is the ordinary state of a short-lane epic, of a stub, and of a classic epic
|
|
109
|
+
that has not reached its architecture gate yet.
|
|
98
110
|
|
|
99
111
|
## Do not re-invent the contract
|
|
100
112
|
|