@windyroad/itil 0.47.12 → 0.47.14
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-check-outbound-responses-staleness +51 -0
- package/bin/wr-itil-enumerate-postrelease-kv-candidates +51 -0
- package/lib/check-outbound-responses-staleness.sh +93 -0
- package/lib/enumerate-postrelease-kv-candidates.sh +106 -0
- package/package.json +1 -1
- package/scripts/run-check-outbound-responses-staleness.sh +21 -0
- package/scripts/run-enumerate-postrelease-kv-candidates.sh +29 -0
- package/skills/check-upstream-responses/SKILL.md +5 -2
- package/skills/manage-problem/SKILL.md +5 -5
- package/skills/review-problems/SKILL.md +28 -4
- package/skills/review-problems/test/jtbd-301-verdict-shape-contract.bats +225 -0
- package/skills/transition-problem/SKILL.md +1 -1
- package/skills/work-problems/SKILL.md +121 -20
- package/skills/work-problems/test/work-problems-step-0d-outbound-responses-staleness-behavioural.bats +174 -0
- package/skills/work-problems/test/work-problems-step-5-is-error-transient-halt.bats +278 -0
- package/skills/work-problems/test/work-problems-step-5-prompt-body-re-grounding.bats +128 -0
- package/skills/work-problems/test/work-problems-step-6-5-postrelease-kv-callback.bats +209 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# Step 6.5 Post-release K→V auto-transition callback (P228) — behavioural.
|
|
3
|
+
#
|
|
4
|
+
# Driver: ADR-022 prescribes K→V transition on release, but until P228
|
|
5
|
+
# there was no auto-fire surface to back-fill the transition once a fix
|
|
6
|
+
# ships. The post-release callback enumerator
|
|
7
|
+
# (`packages/itil/lib/enumerate-postrelease-kv-candidates.sh`) is the
|
|
8
|
+
# data source: it walks `docs/problems/known-error/*.md`, invokes the
|
|
9
|
+
# derive-release-vehicle helper per ticket, and emits one
|
|
10
|
+
# `KV_CANDIDATE: P<NNN> | <changeset>` line per ticket whose changeset
|
|
11
|
+
# has shipped (derive exit 0).
|
|
12
|
+
#
|
|
13
|
+
# The 2026-06-08 P220 witness — `## Fix Released` populated but K→V
|
|
14
|
+
# deferred citing a misapplied P143 amendment — is the empirical bug
|
|
15
|
+
# this enumerator wires the surface to close.
|
|
16
|
+
#
|
|
17
|
+
# Cases covered (behavioural — exercise the helper, assert observable
|
|
18
|
+
# output; structural ban per ADR-005 / P081):
|
|
19
|
+
# 1. known-error/ dir absent → KV_CANDIDATES_SUMMARY: total=0
|
|
20
|
+
# 2. known-error/ dir empty → KV_CANDIDATES_SUMMARY: total=0
|
|
21
|
+
# 3. ticket present, derive exit 0 → KV_CANDIDATE emitted; total=1
|
|
22
|
+
# 4. ticket present, derive exit 2 → skipped silently; total=0
|
|
23
|
+
# (no `.changeset/<name>.md` ref in body — legacy ticket)
|
|
24
|
+
# 5. ticket present, derive exit 3 → skipped silently; total=0
|
|
25
|
+
# (changeset still in working tree — unreleased)
|
|
26
|
+
# 6. mixed cohort (3 tickets: shipped + legacy + unreleased)
|
|
27
|
+
# → only the shipped one emitted
|
|
28
|
+
# 7. README.md inside known-error/ is excluded from the enumeration
|
|
29
|
+
# 8. unknown derive exit code → stderr warning + skip; total=0
|
|
30
|
+
#
|
|
31
|
+
# Cross-references:
|
|
32
|
+
# @problem P228 (K→V auto-transition gap)
|
|
33
|
+
# @adr ADR-022 (Verifying lifecycle)
|
|
34
|
+
# @adr ADR-018 (release-cadence host of the callback)
|
|
35
|
+
# @adr ADR-005 (behavioural bats per P081)
|
|
36
|
+
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — primary driver)
|
|
37
|
+
|
|
38
|
+
setup() {
|
|
39
|
+
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
|
|
40
|
+
HELPER="$REPO_ROOT/packages/itil/lib/enumerate-postrelease-kv-candidates.sh"
|
|
41
|
+
|
|
42
|
+
FIXTURE="$(mktemp -d)"
|
|
43
|
+
mkdir -p "$FIXTURE/docs/problems"
|
|
44
|
+
|
|
45
|
+
STUB_DIR="$(mktemp -d)"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
teardown() {
|
|
49
|
+
rm -rf "$FIXTURE" "$STUB_DIR"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Helper — write a stub derive-release-vehicle command that returns a
|
|
53
|
+
# canned exit code (per ticket-id-to-exit-code map encoded in $STUB_MAP).
|
|
54
|
+
# $STUB_MAP shape: `<NNN>:<exit>:<changeset>;<NNN>:<exit>:<changeset>;...`
|
|
55
|
+
# The third field is consumed only when exit=0 (emitted in the RELEASE_VEHICLE
|
|
56
|
+
# block the lib greps for changeset path).
|
|
57
|
+
write_stub_derive() {
|
|
58
|
+
local stub="$STUB_DIR/wr-itil-derive-release-vehicle"
|
|
59
|
+
cat > "$stub" <<'STUB'
|
|
60
|
+
#!/usr/bin/env bash
|
|
61
|
+
# Stub derive-release-vehicle for the enumerator behavioural test. Reads
|
|
62
|
+
# $STUB_MAP from the environment, returns canned exit codes per ticket.
|
|
63
|
+
nnn="$1"
|
|
64
|
+
nnn_norm="$(printf '%03d' "$((10#$nnn))")"
|
|
65
|
+
IFS=';' read -ra entries <<< "${STUB_MAP:-}"
|
|
66
|
+
for entry in "${entries[@]}"; do
|
|
67
|
+
[ -z "$entry" ] && continue
|
|
68
|
+
IFS=':' read -r id ex cs <<< "$entry"
|
|
69
|
+
id_norm="$(printf '%03d' "$((10#$id))")"
|
|
70
|
+
if [ "$id_norm" = "$nnn_norm" ]; then
|
|
71
|
+
if [ "$ex" -eq 0 ]; then
|
|
72
|
+
cat <<EOF
|
|
73
|
+
RELEASE_VEHICLE:
|
|
74
|
+
changeset: $cs
|
|
75
|
+
version-packages-commit: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
|
|
76
|
+
pr: #999
|
|
77
|
+
merge-commit: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
|
|
78
|
+
release-date: 2026-06-08
|
|
79
|
+
EOF
|
|
80
|
+
fi
|
|
81
|
+
exit "$ex"
|
|
82
|
+
fi
|
|
83
|
+
done
|
|
84
|
+
# Default: no entry for this ticket → exit 1 (not found)
|
|
85
|
+
exit 1
|
|
86
|
+
STUB
|
|
87
|
+
chmod +x "$stub"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# Helper — write a known-error ticket fixture (body content is opaque to
|
|
91
|
+
# the enumerator; only the filename's leading NNN matters since the
|
|
92
|
+
# derive helper is stubbed).
|
|
93
|
+
write_ke_ticket() {
|
|
94
|
+
local nnn="$1"
|
|
95
|
+
local slug="$2"
|
|
96
|
+
mkdir -p "$FIXTURE/docs/problems/known-error"
|
|
97
|
+
cat > "$FIXTURE/docs/problems/known-error/${nnn}-${slug}.md" <<EOF
|
|
98
|
+
# Problem ${nnn}: ${slug}
|
|
99
|
+
|
|
100
|
+
**Status**: Known Error
|
|
101
|
+
|
|
102
|
+
## Description
|
|
103
|
+
|
|
104
|
+
Test fixture for the enumerator behavioural bats.
|
|
105
|
+
EOF
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# Source the lib once for all tests.
|
|
109
|
+
load_lib() {
|
|
110
|
+
# shellcheck source=/dev/null
|
|
111
|
+
source "$HELPER"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@test "helper file exists and is sourceable" {
|
|
115
|
+
[ -f "$HELPER" ]
|
|
116
|
+
load_lib
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@test "case 1: known-error/ dir absent → total=0" {
|
|
120
|
+
load_lib
|
|
121
|
+
rm -rf "$FIXTURE/docs/problems/known-error"
|
|
122
|
+
run enumerate_postrelease_kv_candidates "$FIXTURE/docs/problems"
|
|
123
|
+
[ "$status" -eq 0 ]
|
|
124
|
+
[[ "$output" == *"KV_CANDIDATES_SUMMARY: total=0"* ]]
|
|
125
|
+
[[ "$output" != *"KV_CANDIDATE:"* ]]
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@test "case 2: known-error/ dir empty → total=0" {
|
|
129
|
+
load_lib
|
|
130
|
+
mkdir -p "$FIXTURE/docs/problems/known-error"
|
|
131
|
+
run enumerate_postrelease_kv_candidates "$FIXTURE/docs/problems"
|
|
132
|
+
[ "$status" -eq 0 ]
|
|
133
|
+
[[ "$output" == *"KV_CANDIDATES_SUMMARY: total=0"* ]]
|
|
134
|
+
[[ "$output" != *"KV_CANDIDATE:"* ]]
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@test "case 3: ticket present + derive exit 0 → KV_CANDIDATE emitted, total=1" {
|
|
138
|
+
load_lib
|
|
139
|
+
write_stub_derive
|
|
140
|
+
write_ke_ticket "228" "adr-022-known-error-to-verifying-transition"
|
|
141
|
+
PATH="$STUB_DIR:$PATH" STUB_MAP="228:0:.changeset/p228-fix.md" \
|
|
142
|
+
run enumerate_postrelease_kv_candidates "$FIXTURE/docs/problems"
|
|
143
|
+
[ "$status" -eq 0 ]
|
|
144
|
+
[[ "$output" == *"KV_CANDIDATE: P228 | .changeset/p228-fix.md"* ]]
|
|
145
|
+
[[ "$output" == *"KV_CANDIDATES_SUMMARY: total=1"* ]]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@test "case 4: ticket present + derive exit 2 (no vehicle ref) → skipped silently, total=0" {
|
|
149
|
+
load_lib
|
|
150
|
+
write_stub_derive
|
|
151
|
+
write_ke_ticket "100" "legacy-pre-p330-no-vehicle"
|
|
152
|
+
PATH="$STUB_DIR:$PATH" STUB_MAP="100:2:" \
|
|
153
|
+
run enumerate_postrelease_kv_candidates "$FIXTURE/docs/problems"
|
|
154
|
+
[ "$status" -eq 0 ]
|
|
155
|
+
[[ "$output" != *"KV_CANDIDATE:"* ]]
|
|
156
|
+
[[ "$output" == *"KV_CANDIDATES_SUMMARY: total=0"* ]]
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@test "case 5: ticket present + derive exit 3 (unreleased) → skipped silently, total=0" {
|
|
160
|
+
load_lib
|
|
161
|
+
write_stub_derive
|
|
162
|
+
write_ke_ticket "200" "changeset-still-in-tree"
|
|
163
|
+
PATH="$STUB_DIR:$PATH" STUB_MAP="200:3:" \
|
|
164
|
+
run enumerate_postrelease_kv_candidates "$FIXTURE/docs/problems"
|
|
165
|
+
[ "$status" -eq 0 ]
|
|
166
|
+
[[ "$output" != *"KV_CANDIDATE:"* ]]
|
|
167
|
+
[[ "$output" == *"KV_CANDIDATES_SUMMARY: total=0"* ]]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@test "case 6: mixed cohort — only the shipped ticket is emitted, total=1" {
|
|
171
|
+
load_lib
|
|
172
|
+
write_stub_derive
|
|
173
|
+
write_ke_ticket "228" "shipped"
|
|
174
|
+
write_ke_ticket "100" "legacy-no-vehicle"
|
|
175
|
+
write_ke_ticket "200" "changeset-in-tree"
|
|
176
|
+
PATH="$STUB_DIR:$PATH" \
|
|
177
|
+
STUB_MAP="228:0:.changeset/p228-fix.md;100:2:;200:3:" \
|
|
178
|
+
run enumerate_postrelease_kv_candidates "$FIXTURE/docs/problems"
|
|
179
|
+
[ "$status" -eq 0 ]
|
|
180
|
+
[[ "$output" == *"KV_CANDIDATE: P228 | .changeset/p228-fix.md"* ]]
|
|
181
|
+
[[ "$output" != *"KV_CANDIDATE: P100"* ]]
|
|
182
|
+
[[ "$output" != *"KV_CANDIDATE: P200"* ]]
|
|
183
|
+
[[ "$output" == *"KV_CANDIDATES_SUMMARY: total=1"* ]]
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@test "case 7: README.md inside known-error/ is excluded from the enumeration" {
|
|
187
|
+
load_lib
|
|
188
|
+
write_stub_derive
|
|
189
|
+
mkdir -p "$FIXTURE/docs/problems/known-error"
|
|
190
|
+
printf '# Known Error Tickets\n' > "$FIXTURE/docs/problems/known-error/README.md"
|
|
191
|
+
PATH="$STUB_DIR:$PATH" STUB_MAP="" \
|
|
192
|
+
run enumerate_postrelease_kv_candidates "$FIXTURE/docs/problems"
|
|
193
|
+
[ "$status" -eq 0 ]
|
|
194
|
+
[[ "$output" != *"KV_CANDIDATE:"* ]]
|
|
195
|
+
[[ "$output" == *"KV_CANDIDATES_SUMMARY: total=0"* ]]
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@test "case 8: unknown derive exit code → stderr warning + skip, total=0" {
|
|
199
|
+
load_lib
|
|
200
|
+
write_stub_derive
|
|
201
|
+
write_ke_ticket "999" "weird-exit"
|
|
202
|
+
PATH="$STUB_DIR:$PATH" STUB_MAP="999:42:" \
|
|
203
|
+
run enumerate_postrelease_kv_candidates "$FIXTURE/docs/problems"
|
|
204
|
+
[ "$status" -eq 0 ]
|
|
205
|
+
[[ "$output" != *"KV_CANDIDATE:"* ]]
|
|
206
|
+
[[ "$output" == *"KV_CANDIDATES_SUMMARY: total=0"* ]]
|
|
207
|
+
# Stderr warning is captured into $output when bats merges stderr; the
|
|
208
|
+
# contract here is "skip silently AND don't lose audit signal".
|
|
209
|
+
}
|