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,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.