@metasession.co/devaudit-cli 0.2.0 → 0.3.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 (30) hide show
  1. package/dist/index.js +21 -2
  2. package/dist/index.js.map +1 -1
  3. package/package.json +2 -2
  4. package/sdlc/files/_common/1-plan-requirement.md +6 -2
  5. package/sdlc/files/_common/2-implement-and-test.md +6 -2
  6. package/sdlc/files/_common/3-compile-evidence.md +6 -2
  7. package/sdlc/files/_common/4-submit-for-review.md +6 -2
  8. package/sdlc/files/_common/5-deploy-main.md +6 -2
  9. package/sdlc/files/_common/implementing-an-sdlc-issue.md +6 -2
  10. package/sdlc/files/_common/scripts/close-out-release.sh +8 -1
  11. package/sdlc/files/_common/scripts/close-out-release.test.sh +59 -0
  12. package/sdlc/files/_common/scripts/derive-release-version.sh +2 -1
  13. package/sdlc/files/_common/scripts/derive-release-version.test.sh +29 -0
  14. package/sdlc/files/_common/scripts/sdlc-guard.sh +60 -0
  15. package/sdlc/files/_common/scripts/validate-test-summary.sh +146 -0
  16. package/sdlc/files/_common/scripts/validate-test-summary.test.sh +268 -0
  17. package/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md +28 -2
  18. package/sdlc/files/_common/skills/sdlc-implementer/SKILL.md +21 -2
  19. package/sdlc/files/ci/ci.yml.template +26 -1
  20. package/sdlc/files/ci/compliance-validation.yml.template +3 -0
  21. package/sdlc/files/stacks/node/hooks/pre-commit +10 -2
  22. package/sdlc/files/stacks/node/hooks/pre-push +29 -2
  23. package/sdlc/package.json +1 -1
  24. package/sdlc/src/blueprints/1-plan-requirement.raw.md +1 -1
  25. package/sdlc/src/blueprints/2-implement-and-test.raw.md +13 -1
  26. package/sdlc/src/blueprints/3-compile-evidence.raw.md +1 -1
  27. package/sdlc/src/blueprints/4-submit-for-review.raw.md +1 -1
  28. package/sdlc/src/blueprints/5-deploy-main.raw.md +1 -1
  29. package/sdlc/src/blueprints/implementing-an-sdlc-issue.raw.md +1 -1
  30. package/sdlc/.claude/settings.local.json +0 -11
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env bash
2
+ # validate-test-summary.test.sh — Tests for validate-test-summary.sh.
3
+ #
4
+ # Builds a throwaway git repo per case, creates compliance evidence with
5
+ # crafted test-execution-summary.md files, runs the validator, and asserts
6
+ # on the exit code. Hermetic: runs inside mktemp'd directories that are
7
+ # torn down at the end.
8
+ #
9
+ # Usage:
10
+ # ./scripts/validate-test-summary.test.sh
11
+
12
+ set -euo pipefail
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
15
+ HELPER="$SCRIPT_DIR/validate-test-summary.sh"
16
+ [ -x "$HELPER" ] || chmod +x "$HELPER"
17
+
18
+ PASS=0
19
+ FAIL=0
20
+
21
+ WORK=$(mktemp -d)
22
+ trap 'rm -rf "$WORK"' EXIT
23
+
24
+ # Build a fresh git fixture with a commit referencing REQ-XXX.
25
+ # Sets up compliance/evidence/REQ-XXX/ directory.
26
+ # $1 = dir, $2 = REQ ID, $3 = summary file content (via stdin)
27
+ make_fixture() {
28
+ local dir="$1" req="$2"
29
+ rm -rf "$dir"
30
+ mkdir -p "$dir"
31
+ cd "$dir"
32
+ git init -q --initial-branch=main
33
+ git config user.email "test@example.com"
34
+ git config user.name "test"
35
+
36
+ # Create a base branch and a feature branch with a REQ commit
37
+ echo "x" > f.txt
38
+ git add f.txt
39
+ git commit -q -m "initial"
40
+
41
+ git checkout -q -b feature
42
+ echo "y" > g.txt
43
+ git add g.txt
44
+ git commit -q -m "feat: [${req}] test change
45
+
46
+ Ref: ${req}"
47
+
48
+ # Create evidence directory and RTM row
49
+ mkdir -p "compliance/evidence/${req}"
50
+ echo "| ${req} | #999 | HIGH | compliance/evidence/${req}/ | TESTED - PENDING SIGN-OFF | TBD | -- |" > compliance/RTM.md
51
+ git add compliance/RTM.md
52
+ git commit -q -m "docs: add RTM row for ${req}"
53
+
54
+ # Write the test-execution-summary.md from stdin
55
+ cat > "compliance/evidence/${req}/test-execution-summary.md"
56
+
57
+ # Stay on feature branch so the validator sees the diff from main
58
+ }
59
+
60
+ # Run the validator against the fixture, capture exit code.
61
+ # $1 = fixture dir
62
+ run_validator() {
63
+ local dir="$1"
64
+ cd "$dir"
65
+ local exit_code=0
66
+ bash "$HELPER" main > /tmp/validate-test-summary-output.txt 2>&1 || exit_code=$?
67
+ echo "$exit_code"
68
+ }
69
+
70
+ assert_exit() {
71
+ local desc="$1" want="$2" got="$3"
72
+ if [ "$got" = "$want" ]; then
73
+ echo " PASS: $desc"
74
+ PASS=$((PASS + 1))
75
+ else
76
+ echo " FAIL: $desc"
77
+ echo " want exit: $want"
78
+ echo " got exit: $got"
79
+ cat /tmp/validate-test-summary-output.txt | sed 's/^/ /'
80
+ FAIL=$((FAIL + 1))
81
+ fi
82
+ }
83
+
84
+ echo "=== validate-test-summary.sh tests ==="
85
+
86
+ # --- Case 1: Clean summary with PASS — should pass ---
87
+ D1="$WORK/case1"
88
+ make_fixture "$D1" "REQ-001" << 'EOF'
89
+ # Test Execution Summary — REQ-001
90
+
91
+ ## Test design
92
+
93
+ **Layers planned:** unit, e2e
94
+ **Layers covered:** unit ✓, e2e ✓
95
+
96
+ ## Gate Results
97
+
98
+ | Gate | Result | Details |
99
+ | ---------------- | -------- | -------------------- |
100
+ | TypeScript | PASS | 0 errors |
101
+ | E2E Tests | PASS | All specs green |
102
+ | Unit Tests | PASS | 42 passed |
103
+
104
+ **Final assessment:** All gates passed.
105
+ EOF
106
+ EXIT1=$(run_validator "$D1")
107
+ assert_exit "clean summary with PASS — should pass" 0 "$EXIT1"
108
+
109
+ # --- Case 2: Summary with 'deferred' — should fail ---
110
+ D2="$WORK/case2"
111
+ make_fixture "$D2" "REQ-002" << 'EOF'
112
+ # Test Execution Summary — REQ-002
113
+
114
+ ## Test design
115
+
116
+ **Layers covered:** unit ✓, e2e deferred
117
+
118
+ ## Gate Results
119
+
120
+ | Gate | Result | Details |
121
+ | ---------------- | -------- | ---------------------------------------- |
122
+ | E2E Tests | DEFERRED | Playwright browsers not installed locally |
123
+
124
+ **Final assessment:** All local gates passed. E2E deferred to CI.
125
+ EOF
126
+ EXIT2=$(run_validator "$D2")
127
+ assert_exit "summary with 'deferred' — should fail" 1 "$EXIT2"
128
+
129
+ # --- Case 3: Summary with 'Deferred to CI' — should fail ---
130
+ D3="$WORK/case3"
131
+ make_fixture "$D3" "REQ-003" << 'EOF'
132
+ # Test Execution Summary — REQ-003
133
+
134
+ **Final assessment:** All gates passed. E2E Deferred to CI.
135
+ EOF
136
+ EXIT3=$(run_validator "$D3")
137
+ assert_exit "summary with 'Deferred to CI' — should fail" 1 "$EXIT3"
138
+
139
+ # --- Case 4: Summary with 'browsers not installed' — should fail ---
140
+ D4="$WORK/case4"
141
+ make_fixture "$D4" "REQ-004" << 'EOF'
142
+ # Test Execution Summary — REQ-004
143
+
144
+ ## Gate Results
145
+
146
+ | Gate | Result | Details |
147
+ | ---------------- | -------- | ---------------------------------------- |
148
+ | E2E Tests | SKIPPED | Playwright browsers not installed locally |
149
+
150
+ **Final assessment:** E2E skipped — browsers not installed.
151
+ EOF
152
+ EXIT4=$(run_validator "$D4")
153
+ assert_exit "summary with 'browsers not installed' — should fail" 1 "$EXIT4"
154
+
155
+ # --- Case 5: Summary with NOT_NEEDED and rationale — should pass ---
156
+ D5="$WORK/case5"
157
+ make_fixture "$D5" "REQ-005" << 'EOF'
158
+ # Test Execution Summary — REQ-005
159
+
160
+ ## Gate Results
161
+
162
+ | Gate | Result | Details |
163
+ | ---------------- | ------------ | ------------------------------------------ |
164
+ | E2E Tests | NOT_NEEDED | Schema-only change, no UI surface |
165
+
166
+ **Final assessment:** All gates passed. E2E not needed for this REQ.
167
+ EOF
168
+ EXIT5=$(run_validator "$D5")
169
+ assert_exit "summary with NOT_NEEDED and rationale — should pass" 0 "$EXIT5"
170
+
171
+ # --- Case 6: Summary with SKIPPED and rationale — should pass ---
172
+ D6="$WORK/case6"
173
+ make_fixture "$D6" "REQ-006" << 'EOF'
174
+ # Test Execution Summary — REQ-006
175
+
176
+ ## Gate Results
177
+
178
+ | Gate | Result | Details |
179
+ | ---------------- | ------------ | ------------------------------------------ |
180
+ | E2E Tests | SKIPPED | API-only change, no UI surface (operator-approved) |
181
+
182
+ **Final assessment:** All gates passed. E2E skipped — API-only change.
183
+ EOF
184
+ EXIT6=$(run_validator "$D6")
185
+ assert_exit "summary with SKIPPED and rationale — should pass" 0 "$EXIT6"
186
+
187
+ # --- Case 7: Summary with SKIPPED but no rationale — should fail ---
188
+ D7="$WORK/case7"
189
+ make_fixture "$D7" "REQ-007" << 'EOF'
190
+ # Test Execution Summary — REQ-007
191
+
192
+ ## Gate Results
193
+
194
+ | Gate | Result | Details |
195
+ | ---------------- | ------------ | ---------- |
196
+ | E2E Tests | SKIPPED | |
197
+
198
+ **Final assessment:** All gates passed.
199
+ EOF
200
+ EXIT7=$(run_validator "$D7")
201
+ assert_exit "summary with SKIPPED but no rationale — should fail" 1 "$EXIT7"
202
+
203
+ # --- Case 8: No REQ references — should pass (skip) ---
204
+ D8="$WORK/case8"
205
+ rm -rf "$D8"
206
+ mkdir -p "$D8"
207
+ cd "$D8"
208
+ git init -q --initial-branch=main
209
+ git config user.email "test@example.com"
210
+ git config user.name "test"
211
+ echo "x" > f.txt
212
+ git add f.txt
213
+ git commit -q -m "initial"
214
+ git checkout -q -b feature
215
+ echo "y" > g.txt
216
+ git add g.txt
217
+ git commit -q -m "docs: update README"
218
+ EXIT8=$(run_validator "$D8")
219
+ assert_exit "no REQ references — should pass (skip)" 0 "$EXIT8"
220
+
221
+ # --- Case 9: No test-execution-summary.md — should pass (skip) ---
222
+ D9="$WORK/case9"
223
+ make_fixture "$D9" "REQ-009" << 'EOF'
224
+ # placeholder
225
+ EOF
226
+ rm "$D9/compliance/evidence/REQ-009/test-execution-summary.md"
227
+ EXIT9=$(run_validator "$D9")
228
+ assert_exit "no test-execution-summary.md — should pass (skip)" 0 "$EXIT9"
229
+
230
+ # --- Case 10: Summary with 'e2e deferred' in final assessment — should fail ---
231
+ D10="$WORK/case10"
232
+ make_fixture "$D10" "REQ-010" << 'EOF'
233
+ # Test Execution Summary — REQ-010
234
+
235
+ ## Gate Results
236
+
237
+ | Gate | Result | Details |
238
+ | ---------------- | -------- | --------------- |
239
+ | E2E Tests | PASS | All specs green |
240
+
241
+ **Final assessment:** All gates passed. E2E deferred to CI for critical tier.
242
+ EOF
243
+ EXIT10=$(run_validator "$D10")
244
+ assert_exit "summary with 'e2e deferred' in final assessment — should fail" 1 "$EXIT10"
245
+
246
+ # --- Case 11: NOT_NEEDED without rationale — should fail ---
247
+ D11="$WORK/case11"
248
+ make_fixture "$D11" "REQ-011" << 'EOF'
249
+ # Test Execution Summary — REQ-011
250
+
251
+ ## Gate Results
252
+
253
+ | Gate | Result | Details |
254
+ | ---------------- | ------------ | ---------- |
255
+ | E2E Tests | NOT_NEEDED | |
256
+
257
+ **Final assessment:** All gates passed.
258
+ EOF
259
+ EXIT11=$(run_validator "$D11")
260
+ assert_exit "summary with NOT_NEEDED but no rationale — should fail" 1 "$EXIT11"
261
+
262
+ echo ""
263
+ echo "=== Summary: $PASS pass / $FAIL fail ==="
264
+
265
+ if [ "$FAIL" -gt 0 ]; then
266
+ exit 1
267
+ fi
268
+ exit 0
@@ -241,8 +241,34 @@ Halt and report the gap to the user:
241
241
 
