@metasession.co/devaudit-cli 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metasession.co/devaudit-cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "DevAudit CLI — installs, syncs, and operates the Metasession SDLC across consumer projects.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@clack/prompts": "^0.8.2",
36
- "@metasession.co/devaudit-plugin-sdk": "^0.1.10",
36
+ "@metasession.co/devaudit-plugin-sdk": "^0.1.12",
37
37
  "commander": "^12.1.0",
38
38
  "consola": "^3.2.3",
39
39
  "env-paths": "^3.0.0",
@@ -15,6 +15,12 @@ Detailed workflow instructions are in this project's `SDLC/` directory. Read the
15
15
 
16
16
  When a workflow step requires detailed commands or templates, read the full workflow file rather than relying on the summary below.
17
17
 
18
+ ### Entry point: the `sdlc-implementer` skill
19
+
20
+ The default way to implement a tracked change is the **`sdlc-implementer`** skill (`.claude/skills/sdlc-implementer/SKILL.md`): give it one GitHub issue and it runs Stage 1 (classify risk, assign the next `REQ-XXX`, write the implementation plan, update `RTM.md`) through Stage 4 (PR + UAT review), delegating all end-to-end / visual test work to `e2e-test-engineer`. **Do NOT hand-roll implementation outside this flow** — every change starts from a requirement, which starts from an issue. The only exceptions are trivial housekeeping (docs, formatting, dependency bumps, CI tweaks).
21
+
22
+ **This is enforced, not just advised.** `feat` / `fix` / `refactor` / `perf` commits that cite no requirement (`[REQ-XXX]` in the subject or a `Ref: REQ-XXX` trailer) are **rejected** locally by the commit-msg hook (commitlint) and at PR CI by `validate-commits.sh` (which `--no-verify` cannot skip). So implementation work cannot reach `develop` without a requirement — which is also what keeps release labels correct (the version-deriver only falls back to a bare date for genuine housekeeping, never for real feature work). Housekeeping commit types remain exempt.
23
+
18
24
  ### Before ANY Code Change
19
25
 
20
26
  1. Ask: "Which GitHub Issue is this for?" before writing code. Fetch it with `gh issue view NNN`.
@@ -126,6 +126,8 @@ Write or update E2E tests **after** implementation. E2E tests need working UI/AP
126
126
 
127
127
  > **Skill available:** invoke the **`e2e-test-engineer`** skill for this step (at `.claude/skills/e2e-test-engineer/SKILL.md`). It derives scenarios from the requirement's acceptance criteria, reconciles with the existing test pack (flags obsoletes — but never deletes without confirmation), runs the suite, and files defects for failures or missed ACs. Framework-agnostic (Playwright, Cypress, pytest-playwright, etc.) and tracker-agnostic (GitHub, Linear, Jira, etc.). For projects with no e2e suite yet, the skill also covers bootstrapping one. See [`sdlc/SKILLS.md`](../sdlc/SKILLS.md) for the full list of available skills.
128
128
 
129
+ > **Run authenticated flows in CI.** Tests that need a logged-in session (admin forms, role-gated flows) belong in their own Playwright project that depends on `auth-setup`. Register that project name in `sdlc-config.json` `e2e_projects` and set `e2e_seed_command` / `e2e_env` so CI seeds fixtures and runs it as a **report-only** gate (continue-on-error — it surfaces failures as evidence without blocking the merge until proven stable). Prove each AC with an `evidenceShot(page, 'REQ-XXX', 'ACn-…')` so the PNG lands in `compliance/evidence/REQ-XXX/screenshots/`. This is what lets Stage 3 Step 10 reduce manual UAT to a light smoke instead of a full re-click.
130
+
129
131
  **4a. Review the test plan for E2E items:**
130
132
  ```bash
131
133
  cat compliance/evidence/REQ-XXX/test-plan.md
@@ -399,7 +399,7 @@ If it fails — typically a stale `devaudit.base_url`, a revoked `DEVAUDIT_API_K
399
399
  **Skip this step entirely if any of these are true:**
