yadflow 1.0.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 +50 -0
- package/LICENSE +21 -0
- package/README.md +559 -0
- package/bin/sdlc.mjs +135 -0
- package/cli/commit.mjs +81 -0
- package/cli/epic-state.mjs +220 -0
- package/cli/gate.mjs +456 -0
- package/cli/lib.mjs +142 -0
- package/cli/manifest.mjs +119 -0
- package/cli/openpr.mjs +65 -0
- package/cli/plan.mjs +127 -0
- package/cli/platform.mjs +151 -0
- package/cli/reconcile.mjs +83 -0
- package/cli/repo.mjs +61 -0
- package/cli/setup.mjs +208 -0
- package/package.json +51 -0
- package/skills/sdlc/config.yaml +156 -0
- package/skills/sdlc/install.sh +51 -0
- package/skills/sdlc/module-help.csv +17 -0
- package/skills/sdlc-author-analysis/SKILL.md +136 -0
- package/skills/sdlc-author-architecture/SKILL.md +180 -0
- package/skills/sdlc-author-architecture/references/contract-format.md +72 -0
- package/skills/sdlc-author-epic/SKILL.md +154 -0
- package/skills/sdlc-author-epic/references/state-schema.md +187 -0
- package/skills/sdlc-author-stories/SKILL.md +109 -0
- package/skills/sdlc-author-stories/references/story-schema.md +46 -0
- package/skills/sdlc-author-ui/SKILL.md +113 -0
- package/skills/sdlc-backfill/SKILL.md +91 -0
- package/skills/sdlc-backfill/references/backfill.md +66 -0
- package/skills/sdlc-backfill/templates/checks/backfill-check.sh +42 -0
- package/skills/sdlc-checks/SKILL.md +138 -0
- package/skills/sdlc-checks/references/check-gates.md +168 -0
- package/skills/sdlc-checks/templates/checks/build-test-lint.sh +14 -0
- package/skills/sdlc-checks/templates/checks/contract-check.sh +62 -0
- package/skills/sdlc-checks/templates/checks/spec-link.sh +38 -0
- package/skills/sdlc-checks/templates/checks/verified-commits.sh +120 -0
- package/skills/sdlc-checks/templates/github/sdlc-checks.yml +45 -0
- package/skills/sdlc-checks/templates/github/sdlc-verified-commits.yml +22 -0
- package/skills/sdlc-checks/templates/gitlab/.gitlab-ci.yml +40 -0
- package/skills/sdlc-checks/templates/gitlab/gitlab-ci.include-root.yml +7 -0
- package/skills/sdlc-checks/templates/gitlab/sdlc-checks.gitlab-ci.yml +47 -0
- package/skills/sdlc-checks/templates/gitlab/sdlc-verified-commits.gitlab-ci.yml +21 -0
- package/skills/sdlc-connect-repos/SKILL.md +159 -0
- package/skills/sdlc-connect-repos/references/code-context.md +92 -0
- package/skills/sdlc-connect-repos/references/hub-config.md +77 -0
- package/skills/sdlc-connect-repos/references/repos-registry.md +62 -0
- package/skills/sdlc-hub-bridge/SKILL.md +119 -0
- package/skills/sdlc-hub-bridge/references/bridge.md +136 -0
- package/skills/sdlc-hub-bridge/references/login-roster.md +42 -0
- package/skills/sdlc-hub-bridge/templates/checks/hub-route.sh +50 -0
- package/skills/sdlc-hub-bridge/templates/github/sdlc-gate-sync.yml +63 -0
- package/skills/sdlc-hub-bridge/templates/gitlab/gitlab-ci.include-root.yml +7 -0
- package/skills/sdlc-hub-bridge/templates/gitlab/sdlc-gate-sync.gitlab-ci.yml +64 -0
- package/skills/sdlc-implement/SKILL.md +143 -0
- package/skills/sdlc-implement/references/implement-conventions.md +103 -0
- package/skills/sdlc-implement/templates/.gitmessage +17 -0
- package/skills/sdlc-pr-template/SKILL.md +86 -0
- package/skills/sdlc-pr-template/references/risk-routing.md +54 -0
- package/skills/sdlc-pr-template/templates/checks/risk-route.sh +44 -0
- package/skills/sdlc-pr-template/templates/github/pull_request_template.md +30 -0
- package/skills/sdlc-pr-template/templates/gitlab/merge_request_templates/Default.md +32 -0
- package/skills/sdlc-pr-template/templates/hub/github/pull_request_template.md +36 -0
- package/skills/sdlc-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +37 -0
- package/skills/sdlc-review-comments/SKILL.md +63 -0
- package/skills/sdlc-review-comments/references/comment-conventions.md +55 -0
- package/skills/sdlc-review-comments/templates/github/REVIEW_COMMENTS.md +49 -0
- package/skills/sdlc-review-comments/templates/gitlab/REVIEW_COMMENTS.md +49 -0
- package/skills/sdlc-review-gate/SKILL.md +196 -0
- package/skills/sdlc-review-gate/references/gating.md +79 -0
- package/skills/sdlc-run/SKILL.md +109 -0
- package/skills/sdlc-run/references/run-loop.md +121 -0
- package/skills/sdlc-ship/SKILL.md +86 -0
- package/skills/sdlc-ship/references/ship-and-record.md +67 -0
- package/skills/sdlc-ship/templates/.coderabbit.yaml +19 -0
- package/skills/sdlc-spec/SKILL.md +119 -0
- package/skills/sdlc-spec/references/spec-handoff.md +101 -0
- package/skills/sdlc-status/SKILL.md +92 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Gate predicate — details & worked example
|
|
2
|
+
|
|
3
|
+
## Reviewer rule
|
|
4
|
+
Let `A` = the set of `approved` records in `.sdlc/approvals.json` for this step.
|
|
5
|
+
|
|
6
|
+
- `owners = { a in A : a.role == "owner" }`
|
|
7
|
+
- `reviewers = { a in A : a.role == "reviewer" }` (distinct by `approver`)
|
|
8
|
+
- `domainOwners = { a in A : a.role == "domain-owner" }` (grouped by `a.domain`)
|
|
9
|
+
|
|
10
|
+
**Base pass:** `|owners| >= 1` AND `|reviewers| >= default_reviewers` (default `1`).
|
|
11
|
+
|
|
12
|
+
**Escalated pass** (step `risk_tags` ∩ `{contract, auth, payments}` ≠ ∅): base pass AND, for every
|
|
13
|
+
touched `domain`, `|domainOwners[domain]| >= 1`.
|
|
14
|
+
|
|
15
|
+
**Touched domains** are resolved from files, not hardcoded:
|
|
16
|
+
- Architecture+contract review: the touched domains are the epic's `repos` (every repo shares the
|
|
17
|
+
contract surface).
|
|
18
|
+
- Stories review: the touched domains are the **union of every story's `repos`** under `stories/`.
|
|
19
|
+
|
|
20
|
+
So one gate, two option-shapes:
|
|
21
|
+
- Epic / UI reviews: base rule (no risk tags, no per-repo routing).
|
|
22
|
+
- Architecture+contract review: escalated (`risk_tags: ["contract"]`) — owner + 1 reviewer + a
|
|
23
|
+
`domain-owner` for **each** repo in `epic.repos`. (A small team may have one engineer own several
|
|
24
|
+
repos — one person can supply several `domain-owner` records with different `domain` values.)
|
|
25
|
+
- Stories review: per-repo routing — owner + 1 reviewer + a `domain-owner` (the repo's engineer) for
|
|
26
|
+
**each** repo that appears in any story's `repos`.
|
|
27
|
+
|
|
28
|
+
## Staleness
|
|
29
|
+
An approval round is invalidated if the authored artifact was edited after the newest `approved`
|
|
30
|
+
record's date/round. When that happens, drop back to `comment` — reviewers must re-approve the new
|
|
31
|
+
content. This prevents "approve, then quietly change it" (build plan §5 spirit).
|
|
32
|
+
|
|
33
|
+
For the architecture+contract review there is a second, content-based staleness check: recompute the
|
|
34
|
+
SHA-256 of the contract-surface block and compare it to `.sdlc/contract-lock.json`. A mismatch means
|
|
35
|
+
the locked surface changed even if the file's mtime looks fine — approvals are stale, re-lock and
|
|
36
|
+
re-approve. (Hash recipe: `sdlc-author-architecture/references/contract-format.md`.)
|
|
37
|
+
|
|
38
|
+
## Worked example — epic gate
|
|
39
|
+
|
|
40
|
+
1. `action: open` → `reviews/epic--2026-06-04--comments.md` seeded; step `epic-review` set
|
|
41
|
+
`in_review`; `currentStep = epic-review`.
|
|
42
|
+
2. Reviewer *bob* leaves comments → captured in the comments file; owner *alice* (pm-assisted)
|
|
43
|
+
edits `epic.md`.
|
|
44
|
+
3. `action: approve` approver *alice* role *owner* → ledger entry added. Predicate re-evaluated:
|
|
45
|
+
`|owners|=1, |reviewers|=0` → **fails** (need 1 reviewer). Gate reports "missing: 1 reviewer".
|
|
46
|
+
4. `action: approve` approver *bob* role *reviewer* → ledger entry added. Predicate:
|
|
47
|
+
`|owners|=1, |reviewers|=1` → **base pass**.
|
|
48
|
+
5. `action: advance` → `epic-review.status=done`, `architecture.status=in_progress`,
|
|
49
|
+
`currentStep=architecture`. Gate reports the advance.
|
|
50
|
+
|
|
51
|
+
## Participation record (comments.json)
|
|
52
|
+
`approvals.json` answers "who approved"; `.sdlc/comments.json` answers "who reviewed/commented". The
|
|
53
|
+
gate appends a record per commenter per round on every `comment` action (the machine-readable
|
|
54
|
+
counterpart to the `reviews/*--comments.md` markdown). It does **not** feed the predicate — approvals
|
|
55
|
+
alone decide the gate — but it makes the `approved.md` roster's "Reviewed / commented by" section
|
|
56
|
+
attributable, and it is the same shape a future service or the platform bridge can write.
|
|
57
|
+
|
|
58
|
+
## Platform-backed input (the bridge)
|
|
59
|
+
When the hub has a platform (`.sdlc/hub.json`) and the bridge is enabled, reviewers can approve/comment
|
|
60
|
+
on a real PR/MR instead of (or as well as) the skill recording it directly. `action: sync`
|
|
61
|
+
(`sdlc-hub-bridge`) reads that platform state with the reviewer's own `gh`/`glab` and writes the **same**
|
|
62
|
+
`approvals.json` / `comments.json` / `reviews/*.md` records the manual path writes — bridge approvals
|
|
63
|
+
tagged `"source": "bridge"`. **The predicate above is unchanged**: it counts owner/reviewer/domain-owner
|
|
64
|
+
approvals regardless of how they were recorded.
|
|
65
|
+
|
|
66
|
+
- login → role via the roster; `domain-owner` derived when a roster `name` equals a repo's `domain_owner`
|
|
67
|
+
and that repo is a touched domain; an unmapped login is a plain `reviewer`, never promoted.
|
|
68
|
+
- `sync` is idempotent (upsert by `(step, approver, role, domain)`; supersede revoked; key comments on
|
|
69
|
+
comment id) and never touches **manual** approvals.
|
|
70
|
+
- The architecture+contract staleness rule applies to bridge approvals too: a re-lock discards bridge
|
|
71
|
+
approvals dated before the new lock.
|
|
72
|
+
- No platform / no CLI → the gate runs file-only with no error. Detail: `../sdlc-hub-bridge/references/bridge.md`.
|
|
73
|
+
|
|
74
|
+
## Why this shape
|
|
75
|
+
- Owner + 1 reviewer keeps review load low on a small team (design priority 2) while still requiring
|
|
76
|
+
a second pair of eyes (priority 1, code quality / production safety).
|
|
77
|
+
- Risk-based escalation spends scarce domain-owner attention only where a change can break a shared
|
|
78
|
+
surface (contract/auth/payments).
|
|
79
|
+
- Everything is a file, so a future service can drive the same gate by writing the same records.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdlc-run
|
|
3
|
+
description: 'Phase 4 (automation) — the orchestrator that makes the second dial real. Drives a story''s back-half loop (spec → tasks → implement → checks) in one code repo, reading each step''s automation dial from build-state: on machine_advance it advances on its own, on human_approve it stops for a human. Records every run in the trust log (the evidence base for earning automation). Realizes Step B: when checks is earned, a clean gate pass auto-advances to engineer-review; any failure, scope overrun, or contract-surface touch HALTS and pulls in a human. Also sets a step''s dial (gated by trust evidence) and flips the system-wide kill switch. Never advances a front state or the engineer review. Use when the user says "run the build half", "advance story <id>", "set the checks dial", or "kill switch".'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Run (Phase 4 orchestrator)
|
|
7
|
+
|
|
8
|
+
**Goal:** Be the **engine** that the `automation` dial finally drives. Until Phase 4 the dial was inert
|
|
9
|
+
config; this skill reads it and acts. For ONE story in ONE code repo, walk the back-half steps —
|
|
10
|
+
`spec → tasks → implement → checks → engineer-review` — and at each step either **advance on its own**
|
|
11
|
+
(dial `machine_advance`, step succeeded) or **stop for a human** (dial `human_approve`, or any halt
|
|
12
|
+
condition). Every run is recorded in the **trust log**, the evidence that earns a step its automation.
|
|
13
|
+
|
|
14
|
+
This is the most dangerous skill in the system, so it is built to **halt-and-escalate over guess**:
|
|
15
|
+
a failing check, ambiguity, a scope overrun, or a contract-surface touch stops the loop and pulls in a
|
|
16
|
+
human regardless of any dial. The **front states and the engineer review never auto-advance** — they
|
|
17
|
+
are not in `automation.back_steps` and `engineer-review` is `locked`.
|
|
18
|
+
|
|
19
|
+
Earned so far: **`checks`** (Step B, Phase 4a — safest, a gate's pass/fail was never human judgment)
|
|
20
|
+
and **`implement`** (Step D, Phase 4b — the `implement → check` hand-off; the scope/contract halts and
|
|
21
|
+
the engineer review still gate the merge). **`tasks`** (Step C) and `spec` have their dials and trust
|
|
22
|
+
hooks but stay `human_approve` until their own evidence clears the threshold — there is no historical
|
|
23
|
+
signal to seed them from, so they are earned only on real runs.
|
|
24
|
+
|
|
25
|
+
## Conventions
|
|
26
|
+
|
|
27
|
+
- `{project-root}` resolves from the project working directory — the **product** repo (source of
|
|
28
|
+
truth: it holds the story, the build-state, and the trust log).
|
|
29
|
+
- Code repos are separate git repos under `{project-root}/demo-repos/<repo>/`
|
|
30
|
+
(`config.yaml` `build.code_repos_root`). Operate inside them with absolute paths.
|
|
31
|
+
- Automation config is `skills/sdlc/config.yaml` → `automation:` (`back_steps`, `default`,
|
|
32
|
+
`trust_threshold`, `locked_steps`, `kill_switch`).
|
|
33
|
+
- Per-story build-half state: `epics/<epic>/.sdlc/build-state/<story-id>.json` (per repo).
|
|
34
|
+
- Trust ledger: `epics/<epic>/.sdlc/trust-log.json` (append-only). Schemas:
|
|
35
|
+
`../sdlc-author-epic/references/state-schema.md`.
|
|
36
|
+
- The orchestrator **calls the existing step skills unchanged** — `sdlc-spec` (A), `sdlc-implement`
|
|
37
|
+
(B), `sdlc-checks` (C). It owns only the *advance decision*, never what a step does.
|
|
38
|
+
|
|
39
|
+
## Inputs
|
|
40
|
+
|
|
41
|
+
- `epic` / `story` / `repo` — the story and code repo to drive (ask if not provided).
|
|
42
|
+
- `action` — `run` (default) | `set-dial` | `kill` | `unkill`.
|
|
43
|
+
- For `run`: optional `from` (the step id to start at; default the repo's `currentStep` in
|
|
44
|
+
build-state) and `task` (the atomic task id for the `implement`/`checks` legs).
|
|
45
|
+
- For `set-dial`: `step` (a `back_steps` id), `to` (`human_approve` | `machine_advance`).
|
|
46
|
+
|
|
47
|
+
## On Activation
|
|
48
|
+
|
|
49
|
+
### Step 0 — Load state
|
|
50
|
+
Read `config.yaml` `automation`, the story's `build-state/<story>.json` (create it from the
|
|
51
|
+
`back_steps` defaults if absent — all `human_approve`, `engineer-review` `locked:true`), and
|
|
52
|
+
`trust-log.json` (treat missing as `[]`). Resolve the code repo.
|
|
53
|
+
|
|
54
|
+
### `action: run` — drive the loop
|
|
55
|
+
Walk the steps for `repo` starting at `from`/`currentStep`. For each step:
|
|
56
|
+
|
|
57
|
+
1. **Run the step's skill** — `spec`→`sdlc-spec`, `tasks`→ the tasks leg of `sdlc-spec`,
|
|
58
|
+
`implement`→`sdlc-implement`, `checks`→`sdlc-checks (action: run)`. Capture its result.
|
|
59
|
+
2. **Derive trust signals & append a trust-log entry** (`ranBy: machine` if this advance was
|
|
60
|
+
automated, else `human`) — see `references/run-loop.md` for the derivation. Do this for *every*
|
|
61
|
+
step run, pass or fail; the log is the evidence base.
|
|
62
|
+
3. **Compute the effective dial.** Start from the step's `automation` in build-state, then **force it
|
|
63
|
+
to `human_approve`** if `automation.kill_switch` is true OR the step is `locked` OR the step id is
|
|
64
|
+
in `automation.locked_steps`. (So a kill switch or a lock always wins.)
|
|
65
|
+
4. **Decide:**
|
|
66
|
+
- **HALT** if the step failed — any check FAIL, a scope overrun (`sdlc-implement` stopped on the
|
|
67
|
+
file-boundary rule), a contract-surface touch, or any ambiguity. Set the step `status: blocked`,
|
|
68
|
+
write the `rejected` trust entry, **stop the loop**, and report what a human must resolve.
|
|
69
|
+
- else if effective dial is **`machine_advance`** → set the step `done`, advance `currentStep` to
|
|
70
|
+
the next step, and **continue the loop** (this is the Step B auto-advance for `checks`).
|
|
71
|
+
- else (**`human_approve`**) → set the step `done`/`in_review`, **stop** and report
|
|
72
|
+
"waiting for a human at `<next-step>`".
|
|
73
|
+
5. **Always stop at `engineer-review`** (it is `locked`): hand off to `sdlc-ship` for the human merge
|
|
74
|
+
gate, which finalizes the trust verdict (confirm/override the provisional one).
|
|
75
|
+
|
|
76
|
+
### `action: set-dial` — earn (or revert) a step's automation
|
|
77
|
+
Flip `step`'s `automation` to `to` in build-state. Enforce, in order:
|
|
78
|
+
- **Refuse** if `step` is in `automation.locked_steps` or is a front state or `engineer-review` —
|
|
79
|
+
these can never be `machine_advance` (front-state lock, build plan §E). Report the refusal reason.
|
|
80
|
+
- For `to: machine_advance`, **refuse unless the trust threshold is met**: the step's slice of
|
|
81
|
+
`trust-log.json` has `>= trust_threshold.min_runs` entries AND the fraction with
|
|
82
|
+
`verdict == "approved-unchanged"` is `>= trust_threshold.min_approved_unchanged`. If it is not met,
|
|
83
|
+
report the current evidence (runs, % unchanged) and how far short it is — "it seems fine" is not
|
|
84
|
+
evidence.
|
|
85
|
+
- `to: human_approve` is **always allowed** (reverting automation is one move, never gated).
|
|
86
|
+
|
|
87
|
+
### `action: kill` / `action: unkill` — the kill switch
|
|
88
|
+
Set `automation.kill_switch` to `true` (`kill`) or `false` (`unkill`) in `config.yaml`. While true,
|
|
89
|
+
**every** step's effective dial is `human_approve` system-wide — no per-step edits, instantly
|
|
90
|
+
reversible (build plan §Safety). Report the new state and that `sdlc-status` will show it.
|
|
91
|
+
|
|
92
|
+
## Hard rules (phase-4-build-plan.md)
|
|
93
|
+
|
|
94
|
+
- **Earned per step, with evidence.** A step goes `machine_advance` only after its trust log clears
|
|
95
|
+
the threshold; `set-dial` enforces it.
|
|
96
|
+
- **Reversible in one move.** `human_approve` is never gated; the kill switch reverts everything with
|
|
97
|
+
one command and no code change.
|
|
98
|
+
- **Halt-and-escalate beats guess.** A failing check, ambiguity, scope overrun, or contract-surface
|
|
99
|
+
touch halts the loop and pulls in a human, regardless of the dial.
|
|
100
|
+
- **Front states and the engineer review never auto-advance.** They are not in `back_steps`;
|
|
101
|
+
`engineer-review` is `locked`; the kill switch and locks always override the dial.
|
|
102
|
+
- **The orchestrator never changes what a step does** — it calls the existing skills and owns only the
|
|
103
|
+
advance decision and the trust record.
|
|
104
|
+
|
|
105
|
+
## Reference
|
|
106
|
+
- The loop, the trust-verdict derivation, and the threshold predicate: `references/run-loop.md`.
|
|
107
|
+
- State/trust schemas: `../sdlc-author-epic/references/state-schema.md`.
|
|
108
|
+
- The steps it drives: `../sdlc-spec/`, `../sdlc-implement/`, `../sdlc-checks/`; the human gate it
|
|
109
|
+
hands off to: `../sdlc-ship/`.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# `sdlc-run` — the loop, the trust verdict, the threshold
|
|
2
|
+
|
|
3
|
+
This is the detail behind `SKILL.md`. It restates the orchestration so the skill is self-contained,
|
|
4
|
+
and pins down the two judgments the skill makes: **what trust verdict to record** and **when a step
|
|
5
|
+
has earned `machine_advance`**.
|
|
6
|
+
|
|
7
|
+
## The back-half steps
|
|
8
|
+
|
|
9
|
+
From `config.yaml` `automation.back_steps` plus the human merge gate:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
spec → tasks → implement → checks → engineer-review(locked)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`spec` and `tasks` are the two legs of `sdlc-spec` (the heavy ceremony, then the atomic `tasks.md`).
|
|
16
|
+
`implement` is one atomic task via `sdlc-implement`. `checks` is `sdlc-checks (action: run)`.
|
|
17
|
+
`engineer-review` is the human gate at `sdlc-ship` — always a stop, never automated.
|
|
18
|
+
|
|
19
|
+
## The loop (pseudocode)
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
cfg = config.yaml.automation
|
|
23
|
+
bs = build-state/<story>.json.repos[<repo>] # create from defaults if absent
|
|
24
|
+
step = from or bs.currentStep
|
|
25
|
+
|
|
26
|
+
while step is a back step (not engineer-review):
|
|
27
|
+
result = run_step_skill(step) # sdlc-spec | sdlc-implement | sdlc-checks
|
|
28
|
+
|
|
29
|
+
signals = derive_signals(step, result) # see "Deriving signals"
|
|
30
|
+
verdict = derive_verdict(signals) # rejected | approved-with-edits | approved-unchanged
|
|
31
|
+
append trust-log entry { story, repo, step, automation: bs.step.automation,
|
|
32
|
+
verdict, signals, ranBy, date }
|
|
33
|
+
|
|
34
|
+
eff = effective_dial(step, bs, cfg) # see "Effective dial"
|
|
35
|
+
|
|
36
|
+
if result is a HALT (failed / scope overrun / contract touch / ambiguous):
|
|
37
|
+
bs.step.status = "blocked"; persist; STOP and report the human action needed
|
|
38
|
+
elif eff == "machine_advance":
|
|
39
|
+
bs.step.status = "done"; advance bs.currentStep to next; persist; continue # Step B advance
|
|
40
|
+
else: # human_approve
|
|
41
|
+
bs.step.status = "done"; persist; STOP and report "waiting for human at <next>"
|
|
42
|
+
|
|
43
|
+
# reached engineer-review: always stop, hand to sdlc-ship (human gate, finalizes the verdict)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`ranBy` is `machine` when the *previous* step's effective dial caused this step to run without a human
|
|
47
|
+
nudge; otherwise `human`. Persist build-state after every transition so a halt leaves an accurate,
|
|
48
|
+
resumable record.
|
|
49
|
+
|
|
50
|
+
## Effective dial (kill switch & locks always win)
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
eff = bs.step.automation # human_approve | machine_advance
|
|
54
|
+
if cfg.kill_switch == true: eff = "human_approve"
|
|
55
|
+
if bs.step.locked == true: eff = "human_approve"
|
|
56
|
+
if step in cfg.locked_steps: eff = "human_approve"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
So a kill switch, a `locked` flag, or membership in `locked_steps` forces a stop no matter what the
|
|
60
|
+
per-step dial says. `engineer-review` and the four front states are covered by `locked` / `locked_steps`.
|
|
61
|
+
|
|
62
|
+
## Deriving signals & the provisional verdict
|
|
63
|
+
|
|
64
|
+
`signals` are the raw facts of the run; the **provisional `verdict`** is derived from them. The human
|
|
65
|
+
gate for each step (the engineer review at `sdlc-ship` for `implement`; spec acceptance for `spec`;
|
|
66
|
+
first-consume for `tasks`; the gate itself for `checks`) later confirms or overrides the verdict and
|
|
67
|
+
finalizes the entry — a human always has the last word on the trust signal.
|
|
68
|
+
|
|
69
|
+
`signals` (only the relevant ones are set per step — see the table in
|
|
70
|
+
`../sdlc-author-epic/references/state-schema.md`):
|
|
71
|
+
- `checks` — `pass` | `fail` | `n/a` (only the `checks` step runs the three gates).
|
|
72
|
+
- `human_edited_diff` — `true` if a human changed the produced **diff** before merge (`implement`).
|
|
73
|
+
- `human_edited_spec` — `true` if a human edited the generated **spec/plan/tasks** before accepting (`spec`).
|
|
74
|
+
- `task_rescoped` — `true` if a task's declared `Files:`/scope was edited before implementing (`tasks`).
|
|
75
|
+
- `scope_overrun` — `true` if `sdlc-implement` stopped on the file-boundary rule (diff outside the
|
|
76
|
+
task's declared files).
|
|
77
|
+
- `contract_touch` — `true` if the diff touched the locked contract surface without an upstream
|
|
78
|
+
re-lock (routes back to the architecture gate).
|
|
79
|
+
|
|
80
|
+
`derive_verdict(signals)` — the same three-way shape for every back step:
|
|
81
|
+
```
|
|
82
|
+
edited = human_edited_diff or human_edited_spec or task_rescoped
|
|
83
|
+
if checks == "fail" or scope_overrun or contract_touch: verdict = "rejected"
|
|
84
|
+
elif edited: verdict = "approved-with-edits"
|
|
85
|
+
else: verdict = "approved-unchanged"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This is the **provisional** verdict from the recorded signals. The human gate that finalizes the entry
|
|
89
|
+
may also override it to `rejected` — e.g. the human discards/regenerates the spec or the task list, or
|
|
90
|
+
rejects the diff at the engineer review for a reason no signal captured. A human override always wins.
|
|
91
|
+
|
|
92
|
+
Rationale: the trust log should count an output as fully trustworthy (`approved-unchanged`) only when
|
|
93
|
+
the machine's work was accepted as-is. Any human correction is `approved-with-edits` (useful but not
|
|
94
|
+
yet trustworthy enough to automate); any failure or boundary breach is `rejected`.
|
|
95
|
+
|
|
96
|
+
## The trust threshold (when a step is earned)
|
|
97
|
+
|
|
98
|
+
A step is a **candidate** for `machine_advance` only when its trust evidence clears
|
|
99
|
+
`config.yaml` `automation.trust_threshold`. `set-dial` enforces this predicate before flipping a step
|
|
100
|
+
to `machine_advance`:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
slice = trust-log entries for this step (this story's repo; widen to the project if you track it there)
|
|
104
|
+
runs = len(slice)
|
|
105
|
+
unchanged = count(e.verdict == "approved-unchanged" in slice)
|
|
106
|
+
earned = runs >= trust_threshold.min_runs
|
|
107
|
+
AND (unchanged / runs) >= trust_threshold.min_approved_unchanged
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Defaults: `min_runs: 5`, `min_approved_unchanged: 0.8`. If `earned` is false, `set-dial` refuses and
|
|
111
|
+
reports `runs`, the `unchanged/runs` fraction, and how far short of the bar it is.
|
|
112
|
+
|
|
113
|
+
Reverting (`to: human_approve`) is never gated — automation must be reversible in one move.
|
|
114
|
+
|
|
115
|
+
## What stays human, always
|
|
116
|
+
|
|
117
|
+
- `engineer-review` — the merge gate. `sdlc-run` always stops here and hands to `sdlc-ship`.
|
|
118
|
+
- The four front states (`epic`, `architecture`, `ui-design`, `stories`) — not in `back_steps`, in
|
|
119
|
+
`locked_steps`; the dial-setter refuses them.
|
|
120
|
+
- Any contract-surface change — halts the loop and routes back to the architecture gate, regardless of
|
|
121
|
+
the dial.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdlc-ship
|
|
3
|
+
description: 'Build-half Step E of the gated SDLC — AI review, engineer review, then ship. Wire an advisory AI first-pass (CodeRabbit) on the PR/MR; record the human engineer review with the same human_approve discipline as the front gates (owner + 1 reviewer, escalating to domain owners on high risk / contract / auth / payments — the Step D routing); and on merge, record the ship in the epic build-log and update the story state so the epic → story → task → PR chain is traceable. Never auto-advances — the human owns the merge. Use when the user says "ship this task", "record the engineer review", or "wire the AI review".'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Review & Ship (build-half Step E)
|
|
7
|
+
|
|
8
|
+
**Goal:** Take a task PR/MR that has passed the **check gates** (Step C) through two sets of eyes and
|
|
9
|
+
out to production: an **AI first-pass** (advisory) and a **human engineer review** (the authority),
|
|
10
|
+
then **ship** — merge, record the ship, and update the story state. This is the last build-half step
|
|
11
|
+
(build plan §E). It is a **human gate**, the same `human_approve` discipline as the front states:
|
|
12
|
+
**nothing auto-advances**; the engineer owns the merge.
|
|
13
|
+
|
|
14
|
+
## Conventions
|
|
15
|
+
|
|
16
|
+
- `{project-root}` resolves from the project working directory — the **product** repo (the source of
|
|
17
|
+
truth: it holds the story and the build ledger).
|
|
18
|
+
- Code repos are separate git repos under `{project-root}/demo-repos/<repo>/`.
|
|
19
|
+
- The build ledger is `{project-root}/epics/<epic>/.sdlc/build-log.json` (append-only).
|
|
20
|
+
- The engineer-review rule reuses `sdlc-review-gate`: base = at least one `owner` AND one distinct
|
|
21
|
+
`reviewer`; **escalated** (the PR's Impact & Risk is `high`, or it touches contract/auth/payments) =
|
|
22
|
+
base PLUS one `domain-owner` per touched domain — the same routing `sdlc-pr-template`'s
|
|
23
|
+
`risk-route.sh` prints.
|
|
24
|
+
- AI review wiring: `templates/.coderabbit.yaml` → `<repo>/.coderabbit.yaml`.
|
|
25
|
+
|
|
26
|
+
## Inputs
|
|
27
|
+
|
|
28
|
+
- `epic` / `story` / `task` / `repo` — the PR under review (the task branch `feat/<story>-<task>-…`).
|
|
29
|
+
- `action` — `ai-review` | `approve` | `ship` (default `ai-review`).
|
|
30
|
+
- For `approve`: the reviewer `name` and `role` (`owner` | `reviewer` | `domain-owner`), and for a
|
|
31
|
+
domain owner the `domain`.
|
|
32
|
+
|
|
33
|
+
## On Activation
|
|
34
|
+
|
|
35
|
+
### Step 1 — `ai-review` (advisory first pass)
|
|
36
|
+
Ensure the AI reviewer is wired: copy `templates/.coderabbit.yaml` to `<repo>/.coderabbit.yaml` (commit
|
|
37
|
+
on the default branch if missing). CodeRabbit reviews each PR automatically and posts comments — it is
|
|
38
|
+
a **second set of eyes, never the authority**: it cannot approve or merge. Where CodeRabbit can't run
|
|
39
|
+
(no remote), run an equivalent AI first-pass by hand and capture its notes. Record that the AI review
|
|
40
|
+
ran; surface its findings to the engineer. Do **not** treat AI approval as a gate.
|
|
41
|
+
|
|
42
|
+
### Step 2 — `approve` (the engineer review — the human gate)
|
|
43
|
+
A human engineer reads the diff **against the spec** (`specs/<story>/`) and the acceptance criteria,
|
|
44
|
+
and records an approval. Determine the rule from the PR's Impact & Risk block (run
|
|
45
|
+
`../sdlc-pr-template/templates/checks/risk-route.sh` on the PR body): base, or escalated to a
|
|
46
|
+
domain-owner per touched domain. Record each approval; re-evaluate whether the rule is satisfied.
|
|
47
|
+
Recording an approval does **not** ship — shipping is a separate, explicit step. Front-half discipline:
|
|
48
|
+
the gate talks only through files; refuse to treat AI review as a human approval.
|
|
49
|
+
|
|
50
|
+
### Step 3 — `ship` (merge + record + update state)
|
|
51
|
+
Ship **iff ALL hold**: the check gates pass (Step C), the AI review has run (advisory), and the
|
|
52
|
+
engineer-review rule is satisfied (Step 2). Then:
|
|
53
|
+
- **Merge** the task branch into the repo's default branch (the human performs/authorises the merge).
|
|
54
|
+
- **Record the ship** — append to `epics/<epic>/.sdlc/build-log.json`:
|
|
55
|
+
```json
|
|
56
|
+
{ "story": "<story>", "task": "<task>", "repo": "<repo>", "branch": "feat/<story>-<task>-…",
|
|
57
|
+
"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>" }
|
|
60
|
+
```
|
|
61
|
+
- **Update the story state** — when **every** task in `specs/<story>/tasks.md` has a ship record, set
|
|
62
|
+
the story frontmatter `status: shipped`; otherwise `status: in-build`. The chain
|
|
63
|
+
**epic → story → task → PR → mergeCommit** is now traceable end to end.
|
|
64
|
+
- **Finalize the trust verdict (Phase 4).** If this story has a `build-state/<story>.json` (it ran
|
|
65
|
+
through `sdlc-run`), the engineer **confirms or overrides** the provisional trust verdict that the
|
|
66
|
+
orchestrator derived for this run, and the final verdict is written to
|
|
67
|
+
`epics/<epic>/.sdlc/trust-log.json`. The human has the last word on the trust signal: a diff merged
|
|
68
|
+
as authored is `approved-unchanged`; one the engineer edited before merge is `approved-with-edits`;
|
|
69
|
+
a rejected one is `rejected`. This is the evidence that later earns a step its `machine_advance`
|
|
70
|
+
(it never weakens the merge gate — the engineer still owns the merge).
|
|
71
|
+
|
|
72
|
+
### Step 4 — Stop
|
|
73
|
+
Report what shipped and the story's state. Do not advance anything else; the front-half `state.json`
|
|
74
|
+
stays as it was (`ready-for-build`). The build half is recorded in `build-log.json` + the story status.
|
|
75
|
+
|
|
76
|
+
## Hard rules (build plan §E, Cross-cutting)
|
|
77
|
+
|
|
78
|
+
- **AI review is advisory, never the authority.** Only a human engineer approval counts toward the gate.
|
|
79
|
+
- **High risk routes to domain owners** — the same escalation as `sdlc-review-gate` / `risk-route.sh`.
|
|
80
|
+
- **Ship only after gates + engineer review.** No gate skipped; the human owns the merge.
|
|
81
|
+
- **Nothing auto-advances.** Step E records human decisions in files; it never machine-advances.
|
|
82
|
+
|
|
83
|
+
## Reference
|
|
84
|
+
- The build ledger + story-state rules: `references/ship-and-record.md`.
|
|
85
|
+
- The escalation reused: `../sdlc-review-gate/SKILL.md`; the routing helper: `../sdlc-pr-template/`.
|
|
86
|
+
- The gates that must pass first: `../sdlc-checks/references/check-gates.md`.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Ship — the build ledger and the story state
|
|
2
|
+
|
|
3
|
+
Step E (`sdlc-ship`) closes the build half: AI review (advisory) → engineer review (the human gate) →
|
|
4
|
+
ship. Shipping records the merge and updates the story state so the whole chain is traceable.
|
|
5
|
+
|
|
6
|
+
## Two sets of eyes
|
|
7
|
+
|
|
8
|
+
1. **AI review (advisory).** CodeRabbit (`.coderabbit.yaml`) reviews each PR and comments. It is a
|
|
9
|
+
second set of eyes — it **never approves or merges**. Its findings inform the engineer; they do not
|
|
10
|
+
gate. Where CodeRabbit can't run (no remote), an equivalent AI first-pass is run by hand and its
|
|
11
|
+
notes captured.
|
|
12
|
+
2. **Engineer review (the authority).** A human reads the diff against the spec and the acceptance
|
|
13
|
+
criteria and records an approval. The rule is `sdlc-review-gate`'s:
|
|
14
|
+
- **base:** at least one `owner` AND one distinct `reviewer`.
|
|
15
|
+
- **escalated:** when the PR's Impact & Risk is `high`, or it touches contract/auth/payments — base
|
|
16
|
+
PLUS one `domain-owner` per touched domain (exactly what `risk-route.sh` prints).
|
|
17
|
+
|
|
18
|
+
## The build ledger — `epics/<epic>/.sdlc/build-log.json`
|
|
19
|
+
|
|
20
|
+
Append-only. One record per shipped task:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"epic": "EP-istifta-inquiries",
|
|
25
|
+
"ships": [
|
|
26
|
+
{
|
|
27
|
+
"story": "EP-istifta-inquiries-S01",
|
|
28
|
+
"task": "T01",
|
|
29
|
+
"repo": "backend",
|
|
30
|
+
"branch": "feat/EP-istifta-inquiries-S01-T01-create-inquiry",
|
|
31
|
+
"pr": "<url|#|local>",
|
|
32
|
+
"mergeCommit": "<sha>",
|
|
33
|
+
"gates": ["spec-link", "contract-check", "build-test-lint"],
|
|
34
|
+
"ai_review": "coderabbit (advisory)",
|
|
35
|
+
"engineer_review": [
|
|
36
|
+
{ "approver": "amelia", "role": "owner" },
|
|
37
|
+
{ "approver": "carol", "role": "reviewer" }
|
|
38
|
+
],
|
|
39
|
+
"risk": "low",
|
|
40
|
+
"shippedAt": "2026-06-06"
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This is the back-half analogue of the front half's `approvals.json` — files only, no hidden state, so a
|
|
47
|
+
future service can drive ship by writing the same records.
|
|
48
|
+
|
|
49
|
+
## Story state
|
|
50
|
+
|
|
51
|
+
The story frontmatter `status` reflects build progress:
|
|
52
|
+
|
|
53
|
+
- `in-build` — at least one, but not all, of the story's tasks (from `specs/<story>/tasks.md`) have ship
|
|
54
|
+
records.
|
|
55
|
+
- `shipped` — **every** task in `tasks.md` has a ship record.
|
|
56
|
+
|
|
57
|
+
So the chain is traceable both ways: from the epic down (`epic.md` → `stories/<story>.md` →
|
|
58
|
+
`tasks.md` → `build-log.json` ship → `mergeCommit`) and from a merge commit back up (its `Task:`
|
|
59
|
+
trailer → story → epic).
|
|
60
|
+
|
|
61
|
+
## Preconditions for ship (all required)
|
|
62
|
+
|
|
63
|
+
1. The three **check gates** pass (Step C) — re-run them on the PR branch if unsure.
|
|
64
|
+
2. The **AI review** has run (advisory; findings surfaced to the engineer).
|
|
65
|
+
3. The **engineer review** rule is satisfied (base or escalated per the Impact & Risk block).
|
|
66
|
+
|
|
67
|
+
Only then does the human merge and `sdlc-ship` record it. Nothing auto-advances.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# CodeRabbit — AI first-pass review (Phase 3 build plan §E).
|
|
2
|
+
# Advisory only: a second set of eyes that COMMENTS on every PR. It never approves or merges — the
|
|
3
|
+
# human engineer review (sdlc-review-gate discipline) owns that decision. See skills/sdlc-ship.
|
|
4
|
+
language: en
|
|
5
|
+
reviews:
|
|
6
|
+
request_changes_workflow: false # never block the merge — the engineer review is the gate
|
|
7
|
+
high_level_summary: true
|
|
8
|
+
review_status: true
|
|
9
|
+
poem: false
|
|
10
|
+
auto_review:
|
|
11
|
+
enabled: true
|
|
12
|
+
drafts: false
|
|
13
|
+
path_instructions:
|
|
14
|
+
- path: "src/**"
|
|
15
|
+
instructions: >-
|
|
16
|
+
Check the diff against the task's spec under specs/<story>/; flag any change that leaves the
|
|
17
|
+
files the task declared, or that alters the contract surface without Contract-Change.
|
|
18
|
+
chat:
|
|
19
|
+
auto_reply: true
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdlc-spec
|
|
3
|
+
description: 'Build-half 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
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Author Spec (build-half Step A)
|
|
7
|
+
|
|
8
|
+
**Goal:** Turn ONE `ready-for-build` story into a per-repo Spec Kit spec/plan/tasks inside that
|
|
9
|
+
story's code repo. The heavy spec ceremony runs **once per story per repo**; the light
|
|
10
|
+
tasks → implement loop is **Step B** (`sdlc-implement`). This step **never re-locks the contract** —
|
|
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 front-half state machine;
|
|
13
|
+
when driven by the orchestrator (`sdlc-run`, Phase 4) it records a `spec`/`tasks` trust signal
|
|
14
|
+
(Step 8) — but it never auto-advances a contract change or a front state.
|
|
15
|
+
|
|
16
|
+
Spec Kit is driven as **harness slash-commands** (`/speckit.*`), not a subprocess CLI (Phase 0
|
|
17
|
+
Deviation 3). When Spec Kit is not installed, the same files are hand-authored in Spec Kit's exact
|
|
18
|
+
layout and the spec is marked `speckit: not-installed` — the workflow does not block on the tool. This
|
|
19
|
+
is the same graceful-degradation pattern `sdlc-author-ui` uses for Impeccable.
|
|
20
|
+
|
|
21
|
+
## Conventions
|
|
22
|
+
|
|
23
|
+
- `{project-root}` resolves from the project working directory — the **product** repo (epic
|
|
24
|
+
"thinking" + per-epic `.sdlc/` state live here).
|
|
25
|
+
- **Code repos are separate git repos**, one `.git` each, under `{project-root}/demo-repos/<repo>/`
|
|
26
|
+
(`config.yaml` `build.code_repos_root`). All Spec Kit outputs land **inside the code repo**, never
|
|
27
|
+
in the product repo.
|
|
28
|
+
- `{feature-id}` is the **story ID** (e.g. `EP-istifta-inquiries-S01`) — **pinned**, never Spec Kit's
|
|
29
|
+
numbered auto-slug (which is unstable and severs the permanent story link). The spec folder is
|
|
30
|
+
`specs/<story-id>/`.
|
|
31
|
+
- Spec Kit output layout (RESEARCH-NOTES §2): `specs/<feature-id>/spec.md` (+ `research.md`,
|
|
32
|
+
`data-model.md`, `contracts/`), `plan.md`, `tasks.md`; constitution at `.specify/memory/constitution.md`.
|
|
33
|
+
- Speak in the configured `communication_language`; write documents in `document_output_language`.
|
|
34
|
+
|
|
35
|
+
## Inputs
|
|
36
|
+
|
|
37
|
+
- `epic` — the `EP-<slug>` to operate on (ask if not provided).
|
|
38
|
+
- `story` — the ONE story to spec, `EP-<slug>-S0N` (ask if not provided).
|
|
39
|
+
- `repo` — one entry from that story's `repos` (the ONE repo to spec; ask if the story lists more
|
|
40
|
+
than one).
|
|
41
|
+
|
|
42
|
+
## On Activation
|
|
43
|
+
|
|
44
|
+
### Step 1 — Resolve the story and check readiness
|
|
45
|
+
Read `{project-root}/epics/<epic>/.sdlc/state.json`. Proceed only when
|
|
46
|
+
`currentStep == "ready-for-build"` (the whole front half is `done`). Read the story file
|
|
47
|
+
`epics/<epic>/stories/<story>.md`; confirm `repo` is in its `repos`. If the epic is not ready, STOP
|
|
48
|
+
and point the user at `sdlc-status`. **Do not mutate front-half state** — `ready-for-build` semantics
|
|
49
|
+
stay intact.
|
|
50
|
+
|
|
51
|
+
### Step 2 — Resolve the target code repo
|
|
52
|
+
Map `repo` → `{project-root}/demo-repos/<repo>/`. Confirm it exists and is its own git repo
|
|
53
|
+
(`demo-repos/<repo>/.git` present). If missing, STOP and point the user at `demo-repos/README.md`
|
|
54
|
+
(how to regenerate the throwaway repo). Operate **inside this repo** with absolute paths.
|
|
55
|
+
|
|
56
|
+
### Step 3 — Read the contract (reference, do NOT re-invent)
|
|
57
|
+
Read `epics/<epic>/contract.md` and `epics/<epic>/.sdlc/contract-lock.json`. The spec's contract
|
|
58
|
+
inputs (the API shapes, data-model entities, and events the story touches) are **quoted from the
|
|
59
|
+
locked surface**, not re-authored. The spec MUST stay within that surface. If the story needs surface
|
|
60
|
+
the contract does not define, STOP and route back to the **architecture gate** — never extend the
|
|
61
|
+
contract here.
|
|
62
|
+
|
|
63
|
+
### Step 4 — Detect Spec Kit
|
|
64
|
+
Check for `/speckit.*` slash-commands and/or `demo-repos/<repo>/.specify/`. Record the result for
|
|
65
|
+
Step 6's frontmatter (`speckit: installed | not-installed`).
|
|
66
|
+
|
|
67
|
+
### Step 5 — Run the heavy ceremony ONCE (or degrade)
|
|
68
|
+
**Installed** — from inside `demo-repos/<repo>/`, drive, in order:
|
|
69
|
+
`/speckit.specify` → `/speckit.clarify` → `/speckit.plan` → `/speckit.analyze` →
|
|
70
|
+
`/speckit.checklist` → `/speckit.tasks`. **Pin the feature to `<story>`** (do not accept an
|
|
71
|
+
auto-slug). Seed `specify` from the story's acceptance criteria and the contract elements from Step 3.
|
|
72
|
+
`/speckit.constitution` and `/speckit.implement` are **out of scope for Step A** (implement is Step B).
|
|
73
|
+
|
|
74
|
+
**Not installed (degrade)** — hand-author the identical files in Spec Kit's layout under
|
|
75
|
+
`demo-repos/<repo>/specs/<story>/`: `spec.md`, `research.md`, `data-model.md`, `contracts/`,
|
|
76
|
+
`plan.md`, `tasks.md`. The content is what a real Spec Kit run would produce, traceable to the story's
|
|
77
|
+
acceptance criteria and the locked contract surface. `tasks.md` MUST be numbered atomic tasks (`T01…`),
|
|
78
|
+
each declaring the files it may touch, so Step B's "stay inside the declared files" rule has something
|
|
79
|
+
to read. See `references/spec-handoff.md` for the exact file map and per-file degradation rules.
|
|
80
|
+
|
|
81
|
+
### Step 6 — Write link.md back to the story
|
|
82
|
+
Write `demo-repos/<repo>/specs/<story>/link.md` (template in `references/spec-handoff.md`) with
|
|
83
|
+
frontmatter linking the spec back to the product repo: `story`, `epic`, `repo`, `feature-id`,
|
|
84
|
+
`product-repo` (path), `contract-lock` (the hash **copied** from `contract-lock.json`, NOT recomputed
|
|
85
|
+
in the code repo), `speckit` (`installed | not-installed`), `generated` (date). This `link.md` plus the
|
|
86
|
+
spec folder is the authoritative record that this story's spec exists.
|
|
87
|
+
|
|
88
|
+
### Step 7 — Stop (front-half state untouched)
|
|
89
|
+
Report: the spec folder path, the files written, whether Spec Kit was used, the task count from
|
|
90
|
+
`tasks.md`, and that the next action is **Step B — `sdlc-implement`**. Do **not** edit the epic's
|
|
91
|
+
`state.json`, `approvals.json`, or `contract-lock.json`. Step A is a generation step, not a front gate.
|
|
92
|
+
|
|
93
|
+
### Step 8 — Record the `spec` trust signal (Phase 4b)
|
|
94
|
+
When this step runs under the orchestrator (`sdlc-run`), the generated spec is a back-half run that the
|
|
95
|
+
trust log measures (it is the evidence that could later earn the `spec` step a `machine_advance`). The
|
|
96
|
+
verdict is **anchored to the human who accepts the spec**, never self-graded:
|
|
97
|
+
- the human approves the generated `specs/<story>/` untouched → `approved-unchanged`;
|
|
98
|
+
- the human edits the spec/plan/tasks before accepting → `approved-with-edits` (signal
|
|
99
|
+
`human_edited_spec: true`);
|
|
100
|
+
- the spec is rejected or the ceremony re-run → `rejected`.
|
|
101
|
+
`sdlc-run` records a provisional entry when the spec is generated; this acceptance finalizes it (same
|
|
102
|
+
pattern as the engineer review finalizing `implement` at `sdlc-ship`). Append the finalized entry to
|
|
103
|
+
`epics/<epic>/.sdlc/trust-log.json` (schema:
|
|
104
|
+
`../sdlc-author-epic/references/state-schema.md`). **Run standalone, no trust entry is written** — the
|
|
105
|
+
log measures orchestrated runs. `spec` stays `human_approve` until its slice clears the threshold;
|
|
106
|
+
this step only *gathers* the evidence, it does not flip the dial.
|
|
107
|
+
|
|
108
|
+
## Hard rules (build plan §A, Cross-cutting)
|
|
109
|
+
|
|
110
|
+
- **Heavy spec once per story, not per task.** specify/clarify/plan/analyze/checklist/tasks run once
|
|
111
|
+
per story per repo. Do not re-run the ceremony for each task.
|
|
112
|
+
- **Per-repo spec, shared contract.** Spec/plan/tasks live in the code repo; the contract stays
|
|
113
|
+
singular in the product repo. Never widen the contract surface from here.
|
|
114
|
+
- **Nothing auto-advances.** Step A generates files and stops; no state machine is advanced.
|
|
115
|
+
|
|
116
|
+
## Reference
|
|
117
|
+
- Command list, output map, degradation rules, link.md template: `references/spec-handoff.md`.
|
|
118
|
+
- Contract surface format + hash recipe: `../sdlc-author-architecture/references/contract-format.md`.
|
|
119
|
+
- Spec Kit facts and the slash-command-vs-CLI deviation: `RESEARCH-NOTES.md` §2 + Phase 3 decisions + Deviation 3.
|