@metasession.co/devaudit-cli 0.3.17 → 0.3.19

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 (45) hide show
  1. package/dist/index.js +36 -34
  2. package/dist/index.js.map +1 -1
  3. package/package.json +2 -2
  4. package/scripts/upload-evidence.sh +23 -19
  5. package/sdlc/files/_common/governance/incident-report.md.template +6 -1
  6. package/sdlc/files/_common/governance/nil-incident-report.md.template +5 -2
  7. package/sdlc/files/_common/scripts/check-host-deployment.sh +58 -8
  8. package/sdlc/files/_common/scripts/check-host-deployment.test.sh +35 -3
  9. package/sdlc/files/_common/scripts/check-release-pr-scope.sh +8 -1
  10. package/sdlc/files/_common/scripts/check-release-pr-scope.test.sh +61 -12
  11. package/sdlc/files/_common/scripts/check-self-hosted-runner.sh +103 -0
  12. package/sdlc/files/_common/scripts/check-self-hosted-runner.test.sh +74 -0
  13. package/sdlc/files/_common/scripts/derive-release-version.sh +7 -9
  14. package/sdlc/files/_common/scripts/derive-release-version.test.sh +18 -18
  15. package/sdlc/files/_common/scripts/generate-bundled-changes.sh +24 -3
  16. package/sdlc/files/_common/scripts/generate-bundled-changes.test.sh +9 -5
  17. package/sdlc/files/_common/scripts/reconcile-railway-deployment.sh +37 -0
  18. package/sdlc/files/_common/scripts/reconcile-railway-deployment.test.sh +30 -0
  19. package/sdlc/files/_common/scripts/record-uat-execution.sh +195 -0
  20. package/sdlc/files/_common/scripts/record-uat-execution.test.sh +144 -0
  21. package/sdlc/files/_common/scripts/render-test-executions.sh +146 -0
  22. package/sdlc/files/_common/scripts/{render-test-cycles.test.sh → render-test-executions.test.sh} +12 -18
  23. package/sdlc/files/_common/scripts/{report-test-cycle.sh → report-test-execution.sh} +66 -74
  24. package/sdlc/files/_common/scripts/report-test-execution.test.sh +177 -0
  25. package/sdlc/files/_common/scripts/submit-for-uat-review.sh +21 -0
  26. package/sdlc/files/_common/scripts/upload-evidence.sh +23 -19
  27. package/sdlc/files/_common/scripts/validate-commits.sh +6 -4
  28. package/sdlc/files/_common/scripts/validate-commits.test.sh +15 -0
  29. package/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md +9 -7
  30. package/sdlc/files/_common/skills/e2e-test-engineer/references/e2e-regression-3-tier.yml +62 -10
  31. package/sdlc/files/_common/skills/sdlc-implementer/SKILL.md +19 -16
  32. package/sdlc/files/ci/ci.yml.template +86 -46
  33. package/sdlc/files/ci/compliance-evidence.yml.template +173 -49
  34. package/sdlc/files/ci/feature-e2e.yml.template +17 -17
  35. package/sdlc/files/ci/incident-export.yml.template +18 -4
  36. package/sdlc/files/ci/post-deploy-prod.yml.template +92 -48
  37. package/sdlc/files/ci/python/ci.yml.template +14 -14
  38. package/sdlc/files/ci/quality-gates-provenance.yml.template +3 -0
  39. package/sdlc/files/ci/reconcile-deployment.yml.template +59 -0
  40. package/sdlc/package.json +1 -1
  41. package/sdlc/src/blueprints/3-compile-evidence.raw.md +10 -10
  42. package/sdlc/src/blueprints/4-submit-for-review.raw.md +1 -1
  43. package/sdlc/src/blueprints/5-deploy-main.raw.md +1 -1
  44. package/sdlc/src/blueprints/implementing-an-sdlc-issue.raw.md +3 -3
  45. package/sdlc/files/_common/scripts/render-test-cycles.sh +0 -227
@@ -3,7 +3,9 @@
3
3
  # Generated by `devaudit install` / `devaudit update` from sdlc-config.json.
4
4
  # Do not edit manually — re-run the CLI (`devaudit update`) to regenerate.
5
5
  #
6
- # Production verification is READ-ONLY.
6
+ # Production verification is READ-ONLY and starts only after a successful
7
+ # production deployment status. It must not join the main-push check suite a
8
+ # host evaluates before deciding whether to deploy.
7
9
  # No E2E tests, no database operations, no API mutations.
8
10
  #
9
11
  # Promotes EVERY in-scope release (each requirement with a pending release
@@ -27,12 +29,19 @@ on:
27
29
  release:
28
30
  description: 'Optional REQ-XXX / version to promote (blank = all in-scope from pending release tickets).'
29
31
  required: false
30
- push:
31
- branches: [main]
32
+ deployment_status:
33
+ types: [created]
32
34
 
33
35
  jobs:
34
36
  production-evidence:
35
37
  name: Production Evidence
