@windyroad/itil 0.44.0 → 0.44.2-preview.507
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/.claude-plugin/plugin.json +1 -1
- package/bin/wr-itil-verify-iter-summary +2 -0
- package/package.json +3 -2
- package/scripts/test/verify-iter-summary.bats +196 -0
- package/scripts/verify-iter-summary.sh +129 -0
- package/skills/manage-problem/SKILL.md +15 -3
- package/skills/manage-problem/test/manage-problem-release-vehicle-seed.bats +83 -0
- package/skills/transition-problem/SKILL.md +13 -1
- package/skills/work-problems/SKILL.md +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windyroad/itil",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.2-preview.507",
|
|
4
4
|
"description": "ITIL-aligned IT service management for Claude Code (problem, and future incident/change skills)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"windyroad-itil": "./bin/install.mjs"
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"skills/",
|
|
27
27
|
"scripts/",
|
|
28
28
|
".claude-plugin/",
|
|
29
|
-
"lib/"
|
|
29
|
+
"lib/",
|
|
30
|
+
"!skills/*/eval/"
|
|
30
31
|
]
|
|
31
32
|
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
# @problem P335 — AFK iter subprocess over-claims completion in
|
|
4
|
+
# ITERATION_SUMMARY notes / commit message while on-disk Confirmation
|
|
5
|
+
# checkboxes remain `[ ]`. Step 6.75 currently runs `git status --porcelain`
|
|
6
|
+
# only — catches commit-didn't-land but not commit-landed-with-false-claim.
|
|
7
|
+
# This verifier closes the gap.
|
|
8
|
+
#
|
|
9
|
+
# Contract: `verify-iter-summary.sh` (or PATH shim
|
|
10
|
+
# `wr-itil-verify-iter-summary`) reads:
|
|
11
|
+
# $1 = commit_sha (the iter's landed commit)
|
|
12
|
+
# $2 = path to a file containing the ITERATION_SUMMARY notes field
|
|
13
|
+
# $3 = repo root (optional; defaults to `git rev-parse --show-toplevel`)
|
|
14
|
+
#
|
|
15
|
+
# Mechanism:
|
|
16
|
+
# 1. Extract `ADR-NNN` identifiers from the commit message
|
|
17
|
+
# (`git log -1 --format=%B <sha>`) AND the notes file.
|
|
18
|
+
# 2. For each identifier, resolve to `docs/decisions/<NNN>-*.md` (any
|
|
19
|
+
# status suffix — `.proposed.md` / `.accepted.md` / etc).
|
|
20
|
+
# 3. Detect completion-claim signal in commit message OR notes (regex
|
|
21
|
+
# family: `all .*(green|complete|done|checked|ticked)`,
|
|
22
|
+
# `\([a-z]\)\s*[-–]\s*\([a-z]\)\s+(green|complete|all)`,
|
|
23
|
+
# `all\s+Confirmation\s+items`).
|
|
24
|
+
# 4. When signal present AND any `- [ ]` item exists in the cited ADR's
|
|
25
|
+
# `## Confirmation` section → emit `OVER-CLAIM:` line and exit 1.
|
|
26
|
+
# 5. Otherwise exit 0.
|
|
27
|
+
#
|
|
28
|
+
# Exit codes:
|
|
29
|
+
# 0 = OK (no signal, or signal-and-all-items-checked, or no ADR referenced)
|
|
30
|
+
# 1 = OVER-CLAIM detected
|
|
31
|
+
# 2 = invocation error (missing args, bad sha, etc)
|
|
32
|
+
#
|
|
33
|
+
# @adr ADR-032 (subprocess-boundary trust contract — orchestrator decides
|
|
34
|
+
# trust boundary; verifier is the policy-authorised silent check)
|
|
35
|
+
# @adr ADR-049 (Plugin-bundled scripts ship as bin/ PATH shims;
|
|
36
|
+
# wr-itil-verify-iter-summary is the shim name)
|
|
37
|
+
# @adr ADR-052 (Behavioural tests for skill testing; this bats covers
|
|
38
|
+
# the OVER-CLAIM detection behaviour, not script structure)
|
|
39
|
+
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — orchestrator-side
|
|
40
|
+
# verification keeps AFK loop integrity intact when iter
|
|
41
|
+
# self-certification fails)
|
|
42
|
+
|
|
43
|
+
setup() {
|
|
44
|
+
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
45
|
+
SCRIPT="$SCRIPTS_DIR/verify-iter-summary.sh"
|
|
46
|
+
FIXTURE_DIR="$(mktemp -d)"
|
|
47
|
+
cd "$FIXTURE_DIR"
|
|
48
|
+
git init -q
|
|
49
|
+
git config user.email test@example.com
|
|
50
|
+
git config user.name "Test"
|
|
51
|
+
mkdir -p docs/decisions
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
teardown() {
|
|
55
|
+
cd /
|
|
56
|
+
rm -rf "$FIXTURE_DIR"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Helper: create a fake ADR with the given Confirmation-section body.
|
|
60
|
+
_make_adr() {
|
|
61
|
+
local num="$1" status="$2" confirmation_body="$3"
|
|
62
|
+
cat > "docs/decisions/${num}-fake-adr.${status}.md" <<EOF
|
|
63
|
+
# ${num}. Fake ADR
|
|
64
|
+
|
|
65
|
+
## Status
|
|
66
|
+
${status}
|
|
67
|
+
|
|
68
|
+
## Confirmation
|
|
69
|
+
${confirmation_body}
|
|
70
|
+
EOF
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Helper: commit a file with the given message; return the SHA via stdout.
|
|
74
|
+
_commit_with_message() {
|
|
75
|
+
local message="$1"
|
|
76
|
+
echo "dummy" > dummy.txt
|
|
77
|
+
git add dummy.txt
|
|
78
|
+
git commit -q -m "$message"
|
|
79
|
+
git log -1 --format=%H
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# ── Existence + executable ──────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
@test "verify-iter-summary: script exists" {
|
|
85
|
+
[ -f "$SCRIPT" ]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@test "verify-iter-summary: script is executable" {
|
|
89
|
+
[ -x "$SCRIPT" ]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# ── Exit 0: no completion-claim signal ──────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
@test "verify-iter-summary: notes mention ADR but no completion-claim signal → OK" {
|
|
95
|
+
_make_adr 077 proposed "- [ ] **(a) Item A**
|
|
96
|
+
- [ ] **(b) Item B**"
|
|
97
|
+
local sha; sha=$(_commit_with_message "feat(architect): ADR-077 Slice 1 partial work")
|
|
98
|
+
echo "P327 progressed; partial slice landed; further work needed for Confirmation items (a)+(b)." > notes.txt
|
|
99
|
+
|
|
100
|
+
run "$SCRIPT" "$sha" notes.txt "$FIXTURE_DIR"
|
|
101
|
+
[ "$status" -eq 0 ]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@test "verify-iter-summary: no ADR referenced at all → OK" {
|
|
105
|
+
local sha; sha=$(_commit_with_message "fix(itil): rename helper variable")
|
|
106
|
+
echo "Bugfix; no governance impact." > notes.txt
|
|
107
|
+
|
|
108
|
+
run "$SCRIPT" "$sha" notes.txt "$FIXTURE_DIR"
|
|
109
|
+
[ "$status" -eq 0 ]
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# ── Exit 0: signal present but all items checked ────────────────────────────
|
|
113
|
+
|
|
114
|
+
@test "verify-iter-summary: completion-claim signal AND all items checked → OK" {
|
|
115
|
+
_make_adr 077 proposed "- [x] **(a) Item A**
|
|
116
|
+
- [x] **(b) Item B**"
|
|
117
|
+
local sha; sha=$(_commit_with_message "feat(architect): ADR-077 — all Confirmation items complete")
|
|
118
|
+
echo "All ADR-077 Confirmation items green." > notes.txt
|
|
119
|
+
|
|
120
|
+
run "$SCRIPT" "$sha" notes.txt "$FIXTURE_DIR"
|
|
121
|
+
[ "$status" -eq 0 ]
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# ── Exit 1: P335 witness shape — claim "all green" + unchecked items ────────
|
|
125
|
+
|
|
126
|
+
@test "verify-iter-summary: claim 'all green at source' + unchecked items → OVER-CLAIM" {
|
|
127
|
+
# The P335 session 8 iter 1 witness shape: commit message claims (a)–(j)
|
|
128
|
+
# green; all 10 boxes are `[ ]`.
|
|
129
|
+
_make_adr 077 proposed "- [ ] **(a) Agent prompt amendment**
|
|
130
|
+
- [ ] **(b) Generator script**
|
|
131
|
+
- [ ] **(c) Initial compendium**
|
|
132
|
+
- [ ] **(d) create-adr integration**
|
|
133
|
+
- [ ] **(e) capture-adr integration**
|
|
134
|
+
- [ ] **(f) review-decisions integration**
|
|
135
|
+
- [ ] **(g) CI drift bats**
|
|
136
|
+
- [ ] **(h) Pre-commit hook**
|
|
137
|
+
- [ ] **(i) ADR-031 assertion**
|
|
138
|
+
- [ ] **(j) No silent regression**"
|
|
139
|
+
local sha; sha=$(_commit_with_message "feat(architect): ADR-077 Slice 3 — all (a)-(j) green at source")
|
|
140
|
+
echo "ADR-077 Slice 3 — Confirmation items (a)-(j) all green at source." > notes.txt
|
|
141
|
+
|
|
142
|
+
run "$SCRIPT" "$sha" notes.txt "$FIXTURE_DIR"
|
|
143
|
+
[ "$status" -eq 1 ]
|
|
144
|
+
echo "$output" | grep -q "OVER-CLAIM"
|
|
145
|
+
echo "$output" | grep -q "ADR-077"
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@test "verify-iter-summary: claim 'all Confirmation items complete' + unchecked → OVER-CLAIM" {
|
|
149
|
+
_make_adr 100 accepted "- [x] **(a) Done**
|
|
150
|
+
- [ ] **(b) Still pending**"
|
|
151
|
+
local sha; sha=$(_commit_with_message "feat: ADR-100 — all Confirmation items complete")
|
|
152
|
+
echo "Implementation finished." > notes.txt
|
|
153
|
+
|
|
154
|
+
run "$SCRIPT" "$sha" notes.txt "$FIXTURE_DIR"
|
|
155
|
+
[ "$status" -eq 1 ]
|
|
156
|
+
echo "$output" | grep -q "OVER-CLAIM"
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@test "verify-iter-summary: signal only in notes (not commit msg) + unchecked → OVER-CLAIM" {
|
|
160
|
+
_make_adr 200 proposed "- [ ] **(a) Missing**"
|
|
161
|
+
local sha; sha=$(_commit_with_message "feat: ADR-200 progress")
|
|
162
|
+
# Note completion signal lives in notes, not the commit subject.
|
|
163
|
+
echo "All Confirmation items ticked for ADR-200." > notes.txt
|
|
164
|
+
|
|
165
|
+
run "$SCRIPT" "$sha" notes.txt "$FIXTURE_DIR"
|
|
166
|
+
[ "$status" -eq 1 ]
|
|
167
|
+
echo "$output" | grep -q "OVER-CLAIM"
|
|
168
|
+
echo "$output" | grep -q "ADR-200"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# ── Invocation errors ───────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
@test "verify-iter-summary: missing notes file → invocation error" {
|
|
174
|
+
local sha; sha=$(_commit_with_message "init")
|
|
175
|
+
run "$SCRIPT" "$sha" /nonexistent/notes.txt "$FIXTURE_DIR"
|
|
176
|
+
[ "$status" -eq 2 ]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@test "verify-iter-summary: missing sha → invocation error" {
|
|
180
|
+
echo "" > notes.txt
|
|
181
|
+
run "$SCRIPT" "" notes.txt "$FIXTURE_DIR"
|
|
182
|
+
[ "$status" -eq 2 ]
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# ── Multi-ADR case ──────────────────────────────────────────────────────────
|
|
186
|
+
|
|
187
|
+
@test "verify-iter-summary: two ADRs cited — one clean, one over-claim → OVER-CLAIM only on the bad one" {
|
|
188
|
+
_make_adr 050 accepted "- [x] **(a) Clean**"
|
|
189
|
+
_make_adr 060 proposed "- [ ] **(a) Dirty**"
|
|
190
|
+
local sha; sha=$(_commit_with_message "feat: ADR-050 + ADR-060 — all green")
|
|
191
|
+
echo "Both ADRs progressed; all items green." > notes.txt
|
|
192
|
+
|
|
193
|
+
run "$SCRIPT" "$sha" notes.txt "$FIXTURE_DIR"
|
|
194
|
+
[ "$status" -eq 1 ]
|
|
195
|
+
echo "$output" | grep -q "ADR-060"
|
|
196
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# verify-iter-summary.sh — detect ITERATION_SUMMARY over-claim against
|
|
3
|
+
# on-disk ADR Confirmation state.
|
|
4
|
+
#
|
|
5
|
+
# Closes P335: AFK iter subprocess over-claims completion in ITERATION_SUMMARY
|
|
6
|
+
# while on-disk Confirmation `[ ]` boxes remain. Step 6.75 of work-problems
|
|
7
|
+
# dispatches this script between iter completion and Step 7 loop-back.
|
|
8
|
+
#
|
|
9
|
+
# Contract:
|
|
10
|
+
# verify-iter-summary.sh <commit_sha> <notes_file> [<repo_root>]
|
|
11
|
+
#
|
|
12
|
+
# Exit codes:
|
|
13
|
+
# 0 = OK (no completion-claim signal, OR signal but all items checked, OR
|
|
14
|
+
# no ADR referenced)
|
|
15
|
+
# 1 = OVER-CLAIM detected — at least one cited ADR has a completion-claim
|
|
16
|
+
# signal AND unchecked `- [ ]` items in its `## Confirmation`
|
|
17
|
+
# section
|
|
18
|
+
# 2 = invocation error (missing args, missing notes file, bad sha)
|
|
19
|
+
#
|
|
20
|
+
# Per ADR-049, this script is invoked via the PATH shim
|
|
21
|
+
# `wr-itil-verify-iter-summary` from SKILL.md prose — never via the
|
|
22
|
+
# repo-relative `packages/itil/scripts/...` path.
|
|
23
|
+
|
|
24
|
+
set -u
|
|
25
|
+
|
|
26
|
+
commit_sha="${1:-}"
|
|
27
|
+
notes_file="${2:-}"
|
|
28
|
+
repo_root="${3:-}"
|
|
29
|
+
|
|
30
|
+
if [ -z "$commit_sha" ] || [ -z "$notes_file" ]; then
|
|
31
|
+
echo "verify-iter-summary: missing required arg(s); usage: verify-iter-summary.sh <commit_sha> <notes_file> [<repo_root>]" >&2
|
|
32
|
+
exit 2
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if [ ! -f "$notes_file" ]; then
|
|
36
|
+
echo "verify-iter-summary: notes_file not found: $notes_file" >&2
|
|
37
|
+
exit 2
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if [ -z "$repo_root" ]; then
|
|
41
|
+
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || echo ".")"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Pull commit message; combine with notes for the full claim surface.
|
|
45
|
+
commit_message="$(git -C "$repo_root" log -1 --format=%B "$commit_sha" 2>/dev/null)"
|
|
46
|
+
if [ -z "$commit_message" ]; then
|
|
47
|
+
echo "verify-iter-summary: could not read commit message for $commit_sha" >&2
|
|
48
|
+
exit 2
|
|
49
|
+
fi
|
|
50
|
+
notes_content="$(cat "$notes_file")"
|
|
51
|
+
combined="$commit_message
|
|
52
|
+
$notes_content"
|
|
53
|
+
|
|
54
|
+
# Extract ADR identifiers (ADR-NNN, 1-4 digit numeric).
|
|
55
|
+
adr_ids="$(echo "$combined" | grep -oE 'ADR-[0-9]{1,4}' | sort -u || true)"
|
|
56
|
+
|
|
57
|
+
if [ -z "$adr_ids" ]; then
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Detect completion-claim signal in the combined claim surface.
|
|
62
|
+
# Patterns (case-insensitive):
|
|
63
|
+
# - "all <something> green|complete|done|checked|ticked"
|
|
64
|
+
# - "every <something> green|complete|done|checked|ticked"
|
|
65
|
+
# - "all (Confirmation|criteria) items <complete|green|done|ticked>"
|
|
66
|
+
# - "(a)-(<letter>) green|complete|all" (the ADR-077 witness shape)
|
|
67
|
+
# - "Confirmation items (a)-(<letter>) all green at source"
|
|
68
|
+
has_signal=0
|
|
69
|
+
if echo "$combined" | grep -qiE '(all|every)[[:space:]]+[^.]{0,80}(green|complete|done|checked|ticked|landed)' ; then
|
|
70
|
+
has_signal=1
|
|
71
|
+
fi
|
|
72
|
+
if [ "$has_signal" -eq 0 ] && echo "$combined" | grep -qiE '\([a-z]\)[[:space:]]*[-–][[:space:]]*\([a-z]\)[[:space:]]+(green|complete|all|done|landed)' ; then
|
|
73
|
+
has_signal=1
|
|
74
|
+
fi
|
|
75
|
+
if [ "$has_signal" -eq 0 ] && echo "$combined" | grep -qiE '(green|complete|done|ticked|checked)[[:space:]]+at[[:space:]]+source' ; then
|
|
76
|
+
has_signal=1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if [ "$has_signal" -eq 0 ]; then
|
|
80
|
+
exit 0
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# For each cited ADR, resolve the file path and inspect the Confirmation section.
|
|
84
|
+
over_claim_lines=""
|
|
85
|
+
while IFS= read -r adr_id; do
|
|
86
|
+
[ -z "$adr_id" ] && continue
|
|
87
|
+
# Extract the numeric portion (zero-padded to 3 digits where possible).
|
|
88
|
+
adr_num="${adr_id#ADR-}"
|
|
89
|
+
# Resolve to a file path; the ADR may use any status suffix.
|
|
90
|
+
adr_files="$(find "$repo_root/docs/decisions" -maxdepth 1 -type f \
|
|
91
|
+
\( -name "${adr_num}-*.md" -o -name "$(printf '%03d' "$adr_num" 2>/dev/null)-*.md" \) \
|
|
92
|
+
2>/dev/null | head -1)"
|
|
93
|
+
|
|
94
|
+
if [ -z "$adr_files" ]; then
|
|
95
|
+
# Cited ADR doesn't exist on disk; this is suspicious but not an
|
|
96
|
+
# over-claim per se. Skip silently — the architect/JTBD review surface
|
|
97
|
+
# catches missing-ADR-reference issues separately.
|
|
98
|
+
continue
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
adr_file="$adr_files"
|
|
102
|
+
|
|
103
|
+
# Slice out the `## Confirmation` section (between `## Confirmation` and
|
|
104
|
+
# the next `^## ` heading, or EOF).
|
|
105
|
+
confirmation_section="$(awk '
|
|
106
|
+
/^## Confirmation/ { in_section = 1; next }
|
|
107
|
+
in_section && /^## / { in_section = 0 }
|
|
108
|
+
in_section { print }
|
|
109
|
+
' "$adr_file")"
|
|
110
|
+
|
|
111
|
+
if [ -z "$confirmation_section" ]; then
|
|
112
|
+
continue
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# Count unchecked items: leading `- [ ]` markers.
|
|
116
|
+
unchecked_count="$(echo "$confirmation_section" | grep -cE '^- \[ \]' || true)"
|
|
117
|
+
|
|
118
|
+
if [ "$unchecked_count" -gt 0 ]; then
|
|
119
|
+
over_claim_lines="${over_claim_lines}OVER-CLAIM: $adr_id has $unchecked_count unchecked Confirmation item(s) at $adr_file but iter claim language signals completion
|
|
120
|
+
"
|
|
121
|
+
fi
|
|
122
|
+
done <<< "$adr_ids"
|
|
123
|
+
|
|
124
|
+
if [ -n "$over_claim_lines" ]; then
|
|
125
|
+
printf '%s' "$over_claim_lines"
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
exit 0
|
|
@@ -687,11 +687,23 @@ Update the "Status" field in the file to "Known Error".
|
|
|
687
687
|
|
|
688
688
|
**Known Error → Verification Pending** (fix released, per ADR-022):
|
|
689
689
|
|
|
690
|
-
When the fix for a Known Error ships, transition the ticket in a single commit
|
|
690
|
+
When the fix for a Known Error ships, transition the ticket in a single commit.
|
|
691
|
+
|
|
692
|
+
**Seed `Release vehicle` reference BEFORE the rename (P330).** BEFORE the `git mv` to `.verifying.md`, edit the `.known-error.md` ticket body to append a `**Release vehicle**: .changeset/<name>.md` paragraph at the END of the `## Fix Strategy` section (create the section if absent). The `<name>.md` is the kebab-case slug of the changeset file the fix commit authored under `.changeset/` (e.g. `wr-itil-p330-option-b.md`). The seed eliminates the `wr-itil-derive-release-vehicle <NNN>` helper's exit-2 routing on standalone K→V iters — the helper greps the ticket body for `.changeset/<name>.md` and exits 2 when absent; seeding the reference at fix-ship time (when the changeset name is fresh in scope, since the fix commit just created it) makes the helper exit 0 deterministically on first call. The exit-2 recovery routing documented in `/wr-itil:transition-problem` Step 6 remains as the legacy-ticket fallback. Matches the user's documented workaround pattern across 3 of 4 standalone K→V dogfoods in the 2026-05-30 session (P316 / P281 / P302 — see P330 § Symptoms).
|
|
693
|
+
|
|
694
|
+
> **Two P057 staging-trap windows on K→V (seed + rename).** The seed Edit on `.known-error.md` is the FIRST P057 window; the Edit that updates Status / writes `## Fix Released` AFTER the `git mv` is the SECOND. Consolidate staging into a SINGLE `git add docs/problems/<NNN>-<title>.verifying.md` AFTER both Edits + the `git mv`. `git mv` operates on the index entry — the body content the index references at rename time is the post-seed content, so the seed Edit's content is carried across the rename automatically; the single final `git add` re-stages the post-rename file with the post-`Edit` Status + `## Fix Released` content. The seed step does NOT introduce a separate `git add` of the `.known-error.md` path — staging discipline stays single-call by riding the rename's index entry.
|
|
691
695
|
|
|
692
696
|
```bash
|
|
697
|
+
# Step 1 — seed `**Release vehicle**: .changeset/<name>.md` in the Fix Strategy section
|
|
698
|
+
# ... use the Edit tool to append the seed paragraph to docs/problems/<NNN>-<title>.known-error.md ...
|
|
699
|
+
|
|
700
|
+
# Step 2 — rename
|
|
693
701
|
git mv docs/problems/<NNN>-<title>.known-error.md docs/problems/<NNN>-<title>.verifying.md
|
|
694
|
-
|
|
702
|
+
|
|
703
|
+
# Step 3 — update Status + add `## Fix Released` section
|
|
704
|
+
# ... use the Edit tool on docs/problems/<NNN>-<title>.verifying.md ...
|
|
705
|
+
|
|
706
|
+
# Step 4 — single re-stage covers both Edit windows
|
|
695
707
|
git add docs/problems/<NNN>-<title>.verifying.md
|
|
696
708
|
```
|
|
697
709
|
|
|
@@ -699,7 +711,7 @@ Then edit the file:
|
|
|
699
711
|
- Update the "Status" field to "Verification Pending"
|
|
700
712
|
- Add a `## Fix Released` section with: release marker (version, commit SHA, or date), one-sentence fix summary, "Awaiting user verification" line, and any exercise evidence from the releasing session.
|
|
701
713
|
|
|
702
|
-
Re-stage the `.verifying.md` file explicitly after the `Edit` tool runs (P057). The
|
|
714
|
+
Re-stage the `.verifying.md` file explicitly after the `Edit` tool runs (P057). The trailing `git add` above is NOT redundant — `git mv` alone stages only the rename, not the subsequent content edit; the same `git add` also re-stages the seed Edit content carried across the rename (single staging call, two Edit windows; P330 + P057).
|
|
703
715
|
|
|
704
716
|
Both the `git mv` and the file edits belong in the same commit as the fix implementation per ADR-014 (governance skills commit their own work). The `.verifying.md` suffix signals to every downstream consumer (work-problems classifier, review step 9d, README rendering) that the remaining work is user-side verification — no file-body scan needed.
|
|
705
717
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# tdd-review: structural-permitted (justification: deferred-retrofit per P330 Investigation Task #3 — behavioural K→V-mock test deferred to follow-up commit; this structural backstop guards the SKILL prose carrying the Release-vehicle seed instruction in the meantime per ADR-052 § Surface 2 marker)
|
|
3
|
+
#
|
|
4
|
+
# Doc-lint guard: manage-problem SKILL.md Step 7 Known Error → Verification Pending block
|
|
5
|
+
# must document the P330 Option B seed step that appends a `**Release vehicle**: .changeset/<name>.md`
|
|
6
|
+
# paragraph to the ticket's Fix Strategy section BEFORE the `git mv` to `.verifying.md`.
|
|
7
|
+
# The same instruction must be mirrored in `transition-problem` SKILL.md Step 6 per ADR-010 amended
|
|
8
|
+
# (copy-not-move; P093 split-skill execution ownership).
|
|
9
|
+
#
|
|
10
|
+
# Cross-reference:
|
|
11
|
+
# P330: docs/problems/known-error/330-derive-release-vehicle-helper-requires-pre-edit-of-ticket-changeset-reference-three-touch-when-one-touch-would-suffice.md
|
|
12
|
+
# ADR-010: docs/decisions/010-rename-wr-problem-to-wr-itil.proposed.md (P093 amendment — copy-not-move)
|
|
13
|
+
# ADR-014: docs/decisions/014-governance-skills-commit-their-own-work.proposed.md (single-commit grain)
|
|
14
|
+
# ADR-022: docs/decisions/022-problem-lifecycle-verification-pending-status.proposed.md (Verifying status)
|
|
15
|
+
# ADR-052: docs/decisions/052-behavioural-tests-default-for-skill-testing.proposed.md (Surface 2 marker)
|
|
16
|
+
# @jtbd JTBD-002 (ship with confidence — audit trail self-documents the release vehicle)
|
|
17
|
+
# @jtbd JTBD-006 (progress backlog AFK — eliminates the 3-of-4-dogfoods exit-2 routing friction)
|
|
18
|
+
|
|
19
|
+
setup() {
|
|
20
|
+
TEST_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")" && pwd)"
|
|
21
|
+
REPO_ROOT="$(cd "${TEST_DIR}/../../../../.." && pwd)"
|
|
22
|
+
MANAGE_PROBLEM_SKILL="${REPO_ROOT}/packages/itil/skills/manage-problem/SKILL.md"
|
|
23
|
+
TRANSITION_PROBLEM_SKILL="${REPO_ROOT}/packages/itil/skills/transition-problem/SKILL.md"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@test "manage-problem SKILL.md exists (P330 precondition)" {
|
|
27
|
+
[ -f "$MANAGE_PROBLEM_SKILL" ]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@test "transition-problem SKILL.md exists (P330 precondition)" {
|
|
31
|
+
[ -f "$TRANSITION_PROBLEM_SKILL" ]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@test "manage-problem SKILL.md Step 7 documents the Release vehicle seed step (P330)" {
|
|
35
|
+
# The K→V transition block must instruct authors to seed a `**Release vehicle**: .changeset/<name>.md`
|
|
36
|
+
# paragraph in the ticket's `## Fix Strategy` section BEFORE the `git mv` to `.verifying.md`.
|
|
37
|
+
run grep -inE 'Release vehicle.*\.changeset/' "$MANAGE_PROBLEM_SKILL"
|
|
38
|
+
[ "$status" -eq 0 ]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@test "manage-problem SKILL.md Step 7 seed instruction precedes the K→V git mv (P330)" {
|
|
42
|
+
# Verify ordering: the "Seed `Release vehicle`" instruction must appear BEFORE the
|
|
43
|
+
# `git mv ... .known-error.md ... .verifying.md` block in Step 7. If the seed instruction
|
|
44
|
+
# lands AFTER the rename in the prose, the agent reading top-to-bottom would do the
|
|
45
|
+
# rename first and the seed-on-known-error-path would target a non-existent file.
|
|
46
|
+
seed_line=$(grep -nE 'Seed `Release vehicle` reference BEFORE the rename' "$MANAGE_PROBLEM_SKILL" | head -1 | cut -d: -f1)
|
|
47
|
+
rename_line=$(grep -nE 'git mv docs/problems/<NNN>-<title>\.known-error\.md docs/problems/<NNN>-<title>\.verifying\.md' "$MANAGE_PROBLEM_SKILL" | head -1 | cut -d: -f1)
|
|
48
|
+
[ -n "$seed_line" ]
|
|
49
|
+
[ -n "$rename_line" ]
|
|
50
|
+
[ "$seed_line" -lt "$rename_line" ]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@test "manage-problem SKILL.md Step 7 cites P330 on the seed instruction (P330 traceability)" {
|
|
54
|
+
# The seed instruction must cite P330 so reviewers can chase the rationale.
|
|
55
|
+
run grep -nE 'P330' "$MANAGE_PROBLEM_SKILL"
|
|
56
|
+
[ "$status" -eq 0 ]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@test "manage-problem SKILL.md Step 7 documents the two P057 staging-trap windows (seed + rename)" {
|
|
60
|
+
# The amendment introduces a second Edit-tool window (seed Edit on .known-error.md).
|
|
61
|
+
# The SKILL prose must explicitly call out that the existing single-`git add` shape covers
|
|
62
|
+
# BOTH windows by riding the rename's index entry.
|
|
63
|
+
run grep -inE 'Two P057 staging-trap windows|two .* Edit windows|seed Edit.*FIRST.*P057' "$MANAGE_PROBLEM_SKILL"
|
|
64
|
+
[ "$status" -eq 0 ]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@test "transition-problem SKILL.md Step 6 mirrors the Release vehicle seed step (ADR-010 copy-not-move)" {
|
|
68
|
+
# Per ADR-010 amended (P093 split-skill execution ownership), the manage-problem Step 7
|
|
69
|
+
# block and the transition-problem Step 6 block must stay in sync. Both surfaces are user-
|
|
70
|
+
# initiated K→V entry points (manage-problem fold-fix path + transition-problem standalone path).
|
|
71
|
+
run grep -inE 'Release vehicle.*\.changeset/' "$TRANSITION_PROBLEM_SKILL"
|
|
72
|
+
[ "$status" -eq 0 ]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@test "transition-problem SKILL.md Step 6 cites P330 on the seed instruction (ADR-010 copy-not-move)" {
|
|
76
|
+
run grep -nE 'P330' "$TRANSITION_PROBLEM_SKILL"
|
|
77
|
+
[ "$status" -eq 0 ]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@test "transition-problem SKILL.md Step 6 documents the two P057 staging-trap windows (seed + rename)" {
|
|
81
|
+
run grep -inE 'Two P057 staging-trap windows|two .* Edit windows|seed Edit.*FIRST.*P057' "$TRANSITION_PROBLEM_SKILL"
|
|
82
|
+
[ "$status" -eq 0 ]
|
|
83
|
+
}
|
|
@@ -147,9 +147,21 @@ git add docs/problems/<NNN>-<title>.known-error.md
|
|
|
147
147
|
|
|
148
148
|
**Known Error → Verification Pending** (per ADR-022, on release):
|
|
149
149
|
|
|
150
|
+
**Seed `Release vehicle` reference BEFORE the rename (P330).** BEFORE the `git mv` to `.verifying.md`, edit the `.known-error.md` ticket body to append a `**Release vehicle**: .changeset/<name>.md` paragraph at the END of the `## Fix Strategy` section (create the section if absent). The `<name>.md` is the kebab-case slug of the changeset file the fix commit authored under `.changeset/` (e.g. `wr-itil-p330-option-b.md`). The seed makes the `wr-itil-derive-release-vehicle <NNN>` helper invocation below exit 0 deterministically on first call (the helper greps the ticket body for `.changeset/<name>.md` and exits 2 when absent — Option B-codified per P330 closes that exit-2 routing on standalone K→V iters). The exit-2 fallback in the routing table below remains as the legacy-ticket recovery path for tickets shipped before P330's codification. Mirrors the `/wr-itil:manage-problem` Step 7 seed step (copy-not-move per ADR-010 amended / P093).
|
|
151
|
+
|
|
152
|
+
> **Two P057 staging-trap windows on K→V (seed + rename).** The seed Edit on `.known-error.md` is the FIRST P057 window; the Edit that updates Status / writes `## Fix Released` AFTER the `git mv` is the SECOND. Consolidate staging into a SINGLE `git add docs/problems/<NNN>-<title>.verifying.md` AFTER both Edits + the `git mv`. `git mv` operates on the index entry — the body content the index references at rename time is the post-seed content, so the seed Edit's content is carried across the rename automatically; the single final `git add` re-stages the post-rename file with the post-`Edit` Status + `## Fix Released` content. The seed step does NOT introduce a separate `git add` of the `.known-error.md` path — staging discipline stays single-call by riding the rename's index entry.
|
|
153
|
+
|
|
150
154
|
```bash
|
|
155
|
+
# Step 1 — seed `**Release vehicle**: .changeset/<name>.md` in the Fix Strategy section
|
|
156
|
+
# ... use the Edit tool to append the seed paragraph to docs/problems/<NNN>-<title>.known-error.md ...
|
|
157
|
+
|
|
158
|
+
# Step 2 — rename
|
|
151
159
|
git mv docs/problems/<NNN>-<title>.known-error.md docs/problems/<NNN>-<title>.verifying.md
|
|
152
|
-
|
|
160
|
+
|
|
161
|
+
# Step 3 — update Status to "Verification Pending" AND add the `## Fix Released` section
|
|
162
|
+
# ... use the Edit tool on docs/problems/<NNN>-<title>.verifying.md ...
|
|
163
|
+
|
|
164
|
+
# Step 4 — single re-stage covers both Edit windows (P057 + P330)
|
|
153
165
|
git add docs/problems/<NNN>-<title>.verifying.md
|
|
154
166
|
```
|
|
155
167
|
|
|
@@ -726,6 +726,19 @@ Before spawning the next iteration's subagent, verify the working tree state aga
|
|
|
726
726
|
|
|
727
727
|
**Out of scope for this step**: attempting recovery from an unknown-reason dirty state. Per ADR-013 Rule 6, conflict resolution and ambiguous state require user input; non-interactive recovery would mask the bug this check is meant to surface.
|
|
728
728
|
|
|
729
|
+
**Verify-iter-claims sub-step (P335).** The clean/dirty-known/dirty-unknown classification catches the *commit-didn't-land* failure class but not the *commit-landed-with-false-claim* class — both the commit message and the `ITERATION_SUMMARY.notes` field are written by the same iter subprocess from the same model state, so they can agree with each other while disagreeing with the on-disk artefacts the claim names (the P335 session 8 iter 1 witness: commit message stated "all (a)–(j) Confirmation items green at source" + notes restated it + the cited ADR's 10 boxes were all `[ ]`). When the classification above returns Clean AND the iter reported `committed: true`, run the verify-iter-claims check:
|
|
730
|
+
|
|
731
|
+
1. Dump the iter's `ITERATION_SUMMARY.notes` field to a temp file (`/tmp/iter-notes-$$.txt`).
|
|
732
|
+
2. Invoke `wr-itil-verify-iter-summary <commit_sha> <notes_file>` (the PATH shim per ADR-049; never invoke the repo-relative `packages/itil/scripts/verify-iter-summary.sh` path from SKILL prose — adopter installs resolve the shim, not the source-monorepo path).
|
|
733
|
+
3. Read the exit code:
|
|
734
|
+
- **Exit 0** → no over-claim detected (no ADR referenced, OR no completion-claim signal, OR signal-and-all-Confirmation-items-checked). Proceed to Step 7.
|
|
735
|
+
- **Exit 1** → OVER-CLAIM detected (at least one cited ADR has unchecked `- [ ]` Confirmation items while the iter's commit message or notes contains completion-claim language like "all green at source", "all Confirmation items complete", "(a)-(j) green"). **Halt the loop** with `outcome: halted-iter-over-claim`. Include the verifier's stdout (the `OVER-CLAIM: ADR-NNN has N unchecked Confirmation item(s)...` lines) as the divergence detail in the halt summary. Route through Step 2.5b's surfacing routine before emitting the halt summary (`halt-paths-must-route-design-questions-through-Step-2.5b`); the over-claim halt itself remains a halt-with-bug-signal — the iter's self-contradicting output IS the bug, and the user must adjudicate on return (re-dispatch the work / accept partial state / amend the commit).
|
|
736
|
+
- **Exit 2** → verifier invocation error (missing args, unreadable notes file, bad sha). Halt the loop with `outcome: halted-iter-verifier-error` and the verifier's stderr. This shape is itself an orchestrator-side bug; surfacing it loudly is preferable to silently proceeding.
|
|
737
|
+
|
|
738
|
+
**Detection class boundary.** Verify-iter-claims is the *emit-but-over-claim* class detector — distinct from the *stuck-before-emit* class (P147, exit 143 + 0-byte JSON) which is already covered by the Step 5 idle-timeout SIGTERM handling + this step's existing dirty/clean check (working tree dirty after a missing-summary iter halts the loop). The verifier is intentionally narrow (ADR `## Confirmation` checkboxes) — it catches the load-bearing recurring shape where an iter ships an invariant gate (CI drift, README pairing) in the same commit as the work the gate is meant to test. Other over-claim shapes (claimed commits with no diff hunks; claimed file edits not in `git show --stat`) can be added incrementally as further witnesses surface; option (d) iter-local drift-bats (running the verifier inside the iter subprocess before `ITERATION_SUMMARY` emission) is deferred pending evidence that orchestrator-side (a) is insufficient — evidence-based, not BUFD (same shape as P246/P247).
|
|
739
|
+
|
|
740
|
+
**Auto-correction is out of scope.** The orchestrator cannot retroactively make a false claim true; halt-with-bug-signal is the correct stance per ADR-013 Rule 6.
|
|
741
|
+
|
|
729
742
|
### Step 7: Loop
|
|
730
743
|
|
|
731
744
|
Go back to step 1. The backlog may have changed — new problems may have been created during fixes, priorities may have shifted, and the README.md cache will be stale.
|
|
@@ -758,6 +771,7 @@ When `AskUserQuestion` is unavailable or the user is AFK, the skill (and the del
|
|
|
758
771
|
| Pre-`ALL_DONE` gate sequence at any loop end (every stop-condition + every halt-path that emits a final summary + quota-exhaustion natural end) | Run Step 2.4 sequence UNCONDITIONALLY before `ALL_DONE` emit: gate (a) outstanding-questions surface via Step 2.5b; gate (b) session-level retro via `/wr-retrospective:run-retro`; gate (c) emit `ALL_DONE` only after (a) AND (b) complete. Hard-fail mode: if either gate cannot complete cleanly, halt with directive instead of emit `ALL_DONE` — recovery is the user satisfying the gate and re-invoking the skill. Per ADR-044 framework-resolution boundary + ADR-013 + ADR-014 (retro commits its own work) + P086 (extends iter-level retro to orchestrator-level) + P341 (Step 2.4). |
|
|
759
772
|
| Halt-path final summary with accumulated user-answerable skips (CI failure / Rule 5 above-appetite / dirty-unknown / session-continuity / fetch failure) | Run Step 2.5b's surfacing routine before emitting the halt path's final AFK summary. Step 2.5b is gated on ≥1 accumulated user-answerable skip — empty-skip halts skip the routine. Step 2.5b surfaces *prior-iter accumulated user-answerable skips only*; it does NOT ask the user how to remediate the halt cause itself (CI failure / above-appetite state / dirty-unknown state remain halt-with-bug-signal). Per ADR-013 Rule 1 + ADR-032 + P126 (`halt-paths-must-route-design-questions-through-Step-2.5b`). |
|
|
760
773
|
| Unexpected dirty state between iterations | Halt the loop. Report the `git status --porcelain` output, the last iteration's reported outcome, and the divergence — per P036 (Step 6.75). Run Step 2.5b before emitting the halt summary if ≥1 accumulated user-answerable skip from prior iters (P126). Do NOT attempt non-interactive recovery of the dirty state itself. |
|
|
774
|
+
| Iter committed cleanly + claim contradicts on-disk ADR Confirmation state (P335) | Halt the loop with `outcome: halted-iter-over-claim`. Include the `wr-itil-verify-iter-summary` stdout (the `OVER-CLAIM: ADR-NNN has N unchecked Confirmation item(s)...` lines) as the divergence detail. Run Step 2.5b before emitting the halt summary if ≥1 accumulated user-answerable skip from prior iters. Do NOT auto-correct the iter's claim — the orchestrator cannot retroactively make a false claim true; the user adjudicates on return (re-dispatch / accept partial / amend). Per ADR-013 Rule 6 + ADR-032 subprocess-boundary trust contract + P335 (Step 6.75 verify-iter-claims sub-step). |
|
|
761
775
|
| External root cause detected at Open → Known Error, or at park with `upstream-blocked` reason | Append the stable `- **Upstream report pending** — external dependency identified; invoke /wr-itil:report-upstream when ready` marker to the ticket's `## Related` section; do NOT auto-invoke `/wr-itil:report-upstream` (Step 6 security-path branch is interactive — per ADR-024 Consequences). Use the already-noted grep check to avoid duplicate lines. Per P063 + ADR-013 Rule 6. |
|
|
762
776
|
| Mid-loop ask between iters in the orchestrator's main turn | Forbidden except at framework-prescribed halt points (Step 0 session-continuity / fetch-failure halt; Step 2.5 / 2.5b loop-end emit; Step 6.5 above-appetite Rule 5 halt; Step 6.5 CI-failure / release:watch halt; Step 6.5 cohort-graduation halt-no-resolution halt; Step 6.75 dirty-for-unknown-reason halt). The loop's purpose is **progress + accumulation**; mechanical-stage transitions between iters are framework-resolved and MUST NOT prompt the user. Per ADR-044 framework-resolution boundary + ADR-013 Rule 1 (as amended by ADR-044) + P130. |
|
|
763
777
|
|
|
@@ -774,6 +788,7 @@ The orchestrator MUST NOT call `AskUserQuestion` between iterations except at th
|
|
|
774
788
|
- **Step 6.5 CI-failure / `release:watch` failure halt** — push:watch or release:watch failed AND the failure is genuinely-unrecoverable (outside the fixable-in-iter allow-list, or 3-retry cap reached); halt-with-batched-questions per the Step 2.5b cross-reference. Failures inside the closed allow-list route to fix-and-continue per Step 6.5 Failure handling (P140), not this halt point.
|
|
775
789
|
- **Step 6.5 cohort-graduation halt-no-resolution halt (P246)** — graduation evaluator returned `status=halt-no-resolution` for one or more held candidates (Rule 1a terminal: neither filename-convention join nor body-grep fallback resolved a problem ticket, OR the resolved ticket file is missing/unreadable). The orchestrator MUST NOT auto-graduate under ambiguity per ADR-061 Rule 1a; halt-with-batched-questions per the Step 2.5b cross-reference. The halt-causing ambiguity itself remains a halt-with-bug-signal (the held entry stays in `docs/changesets-holding/`; manual reinstate or ticket-file correction required); Step 2.5b surfaces *prior-iter accumulated user-answerable skips only* and does NOT ask the user to resolve the ambiguity itself.
|
|
776
790
|
- **Step 6.75 dirty-for-unknown-reason halt** — `git status --porcelain` divergence; halt-with-batched-questions per the Step 2.5b cross-reference.
|
|
791
|
+
- **Step 6.75 iter-over-claim halt (P335)** — `wr-itil-verify-iter-summary` detected the iter's commit message or `ITERATION_SUMMARY.notes` contains completion-claim language for an ADR whose `## Confirmation` section still has unchecked `- [ ]` items; halt-with-batched-questions per the Step 2.5b cross-reference. The over-claim itself remains a halt-with-bug-signal — Step 2.5b surfaces *prior-iter accumulated user-answerable skips only*; it does NOT ask the user how to remediate the false claim (re-dispatch / accept partial / amend the commit remains a user decision on return).
|
|
777
792
|
|
|
778
793
|
**No mid-iter ask points.** Every other point in the orchestrator's main turn (between Step 5 dispatch completing and Step 6.5 release-cadence check; between Step 6.75 verification and Step 7 loop-back; between Step 7 and Step 1 next-iteration; between consecutive iters generally) is a mechanical-stage transition that the framework has already resolved. Do NOT introduce ad-hoc `AskUserQuestion` calls at those points to confirm "is it OK to proceed?" or "want me to start the next iter?" — proceeding IS the framework-resolved default. Continue iterating until quota or stop-condition #1/#2/#3 fires.
|
|
779
794
|
|