@metasession.co/devaudit-cli 0.3.18 → 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.
- package/dist/index.js +35 -34
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/scripts/upload-evidence.sh +23 -19
- package/sdlc/files/_common/governance/incident-report.md.template +6 -1
- package/sdlc/files/_common/governance/nil-incident-report.md.template +5 -2
- package/sdlc/files/_common/scripts/check-release-pr-scope.sh +8 -1
- package/sdlc/files/_common/scripts/check-release-pr-scope.test.sh +58 -10
- package/sdlc/files/_common/scripts/check-self-hosted-runner.sh +103 -0
- package/sdlc/files/_common/scripts/check-self-hosted-runner.test.sh +74 -0
- package/sdlc/files/_common/scripts/record-uat-execution.sh +195 -0
- package/sdlc/files/_common/scripts/record-uat-execution.test.sh +144 -0
- package/sdlc/files/_common/scripts/render-test-executions.sh +146 -0
- package/sdlc/files/_common/scripts/{render-test-cycles.test.sh → render-test-executions.test.sh} +12 -18
- package/sdlc/files/_common/scripts/{report-test-cycle.sh → report-test-execution.sh} +66 -74
- package/sdlc/files/_common/scripts/report-test-execution.test.sh +177 -0
- package/sdlc/files/_common/scripts/submit-for-uat-review.sh +21 -0
- package/sdlc/files/_common/scripts/upload-evidence.sh +23 -19
- package/sdlc/files/_common/scripts/validate-commits.sh +6 -4
- package/sdlc/files/_common/scripts/validate-commits.test.sh +15 -0
- package/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md +9 -7
- package/sdlc/files/_common/skills/e2e-test-engineer/references/e2e-regression-3-tier.yml +4 -1
- package/sdlc/files/_common/skills/sdlc-implementer/SKILL.md +16 -14
- package/sdlc/files/ci/ci.yml.template +54 -44
- package/sdlc/files/ci/compliance-evidence.yml.template +135 -46
- package/sdlc/files/ci/feature-e2e.yml.template +17 -17
- package/sdlc/files/ci/incident-export.yml.template +18 -4
- package/sdlc/files/ci/post-deploy-prod.yml.template +33 -30
- package/sdlc/files/ci/python/ci.yml.template +14 -14
- package/sdlc/files/ci/quality-gates-provenance.yml.template +3 -0
- package/sdlc/package.json +1 -1
- package/sdlc/src/blueprints/3-compile-evidence.raw.md +10 -10
- package/sdlc/src/blueprints/4-submit-for-review.raw.md +1 -1
- package/sdlc/src/blueprints/5-deploy-main.raw.md +1 -1
- package/sdlc/src/blueprints/implementing-an-sdlc-issue.raw.md +3 -3
- package/sdlc/files/_common/scripts/render-test-cycles.sh +0 -227
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# report-test-execution.test.sh - Focused regression tests for the test execution lifecycle helper.
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
7
|
+
HELPER="$SCRIPT_DIR/report-test-execution.sh"
|
|
8
|
+
[ -x "$HELPER" ] || chmod +x "$HELPER"
|
|
9
|
+
|
|
10
|
+
PASS=0
|
|
11
|
+
FAIL=0
|
|
12
|
+
|
|
13
|
+
ok() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
|
14
|
+
no() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
|
15
|
+
|
|
16
|
+
make_fixture() {
|
|
17
|
+
local dir="$1"
|
|
18
|
+
rm -rf "$dir"
|
|
19
|
+
mkdir -p "$dir/bin"
|
|
20
|
+
cat > "$dir/bin/curl" <<'EOF'
|
|
21
|
+
#!/usr/bin/env bash
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
LOG_FILE="${EXECUTION_TEST_LOG:?}"
|
|
24
|
+
URL=""
|
|
25
|
+
OUT_FILE=""
|
|
26
|
+
WRITE_OUT=""
|
|
27
|
+
BODY=""
|
|
28
|
+
ARGS=("$@")
|
|
29
|
+
for ((i=0; i<${#ARGS[@]}; i++)); do
|
|
30
|
+
arg="${ARGS[$i]}"
|
|
31
|
+
case "$arg" in
|
|
32
|
+
-o) OUT_FILE="${ARGS[$((i+1))]}" ;;
|
|
33
|
+
-w) WRITE_OUT="${ARGS[$((i+1))]}" ;;
|
|
34
|
+
-d) BODY="${ARGS[$((i+1))]}" ;;
|
|
35
|
+
http://*|https://*) URL="$arg" ;;
|
|
36
|
+
esac
|
|
37
|
+
done
|
|
38
|
+
printf 'URL:%s\n' "$URL" >> "$LOG_FILE"
|
|
39
|
+
if [ -n "$BODY" ]; then
|
|
40
|
+
printf 'BODY:%s\n' "$BODY" >> "$LOG_FILE"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
status=500
|
|
44
|
+
payload='{"error":"unhandled"}'
|
|
45
|
+
case "$URL" in
|
|
46
|
+
*"/api/ci/releases/resolve"*)
|
|
47
|
+
status="${RESOLVE_STATUS:-200}"
|
|
48
|
+
payload="${RESOLVE_BODY:-{}}"
|
|
49
|
+
;;
|
|
50
|
+
*"/cycles/start")
|
|
51
|
+
status="${START_STATUS:-201}"
|
|
52
|
+
payload="${START_BODY:-{}}"
|
|
53
|
+
;;
|
|
54
|
+
*"/cycles/complete")
|
|
55
|
+
status="${COMPLETE_STATUS:-200}"
|
|
56
|
+
payload="${COMPLETE_BODY:-{}}"
|
|
57
|
+
;;
|
|
58
|
+
*"/cycles/reconcile")
|
|
59
|
+
status="${RECONCILE_STATUS:-200}"
|
|
60
|
+
payload="${RECONCILE_BODY:-{}}"
|
|
61
|
+
;;
|
|
62
|
+
esac
|
|
63
|
+
|
|
64
|
+
if [ -n "$OUT_FILE" ]; then
|
|
65
|
+
printf '%s' "$payload" > "$OUT_FILE"
|
|
66
|
+
fi
|
|
67
|
+
if [ -n "$WRITE_OUT" ]; then
|
|
68
|
+
printf '%s' "$status"
|
|
69
|
+
fi
|
|
70
|
+
EOF
|
|
71
|
+
chmod +x "$dir/bin/curl"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
run_helper() {
|
|
75
|
+
PATH="$1/bin:$PATH" \
|
|
76
|
+
EXECUTION_TEST_LOG="$1/curl.log" \
|
|
77
|
+
DEVAUDIT_BASE_URL="https://devaudit.example.test" \
|
|
78
|
+
DEVAUDIT_API_KEY="mc_test_dummy" \
|
|
79
|
+
"$HELPER" "${@:2}"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
assert_contains() {
|
|
83
|
+
local label="$1" needle="$2" file="$3"
|
|
84
|
+
if grep -Fq -- "$needle" "$file"; then ok "$label"; else no "$label"; fi
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
echo "=== report-test-execution.sh tests ==="
|
|
88
|
+
|
|
89
|
+
case_start_success() {
|
|
90
|
+
echo "case: start resolves exact release and records execution"
|
|
91
|
+
local dir out exit_code
|
|
92
|
+
dir=$(mktemp -d)
|
|
93
|
+
make_fixture "$dir"
|
|
94
|
+
out="$dir/out.env"
|
|
95
|
+
RESOLVE_STATUS=200 \
|
|
96
|
+
RESOLVE_BODY='{"latest":{"id":"release-1","version":"REQ-100"}}' \
|
|
97
|
+
START_STATUS=201 \
|
|
98
|
+
START_BODY='{"id":"execution-1"}' \
|
|
99
|
+
run_helper "$dir" start \
|
|
100
|
+
--project-slug fixture-app \
|
|
101
|
+
--release REQ-100 \
|
|
102
|
+
--sdlc-stage 2 \
|
|
103
|
+
--environment uat \
|
|
104
|
+
--suite-kind e2e \
|
|
105
|
+
--iteration-key rework-1 \
|
|
106
|
+
--iteration-ordinal 1 \
|
|
107
|
+
--idempotency-key github:fixture/repo:feature-e2e.e2e:12345:1:2:REQ-100 \
|
|
108
|
+
--output-file "$out" >"$dir/stdout.log" 2>"$dir/stderr.log" && exit_code=0 || exit_code=$?
|
|
109
|
+
if [ "$exit_code" -eq 0 ]; then ok "exit code 0"; else no "expected exit 0"; fi
|
|
110
|
+
assert_contains "outputs supported=true" "execution_supported=true" "$out"
|
|
111
|
+
assert_contains "outputs execution_record_id" "execution_record_id=execution-1" "$out"
|
|
112
|
+
assert_contains "called start endpoint" "/cycles/start" "$dir/curl.log"
|
|
113
|
+
assert_contains "payload has suite kind" '"suiteKind": "e2e"' "$dir/curl.log"
|
|
114
|
+
assert_contains "payload carries portal transport kind" '"cycleKind": "e2e"' "$dir/curl.log"
|
|
115
|
+
assert_contains "payload has iteration key" '"iterationKey": "rework-1"' "$dir/curl.log"
|
|
116
|
+
rm -rf "$dir"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
case_complete_reconciles_terminal_conflict() {
|
|
120
|
+
echo "case: complete falls back to reconcile on terminal-outcome conflict"
|
|
121
|
+
local dir out exit_code
|
|
122
|
+
dir=$(mktemp -d)
|
|
123
|
+
make_fixture "$dir"
|
|
124
|
+
out="$dir/out.env"
|
|
125
|
+
RESOLVE_STATUS=200 \
|
|
126
|
+
RESOLVE_BODY='{"latest":{"id":"release-1","version":"REQ-100"}}' \
|
|
127
|
+
COMPLETE_STATUS=400 \
|
|
128
|
+
COMPLETE_BODY='{"error":"Test execution already has a different terminal outcome; use reconcile"}' \
|
|
129
|
+
RECONCILE_STATUS=200 \
|
|
130
|
+
RECONCILE_BODY='{"id":"execution-1"}' \
|
|
131
|
+
run_helper "$dir" complete \
|
|
132
|
+
--project-slug fixture-app \
|
|
133
|
+
--release REQ-100 \
|
|
134
|
+
--sdlc-stage 2 \
|
|
135
|
+
--environment uat \
|
|
136
|
+
--suite-kind e2e \
|
|
137
|
+
--idempotency-key github:fixture/repo:feature-e2e.e2e:12345:1:2:REQ-100 \
|
|
138
|
+
--started-at 2026-07-16T10:00:00Z \
|
|
139
|
+
--outcome failed \
|
|
140
|
+
--output-file "$out" >"$dir/stdout.log" 2>"$dir/stderr.log" && exit_code=0 || exit_code=$?
|
|
141
|
+
if [ "$exit_code" -eq 0 ]; then ok "exit code 0"; else no "expected exit 0"; fi
|
|
142
|
+
assert_contains "called complete endpoint" "/cycles/complete" "$dir/curl.log"
|
|
143
|
+
assert_contains "called reconcile endpoint" "/cycles/reconcile" "$dir/curl.log"
|
|
144
|
+
assert_contains "outputs reconcile endpoint" "execution_endpoint=reconcile" "$out"
|
|
145
|
+
rm -rf "$dir"
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
case_missing_release_fails() {
|
|
149
|
+
echo "case: release resolve failure is not treated as successful fallback"
|
|
150
|
+
local dir out exit_code
|
|
151
|
+
dir=$(mktemp -d)
|
|
152
|
+
make_fixture "$dir"
|
|
153
|
+
out="$dir/out.env"
|
|
154
|
+
RESOLVE_STATUS=404 \
|
|
155
|
+
RESOLVE_BODY='{"error":"missing"}' \
|
|
156
|
+
run_helper "$dir" start \
|
|
157
|
+
--project-slug fixture-app \
|
|
158
|
+
--release REQ-100 \
|
|
159
|
+
--sdlc-stage 2 \
|
|
160
|
+
--environment uat \
|
|
161
|
+
--suite-kind e2e \
|
|
162
|
+
--idempotency-key key \
|
|
163
|
+
--output-file "$out" >"$dir/stdout.log" 2>"$dir/stderr.log" && exit_code=0 || exit_code=$?
|
|
164
|
+
if [ "$exit_code" -ne 0 ]; then ok "exit code non-zero"; else no "expected non-zero"; fi
|
|
165
|
+
if grep -q '/cycles/start' "$dir/curl.log"; then no "unexpected start endpoint call"; else ok "no start endpoint call"; fi
|
|
166
|
+
rm -rf "$dir"
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
case_start_success
|
|
170
|
+
case_complete_reconciles_terminal_conflict
|
|
171
|
+
case_missing_release_fails
|
|
172
|
+
|
|
173
|
+
echo ""
|
|
174
|
+
echo "=== report-test-execution.test.sh: $PASS passed, $FAIL failed ==="
|
|
175
|
+
if [ "$FAIL" -gt 0 ]; then
|
|
176
|
+
exit 1
|
|
177
|
+
fi
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
# If status is uat_review → idempotent no-op (exit 0, "already submitted").
|
|
28
28
|
# If status is uat_approved → idempotent no-op (exit 0, "already approved").
|
|
29
29
|
# Any other status → refuse with an explanatory message.
|
|
30
|
+
# 6. Print the explicit Stage 4 UAT execution command to run after the
|
|
31
|
+
# reviewer has completed UAT. Submission is not UAT execution.
|
|
30
32
|
|
|
31
33
|
set -euo pipefail
|
|
32
34
|
|
|
@@ -50,6 +52,23 @@ note() { printf ' - %s\n' "$*"; }
|
|
|
50
52
|
fail() { printf ' ✗ %s\n' "$*"; FAILED=$((FAILED + 1)); }
|
|
51
53
|
ok() { printf ' ✓ %s\n' "$*"; }
|
|
52
54
|
|
|
55
|
+
print_uat_execution_next_step() {
|
|
56
|
+
local tested_sha="${1:-}"
|
|
57
|
+
[ -n "$tested_sha" ] || tested_sha="$(git rev-parse HEAD 2>/dev/null || true)"
|
|
58
|
+
echo ""
|
|
59
|
+
echo "Next required control: after the reviewer performs UAT, record the Stage 4 execution explicitly."
|
|
60
|
+
echo "Submission only moves the release into review; it does not claim UAT passed."
|
|
61
|
+
echo ""
|
|
62
|
+
echo " ./scripts/record-uat-execution.sh \\"
|
|
63
|
+
echo " --project-slug ${PROJECT_SLUG} \\"
|
|
64
|
+
echo " --release ${RELEASE_VERSION:-$VERSION_PREFIX} \\"
|
|
65
|
+
echo " --outcome passed \\"
|
|
66
|
+
echo " --executor \"<reviewer identity>\" \\"
|
|
67
|
+
echo " --tested-sha ${tested_sha:-<tested sha>} \\"
|
|
68
|
+
echo " --checklist-ref \"<UAT checklist or portal note>\" \\"
|
|
69
|
+
echo " --evidence-ref \"<supporting evidence path or URL>\""
|
|
70
|
+
}
|
|
71
|
+
|
|
53
72
|
echo "Readiness checks for ${PROJECT_SLUG} ${VERSION_PREFIX}"
|
|
54
73
|
|
|
55
74
|
# 1. Working tree clean
|
|
@@ -134,6 +153,7 @@ case "$RELEASE_STATUS" in
|
|
|
134
153
|
NEW_STATUS=$(echo "$BODY" | jq -r '.status')
|
|
135
154
|
echo " Status: draft → ${NEW_STATUS}"
|
|
136
155
|
echo " Review page: ${BASE_URL}/projects/${PROJECT_SLUG}/releases/${RELEASE_ID}?env=uat"
|
|
156
|
+
print_uat_execution_next_step "$REMOTE_SHA"
|
|
137
157
|
else
|
|
138
158
|
echo " Submission failed (HTTP ${HTTP_CODE}): $(echo "$BODY" | jq -r '.error // .')" >&2
|
|
139
159
|
exit 1
|
|
@@ -143,6 +163,7 @@ case "$RELEASE_STATUS" in
|
|
|
143
163
|
echo ""
|
|
144
164
|
echo "Release already submitted for UAT review (status: uat_review). No action taken."
|
|
145
165
|
echo "Review page: ${BASE_URL}/projects/${PROJECT_SLUG}/releases/${RELEASE_ID}?env=uat"
|
|
166
|
+
print_uat_execution_next_step "$REMOTE_SHA"
|
|
146
167
|
;;
|
|
147
168
|
uat_approved | prod_review | prod_approved | released)
|
|
148
169
|
echo ""
|
|
@@ -42,19 +42,19 @@
|
|
|
42
42
|
# 4 submit-for-review, 5 deploy. Forwarded as
|
|
43
43
|
# `sdlcStage`; unknown to older portals (ignored
|
|
44
44
|
# server-side, no error).
|
|
45
|
-
# --test-
|
|
46
|
-
# ID). Forwarded
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
# portals ignore the field (no error).
|
|
45
|
+
# --test-execution <id> Test execution identifier (typically the CI run
|
|
46
|
+
# ID). Forwarded to the portal transport as
|
|
47
|
+
# `testCycleId` until the upload API field is
|
|
48
|
+
# renamed.
|
|
50
49
|
# --evidence-scope <scope> Evidence ownership scope: release | stage |
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# --test-
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
50
|
+
# execution | approval. `execution` is mapped
|
|
51
|
+
# to the portal transport value `cycle` until
|
|
52
|
+
# the upload API field is renamed.
|
|
53
|
+
# --test-execution-record-id <id>
|
|
54
|
+
# First-class portal test execution UUID.
|
|
55
|
+
# Requires `--evidence-scope execution`.
|
|
56
|
+
# Forwarded to the portal transport as
|
|
57
|
+
# `testCycleRecordId`.
|
|
58
58
|
#
|
|
59
59
|
# Required environment variables:
|
|
60
60
|
# DEVAUDIT_BASE_URL e.g. https://meta-comply-production.up.railway.app
|
|
@@ -136,9 +136,9 @@ while [ "$#" -gt 0 ]; do
|
|
|
136
136
|
# DevAudit-Installer#96.
|
|
137
137
|
--gate-status) GATE_STATUS="$2"; shift 2 ;;
|
|
138
138
|
--sdlc-stage) SDLC_STAGE="$2"; shift 2 ;;
|
|
139
|
-
--test-
|
|
139
|
+
--test-execution) TEST_CYCLE="$2"; shift 2 ;;
|
|
140
140
|
--evidence-scope) EVIDENCE_SCOPE="$2"; shift 2 ;;
|
|
141
|
-
--test-
|
|
141
|
+
--test-execution-record-id) TEST_CYCLE_RECORD_ID="$2"; shift 2 ;;
|
|
142
142
|
# --meta-key key=value (repeatable). Merged into the metadata JSON
|
|
143
143
|
# before posting. Validates the `key=value` shape; rejects bare
|
|
144
144
|
# keys without `=`.
|
|
@@ -166,14 +166,18 @@ if [ -n "$SDLC_STAGE" ] && ! [[ "$SDLC_STAGE" =~ ^[1-5]$ ]]; then
|
|
|
166
166
|
echo "Error: --sdlc-stage must be an integer 1-5 (got: $SDLC_STAGE)"
|
|
167
167
|
exit 1
|
|
168
168
|
fi
|
|
169
|
-
if [ -n "$EVIDENCE_SCOPE" ] && ! [[ "$EVIDENCE_SCOPE" =~ ^(release|stage|
|
|
170
|
-
echo "Error: --evidence-scope must be one of: release, stage,
|
|
169
|
+
if [ -n "$EVIDENCE_SCOPE" ] && ! [[ "$EVIDENCE_SCOPE" =~ ^(release|stage|execution|approval)$ ]]; then
|
|
170
|
+
echo "Error: --evidence-scope must be one of: release, stage, execution, approval"
|
|
171
171
|
exit 1
|
|
172
172
|
fi
|
|
173
|
-
if [ -n "$TEST_CYCLE_RECORD_ID" ] && [ "$EVIDENCE_SCOPE" != "
|
|
174
|
-
echo "Error: --test-
|
|
173
|
+
if [ -n "$TEST_CYCLE_RECORD_ID" ] && [ "$EVIDENCE_SCOPE" != "execution" ]; then
|
|
174
|
+
echo "Error: --test-execution-record-id requires --evidence-scope execution"
|
|
175
175
|
exit 1
|
|
176
176
|
fi
|
|
177
|
+
TRANSPORT_EVIDENCE_SCOPE="$EVIDENCE_SCOPE"
|
|
178
|
+
if [ "$TRANSPORT_EVIDENCE_SCOPE" = "execution" ]; then
|
|
179
|
+
TRANSPORT_EVIDENCE_SCOPE="cycle"
|
|
180
|
+
fi
|
|
177
181
|
|
|
178
182
|
if [ -z "${DEVAUDIT_BASE_URL:-}" ]; then
|
|
179
183
|
echo "Error: DEVAUDIT_BASE_URL environment variable is required"
|
|
@@ -553,7 +557,7 @@ for FILE in "${FILES[@]}"; do
|
|
|
553
557
|
[ -n "$GATE_STATUS" ] && CURL_ARGS+=(-F "gateStatus=${GATE_STATUS}")
|
|
554
558
|
[ -n "$SDLC_STAGE" ] && CURL_ARGS+=(-F "sdlcStage=${SDLC_STAGE}")
|
|
555
559
|
[ -n "$TEST_CYCLE" ] && CURL_ARGS+=(-F "testCycleId=${TEST_CYCLE}")
|
|
556
|
-
[ -n "$
|
|
560
|
+
[ -n "$TRANSPORT_EVIDENCE_SCOPE" ] && CURL_ARGS+=(-F "evidenceScope=${TRANSPORT_EVIDENCE_SCOPE}")
|
|
557
561
|
[ -n "$TEST_CYCLE_RECORD_ID" ] && CURL_ARGS+=(-F "testCycleRecordId=${TEST_CYCLE_RECORD_ID}")
|
|
558
562
|
[ -n "$SENTINEL_CONTENT" ] && CURL_ARGS+=(-F "sentinelContent=${SENTINEL_CONTENT}")
|
|
559
563
|
[ -n "$COMMIT_TIMESTAMP" ] && CURL_ARGS+=(-F "commitTimestamp=${COMMIT_TIMESTAMP}")
|
|
@@ -21,11 +21,12 @@ echo "=== Commit Convention Validation ==="
|
|
|
21
21
|
echo "Comparing: $BASE_BRANCH...HEAD"
|
|
22
22
|
echo ""
|
|
23
23
|
|
|
24
|
-
# Conventional Commit regex:
|
|
24
|
+
# Conventional Commit regex: optional [REQ-XXX] prefix, then
|
|
25
|
+
# type(optional-scope): description.
|
|
25
26
|
# Scope accepts anything except `)` so multi-scope subjects like
|
|
26
27
|
# `feat(auth,profile):` and `fix(rewards/expiry):` validate. The closing-paren
|
|
27
|
-
# guard prevents pathological inputs. DevAudit-Installer#93.
|
|
28
|
-
CC_REGEX='^(feat|fix|docs|test|refactor|chore|compliance|security|perf|ci|build|revert)(\([^)]+\))?!?: .+'
|
|
28
|
+
# guard prevents pathological inputs. DevAudit-Installer#93/#440.
|
|
29
|
+
CC_REGEX='^(\[REQ-[0-9]{3,}\][[:space:]]+)?(feat|fix|docs|test|refactor|chore|compliance|security|perf|ci|build|revert)(\([^)]+\))?!?: .+'
|
|
29
30
|
|
|
30
31
|
COMMITS=$(git log "$BASE_BRANCH"..HEAD --format='%H' || true)
|
|
31
32
|
|
|
@@ -78,7 +79,8 @@ while IFS= read -r sha; do
|
|
|
78
79
|
# are exempt. Mirrors the commitlint rule; this is the PR-CI half that
|
|
79
80
|
# `--no-verify` can't skip. Work starts from a requirement (which starts
|
|
80
81
|
# from an issue) — use the sdlc-implementer skill to assign one.
|
|
81
|
-
|
|
82
|
+
SUBJECT_FOR_TYPE=$(echo "$SUBJECT" | sed -E 's/^\[REQ-[0-9]{3,}\][[:space:]]+//')
|
|
83
|
+
TYPE=$(echo "$SUBJECT_FOR_TYPE" | grep -oE '^[a-z]+' || true)
|
|
82
84
|
case "$TYPE" in
|
|
83
85
|
feat|fix|refactor|perf)
|
|
84
86
|
if ! echo "$SUBJECT" | grep -qP '\[REQ-\d{3,}\]' \
|
|
@@ -138,6 +138,21 @@ run_validator
|
|
|
138
138
|
assert_exit "no active context exits 1" 1
|
|
139
139
|
assert_grep "hard error emitted without any active release context" "ERROR .*implementation commit but cites no requirement" 1
|
|
140
140
|
|
|
141
|
+
# Case 5: leading REQ prefix is accepted before the Conventional Commit type.
|
|
142
|
+
echo "Case 5: leading REQ prefix before type is accepted"
|
|
143
|
+
make_fixture "$WORKDIR/case5" "[REQ-123] fix(reports): map dynamic category reports" "Co-Authored-By: Test <test@example.com>"
|
|
144
|
+
run_validator
|
|
145
|
+
assert_exit "leading REQ prefix exits 0" 0
|
|
146
|
+
assert_grep "no conventional-commit error for leading REQ prefix" "Not Conventional Commits format" 0
|
|
147
|
+
assert_grep "no missing-requirement error for leading REQ prefix" "implementation commit but cites no requirement" 0
|
|
148
|
+
|
|
149
|
+
# Case 6: malformed leading REQ prefixes remain invalid.
|
|
150
|
+
echo "Case 6: malformed leading REQ prefix is rejected"
|
|
151
|
+
make_fixture "$WORKDIR/case6" "[REQ-12] fix: invalid short req prefix" "Co-Authored-By: Test <test@example.com>"
|
|
152
|
+
run_validator
|
|
153
|
+
assert_exit "malformed leading REQ prefix exits 1" 1
|
|
154
|
+
assert_grep "malformed prefix is not treated as conventional" "Not Conventional Commits format" 1
|
|
155
|
+
|
|
141
156
|
echo
|
|
142
157
|
echo "Result: $PASS passed, $FAIL failed"
|
|
143
158
|
[ "$FAIL" = "0" ]
|
|
@@ -229,9 +229,9 @@ Before running the suite (Phase 6), verify that the evidence traceability wiring
|
|
|
229
229
|
|
|
230
230
|
Also verify the import is present: `import { tagTest } from './helpers/test-tags'` (or the correct relative path from the spec's location to `e2e/helpers/test-tags.ts`).
|
|
231
231
|
|
|
232
|
-
4. **Check release and
|
|
232
|
+
4. **Check release and execution provenance.** Before handing the work back to `sdlc-implementer`, identify the tracked `REQ-XXX`, the source branch SHA, and the expected SDLC stage/test execution for the run. The CI evidence upload must retain those values so the portal can show the result in the correct numbered execution for the release that produced it.
|
|
233
233
|
- A passing local run is not portal evidence by itself. Report it as local verification and let the configured CI workflow upload the resulting report and screenshots.
|
|
234
|
-
- For a bundled release, evidence remains attributed to its originating REQ and
|
|
234
|
+
- For a bundled release, evidence remains attributed to its originating REQ and execution. The absorbing release may reference that source release through bundle lineage, but must not relabel the source E2E run as newly produced by the absorbing REQ.
|
|
235
235
|
- Confirm the CI invocation has an unambiguous release context (`REQ-XXX` or the documented standalone-housekeeping declaration). A bare-date integration housekeeping run is historical CI only; it must not create an approval-ready E2E evidence set.
|
|
236
236
|
- If the project workflow cannot provide this context, halt and report a workflow-contract gap. Do not claim that screenshots or E2E results will appear correctly on the portal.
|
|
237
237
|
|
|
@@ -247,7 +247,7 @@ Halt and report the gap to the user:
|
|
|
247
247
|
|
|
248
248
|
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.
|
|
249
249
|
|
|
250
|
-
**Write the evidence-wiring sentinel (devaudit-installer#226).** After all Phase 5½ checks pass (all `@requirement`, `evidenceShot()`, `tagTest()`, and release/
|
|
250
|
+
**Write the evidence-wiring sentinel (devaudit-installer#226).** After all Phase 5½ checks pass (all `@requirement`, `evidenceShot()`, `tagTest()`, and release/execution provenance checks 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:
|
|
251
251
|
|
|
252
252
|
```bash
|
|
253
253
|
echo "WIRED $(date -u +%Y-%m-%dT%H:%M:%SZ) REQ-XXX" > .e2e-evidence-wired
|
|
@@ -366,7 +366,7 @@ Each filed issue needs:
|
|
|
366
366
|
|
|
367
367
|
#### Framework classification + the `incident` label
|
|
368
368
|
|
|
369
|
-
Every defect filed from Phase 6 becomes `incident_report` evidence when (a) the issue is labelled `incident` and (b) the issue is closed. The flow: closed-with-label → `incident-export.yml` exports the body to `compliance/governance/incident-report-<N>.md` → `compliance-evidence.yml` uploads as `incident_report` evidence → portal flips the attributed clauses MISSING → COVERED.
|
|
369
|
+
Every defect filed from Phase 6 becomes `incident_report` evidence when (a) the issue is labelled `incident` and (b) the issue is closed. The flow: closed-with-label → `incident-export.yml` exports the body to `compliance/governance/incident-report-<N>.md` with `incident_kind`, `source_release`, `source_issue`, and `semantic_id` frontmatter → `compliance-evidence.yml` uploads it as source-owned `incident_report` evidence → portal flips the attributed clauses MISSING → COVERED for that source release.
|
|
370
370
|
|
|
371
371
|
Classify the defect against this table when filing — the canonical version lives at `governance-doc-author/references/incident-classification.md`, mirrored here for the e2e workflow:
|
|
372
372
|
|
|
@@ -411,6 +411,8 @@ Once closed, the `incident-export.yml` workflow exports this issue's body to `co
|
|
|
411
411
|
- **Path B (any of SOC2/GDPR/EUAIA ticked):** auto-files a PR with the GDPR triage + sign-off sections to fill in. Merge that PR → `compliance-evidence.yml` uploads as `incident_report`.
|
|
412
412
|
```
|
|
413
413
|
|
|
414
|
+
The issue body must identify the owning `REQ-XXX` or standalone housekeeping release so the exported report's `source_release` is correct. Do not let a later bundled release claim the incident as newly produced evidence; bundles inherit by explicit lineage.
|
|
415
|
+
|
|
414
416
|
Pre-tick boxes you're confident about. Leave the operator-judgement ones (GDPR triage, AI-failure classification) for the operator to confirm in the export PR.
|
|
415
417
|
|
|
416
418
|
#### Worked examples
|
|
@@ -448,7 +450,7 @@ Wrap up with a summary the user can drop into the PR or ticket:
|
|
|
448
450
|
- Defects filed — count, with links.
|
|
449
451
|
- Requirements gap reports — count, with details (devaudit-installer#212 Gap 4). These are ACs classified as "impossible to test" or "missing AC" — returned to `sdlc-implementer` for the requirements gap flow, not filed as defects.
|
|
450
452
|
- Missed requirements — count, with links.
|
|
451
|
-
- **Release provenance** — originating `REQ-XXX`, local run result, expected CI workflow/run, and expected portal stage/
|
|
453
|
+
- **Release provenance** — originating `REQ-XXX`, local run result, expected CI workflow/run, and expected portal stage/execution. For bundled work, state the source REQ explicitly and that the absorbing release will reference it through lineage rather than overwrite its attribution.
|
|
452
454
|
|
|
453
455
|
**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:
|
|
454
456
|
|
|
@@ -496,8 +498,8 @@ The canonical helper source lives at `references/evidence.ts` in this skill.
|
|
|
496
498
|
|
|
497
499
|
The number of `evidenceShot` calls per spec should scale to the spec's role:
|
|
498
500
|
|
|
499
|
-
- **While the spec is a feature artefact** (newly authored on the branch, before merge to develop): capture multiple stages
|
|
500
|
-
- **Once the spec joins the regression pack** (post-merge, `git diff --diff-filter=A` no longer matches it): capture only the canonical "this still works" anchor per AC. Re-running the dense journey on every regression
|
|
501
|
+
- **While the spec is a feature artefact** (newly authored on the branch, before merge to develop): capture multiple stages - every meaningful transition or state the AC documents. The dense evidence is what reviewers use to verify the AC was met end-to-end during the feature iteration.
|
|
502
|
+
- **Once the spec joins the regression pack** (post-merge, `git diff --diff-filter=A` no longer matches it): capture only the canonical "this still works" anchor per AC. Re-running the dense journey on every regression execution is noise and inflates CI artefact storage with little signal.
|
|
501
503
|
|
|
502
504
|
The `EvidenceShotOrigin` signal (`'feature' | 'regression'`) auto-detects from `E2E_NEW_SPECS`. Mark stage screenshots with `{ tier: 'feature' }`; the helper auto-suppresses them on regression runs. The canonical anchor uses the default tier (`'always'`).
|
|
503
505
|
|
|
@@ -49,7 +49,10 @@ jobs:
|
|
|
49
49
|
if: >-
|
|
50
50
|
github.event_name != 'deployment_status' ||
|
|
51
51
|
(github.event.deployment_status.state == 'success' &&
|
|
52
|
-
(github.event.deployment.environment == 'production' ||
|
|
52
|
+
(github.event.deployment.environment == 'production' ||
|
|
53
|
+
github.event.deployment.environment == 'prod' ||
|
|
54
|
+
endsWith(github.event.deployment.environment, '/ production') ||
|
|
55
|
+
endsWith(github.event.deployment.environment, '/production')))
|
|
53
56
|
runs-on: ubuntu-latest # adapt to your runner; e.g. self-hosted, ubuntu-24.04
|
|
54
57
|
# The full regression target is about 35 minutes. Leave time to archive
|
|
55
58
|
# partial output before GitHub terminates the job.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sdlc-implementer
|
|
3
|
-
description: Take a GitHub issue end-to-end through the Metasession SDLC. Opens with a Workflow Triage step (Phase 0) that classifies the change and routes it — tracked work continues into the full
|
|
3
|
+
description: Take a GitHub issue end-to-end through the Metasession SDLC. Opens with a Workflow Triage step (Phase 0) that classifies the change and routes it — tracked work continues into the full execution; housekeeping/trivial/doc-only is driven to merge down a lightweight path (same step-by-step guidance, no tracked ceremony). Use when the user wants to implement a single GitHub issue as a complete SDLC execution — Phase 1 (classify risk, write implementation plan, update RTM) through Phase 4 (open PR, request UAT review on the portal), then halt; and Phase 5 (merge, post-deploy smoke evidence, mark Released, or change-request loop) on resume. Trigger phrases — "implement issue #N", "fix issue #N", "do issue #N", "implement #N", "implement issue #N under the SDLC", "run the SDLC for issue #N", "automate REQ-XXX from issue to release", "do the SDLC stages for [issue]". Resume phrase — "resume REQ-XXX". MUST delegate end-to-end and visual-regression test work to the e2e-test-engineer skill in Phase 2; never authors e2e tests directly. Do NOT use for partial work — for stage-1 planning only, run the manual walkthrough; for test work alone, invoke e2e-test-engineer directly.
|
|
4
4
|
tags: [sdlc, orchestration, compliance, automation]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# SDLC implementer
|
|
8
8
|
|
|
9
|
-
Take a single GitHub issue end-to-end through the Metasession SDLC. The skill **triages first** (Phase 0): it classifies the change, announces the path it will take, and routes — only a **tracked** change continues into the full
|
|
9
|
+
Take a single GitHub issue end-to-end through the Metasession SDLC. The skill **triages first** (Phase 0): it classifies the change, announces the path it will take, and routes — only a **tracked** change continues into the full execution, while housekeeping, trivial, and compliance-doc-only work is driven down its lighter path **to completion** (the skill still guides every step to merge; it just skips the tracked ceremony). For a tracked change, one command runs Phase 1 through Phase 4 unattended (with a plan-approval pause for HIGH/CRITICAL risk); the human enters the loop at the UAT review gate on the portal. On resume, the skill runs Phase 5 — merge, post-deploy smoke evidence, mark the release Released, or address change-requests and re-submit for UAT re-review.
|
|
10
10
|
|
|
11
11
|
This skill is a single entry point that **routes**, not one that always runs heavy. The change-type taxonomy it routes against is the canonical table in [`change-workflows.md`](https://github.com/metasession-dev/DevAudit-Installer/blob/main/docs/change-workflows.md) (six change-types → commit-type → requirement? → path).
|
|
12
12
|
|
|
@@ -105,7 +105,7 @@ This gate is distinct from Phase 2 step 4's "any deviation from the plan must be
|
|
|
105
105
|
|
|
106
106
|
## Requirements gap flow (devaudit-installer#212)
|
|
107
107
|
|
|
108
|
-
A **requirements gap** is "the ACs themselves were wrong, incomplete, or missing" — discovered by the skill or sub-skills mid-
|
|
108
|
+
A **requirements gap** is "the ACs themselves were wrong, incomplete, or missing" — discovered by the skill or sub-skills mid-execution, not by a user request. This is distinct from:
|
|
109
109
|
|
|
110
110
|
- **Scope expansion** (user asks for something beyond the ACs → scope-expansion halt gate above)
|
|
111
111
|
- **Defect** (implementation doesn't match the ACs → incident filing)
|
|
@@ -146,7 +146,7 @@ Amendment steps:
|
|
|
146
146
|
8. If Phase 3+: re-compile affected evidence
|
|
147
147
|
9. Continue from current phase
|
|
148
148
|
|
|
149
|
-
**(c) File a follow-up REQ** — ship the current REQ as-is, file a separate issue for the requirements gap. Appropriate when the gap is a genuine new behaviour that deserves its own
|
|
149
|
+
**(c) File a follow-up REQ** — ship the current REQ as-is, file a separate issue for the requirements gap. Appropriate when the gap is a genuine new behaviour that deserves its own execution. Continue with the current REQ unchanged.
|
|
150
150
|
|
|
151
151
|
### Distinction from scope-expansion halt gate
|
|
152
152
|
|
|
@@ -324,7 +324,7 @@ _Workflow tweak (CI artifact upload, gate timeout bump, etc.)_
|
|
|
324
324
|
|
|
325
325
|
### Lightweight path (housekeeping / trivial / compliance-doc-only)
|
|
326
326
|
|
|
327
|
-
Reached from Phase 0 for non-tracked change-types. The skill drives this end-to-end; the only difference from the tracked
|
|
327
|
+
Reached from Phase 0 for non-tracked change-types. The skill drives this end-to-end; the only difference from the tracked execution is the absence of _ceremony_, not the absence of _guidance_. It pauses only where a human is genuinely required (PR review, merge).
|
|
328
328
|
|
|
329
329
|
**CI trigger shape — read once before step 7.** DevAudit-Installer-generated `ci.yml.template` runs `Quality Gates` on PRs to the integration branch and on pushes to the integration branch. Older consumers may still have post-merge-only CI (`push: branches: [<integration>]`, no `pull_request:` trigger) until they re-run `devaudit update`. The skill must adapt step 7's wording to whichever shape the project uses; never poll a PR for checks that won't arrive on that consumer yet.
|
|
330
330
|
|
|
@@ -499,9 +499,10 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
499
499
|
|
|
500
500
|
5. **Generate nil incident report if no incidents were closed (devaudit-installer#210 §8a).** After the test pack re-run passes, check whether any `incident`-labelled issues were closed during this REQ's lifecycle (`gh issue list --label incident --state closed --search "REQ-XXX" --json number`). If none were closed and the test pack re-run passes:
|
|
501
501
|
- Create `compliance/governance/nil-incident-report-<version>.md` from the `nil-incident-report.md.template` template.
|
|
502
|
+
- Set frontmatter `incident_kind: "no_incidents_attestation"`, `source_release: "<version>"`, and `semantic_id: "NIL-<version>"`. The `source_release` must be the REQ or standalone housekeeping release that actually owns the attestation.
|
|
502
503
|
- Fill in the scope section (test cases executed/passed/failed, defects filed, incidents reported).
|
|
503
504
|
- Leave the sign-off section with REPLACE markers — the operator fills it in.
|
|
504
|
-
- 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.
|
|
505
|
+
- The nil report uploads as source-owned `incident_report` evidence via `compliance-evidence.yml`'s `upload_incident_report` function, flipping `ISO29119.3.5.4` to COVERED for clean releases. Historical nil reports are not re-uploaded to later REQs unless an explicit bundle manifest references the source release; even then ownership remains on the source release.
|
|
505
506
|
- If incidents WERE closed, skip nil report generation — the populated incident report(s) from `incident-export.yml` serve as the evidence.
|
|
506
507
|
|
|
507
508
|
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:
|
|
@@ -512,22 +513,22 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
512
513
|
|
|
513
514
|
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.
|
|
514
515
|
|
|
515
|
-
|
|
516
|
+
5b.1. **Render the Test Executions table from the portal's execution read model when available (devaudit-installer#394).** Do not hand-build execution rows from uploaded artefacts if the portal exposes first-class test execution records. Query the release-journey / execution API, save the JSON, and render the markdown table with:
|
|
516
517
|
|
|
517
518
|
```bash
|
|
518
|
-
bash scripts/render-test-
|
|
519
|
+
bash scripts/render-test-executions.sh /tmp/release-journey.json
|
|
519
520
|
```
|
|
520
521
|
|
|
521
522
|
First-class rows must preserve:
|
|
522
523
|
- source release
|
|
523
524
|
- SDLC stage
|
|
524
|
-
-
|
|
525
|
-
-
|
|
525
|
+
- execution ordinal within that source release + stage
|
|
526
|
+
- execution kind / outcome
|
|
526
527
|
- workflow or run link
|
|
527
528
|
- related evidence
|
|
528
529
|
- incident or remediation reference
|
|
529
530
|
|
|
530
|
-
If the portal does not
|
|
531
|
+
If the portal does not expose first-class test executions, do not infer executions from uploaded artefact groups. Record the gap in the summary and keep the release unresolved until the execution read model is available.
|
|
531
532
|
|
|
532
533
|
5c. **Run the Phase 3 completion guard before any PR/release-review step (devaudit-installer#341).** The tracked-release evidence pack is incomplete until the required Git artefacts exist. Before proceeding past Phase 3, verify:
|
|
533
534
|
|
|
@@ -634,7 +635,7 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
634
635
|
**Solo-operator teams.** On a one-person team, the literal "reviewer ≠ submitter" check is structurally unsatisfiable. The supported interpretation is _actor type, not human identity_ — AI tooling (the skill-trigger) and the human operator (the portal-approver) are distinct actors. Document this on the release ticket under `## Sign-off (dual-actor)` with the explicit interpretation, and ensure the human operator has independently reviewed the diff before clicking _Approve Production_ in the portal. Without this attestation the four-eyes claim is performative.
|
|
635
636
|
|
|
636
637
|
3. **Apply labels** — `awaiting-uat-review`, `risk:<class>`.
|
|
637
|
-
4. **Comment on the issue**: "Implementation complete. PR #M opened. Evidence on portal: <link>. UAT review requested. Resume with `resume REQ-XXX` once UAT approval is granted on the portal."
|
|
638
|
+
4. **Comment on the issue**: "Implementation complete. PR #M opened. Evidence on portal: <link>. UAT review requested. Reviewer action — perform UAT, record it with `scripts/record-uat-execution.sh`, then approve or request changes on the portal. Resume with `resume REQ-XXX` once UAT approval is granted on the portal."
|
|
638
639
|
5. **Inspect PR blockers before handoff (devaudit-installer#304).** Run `gh pr view <N> --json mergeStateStatus,reviewDecision,statusCheckRollup,url` and categorize the state:
|
|
639
640
|
- `reviewDecision` not approved → human approval blocker; hand off to the reviewer.
|
|
640
641
|
- Release Approval Gate failing while portal state is not `uat_approved` → portal approval blocker; hand off to portal UAT reviewer.
|
|
@@ -658,7 +659,8 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
658
659
|
The watcher persists retry state in `.sdlc-pr-watch.json`, polls `gh pr view` + `gh pr checks`, re-runs likely flaky workflows automatically, and re-runs the Release Approval Gate when the portal is already approved but GitHub has not converged yet. For a release PR (`$INTEGRATION_BRANCH -> $RELEASE_BRANCH`), it must not call the PR green until the full required release check set has reached terminal success: `Quality Gates`, `Release Scope Integrity`, `Compliance Validation`, `DevAudit Release Approval`, and `E2E Regression Suite`. Use `--once` when you only need a single classification pass.
|
|
659
660
|
|
|
660
661
|
6. **Hard stop only after blocker classification.** Phase 4 ends here. Do not proceed to merge; the human's next action is reviewing on the portal or clearing the categorized blocker above.
|
|
661
|
-
7. **
|
|
662
|
+
7. **Require a separate UAT execution record.** `scripts/submit-for-uat-review.sh` is a queue transition only. The reviewer must run `scripts/record-uat-execution.sh --project-slug <slug> --release REQ-XXX --outcome passed|failed --executor "<identity>" --tested-sha <sha> --checklist-ref "<ref>" --evidence-ref "<ref>"` after performing UAT and before portal approval. A `failed` execution must include `--remediation-ref <issue-or-pr>` and returns to the change-request loop. The skill must not create a passing UAT execution on behalf of the reviewer.
|
|
663
|
+
8. **Update SDLC status sticky** before halting: `bash scripts/update-sdlc-status.sh "$ISSUE_NUM" "Phase 4 — truthful release PR #<N> prepared against $RELEASE_BRANCH; blockers classified" "Operator action — review PR #<N>, perform UAT, record Stage 4 UAT execution, then approve or request changes on the portal; sdlc-implementer halts until you ping resume REQ-XXX"`. This is a critical handoff — the sticky must reflect that the agent has stopped + the operator is on the hook.
|
|
662
664
|
|
|
663
665
|
**When an external gate hangs or fails for unrelated reasons.** A required gate may fail for reasons outside the change's scope — flaky infra, an unrelated regression test that hangs at hour-plus runtime with no log activity, a known-failing suite. When this happens:
|
|
664
666
|
|
|
@@ -706,7 +708,7 @@ Invoked separately by the user after UAT activity on the portal. Trigger: "resum
|
|
|
706
708
|
These steps are mandatory — "PR merged" or "release marked Released" is not complete until the automated close-out PR has merged or a documented fallback reconciliation is complete. Without it, CI can keep uploading evidence against a completed REQ and pollute the audit trail.
|
|
707
709
|
- **Update SDLC status sticky** to the terminal state: `bash scripts/update-sdlc-status.sh "$ISSUE_NUM" "Phase 5 complete — release marked Released; production smoke evidence uploaded; automated close-out reconciled RTM and release ticket" "Done — close issue + retire feature branch (sdlc-implementer halts)"`.
|
|
708
710
|
- Close the issue only after close-out reconciliation completes.
|
|
709
|
-
- If production smoke fails: do NOT mark as Released. **Delegate incident filing to `governance-doc-author` (devaudit-installer#210 §6c)** — invoke `Skill(name: "governance-doc-author", args: "Production smoke failure for REQ-XXX. File an incident issue with the `incident` label + `### Framework attribution` section (ISO29119.3.5.4 + SOC2.CC7.2), severity `blocker`. Include the production URL, git SHA,
|
|
711
|
+
- If production smoke fails: do NOT mark as Released. **Delegate incident filing to `governance-doc-author` (devaudit-installer#210 §6c)** — invoke `Skill(name: "governance-doc-author", args: "Production smoke failure for REQ-XXX. File an incident issue with the `incident` label + `### Framework attribution` section (ISO29119.3.5.4 + SOC2.CC7.2), severity `blocker`. Include the production URL, git SHA, testExecutionId (CI run ID), and smoke results in the issue body.")`. Page the on-call per the project's incident playbook, follow the rollback plan from the implementation plan. If the rollback also fails: update the sticky to "Phase 5 CRITICAL — production smoke failed AND rollback failed. Production is in a broken state. Operator action — page on-call immediately, engage hosting platform support, declare incident per the project's incident playbook. This is beyond the skill's scope." Do NOT attempt further automated remediation. **Update the sticky** to reflect the incident state: `… "Phase 5 BLOCKED — production smoke failed; INCIDENT issue #N filed" "Operator action — read INCIDENT #N + execute rollback per plan"`.
|
|
710
712
|
|
|
711
713
|
- **Changes requested** → run change-request loop:
|
|
712
714
|
- Fetch change-request comments from the PR (`gh pr view <M> --comments`) and from the portal release page.
|