38
+ if: >-
39
+ github.event_name == 'workflow_dispatch' ||
40
+ (github.event.deployment_status.state == 'success' &&
41
+ (github.event.deployment.environment == 'production' ||
42
+ github.event.deployment.environment == 'prod' ||
43
+ endsWith(github.event.deployment.environment, '/ production') ||
44
+ endsWith(github.event.deployment.environment, '/production')))
36
45
  runs-on: {{RUNNER}}
37
46
  permissions:
38
47
  contents: read
@@ -43,7 +52,7 @@ jobs:
43
52
  DEVAUDIT_API_KEY: ${{ secrets.DEVAUDIT_API_KEY }}
44
53
  PROD_URL: ${{ secrets.{{PRODUCTION_URL_SECRET}} }}
45
54
  PROJECT_SLUG: {{PROJECT_SLUG}}
46
- GIT_SHA: ${{ github.sha }}
55
+ GIT_SHA: ${{ github.event.deployment.sha || github.sha }}
47
56
  CI_RUN: ${{ github.run_id }}
48
57
  RELEASE_INPUT: ${{ github.event.inputs.release }}
49
58
 
@@ -138,17 +147,17 @@ jobs:
138
147
  echo "In-scope releases to promote: ${REQS}"
139
148
  echo "REQS=${REQS}" >> "$GITHUB_ENV"
140
149
 
141
- - name: Start production deployment cycles
150
+ - name: Start production deployment executions
142
151
  run: |
143
- chmod +x scripts/report-test-cycle.sh 2>/dev/null || true
152
+ chmod +x scripts/report-test-execution.sh 2>/dev/null || true
144
153
  for PREFIX in ${REQS}; do
145
154
  RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
146
155
  "${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
147
156
  VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
148
157
  [ -n "$VERSION" ] || VERSION="$PREFIX"
149
- bash scripts/report-test-cycle.sh start \
158
+ bash scripts/report-test-execution.sh start \
150
159
  --project-slug "$PROJECT_SLUG" --release "$VERSION" \
151
- --sdlc-stage 5 --environment production --cycle-kind deployment \
160
+ --sdlc-stage 5 --environment production --suite-kind deployment \
152
161
  --provider github_actions --external-run-id "$CI_RUN" \
153
162
  --external-run-attempt "${{ github.run_attempt }}" --external-job-id "host-deployment" \
154
163
  --idempotency-key "github:${{ github.repository }}:post-deploy-prod.deployment:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
@@ -157,67 +166,90 @@ jobs:
157
166
  --workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
158
167
  done
159
168
 
160
- - name: Wait for production deployment
161
- id: wait_deployment
169
+ - name: Probe production health independently
170
+ id: production_probe
162
171
  run: |
172
+ set -euo pipefail
163
173
  DEPLOY_READY=false
174
+ LAST_HTTP_CODE=000
164
175
  for i in $(seq 1 30); do
165
176
  HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "${PROD_URL}/" || echo "000")
177
+ LAST_HTTP_CODE="$HTTP_CODE"
166
178
  if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then
167
- echo "Production is up (HTTP ${HTTP_CODE})"
179
+ echo "::notice::production health probe attempt=${i}/30 url=${PROD_URL}/ http_status=${HTTP_CODE}"
168
180
  DEPLOY_READY=true
169
181
  break
170
182
  fi
171
- echo "Attempt ${i}/30: HTTP ${HTTP_CODE} — waiting 10s..."
183
+ echo "::notice::production health probe attempt=${i}/30 url=${PROD_URL}/ http_status=${HTTP_CODE}"
172
184
  sleep 10
173
185
  done
174
- if [ "$DEPLOY_READY" != "true" ]; then
175
- echo "::error::Production did not become ready within the deployment window"
176
- exit 1
186
+ if [ "$DEPLOY_READY" = "true" ]; then
187
+ echo "outcome=success" >> "$GITHUB_OUTPUT"
188
+ echo "verification=production_health_success" >> "$GITHUB_OUTPUT"
189
+ else
190
+ echo "outcome=failure" >> "$GITHUB_OUTPUT"
191
+ echo "verification=production_health_timeout" >> "$GITHUB_OUTPUT"
192
+ echo "::error::production_health_timeout: ${PROD_URL}/ did not return a successful response after 30 attempts (last HTTP ${LAST_HTTP_CODE})."
177
193
  fi
194
+ echo "http_code=${LAST_HTTP_CODE}" >> "$GITHUB_OUTPUT"
178
195
 
179
196
  - name: Confirm terminal host deployment success
180
197
  id: host_deployment
181
- if: steps.wait_deployment.outcome == 'success'
182
198
  env:
183
199
  GH_TOKEN: ${{ github.token }}
184
200
  run: |
201
+ set +e
185
202
  chmod +x scripts/check-host-deployment.sh 2>/dev/null || true
186
203
  bash scripts/check-host-deployment.sh \
187
204
  --repo="${{ github.repository }}" \
188
205
  --sha="${GIT_SHA}" \
189
206
  --max-attempts=30 \