400
400
 
401
401
  - Project's `sdlc-config.json` has `uat.enabled: false` — meaning the project has no deployed UAT environment configured (internal services, retroactive-compliance pickups, etc.).
402
- - Requirement's risk class is **not** listed in project's `uat.required_risk_classes` (defaults: `payment`, `destructive_migration`, `realtime`, `physical_ux`). Text-only fixes, internal refactors, low-risk UI tweaks carry none of these and skip UAT-env verification.
402
+ - Requirement's risk class is **not** listed in project's `uat.required_risk_classes` (defaults: `payment`, `destructive_migration`, `realtime`, `physical_ux`). Text-only fixes, internal refactors, low-risk UI tweaks carry none of these and skip UAT-env verification. **Wildcard:** if `required_risk_classes` contains `"*"`, every requirement requires UAT-env verification regardless of risk class — use this for projects that deploy `develop` to a UAT environment and exercise every release there before promotion.
403
403
 
404
404
  When skipped, proceed directly to Step 11.
405
405
 
@@ -407,6 +407,8 @@ When skipped, proceed directly to Step 11.
407
407
 
408
408
  When this step DOES apply, the develop branch's auto-deploy to UAT must complete first. **Wait for the deployment to complete**, then verify the change works in the UAT environment.
409
409
 
410
+ > **Automated e2e shrinks this step — it does not delete it.** When a requirement's acceptance criteria are covered by **passing CI e2e tests** authored with the `e2e-test-engineer` skill (each AC proven by an `evidenceShot`, run via the report-only authenticated-e2e gate — see `sdlc-config.json` `e2e_projects` / `e2e_seed_command`), those ACs are already exercised against the running app on every push. For those ACs, this step is **not** a full manual re-click of every criterion: it reduces to a **light manual smoke** on the deployed UAT environment — confirm the build is live, the changed area loads, and spot-check anything the e2e couldn't reach (real third-party integrations, environment-specific config, payment sandboxes). Record which ACs were discharged by automated e2e vs. exercised manually. ACs **not** covered by a passing e2e test still need full manual verification here.
411
+
410
412
  #### WAIT CHECKPOINT: Confirm CI + Deployment Complete
411
413
 
412
414
  Before UAT verification, confirm BOTH CI and deployment are complete:
@@ -52,6 +52,28 @@ while IFS= read -r sha; do
52
52
  continue
53
53
  fi
54
54
 
55
+ # Requirement traceability: implementation commits (feat/fix/refactor/perf)
56
+ # MUST cite a requirement — [REQ-XXX] in the subject or a Ref: REQ-XXX
57
+ # trailer. Housekeeping types (docs/chore/ci/build/test/compliance/revert)
58
+ # are exempt. Mirrors the commitlint rule; this is the PR-CI half that
59
+ # `--no-verify` can't skip. Work starts from a requirement (which starts
60
+ # from an issue) — use the sdlc-implementer skill to assign one.
61
+ TYPE=$(echo "$SUBJECT" | grep -oE '^[a-z]+' || true)
62
+ case "$TYPE" in
63
+ feat|fix|refactor|perf)
64
+ if ! echo "$SUBJECT" | grep -qP '\[REQ-\d{3,}\]' \
65
+ && ! echo "$BODY" | grep -qiP 'Ref:\s*REQ-\d{3,}'; then
66
+ echo "ERROR [$SHORT]: '$TYPE' is an implementation commit but cites no requirement."
67
+ echo " Add [REQ-XXX] to the subject or a 'Ref: REQ-XXX' trailer. Start work"
68
+ echo " from a requirement via the sdlc-implementer skill (it assigns the REQ"
69
+ echo " from the originating issue in Phase 1)."
70
+ FAILED=$((FAILED + 1))
71
+ EXIT_CODE=1
72
+ continue
73
+ fi
74
+ ;;
75
+ esac
76
+
55
77
  # Check Co-Authored-By on commits that touch code files
