@metasession.co/devaudit-cli 0.3.12 → 0.3.13

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 (65) hide show
  1. package/dist/index.js +53 -4
  2. package/dist/index.js.map +1 -1
  3. package/package.json +2 -2
  4. package/scripts/upload-evidence.sh +55 -1
  5. package/sdlc/files/_common/0-project-setup.md +10 -4
  6. package/sdlc/files/_common/Periodic_Security_Review_Schedule.md +5 -5
  7. package/sdlc/files/_common/README_TEMPLATE.md +8 -8
  8. package/sdlc/files/_common/Test_Architecture.md +15 -15
  9. package/sdlc/files/_common/Test_Plan_TEMPLATE.md +13 -13
  10. package/sdlc/files/_common/Test_Policy.md +2 -2
  11. package/sdlc/files/_common/Test_Strategy.md +10 -10
  12. package/sdlc/files/_common/governance/ai-disclosure.md.template +3 -3
  13. package/sdlc/files/_common/governance/dpia.md.template +3 -3
  14. package/sdlc/files/_common/governance/incident-report.md.template +3 -3
  15. package/sdlc/files/_common/governance/nil-incident-report.md.template +1 -1
  16. package/sdlc/files/_common/governance/periodic-review.md.template +3 -3
  17. package/sdlc/files/_common/governance/risk-register.md.template +1 -1
  18. package/sdlc/files/_common/governance/ropa.md.template +2 -2
  19. package/sdlc/files/_common/joining-an-existing-project.md +4 -4
  20. package/sdlc/files/_common/scripts/check-host-deployment.sh +107 -0
  21. package/sdlc/files/_common/scripts/check-host-deployment.test.sh +119 -0
  22. package/sdlc/files/_common/scripts/check-release-pr-scope.sh +95 -0
  23. package/sdlc/files/_common/scripts/check-release-pr-scope.test.sh +137 -0
  24. package/sdlc/files/_common/scripts/close-out-release.sh +175 -54
  25. package/sdlc/files/_common/scripts/close-out-release.test.sh +90 -0
  26. package/sdlc/files/_common/scripts/extract-release-metadata.sh +27 -0
  27. package/sdlc/files/_common/scripts/extract-release-metadata.test.sh +13 -1
  28. package/sdlc/files/_common/scripts/generate-bundled-changes.sh +302 -64
  29. package/sdlc/files/_common/scripts/generate-bundled-changes.test.sh +128 -82
  30. package/sdlc/files/_common/scripts/generate-housekeeping-release-ticket.sh +18 -9
  31. package/sdlc/files/_common/scripts/generate-housekeeping-release-ticket.test.sh +66 -0
  32. package/sdlc/files/_common/scripts/generate-security-summary.sh +14 -5
  33. package/sdlc/files/_common/scripts/generate-security-summary.test.sh +57 -0
  34. package/sdlc/files/_common/scripts/prepare-release-pr.sh +44 -4
  35. package/sdlc/files/_common/scripts/render-test-cycles.sh +227 -0
  36. package/sdlc/files/_common/scripts/render-test-cycles.test.sh +107 -0
  37. package/sdlc/files/_common/scripts/report-test-cycle.sh +344 -0
  38. package/sdlc/files/_common/scripts/submit-bundle-manifest.sh +100 -0
  39. package/sdlc/files/_common/scripts/submit-bundle-manifest.test.sh +138 -0
  40. package/sdlc/files/_common/scripts/upload-evidence.sh +24 -0
  41. package/sdlc/files/_common/scripts/validate-compliance-artifacts.sh +16 -0
  42. package/sdlc/files/_common/scripts/validate-compliance-artifacts.test.sh +14 -0
  43. package/sdlc/files/_common/scripts/validate-test-summary.test.sh +4 -4
  44. package/sdlc/files/_common/skills/adr-author/SKILL.md +2 -2
  45. package/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md +2 -2
  46. package/sdlc/files/_common/skills/e2e-test-engineer/references/bootstrap.md +5 -5
  47. package/sdlc/files/_common/skills/governance-doc-author/references/incident-classification.md +1 -1
  48. package/sdlc/files/_common/skills/requirements-aligner/SKILL.md +4 -4
  49. package/sdlc/files/_common/skills/sdlc-implementer/SKILL.md +21 -2
  50. package/sdlc/files/_common/skills/sdlc-implementer/references/change-request-loop.md +1 -1
  51. package/sdlc/files/_common/skills/sdlc-implementer/references/compliance-constraints.md +7 -14
  52. package/sdlc/files/ci/ci.yml.template +82 -28
  53. package/sdlc/files/ci/close-out-release.yml.template +7 -4
  54. package/sdlc/files/ci/compliance-evidence.yml.template +204 -20
  55. package/sdlc/files/ci/feature-e2e.yml.template +84 -1
  56. package/sdlc/files/ci/post-deploy-prod.yml.template +59 -4
  57. package/sdlc/files/ci/python/ci.yml.template +60 -12
  58. package/sdlc/files/ci/quality-gates-provenance.yml.template +123 -28
  59. package/sdlc/package.json +1 -1
  60. package/sdlc/src/bin/devaudit-sdlc.js +44 -2
  61. package/sdlc/src/blueprints/1-plan-requirement.raw.md +6 -1
  62. package/sdlc/src/blueprints/2-implement-and-test.raw.md +1 -1
  63. package/sdlc/src/blueprints/3-compile-evidence.raw.md +34 -20
  64. package/sdlc/src/blueprints/4-submit-for-review.raw.md +2 -2
  65. package/sdlc/src/blueprints/5-deploy-main.raw.md +2 -2