190
- --poll-seconds=10
207
+ --poll-seconds=10 \
208
+ --output-file=host-deployment-result.env
209
+ SCRIPT_EXIT=$?
210
+ set -e
211
+ if [ -f host-deployment-result.env ]; then
212
+ for KEY in verification deployment_id deployment_state target_url environment elapsed_seconds; do
213
+ VALUE=$(sed -n "s/^${KEY}=//p" host-deployment-result.env | head -n 1)
214
+ echo "${KEY}=${VALUE}" >> "$GITHUB_OUTPUT"
215
+ done
216
+ fi
217
+ exit "$SCRIPT_EXIT"
191
218
 
192
- - name: Complete production deployment cycles
219
+ - name: Complete production deployment executions
193
220
  if: always() && env.BASE != ''
194
221
  run: |
195
- if [ "${{ steps.wait_deployment.outcome }}" = "success" ] && [ "${{ steps.host_deployment.outcome }}" = "success" ]; then
222
+ HOST_VERIFICATION="${{ steps.host_deployment.outputs.verification || 'not_run' }}"
223
+ PROBE_VERIFICATION="${{ steps.production_probe.outputs.verification || 'not_run' }}"
224
+ if [ "$HOST_VERIFICATION" = "success" ] && [ "$PROBE_VERIFICATION" = "production_health_success" ]; then
196
225
  OUTCOME=passed
197
226
  CHECK_STATUS=successful
198
- elif [ "${{ steps.wait_deployment.outcome }}" = "cancelled" ] || [ "${{ steps.host_deployment.outcome }}" = "cancelled" ]; then
227
+ elif [ "$HOST_VERIFICATION" = "deployment_status_timeout" ]; then
228
+ OUTCOME=timed_out
229
+ CHECK_STATUS=failed
230
+ elif [ "${{ steps.host_deployment.outcome }}" = "cancelled" ]; then
199
231
  OUTCOME=cancelled
200
232
  CHECK_STATUS=cancelled
201
233
  else
202
234
  OUTCOME=failed
203
235
  CHECK_STATUS=failed
204
236
  fi
205
- chmod +x scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
237
+ chmod +x scripts/report-test-execution.sh scripts/report-release-check.sh 2>/dev/null || true
206
238
  for PREFIX in ${REQS}; do
207
239
  RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
208
240
  "${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
209
241
  VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
210
242
  [ -n "$VERSION" ] || VERSION="$PREFIX"
211
- bash scripts/report-test-cycle.sh complete \
243
+ bash scripts/report-test-execution.sh complete \
212
244
  --project-slug "$PROJECT_SLUG" --release "$VERSION" \
213
- --sdlc-stage 5 --environment production --cycle-kind deployment \
245
+ --sdlc-stage 5 --environment production --suite-kind deployment \
214
246
  --provider github_actions --external-run-id "$CI_RUN" \
215
247
  --external-run-attempt "${{ github.run_attempt }}" --external-job-id "host-deployment" \
216
248
  --idempotency-key "github:${{ github.repository }}:post-deploy-prod.deployment:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
217
249
  --commit-sha "$GIT_SHA" --branch main \
218
250
  --workflow-name "Post-Deploy Production" \
219
251
  --workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
220
- --outcome "$OUTCOME" --outcome-reason "host deployment: ${{ steps.host_deployment.outcome }}"
252
+ --outcome "$OUTCOME" --outcome-reason "host verification=${HOST_VERIFICATION}; production probe=${PROBE_VERIFICATION}; last HTTP=${{ steps.production_probe.outputs.http_code || 'unknown' }}"
221
253
  bash scripts/report-release-check.sh \
222
254
  --project-slug "$PROJECT_SLUG" --release "$VERSION" \
223
255
  --check-key "production-deployment:${CI_RUN}:${{ github.run_attempt }}" \
@@ -225,21 +257,33 @@ jobs:
225
257
  --external-run-id "$CI_RUN" \
226
258
  --external-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
227
259
  --commit-sha "$GIT_SHA" --branch main \
228
- --details-json '{"waitOutcome":"${{ steps.wait_deployment.outcome }}","hostOutcome":"${{ steps.host_deployment.outcome }}"}'
260
+ --details-json "$(jq -cn \
261
+ --arg hostVerification "$HOST_VERIFICATION" \
262
+ --arg hostOutcome "${{ steps.host_deployment.outcome }}" \
263
+ --arg deploymentId "${{ steps.host_deployment.outputs.deployment_id || '' }}" \
264
+ --arg deploymentState "${{ steps.host_deployment.outputs.deployment_state || '' }}" \
265
+ --arg targetUrl "${{ steps.host_deployment.outputs.target_url || '' }}" \
266
+ --arg probeVerification "$PROBE_VERIFICATION" \
267
+ --arg probeHttpCode "${{ steps.production_probe.outputs.http_code || '' }}" \
268
+ '{hostVerification:$hostVerification,hostOutcome:$hostOutcome,deploymentId:$deploymentId,deploymentState:$deploymentState,targetUrl:$targetUrl,probeVerification:$probeVerification,probeHttpCode:$probeHttpCode}')"
229
269
  done
270
+ if [ "$CHECK_STATUS" != "successful" ]; then
271
+ echo "::error::Production deployment verification is not successful: host=${HOST_VERIFICATION}, probe=${PROBE_VERIFICATION}. Investigate the hosting provider before retrying."
272
+ exit 1
273
+ fi
230
274
 