56
78
  CODE_FILES=$(git diff-tree --no-commit-id --name-only -r "$sha" -- '*.ts' '*.tsx' '*.js' '*.jsx' '*.py' 2>/dev/null || true)
57
79
  if [ -n "$CODE_FILES" ]; then
@@ -150,7 +150,7 @@ jobs:
150
150
  PLAYWRIGHT_HTML_REPORTER_OPEN: never
151
151
  PLAYWRIGHT_JSON_OUTPUT_NAME: e2e-results.json
152
152
  run: npx playwright test --project={{E2E_PROJECT}} --reporter=json,html
153
-
153
+ {{E2E_AUTHENTICATED_STEP}}
154
154
  # ── Gate 5: Build ──
155
155
 
156
156
  - name: Build Check
@@ -169,6 +169,7 @@ jobs:
169
169
  sast-results.json
170
170
  dependency-audit.json
171
171
  e2e-results.json
172
+ e2e-auth-results.json
172
173
  playwright-report/
173
174
  coverage/coverage-summary.json
174
175
  retention-days: 90
@@ -20,6 +20,7 @@
20
20
  name: Compliance Evidence Upload
21
21
 
22
22
  on:
23
+ workflow_dispatch:
23
24
  push:
24
25
  branches: [develop]
25
26
  paths:
@@ -98,9 +99,16 @@ jobs:
98
99
  if: steps.resolve.outputs.skip != 'true'
99
100
  run: |
100
101
  chmod +x scripts/upload-evidence.sh 2>/dev/null || true
102
+ # Common flags WITHOUT --release. Each upload appends its OWN
103
+ # --release so per-requirement artifacts land in their own release
104
+ # record (version = REQ-ID) instead of all collapsing into whichever
105
+ # single version the triggering commit derived. DevAudit #135 follow-
106
+ # up: this fixes release *attribution* (not just duplication) — an
107
+ # untagged docs commit must not sweep every in-scope REQ into a date
108
+ # release. Note: upload-evidence.sh keeps the LAST --release seen.
101
109
  FLAGS="--git-sha ${{ github.sha }} --ci-run-id ${{ github.run_id }} --branch ${{ github.ref_name }}"
102
- FLAGS="${FLAGS} --release ${{ steps.version.outputs.version }} --create-release-if-missing"
103
- FLAGS="${FLAGS} --environment uat"
110
+ FLAGS="${FLAGS} --create-release-if-missing --environment uat"
111
+ DERIVED_RELEASE="${{ steps.version.outputs.version }}"
104
112
 
105
113
  # Upload compliance docs (planning category)
106
114
  for DOC in compliance/RTM.md compliance/test-plan.md compliance/test-cases.md compliance/test-summary-report.md; do
@@ -108,7 +116,7 @@ jobs:
108
116
  echo "Uploading: $(basename "$DOC")"
109
117
  bash scripts/upload-evidence.sh \
110
118
  {{PROJECT_SLUG}} _compliance-docs compliance_document "$DOC" \
111
- --category planning ${FLAGS} || echo "Warning: Failed to upload $(basename "$DOC")"
119
+ --category planning ${FLAGS} --release "${DERIVED_RELEASE}" || echo "Warning: Failed to upload $(basename "$DOC")"
112
120
  fi
113
121
  done
114
122
 
@@ -116,10 +124,20 @@ jobs:
116
124
  if [ -d "compliance/pending-releases" ]; then