@@ -8,8 +8,7 @@ The constraints are enforced in `SKILL.md` and in the smoke pass. Where applicab
8
8
 
9
9
  ### 1. Never skip the UAT review gate
10
10
 
11
- | | |
12
- |---|---|
11
+ | | | | --- | --- |
13
12
  | **What** | The skill must not attempt to merge a PR while the `DevAudit Release Approval` check is red. |
14
13
  | **Why (framework)** | ISO 27001 A.8.32 (Change management); SOC 2 CC8 (Change management); EU AI Act Art. 14 (Human oversight). The UAT gate is the load-bearing human-oversight checkpoint. |
15
14
  | **Enforcement** | Portal-side via `check-release-approval.yml` workflow status check + branch protection. Skill-side: never call `gh pr merge` until the check is green. |
@@ -17,8 +16,7 @@ The constraints are enforced in `SKILL.md` and in the smoke pass. Where applicab
17
16
 
18
17
  ### 2. For HIGH/CRITICAL, never act as the UAT approver
19
18
 
20
- | | |
21
- |---|---|
19
+ | | | | --- | --- |
22
20
  | **What** | The skill must verify at Phase 4 that the configured UAT reviewer (in `compliance/plans/REQ-XXX/implementation-plan.md` §Four-eyes attestation slot) differs from the skill-trigger user. If they match, halt. |
23
21
  | **Why (framework)** | SOC 2 CC8.1 — segregation of duties; ISO 27001 A.5.15 (Access control — duty segregation). The change-author cannot also be the change-approver for higher-risk work. |
24
22
  | **Enforcement** | Portal-side: the release-approval API rejects self-approval for MEDIUM/HIGH/CRITICAL risk classes. Skill-side: refuses to open the PR if the configured reviewer matches the trigger user. |
@@ -26,8 +24,7 @@ The constraints are enforced in `SKILL.md` and in the smoke pass. Where applicab
26
24
 
27
25
  ### 3. Plan checkpoint mandatory for HIGH/CRITICAL
28
26
 
29
- | | |
30
- |---|---|
27
+ | | | | --- | --- |
31
28
  | **What** | At Phase 1 step 8, the skill pauses for human approval of the plan **iff** risk class is HIGH or CRITICAL. LOW/MEDIUM pass through automatically. Can be forced on for all classes via `--require-plan-approval` flag or `DEVAUDIT_REQUIRE_PLAN_APPROVAL=1` env var. |
32
29
  | **Why (framework)** | EU AI Act Art. 14 (Human oversight for high-risk AI systems); SOC 2 CC3 (Risk assessment requires human judgement); ISO 29119 §6 (Test management — planning is a documented human step). For HIGH/CRITICAL work the plan IS the design — human review must precede code. |