231
- - name: Start production smoke cycles
232
- if: steps.wait_deployment.outcome == 'success' && steps.host_deployment.outcome == 'success'
275
+ - name: Start production smoke executions
276
+ if: steps.production_probe.outputs.verification == 'production_health_success' && steps.host_deployment.outputs.verification == 'success'
233
277
  run: |
234
- chmod +x scripts/report-test-cycle.sh 2>/dev/null || true
278
+ chmod +x scripts/report-test-execution.sh 2>/dev/null || true
235
279
  for PREFIX in ${REQS}; do
236
280
  RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
237
281
  "${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
238
282
  VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
239
283
  [ -n "$VERSION" ] || VERSION="$PREFIX"
240
- bash scripts/report-test-cycle.sh start \
284
+ bash scripts/report-test-execution.sh start \
241
285
  --project-slug "$PROJECT_SLUG" --release "$VERSION" \
242
- --sdlc-stage 5 --environment production --cycle-kind smoke \
286
+ --sdlc-stage 5 --environment production --suite-kind smoke \
243
287
  --provider github_actions --external-run-id "$CI_RUN" \
244
288
  --external-run-attempt "${{ github.run_attempt }}" --external-job-id "production-smoke" \
245
289
  --idempotency-key "github:${{ github.repository }}:post-deploy-prod.smoke:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
@@ -250,7 +294,7 @@ jobs:
250
294
 
251
295
  - name: Production smoke tests (read-only)
252
296
  id: production_smoke
253
- if: steps.wait_deployment.outcome == 'success' && steps.host_deployment.outcome == 'success'
297
+ if: steps.production_probe.outputs.verification == 'production_health_success' && steps.host_deployment.outputs.verification == 'success'
254
298
  run: |
255
299
  echo "=== Production Smoke Tests ==="
256
300
  HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "${PROD_URL}/")
@@ -273,7 +317,7 @@ jobs:
273
317
  }
274
318
  RESULTS_EOF
275
319
 
276
- - name: Complete production smoke cycles
320
+ - name: Complete production smoke executions
277
321
  if: always() && env.BASE != '' && steps.host_deployment.outcome == 'success'
278
322
  run: |
279
323
  case "${{ steps.production_smoke.outcome }}" in
@@ -282,15 +326,15 @@ jobs:
282
326
  skipped) OUTCOME=skipped; CHECK_STATUS=skipped ;;
283
327
  *) OUTCOME=failed; CHECK_STATUS=failed ;;
284
328
  esac
285
- chmod +x scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
329
+ chmod +x scripts/report-test-execution.sh scripts/report-release-check.sh 2>/dev/null || true
286
330
  for PREFIX in ${REQS}; do
287
331
  RESP=$(curl -fsS -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
288
332
  "${BASE}/api/ci/releases/resolve?projectSlug=${PROJECT_SLUG}&versionPrefix=${PREFIX}")
289
333
  VERSION=$(echo "$RESP" | jq -r '.latest.version // empty')
290
334
  [ -n "$VERSION" ] || VERSION="$PREFIX"
291
- bash scripts/report-test-cycle.sh complete \
335
+ bash scripts/report-test-execution.sh complete \
292
336
  --project-slug "$PROJECT_SLUG" --release "$VERSION" \
293
- --sdlc-stage 5 --environment production --cycle-kind smoke \
337
+ --sdlc-stage 5 --environment production --suite-kind smoke \
294
338
  --provider github_actions --external-run-id "$CI_RUN" \
295
339
  --external-run-attempt "${{ github.run_attempt }}" --external-job-id "production-smoke" \
296
340
  --idempotency-key "github:${{ github.repository }}:post-deploy-prod.smoke:${CI_RUN}:${{ github.run_attempt }}:5:${VERSION}" \
@@ -324,8 +368,8 @@ jobs:
324
368
  # incident-export.yml fires on close → incident_report evidence
325
369
  # lands on the portal → ISO29119.3.5.4 + SOC2.CC7.2 flip to COVERED.
326
370
  #
327
- # testCycleId (CI run ID) cross-references #209 so the incident
328
- # report traces back to the specific test cycle that detected
371
+ # testExecutionId (CI run ID) cross-references #209 so the incident
372
+ # report traces back to the specific test execution that detected
329
373
  # the production failure.
330
374
  #
331
375
  # Ensure the incident label exists (idempotent).
@@ -344,7 +388,7 @@ jobs:
344
388
 
345
389
  **Production URL:** ${PROD_URL}
346
390
  **Git SHA:** ${GIT_SHA}
347
- **testCycleId:** ${CI_RUN}
391
+ **testExecutionId:** ${CI_RUN}
348
392
  **Workflow run:** ${WORKFLOW_URL}
349
393
  **Date:** ${DATE}
350
394
 
@@ -388,7 +432,7 @@ jobs:
388
432
  - name: Promote in-scope releases (evidence + status)
389
433
  if: steps.production_smoke.outcome == 'success'
390
434
  run: |
391
- chmod +x scripts/upload-evidence.sh scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
435
+ chmod +x scripts/upload-evidence.sh scripts/report-test-execution.sh scripts/report-release-check.sh 2>/dev/null || true
392
436
  PROMOTED=0
