@metasession.co/devaudit-cli 0.1.70 → 0.1.72
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 +41 -3
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/sdlc/files/_common/scripts/derive-release-version.sh +7 -0
- package/sdlc/files/_common/scripts/generate-bundled-changes.sh +88 -0
- package/sdlc/files/_common/scripts/generate-bundled-changes.test.sh +183 -0
- package/sdlc/files/_common/scripts/validate-commits.sh +23 -0
- package/sdlc/files/_common/skills/e2e-test-engineer/SKILL.md +14 -0
- package/sdlc/files/_common/skills/sdlc-implementer/SKILL.md +111 -9
- package/sdlc/files/ci/ci.yml.template +41 -3
- package/sdlc/files/ci/compliance-evidence.yml.template +59 -41
- package/sdlc/files/ci/incident-export.yml.template +18 -8
- package/sdlc/files/stacks/node/hooks/pre-push +118 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metasession.co/devaudit-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.72",
|
|
4
4
|
"description": "DevAudit CLI — installs, syncs, and operates the Metasession SDLC across consumer projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@clack/prompts": "^0.8.2",
|
|
36
|
-
"@metasession.co/devaudit-plugin-sdk": "^0.1.
|
|
36
|
+
"@metasession.co/devaudit-plugin-sdk": "^0.1.72",
|
|
37
37
|
"ajv": "^8.20.0",
|
|
38
38
|
"commander": "^12.1.0",
|
|
39
39
|
"consola": "^3.2.3",
|
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
"execa": "^9.5.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
+
"@types/js-yaml": "^4.0.9",
|
|
44
45
|
"@types/node": "^22.9.0",
|
|
46
|
+
"js-yaml": "^5.1.0",
|
|
45
47
|
"msw": "^2.7.0",
|
|
46
48
|
"tsup": "^8.3.5",
|
|
47
49
|
"typescript": "^5.7.2",
|
|
@@ -26,6 +26,13 @@
|
|
|
26
26
|
# bare date — when exactly one ticket is open, attribute to it.
|
|
27
27
|
# Multiple open tickets stays ambiguous → bare-date fallback.
|
|
28
28
|
#
|
|
29
|
+
# Note (DevAudit-Installer#220): `devaudit update` syncs now include
|
|
30
|
+
# `[skip ci]` in their commit message, so they no longer trigger CI
|
|
31
|
+
# at all. The bare-date fallback (step 5) is therefore reached only by
|
|
32
|
+
# human-authored housekeeping commits — the intended use case. Skipped
|
|
33
|
+
# housekeeping changes are bundled into the next REQ release via
|
|
34
|
+
# `generate-bundled-changes.sh` (run by the register-release CI job).
|
|
35
|
+
#
|
|
29
36
|
# Step 4-bis (DevAudit-Installer#95) is the zero-ceremony equivalent:
|
|
30
37
|
# RTM.md is the file the operator already maintains as the source of
|
|
31
38
|
# truth for release state. When step 4 finds no ticket and exactly one
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# generate-bundled-changes.sh
|
|
3
|
+
#
|
|
4
|
+
# Scans commits since a given ref (tag, SHA, or branch) and filters for
|
|
5
|
+
# housekeeping commit types (chore/docs/ci/build/test/revert) that were
|
|
6
|
+
# skipped via [skip ci] or otherwise not individually released. Outputs
|
|
7
|
+
# a markdown summary suitable for upload as `bundled_changes` evidence
|
|
8
|
+
# against a REQ-tagged release.
|
|
9
|
+
#
|
|
10
|
+
# Synced into the consumer's `scripts/` by `devaudit update`; invoked
|
|
11
|
+
# from `ci.yml` register-release job when the derived version is a
|
|
12
|
+
# REQ-tagged release (not bare-date).
|
|
13
|
+
#
|
|
14
|
+
# Usage:
|
|
15
|
+
# bash scripts/generate-bundled-changes.sh <since-ref> [<version>]
|
|
16
|
+
#
|
|
17
|
+
# Where:
|
|
18
|
+
# <since-ref> — git ref to scan from (tag, SHA, or branch name).
|
|
19
|
+
# Typically the previous release tag or the merge-base
|
|
20
|
+
# of the current branch and the previous release.
|
|
21
|
+
# <version> — (optional) the release version for the header.
|
|
22
|
+
# Defaults to "current release".
|
|
23
|
+
#
|
|
24
|
+
# Output (stdout): markdown document listing housekeeping commits
|
|
25
|
+
# absorbed into this release.
|
|
26
|
+
#
|
|
27
|
+
# DevAudit-Installer#220.
|
|
28
|
+
|
|
29
|
+
set -euo pipefail
|
|
30
|
+
|
|
31
|
+
SINCE_REF="${1:-}"
|
|
32
|
+
VERSION="${2:-current release}"
|
|
33
|
+
|
|
34
|
+
if [ -z "$SINCE_REF" ]; then
|
|
35
|
+
echo "Usage: bash scripts/generate-bundled-changes.sh <since-ref> [<version>]" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Verify the ref exists before proceeding.
|
|
40
|
+
if ! git rev-parse --verify "$SINCE_REF" >/dev/null 2>&1; then
|
|
41
|
+
echo "Error: ref '$SINCE_REF' not found in git history." >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Housekeeping commit type prefixes (Conventional Commits).
|
|
46
|
+
# feat/fix are tracked changes — excluded. Anything else is housekeeping.
|
|
47
|
+
# The git log format is "<short-sha>\t<subject>", so the regex matches
|
|
48
|
+
# the commit type after the tab character.
|
|
49
|
+
HOUSEKEEPING_TYPES='^[0-9a-f]+ (chore|docs|ci|build|test|revert|style|perf|refactor)(\(.+\))?!?:'
|
|
50
|
+
|
|
51
|
+
# Collect commits since the ref, filtering for housekeeping types.
|
|
52
|
+
# Format: <short-sha>\t<subject>
|
|
53
|
+
COMMITS=$(git log "$SINCE_REF"..HEAD --format='%h %s' 2>/dev/null || true)
|
|
54
|
+
|
|
55
|
+
if [ -z "$COMMITS" ]; then
|
|
56
|
+
# No commits since ref — output an empty summary.
|
|
57
|
+
echo "## Bundled Changes"
|
|
58
|
+
echo ""
|
|
59
|
+
echo "No housekeeping commits found since \`${SINCE_REF}\`."
|
|
60
|
+
echo ""
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Filter for housekeeping commit types.
|
|
65
|
+
BUNDLED=$(echo "$COMMITS" | grep -E "$HOUSEKEEPING_TYPES" || true)
|
|
66
|
+
|
|
67
|
+
if [ -z "$BUNDLED" ]; then
|
|
68
|
+
echo "## Bundled Changes"
|
|
69
|
+
echo ""
|
|
70
|
+
echo "No housekeeping commits found since \`${SINCE_REF}\`."
|
|
71
|
+
echo ""
|
|
72
|
+
exit 0
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# Count the bundled commits.
|
|
76
|
+
COUNT=$(echo "$BUNDLED" | wc -l | tr -d ' ')
|
|
77
|
+
|
|
78
|
+
# Generate the markdown summary.
|
|
79
|
+
echo "## Bundled Changes"
|
|
80
|
+
echo ""
|
|
81
|
+
echo "The following ${COUNT} housekeeping commit(s) were absorbed into release \`${VERSION}\` since \`${SINCE_REF}\`:"
|
|
82
|
+
echo ""
|
|
83
|
+
echo "$BUNDLED" | while IFS=$'\t' read -r SHA SUBJECT; do
|
|
84
|
+
echo "- \`${SHA}\` ${SUBJECT}"
|
|
85
|
+
done
|
|
86
|
+
echo ""
|
|
87
|
+
echo "These commits were not individually released (tooling syncs / housekeeping)."
|
|
88
|
+
echo "Gate evidence above covers the full state of develop at CI time, including these changes."
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# generate-bundled-changes.test.sh — Tests for generate-bundled-changes.sh.
|
|
3
|
+
#
|
|
4
|
+
# Builds a throwaway git repo per case, crafts commits with mixed types,
|
|
5
|
+
# runs the helper against it, asserts on the stdout content. Hermetic:
|
|
6
|
+
# runs inside mktemp'd directories that are torn down at the end.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# ./scripts/generate-bundled-changes.test.sh
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
14
|
+
HELPER="$SCRIPT_DIR/generate-bundled-changes.sh"
|
|
15
|
+
[ -x "$HELPER" ] || chmod +x "$HELPER"
|
|
16
|
+
|
|
17
|
+
PASS=0
|
|
18
|
+
FAIL=0
|
|
19
|
+
|
|
20
|
+
TMPDIR_BASE="$(mktemp -d)"
|
|
21
|
+
trap 'rm -rf "$TMPDIR_BASE"' EXIT
|
|
22
|
+
|
|
23
|
+
# Build a fresh git fixture with an initial commit.
|
|
24
|
+
make_fixture() {
|
|
25
|
+
local dir="$1"
|
|
26
|
+
rm -rf "$dir"
|
|
27
|
+
mkdir -p "$dir"
|
|
28
|
+
cd "$dir"
|
|
29
|
+
git init -q --initial-branch=main
|
|
30
|
+
git config user.email "test@example.com"
|
|
31
|
+
git config user.name "test"
|
|
32
|
+
echo "x" > f.txt
|
|
33
|
+
git add f.txt
|
|
34
|
+
git commit -q -m "feat: initial commit [REQ-001]"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Add a commit with a given message.
|
|
38
|
+
add_commit() {
|
|
39
|
+
local msg="$1"
|
|
40
|
+
echo "$(date +%s%N)" >> f.txt
|
|
41
|
+
git add f.txt
|
|
42
|
+
git commit -q -m "$msg"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
assert_contains() {
|
|
46
|
+
local desc="$1" want="$2" got="$3"
|
|
47
|
+
if echo "$got" | grep -qF "$want"; then
|
|
48
|
+
echo " PASS: $desc"
|
|
49
|
+
PASS=$((PASS + 1))
|
|
50
|
+
else
|
|
51
|
+
echo " FAIL: $desc"
|
|
52
|
+
echo " want (substring): $want"
|
|
53
|
+
echo " got:"
|
|
54
|
+
echo "$got" | sed 's/^/ /'
|
|
55
|
+
FAIL=$((FAIL + 1))
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
assert_not_contains() {
|
|
60
|
+
local desc="$1" want="$2" got="$3"
|
|
61
|
+
if echo "$got" | grep -qF "$want"; then
|
|
62
|
+
echo " FAIL: $desc"
|
|
63
|
+
echo " should not contain: $want"
|
|
64
|
+
echo " got:"
|
|
65
|
+
echo "$got" | sed 's/^/ /'
|
|
66
|
+
FAIL=$((FAIL + 1))
|
|
67
|
+
else
|
|
68
|
+
echo " PASS: $desc"
|
|
69
|
+
PASS=$((PASS + 1))
|
|
70
|
+
fi
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# ─── Test 1: Mixed commits — only housekeeping types in output ─────
|
|
74
|
+
echo "Test 1: mixed commits filter to housekeeping only"
|
|
75
|
+
DIR1="$TMPDIR_BASE/test1"
|
|
76
|
+
make_fixture "$DIR1"
|
|
77
|
+
add_commit "chore: sync DevAudit templates from v0.1.69 to v0.1.70 [skip ci]"
|
|
78
|
+
add_commit "docs: update API reference for /bookings endpoint"
|
|
79
|
+
add_commit "feat: add booking widget [REQ-042]"
|
|
80
|
+
add_commit "chore: bump eslint 9.0.5 to 9.0.6"
|
|
81
|
+
add_commit "fix: resolve null pointer in booking service [REQ-042]"
|
|
82
|
+
# Tag the initial commit as the "since" ref
|
|
83
|
+
SINCE=$(git rev-list --max-parents=0 HEAD)
|
|
84
|
+
OUTPUT=$(bash "$HELPER" "$SINCE" "REQ-042" 2>&1 || true)
|
|
85
|
+
assert_contains "housekeeping chore: sync in output" "chore: sync DevAudit templates" "$OUTPUT"
|
|
86
|
+
assert_contains "housekeeping docs: update in output" "docs: update API reference" "$OUTPUT"
|
|
87
|
+
assert_contains "housekeeping chore: bump eslint in output" "chore: bump eslint" "$OUTPUT"
|
|
88
|
+
assert_not_contains "feat commit excluded" "feat: add booking widget" "$OUTPUT"
|
|
89
|
+
assert_not_contains "fix commit excluded" "fix: resolve null pointer" "$OUTPUT"
|
|
90
|
+
assert_contains "header present" "## Bundled Changes" "$OUTPUT"
|
|
91
|
+
assert_contains "version in header" "REQ-042" "$OUTPUT"
|
|
92
|
+
echo
|
|
93
|
+
|
|
94
|
+
# ─── Test 2: No housekeeping commits ────────────────────────────────
|
|
95
|
+
echo "Test 2: no housekeeping commits — empty summary"
|
|
96
|
+
DIR2="$TMPDIR_BASE/test2"
|
|
97
|
+
make_fixture "$DIR2"
|
|
98
|
+
add_commit "feat: add feature A [REQ-010]"
|
|
99
|
+
add_commit "fix: fix bug B [REQ-010]"
|
|
100
|
+
SINCE=$(git rev-list --max-parents=0 HEAD)
|
|
101
|
+
OUTPUT=$(bash "$HELPER" "$SINCE" "REQ-010" 2>&1 || true)
|
|
102
|
+
assert_contains "no housekeeping message" "No housekeeping commits found" "$OUTPUT"
|
|
103
|
+
echo
|
|
104
|
+
|
|
105
|
+
# ─── Test 3: All housekeeping types captured ────────────────────────
|
|
106
|
+
echo "Test 3: all housekeeping commit types captured"
|
|
107
|
+
DIR3="$TMPDIR_BASE/test3"
|
|
108
|
+
make_fixture "$DIR3"
|
|
109
|
+
add_commit "ci: update workflow timeout"
|
|
110
|
+
add_commit "build: bump node version to 22"
|
|
111
|
+
add_commit "test: add unit test for booking"
|
|
112
|
+
add_commit "revert: remove experimental feature"
|
|
113
|
+
add_commit "style: fix formatting in utils"
|
|
114
|
+
add_commit "perf: optimize query in booking"
|
|
115
|
+
add_commit "refactor: extract validation logic"
|
|
116
|
+
SINCE=$(git rev-list --max-parents=0 HEAD)
|
|
117
|
+
OUTPUT=$(bash "$HELPER" "$SINCE" "REQ-030" 2>&1 || true)
|
|
118
|
+
assert_contains "ci: type captured" "ci: update workflow timeout" "$OUTPUT"
|
|
119
|
+
assert_contains "build: type captured" "build: bump node version" "$OUTPUT"
|
|
120
|
+
assert_contains "test: type captured" "test: add unit test for booking" "$OUTPUT"
|
|
121
|
+
assert_contains "revert: type captured" "revert: remove experimental feature" "$OUTPUT"
|
|
122
|
+
assert_contains "style: type captured" "style: fix formatting" "$OUTPUT"
|
|
123
|
+
assert_contains "perf: type captured" "perf: optimize query" "$OUTPUT"
|
|
124
|
+
assert_contains "refactor: type captured" "refactor: extract validation" "$OUTPUT"
|
|
125
|
+
echo
|
|
126
|
+
|
|
127
|
+
# ─── Test 4: No commits since ref ───────────────────────────────────
|
|
128
|
+
echo "Test 4: no commits since ref — empty summary"
|
|
129
|
+
DIR4="$TMPDIR_BASE/test4"
|
|
130
|
+
make_fixture "$DIR4"
|
|
131
|
+
SINCE=$(git rev-parse HEAD)
|
|
132
|
+
OUTPUT=$(bash "$HELPER" "$SINCE" "REQ-001" 2>&1 || true)
|
|
133
|
+
assert_contains "no commits message" "No housekeeping commits found" "$OUTPUT"
|
|
134
|
+
echo
|
|
135
|
+
|
|
136
|
+
# ─── Test 5: Invalid ref ────────────────────────────────────────────
|
|
137
|
+
echo "Test 5: invalid ref — error exit"
|
|
138
|
+
DIR5="$TMPDIR_BASE/test5"
|
|
139
|
+
make_fixture "$DIR5"
|
|
140
|
+
set +e
|
|
141
|
+
OUTPUT=$(bash "$HELPER" "nonexistent-ref" "REQ-001" 2>&1)
|
|
142
|
+
RC=$?
|
|
143
|
+
set -e
|
|
144
|
+
if [ "$RC" -ne 0 ]; then
|
|
145
|
+
echo " PASS: non-zero exit code for invalid ref"
|
|
146
|
+
PASS=$((PASS + 1))
|
|
147
|
+
else
|
|
148
|
+
echo " FAIL: expected non-zero exit code for invalid ref"
|
|
149
|
+
FAIL=$((FAIL + 1))
|
|
150
|
+
fi
|
|
151
|
+
echo
|
|
152
|
+
|
|
153
|
+
# ─── Test 6: Scoped commit types (chore(deps)) ─────────────────────
|
|
154
|
+
echo "Test 6: scoped housekeeping commits captured"
|
|
155
|
+
DIR6="$TMPDIR_BASE/test6"
|
|
156
|
+
make_fixture "$DIR6"
|
|
157
|
+
add_commit "chore(deps): bump eslint from 9.0.5 to 9.0.6"
|
|
158
|
+
add_commit "ci(workflow): update timeout to 30 minutes"
|
|
159
|
+
SINCE=$(git rev-list --max-parents=0 HEAD)
|
|
160
|
+
OUTPUT=$(bash "$HELPER" "$SINCE" "REQ-050" 2>&1 || true)
|
|
161
|
+
assert_contains "scoped chore(deps) captured" "chore(deps): bump eslint" "$OUTPUT"
|
|
162
|
+
assert_contains "scoped ci(workflow) captured" "ci(workflow): update timeout" "$OUTPUT"
|
|
163
|
+
echo
|
|
164
|
+
|
|
165
|
+
# ─── Test 7: Missing since-ref argument ────────────────────────────
|
|
166
|
+
echo "Test 7: missing since-ref argument — error exit"
|
|
167
|
+
DIR7="$TMPDIR_BASE/test7"
|
|
168
|
+
make_fixture "$DIR7"
|
|
169
|
+
set +e
|
|
170
|
+
OUTPUT=$(bash "$HELPER" 2>&1)
|
|
171
|
+
RC=$?
|
|
172
|
+
set -e
|
|
173
|
+
if [ "$RC" -ne 0 ]; then
|
|
174
|
+
echo " PASS: non-zero exit code for missing argument"
|
|
175
|
+
PASS=$((PASS + 1))
|
|
176
|
+
else
|
|
177
|
+
echo " FAIL: expected non-zero exit code for missing argument"
|
|
178
|
+
FAIL=$((FAIL + 1))
|
|
179
|
+
fi
|
|
180
|
+
echo
|
|
181
|
+
|
|
182
|
+
echo "=== Summary: ${PASS} pass / ${FAIL} fail ==="
|
|
183
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -74,6 +74,29 @@ while IFS= read -r sha; do
|
|
|
74
74
|
EXIT_CODE=1
|
|
75
75
|
continue
|
|
76
76
|
fi
|
|
77
|
+
|
|
78
|
+
# RTM provenance check (devaudit-installer#226): verify the REQ-XXX
|
|
79
|
+
# cited in the commit has an sdlc-implementer@<version> provenance
|
|
80
|
+
# stamp in compliance/RTM.md. Without the stamp, the skill was not
|
|
81
|
+
# invoked and the RTM row was created manually.
|
|
82
|
+
REQ_ID=$(echo "$SUBJECT" | grep -oP '\[REQ-\d{3,}\]' | tr -d '[]' || true)
|
|
83
|
+
if [ -z "$REQ_ID" ]; then
|
|
84
|
+
REQ_ID=$(echo "$BODY" | grep -oiP 'Ref:\s*REQ-\d{3,}' | grep -oP 'REQ-\d{3,}' | tail -1 || true)
|
|
85
|
+
fi
|
|
86
|
+
if [ -n "$REQ_ID" ] && [ -f compliance/RTM.md ]; then
|
|
87
|
+
RTM_ROW=$(grep -m1 -E "^\| ${REQ_ID} " compliance/RTM.md || true)
|
|
88
|
+
if [ -n "$RTM_ROW" ]; then
|
|
89
|
+
if ! echo "$RTM_ROW" | grep -q 'sdlc-implementer@'; then
|
|
90
|
+
echo "ERROR [$SHORT]: $REQ_ID in commit message has no sdlc-implementer provenance in RTM.md."
|
|
91
|
+
echo " The RTM row for $REQ_ID was not created by the sdlc-implementer skill."
|
|
92
|
+
echo " Either invoke sdlc-implementer and re-run, or add the provenance marker"
|
|
93
|
+
echo " 'sdlc-implementer@<version>' to the RTM row manually with operator sign-off."
|
|
94
|
+
FAILED=$((FAILED + 1))
|
|
95
|
+
EXIT_CODE=1
|
|
96
|
+
continue
|
|
97
|
+
fi
|
|
98
|
+
fi
|
|
99
|
+
fi
|
|
77
100
|
;;
|
|
78
101
|
esac
|
|
79
102
|
|
|
@@ -288,6 +288,20 @@ There is no `regression/` sub-directory, no `@regression` tag, no manifest file.
|
|
|
288
288
|
|
|
289
289
|
You don't need to do anything explicit for this step — it's a property of the pipeline, not an action. Surface it in the final report so the reviewer knows the new tests are now load-bearing for every future release.
|
|
290
290
|
|
|
291
|
+
**Write the E2E gate sentinel (devaudit-installer#226).** After a successful full regression run (Phase 6 step 2), write a `.e2e-gate-passed` sentinel file in the repo root so the pre-push hook and `sdlc-implementer` Phase 2 step 5b can verify the E2E gate ran:
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
echo "PASSED $(date -u +%Y-%m-%dT%H:%M:%SZ) ${{ github.run_id }}" > .e2e-gate-passed
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
If you determined e2e is not needed for this REQ (schema-only, API-only, no UI surface), write the sentinel with a `NOT_NEEDED` reason instead:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
echo "NOT_NEEDED $(date -u +%Y-%m-%dT%H:%M:%SZ) <reason>" > .e2e-gate-passed
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
The file is gitignored and never committed — it's a local-only signal that the gate was run in this working directory.
|
|
304
|
+
|
|
291
305
|
### Filing defects
|
|
292
306
|
|
|
293
307
|
Use whatever tracker integration you found in Phase 1: `gh issue create`, `glab issue create`, a Jira or Linear MCP tool, `az boards work-item create`. If nothing is available, produce a markdown report with each defect formatted ready to paste.
|
|
@@ -96,7 +96,7 @@ When the user asks for a change that goes beyond the current REQ's acceptance cr
|
|
|
96
96
|
|
|
97
97
|
4. **Wait for the user to confirm one of:**
|
|
98
98
|
- **(a) File a separate issue** (new REQ) — ship the current REQ as-is. The agent continues with the original scope.
|
|
99
|
-
- **(b) Amend REQ-XXX's scope** — explicitly expand `test-scope.md` / `implementation-plan.md`, update the plan, invalidate existing evidence, and re-walk Stage 3. This option carries a warning: *"Amending scope after evidence is compiled (Stage 3+) invalidates the existing test-execution-summary, screenshots, and UAT verification. All Stage 3 evidence must be re-compiled."*
|
|
99
|
+
- **(b) Amend REQ-XXX's scope** — explicitly expand `test-scope.md` / `test-plan.md` / `implementation-plan.md`, update the plan, invalidate existing evidence, and re-walk Stage 3. Re-extract both `test-scope.md` and `test-plan.md` from the updated plan (Phase 1 step 5b drift management). This option carries a warning: *"Amending scope after evidence is compiled (Stage 3+) invalidates the existing test-execution-summary, screenshots, and UAT verification. All Stage 3 evidence must be re-compiled."*
|
|
100
100
|
- **(c) Abandon the request** — do nothing, continue with the original scope.
|
|
101
101
|
|
|
102
102
|
**Do not implement the out-of-scope change before the user picks (a), (b), or (c).** The inertia trap is real: the agent is mid-flow, the codebase is open, and the request sounds reasonable. The gate exists to interrupt that inertia — STOP, surface the scope gap, and let the user decide.
|
|
@@ -140,10 +140,11 @@ Amendment steps:
|
|
|
140
140
|
2. Re-invoke `requirements-aligner` → propose new/updated SRS stubs
|
|
141
141
|
3. Operator edits SRS stubs into canonical Given/When/Then prose in `docs/SRS.md`
|
|
142
142
|
4. Update `compliance/RTM.md`
|
|
143
|
-
5.
|
|
144
|
-
6.
|
|
145
|
-
7. If Phase
|
|
146
|
-
8.
|
|
143
|
+
5. Re-extract `compliance/evidence/REQ-XXX/test-scope.md` and `compliance/evidence/REQ-XXX/test-plan.md` from the updated plan (Phase 1 step 5b drift management, devaudit-installer#226)
|
|
144
|
+
6. Commit: `compliance: [REQ-XXX] amend ACs — requirements gap <description>`
|
|
145
|
+
7. If Phase 2+: re-run affected tests (delegating to `e2e-test-engineer` if e2e)
|
|
146
|
+
8. If Phase 3+: re-compile affected evidence
|
|
147
|
+
9. Continue from current phase
|
|
147
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 cycle. Continue with the current REQ unchanged.
|
|
149
150
|
|
|
@@ -254,7 +255,7 @@ Runs **first**, before any `REQ-XXX` is assigned. It decides which of the six ch
|
|
|
254
255
|
3. **Announce a "Workflow Decision" block** (template below): change-type, commit-type, whether a `REQ-XXX` is needed, risk class, which stages/gates run, which approvals the **operator** must perform (UAT four-eyes, Production approval), and what is **skipped**.
|
|
255
256
|
4. **Pause policy — pause-when-it-matters.** Pause for explicit confirmation on **tracked / heavier** paths, or when classification is **ambiguous**; **announce-and-auto-proceed** on trivial / housekeeping. The operator can always reclassify ("treat this as housekeeping" / "this is HIGH risk").
|
|
256
257
|
5. **Route — and stay on to completion.** A route is a choice of _which workflow to drive_, never a hand-off that abandons the operator. Whatever the path, the skill keeps guiding step by step until no further action is required (typically: merged).
|
|
257
|
-
- **tracked** (feature / bug fix / refactor / perf) → continue into Phase 1 below (full Stages 1–5).
|
|
258
|
+
- **tracked** (feature / bug fix / refactor / perf) → continue into Phase 1 below (full Stages 1–5). **Write the skill-invocation sentinel** (devaudit-installer#226): `echo "INVOKED $(date -u +%Y-%m-%dT%H:%M:%SZ)" > .sdlc-implementer-invoked`. This file is gitignored and never committed — it's a local-only signal that the pre-push hook checks before allowing `feat`/`fix`/`refactor`/`perf` commits to be pushed. Without this sentinel, the pre-push hook will refuse the push and `validate-commits.sh` in CI will flag missing RTM provenance.
|
|
258
259
|
- **housekeeping / trivial** → drive the **Lightweight path** below to completion. No `REQ-XXX`, no RTM row, no evidence pack, no portal release approvals — but the skill still branches, runs the gates, opens the PR, and walks the operator through review → merge.
|
|
259
260
|
- **compliance-doc-only** → drive the same Lightweight path as a docs push (or PR, per the project's flow) referencing the **existing** `REQ-XXX`: no new requirement and no quality-gate ceremony, but driven through to merge.
|
|
260
261
|
6. **Write labels back.** Apply the inferred `type:*` / `risk:*` labels so the issue ends up labelled — `gh label create <label> --force` to ensure the label exists (idempotent; no failure if a label-seeding step never ran), then `gh issue edit <N> --add-label <label>`. Future triage is then a glance.
|
|
@@ -354,6 +355,15 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
354
355
|
|
|
355
356
|
**Don't delete sections** — mark with `N/A — <reason>` if a clause genuinely doesn't apply (e.g. UI-only change with no personal-data scope). Empty stubs commit-then-upload as placeholder evidence and break the audit trail.
|
|
356
357
|
|
|
358
|
+
5b. **Extract `test-scope.md` and `test-plan.md` from the implementation plan (devaudit-installer#226).** After step 5, extract two artefacts from the plan into `compliance/evidence/REQ-XXX/` so CI's `validate-compliance-artifacts.sh` finds them in the expected location:
|
|
359
|
+
|
|
360
|
+
- **`compliance/evidence/REQ-XXX/test-scope.md`** — the AC table with SRS-IDs, risk class, and verification method per AC. Extracted from the plan's "Acceptance criteria" table.
|
|
361
|
+
- **`compliance/evidence/REQ-XXX/test-plan.md`** — the test file listing with AC coverage mapping: which test file covers which AC, test type (unit/integration/e2e), and whether each AC has at least one test. Extracted from the plan's "Test scope" section.
|
|
362
|
+
|
|
363
|
+
These files are the CI validator's expected artefacts. Without them, `validate-compliance-artifacts.sh` fails and the pre-push hook blocks the push. The plan directory (`compliance/plans/REQ-XXX/`) retains the full plan; these are extracted subsets for CI validation.
|
|
364
|
+
|
|
365
|
+
**Drift management (devaudit-installer#226).** If the plan's AC table changes after step 5b (requirements gap flow option (b), scope-expansion halt gate option (b), or plan deviation), re-extract both `test-scope.md` and `test-plan.md` from the updated plan. The extracted files must always match the plan's current AC table. Phase 2 step 5b checks plan ↔ test-scope AC consistency before running E2E.
|
|
366
|
+
|
|
357
367
|
6. **Invoke `requirements-aligner` to populate the SRS-ID column on the AC table.** The plan's "Acceptance criteria" table carries an SRS-ID column per AC; `requirements-aligner` fuzzy-matches each AC against `docs/SRS.md` and proposes new `REQ-AREA-NNN` stubs, flags stale items, or annotates `@srs-deferred`. Don't author the SRS-ID column inline — call via the standard Claude Code Skill mechanism (`Skill(name: "requirements-aligner", …)`). Block plan APPROVAL until every AC has a resolved SRS-ID per the skill's Phase 1 contract (configurable via `sdlc-config.json:requirements_aligner.block_on_stage_1`; ramp-up mode default-on for legacy projects).
|
|
358
368
|
|
|
359
369
|
**SRS stub editing (devaudit-installer#212 Gap 5).** After `requirements-aligner` returns, the plan's SRS items proposed/touched section may contain N new stubs and M stale items. The operator must edit `docs/SRS.md` to flesh out the stubs into canonical Given/When/Then prose and update stale items. Do not proceed to Phase 2 until the SRS is updated. The skill enforces this by checking that no stub placeholders remain in `docs/SRS.md` for the proposed SRS-IDs before auto-continuing. A stub placeholder is any SRS entry containing `<TODO>` or the `@srs-stub` marker.
|
|
@@ -364,7 +374,7 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
364
374
|
- **`requirements-aligner` fails** (e.g. no `docs/SRS.md`): If `block_on_stage_1` is true, halt — "requirements-aligner could not find SRS.md. Operator action — create `docs/SRS.md` or disable `requirements_aligner.block_on_stage_1` in `sdlc-config.json`." If false, warn and continue with `@srs-deferred` on all ACs.
|
|
365
375
|
- **`adr-author` fails**: Warn and continue — ADR is advisory by default. Mark the plan's "Architecture decisions" section as "ADR assessment skipped — <error>".
|
|
366
376
|
- **`risk-register-keeper` fails**: If `block_on_stage_1` is true, halt. If false, warn and continue — mark the plan's "Risk register entries" section as "Risk assessment skipped — <error>".
|
|
367
|
-
9. **Update `compliance/RTM.md`** with the new entry: REQ-XXX, title, risk class, linked issue, linked test cases (placeholder).
|
|
377
|
+
9. **Update `compliance/RTM.md`** with the new entry: REQ-XXX, title, risk class, linked issue, linked test cases (placeholder), and a provenance marker `sdlc-implementer@<version>` (devaudit-installer#226). The provenance column is the last column in the RTM row — `validate-commits.sh` in CI checks for its presence when `feat`/`fix`/`refactor`/`perf` commits cite a REQ-XXX. Without the stamp, CI fails with "no sdlc-implementer provenance in RTM.md." If the RTM table doesn't have a provenance column, add one with header `Provenance`.
|
|
368
378
|
10. **Post plan summary as an issue comment.** Format: TL;DR; Risk class + signals; Acceptance criteria (with SRS-IDs); Architectural decisions (ADR-NNN reference or no-ADR rationale); Risk register entries (RISK-NNN list); Technical approach (one paragraph); Dependencies; Test scope.
|
|
369
379
|
11. **Checkpoint** — pause for human approval **iff** risk class is HIGH or CRITICAL. LOW and MEDIUM pass through to Phase 2 automatically. The checkpoint can be forced on for all classes via the `--require-plan-approval` flag (or `DEVAUDIT_REQUIRE_PLAN_APPROVAL=1` env var) for orgs that want it always-on.
|
|
370
380
|
12. **Update SDLC status sticky** before exiting Phase 1: `bash scripts/update-sdlc-status.sh "$ISSUE_NUM" "Phase 1 complete — plan written to compliance/plans/REQ-XXX/implementation-plan.md (risk class <CLASS>)" "Phase 2 — sdlc-implementer auto-continuing"` (or "Operator action — review plan + ping resume" if the HIGH/CRITICAL checkpoint paused).
|
|
@@ -401,6 +411,19 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
401
411
|
**E2E gate** — run _once_, after the fast gates are clean:
|
|
402
412
|
- `npx playwright test` (delegated to `e2e-test-engineer`, which has its own focused-iteration discipline for within-e2e fix-and-verify loops)
|
|
403
413
|
|
|
414
|
+
5b. **E2E gate verification — mandatory before commit (devaudit-installer#226).** After running gates in step 5, verify the E2E gate actually ran before proceeding to step 7 (commit). This is the skill-level enforcement that backs the pre-push hook.
|
|
415
|
+
|
|
416
|
+
Check whether the change touches UI-facing files:
|
|
417
|
+
```bash
|
|
418
|
+
git diff --name-only "$INTEGRATION_BRANCH"...HEAD -- 'app/**/*.tsx' 'src/**/*.tsx' 'pages/**/*.tsx' 'app/**/*.jsx' 'src/**/*.jsx' 'pages/**/*.jsx'
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
- **If UI-facing files are present:** check for `.e2e-gate-passed` sentinel file (written by `e2e-test-engineer` after a successful run) or `playwright-report/` directory with recent content. If neither exists, **HALT**: "E2E gate was not run. The change touches UI-facing files. Run `npx playwright test` (or invoke `e2e-test-engineer`) before committing. The pre-push hook will also block this push."
|
|
422
|
+
- **If no UI-facing files (API-only, config, docs):** skip the check. Note the exemption in the commit body: "E2E gate skipped — no UI-facing files in this change."
|
|
423
|
+
- **If `e2e-test-engineer` was invoked and determined e2e is not needed** (e.g. schema-only change): the skill writes `.e2e-gate-passed` with a `NOT_NEEDED` reason. The sentinel check passes. Note the exemption in the commit body: "E2E gate not needed — e2e-test-engineer assessed no UI surface (turn N)."
|
|
424
|
+
|
|
425
|
+
**Plan ↔ test-scope AC consistency check (devaudit-installer#226 drift management).** Before running E2E, verify the AC table in `compliance/plans/REQ-XXX/implementation-plan.md` matches `compliance/evidence/REQ-XXX/test-scope.md`. Compare the AC IDs in both files — if they diverge (new AC added to plan but not re-extracted, or AC removed from plan but still in test-scope), **HALT**: "test-scope.md is out of sync with implementation-plan.md. AC IDs differ: <diff>. Re-extract test-scope.md and test-plan.md from the updated plan (Phase 1 step 5b) before running E2E."
|
|
426
|
+
|
|
404
427
|
6. **On gate failure**, iterate up to N=3 attempts. Each iteration: read the failure output, propose a fix, apply, re-run. On exhausted attempts, halt with the full failure output and explicit resume instructions: "Gate <name> failed after N=3 attempts. Last failure: <output>. Operator action — fix the failure, commit to the feature branch, push, then ping `resume REQ-XXX`. The skill will re-run the gate from where it left off." Update the sticky with the same. Never use `--no-verify`, `eslint-disable`, `@ts-expect-error`, `xfail`, or any other bypass.
|
|
405
428
|
7. **Commit** using Conventional Commits with `Ref: REQ-XXX` trailer and `Co-Authored-By: Claude` trailer. One commit per logical step; never amend a commit that's already been pushed.
|
|
406
429
|
8. **Land the work on `$INTEGRATION_BRANCH`.** Push the feature branch, then open a PR `feat/REQ-XXX-<slug> → $INTEGRATION_BRANCH` and merge it once CI is green. This is the **integration hop** — there is no UAT four-eyes gate here (that's the release PR in Phase 4); for MEDIUM+ risk get a peer review on this PR per the project's norms. The push to `$INTEGRATION_BRANCH` is what triggers `ci.yml` to register the release and upload gate evidence. **Merge conflict resolution:** if the PR has merge conflicts (another feature branch merged first), pull the latest `$INTEGRATION_BRANCH` into the feature branch (`git merge "$INTEGRATION_BRANCH" --no-edit`), resolve conflicts (preferring the feature branch's changes for files this REQ touches), push, wait for CI. If conflicts are in files this REQ doesn't touch, halt — "Merge conflict in <files> from another feature. Operator action — review the conflict, these files are outside REQ-XXX's scope."
|
|
@@ -462,6 +485,9 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
462
485
|
|
|
463
486
|
```
|
|
464
487
|
compliance/evidence/REQ-XXX/
|
|
488
|
+
├── test-scope.md ← extracted in Phase 1 step 5b
|
|
489
|
+
├── test-plan.md ← extracted in Phase 1 step 5b
|
|
490
|
+
├── implementation-plan.md ← copied from compliance/plans/ in step 6b
|
|
465
491
|
├── srs-alignment.md ← produced in step 1 by requirements-aligner
|
|
466
492
|
├── architecture-decision.md ← produced in step 2 by adr-author
|
|
467
493
|
├── risk-assessment.md ← produced in step 3 by risk-register-keeper
|
|
@@ -474,6 +500,14 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
474
500
|
|
|
475
501
|
Copy Playwright's `test-results/` folder verbatim into `YYYY-MM-DD_traces/` so trace-by-test-name is available for audit without walking the HTML report's hash-name index. For HIGH/CRITICAL releases the traces are part of the audit trail — _"what state was the page in when test X failed and was overridden?"_ answers in one `ls` instead of an HTML-report walk.
|
|
476
502
|
|
|
503
|
+
6b. **Copy `implementation-plan.md` from `compliance/plans/` to `compliance/evidence/` (devaudit-installer#226).** The CI validator (`validate-compliance-artifacts.sh`) expects `implementation-plan.md` in `compliance/evidence/REQ-XXX/`, not in `compliance/plans/REQ-XXX/`. Copy (not move) the file so the plan directory retains the original:
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
cp compliance/plans/REQ-XXX/implementation-plan.md compliance/evidence/REQ-XXX/implementation-plan.md
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
This ensures the pre-push hook's compliance validator check passes. The plan directory retains the original for in-flight reference; the evidence directory has the copy for CI validation and audit.
|
|
510
|
+
|
|
477
511
|
6. **Upload each artefact to the portal** — retry each upload up to 3 times with backoff (5s, 15s, 45s). If an upload still fails after 3 retries, mark it in the RTM as `UPLOAD_FAILED` and surface a warning. Do not mark the RTM as verified for failed uploads. On `resume REQ-XXX`, re-attempt failed uploads before proceeding to Phase 4.
|
|
478
512
|
```bash
|
|
479
513
|
devaudit push <project-slug> REQ-XXX <evidence-type> <file> \
|
|
@@ -528,6 +562,12 @@ Reached only on the **tracked** route from Phase 0 (the issue is already fetched
|
|
|
528
562
|
|
|
529
563
|
Invoked separately by the user after UAT activity on the portal. Trigger: "resume REQ-XXX", "REQ-XXX UAT done", or just re-firing the skill on the same issue.
|
|
530
564
|
|
|
565
|
+
0. **Re-read state (devaudit-installer#226).** On resume, reconstruct state from the filesystem before acting:
|
|
566
|
+
- Re-read `compliance/RTM.md` to check the REQ-XXX row's current status.
|
|
567
|
+
- Check whether `compliance/pending-releases/RELEASE-TICKET-REQ-XXX.md` still exists (not yet moved to `approved-releases/`).
|
|
568
|
+
- Check `git log` for the merge commit on `$RELEASE_BRANCH`.
|
|
569
|
+
- If resuming after an environment detour (not a UAT approval), re-read `compliance/evidence/REQ-XXX/` to see which artefacts already exist and resume at the appropriate phase.
|
|
570
|
+
|
|
531
571
|
1. **Read portal state.** `curl` `https://devaudit.metasession.co/api/projects/<slug>/releases/<version>` and inspect the approval status. Retry up to 3 times with exponential backoff (5s, 15s, 45s) on 5xx responses. If all retries fail, halt — "Portal unreachable at <URL>. Cannot determine UAT approval state. Operator action — verify portal availability + API key, then ping `resume REQ-XXX`." If the API returns 401/403, halt — "Portal API key rejected (HTTP 401/403). The `DEVAUDIT_API_KEY` secret may be expired or revoked. Operator action — rotate the API key, then ping `resume REQ-XXX`." Never guess the portal state.
|
|
532
572
|
|
|
533
573
|
2. **Branch on state:**
|
|
@@ -541,14 +581,23 @@ Invoked separately by the user after UAT activity on the portal. Trigger: "resum
|
|
|
541
581
|
- If `released` (Option B): PATCH directly to `released` — `PATCH /releases/<version>` with `{"status": "released"}`.
|
|
542
582
|
- If `prod_review` (Option A, default): after `post-deploy-prod.yml` completes, the release is at `prod_review`. Update the sticky to "Phase 5 — production deployed; awaiting prod approval on portal" and halt. The operator clicks "Approve Production" (`prod_review` → `prod_approved`) then "Mark as Released" (`prod_approved` → `released`) in the portal. On next `resume REQ-XXX`, the skill reads the portal state — if `released`, finalise (close issue, update sticky to terminal). If `prod_approved`, prompt the operator to click "Mark as Released". If still `prod_review`, report "awaiting production approval" and stop.
|
|
543
583
|
- Comment on the issue: "Released. Production smoke evidence: <link>." (only after release status is `released`)
|
|
544
|
-
- **
|
|
584
|
+
- **Phase 5 close-out — mandatory post-merge compliance steps (devaudit-installer#226).** After the release is marked `released` on the portal, perform the close-out:
|
|
585
|
+
1. **Update RTM status** — change the REQ-XXX row from `TESTED - PENDING SIGN-OFF` to `APPROVED - DEPLOYED` in `compliance/RTM.md`.
|
|
586
|
+
2. **Move release ticket** — move `compliance/pending-releases/RELEASE-TICKET-REQ-XXX.md` to `compliance/approved-releases/`. This prevents CI's `upload-evidence` job from treating the REQ as in-scope for subsequent releases.
|
|
587
|
+
3. **Verify portal approval** — confirm the DevAudit portal release record is in `released` status.
|
|
588
|
+
4. **Commit the close-out** — `git add compliance/RTM.md compliance/pending-releases/ compliance/approved-releases/ && git commit -m "compliance: [REQ-XXX] close out release — RTM updated to APPROVED - DEPLOYED, ticket moved to approved-releases/"`.
|
|
589
|
+
5. **Push the close-out commit** to `$INTEGRATION_BRANCH`.
|
|
590
|
+
|
|
591
|
+
These steps are mandatory — the native agent must not treat "PR merged" or "release marked Released" as completion without performing the close-out. Without moving the release ticket to `approved-releases/`, CI continues uploading evidence for the REQ on every subsequent release, polluting the portal's audit trail.
|
|
592
|
+
- **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; close-out committed (RTM → APPROVED - DEPLOYED, ticket → approved-releases/)" "Done — close issue + retire feature branch (sdlc-implementer halts)"`.
|
|
545
593
|
- Close the issue.
|
|
546
594
|
- 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, testCycleId (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"`.
|
|
547
595
|
|
|
548
596
|
- **Changes requested** → run change-request loop:
|
|
549
597
|
- Fetch change-request comments from the PR (`gh pr view <M> --comments`) and from the portal release page.
|
|
550
|
-
- **Classify the change request (devaudit-installer#210 §6b):** Assess whether the change request is a **defect** (the implementation doesn't match the AC — the reviewer found a bug)
|
|
598
|
+
- **Classify the change request (devaudit-installer#210 §6b, devaudit-installer#212 Gap 6):** Assess whether the change request is a **defect** (the implementation doesn't match the AC — the reviewer found a bug), a **requirements gap** (the reviewer identified behaviour that should have been an AC but wasn't — the plan was incomplete, not the implementation), or a **scope change** (the reviewer wants new behaviour this REQ genuinely shouldn't deliver).
|
|
551
599
|
- **If it's a defect:** Delegate to `e2e-test-engineer` to file the incident with the `incident` label + `### Framework attribution` section before fixing. Invoke `Skill(name: "e2e-test-engineer", args: "Phase 6 triage — UAT reviewer found defect in REQ-XXX. Change-request comment: <summary>. Triage and file application defects with the `incident` label + `### Framework attribution` section per the standard convention.")`. `e2e-test-engineer` returns with a summary of filed incidents. Then fix the defect in the same Phase 2 re-run. This ensures UAT-discovered defects produce `incident_report` evidence, closing `ISO29119.3.5.4` for the defect — not just silently fixing it.
|
|
600
|
+
- **If it's a requirements gap:** Trigger the [requirements gap flow](#requirements-gap-flow-devaudit-installer212) with the reviewer's feedback as the gap report. The operator decides: accept the gap (ship without the edge case), amend the ACs (add the edge case as a new AC, update plan + SRS, re-walk Phase 2-3), or file a follow-up REQ. If "amend" is chosen, the change-request iteration includes the new AC in the delta-plan section, `requirements-aligner` is re-invoked for the new AC, and the SRS is updated. Do NOT file an incident — the plan was incomplete, not the implementation buggy. Do NOT use the scope-expansion halt gate — this is a plan quality issue, not a scope creep request.
|
|
552
601
|
- **If it's a scope change:** Use the existing scope-expansion halt gate (REQ-SKILL-IMPLEMENTER-019) — file a separate issue or amend the REQ scope. Do NOT file an incident — the AC itself needs amendment, not a defect fix.
|
|
553
602
|
- Add a new `## Change-request iteration N` section to `compliance/plans/REQ-XXX/implementation-plan.md` describing what changed and why.
|
|
554
603
|
- **Update the release ticket status** (`compliance/pending-releases/RELEASE-TICKET-REQ-XXX.md`): set `**Status:**` to `CHANGES REQUESTED — ITERATION N` when entering the iteration. Commit the ticket update alongside the delta-plan section in the same iteration commit.
|
|
@@ -569,6 +618,59 @@ Invoked separately by the user after UAT activity on the portal. Trigger: "resum
|
|
|
569
618
|
|
|
570
619
|
- **UAT rejected** → halt. Post on the issue: "UAT rejected this release. Options: (a) close PR and re-plan from scratch, (b) escalate to a different reviewer, (c) appeal the rejection with new context." See [`references/change-request-loop.md`](./references/change-request-loop.md) §"If the change-request is a rejection" for details. Do not attempt to address — the reviewer has marked the release fundamentally broken. Wait for the user to decide.
|
|
571
620
|
|
|
621
|
+
## Native agent responsibilities and re-invocation protocol (devaudit-installer#226)
|
|
622
|
+
|
|
623
|
+
The `skill` tool is a **stateless instruction injection** — not a persistent sub-agent. When invoked, the skill's markdown is loaded into the native agent's context. The native agent executes the steps. But the skill has no persistent state, no execution monitoring, and no re-invoke triggers. The following protocol bridges this gap.
|
|
624
|
+
|
|
625
|
+
### Native agent responsibilities
|
|
626
|
+
|
|
627
|
+
The native agent (the AI coding assistant executing this skill) is responsible for:
|
|
628
|
+
|
|
629
|
+
- **Command execution** — running `npx playwright test`, `npm run dev`, `mongod`, etc.
|
|
630
|
+
- **Environment debugging** — port conflicts, stale locks, missing binaries, Playwright browser installs
|
|
631
|
+
- **Browser inspection** — reading page snapshots, DOM state, error dialogs during E2E debugging
|
|
632
|
+
- **External service interaction** — Railway deploy status, UAT health checks, DevAudit portal (human-only)
|
|
633
|
+
- **Git operations** — merge conflicts, push retries, branch management
|
|
634
|
+
|
|
635
|
+
The skill is responsible for workflow decisions, compliance checklists, and phase transitions. The native agent executes; the skill decides what to do next.
|
|
636
|
+
|
|
637
|
+
### Re-invocation protocol
|
|
638
|
+
|
|
639
|
+
After any **environment detour** — service startup failure, test debugging iteration loop, CI failure fix — the native agent must re-invoke this skill to get back on track:
|
|
640
|
+
|
|
641
|
+
```
|
|
642
|
+
Skill(name: "sdlc-implementer", args: "resume REQ-XXX — <detour description>, re-enter at Phase N")
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
The skill re-reads state from the filesystem and continues from where it left off. It is idempotent on re-entry:
|
|
646
|
+
|
|
647
|
+
- Re-read `compliance/RTM.md` to confirm the REQ-XXX row exists and has a provenance stamp.
|
|
648
|
+
- Re-read `compliance/evidence/REQ-XXX/` to see which artefacts already exist.
|
|
649
|
+
- Check `git log` for commits already made on this branch.
|
|
650
|
+
- Resume at the appropriate phase: if Phase 2 implementation is complete but Phase 3 artefacts are missing, resume at Phase 3 step 1.
|
|
651
|
+
|
|
652
|
+
The native agent must NOT continue to the next phase (Phase 3 → Phase 4, Phase 2 → Phase 3) without re-invoking the skill. The only exception is the skill's own auto-continue steps (Phase 2 step 11) where the skill explicitly says it will continue to the next phase in the same turn.
|
|
653
|
+
|
|
654
|
+
**PR merged to main ≠ done.** After the release PR is merged to `main`, the native agent must re-invoke the skill for Phase 5 close-out (see Phase 5 step 0 below). The merge is not the end of the workflow — post-merge compliance steps are mandatory.
|
|
655
|
+
|
|
656
|
+
### Commit-scoping rule for SRS updates (devaudit-installer#226)
|
|
657
|
+
|
|
658
|
+
When a commit is authored as part of REQ-XXX's SDLC flow, the commit subject must cite `[REQ-XXX]` — the **active REQ** driving the current SDLC flow — regardless of which other REQs the content touches. Other REQs may appear in the body for traceability, but never in the subject.
|
|
659
|
+
|
|
660
|
+
**Correct:**
|
|
661
|
+
```
|
|
662
|
+
docs: [REQ-085] add SRS stubs for REQ-083/084/085 — order status revert, checkout separation, tab payment
|
|
663
|
+
|
|
664
|
+
Ref: REQ-083, REQ-084
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
**Incorrect:**
|
|
668
|
+
```
|
|
669
|
+
docs: [REQ-083/084] update SRS with order status revert fix and checkout separation
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
The portal's commit scanner parses `REQ-XXX` tags from commit subjects within a PR's diff. Citing the wrong REQ in the subject causes the portal to associate out-of-scope REQs with the current release.
|
|
673
|
+
|
|
572
674
|
## Compliance constraints
|
|
573
675
|
|
|
574
676
|
Hard rules — the skill's SKILL.md fails review if any of these are violated. Audited against ISO 29119, ISO 27001, SOC 2, GDPR, and the EU AI Act; details in [`references/compliance-constraints.md`](./references/compliance-constraints.md).
|