33
30
  | **Enforcement** | Skill-side. Phase 1 explicitly halts and waits for the human's "go" before Phase 2. |
@@ -35,8 +32,7 @@ The constraints are enforced in `SKILL.md` and in the smoke pass. Where applicab
35
32
 
36
33
  ### 4. Change-request loop triggers full UAT re-review
37
34
 
38
- | | |
39
- |---|---|
35
+ | | | | --- | --- |
40
36
  | **What** | When new commits land on a PR after a UAT change-request, the portal's release-approval state resets. The skill respects the reset, surfaces a "UAT re-review needed" comment, and never assumes the prior approval still covers the new changes. |
41
37
  | **Why (framework)** | ISO 27001 A.14.2.4 (Restrictions on changes to software packages — each change goes through controls); SOC 2 CC8.1 (Each change requires approval). Treating "approval given once, all subsequent commits inherit it" would make UAT a one-shot rubber-stamp. |
42
38
  | **Enforcement** | Portal-side: the release-approval state machine resets on new commits to the linked branch. Skill-side: re-requests review explicitly via the portal API after each change-request iteration. |
@@ -44,8 +40,7 @@ The constraints are enforced in `SKILL.md` and in the smoke pass. Where applicab
44
40
 
45
41
  ### 5. AI involvement disclosed on every commit
46
42
 
47
- | | |
48
- |---|---|
43
+ | | | | --- | --- |
49
44
  | **What** | Every commit the skill creates carries a `Co-Authored-By: Claude <noreply@anthropic.com>` trailer (or equivalent for the specific Claude model in use). |