393
437
  EVIDENCE_FAILURES=0
394
438
  for PREFIX in ${REQS}; do
@@ -399,14 +443,14 @@ jobs:
399
443
  [ -z "$VERSION" ] && VERSION="${PREFIX}"
400
444
  RELEASE_ID=$(echo "$RESP" | jq -r '.latest.id // empty')
401
445
  REQ_FAILURES=0
402
- LINEAGE_FLAGS=(--test-cycle "${CI_RUN}")
403
- CYCLE_OUT="$(mktemp)"
404
- bash scripts/report-test-cycle.sh start \
446
+ LINEAGE_FLAGS=(--test-execution "${CI_RUN}")
447
+ EXECUTION_OUT="$(mktemp)"
448
+ bash scripts/report-test-execution.sh start \
405
449
  --project-slug "${PROJECT_SLUG}" \
406
450
  --release "${VERSION}" \
407
451
  --sdlc-stage 5 \
408
452
  --environment production \
409
- --cycle-kind smoke \
453
+ --suite-kind smoke \
410
454
  --provider github_actions \
411
455
  --external-run-id "${CI_RUN}" \
412
456
  --external-run-attempt "${{ github.run_attempt }}" \
@@ -416,11 +460,11 @@ jobs:
416
460
  --branch main \
417
461
  --workflow-name "Post-Deploy Production" \
418
462
  --workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
419
- --output-file "$CYCLE_OUT"
420
- . "$CYCLE_OUT"
421
- rm -f "$CYCLE_OUT"
422
- if [ "${cycle_supported:-false}" = "true" ] && [ -n "${cycle_record_id:-}" ]; then
423
- LINEAGE_FLAGS+=(--evidence-scope cycle --test-cycle-record-id "${cycle_record_id}")
463
+ --output-file "$EXECUTION_OUT"
464
+ . "$EXECUTION_OUT"
465
+ rm -f "$EXECUTION_OUT"
466
+ if [ "${execution_supported:-false}" = "true" ] && [ -n "${execution_record_id:-}" ]; then
467
+ LINEAGE_FLAGS+=(--evidence-scope execution --test-execution-record-id "${execution_record_id}")
424
468
  fi
425
469
  # Production smoke evidence (whole-app health) attached to this release.
426
470
  if [ -f prod-smoke-results.json ]; then
@@ -357,19 +357,19 @@ jobs:
357
357
  - name: Generate and upload gate evidence
358
358
  if: env.DEVAUDIT_BASE_URL != ''
359
359
  run: |
360
- chmod +x scripts/upload-evidence.sh scripts/report-test-cycle.sh 2>/dev/null || true
360
+ chmod +x scripts/upload-evidence.sh scripts/report-test-execution.sh 2>/dev/null || true
361
361
  FLAGS="--git-sha ${{ github.sha }} --ci-run-id ${{ github.run_id }} --branch ${{ github.ref_name }}"
362
362
  FLAGS="${FLAGS} --release ${{ needs.register-release.outputs.version }} --create-release-if-missing"
363
363
  FLAGS="${FLAGS} --environment uat"
364
364
  FLAGS="${FLAGS} --sdlc-stage 2"
365
- PRIMARY_LINEAGE_FLAGS=(--test-cycle "${{ github.run_id }}")
366
- CYCLE_OUT="$(mktemp)"
367
- bash scripts/report-test-cycle.sh start \
365
+ PRIMARY_LINEAGE_FLAGS=(--test-execution "${{ github.run_id }}")
366
+ EXECUTION_OUT="$(mktemp)"
367
+ bash scripts/report-test-execution.sh start \
368
368
  --project-slug {{PROJECT_SLUG}} \
369
369
  --release "${{ needs.register-release.outputs.version }}" \
370
370
  --sdlc-stage 2 \
371
371
  --environment uat \
372
- --cycle-kind quality_gate \
372
+ --suite-kind quality_gate \
373
373
  --provider github_actions \
374
374
  --external-run-id "${{ github.run_id }}" \
375
375
  --external-run-attempt "${{ github.run_attempt }}" \
@@ -378,11 +378,11 @@ jobs:
378
378
  --branch "${{ github.ref_name }}" \
379
379
  --workflow-name "Quality Gates" \
380
380
  --workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
381
- --output-file "$CYCLE_OUT"
382
- . "$CYCLE_OUT"
383
- rm -f "$CYCLE_OUT"
384
- if [ "${cycle_supported:-false}" = "true" ] && [ -n "${cycle_record_id:-}" ]; then
385
- PRIMARY_LINEAGE_FLAGS+=(--evidence-scope cycle --test-cycle-record-id "${cycle_record_id}")
381
+ --output-file "$EXECUTION_OUT"
382
+ . "$EXECUTION_OUT"
383
+ rm -f "$EXECUTION_OUT"
384
+ if [ "${execution_supported:-false}" = "true" ] && [ -n "${execution_record_id:-}" ]; then
385
+ PRIMARY_LINEAGE_FLAGS+=(--evidence-scope execution --test-execution-record-id "${execution_record_id}")
386
386
  fi
387
387
 
388
388
  UPLOAD_FAILURES=0