242
242
  Do **not** proceed to Phase 6 until all gaps are resolved. The user may choose to skip an AC (e.g. API-only, transport-only) — that's valid, but it must be an explicit decision recorded in the test-execution-summary, not an omission.
243
243
 
244
+ **Write the evidence-wiring sentinel (devaudit-installer#226).** After all Phase 5½ checks pass (all `@requirement`, `evidenceShot()`, and `tagTest()` calls verified), write a `.e2e-evidence-wired` sentinel file in the repo root so the pre-push hook and `sdlc-implementer` Phase 2 step 5b can verify evidence wiring was validated:
245
+
246
+ ```bash
247
+ echo "WIRED $(date -u +%Y-%m-%dT%H:%M:%SZ) REQ-XXX" > .e2e-evidence-wired
248
+ ```
249
+
250
+ If the user explicitly skipped an AC (e.g. API-only), note it in the sentinel:
251
+
252
+ ```bash
253
+ echo "WIRED $(date -u +%Y-%m-%dT%H:%M:%SZ) REQ-XXX (AC3 skipped — API-only)" > .e2e-evidence-wired
254
+ ```
255
+
256
+ The file is gitignored and never committed — it's a local-only signal that evidence wiring was validated in this working directory.
257
+
244
258
  ### Phase 6 — Execute and report
245
259
 
260
+ **Pre-flight: browser availability (devaudit-installer#238).** Before running the suite, verify Playwright browsers are installed:
261
+
262
+ ```bash
263
+ npx playwright install --dry-run 2>&1 | grep -q "is already installed" || npx playwright install
264
+ ```
265
+
266
+ If the install fails (e.g. missing system dependencies on Linux), run `npx playwright install --with-deps` (requires sudo on some systems — ask the operator). Do not defer E2E execution to CI because browsers are not installed. Installing browsers takes ~30 seconds; deferring breaks the evidence trail.
267
+
268
+ **Do not defer E2E to CI (devaudit-installer#238).** If browsers are not installed, install them. If the dev server will not start, debug it. If the database is not running, start it. CI is a safety net, not a replacement for local E2E execution. The `.e2e-gate-passed` sentinel must be written by a local run — skipping it by deferring to CI breaks the evidence-completeness chain and causes the evidence-completeness gate (#237) to fire with false negatives.
269
+
270
+ **Gate state vocabulary (devaudit-installer#240).** In `test-execution-summary.md`, E2E gate results must be one of: `PASS`, `FAIL`, `NOT_NEEDED` (with reason), or `SKIPPED` (with operator-approved rationale). The word "deferred" must never appear in `test-execution-summary.md` — not as a gate state, not in prose, not in final assessment. The CI validator (`validate-test-summary.sh`) rejects any file containing "deferred" anywhere. If E2E was not run locally, record it as `SKIPPED` with the reason and flag it as a gate failure for the reviewer. Do not write "E2E deferred to CI" or "Playwright browsers not installed locally" — these are environment issues, not gate states.
271
+
246
272
  Run the suite. Strategy:
247
273
 
248
274
  1. **Iterate focused.** During fix-and-verify, run only the failing specs (`--grep`, spec-path args, or a CI input that scopes to a subset). Cycle time is what makes the loop tractable — full regression for every iteration burns CI budget and operator patience. Expect to loop: fix → focused run → fix → focused run, many times.
@@ -404,8 +430,8 @@ Wrap up with a summary the user can drop into the PR or ticket:
404
430
  **Then feed the test-design record (devaudit#50).** The Stage 3 `test-execution-summary.md` (generated per `3-compile-evidence.md` Step 1a) carries a `## Test design` section at the top. Before Stage 3 finalises the file, populate that section with the design-time decisions this skill made, so the SDLC has a recorded trace that scope was *decided*, not implicit:
405
431
 
406
432
  - **Layers planned** — which of `unit | integration | e2e | visual | manual` applied to this REQ
407
- - **Layers covered** — same list with ✓ or `deferred`
408
- - **Deferrals** — explicit one-line rationale per deferred layer (`e2e N/A — schema-only, no UI yet` rather than silent absence)
433
+ - **Layers covered** — same list with ✓ or `NOT_NEEDED` (with reason)
434
+ - **Exemptions** — explicit one-line rationale per exempt layer (`e2e NOT_NEEDED — schema-only, no UI yet` rather than silent absence). Do not use "deferred" as a gate state — it is not a valid SDLC state (devaudit-installer#240). The CI validator (`validate-test-summary.sh`) will reject any summary containing "deferred".
409
435
  - **Skill invocation** — _"`e2e-test-engineer` invoked on turn N during Phase 2"_, with a turn pointer the reviewer can verify against the chat transcript
410
436
 
411
437
  If you authored or modified `e2e/**/*.spec.ts` directly without invoking this skill, that's a delegation gap — the `sdlc-implementer` Phase 2 audit (devaudit#132) will catch it before Phase 3. The honest record is: the skill ran (or didn't), the layers were chosen for stated reasons, and the test-execution-summary attribution points back at the chat turn where the decision happened.
@@ -265,7 +265,7 @@ Runs **first**, before any `REQ-XXX` is assigned. It decides which of the six ch
265
265
  3. **Announce a "Workflow Decision" block** (template below): change-type, commit-type, whether a `REQ-XXX` is needed, risk class, which stages/gates run, which approvals the **operator** must perform (UAT four-eyes, Production approval), and what is **skipped**.
266
266
  4. **Pause policy — pause-when-it-matters.** Pause for explicit confirmation on **tracked / heavier** paths, or when classification is **ambiguous**; **announce-and-auto-proceed** on trivial / housekeeping. The operator can always reclassify ("treat this as housekeeping" / "this is HIGH risk").
267
267
  5. **Route — and stay on to completion.** A route is a choice of _which workflow to drive_, never a hand-off that abandons the operator. Whatever the path, the skill keeps guiding step by step until no further action is required (typically: merged).
268
- - **tracked** (feature / bug fix / refactor / perf) → continue into Phase 1 below (full Stages 1–5). **Write the skill-invocation sentinel** (devaudit-installer#226): `npx devaudit-sdlc --phase=issue`. This invokes the v0.2.0 CLI engine, which appends a JSON phase record to `.sdlc-implementer-invoked` (a gitignored, local-only file). The pre-push hook checks for this file's existence before allowing `feat`/`fix`/`refactor`/`perf` commits to be pushed. Without this sentinel, the pre-push hook will refuse the push and `validate-commits.sh` in CI will flag missing RTM provenance. Each subsequent phase transition (Phase 1, 2, 3, 4, 5) must also invoke `npx devaudit-sdlc --phase=<N>` to append its phase record to the sentinel.
268
+ - **tracked** (feature / bug fix / refactor / perf) → continue into Phase 1 below (full Stages 1–5). **Write the skill-invocation sentinel** (devaudit-installer#226): `node SDLC/bin/devaudit-sdlc.js --phase=issue` (or `node SDLC/bin/devaudit-sdlc.js --phase=issue` if the npm package is installed). This invokes the CLI engine, which appends a JSON phase record to `.sdlc-implementer-invoked` (a gitignored, local-only file). The pre-push hook checks for this file's existence before allowing `feat`/`fix`/`refactor`/`perf` commits to be pushed. Without this sentinel, the pre-push hook will refuse the push and `validate-commits.sh` in CI will flag missing RTM provenance. Each subsequent phase transition (Phase 1, 2, 3, 4, 5) must also invoke `node SDLC/bin/devaudit-sdlc.js --phase=<N>` to append its phase record to the sentinel.
269
269
  - **housekeeping / trivial** → drive the **Lightweight path** below to completion. No `REQ-XXX`, no RTM row, no evidence pack, no portal release approvals — but the skill still branches, runs the gates, opens the PR, and walks the operator through review → merge.
270
270
  - **compliance-doc-only** → drive the same Lightweight path as a docs push (or PR, per the project's flow) referencing the **existing** `REQ-XXX`: no new requirement and no quality-gate ceremony, but driven through to merge.
271
271
  6. **Write labels back.** Apply the inferred `type:*` / `risk:*` labels so the issue ends up labelled — `gh label create <label> --force` to ensure the label exists (idempotent; no failure if a label-seeding step never ran), then `gh issue edit <N> --add-label <label>`. Future triage is then a glance.
@@ -409,6 +409,15 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
409
409
  - **Requirements deviation** (an AC is wrong, incomplete, or missing) — trigger the [requirements gap flow](#requirements-gap-flow-devaudit-installer212). Do NOT just note it as a plan deviation. The AC table must be updated, `requirements-aligner` must be re-invoked to re-check SRS alignment, and the RTM must be updated.
410
410
 
411
411
  The classification question: "Did the implementation deviate from the plan's approach (how to build it), or did the plan's requirements deviate from reality (what to build)?" If the former, note and continue. If the latter, trigger the requirements gap flow.
412
+
413
+ 4b. **Reconcile test-plan.md file paths with actual files (devaudit-installer#241).** After writing/updating tests (both unit and E2E), diff the actual test file paths against `compliance/evidence/REQ-XXX/test-plan.md`. The test plan was authored during Stage 1 with predicted file paths — during implementation, tests are often added to existing files instead of creating new ones. This is a natural drift, but it must be reconciled before committing so `validate-compliance-artifacts.sh` doesn't fail at PR time.
414
+
415
+ For each file path referenced in `test-plan.md`:
416
+ - If the file exists on disk → OK, no action needed.
417
+ - If the file does not exist → check whether a test covering the same AC was added to a different file. If so, update `test-plan.md` to reference the actual file path.
418
+ - If the file does not exist and no equivalent test was found → **HALT**: "test-plan.md references <file> but no test file exists and no equivalent test covering the same AC was found. Either create the test file, update test-plan.md to point to the actual test file, or remove the entry if the AC is no longer relevant."
419
+
420
+ Commit the updated `test-plan.md` alongside the test code. This is a file-path reconciliation — it does not change the AC table (that's the step 5b plan ↔ test-scope AC consistency check, which is separate and checks AC drift, not file-path drift).
412
421
  5. **Run gates locally, cheap-first.** The gates are not equivalent-cost — `npm run lint` is seconds, `npx playwright test` is 30–60 minutes. Iterate on the fast gates; spend the e2e cost once.
413
422
 
414
423
  **Fast gates** (run on every change, ideally pre-commit):
@@ -428,7 +437,9 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
428
437
  git diff --name-only "$INTEGRATION_BRANCH"...HEAD -- 'app/**/*.tsx' 'src/**/*.tsx' 'pages/**/*.tsx' 'app/**/*.jsx' 'src/**/*.jsx' 'pages/**/*.jsx'
429
438
  ```
430
439
 
431
- - **If UI-facing files are present:** check for `.e2e-gate-passed` sentinel file (written by `e2e-test-engineer` after a successful run) or `playwright-report/` directory with recent content. If neither exists, **HALT**: "E2E gate was not run. The change touches UI-facing files. Run `npx playwright test` (or invoke `e2e-test-engineer`) before committing. The pre-push hook will also block this push."
440
+ - **If UI-facing files are present:** check for `.e2e-gate-passed` sentinel file (written by `e2e-test-engineer` after a successful run) or `playwright-report/` directory with recent content. If neither exists, **HALT**: "E2E gate was not run. The change touches UI-facing files. Run `npx playwright test` (or invoke `e2e-test-engineer`) before committing. Do not defer to CI — install Playwright browsers with `npx playwright install` if needed. The pre-push hook will also block this push."
441
+
442
+ **Also check for `.e2e-evidence-wired` sentinel (devaudit-installer#226).** If `e2e/**/*.spec.ts` files were authored or modified, verify the `.e2e-evidence-wired` sentinel exists (written by `e2e-test-engineer` Phase 5½ after validating `tagTest()` and `evidenceShot()` calls). If missing, **HALT**: "Evidence wiring validation (Phase 5½) was not run. The change includes E2E spec files but no evidence wiring sentinel. Invoke `e2e-test-engineer` to validate `tagTest()` and `evidenceShot()` calls before committing. The pre-push hook will also block this push."
432
443
  - **If no UI-facing files (API-only, config, docs):** skip the check. Note the exemption in the commit body: "E2E gate skipped — no UI-facing files in this change."
433
444
  - **If `e2e-test-engineer` was invoked and determined e2e is not needed** (e.g. schema-only change): the skill writes `.e2e-gate-passed` with a `NOT_NEEDED` reason. The sentinel check passes. Note the exemption in the commit body: "E2E gate not needed — e2e-test-engineer assessed no UI surface (turn N)."
434
445
 
@@ -491,6 +502,14 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
491
502
  - The nil report uploads as `incident_report` evidence via `compliance-evidence.yml`'s `upload_incident_report` function, flipping `ISO29119.3.5.4` to COVERED for clean releases.
492
503
  - If incidents WERE closed, skip nil report generation — the populated incident report(s) from `incident-export.yml` serve as the evidence.
493
504
 
505
+ 5b. **Validate test-execution-summary.md gate states (devaudit-installer#240).** Before uploading evidence, verify that `compliance/evidence/REQ-XXX/test-execution-summary.md` does not contain invalid gate states. Run:
506
+
507
+ ```bash
508
+ bash scripts/validate-test-summary.sh origin/main
509
+ ```
510
+
511
+ If the validator fails, fix the summary before proceeding. E2E gate results must be one of: `PASS`, `FAIL`, `NOT_NEEDED` (with reason), or `SKIPPED` (with operator-approved rationale). The word "deferred" must never appear in `test-execution-summary.md` — not as a gate state, not in prose, not in final assessment. "Deferred to CI" and "Playwright browsers not installed locally" are environment issues, not gate states. The CI validator (`validate-test-summary.sh`) will reject any summary containing "deferred" or "browsers not installed" on PRs to main.
512
+
494
513
  6. **Organise artefacts** under `compliance/evidence/REQ-XXX/` with date-prefixed naming:
495
514
 
496
515
  ```
@@ -793,10 +793,35 @@ jobs:
793
793
  # specs exist on disk. If specs are found but weren't run in
794
794
  # this tier, emit a non-blocking warning instead of an error.
795
795
  SPECS_ON_DISK=$(grep -rl --include='*.spec.ts' -e "@requirement ${REQ}" -e "tagTest.*${REQ}" -e "'${REQ}'" e2e/ 2>/dev/null | wc -l)
796
+
797
+ # devaudit-installer#237 — also scan unit test files for
798
+ # @requirement REQ-XXX annotations. A REQ with thorough unit
799
+ # test coverage but no E2E specs (legitimate for API-only or
800
+ # backend-only changes) should not be hard-blocked.
801
+ UNIT_TESTS_ON_DISK=$(grep -rl --include='*.test.ts' --include='*.test.tsx' -e "@requirement ${REQ}" -e "'${REQ}'" e2e/ __tests__/ tests/ src/ 2>/dev/null | wc -l)
802
+
803
+ # devaudit-installer#237 — check for test-execution-summary.md
804
+ # as a secondary signal. This is a human-authored document and
805
+ # weaker than machine-generated evidence, so it only converts
806
+ # a hard error to a warning when combined with unit test files
807
+ # on disk — never alone.
808
+ HAS_SUMMARY=false
809
+ if [ -f "compliance/evidence/${REQ}/test-execution-summary.md" ]; then
810
+ HAS_SUMMARY=true
811
+ fi
812
+
796
813
  if [ "$SPECS_ON_DISK" -gt 0 ]; then
814
+ # Scenario B: E2E specs exist on disk but outside the smoke tier
797
815
  echo "::warning::Evidence completeness gate: ${REQ} has zero tagged tests in this smoke run and zero per-AC screenshots, but ${SPECS_ON_DISK} spec file(s) on disk reference it (outside the smoke project). Evidence exists but was not executed in this CI tier. Consider running --project=critical or --grep \"${REQ}\" to capture evidence."
816
+ elif [ "$UNIT_TESTS_ON_DISK" -gt 0 ] && [ "$HAS_SUMMARY" = "true" ]; then
817
+ # Scenario C: unit test files exist with @requirement annotations
818
+ # and a test-execution-summary.md documents coverage
819
+ echo "::warning::Evidence completeness gate: ${REQ} has zero E2E tagged tests and zero screenshots, but ${UNIT_TESTS_ON_DISK} unit test file(s) on disk reference it and a test-execution-summary.md exists. Unit test evidence found but execution was not verified in this run. If this is an API-only or backend-only change, this is expected."
798
820
  else
799
- echo "::error::Evidence completeness gate: ${REQ} has zero tagged tests AND zero per-AC screenshots. The release cannot proceed to UAT with no traceable evidence. Ensure specs carry @requirement ${REQ} annotations and evidenceShot() calls (skill Phase 5½, issue #170)."
821
+ # Scenario A: genuinely no evidence no E2E specs, no unit tests,
822
+ # no test-execution-summary. Hard error preserved (#237 Constraint 3).
823
+ echo "::error::Evidence completeness gate: ${REQ} has zero traceable evidence — no tagged E2E tests, no per-AC screenshots, no unit test files with @requirement annotations, and no test-execution-summary.md. The release cannot proceed to UAT with no traceable per-REQ evidence."
824
+ echo "::error::If E2E specs exist for this REQ, ensure they carry @requirement ${REQ} JSDoc annotations and tagTest() calls (e2e-test-engineer Phase 5½, issue #170). If unit tests exist, add @requirement ${REQ} annotations to the .test.ts files. If this is a pure config/docs change with no testable surface, document it in test-execution-summary.md."
800
825
  EVIDENCE_GAPS=$((EVIDENCE_GAPS + 1))
801
826
  fi
802
827
  else
@@ -30,5 +30,8 @@ jobs:
30
30
  - name: Validate compliance artifacts
31
31
  run: bash scripts/validate-compliance-artifacts.sh origin/main
32
32
 
33
+ - name: Validate test execution summaries
34
+ run: bash scripts/validate-test-summary.sh origin/main
35
+
33
36
  - name: Validate commit conventions
34
37
  run: bash scripts/validate-commits.sh origin/main
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env bash
2
- # Husky pre-commit hook — runs lint-staged on staged files.
3
- # Catches linting issues before they enter the commit history.
2
+ # Husky pre-commit hook — SDLC guard + lint-staged on staged files.
3
+ #
4
+ # 1. SDLC guard — blocks manual execution on tracked branches (#231)
5
+ # 2. lint-staged — catches linting issues before they enter the commit history
4
6
  #
5
7
  # Install: cp this file to .husky/pre-commit && chmod +x .husky/pre-commit
6
8
  #
@@ -10,4 +12,10 @@
10
12
  # "*.{ts,tsx,js,jsx,json,md}": ["prettier --write"]
11
13
  # }
12
14
 
15
+ # ── 1. SDLC guard (devaudit-installer#231) ──────────────────────────
16
+ if [ -f scripts/sdlc-guard.sh ]; then
17
+ bash scripts/sdlc-guard.sh
18
+ fi
19
+
20
+ # ── 2. lint-staged ──────────────────────────────────────────────────
13
21
  npx lint-staged
@@ -1,7 +1,8 @@
1
1
  #!/bin/sh
2
- # Husky pre-push hook — fast gates + E2E evidence + skill-invocation sentinel + compliance validator.
2
+ # Husky pre-push hook — SDLC guard + fast gates + E2E evidence + skill-invocation sentinel + compliance validator.
3
3
  #
4
- # Runs four checks before allowing a push:
4
+ # Runs five checks before allowing a push:
5
+ # 0. SDLC guard — branch-name check for manual execution detection (#231)
5
6
  # 1. TypeScript check (fast gate)
6
7
  # 2. E2E evidence check — if UI-facing files changed, verify Playwright ran
7
8
  # 3. Skill-invocation sentinel — if feat/fix/refactor/perf commits present,
@@ -15,6 +16,13 @@
15
16
 
16
17
  set -eu
17
18
 
19
+ # ── 0. SDLC guard (devaudit-installer#231) ──────────────────────────
20
+ # Fast-fail: if on a tracked branch (feat/fix/refactor/perf) and the
21
+ # sentinel is missing, bail before running expensive test suites.
22
+ if [ -f scripts/sdlc-guard.sh ]; then
23
+ bash scripts/sdlc-guard.sh
24
+ fi
25
+
18
26
  # ── 1. TypeScript check ──────────────────────────────────────────────
19
27
  echo "Pre-push: running TypeScript check..."
20
28
  npx tsc --noEmit
@@ -30,6 +38,8 @@ echo "Pre-push: TypeScript check passed."
30
38
  # Only fires if UI-facing files are in the push. Checks for either
31
39
  # playwright-report/ directory or .e2e-gate-passed sentinel (written by
32
40
  # e2e-test-engineer after a successful run).
41
+ # Also checks .e2e-evidence-wired sentinel if e2e spec files changed
42
+ # (written by e2e-test-engineer Phase 5½ after validating tagTest/evidenceShot).
33
43
  INTEGRATION_BRANCH=$(jq -r '.integration_branch // "develop"' sdlc-config.json 2>/dev/null || echo "develop")
34
44
 
35
45
  # Read stdin to get the pushed refs (husky pre-push protocol)
@@ -70,6 +80,23 @@ while read -r local_ref local_sha remote_ref remote_sha; do
70
80
  fi
71
81
  echo "Pre-push: E2E evidence check passed."
72
82
  fi
83
+
84
+ # Check for E2E spec file changes — require .e2e-evidence-wired sentinel
85
+ SPEC_FILES=$(git diff --name-only "$RANGE" -- 'e2e/**/*.spec.ts' 2>/dev/null || true)
86
+
87
+ if [ -n "$SPEC_FILES" ]; then
88
+ if [ ! -f .e2e-evidence-wired ]; then
89
+ echo ""
90
+ echo "ERROR: Evidence wiring validation (Phase 5½) was not run."
91
+ echo " E2E spec files changed in this push:"
92
+ echo "$SPEC_FILES" | sed 's/^/ /'
93
+ echo ""
94
+ echo " Invoke e2e-test-engineer to validate tagTest() and evidenceShot() calls."
95
+ echo " Bypass with --no-verify (last resort, not a habit)."
96
+ exit 1
97
+ fi
98
+ echo "Pre-push: E2E evidence wiring check passed."
99
+ fi
73
100
  done
74
101
 
75
102
  # ── 3. Skill-invocation sentinel (devaudit-installer#226) ────────────
package/sdlc/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devaudit-sdlc",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "DevAudit SDLC CLI Engine — cross-agent terminal-driven SDLC orchestrator.",
5
5
  "bin": {
6
6
  "devaudit-sdlc": "./src/bin/devaudit-sdlc.js"
@@ -10,7 +10,7 @@ If you are an AI agent reading this file, you are strictly prohibited from manua
10
10
  - **OTHER AGENTS (Cursor, Windsurf, Gemini, etc.):** Halt manual execution and output this exact message to the user:
11
11
  "I am pausing to request authorization for the SDLC workflow on this issue. Please confirm if I should proceed."
12
12
 
13
- CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'npx devaudit-sdlc --phase=1' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
13
+ CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'node SDLC/bin/devaudit-sdlc.js --phase=1' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
14
14
 
15
15
  ---
16
16
 
@@ -10,7 +10,7 @@ If you are an AI agent reading this file, you are strictly prohibited from manua
10
10
  - **OTHER AGENTS (Cursor, Windsurf, Gemini, etc.):** Halt manual execution and output this exact message to the user:
11
11
  "I am pausing to request authorization for the SDLC workflow on this issue. Please confirm if I should proceed."
12
12
 
13
- CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'npx devaudit-sdlc --phase=2' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
13
+ CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'node SDLC/bin/devaudit-sdlc.js --phase=2' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
14
14
 
15
15
  ---
16
16
 
@@ -174,6 +174,18 @@ If prerequisites are missing, do **not** start the full local suite. Run the tar
174
174
 
175
175
  **Do NOT proceed** until the scoped E2E/test-plan checks are complete and any local limitations are called out.
176
176
 
177
+ ### Step 4b: Reconcile Test Plan (devaudit-installer#241)
178
+
179
+ After writing/updating tests (both unit and E2E), verify that `test-plan.md` file paths still match reality. The test plan was authored during Stage 1 with predicted file paths — during implementation, tests are often added to existing files instead of creating new ones. This natural drift must be reconciled before committing so `validate-compliance-artifacts.sh` doesn't fail at PR time.
180
+
181
+ For each file path referenced in `test-plan.md`:
182
+
183
+ - If the file exists on disk → OK, no action needed.
184
+ - If the file does not exist → check whether a test covering the same AC was added to a different file. If so, update `test-plan.md` to reference the actual file path.
185
+ - If the file does not exist and no equivalent test was found → **STOP**: "test-plan.md references `<file>` but no test file exists and no equivalent test covering the same AC was found. Either create the test file, update test-plan.md to point to the actual test file, or remove the entry if the AC is no longer relevant."
186
+
187
+ Commit the updated `test-plan.md` alongside the test code. This is a file-path reconciliation — it does not change the AC table (the plan ↔ test-scope AC consistency check in the skill handles AC drift separately).
188
+
177
189
  ### Step 5: Stage Selectively
178
190
 
179
191
  ```bash
@@ -10,7 +10,7 @@ If you are an AI agent reading this file, you are strictly prohibited from manua
10
10
  - **OTHER AGENTS (Cursor, Windsurf, Gemini, etc.):** Halt manual execution and output this exact message to the user:
11
11
  "I am pausing to request authorization for the SDLC workflow on this issue. Please confirm if I should proceed."
12
12
 
13
- CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'npx devaudit-sdlc --phase=3' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
13
+ CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'node SDLC/bin/devaudit-sdlc.js --phase=3' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
14
14
 
15
15
  ---
16
16
 
@@ -10,7 +10,7 @@ If you are an AI agent reading this file, you are strictly prohibited from manua
10
10
  - **OTHER AGENTS (Cursor, Windsurf, Gemini, etc.):** Halt manual execution and output this exact message to the user:
11
11
  "I am pausing to request authorization for the SDLC workflow on this issue. Please confirm if I should proceed."
12
12
 
13
- CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'npx devaudit-sdlc --phase=4' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
13
+ CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'node SDLC/bin/devaudit-sdlc.js --phase=4' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
14
14
 
15
15
  ---
16
16
 
@@ -10,7 +10,7 @@ If you are an AI agent reading this file, you are strictly prohibited from manua
10
10
  - **OTHER AGENTS (Cursor, Windsurf, Gemini, etc.):** Halt manual execution and output this exact message to the user:
11
11
  "I am pausing to request authorization for the SDLC workflow on this issue. Please confirm if I should proceed."
12
12
 
13
- CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'npx devaudit-sdlc --phase=5' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
13
+ CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'node SDLC/bin/devaudit-sdlc.js --phase=5' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
14
14
 
15
15
  ---
16
16
 
@@ -8,7 +8,7 @@ If you are an AI agent reading this file, you are strictly prohibited from manua
8
8
  - **OTHER AGENTS (Cursor, Windsurf, Gemini, etc.):** Halt manual execution and output this exact message to the user:
9
9
  "I am pausing to request authorization for the SDLC workflow on this issue. Please confirm if I should proceed."
10
10
 
11
- CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'npx devaudit-sdlc --phase=issue' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
11
+ CRITICAL WORKFLOW REQUIRED AFTER AUTHORIZATION: Once the operator grants permission to proceed, you MUST immediately execute 'node SDLC/bin/devaudit-sdlc.js --phase=issue' to generate the required commit sentinel file in the root directory BEFORE making any file modifications or code changes. Failure to create this file will result in your local git commits being automatically blocked by our pre-commit hooks.
12
12
 
13
13
  End-to-end walkthrough for taking a GitHub issue from triage to merged-and-deployed under the Metasession SDLC. Audience: this project's developers and AI coding agents.
14
14
 
@@ -1,11 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(git init:*)",
5
- "Bash(git add:*)",
6
- "Bash(git branch:*)",
7
- "Bash(git commit:*)",
8
- "Bash(gh repo:*)"
9
- ]
10
- }
11
- }