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,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdlc-author-architecture
|
|
3
|
+
description: 'Front state 3 of the gated SDLC. With the architect, author architecture.md and the locked contract.md (the shared cross-repo surface), then hash-lock the contract surface into .sdlc/contract-lock.json. Reads epic.md as input. Never auto-advances — hands off to the team review gate (which escalates on the contract risk tag). Use when the user says "author the architecture" or after the epic gate passes.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Author Architecture + Contract (front state 3)
|
|
7
|
+
|
|
8
|
+
**Goal:** Produce a human-authored, AI-assisted `architecture.md` and the **locked** `contract.md`
|
|
9
|
+
for an approved epic, then record a hash-lock of the contract surface so a later contract-check can
|
|
10
|
+
detect drift. This is a **front state**: human-authored with AI assist, **never auto-advances**.
|
|
11
|
+
When both artifacts are drafted, control passes to `sdlc-review-gate`, which **escalates** this review
|
|
12
|
+
by default (the architecture step carries `risk_tags: ["contract"]`).
|
|
13
|
+
|
|
14
|
+
This skill enforces the build plan's core rules: all state lives in files; the contract holds only the
|
|
15
|
+
shared cross-repo surface at charter altitude; front steps stay locked to `human_approve`.
|
|
16
|
+
|
|
17
|
+
## Conventions
|
|
18
|
+
|
|
19
|
+
- `{project-root}` resolves from the project working directory.
|
|
20
|
+
- Artifacts live under `{project-root}/epics/EP-<slug>/` (build plan §6).
|
|
21
|
+
- Speak in the configured `communication_language`; write documents in `document_output_language`.
|
|
22
|
+
|
|
23
|
+
## On Activation
|
|
24
|
+
|
|
25
|
+
### Step 1 — Resolve the epic and check the gate
|
|
26
|
+
Resolve the `EP-<slug>` (ask if not provided). Read `{project-root}/epics/EP-<slug>/.sdlc/state.json`.
|
|
27
|
+
Only proceed when `currentStep == "architecture"` and that step's `status == "in_progress"` (the epic
|
|
28
|
+
review must already have passed). If not, stop and point the user at `sdlc-status` / the gate.
|
|
29
|
+
|
|
30
|
+
### Step 1b — Open the authoring branch
|
|
31
|
+
Open the architecture authoring branch `architecture/EP-<slug>` per the shared procedure
|
|
32
|
+
(`../sdlc-author-epic/references/state-schema.md` → "Authoring branches"): git-safe (skip with a note
|
|
33
|
+
if `{project-root}` is not a git work tree), check out the branch if it exists, else create it from the
|
|
34
|
+
hub's default branch. Author and commit `architecture.md` / `contract.md` / `contract-lock.json` on it.
|
|
35
|
+
This is **distinct** from the bridge's `review/…` branch.
|
|
36
|
+
|
|
37
|
+
### Step 2 — Read the epic as input context
|
|
38
|
+
Read `epic.md`. Note `repos` (the touched domains), the goal, scope, and acceptance signals. The
|
|
39
|
+
architecture must serve every repo listed in `repos`.
|
|
40
|
+
|
|
41
|
+
### Step 2b — Load existing-code context (make the brain code-aware)
|
|
42
|
+
Read the registry `{project-root}/.sdlc/repos.json` (`config.yaml` `code_context`). For **each repo in
|
|
43
|
+
`epic.repos`**, load the lightweight code-map `{project-root}/.sdlc/code-context/<repo>/code-map.md`
|
|
44
|
+
**and**, because this phase locks the contract, the full pack `.../pack.md` when you need depth on the
|
|
45
|
+
existing **endpoints, events, and data models**. This is the context that stops the architecture from
|
|
46
|
+
re-defining or contradicting what is already built. (`pack.md` is **not committed** — if it is absent
|
|
47
|
+
locally, regenerate it with `sdlc repo refresh <repo>`; the committed `code-map.md`
|
|
48
|
+
is always present.)
|
|
49
|
+
|
|
50
|
+
- **Greenfield-safe:** if `repos.json` is absent/empty, note "no repos connected" and proceed — design
|
|
51
|
+
from scratch as before.
|
|
52
|
+
- **Staleness:** if a repo's current HEAD ≠ its registry `syncedHead`, warn and suggest
|
|
53
|
+
`sdlc repo refresh <repo>` (a human decision — flag and stop, never auto-refresh); stamp
|
|
54
|
+
`code-context: stale` in the frontmatter.
|
|
55
|
+
- **Traceability:** record the loaded maps in the `code-context:` frontmatter of both `architecture.md`
|
|
56
|
+
and `contract.md`.
|
|
57
|
+
- For an area not in the code-map, do a live on-demand read (`sdlc-connect-repos`
|
|
58
|
+
`references/code-context.md`).
|
|
59
|
+
|
|
60
|
+
### Step 3 — Author the architecture (assist: architect)
|
|
61
|
+
Adopt the **architect** lens (`bmad-agent-architect`, Winston) and write
|
|
62
|
+
`{project-root}/epics/EP-<slug>/architecture.md` using EXACTLY this template:
|
|
63
|
+
|
|
64
|
+
```markdown
|
|
65
|
+
---
|
|
66
|
+
id: EP-<slug>
|
|
67
|
+
artifact: architecture
|
|
68
|
+
status: draft
|
|
69
|
+
owner: <inherit from epic.md owner> # the epic owner carries through; not retyped
|
|
70
|
+
repos: [<inherit from epic>]
|
|
71
|
+
code-context: { repos: [], loaded: <YYYY-MM-DD or none> } # code-maps cross-checked (Step 2b/4b)
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Overview
|
|
75
|
+
<!-- the shape of the solution across repos, 2-4 sentences -->
|
|
76
|
+
|
|
77
|
+
## Components by repo
|
|
78
|
+
<!-- one subsection per repo in `repos`; responsibilities at charter altitude -->
|
|
79
|
+
|
|
80
|
+
## Cross-repo flows
|
|
81
|
+
<!-- the key request/event flows that span repos -->
|
|
82
|
+
|
|
83
|
+
## Data ownership
|
|
84
|
+
<!-- which repo owns which entity/store -->
|
|
85
|
+
|
|
86
|
+
## Risks & decisions
|
|
87
|
+
<!-- notable trade-offs; anything that drove the contract surface -->
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Keep per-repo detail at responsibility altitude — implementation detail belongs in stories/specs, not
|
|
91
|
+
here.
|
|
92
|
+
|
|
93
|
+
### Step 4 — Author the locked contract (assist: architect)
|
|
94
|
+
Write `{project-root}/epics/EP-<slug>/contract.md`. The contract holds **only the shared cross-repo
|
|
95
|
+
surface**: API shape, events, and data model — at charter altitude, **no per-repo implementation
|
|
96
|
+
detail**. Wrap that surface in a single delimited block bounded by the exact markers
|
|
97
|
+
`<!-- CONTRACT-SURFACE:BEGIN -->` and `<!-- CONTRACT-SURFACE:END -->` so the hash-lock and the later
|
|
98
|
+
contract-check operate on a stable, unambiguous region. Use EXACTLY this template:
|
|
99
|
+
|
|
100
|
+
```markdown
|
|
101
|
+
---
|
|
102
|
+
id: EP-<slug>
|
|
103
|
+
artifact: contract
|
|
104
|
+
status: locked
|
|
105
|
+
repos: [<inherit from epic>]
|
|
106
|
+
code-context: { repos: [], loaded: <YYYY-MM-DD or none> } # not hashed — frontmatter sits outside CONTRACT-SURFACE
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
# Contract — EP-<slug>
|
|
110
|
+
|
|
111
|
+
> Shared cross-repo surface only. Charter altitude. Changing anything inside the
|
|
112
|
+
> CONTRACT-SURFACE block re-locks the hash and invalidates prior approvals.
|
|
113
|
+
|
|
114
|
+
<!-- CONTRACT-SURFACE:BEGIN -->
|
|
115
|
+
## API
|
|
116
|
+
<!-- endpoints: method + path + purpose; request/response shape at field level, no impl -->
|
|
117
|
+
|
|
118
|
+
## Events
|
|
119
|
+
<!-- event name + payload shape + producer/consumer repos -->
|
|
120
|
+
|
|
121
|
+
## Data model
|
|
122
|
+
<!-- shared entities + fields that cross a repo boundary -->
|
|
123
|
+
<!-- CONTRACT-SURFACE:END -->
|
|
124
|
+
|
|
125
|
+
## Notes
|
|
126
|
+
<!-- anything outside the surface: rationale, open questions (not hashed) -->
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Step 4b — Cross-check the surface against existing code (BEFORE locking)
|
|
130
|
+
Using the code-context loaded in Step 2b, compare the proposed `CONTRACT-SURFACE` against what the
|
|
131
|
+
connected repos **already expose** (their code-maps' endpoints / events / data models):
|
|
132
|
+
|
|
133
|
+
- If a proposed endpoint, event, or entity **collides with or duplicates** an existing one, do not
|
|
134
|
+
silently re-define it — either **reuse** the existing surface, or record the deliberate change in
|
|
135
|
+
`architecture.md` "Risks & decisions" (it will likely need a `Contract-Change` later).
|
|
136
|
+
- If the new surface **depends on** existing behaviour, name that dependency in "Cross-repo flows" /
|
|
137
|
+
"Risks & decisions" so stories build on it rather than rebuilding it.
|
|
138
|
+
- Reconcile every conflict **before** Step 5 — the hash locks whatever you settle on, so the surface
|
|
139
|
+
must already be consistent with the code when it is locked.
|
|
140
|
+
|
|
141
|
+
If no repos are connected (greenfield), skip this step.
|
|
142
|
+
|
|
143
|
+
### Step 5 — Lock the contract surface (hash)
|
|
144
|
+
Compute the SHA-256 of the **exact bytes between** the `CONTRACT-SURFACE:BEGIN` and
|
|
145
|
+
`CONTRACT-SURFACE:END` markers (the content between the markers, excluding the marker lines
|
|
146
|
+
themselves) and write `{project-root}/epics/EP-<slug>/.sdlc/contract-lock.json`:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{ "artifact": "contract.md", "hash": "sha256:<hex>", "lockedAt": "<YYYY-MM-DD>" }
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Canonicalization (so the hash round-trips): hash the surface region as written between the markers,
|
|
153
|
+
LF line endings, no leading/trailing blank-line normalization beyond what is in the file. Recompute
|
|
154
|
+
the same way later; if it differs, the contract surface changed. The reference command:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
awk '/CONTRACT-SURFACE:BEGIN/{f=1;next} /CONTRACT-SURFACE:END/{f=0} f' \
|
|
158
|
+
epics/EP-<slug>/contract.md | shasum -a 256
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
(See `references/contract-format.md` for the altitude rule and the exact hashing recipe.)
|
|
162
|
+
|
|
163
|
+
### Step 6 — Advance the authoring step (NOT the gate)
|
|
164
|
+
In `state.json`: set `architecture.status: "done"`, set `architecture-review.status: "in_review"`, and
|
|
165
|
+
set `currentStep: "architecture-review"`. Write `state.json`. Do **not** touch `approvals.json` — only
|
|
166
|
+
real reviewers approve, through the gate.
|
|
167
|
+
|
|
168
|
+
### Step 7 — Stop at the gate (do NOT advance)
|
|
169
|
+
Report: the paths to `architecture.md`, `contract.md`, and `contract-lock.json`; the contract hash;
|
|
170
|
+
and that the next action is **review** via `sdlc-review-gate`. Note that this review **escalates**
|
|
171
|
+
(risk tag `contract`): it needs owner + 1 reviewer **plus a domain owner for each touched repo**.
|
|
172
|
+
**Never record approval here.** Front states do not auto-advance. When the hub has a platform, the gate
|
|
173
|
+
opens a review PR on the hub (via `sdlc-hub-bridge`, labelled per touched repo) and
|
|
174
|
+
`sdlc-review-gate action: sync` pulls platform approvals/comments into the ledger; a contract re-lock
|
|
175
|
+
invalidates prior platform approvals too. Otherwise the review is recorded file-only.
|
|
176
|
+
|
|
177
|
+
## Reference
|
|
178
|
+
- Contract surface, altitude rule, and hashing recipe: `references/contract-format.md`.
|
|
179
|
+
- State schema and field meanings: `../sdlc-author-epic/references/state-schema.md`.
|
|
180
|
+
- Connecting code repos + the code-context cross-checked here: `../sdlc-connect-repos/SKILL.md`.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Contract surface — format, altitude, and hash-lock
|
|
2
|
+
|
|
3
|
+
The `contract.md` produced at front state 3 is the **single source of truth for the shared cross-repo
|
|
4
|
+
surface** of an epic. Phase 3's contract-check (not built yet) fails a PR when a repo drifts from this
|
|
5
|
+
surface. To make that check possible, the surface is delimited and hash-locked now.
|
|
6
|
+
|
|
7
|
+
## What goes in the surface (altitude rule)
|
|
8
|
+
|
|
9
|
+
Inside the `CONTRACT-SURFACE` block, and nowhere else:
|
|
10
|
+
|
|
11
|
+
- **API** — the endpoints that cross a repo boundary: method, path, purpose, and the request/response
|
|
12
|
+
shape at the field level. No handler logic, no per-repo framework detail.
|
|
13
|
+
- **Events** — event name, payload shape, and which repos produce/consume it.
|
|
14
|
+
- **Data model** — only entities/fields that cross a repo boundary (shared identifiers, shared
|
|
15
|
+
enums/status values). A field private to one repo does not belong here.
|
|
16
|
+
|
|
17
|
+
Charter altitude: describe the *shape of the agreement between repos*, not how any repo implements it.
|
|
18
|
+
Implementation detail belongs in stories and (Phase 3) Spec Kit specs, not in the contract.
|
|
19
|
+
|
|
20
|
+
Anything that is rationale, open questions, or non-binding notes goes **outside** the block (under
|
|
21
|
+
`## Notes`) so it can change without re-locking the hash.
|
|
22
|
+
|
|
23
|
+
## The delimited block
|
|
24
|
+
|
|
25
|
+
Exactly two marker lines bound the hashed region:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
<!-- CONTRACT-SURFACE:BEGIN -->
|
|
29
|
+
... hashed content ...
|
|
30
|
+
<!-- CONTRACT-SURFACE:END -->
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Only the content **between** the markers is hashed — the marker lines themselves are excluded. This
|
|
34
|
+
keeps the hash stable against edits to the surrounding prose, frontmatter, or notes.
|
|
35
|
+
|
|
36
|
+
## The hash-lock
|
|
37
|
+
|
|
38
|
+
Stored at `epics/EP-<slug>/.sdlc/contract-lock.json`:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{ "artifact": "contract.md", "hash": "sha256:<hex>", "lockedAt": "<YYYY-MM-DD>" }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Recipe (must round-trip)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
awk '/CONTRACT-SURFACE:BEGIN/{f=1;next} /CONTRACT-SURFACE:END/{f=0} f' \
|
|
48
|
+
epics/EP-<slug>/contract.md | tr -d '\r' | shasum -a 256
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- `awk` emits every line strictly between the two markers (the `next` after BEGIN skips the BEGIN
|
|
52
|
+
line; setting `f=0` on END stops before printing END).
|
|
53
|
+
- `tr -d '\r'` normalizes CRLF line endings to LF before hashing — the same surface must hash
|
|
54
|
+
identically no matter which platform last saved the file (the CLI normalizes the same way).
|
|
55
|
+
- `shasum -a 256` (BSD/macOS) or `sha256sum` (GNU/Linux) produce the same hex digest for identical
|
|
56
|
+
bytes. Prefix the digest with `sha256:` when writing the lock file.
|
|
57
|
+
- Round-trip property: hashing unchanged content twice yields the same digest; any edit inside the
|
|
58
|
+
block changes it. That is exactly the drift signal the Phase 3 check needs.
|
|
59
|
+
|
|
60
|
+
## Interaction with the review gate
|
|
61
|
+
|
|
62
|
+
- The `architecture-review` step carries `risk_tags: ["contract"]`, so `sdlc-review-gate` **escalates**
|
|
63
|
+
it: owner + 1 reviewer **plus** one `domain-owner` approval per repo in the epic's `repos`.
|
|
64
|
+
- **Staleness:** if the surface block is edited after approvals are recorded, the recomputed hash will
|
|
65
|
+
not match the lock — approvals are stale and the gate drops back to `comment`. Re-lock (Step 5 of the
|
|
66
|
+
skill) and re-approve.
|
|
67
|
+
|
|
68
|
+
## Why a hash (vs structured diff)
|
|
69
|
+
|
|
70
|
+
A hash is the smallest representation that proves "did the agreed surface change?" — which is all the
|
|
71
|
+
front half needs. A field-by-field structured diff is a Phase 3 concern (it tells you *what* drifted in
|
|
72
|
+
a failing PR); the lock established here is what that future check compares against.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdlc-author-epic
|
|
3
|
+
description: 'Front state for the epic in the gated SDLC. Shape a feature idea with the analyst (or read analysis.md when the optional analysis step already ran), then write the epic with the pm, into epic.md. The entry point when analysis is skipped: assigns the EP-<slug> ID and seeds .sdlc/ state. Never auto-advances — hands off to the team review gate. Use when the user says "start a new feature/epic" or "author an epic".'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SDLC — Author Epic (front state)
|
|
7
|
+
|
|
8
|
+
**Goal:** Produce a human-authored, AI-assisted `epic.md` for a new feature, and — when the epic is the
|
|
9
|
+
entry point — assign its stable `EP-<slug>` ID and initialise the per-epic state machine in `.sdlc/`.
|
|
10
|
+
This is a **front state**: human-authored with AI assist and **never auto-advances**. When the epic is
|
|
11
|
+
drafted, control passes to `sdlc-review-gate`.
|
|
12
|
+
|
|
13
|
+
**Two entry modes** (the optional `sdlc-author-analysis` step decides which):
|
|
14
|
+
- **Analysis ran** — `.sdlc/state.json` already exists with `currentStep == "epic"`. The epic **reads
|
|
15
|
+
`analysis.md`** as its shaped input and does not re-seed state.
|
|
16
|
+
- **Analysis skipped** (the default) — no `state.json` yet. The epic is the entry point: it shapes the
|
|
17
|
+
idea inline with the analyst, assigns `EP-<slug>`, and seeds the **8-step** chain.
|
|
18
|
+
|
|
19
|
+
This skill enforces the build plan's core rules: all state lives in files; IDs are generated by the
|
|
20
|
+
engine (never typed by hand); front steps are locked to `human_approve`.
|
|
21
|
+
|
|
22
|
+
## Conventions
|
|
23
|
+
|
|
24
|
+
- `{project-root}` resolves from the project working directory.
|
|
25
|
+
- Epic artifacts live under `{project-root}/epics/EP-<slug>/` (build plan §6).
|
|
26
|
+
- Speak in the configured `communication_language`; write documents in `document_output_language`.
|
|
27
|
+
|
|
28
|
+
## On Activation
|
|
29
|
+
|
|
30
|
+
### Step 1 — Determine the entry mode
|
|
31
|
+
Read `{project-root}/epics/EP-<slug>/.sdlc/state.json` if an epic is named, otherwise check whether one
|
|
32
|
+
exists for the idea.
|
|
33
|
+
|
|
34
|
+
- **Analysis ran** — `state.json` exists with `currentStep == "epic"` and the `epic` step
|
|
35
|
+
`status == "in_progress"` (the analysis review already passed). Skip **Step 3** (the ID is already
|
|
36
|
+
assigned) and **Step 5** (state is already seeded); take the *analysis-ran* branch of Step 2 (read
|
|
37
|
+
`analysis.md`) and run Step 5b to advance the authoring step.
|
|
38
|
+
- **Analysis skipped** (the default) — no `state.json`. The epic is the entry point: run Steps 2–5
|
|
39
|
+
(inline analyst shaping + ID assignment + seed) and **skip Step 5b**.
|
|
40
|
+
|
|
41
|
+
Either mode runs Step 3b (branch), Step 4 (write the epic), and Step 6 (stop at the gate).
|
|
42
|
+
|
|
43
|
+
If `state.json` exists but `currentStep != "epic"`, stop and point the user at `sdlc-status` / the gate.
|
|
44
|
+
|
|
45
|
+
### Step 2 — Shape the idea (assist: analyst) — or read the analysis
|
|
46
|
+
- **Analysis skipped:** ask the user for a one-line feature idea if not provided, then adopt the
|
|
47
|
+
**analyst** lens (`bmad-agent-analyst`, Mary) to pressure-test it: who is the user, what problem, what
|
|
48
|
+
signals success, what is out of scope. Keep it brief — this is shaping, not a PRD.
|
|
49
|
+
- **Analysis ran:** read `{project-root}/epics/EP-<slug>/analysis.md` (the analyst's discovery brief)
|
|
50
|
+
and carry its Recommendation / Scope framing forward — do not re-shape from scratch.
|
|
51
|
+
|
|
52
|
+
### Step 2b — Load existing-code context (make the brain code-aware)
|
|
53
|
+
Read the registry `{project-root}/.sdlc/repos.json` (`config.yaml` `code_context`). For **every
|
|
54
|
+
connected repo** (the epic's `repos` are not chosen yet at this point), load the lightweight code-map
|
|
55
|
+
`{project-root}/.sdlc/code-context/<repo>/code-map.md`. Use it so the epic's **Scope / Out of scope /
|
|
56
|
+
Context** reflect what is **already built** — reference existing behaviour rather than re-proposing it,
|
|
57
|
+
and let it inform which `repos` the epic should touch.
|
|
58
|
+
|
|
59
|
+
- **Greenfield-safe:** if `repos.json` is absent or empty, note "no repos connected" and proceed — no
|
|
60
|
+
behaviour change for a project with no code yet.
|
|
61
|
+
- **Staleness:** if a repo's current HEAD (`git -C <path> rev-parse HEAD`) ≠ its registry `syncedHead`,
|
|
62
|
+
warn and suggest `sdlc repo refresh <repo>` (a human decision — flag and stop, never auto-refresh);
|
|
63
|
+
stamp `code-context: stale` in the frontmatter.
|
|
64
|
+
- **Traceability:** record which maps you loaded in the epic frontmatter `code-context:` field.
|
|
65
|
+
- For depth on a specific area not in the map, do a live on-demand read (see `sdlc-connect-repos`
|
|
66
|
+
`references/code-context.md`) — do not block on it.
|
|
67
|
+
|
|
68
|
+
### Step 3 — Generate the Epic ID (engine-assigned, never by hand) — analysis-skipped only
|
|
69
|
+
*(Skip when analysis ran — the ID was already assigned by `sdlc-author-analysis`.)*
|
|
70
|
+
Derive `EP-<slug>` where `slug` is **2–4 lowercase words joined by hyphens**, drawn from the idea
|
|
71
|
+
(e.g. `EP-istifta-inquiries`). Lowercase except the fixed `EP` prefix. **The ID is assigned once and
|
|
72
|
+
never renamed** — renaming breaks every downstream link (build plan §6b).
|
|
73
|
+
Check `{project-root}/epics/` for collisions; if the slug exists, append a distinguishing word.
|
|
74
|
+
|
|
75
|
+
### Step 3b — Open the authoring branch
|
|
76
|
+
Open the epic authoring branch `epic/EP-<slug>` per the shared procedure
|
|
77
|
+
(`references/state-schema.md` → "Authoring branches"): git-safe (skip with a note if `{project-root}`
|
|
78
|
+
is not a git work tree), check out the branch if it exists, else create it from the hub's default
|
|
79
|
+
branch. Author and commit `epic.md` on it. This is **distinct** from the bridge's `review/…` branch.
|
|
80
|
+
|
|
81
|
+
### Step 4 — Write the epic (assist: pm)
|
|
82
|
+
Adopt the **pm** lens (`bmad-agent-pm`, John) and write `{project-root}/epics/EP-<slug>/epic.md`
|
|
83
|
+
using EXACTLY this template (build plan §6b):
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
---
|
|
87
|
+
id: EP-<slug>
|
|
88
|
+
status: draft
|
|
89
|
+
owner:
|
|
90
|
+
technical_product_owner:
|
|
91
|
+
repos: [backend, mobile, dashboard]
|
|
92
|
+
code-context: { repos: [], loaded: <YYYY-MM-DD or none> } # which code-maps informed this epic (Step 2b)
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Goal
|
|
96
|
+
<!-- why this feature exists, 1-2 sentences -->
|
|
97
|
+
|
|
98
|
+
## Scope
|
|
99
|
+
## Out of scope
|
|
100
|
+
## Context / background
|
|
101
|
+
## Acceptance signals (user-level)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Fill the body with the user; leave `owner` / `technical_product_owner` for the user to set. Set
|
|
105
|
+
`repos` to the repos this epic will touch.
|
|
106
|
+
|
|
107
|
+
### Step 5 — Seed the state machine — analysis-skipped only
|
|
108
|
+
*(Skip when analysis ran — `sdlc-author-analysis` already seeded the 10-step chain. Go to Step 5b.)*
|
|
109
|
+
Create `{project-root}/epics/EP-<slug>/.sdlc/state.json` describing the full **8-step** front-state
|
|
110
|
+
sequence (no analysis), all steps defaulting to `automation: human_approve`, with the four authoring
|
|
111
|
+
steps **locked**. Use this exact shape (see `references/state-schema.md`):
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"epicId": "EP-<slug>",
|
|
116
|
+
"createdAt": "<YYYY-MM-DD>",
|
|
117
|
+
"currentStep": "epic-review",
|
|
118
|
+
"steps": [
|
|
119
|
+
{ "id": "epic", "type": "author", "artifact": "epic.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "done", "risk_tags": [] },
|
|
120
|
+
{ "id": "epic-review", "type": "review+approve", "artifact": "epic.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "in_review", "risk_tags": [] },
|
|
121
|
+
{ "id": "architecture", "type": "author", "artifact": "architecture.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
|
|
122
|
+
{ "id": "architecture-review","type": "review+approve", "artifact": "architecture.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": ["contract"] },
|
|
123
|
+
{ "id": "ui-design", "type": "author", "artifact": "ui-design.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
|
|
124
|
+
{ "id": "ui-design-review", "type": "review+approve", "artifact": "ui-design.md", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
|
|
125
|
+
{ "id": "stories", "type": "author", "artifact": "stories/", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] },
|
|
126
|
+
{ "id": "stories-review", "type": "review+approve", "artifact": "stories/", "assistance": "review", "automation": "human_approve", "locked": true, "status": "blocked", "risk_tags": [] }
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Notes:
|
|
132
|
+
- `architecture-review` carries `risk_tags: ["contract"]` so the gate escalates it by default
|
|
133
|
+
(build plan §4): the contract review needs domain owners, not just owner + 1.
|
|
134
|
+
- Also create an empty approvals ledger `{project-root}/epics/EP-<slug>/.sdlc/approvals.json`
|
|
135
|
+
and an empty comments ledger `{project-root}/epics/EP-<slug>/.sdlc/comments.json`, each containing
|
|
136
|
+
`[]`, and the `reviews/` directory. (`comments.json` is the machine-readable counterpart to the
|
|
137
|
+
`reviews/*--comments.md` markdown — `sdlc-review-gate` appends to it on every `comment`.)
|
|
138
|
+
|
|
139
|
+
### Step 5b — Advance the authoring step — analysis-ran only
|
|
140
|
+
*(Only when analysis ran — `state.json` already exists from `sdlc-author-analysis`.)*
|
|
141
|
+
In `state.json`: set `epic.status: "done"`, set `epic-review.status: "in_review"`, and set
|
|
142
|
+
`currentStep: "epic-review"`. Write `state.json`. Do **not** re-seed and do **not** touch
|
|
143
|
+
`approvals.json` — only real reviewers approve, through the gate.
|
|
144
|
+
|
|
145
|
+
### Step 6 — Stop at the gate (do NOT advance)
|
|
146
|
+
Report: epic ID, the path to `epic.md`, and that the next action is **review** via
|
|
147
|
+
`sdlc-review-gate`. **Never mark the epic-review step approved here** — only real reviewers do that
|
|
148
|
+
through the gate. Front states do not auto-advance. When the hub has a platform, the gate opens a review
|
|
149
|
+
PR on the hub (via `sdlc-hub-bridge`) and `sdlc-review-gate action: sync` pulls platform approvals/
|
|
150
|
+
comments into the ledger; otherwise the review is recorded file-only.
|
|
151
|
+
|
|
152
|
+
## Reference
|
|
153
|
+
- State schema and field meanings: `references/state-schema.md`.
|
|
154
|
+
- Connecting code repos + the code-context the brain reads: `../sdlc-connect-repos/SKILL.md`.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# `.sdlc/` state schema
|
|
2
|
+
|
|
3
|
+
All SDLC state lives in plain files under `epics/EP-<slug>/.sdlc/` (build plan §1: "All state lives
|
|
4
|
+
in files on disk. Nothing hidden."). No database, no browser storage.
|
|
5
|
+
|
|
6
|
+
## `state.json`
|
|
7
|
+
The per-epic state machine.
|
|
8
|
+
|
|
9
|
+
| Field | Meaning |
|
|
10
|
+
|-------|---------|
|
|
11
|
+
| `epicId` | The stable `EP-<slug>` ID. Never renamed. |
|
|
12
|
+
| `createdAt` | ISO date the epic was created. |
|
|
13
|
+
| `currentStep` | `id` of the step the workflow is waiting on right now. |
|
|
14
|
+
| `steps[]` | Ordered list of every front-state step. |
|
|
15
|
+
|
|
16
|
+
Each `steps[]` entry:
|
|
17
|
+
|
|
18
|
+
| Field | Values | Meaning |
|
|
19
|
+
|-------|--------|---------|
|
|
20
|
+
| `id` | `analysis`, `analysis-review`, `epic`, `epic-review`, `architecture`, `architecture-review`, `ui-design`, `ui-design-review`, `stories`, `stories-review` | Step identity. |
|
|
21
|
+
|
|
22
|
+
### Two valid chain shapes (analysis is optional)
|
|
23
|
+
|
|
24
|
+
The `analysis` step (and its `analysis-review` gate) is **optional** — it exists only when the team
|
|
25
|
+
ran `sdlc-author-analysis` before the epic. The entry-point skill (whichever runs first) is the one
|
|
26
|
+
that assigns `EP-<slug>` and seeds `state.json` + the empty ledgers; the other skill detects an
|
|
27
|
+
existing `state.json` and does **not** re-seed.
|
|
28
|
+
|
|
29
|
+
- **With analysis** (10 steps — `sdlc-author-analysis` seeded the chain):
|
|
30
|
+
`analysis → analysis-review → epic → epic-review → architecture → architecture-review → ui-design →
|
|
31
|
+
ui-design-review → stories → stories-review`. Seeded `currentStep` is `analysis-review`; `epic`
|
|
32
|
+
starts `blocked`.
|
|
33
|
+
- **Without analysis** (8 steps — `sdlc-author-epic` is the entry point, the default):
|
|
34
|
+
`epic → epic-review → … → stories-review`. Seeded `currentStep` is `epic-review`.
|
|
35
|
+
|
|
36
|
+
After `stories-review` passes, `currentStep` becomes the `ready-for-build` sentinel either way.
|
|
37
|
+
`analysis-review` carries no `risk_tags` (base rule: owner + 1 reviewer).
|
|
38
|
+
|
|
39
|
+
### Authoring branches
|
|
40
|
+
|
|
41
|
+
Each front **authoring** step opens its own git branch at the start of the step, named
|
|
42
|
+
`<step>/EP-<slug>` where `<step>` ∈ `analysis | epic | architecture | ui-design | stories`
|
|
43
|
+
(`config.yaml` `defaults.front_authoring_branch`). This is **distinct** from the review branch
|
|
44
|
+
`review/EP-<slug>/<artifact-base>` that `sdlc-hub-bridge` opens later for the review PR/MR.
|
|
45
|
+
|
|
46
|
+
The shared procedure (run once the `EP-<slug>` is known):
|
|
47
|
+
1. **Git-safe / greenfield-safe:** if `{project-root}` is not a git work tree
|
|
48
|
+
(`git rev-parse --is-inside-work-tree` fails), skip branching with a note and author on the current
|
|
49
|
+
tree — no error.
|
|
50
|
+
2. Branch name = `<step>/EP-<slug>`. If it already exists, check it out; otherwise create it from the
|
|
51
|
+
hub's default branch (`git checkout -b <step>/EP-<slug>`).
|
|
52
|
+
3. Author and commit the step's artifact(s) on that branch. The bridge's `review/…` branch is created
|
|
53
|
+
separately at review time and is untouched by this step.
|
|
54
|
+
| `type` | `author` \| `review+approve` | Authoring step or a team review gate. |
|
|
55
|
+
| `artifact` | filename or folder | The file/folder this step produces or gates. |
|
|
56
|
+
| `assistance` | `none` \| `review` \| `heavy` | Dial 1 — how much AI helps (build plan §2). |
|
|
57
|
+
| `automation` | `human_approve` \| `machine_advance` | Dial 2 — who advances (build plan §2). |
|
|
58
|
+
| `locked` | `true` \| `false` | Front steps are `true`: may NOT be set to `machine_advance` in this version. |
|
|
59
|
+
| `status` | `blocked` \| `in_progress` \| `in_review` \| `done` | Lifecycle. `blocked` = upstream step not yet approved. |
|
|
60
|
+
| `risk_tags` | subset of `contract`, `auth`, `payments` | Drives review escalation (build plan §4). |
|
|
61
|
+
|
|
62
|
+
## `approvals.json`
|
|
63
|
+
Append-only ledger (an array). Each entry:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{ "artifact": "epic.md", "step": "epic-review", "approver": "<name>", "role": "owner|reviewer|domain-owner", "domain": "<repo-or-area, optional>", "status": "approved", "date": "<YYYY-MM-DD>", "source": "<bridge, optional>" }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`source: "bridge"` marks an approval synced from a hub review PR/MR by `sdlc-review-gate action: sync`
|
|
70
|
+
(via `sdlc-hub-bridge`). Manual approvals omit `source` and are never altered by `sync`.
|
|
71
|
+
|
|
72
|
+
## `comments.json`
|
|
73
|
+
Append-only ledger (an array), the machine-readable counterpart to the `reviews/*--comments.md` markdown
|
|
74
|
+
("who reviewed/commented", as `approvals.json` is "who approved"). Written by `sdlc-review-gate`'s
|
|
75
|
+
`comment` action; feeds the `approved.md` participation roster, not the gate predicate. Each entry:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{ "artifact": "epic.md", "step": "epic-review", "commenter": "<name>", "role": "owner|reviewer|domain-owner", "domain": "<optional>", "round": <n>, "count": <comments this round>, "date": "<YYYY-MM-DD>" }
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## `hub-prs.json`
|
|
82
|
+
Present only when the front-half review runs through the platform bridge. Per review step, the review
|
|
83
|
+
PR/MR opened on the hub (sibling of `approvals.json`, so the locked `state.json` step shape is untouched):
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{ "step": "<review step id>", "artifact": "<artifact>", "platform": "github|gitlab", "number": <n>, "url": "<pr/mr url>", "branch": "review/EP-<slug>/<artifact-base>", "lastSyncedAt": "<YYYY-MM-DD or null>" }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## `reviews/`
|
|
90
|
+
Human-readable review records, one file per round:
|
|
91
|
+
`reviews/<artifact-base>--<YYYY-MM-DD>--<status>.md` where `status` ∈ `comments` | `approved`
|
|
92
|
+
and `<artifact-base>` is the artifact without extension (e.g. `epic`, `architecture`, `stories-S01`).
|
|
93
|
+
|
|
94
|
+
## Dial defaults & locks
|
|
95
|
+
- Every step defaults to `automation: human_approve` (build plan §2).
|
|
96
|
+
- The four authoring front steps and their reviews are `locked: true` — the engine refuses to set
|
|
97
|
+
them to `machine_advance` in this version (build plan §1, §8.7). Only back states (build pipeline,
|
|
98
|
+
steps 9–14) may move toward machine-advance in a later iteration.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
# Phase 4 build-half state (the back half made dial-bearing)
|
|
103
|
+
|
|
104
|
+
Phase 3 recorded build progress only *after the fact* in `build-log.json`. Phase 4 needs the back
|
|
105
|
+
steps to carry their own `automation` dial so the orchestrator (`sdlc-run`) can read it and decide
|
|
106
|
+
whether to advance on its own. Two new files under `.sdlc/` do this.
|
|
107
|
+
|
|
108
|
+
## `build-state/<story-id>.json`
|
|
109
|
+
One file per story that has entered the build half. The build half is **per-story, per-repo**, so the
|
|
110
|
+
steps live under each repo (mirrors the per-repo shape of `build-log.json`).
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"story": "EP-<slug>-S0N",
|
|
115
|
+
"repos": {
|
|
116
|
+
"backend": {
|
|
117
|
+
"currentStep": "checks",
|
|
118
|
+
"steps": [
|
|
119
|
+
{ "id": "spec", "automation": "human_approve", "locked": false, "status": "done" },
|
|
120
|
+
{ "id": "tasks", "automation": "human_approve", "locked": false, "status": "done" },
|
|
121
|
+
{ "id": "implement", "automation": "human_approve", "locked": false, "status": "done" },
|
|
122
|
+
{ "id": "checks", "automation": "machine_advance","locked": false, "status": "in_progress" },
|
|
123
|
+
{ "id": "engineer-review", "automation": "human_approve", "locked": true, "status": "blocked" }
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Each `steps[]` entry:
|
|
131
|
+
|
|
132
|
+
| Field | Values | Meaning |
|
|
133
|
+
|-------|--------|---------|
|
|
134
|
+
| `id` | `spec`, `tasks`, `implement`, `checks`, `engineer-review` | Back-half step identity (the `back_steps` from `config.yaml` + the human merge gate). |
|
|
135
|
+
| `automation` | `human_approve` \| `machine_advance` | Dial 2. Defaults to `human_approve`; flipped to `machine_advance` only after the trust threshold is met (and never for `locked` steps). |
|
|
136
|
+
| `locked` | `true` \| `false` | `engineer-review` is `true` — it never auto-advances (build plan §E). |
|
|
137
|
+
| `status` | `blocked` \| `in_progress` \| `in_review` \| `done` | Lifecycle. `sdlc-run` advances `done` steps and `blocked`s on a halt. |
|
|
138
|
+
|
|
139
|
+
`currentStep` is the `id` the orchestrator is waiting on / about to run for that repo. The file is
|
|
140
|
+
created when a story enters the build half; all dials start `human_approve` (the `config.yaml`
|
|
141
|
+
`automation.default`).
|
|
142
|
+
|
|
143
|
+
## `trust-log.json`
|
|
144
|
+
Append-only ledger (an array), the back-half analogue of `approvals.json`. **This is the evidence
|
|
145
|
+
base** that decides when a step is safe to automate (build plan Step A). One entry per step run:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"story": "EP-<slug>-S0N",
|
|
150
|
+
"repo": "backend",
|
|
151
|
+
"step": "checks",
|
|
152
|
+
"automation": "human_approve",
|
|
153
|
+
"verdict": "approved-unchanged",
|
|
154
|
+
"signals": { "checks": "pass", "human_edited_diff": false, "scope_overrun": false, "contract_touch": false },
|
|
155
|
+
"ranBy": "machine",
|
|
156
|
+
"date": "<YYYY-MM-DD>",
|
|
157
|
+
"note": "<optional>"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
| Field | Values | Meaning |
|
|
162
|
+
|-------|--------|---------|
|
|
163
|
+
| `step` | a `back_steps` id | Which step this run is recorded against. |
|
|
164
|
+
| `automation` | dial in force at run time | So the log shows whether the run was a manual or an automated advance. |
|
|
165
|
+
| `verdict` | `approved-unchanged` \| `approved-with-edits` \| `rejected` | The trust signal. **Provisional verdict is derived** (below); the human gate for that step confirms or overrides it and finalizes the entry. |
|
|
166
|
+
| `signals` | object | The raw inputs the provisional verdict was derived from. The fields present depend on the step (table below). |
|
|
167
|
+
| `ranBy` | `machine` \| `human` | Whether the orchestrator advanced it or a human did. |
|
|
168
|
+
|
|
169
|
+
**Per-step `signals` fields** (only the relevant ones are set; others may be omitted or `n/a`):
|
|
170
|
+
|
|
171
|
+
| Step | Signals | Finalized at (the human gate) |
|
|
172
|
+
|------|---------|-------------------------------|
|
|
173
|
+
| `spec` | `human_edited_spec` | the human who accepts `specs/<story>/` (`sdlc-spec` Step 8) |
|
|
174
|
+
| `tasks` | `task_rescoped` | first consume by `sdlc-implement` (Step 8) |
|
|
175
|
+
| `implement` | `human_edited_diff`, `scope_overrun`, `contract_touch` | engineer review at `sdlc-ship` |
|
|
176
|
+
| `checks` | `checks` (`pass`\|`fail`) | the gate run itself (objective) |
|
|
177
|
+
|
|
178
|
+
**Deriving the provisional verdict** (build plan Step A; extended for `spec`/`tasks` in Phase 4b — the
|
|
179
|
+
same three-way shape, anchored to each step's human gate, never self-graded):
|
|
180
|
+
- any check FAIL, scope overrun, contract-surface touch, or a discarded/regenerated artifact → `rejected`;
|
|
181
|
+
- accepted after a human edited the output (`human_edited_diff` / `human_edited_spec` / `task_rescoped`) → `approved-with-edits`;
|
|
182
|
+
- accepted as produced → `approved-unchanged`.
|
|
183
|
+
|
|
184
|
+
**Trust threshold** (from `config.yaml` `automation.trust_threshold`): a step is a candidate for
|
|
185
|
+
`machine_advance` only when its slice of `trust-log.json` (same `step`, this story's repo or the
|
|
186
|
+
project) has `>= min_runs` entries AND the fraction with `verdict == "approved-unchanged"` is
|
|
187
|
+
`>= min_approved_unchanged`. The dial-setter in `sdlc-run` enforces this; `sdlc-status` surfaces it.
|