@@ -546,7 +546,7 @@ jobs:
546
546
  exit 1
547
547
  fi
548
548
 
549
- - name: Complete primary quality-gate cycle
549
+ - name: Complete primary quality-gate execution
550
550
  if: always() && env.DEVAUDIT_BASE_URL != ''
551
551
  run: |
552
552
  case "${{ job.status }}" in
@@ -554,13 +554,13 @@ jobs:
554
554
  cancelled) OUTCOME=cancelled ;;
555
555
  *) OUTCOME=failed ;;
556
556
  esac
557
- chmod +x scripts/report-test-cycle.sh 2>/dev/null || true
558
- bash scripts/report-test-cycle.sh complete \
557
+ chmod +x scripts/report-test-execution.sh 2>/dev/null || true
558
+ bash scripts/report-test-execution.sh complete \
559
559
  --project-slug {{PROJECT_SLUG}} \
560
560
  --release "${{ needs.register-release.outputs.version }}" \
561
561
  --sdlc-stage 2 \
562
562
  --environment uat \
563
- --cycle-kind quality_gate \
563
+ --suite-kind quality_gate \
564
564
  --provider github_actions \
565
565
  --external-run-id "${{ github.run_id }}" \
566
566
  --external-run-attempt "${{ github.run_attempt }}" \
@@ -42,6 +42,9 @@ jobs:
42
42
  PR_TITLE: ${{ github.event.pull_request.title }}
43
43
  PR_BODY: ${{ github.event.pull_request.body }}
44
44
  HEAD_REF: ${{ github.event.pull_request.head.ref }}
45
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
46
+ INTEGRATION_BRANCH: {{INTEGRATION_BRANCH}}
47
+ RELEASE_BRANCH: {{RELEASE_BRANCH}}
45
48
  run: |
46
49
  chmod +x scripts/check-release-pr-scope.sh 2>/dev/null || true
47
50
  bash scripts/check-release-pr-scope.sh
@@ -0,0 +1,59 @@
1
+ name: Reconcile Verified Host Deployment
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ release:
7
+ description: 'REQ-XXX release receiving recovery evidence'
8
+ required: true
9
+ expected_sha:
10
+ description: 'Exact main SHA verified at the provider'
11
+ required: true
12
+ github_deployment_id:
13
+ description: 'Existing GitHub deployment ID to reconcile'
14
+ required: true
15
+ railway_deployment_id:
16
+ description: 'Terminal-successful Railway deployment ID'
17
+ required: true
18
+ railway_project:
19
+ description: 'Railway project ID'
20
+ required: true
21
+ railway_service:
22
+ description: 'Railway service ID or name'
23
+ required: true
24
+ health_url:
25
+ description: 'Configured production health URL'
26
+ required: true
27
+
28
+ jobs:
29
+ reconcile:
30
+ name: Verify and reconcile deployment
31
+ runs-on: {{RUNNER}}
32
+ permissions:
33
+ contents: read
34
+ deployments: write
35
+ env:
36
+ DEVAUDIT_API_KEY: ${{ secrets.DEVAUDIT_API_KEY }}
37
+ DEVAUDIT_BASE_URL: ${{ vars.DEVAUDIT_BASE_URL }}
38
+ steps:
39
+ - uses: actions/checkout@v6
40
+ with:
41
+ ref: ${{ inputs.expected_sha }}
42
+ - name: Verify provider deployment before reconciliation
43
+ env:
44
+ GH_TOKEN: ${{ github.token }}
45
+ RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
46
+ run: |
47
+ chmod +x scripts/reconcile-railway-deployment.sh
48
+ bash scripts/reconcile-railway-deployment.sh \
49
+ --repo="${{ github.repository }}" --sha="${{ inputs.expected_sha }}" \
50
+ --github-deployment-id="${{ inputs.github_deployment_id }}" \
51
+ --railway-deployment-id="${{ inputs.railway_deployment_id }}" \
52
+ --railway-project="${{ inputs.railway_project }}" --railway-service="${{ inputs.railway_service }}" \
53
+ --health-url="${{ inputs.health_url }}"
54
+ - name: Upload manual reconciliation evidence
55
+ run: |
56
+ bash scripts/upload-evidence.sh {{PROJECT_SLUG}} "${{ inputs.release }}" test_report deployment-reconciliation.json \
57
+ --category release_artifact --release "${{ inputs.release }}" --environment production \
58
+ --git-sha "${{ inputs.expected_sha }}" --branch main --sdlc-stage 5 \
59
+ --meta-key 'provenance=manual_reconciliation' --meta-key 'provider=railway'
package/sdlc/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metasession.co/devaudit-sdlc",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
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"
@@ -82,7 +82,7 @@ A release is classified by version shape and release mode. **Most of this doc wa
82
82
 
83
83
  ### Housekeeping outcomes
84
84
 
85
- Normal housekeeping skips the per-requirement evidence and approval path. Run the relevant gates, obtain terminal-green PR review, and merge to `develop`; the bare-date portal row is integration history. When a tracked release later absorbs the work, its bundled-change manifest preserves the source title, evidence ownership, stage, and cycles.
85
+ Normal housekeeping skips the per-requirement evidence and approval path. Run the relevant gates, obtain terminal-green PR review, and merge to `develop`; the bare-date portal row is integration history. When a tracked release later absorbs the work, its bundled-change manifest preserves the source title, evidence ownership, stage, and executions.
86
86
 
