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.
Files changed (77) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/LICENSE +21 -0
  3. package/README.md +559 -0
  4. package/bin/sdlc.mjs +135 -0
  5. package/cli/commit.mjs +81 -0
  6. package/cli/epic-state.mjs +220 -0
  7. package/cli/gate.mjs +456 -0
  8. package/cli/lib.mjs +142 -0
  9. package/cli/manifest.mjs +119 -0
  10. package/cli/openpr.mjs +65 -0
  11. package/cli/plan.mjs +127 -0
  12. package/cli/platform.mjs +151 -0
  13. package/cli/reconcile.mjs +83 -0
  14. package/cli/repo.mjs +61 -0
  15. package/cli/setup.mjs +208 -0
  16. package/package.json +51 -0
  17. package/skills/sdlc/config.yaml +156 -0
  18. package/skills/sdlc/install.sh +51 -0
  19. package/skills/sdlc/module-help.csv +17 -0
  20. package/skills/sdlc-author-analysis/SKILL.md +136 -0
  21. package/skills/sdlc-author-architecture/SKILL.md +180 -0
  22. package/skills/sdlc-author-architecture/references/contract-format.md +72 -0
  23. package/skills/sdlc-author-epic/SKILL.md +154 -0
  24. package/skills/sdlc-author-epic/references/state-schema.md +187 -0
  25. package/skills/sdlc-author-stories/SKILL.md +109 -0
  26. package/skills/sdlc-author-stories/references/story-schema.md +46 -0
  27. package/skills/sdlc-author-ui/SKILL.md +113 -0
  28. package/skills/sdlc-backfill/SKILL.md +91 -0
  29. package/skills/sdlc-backfill/references/backfill.md +66 -0
  30. package/skills/sdlc-backfill/templates/checks/backfill-check.sh +42 -0
  31. package/skills/sdlc-checks/SKILL.md +138 -0
  32. package/skills/sdlc-checks/references/check-gates.md +168 -0
  33. package/skills/sdlc-checks/templates/checks/build-test-lint.sh +14 -0
  34. package/skills/sdlc-checks/templates/checks/contract-check.sh +62 -0
  35. package/skills/sdlc-checks/templates/checks/spec-link.sh +38 -0
  36. package/skills/sdlc-checks/templates/checks/verified-commits.sh +120 -0
  37. package/skills/sdlc-checks/templates/github/sdlc-checks.yml +45 -0
  38. package/skills/sdlc-checks/templates/github/sdlc-verified-commits.yml +22 -0
  39. package/skills/sdlc-checks/templates/gitlab/.gitlab-ci.yml +40 -0
  40. package/skills/sdlc-checks/templates/gitlab/gitlab-ci.include-root.yml +7 -0
  41. package/skills/sdlc-checks/templates/gitlab/sdlc-checks.gitlab-ci.yml +47 -0
  42. package/skills/sdlc-checks/templates/gitlab/sdlc-verified-commits.gitlab-ci.yml +21 -0
  43. package/skills/sdlc-connect-repos/SKILL.md +159 -0
  44. package/skills/sdlc-connect-repos/references/code-context.md +92 -0
  45. package/skills/sdlc-connect-repos/references/hub-config.md +77 -0
  46. package/skills/sdlc-connect-repos/references/repos-registry.md +62 -0
  47. package/skills/sdlc-hub-bridge/SKILL.md +119 -0
  48. package/skills/sdlc-hub-bridge/references/bridge.md +136 -0
  49. package/skills/sdlc-hub-bridge/references/login-roster.md +42 -0
  50. package/skills/sdlc-hub-bridge/templates/checks/hub-route.sh +50 -0
  51. package/skills/sdlc-hub-bridge/templates/github/sdlc-gate-sync.yml +63 -0
  52. package/skills/sdlc-hub-bridge/templates/gitlab/gitlab-ci.include-root.yml +7 -0
  53. package/skills/sdlc-hub-bridge/templates/gitlab/sdlc-gate-sync.gitlab-ci.yml +64 -0
  54. package/skills/sdlc-implement/SKILL.md +143 -0
  55. package/skills/sdlc-implement/references/implement-conventions.md +103 -0
  56. package/skills/sdlc-implement/templates/.gitmessage +17 -0
  57. package/skills/sdlc-pr-template/SKILL.md +86 -0
  58. package/skills/sdlc-pr-template/references/risk-routing.md +54 -0
  59. package/skills/sdlc-pr-template/templates/checks/risk-route.sh +44 -0
  60. package/skills/sdlc-pr-template/templates/github/pull_request_template.md +30 -0
  61. package/skills/sdlc-pr-template/templates/gitlab/merge_request_templates/Default.md +32 -0
  62. package/skills/sdlc-pr-template/templates/hub/github/pull_request_template.md +36 -0
  63. package/skills/sdlc-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +37 -0
  64. package/skills/sdlc-review-comments/SKILL.md +63 -0
  65. package/skills/sdlc-review-comments/references/comment-conventions.md +55 -0
  66. package/skills/sdlc-review-comments/templates/github/REVIEW_COMMENTS.md +49 -0
  67. package/skills/sdlc-review-comments/templates/gitlab/REVIEW_COMMENTS.md +49 -0
  68. package/skills/sdlc-review-gate/SKILL.md +196 -0
  69. package/skills/sdlc-review-gate/references/gating.md +79 -0
  70. package/skills/sdlc-run/SKILL.md +109 -0
  71. package/skills/sdlc-run/references/run-loop.md +121 -0
  72. package/skills/sdlc-ship/SKILL.md +86 -0
  73. package/skills/sdlc-ship/references/ship-and-record.md +67 -0
  74. package/skills/sdlc-ship/templates/.coderabbit.yaml +19 -0
  75. package/skills/sdlc-spec/SKILL.md +119 -0
  76. package/skills/sdlc-spec/references/spec-handoff.md +101 -0
  77. 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.