117
125
  for TICKET in compliance/pending-releases/*.md; do
118
126
  [ -f "$TICKET" ] || continue
119
- echo "Uploading: $(basename "$TICKET")"
127
+ # A RELEASE-TICKET-REQ-XXX.md belongs to that requirement's
128
+ # release record; any other ticket rides the derived release.
129
+ TICKET_BASE=$(basename "$TICKET" .md)
130
+ case "$TICKET_BASE" in
131
+ RELEASE-TICKET-REQ-*)
132
+ TICKET_REQ="${TICKET_BASE#RELEASE-TICKET-}"
133
+ TICKET_OWNER="$TICKET_REQ"; TICKET_RELEASE="$TICKET_REQ" ;;
134
+ *)
135
+ TICKET_OWNER="_compliance-docs"; TICKET_RELEASE="$DERIVED_RELEASE" ;;
136
+ esac
137
+ echo "Uploading: $(basename "$TICKET") -> release ${TICKET_RELEASE}"
120
138
  bash scripts/upload-evidence.sh \
121
- {{PROJECT_SLUG}} _compliance-docs compliance_document "$TICKET" \
122
- --category release_artifact ${FLAGS} || echo "Warning: Failed to upload $(basename "$TICKET")"
139
+ {{PROJECT_SLUG}} "${TICKET_OWNER}" compliance_document "$TICKET" \
140
+ --category release_artifact ${FLAGS} --release "${TICKET_RELEASE}" || echo "Warning: Failed to upload $(basename "$TICKET")"
123
141
  done
124
142
  fi
125
143
 
@@ -152,7 +170,7 @@ jobs:
152
170
  echo "Uploading: ${REQ_ID}/$(basename "$ARTIFACT")"
153
171
  bash scripts/upload-evidence.sh \
154
172
  {{PROJECT_SLUG}} "${REQ_ID}" compliance_document "$ARTIFACT" \
155
- --category planning ${FLAGS} || echo "Warning: Failed to upload $(basename "$ARTIFACT")"
173
+ --category planning ${FLAGS} --release "${REQ_ID}" || echo "Warning: Failed to upload $(basename "$ARTIFACT")"
156
174
  done
157
175
  done
158
176
  fi
@@ -6,16 +6,27 @@
6
6
  # Production verification is READ-ONLY.
7
7
  # No E2E tests, no database operations, no API mutations.
8
8
  #
9
+ # Promotes EVERY in-scope release (each requirement with a pending release
10
+ # ticket), not just the first REQ found — a develop→main PR that bundles
11
+ # several requirements must advance all of them to the terminal status, else
12
+ # the requirements not picked first stay stuck at uat_approved with no
13
+ # production evidence. `workflow_dispatch` allows re-running / catching up a
14
+ # single release via the `release` input.
15
+ #
9
16
  # In sdlc-v1.22.0+ the terminal release status is configurable via
10
17
  # sdlc-config.json `production_review.terminal_status`:
11
18
  # - "prod_review" (default, Option A) — stop at prod_review; human in the
12
- # portal clicks "Approve Production" then "Mark as Released" for an
13
- # explicit audit trail. Closes #138.
19
+ # portal clicks "Approve Production" then "Mark as Released".
14
20
  # - "released" (Option B) — preserves v1.21.x auto-release behaviour.
15
21
 
16
22
  name: Post-Deploy Production Evidence
17
23
 
18
24
  on:
25
+ workflow_dispatch:
26
+ inputs:
27
+ release:
28
+ description: 'Optional REQ-XXX / version to promote (blank = all in-scope from pending release tickets).'
29
+ required: false
19
30
  push:
20
31
  branches: [main]
21
32
 
@@ -30,11 +41,12 @@ jobs:
30
41
  PROJECT_SLUG: {{PROJECT_SLUG}}
31
42
  GIT_SHA: ${{ github.sha }}
32
43
  CI_RUN: ${{ github.run_id }}
44
+ RELEASE_INPUT: ${{ github.event.inputs.release }}
33
45
 
34
46
  steps:
35
47
  - uses: actions/checkout@v4
36
48
  with:
37
- fetch-depth: 0 # full history so the merged commits' REQ tags are readable
49
+ fetch-depth: 0 # full history so merged commits' REQ tags are readable
38
50
 
39
51
  - name: Resolve DevAudit base URL and post-deploy terminal status
40
52
  run: |
@@ -75,37 +87,31 @@ jobs:
75
87
  echo "DEVAUDIT_BASE_URL=${BASE%/}" >> "$GITHUB_ENV"
76
88
  echo "TERMINAL_STATUS=${TERMINAL_STATUS}" >> "$GITHUB_ENV"
77
89
 
78
- - name: Resolve current release
79
- id: release
90
+ - name: Resolve in-scope releases
80
91
  run: |
81
- # Resolve the release being PROMOTED the same REQ the dev/UAT
82
- # pipeline versioned (ci.yml / compliance-evidence.yml use
83
- # derive-release-version.sh → REQ-XXX). The merge commit itself
84
- # carries no REQ tag, so derive it from the commits merged into
85
- # this push ([REQ-XXX] subject tags / Ref: lines), and only fall
86
- # back to a bare date when the consumer uses date-versioned
87
- # releases. Without this, a REQ-versioned release never converges:
88
- # production evidence + the prod-review advance land on a phantom
89
- # date release while the real REQ release stays uat_approved.
90
- REQ=$(git log "${{ github.event.before }}..${{ github.sha }}" --format='%s%n%b' 2>/dev/null \
91
- | grep -oiE '\[REQ-[0-9]+\]|Ref:[[:space:]]*REQ-[0-9]+' \
92
- | grep -oiE 'REQ-[0-9]+' | head -1 | tr '[:lower:]' '[:upper:]' || true)
93
- if [ -n "$REQ" ]; then
94
- PREFIX="$REQ"
92
+ # The releases being PROMOTED are the requirements with a pending
93
+ # release ticket (the same set the dev/UAT pipeline versioned via
94
+ # derive-release-version.sh → REQ-XXX). A bundled develop→main PR
95
+ # carries several; promote ALL of them, not just the first. A manual
96
+ # dispatch can target one via the `release` input. Fall back to a
97
+ # bare date for date-versioned (ticketless) releases.
98
+ if [ -n "${RELEASE_INPUT}" ]; then
99
+ REQS="${RELEASE_INPUT}"
95
100
  else
96
- PREFIX="v$(date +%Y.%m.%d)"
97
- fi
98
- echo "Resolving release for version prefix: ${PREFIX}"
99
- RESP=$(curl -s -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
100
- "${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
101
- VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
102
- if [ -z "$VERSION" ]; then
103
- VERSION="${PREFIX}"
101
+ REQS=""
102
+ if [ -d compliance/pending-releases ]; then
103
+ for T in compliance/pending-releases/RELEASE-TICKET-REQ-*.md; do
104
+ [ -f "$T" ] || continue
105
+ REQS="${REQS} $(basename "$T" .md | sed 's/^RELEASE-TICKET-//')"
106
+ done
107
+ fi
108
+ REQS=$(echo ${REQS} | tr ' ' '\n' | sort -u | tr '\n' ' ' | sed 's/[[:space:]]*$//')
109
+ if [ -z "${REQS}" ]; then
110
+ REQS="v$(date +%Y.%m.%d)"
111
+ fi
104
112
  fi
105
- RELEASE_ID=$(echo "$RESP" | jq -r '.latest.id // empty')
106
- echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
107
- echo "release_id=${RELEASE_ID}" >> "$GITHUB_OUTPUT"
108
- echo "Release version: ${VERSION}"
113
+ echo "In-scope releases to promote: ${REQS}"
114
+ echo "REQS=${REQS}" >> "$GITHUB_ENV"
109
115
 
110
116
  - name: Wait for production deployment
111
117
  run: |
@@ -142,63 +148,57 @@ jobs:
142
148
  }
143
149
  RESULTS_EOF
144
150
 
145
- - name: Upload production evidence
146
- run: |
147
- chmod +x scripts/upload-evidence.sh 2>/dev/null || true
148
- VERSION="${{ steps.release.outputs.version }}"
149
- FLAGS="--release ${VERSION} --create-release-if-missing --environment production --category test_report"
150
- FLAGS="${FLAGS} --git-sha ${GIT_SHA} --ci-run-id ${CI_RUN} --branch main"
151
- if [ -f prod-smoke-results.json ]; then
152
- bash scripts/upload-evidence.sh \
153
- "${PROJECT_SLUG}" "_compliance-docs" "test_report" prod-smoke-results.json \
154
- ${FLAGS} || echo "Warning: Failed to upload smoke results"
155
- fi
156
-
157
- - name: Upload release ticket to production
151
+ - name: Promote in-scope releases (evidence + status)
158
152
  run: |
159
- # Submit-for-production-review requires a release ticket (release_artifact)
160
- # in the PRODUCTION environment — the dev/UAT pipeline only uploads it to
161
- # uat. Carry the promoted release's ticket forward to production so the
162
- # production release is self-contained and the prod-review gate passes.
163
153
  chmod +x scripts/upload-evidence.sh 2>/dev/null || true
164
- VERSION="${{ steps.release.outputs.version }}"
165
- FLAGS="--release ${VERSION} --create-release-if-missing --environment production --category release_artifact"
166
- FLAGS="${FLAGS} --git-sha ${GIT_SHA} --ci-run-id ${CI_RUN} --branch main"
167
- TICKET=""
168
- for DIR in compliance/pending-releases compliance/approved-releases; do
169
- if [ -f "${DIR}/RELEASE-TICKET-${VERSION}.md" ]; then
170
- TICKET="${DIR}/RELEASE-TICKET-${VERSION}.md"
171
- break
154
+ PROMOTED=0
155
+ for PREFIX in ${REQS}; do
156
+ echo "=== Promoting ${PREFIX} ==="
157
+ RESP=$(curl -s -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
158
+ "${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
159
+ VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
160
+ [ -z "$VERSION" ] && VERSION="${PREFIX}"
161
+ RELEASE_ID=$(echo "$RESP" | jq -r '.latest.id // empty')
162
+ # Production smoke evidence (whole-app health) attached to this release.
163
+ if [ -f prod-smoke-results.json ]; then
164
+ bash scripts/upload-evidence.sh \
165
+ "${PROJECT_SLUG}" "${VERSION}" test_report prod-smoke-results.json \
166
+ --release "${VERSION}" --create-release-if-missing --environment production \
167
+ --category test_report --git-sha "${GIT_SHA}" --ci-run-id "${CI_RUN}" --branch main \
168
+ || echo "Warning: smoke upload failed for ${VERSION}"
169
+ fi
170
+ # Carry the release ticket into the production environment so the
171
+ # prod-review gate is self-contained.
172
+ TICKET=""
173
+ for DIR in compliance/pending-releases compliance/approved-releases; do
174
+ if [ -f "${DIR}/RELEASE-TICKET-${VERSION}.md" ]; then
175
+ TICKET="${DIR}/RELEASE-TICKET-${VERSION}.md"; break
176
+ fi
177
+ done
178
+ if [ -n "$TICKET" ]; then
179
+ bash scripts/upload-evidence.sh \
180
+ "${PROJECT_SLUG}" "${VERSION}" compliance_document "$TICKET" \
181
+ --release "${VERSION}" --create-release-if-missing --environment production \
182
+ --category release_artifact --git-sha "${GIT_SHA}" --ci-run-id "${CI_RUN}" --branch main \
183
+ || echo "Warning: ticket upload failed for ${VERSION}"
184
+ else
185
+ echo "No RELEASE-TICKET-${VERSION}.md found — skipping ticket (date-versioned or archived)."
186
+ fi
187
+ # Advance status (idempotent — re-PATCHing an already-promoted release is a no-op).
188
+ if [ -n "$RELEASE_ID" ]; then
189
+ curl -s -o /dev/null -w " ${VERSION} status patch: HTTP %{http_code}\n" \
190
+ -X PATCH "${BASE}/api/ci/releases/${RELEASE_ID}" \
191
+ -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
192
+ -H "Content-Type: application/json" \
193
+ -d "{\"status\":\"${TERMINAL_STATUS}\"}"
194
+ echo " ${VERSION} → ${TERMINAL_STATUS}"
195
+ PROMOTED=$((PROMOTED + 1))
196
+ else
197
+ echo "::warning::No release_id resolved for ${PREFIX} — skipping status patch"
172
198
  fi
173
199
  done
174
- if [ -n "$TICKET" ]; then
175
- echo "Uploading release ticket to production: $TICKET"
176
- bash scripts/upload-evidence.sh \
177
- "${PROJECT_SLUG}" "_compliance-docs" compliance_document "$TICKET" \
178
- ${FLAGS} || echo "Warning: Failed to upload release ticket to production"
179
- else
180
- echo "No RELEASE-TICKET-${VERSION}.md in pending-/approved-releases — skipping (date-versioned release or ticket archived)."
181
- fi
182
-
183
- - name: Advance release status (post-deploy)
184
- run: |
185
- RELEASE_ID="${{ steps.release.outputs.release_id }}"
186
- if [ -z "$RELEASE_ID" ]; then
187
- echo "::warning::No release_id resolved — skipping status patch"
188
- exit 0
200
+ echo "Promoted ${PROMOTED} release(s) to ${TERMINAL_STATUS}."
201
+ if [ "${TERMINAL_STATUS}" = "prod_review" ]; then
202
+ echo "Next: a human in the portal clicks 'Approve Production' then 'Mark as Released' for each."
203
+ echo "Audit trail captures both events with reviewer identity per compliance/risk-register.md."
189
204
  fi
190
- curl -s -o /dev/null -w "Release status patch: HTTP %{http_code}\n" \
191
- -X PATCH "${BASE}/api/ci/releases/${RELEASE_ID}" \
192
- -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
193
- -H "Content-Type: application/json" \
194
- -d "{\"status\":\"${TERMINAL_STATUS}\"}"
195
- case "$TERMINAL_STATUS" in
196
- prod_review)
197
- echo "Release ${{ steps.release.outputs.version }} → prod_review."
198
- echo "Next: a human in the portal clicks 'Approve Production' (→ prod_approved), then 'Mark as Released' (→ released)."
199
- echo "Audit trail captures both events with reviewer identity per compliance/risk-register.md."
200
- ;;
201
- released)
202
- echo "Release ${{ steps.release.outputs.version }} → released (Option B: auto-release with no post-deploy human gate)."
203
- ;;
204
- esac
@@ -32,6 +32,11 @@
32
32
  "e2e_project": "chromium",
33
33
  "e2e_start_command": "npm run dev",
34
34
 
35
+ "_comment_e2e_authenticated": "Optional report-only authenticated e2e gate (continue-on-error, never blocks the merge). e2e_projects = Playwright project names that need a logged-in session (auth-setup runs automatically as their dependency); e2e_seed_command seeds admins/fixtures before the run; e2e_env maps repo secrets onto the seed + e2e steps. Author these specs with the e2e-test-engineer skill (evidenceShot per AC). Leave empty to run only the blocking smoke project above.",
36
+ "e2e_seed_command": "",
37
+ "e2e_projects": [],
38
+ "e2e_env": {},
39
+
35
40
  "paths_ignore": [
36
41
  ".github/workflows/**",
37
42
  "SDLC/**",
@@ -53,7 +58,7 @@
53
58
  "api_key_secret": "DEVAUDIT_API_KEY"
54
59
  },
55
60
 
56
- "_comment_uat": "UAT-environment verification (Stage 3 Step 10). Opt-in: enabled=false skips Step 10 entirely. When enabled, only requirements whose risk class is listed in required_risk_classes go through UAT-env verification.",
61
+ "_comment_uat": "UAT-environment verification (Stage 3 Step 10). Opt-in: enabled=false skips Step 10 entirely. When enabled, only requirements whose risk class is listed in required_risk_classes go through UAT-env verification; use [\"*\"] to require it for every requirement (projects that UAT every release).",
57
62
  "uat": {
58
63
  "enabled": false,
59
64
  "url": "",
@@ -2,15 +2,24 @@
2
2
  * Commitlint configuration for Metasession SDLC.
3
3
  *
4
4
  * Enforces:
5
- * - Conventional Commits format (feat, fix, docs, test, refactor, chore, compliance, security)
6
- * - Co-Authored-By tag presence (warning not every commit is AI-generated)
7
- * - Ref: REQ-XXX trailer presence (warning trivial commits skip requirements)
5
+ * - Conventional Commits format (feat, fix, docs, test, refactor, chore, ).
6
+ * - Requirement traceability: **implementation** commits (feat / fix /
7
+ * refactor / perf) MUST cite a requirement via `[REQ-XXX]` in the subject
8
+ * or a `Ref: REQ-XXX` trailer (ERROR). Housekeeping types (docs, chore, ci,
9
+ * build, test, compliance, revert) are exempt. This is the local half of
10
+ * the "no implementation without a requirement" rule; `validate-commits.sh`
11
+ * enforces the same at PR CI (which `--no-verify` can't skip). Work starts
12
+ * from a requirement, which starts from an issue — run the `sdlc-implementer`
13
+ * skill, whose Phase 1 assigns the REQ from the originating issue.
14
+ * - Co-Authored-By trailer (warning — not every commit is AI-generated).
8
15
  *
9
16
  * Install:
10
17
  * npm install --save-dev @commitlint/cli @commitlint/config-conventional
11
18
  * cp this file to your project root as commitlint.config.mjs
12
19
  */