87
87
  Use standalone housekeeping only when the change cannot reasonably wait for that tracked release. Follow `docs/release-playbooks/housekeeping-release.md`: add the validated `STANDALONE-HOUSEKEEPING-vYYYY.MM.DD.json` declaration, document why promotion is necessary, pass the required checks, and verify production. There is no automatic release-ticket or security-summary stub PR for either housekeeping outcome.
88
88
 
@@ -173,27 +173,27 @@ Rules:
173
173
  - `environment_gap` and `precondition_gap` skips must be resolved before listing — if they appear here, the gate is not truly `SKIPPED` with operator approval.
174
174
  - A skipped test never proves an acceptance criterion.
175
175
 
176
- ## Test Cycles
176
+ ## Test Executions
177
177
 
178
- Prefer the first-class release-journey / cycle API when the portal exposes it. Generate the table from the API response rather than inferring cycles from uploaded files:
178
+ Prefer the first-class release-journey / execution API when the portal exposes it. Generate the table from the API response rather than inferring executions from uploaded files:
179
179
 
180
180
  ```bash
181
181
  # Example:
182
182
  curl -s -H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
183
183
  "${DEVAUDIT_BASE_URL%/}/api/projects/<slug>/releases/REQ-XXX/journey" \
184
184
  > /tmp/release-journey.json
185
- bash scripts/render-test-cycles.sh /tmp/release-journey.json
185
+ bash scripts/render-test-executions.sh /tmp/release-journey.json
186
186
  ```
187
187
 
188
- The helper renders a first-class table when `.cycles[]` is present, and falls back to legacy `testCycleId` grouping when the portal has not yet rolled out cycle records.
188
+ The helper renders a first-class table when `.testExecutions[]` is present. It must not infer executions from legacy artifact grouping.
189
189
 
190
- | Source Release | SDLC Stage | Cycle | Kind | Outcome | Workflow / Run | Related Evidence | Incident / Remediation | Date |
190
+ | Source Release | SDLC Stage | Execution | Kind | Outcome | Workflow / Run | Related Evidence | Incident / Remediation | Date |
191
191
  | --- | --- | --- | --- | --- | --- | --- | --- | --- |
192
192
  | REQ-XXX | 2 implement_test | #1 | quality_gate | passed | [Quality Gates](https://github.com/example/repo/actions/runs/123) (run 123, attempt 1) | quality-gates.json | None | 2026-07-16 11:03:00 |
193
193
  | REQ-XXX | 2 implement_test | #2 | e2e | passed | [E2E Regression](https://github.com/example/repo/actions/runs/124) (run 124, attempt 2) | e2e-results.json, screenshots.zip | Incident #501 fixed in PR #507 | 2026-07-16 11:19:00 |
194
194
  | REQ-089 | 4 uat_review | #1 | uat | passed | [UAT Review](https://devaudit.example/releases/REQ-089) | uat-checklist.md | None | 2026-07-16 12:02:00 |
195
195
 
196
- **Final assessment:** [First-class cycle records show all stage cycles passed / N cycles failed — see incidents]
196
+ **Final assessment:** [First-class test execution records show all stage executions passed / N executions failed — see incidents]
197
197
 
198
198
  ## Bundled Release Context
199
199
 
@@ -338,12 +338,12 @@ status: "nil"
338
338
 
339
339
  ## Attestation
340
340
 
341
- No incidents or defects were discovered during the test cycle for release `<version>`.
341
+ No incidents or defects were discovered during the test execution for release `<version>`.
342
342
 
343
343
  ## Scope
344
344
 
345
345
  - **Release:** <version>
346
- - **Test cycle:** <description>
346
+ - **Test execution:** <description>
347
347
  - **Test cases executed:** <count>
348
348
  - **Test cases passed:** <count>
349
349
  - **Test cases failed:** 0
@@ -352,7 +352,7 @@ No incidents or defects were discovered during the test cycle for release `<vers
352
352
 
353
353
  ## Framework attribution
354
354
 
355
- - [x] `ISO29119.3.5.4` (Test incident report — nil report for this release cycle)
355
+ - [x] `ISO29119.3.5.4` (Test incident report — nil report for this release execution)
356
356
 
357
357
  ## Sign-off
358
358
 
@@ -179,7 +179,7 @@ CI runs automatically on this PR. The following gates must pass before merge:
179
179
  - [ ] Implementation plan present and matches implementation (MEDIUM/HIGH risk)
180
180
  - [ ] Release ticket created
181
181
  - [ ] Test evidence saved
182
- - [ ] Test execution summary includes Test Cycles section (all CI runs for this release listed)
182
+ - [ ] Test execution summary includes Test Executions section (all CI runs for this release listed)
183
183
  - [ ] Security evidence saved
184
184
  - [ ] AI use documented
185
185
 
@@ -151,7 +151,7 @@ The backend stores both with reviewer identity, SHA, and timestamp. This satisfi
151
151
 
152
152
  1. Wait for `post-deploy-prod.yml` to complete successfully **and** for its host-deployment check to confirm terminal success for the merged SHA.
153
153
  2. Open the release in DevAudit: `https://[DEVAUDIT_BASE_URL]/projects/[PROJECT_SLUG]/releases/[releaseId]`.