50
45
  | **Why (framework)** | ISO 27001 — transparency norms; EU AI Act Art. 13 (Transparency and provision of information to deployers); GDPR Art. 22 (data subjects' right to know about automated decisions, where applicable). When an auditor traces a commit, the AI involvement must be visible. |
51
46
  | **Enforcement** | Skill-side. Every `git commit` call includes the trailer. CI's `compliance-validation.yml` workflow can be configured to grep for `Co-Authored-By` on PRs labelled with the AI-touched marker; this is optional but recommended. |
@@ -53,8 +48,7 @@ The constraints are enforced in `SKILL.md` and in the smoke pass. Where applicab
53
48
 
54
49
  ### 6. All portal mutations through audit-logged APIs
55
50
 
56
- | | |
57
- |---|---|
51
+ | | | | --- | --- |
58
52
  | **What** | The skill calls `devaudit push` and the standard portal HTTP APIs — never a database back-channel, never a service-role-key-equivalent that bypasses the audit log. |
59
53
  | **Why (framework)** | ISO 27001 A.12.4 (Logging and monitoring); SOC 2 CC4 + CC7 (Monitoring activities + system operations). Every action that affects compliance state must produce an audit-log entry attributable to a human identity (the user whose PAT is in `DEVAUDIT_USER_TOKEN`). |
60
54
  | **Enforcement** | Skill-side. All portal interaction goes through `devaudit push` or `curl`/`gh api` against the documented REST endpoints. |
@@ -64,8 +58,7 @@ The constraints are enforced in `SKILL.md` and in the smoke pass. Where applicab
64
58
 
65
59
  ### 7. Rubber-stamping at UAT
66
60
 
67
- | | |
68
- |---|---|
61
+ | | | | --- | --- |
69
62
  | **What** | If the UAT reviewer approves without actually reading the change, the controls are formally satisfied but substantively hollow. |
70
63
  | **Why (framework)** | SOC 2 CC4.1 (Monitoring activities — the entity should detect this via its own QA sampling). Not enforced by any control mechanism; relies on human discipline. |
71
64
  | **Enforcement** | Not architectural. Mitigations: the SKILL.md's Principles section names the UAT reviewer as "the load-bearing human"; the portal's UAT-review UI intentionally adds friction (no one-click approve from email); org policy should random-sample approvals for QA. |
@@ -6,8 +6,9 @@
6
6
  # Single consolidated job — on a self-hosted runner, parallel jobs run
7
7
  # sequentially anyway. One checkout + one cached npm ci = fast.
8
8
  #
9
- # PRs to develop run Quality Gates before integration. PRs to main are verified
10
- # by quality-gates-provenance.yml (same-SHA provenance check, not heavy CI rerun).
9
+ # PRs to {{INTEGRATION_BRANCH}} run Quality Gates before integration. PRs to
10
+ # {{RELEASE_BRANCH}} are handled by quality-gates-provenance.yml: provenance-only
11
+ # for release PRs, full CI rerouted for hotfix/* PRs.
11
12
  # Compliance validation runs separately on PRs (compliance-validation.yml).
12
13
 
13
14
  name: CI Pipeline
@@ -15,9 +16,9 @@ name: CI Pipeline
15
16
  on:
16
17
  workflow_dispatch:
17
18
  pull_request:
18
- branches: [develop]
19
+ branches: [{{INTEGRATION_BRANCH}}]
19
20
  push:
20
- branches: [develop]
21
+ branches: [{{INTEGRATION_BRANCH}}]
21
22
  paths-ignore:
22
23
  {{PATHS_IGNORE}} - 'sdlc-config.json'
23
24
 
@@ -31,6 +32,7 @@ jobs:
31
32
  # ──────────────────────────────────────────────
32
33
  quality-gates:
33
34
  name: Quality Gates
35
+ if: ${{ github.event_name != 'pull_request' || !startsWith(github.head_ref, 'chore/close-out-') }}
34
36
  runs-on: {{RUNNER}}
35
37
 
36
38
  services:
@@ -238,7 +240,7 @@ jobs:
238
240
  # PRs to develop should report Quality Gates without mutating DevAudit
239
241
  # releases or evidence. Release registration remains a develop-push /
240
242
  # manual-dispatch side effect.
241
- if: ${{ github.event_name != 'pull_request' }}
243
+ if: ${{ github.event_name != 'pull_request' && github.ref_name == '{{INTEGRATION_BRANCH}}' }}
242
244
  outputs:
243
245
  version: ${{ steps.version.outputs.version }}
244
246
  env:
@@ -295,18 +297,16 @@ jobs:
295
297
  echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
296
298
  echo "Release version: ${VERSION}"
297
299
 
298
- - name: Check release exists (no creation — deferred to upload-evidence)
300
+ - name: Ensure release exists for gate-cycle lineage
299
301
  if: env.DEVAUDIT_BASE_URL != '' && steps.version.outputs.version != 'skip'
300
302
  run: |
301
- # Release creation is deferred to the upload-evidence job (which
302
- # runs after gates pass) so the portal never shows a release from
303
- # a push where gates weren't verified (devaudit-installer#226).
304
- # This step only checks whether the release already exists (e.g.
305
- # created earlier by sdlc-implementer Phase 1 step 3).
303
+ # First-class cycle APIs need an exact release row before the
304
+ # stage-2 cycle can start. This keeps failed gate runs visible even
305
+ # when later evidence generation fails.
306
306
  chmod +x scripts/upload-evidence.sh 2>/dev/null || true
307
307
  bash scripts/upload-evidence.sh \
308
308
  {{PROJECT_SLUG}} _compliance-docs release_registration README.md \
309
- --release ${{ steps.version.outputs.version }} \
309
+ --release ${{ steps.version.outputs.version }} --create-release-if-missing \
310
310
  --environment uat --category planning \
311
311
  --git-sha ${{ github.sha }} --branch ${{ github.ref_name }} || true
312
312
 
@@ -338,8 +338,19 @@ jobs:
338
338
  fi
339
339
  echo "Scanning bundled changes since ${SINCE_REF} for ${VERSION}"
340
340
  BUNDLED_FILE="compliance/pending-releases/BUNDLED-CHANGES-${VERSION}.md"
341
+ BUNDLED_MANIFEST="compliance/pending-releases/BUNDLED-CHANGES-${VERSION}.json"
341
342
  mkdir -p compliance/pending-releases
342
- bash scripts/generate-bundled-changes.sh "$SINCE_REF" "$VERSION" > "$BUNDLED_FILE"
343
+ chmod +x scripts/submit-bundle-manifest.sh 2>/dev/null || true
344
+ bash scripts/generate-bundled-changes.sh \
345
+ "$SINCE_REF" "$VERSION" --json-out "$BUNDLED_MANIFEST" > "$BUNDLED_FILE"
346
+ MEMBER_COUNT=$(jq -r '(.members // []) | length' "$BUNDLED_MANIFEST" 2>/dev/null || echo 0)
347
+ WORK_ITEM_COUNT=$(jq -r '(.nonReleaseWorkItems // []) | length' "$BUNDLED_MANIFEST" 2>/dev/null || echo 0)
348
+ if [ "$MEMBER_COUNT" = "0" ] && [ "$WORK_ITEM_COUNT" = "0" ]; then
349
+ echo "No bundled predecessor releases or non-release work detected for ${VERSION}."
350
+ rm -f "$BUNDLED_FILE" "$BUNDLED_MANIFEST"
351
+ exit 0
352
+ fi
353
+ bash scripts/submit-bundle-manifest.sh {{PROJECT_SLUG}} "$VERSION" "$BUNDLED_MANIFEST"
343
354
  # Upload as bundled_changes evidence against the REQ release.
344
355
  bash scripts/upload-evidence.sh \
345
356
  {{PROJECT_SLUG}} _compliance-docs bundled_changes "$BUNDLED_FILE" \
@@ -407,7 +418,7 @@ jobs:
407
418
  # evidence — `status=failed` is itself the audit trail. `!cancelled()`
408
419
  # still guards against partial state on operator-cancel.
409
420
  # DevAudit-Installer#96.
410
- if: ${{ always() && !cancelled() && needs.register-release.result == 'success' }}
421
+ if: ${{ always() && !cancelled() && github.ref_name == '{{INTEGRATION_BRANCH}}' && needs.register-release.result == 'success' }}
411
422
  env:
412
423
  DEVAUDIT_BASE_URL_VAR: ${{ vars.DEVAUDIT_BASE_URL }}
413
424
  DEVAUDIT_API_KEY: ${{ secrets.DEVAUDIT_API_KEY }}
@@ -444,17 +455,33 @@ jobs:
444
455
  - name: Generate and upload gate evidence
445
456
  if: env.DEVAUDIT_BASE_URL != ''
446
457
  run: |
447
- chmod +x scripts/upload-evidence.sh 2>/dev/null || true
448
- # --create-release-if-missing is intentionally here (post-gate) rather
449
- # than in register-release. This ensures the portal release record only
450
- # appears after gates have run — even if gates failed, the release
451
- # record is created here so failure evidence attaches to it.
452
- # (devaudit-installer#226)
458
+ chmod +x scripts/upload-evidence.sh scripts/report-test-cycle.sh 2>/dev/null || true
453
459
  FLAGS="--git-sha ${{ github.sha }} --ci-run-id ${{ github.run_id }} --branch ${{ github.ref_name }}"
454
460
  FLAGS="${FLAGS} --release ${{ needs.register-release.outputs.version }} --create-release-if-missing"
455
461
  FLAGS="${FLAGS} --environment uat"
456
462
  FLAGS="${FLAGS} --sdlc-stage 2"
457
- FLAGS="${FLAGS} --test-cycle ${{ github.run_id }}"
463
+ PRIMARY_LINEAGE_FLAGS=(--test-cycle "${{ github.run_id }}")
464
+ CYCLE_OUT="$(mktemp)"
465
+ bash scripts/report-test-cycle.sh start \
466
+ --project-slug {{PROJECT_SLUG}} \
467
+ --release "${{ needs.register-release.outputs.version }}" \
468
+ --sdlc-stage 2 \
469
+ --environment uat \
470
+ --cycle-kind quality_gate \
471
+ --provider github_actions \
472
+ --external-run-id "${{ github.run_id }}" \
473
+ --external-run-attempt "${{ github.run_attempt }}" \
474
+ --idempotency-key "github:${{ github.repository }}:quality-gates.quality_gate:${{ github.run_id }}:${{ github.run_attempt }}:2:${{ needs.register-release.outputs.version }}" \
475
+ --commit-sha "${{ github.sha }}" \
476
+ --branch "${{ github.ref_name }}" \
477
+ --workflow-name "Quality Gates" \
478
+ --workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
479
+ --output-file "$CYCLE_OUT"
480
+ . "$CYCLE_OUT"
481
+ rm -f "$CYCLE_OUT"
482
+ if [ "${cycle_supported:-false}" = "true" ] && [ -n "${cycle_record_id:-}" ]; then
483
+ PRIMARY_LINEAGE_FLAGS+=(--evidence-scope cycle --test-cycle-record-id "${cycle_record_id}")
484
+ fi
458
485
 
459
486
  # Track failures across all uploads so we can fail the job at the
460
487
  # end with the full picture. Previously each upload used
@@ -494,7 +521,7 @@ jobs:
494
521
  STATUS_BUILD=$(gate_status "$(jq -r '.build // "skipped"' ci-evidence/gate-outcomes.json)")
495
522
  upload gate-outcomes.json \
496
523
  {{PROJECT_SLUG}} _compliance-docs gate_outcome ci-evidence/gate-outcomes.json \
497
- --category ci_pipeline ${FLAGS}
524
+ --category ci_pipeline ${FLAGS} "${PRIMARY_LINEAGE_FLAGS[@]}"
498
525
  fi
499
526
 
500
527
  # Re-generate gate evidence as fallback if artifact download failed
@@ -519,7 +546,7 @@ jobs:
519
546
  if [ -f ci-evidence/sast-results.json ]; then
520
547
  upload sast-results.json \
521
548
  {{PROJECT_SLUG}} _compliance-docs sast_report ci-evidence/sast-results.json \
522
- --category security_scan --gate-status "$STATUS_SAST" ${FLAGS}
549
+ --category security_scan --gate-status "$STATUS_SAST" ${FLAGS} "${PRIMARY_LINEAGE_FLAGS[@]}"
523
550
  fi
524
551
 
525
552
  # Upload dependency audit — precise evidence_type=dependency_audit
@@ -527,14 +554,14 @@ jobs:
527
554
  if [ -f ci-evidence/dependency-audit.json ]; then
528
555
  upload dependency-audit.json \
529
556
  {{PROJECT_SLUG}} _compliance-docs dependency_audit ci-evidence/dependency-audit.json \
530
- --category security_scan --gate-status "$STATUS_DEPAUDIT" ${FLAGS}
557
+ --category security_scan --gate-status "$STATUS_DEPAUDIT" ${FLAGS} "${PRIMARY_LINEAGE_FLAGS[@]}"
531
558
  fi
532
559
 
533
560
  # Upload E2E test results (e2e_result category)
534
561
  if [ -f ci-evidence/e2e-results.json ]; then
535
562
  upload e2e-results.json \
536
563
  {{PROJECT_SLUG}} _compliance-docs e2e_result ci-evidence/e2e-results.json \
537
- --category e2e_result ${FLAGS}
564
+ --category e2e_result ${FLAGS} "${PRIMARY_LINEAGE_FLAGS[@]}"
538
565
  fi
539
566
 
540
567
  # Upload Playwright HTML report (e2e_report — run context, NOT
@@ -546,7 +573,7 @@ jobs:
546
573
  if [ -f ci-evidence/playwright-report.zip ]; then
547
574
  upload playwright-report.zip \
548
575
  {{PROJECT_SLUG}} _compliance-docs e2e_report ci-evidence/playwright-report.zip \
549
- --category e2e_report ${FLAGS}
576
+ --category e2e_report ${FLAGS} "${PRIMARY_LINEAGE_FLAGS[@]}"
550
577
  fi
551
578
  fi
552
579
 
@@ -557,7 +584,7 @@ jobs:
557
584
  if [ -f ci-evidence/coverage/coverage-summary.json ]; then
558
585
  upload coverage-summary.json \
559
586
  {{PROJECT_SLUG}} _compliance-docs coverage_report ci-evidence/coverage/coverage-summary.json \
560
- --category coverage_report ${FLAGS}
587
+ --category coverage_report ${FLAGS} "${PRIMARY_LINEAGE_FLAGS[@]}"
561
588
  fi
562
589
 
563
590
  # Upload project-level Test Summary Report as a baseline
@@ -571,7 +598,9 @@ jobs:
571
598
  if [ -f "compliance/test-summary-report.md" ]; then
572
599
  upload test-summary-report.md \
573
600
  {{PROJECT_SLUG}} _compliance-docs compliance_document compliance/test-summary-report.md \
574
- --category planning ${FLAGS}
601
+ --category planning --git-sha ${{ github.sha }} --ci-run-id ${{ github.run_id }} --branch ${{ github.ref_name }} \
602
+ --release ${{ needs.register-release.outputs.version }} --create-release-if-missing \
603
+ --environment uat --sdlc-stage 2
575
604
  fi
576
605
 
577
606
  # devaudit-installer#200 Fix 4 — Per-REQ gate evidence fan-out.
@@ -850,5 +879,30 @@ jobs:
850
879
  exit 1
851
880
  fi
852
881
 
882
+ - name: Complete primary quality-gate cycle
883
+ if: always() && env.DEVAUDIT_BASE_URL != ''
884
+ run: |
885
+ case "${{ job.status }}" in
886
+ success) OUTCOME=passed ;;
887
+ cancelled) OUTCOME=cancelled ;;
888
+ *) OUTCOME=failed ;;
889
+ esac
890
+ chmod +x scripts/report-test-cycle.sh 2>/dev/null || true
891
+ bash scripts/report-test-cycle.sh complete \
892
+ --project-slug {{PROJECT_SLUG}} \
893
+ --release "${{ needs.register-release.outputs.version }}" \
894
+ --sdlc-stage 2 \
895
+ --environment uat \
896
+ --cycle-kind quality_gate \
897
+ --provider github_actions \
898
+ --external-run-id "${{ github.run_id }}" \
899
+ --external-run-attempt "${{ github.run_attempt }}" \
900
+ --idempotency-key "github:${{ github.repository }}:quality-gates.quality_gate:${{ github.run_id }}:${{ github.run_attempt }}:2:${{ needs.register-release.outputs.version }}" \
901
+ --commit-sha "${{ github.sha }}" \
902
+ --branch "${{ github.ref_name }}" \
903
+ --workflow-name "Quality Gates" \
904
+ --workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
905
+ --outcome "$OUTCOME"
906
+
853
907
  - name: Summary