13
20
 
21
+ const IMPLEMENTATION_TYPES = ['feat', 'fix', 'refactor', 'perf'];
22
+
14
23
  export default {
15
24
  extends: ['@commitlint/config-conventional'],
16
25
  rules: {
@@ -35,20 +44,29 @@ export default {
35
44
  ],
36
45
  // Warn (not error) when body is missing — some commits are one-liners
37
46
  'body-empty': [1, 'never'],
47
+ // Implementation commits must trace to a requirement (ERROR)
48
+ 'requirement-ref-for-impl': [2, 'always'],
49
+ // AI-authored commits should be attributed (warning)
50
+ 'trailer-co-authored-by': [1, 'always'],
38
51
  },
39
52
  plugins: [
40
53
  {
41
54
  rules: {
42
- 'trailer-ref-requirement': ({ raw }) => {
43
- // Warn if Ref: REQ-XXX is missing trivial commits don't need it
44
- const hasRef = /Ref:\s*REQ-\d+/i.test(raw);
55
+ 'requirement-ref-for-impl': ({ type, raw }) => {
56
+ // Only implementation work is requirement-gated; housekeeping is exempt.
57
+ if (!IMPLEMENTATION_TYPES.includes(type)) return [true];
58
+ const hasRef =
59
+ /\[REQ-\d{3,}\]/i.test(raw) || /Ref:\s*REQ-\d{3,}/i.test(raw);
45
60
  return [
46
61
  hasRef,
47
- 'Commit should include "Ref: REQ-XXX" for tracked requirements',
62
+ `"${type}" is an implementation commit and must cite a requirement: ` +
63
+ `add [REQ-XXX] to the subject or a "Ref: REQ-XXX" trailer. Work must ` +
64
+ `start from a requirement (which starts from an issue) — run the ` +
65
+ `sdlc-implementer skill to assign one. Housekeeping types ` +
66
+ `(docs/chore/ci/build/test/compliance/revert) are exempt.`,
48
67
  ];
49
68
  },
50
69
  'trailer-co-authored-by': ({ raw }) => {
51
- // Warn if Co-Authored-By is missing — not every commit is AI-generated
52
70
  const hasCoAuthor = /Co-Authored-By:/i.test(raw);
53
71
  return [
54
72
  hasCoAuthor,
@@ -58,7 +76,5 @@ export default {
58
76
  },
59
77
  },
60
78
  ],
61
- // Apply custom rules as warnings (level 1), not errors
62
- // Override in your project if you want stricter enforcement
63
79
  helpUrl: 'https://www.conventionalcommits.org/',
64
80
  };