154
- 3. Review the production deployment and smoke cycle records, their evidence, and any post-deploy actions logged in the release ticket. Do not approve while either cycle or the host deployment remains queued/in progress.
154
+ 3. Review the production deployment and smoke test execution records, their evidence, and any post-deploy actions logged in the release ticket. Do not approve while either execution or the host deployment remains queued/in progress.
155
155
  4. Click **Approve Production** — status transitions to `prod_approved`.
156
156
  5. Click **Mark as Released** — status transitions to `released`. This dispatches the automated close-out flow.
157
157
 
@@ -67,7 +67,7 @@ The [`sdlc-implementer`](#skills-inventory) skill is the **default way to implem
67
67
  > Implement issue #N under the SDLC.
68
68
  ```
69
69
 
70
- It **triages first** (Phase 0): it reads the issue + labels, classifies the change-type against the [change-workflows](https://github.com/metasession-dev/DevAudit-Installer/blob/main/docs/change-workflows.md) taxonomy, announces a **Workflow Decision** (which path, which gates, which approvals, what's skipped), and routes — only a tracked change continues into the full cycle; housekeeping / trivial / doc-only is announced and handed off to its lighter path. So pointing the skill at an issue no longer defaults to maximum ceremony — it decides the path at pickup.
70
+ It **triages first** (Phase 0): it reads the issue + labels, classifies the change-type against the [change-workflows](https://github.com/metasession-dev/DevAudit-Installer/blob/main/docs/change-workflows.md) taxonomy, announces a **Workflow Decision** (which path, which gates, which approvals, what's skipped), and routes — only a tracked change continues into the full execution; housekeeping / trivial / doc-only is announced and handed off to its lighter path. So pointing the skill at an issue no longer defaults to maximum ceremony — it decides the path at pickup.
71
71
 
72
72
  For a tracked change it then runs Phases 1–4 unattended (with a plan-approval pause for HIGH/CRITICAL risk, or always-on via `--require-plan-approval`): classify risk, assign the next `REQ-XXX`, write the implementation plan, update `RTM.md`, implement, delegate all end-to-end / visual test work to [`e2e-test-engineer`](#skills-inventory), run the gates, compile evidence, open the PR, and submit for UAT review on the portal. It then **halts** at the UAT gate. After a reviewer approves on the portal:
73
73
 
@@ -77,9 +77,9 @@ For a tracked change it then runs Phases 1–4 unattended (with a plan-approval
77
77
 
78
78
  It runs Phase 5: merge, monitor post-deploy, confirm production smoke evidence, advance the release. If changes are requested at UAT instead of approval, it addresses them and re-submits for UAT re-review. It **refuses** issues that decompose into multiple requirements (split them first).
79
79
 
80
- **Where it routes (the Phase-0 decision):** the skill now makes this call at pickup rather than you discovering mid-PR that you over- (or under-) ceremonied. It still **drives each path to completion** — these are the paths it takes *instead of* the full tracked cycle, not points where it abandons you:
80
+ **Where it routes (the Phase-0 decision):** the skill now makes this call at pickup rather than you discovering mid-PR that you over- (or under-) ceremonied. It still **drives each path to completion** — these are the paths it takes *instead of* the full tracked execution, not points where it abandons you:
81
81
 
82
- - **Trivial / housekeeping changes** → the skill drives the lightweight escape hatch (above) to merge: branch → all gates locally → `chore:`/`docs:`/`ci:` PR → review → merge. No requirement, no tracked cycle, but it guides every step. Docs, formatting, dependency bumps, CI tweaks (`docs:` / `chore:` / `ci:` …) don't need a requirement. (Note: `feat` / `fix` / `refactor` / `perf` commits **do** require a `[REQ-XXX]` / `Ref: REQ-XXX` and are rejected by commitlint + `validate-commits.sh` without one.)
82
+ - **Trivial / housekeeping changes** → the skill drives the lightweight escape hatch (above) to merge: branch → all gates locally → `chore:`/`docs:`/`ci:` PR → review → merge. No requirement, no tracked execution, but it guides every step. Docs, formatting, dependency bumps, CI tweaks (`docs:` / `chore:` / `ci:` …) don't need a requirement. (Note: `feat` / `fix` / `refactor` / `perf` commits **do** require a `[REQ-XXX]` / `Ref: REQ-XXX` and are rejected by commitlint + `validate-commits.sh` without one.)
83
83
  - **Compliance-doc-only** → the skill drives a docs push against an **existing** `REQ-XXX` through to merge; no new requirement, no quality gates.
84
84
  - **Stage-1 planning in isolation, or e2e test work alone** → run the manual walkthrough / invoke `e2e-test-engineer` directly.
85
85
  - **Cross-issue refactors** spanning multiple `REQ-XXX` scopes → out of the one-issue contract; the skill refuses and asks you to split.