854
908
  run: echo "Evidence uploaded for ${{ needs.register-release.outputs.version }} (UAT)"
@@ -11,10 +11,11 @@
11
11
  # - workflow_dispatch — manual catch-up for an already-released requirement.
12
12
  #
13
13
  # It merges origin/main into a branch from develop (devaudit#281), runs
14
- # scripts/close-out-release.sh for the requirement (flip ticket + RTM, move
15
- # ticket to approved-releases/), then opens one PR to develop containing both
16
- # the main→develop sync and the compliance-tree close-out. The script is
17
- # idempotent, so a no-op produces no PR.
14
+ # scripts/close-out-release.sh for the requirement (flip the governing ticket +
15
+ # RTM, move the governing ticket to approved-releases/, and move any absorbed
16
+ # predecessor tickets to superseded-releases/), then opens one PR to develop
17
+ # containing both the main→develop sync and the compliance-tree close-out. The
18
+ # script is idempotent, so a no-op produces no PR.
18
19
 
19
20
  name: Release Close-out
20
21
 
@@ -133,6 +134,7 @@ jobs:
133
134
  - release ticket moved to approved-releases/
134
135
  - release ticket status → RELEASED
135
136
  - RTM row → RELEASED
137
+ - absorbed predecessor tickets → superseded-releases/ (if the bundle manifest listed any)
136
138
 
137
139
  Ref: ${REQ}"
138
140
  git push -u origin "$BRANCH" --force-with-lease
@@ -144,6 +146,7 @@ jobs:
144
146
  - **main → develop reconciliation** — merges released code back into develop
145
147
  - **release ticket** moved to \`approved-releases/\`, status \`RELEASED\`
146
148
  - **RTM row** flipped to \`RELEASED\`
149
+ - **absorbed predecessor tickets** moved to \`superseded-releases/\` when the release bundle lists them
147
150
 
148
151
  Review + merge to develop."
149
152
  gh pr create --base develop --head "$BRANCH" \