@windyroad/itil 0.26.0 → 0.27.0
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/package.json +1 -1
- package/scripts/migrate-problems-add-type.sh +116 -0
- package/scripts/reconcile-readme.sh +30 -3
- package/scripts/test/dual-tolerant-glob-rfc-002-t2.bats +309 -0
- package/scripts/test/i2-no-type-branching.bats +320 -0
- package/scripts/test/migrate-problems-add-type.bats +280 -0
- package/scripts/test/reconcile-readme.bats +353 -0
- package/scripts/test/skill-md-dual-tolerant-coverage-rfc-002-t3.bats +374 -0
- package/skills/capture-problem/SKILL.md +53 -12
- package/skills/capture-rfc/SKILL.md +6 -3
- package/skills/close-incident/SKILL.md +2 -2
- package/skills/link-incident/SKILL.md +4 -2
- package/skills/list-problems/SKILL.md +15 -11
- package/skills/manage-problem/SKILL.md +25 -13
- package/skills/manage-rfc/SKILL.md +4 -1
- package/skills/report-upstream/SKILL.md +3 -1
- package/skills/review-problems/SKILL.md +8 -7
- package/skills/transition-problem/SKILL.md +3 -3
- package/skills/transition-problems/SKILL.md +2 -2
- package/skills/work-problem/SKILL.md +6 -1
- package/skills/work-problems/SKILL.md +1 -1
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
# @rfc RFC-002 T3 — Bats fixture audit + dual-tolerant assertions
|
|
4
|
+
# @adr ADR-031 (Problem-ticket directory layout — per-state subdirs)
|
|
5
|
+
# @adr ADR-051 (load-bearing-from-the-start — each SKILL-prescribed
|
|
6
|
+
# enumeration pipeline ships with a behavioural enforcement test
|
|
7
|
+
# exercised against per-state-layout synthetic fixtures, not later
|
|
8
|
+
# by graceful drift discovery during the T5 migration cutover)
|
|
9
|
+
# @adr ADR-052 (behavioural-bats default — these tests run the actual
|
|
10
|
+
# shell pipelines the SKILL.md sites prescribe against synthetic
|
|
11
|
+
# fixtures and assert observable enumeration. They do NOT structurally
|
|
12
|
+
# grep SKILL.md prose for the dual-pattern string, which would be
|
|
13
|
+
# P081-class structural-test-disguised-as-behavioural and was
|
|
14
|
+
# explicitly excluded from T2 per architect finding 3)
|
|
15
|
+
# @adr ADR-014 (single-purpose: one mechanical contract — the
|
|
16
|
+
# SKILL-prescribed pipelines compose with per-state-layout fixtures)
|
|
17
|
+
# @adr ADR-060 (Phase 1 Slice 5 forward-dogfood — T3 commit grain)
|
|
18
|
+
# @problem P069 (driving — flat layout unskimmable; the migration this
|
|
19
|
+
# contract guards is the relief)
|
|
20
|
+
# @problem P081 (no structural-grep on SKILL.md content — this test
|
|
21
|
+
# is the behavioural alternative)
|
|
22
|
+
# @jtbd JTBD-001 (extended scope — multi-commit RFC-grain coordinated
|
|
23
|
+
# change governance; T3 is one of 11 RFC-002 sub-tasks; behavioural
|
|
24
|
+
# coverage is how per-edit governance stays trustworthy across the
|
|
25
|
+
# migration window)
|
|
26
|
+
# @jtbd JTBD-006 (work-backlog-AFK — dual-tolerant pipelines preserve
|
|
27
|
+
# AFK-loop continuity during the T2-to-T6 migration window; without
|
|
28
|
+
# this contract, mid-migration AFK iterations silently miss tickets
|
|
29
|
+
# in the un-migrated layout half)
|
|
30
|
+
# @jtbd JTBD-008 (decompose-fix-into-coordinated-changes — RFC-002 T3
|
|
31
|
+
# is the load-bearing test artefact for the coordinated-change
|
|
32
|
+
# sub-workstream; visible as an RFC-002-T3 entity rather than
|
|
33
|
+
# diffusing across 14 existing files per JTBD review)
|
|
34
|
+
# @jtbd JTBD-101 (extend-the-suite — adopter projects consuming
|
|
35
|
+
# @windyroad/itil at the T2-shipped state must enumerate correctly
|
|
36
|
+
# against their flat-layout tickets AND post-auto-migration per-state
|
|
37
|
+
# tickets; T3 proves both halves)
|
|
38
|
+
#
|
|
39
|
+
# Contract: every SKILL.md call site updated in T2 (commit `0795e91`,
|
|
40
|
+
# 14 SKILL.md surfaces) prescribes a shell pipeline of canonical shape:
|
|
41
|
+
#
|
|
42
|
+
# ls docs/problems/*.<state>.md docs/problems/<state>/*.md 2>/dev/null
|
|
43
|
+
# ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null
|
|
44
|
+
# ls docs/problems/<ID>-*.md docs/problems/*/<ID>-*.md 2>/dev/null
|
|
45
|
+
#
|
|
46
|
+
# T2's `dual-tolerant-glob-rfc-002-t2.bats` exercises the canonical
|
|
47
|
+
# pattern shapes generically. T3 extends that coverage to the
|
|
48
|
+
# end-to-end SKILL-prescribed PIPELINES — the next-ID compute pipeline
|
|
49
|
+
# (`ls X Y | sed | grep -oE | sort -n | tail -1`), the multi-state
|
|
50
|
+
# union form (4-pathspec for open + known-error backlog scan), the
|
|
51
|
+
# verifying-state filter as run-retro Step 4a dispatches it, and the
|
|
52
|
+
# brace-expansion ID + state-set form report-upstream uses. Each test
|
|
53
|
+
# runs the pipeline against three synthetic fixture shapes (flat-only,
|
|
54
|
+
# per-state-only, mixed) and asserts observable enumeration.
|
|
55
|
+
#
|
|
56
|
+
# T6 (post-T5 verification) drops the flat-layout half. This test
|
|
57
|
+
# updates at T6 to single-pattern (per-state only), NOT removed — the
|
|
58
|
+
# contract narrows but the behavioural enforcement remains.
|
|
59
|
+
#
|
|
60
|
+
# CONTRACT NOTE: when one half of the dual-pattern has zero matches
|
|
61
|
+
# in the current fixture (single-layout fixtures), `ls X Y 2>/dev/null`
|
|
62
|
+
# exits nonzero — the unmatched literal pathname propagates to ls's
|
|
63
|
+
# argv and `2>/dev/null` only suppresses the stderr noise, not the
|
|
64
|
+
# exit code. SKILL.md call sites MUST treat STDOUT emptiness as the
|
|
65
|
+
# canonical "no tickets" signal, NOT exit code zero. Test assertions
|
|
66
|
+
# probe stdout content via `run` (which absorbs the exit code into
|
|
67
|
+
# `$status`); `$status` is asserted only in the empty-fixture and
|
|
68
|
+
# missing-ID cases where nonzero exit is the intended contract.
|
|
69
|
+
|
|
70
|
+
setup() {
|
|
71
|
+
REPO_ROOT="$(mktemp -d)"
|
|
72
|
+
cd "$REPO_ROOT"
|
|
73
|
+
mkdir -p docs/problems
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
teardown() {
|
|
77
|
+
cd /
|
|
78
|
+
rm -rf "$REPO_ROOT"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# ── fixture builders ─────────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
build_flat_layout() {
|
|
84
|
+
cat > docs/problems/100-foo.open.md <<'EOF'
|
|
85
|
+
# Problem 100: Foo
|
|
86
|
+
**Status**: Open
|
|
87
|
+
**WSJF**: 5.0
|
|
88
|
+
EOF
|
|
89
|
+
cat > docs/problems/101-bar.known-error.md <<'EOF'
|
|
90
|
+
# Problem 101: Bar
|
|
91
|
+
**Status**: Known Error
|
|
92
|
+
**WSJF**: 4.0
|
|
93
|
+
EOF
|
|
94
|
+
cat > docs/problems/102-baz.verifying.md <<'EOF'
|
|
95
|
+
# Problem 102: Baz
|
|
96
|
+
**Status**: Verification Pending
|
|
97
|
+
EOF
|
|
98
|
+
cat > docs/problems/103-qux.parked.md <<'EOF'
|
|
99
|
+
# Problem 103: Qux
|
|
100
|
+
**Status**: Parked
|
|
101
|
+
EOF
|
|
102
|
+
cat > docs/problems/104-quux.closed.md <<'EOF'
|
|
103
|
+
# Problem 104: Quux
|
|
104
|
+
**Status**: Closed
|
|
105
|
+
EOF
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
build_per_state_layout() {
|
|
109
|
+
mkdir -p docs/problems/open docs/problems/known-error docs/problems/verifying docs/problems/parked docs/problems/closed
|
|
110
|
+
cat > docs/problems/open/200-foo2.md <<'EOF'
|
|
111
|
+
# Problem 200: Foo2
|
|
112
|
+
**Status**: Open
|
|
113
|
+
**WSJF**: 6.0
|
|
114
|
+
EOF
|
|
115
|
+
cat > docs/problems/known-error/201-bar2.md <<'EOF'
|
|
116
|
+
# Problem 201: Bar2
|
|
117
|
+
**Status**: Known Error
|
|
118
|
+
**WSJF**: 3.5
|
|
119
|
+
EOF
|
|
120
|
+
cat > docs/problems/verifying/202-baz2.md <<'EOF'
|
|
121
|
+
# Problem 202: Baz2
|
|
122
|
+
**Status**: Verification Pending
|
|
123
|
+
EOF
|
|
124
|
+
cat > docs/problems/parked/203-qux2.md <<'EOF'
|
|
125
|
+
# Problem 203: Qux2
|
|
126
|
+
**Status**: Parked
|
|
127
|
+
EOF
|
|
128
|
+
cat > docs/problems/closed/204-quux2.md <<'EOF'
|
|
129
|
+
# Problem 204: Quux2
|
|
130
|
+
**Status**: Closed
|
|
131
|
+
EOF
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
build_mixed_layout() {
|
|
135
|
+
build_flat_layout
|
|
136
|
+
build_per_state_layout
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# ── Pipeline 1: Next-ID compute (manage-problem Step 3 + capture-problem Step 3)
|
|
140
|
+
#
|
|
141
|
+
# SKILL.md prescribes the recursive local_max formula:
|
|
142
|
+
# ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null \
|
|
143
|
+
# | sed 's|.*/||' \
|
|
144
|
+
# | grep -oE '^[0-9]+' \
|
|
145
|
+
# | sort -n | tail -1
|
|
146
|
+
#
|
|
147
|
+
# Architect finding 2 (T2): the recursive enumeration MUST contribute
|
|
148
|
+
# tickets from BOTH layouts to max-ID, otherwise a per-state ticket at
|
|
149
|
+
# ID 204 is invisible to a flat-only-enumerating capture-problem and
|
|
150
|
+
# the next ID re-allocates an already-taken slot. T3 exercises the
|
|
151
|
+
# pipeline against per-state-only AND mixed fixtures to prove the
|
|
152
|
+
# dual-pathspec composes with the downstream sed/grep/sort pipeline.
|
|
153
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
@test "next-ID pipeline: flat-only fixture yields max ID 104" {
|
|
156
|
+
build_flat_layout
|
|
157
|
+
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
158
|
+
[ "$output" = "104" ]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@test "next-ID pipeline: per-state-only fixture yields max ID 204" {
|
|
162
|
+
build_per_state_layout
|
|
163
|
+
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
164
|
+
[ "$output" = "204" ]
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@test "next-ID pipeline: mixed fixture yields max ID 204 (recursive enumeration spans both layouts)" {
|
|
168
|
+
# Architect finding 2: a per-state ticket at ID 204 MUST contribute
|
|
169
|
+
# to max-ID even when flat-layout 104 also exists. Drop the per-state
|
|
170
|
+
# half of the dual-pathspec and this test fails — capture-problem
|
|
171
|
+
# would re-allocate ID 105 instead of advancing to 205.
|
|
172
|
+
build_mixed_layout
|
|
173
|
+
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
174
|
+
[ "$output" = "204" ]
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@test "next-ID pipeline: empty fixture yields empty result" {
|
|
178
|
+
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
179
|
+
[ -z "$output" ]
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# ── Pipeline 2: Open + known-error multi-state union
|
|
183
|
+
# (work-problems Step 1, list-problems live scan)
|
|
184
|
+
#
|
|
185
|
+
# SKILL.md prescribes the 4-pathspec form:
|
|
186
|
+
# ls docs/problems/*.open.md docs/problems/*.known-error.md \
|
|
187
|
+
# docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null
|
|
188
|
+
#
|
|
189
|
+
# This is wider than T2's single-state filter — it unions two states
|
|
190
|
+
# across two layouts in one ls invocation. The prove-out shape: the
|
|
191
|
+
# union enumerates open + known-error from BOTH layouts and excludes
|
|
192
|
+
# verifying / parked / closed from BOTH layouts.
|
|
193
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
@test "open+known-error union: per-state-only fixture enumerates 200 and 201" {
|
|
196
|
+
build_per_state_layout
|
|
197
|
+
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
198
|
+
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
199
|
+
[[ "$output" == *"known-error/201-bar2.md"* ]]
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@test "open+known-error union: per-state-only fixture excludes verifying/parked/closed" {
|
|
203
|
+
build_per_state_layout
|
|
204
|
+
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
205
|
+
[[ "$output" != *"202-baz2"* ]]
|
|
206
|
+
[[ "$output" != *"203-qux2"* ]]
|
|
207
|
+
[[ "$output" != *"204-quux2"* ]]
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@test "open+known-error union: mixed fixture enumerates all four (100, 101, 200, 201)" {
|
|
211
|
+
build_mixed_layout
|
|
212
|
+
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
213
|
+
[[ "$output" == *"100-foo.open.md"* ]]
|
|
214
|
+
[[ "$output" == *"101-bar.known-error.md"* ]]
|
|
215
|
+
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
216
|
+
[[ "$output" == *"known-error/201-bar2.md"* ]]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@test "open+known-error union: mixed fixture excludes verifying/parked/closed from BOTH layouts" {
|
|
220
|
+
build_mixed_layout
|
|
221
|
+
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
222
|
+
[[ "$output" != *"102-baz"* ]]
|
|
223
|
+
[[ "$output" != *"103-qux"* ]]
|
|
224
|
+
[[ "$output" != *"104-quux"* ]]
|
|
225
|
+
[[ "$output" != *"202-baz2"* ]]
|
|
226
|
+
[[ "$output" != *"203-qux2"* ]]
|
|
227
|
+
[[ "$output" != *"204-quux2"* ]]
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
# ── Pipeline 3: Verifying-state filter (run-retro Step 4a)
|
|
231
|
+
#
|
|
232
|
+
# SKILL.md prescribes:
|
|
233
|
+
# ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null
|
|
234
|
+
#
|
|
235
|
+
# run-retro Step 4a uses this to surface verification-close candidates
|
|
236
|
+
# from the session-context evidence. T3 proves the pipeline finds the
|
|
237
|
+
# verifying ticket in BOTH layouts independently.
|
|
238
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
@test "verifying-state pipeline: flat-only fixture finds 102" {
|
|
241
|
+
build_flat_layout
|
|
242
|
+
run bash -c 'ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null'
|
|
243
|
+
[[ "$output" == *"102-baz.verifying.md"* ]]
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@test "verifying-state pipeline: per-state-only fixture finds 202" {
|
|
247
|
+
build_per_state_layout
|
|
248
|
+
run bash -c 'ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null'
|
|
249
|
+
[[ "$output" == *"verifying/202-baz2.md"* ]]
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@test "verifying-state pipeline: mixed fixture finds 102 AND 202" {
|
|
253
|
+
build_mixed_layout
|
|
254
|
+
run bash -c 'ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null'
|
|
255
|
+
[[ "$output" == *"102-baz.verifying.md"* ]]
|
|
256
|
+
[[ "$output" == *"verifying/202-baz2.md"* ]]
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
# ── Pipeline 4: ID-anchored ticket lookup
|
|
260
|
+
# (manage-problem ticket-by-ID, link-incident, close-incident,
|
|
261
|
+
# transition-problem Step 2, capture-problem Step 2 dup-detect)
|
|
262
|
+
#
|
|
263
|
+
# SKILL.md prescribes:
|
|
264
|
+
# ls docs/problems/<ID>-*.md docs/problems/*/<ID>-*.md 2>/dev/null
|
|
265
|
+
#
|
|
266
|
+
# T3 exercises lookup of a known-existing ID across both layouts and
|
|
267
|
+
# the missing-ID case (asserts empty stdout + nonzero exit).
|
|
268
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
@test "ID-anchored pipeline: per-state-only fixture finds 200 in subdir" {
|
|
271
|
+
build_per_state_layout
|
|
272
|
+
run bash -c 'ls docs/problems/200-*.md docs/problems/*/200-*.md 2>/dev/null'
|
|
273
|
+
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@test "ID-anchored pipeline: mixed fixture finds 100 (flat) and 200 (per-state)" {
|
|
277
|
+
build_mixed_layout
|
|
278
|
+
run bash -c 'ls docs/problems/100-*.md docs/problems/*/100-*.md 2>/dev/null'
|
|
279
|
+
[[ "$output" == *"100-foo.open.md"* ]]
|
|
280
|
+
run bash -c 'ls docs/problems/200-*.md docs/problems/*/200-*.md 2>/dev/null'
|
|
281
|
+
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@test "ID-anchored pipeline: missing ID yields empty stdout + nonzero exit" {
|
|
285
|
+
build_per_state_layout
|
|
286
|
+
run bash -c 'ls docs/problems/999-*.md docs/problems/*/999-*.md 2>/dev/null'
|
|
287
|
+
[ -z "$output" ]
|
|
288
|
+
[ "$status" -ne 0 ]
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
# ── Pipeline 5: Brace-expansion ID + state-set (report-upstream)
|
|
292
|
+
#
|
|
293
|
+
# SKILL.md prescribes:
|
|
294
|
+
# ls docs/problems/<ID>-*.{open,known-error,verifying,closed}.md \
|
|
295
|
+
# docs/problems/*/<ID>-*.md 2>/dev/null
|
|
296
|
+
#
|
|
297
|
+
# The flat half restricts to a state-set (excludes parked); the
|
|
298
|
+
# per-state half is unrestricted (no state filter). T3 proves the
|
|
299
|
+
# brace expansion composes with the per-state pathspec without false
|
|
300
|
+
# positives across the migration window.
|
|
301
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
@test "brace-id-state pipeline: per-state-only fixture finds 200 via per-state half" {
|
|
304
|
+
build_per_state_layout
|
|
305
|
+
run bash -c 'ls docs/problems/200-*.{open,known-error,verifying,closed}.md docs/problems/*/200-*.md 2>/dev/null'
|
|
306
|
+
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
@test "brace-id-state pipeline: mixed fixture finds flat 100 (open) and per-state 200 (open)" {
|
|
310
|
+
build_mixed_layout
|
|
311
|
+
run bash -c 'ls docs/problems/100-*.{open,known-error,verifying,closed}.md docs/problems/*/100-*.md 2>/dev/null'
|
|
312
|
+
[[ "$output" == *"100-foo.open.md"* ]]
|
|
313
|
+
run bash -c 'ls docs/problems/200-*.{open,known-error,verifying,closed}.md docs/problems/*/200-*.md 2>/dev/null'
|
|
314
|
+
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
@test "brace-id-state pipeline: parked ticket excluded from flat half but matched in per-state half" {
|
|
318
|
+
# Flat 103 is parked (excluded by the brace state-set); per-state 203
|
|
319
|
+
# is parked but the per-state pathspec is state-unrestricted, so it
|
|
320
|
+
# MUST surface. This is the contract architect finding 2 codifies.
|
|
321
|
+
build_mixed_layout
|
|
322
|
+
run bash -c 'ls docs/problems/103-*.{open,known-error,verifying,closed}.md docs/problems/*/103-*.md 2>/dev/null'
|
|
323
|
+
[[ "$output" != *"103-qux.parked.md"* ]]
|
|
324
|
+
run bash -c 'ls docs/problems/203-*.{open,known-error,verifying,closed}.md docs/problems/*/203-*.md 2>/dev/null'
|
|
325
|
+
[[ "$output" == *"parked/203-qux2.md"* ]]
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
# ── Pipeline 6: Closed-ticket ID-anchored lookup
|
|
329
|
+
# (review-problems Step 5: closed-section rendering uses
|
|
330
|
+
# `docs/problems/*.closed.md docs/problems/closed/*.md`)
|
|
331
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
332
|
+
|
|
333
|
+
@test "closed-ticket pipeline: mixed fixture enumerates flat 104 and per-state 204" {
|
|
334
|
+
build_mixed_layout
|
|
335
|
+
run bash -c 'ls docs/problems/*.closed.md docs/problems/closed/*.md 2>/dev/null'
|
|
336
|
+
[[ "$output" == *"104-quux.closed.md"* ]]
|
|
337
|
+
[[ "$output" == *"closed/204-quux2.md"* ]]
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
@test "closed-ticket pipeline: per-state-only fixture excludes other-state subdirs" {
|
|
341
|
+
build_per_state_layout
|
|
342
|
+
run bash -c 'ls docs/problems/*.closed.md docs/problems/closed/*.md 2>/dev/null'
|
|
343
|
+
[[ "$output" == *"closed/204-quux2.md"* ]]
|
|
344
|
+
[[ "$output" != *"open/200"* ]]
|
|
345
|
+
[[ "$output" != *"known-error/201"* ]]
|
|
346
|
+
[[ "$output" != *"verifying/202"* ]]
|
|
347
|
+
[[ "$output" != *"parked/203"* ]]
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
# ── Pipeline 7: Parked-state filter (review-problems Step 3 parked section)
|
|
351
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
352
|
+
|
|
353
|
+
@test "parked-state pipeline: mixed fixture enumerates flat 103 and per-state 203" {
|
|
354
|
+
build_mixed_layout
|
|
355
|
+
run bash -c 'ls docs/problems/*.parked.md docs/problems/parked/*.md 2>/dev/null'
|
|
356
|
+
[[ "$output" == *"103-qux.parked.md"* ]]
|
|
357
|
+
[[ "$output" == *"parked/203-qux2.md"* ]]
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
# ── Composition: ls-with-2>/dev/null exit-code semantics
|
|
361
|
+
# (mirrors T2's empty-fixture contract; proves the SKILL.md contract
|
|
362
|
+
# remains "stdout content is the signal, not exit code")
|
|
363
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
364
|
+
|
|
365
|
+
@test "all pipelines: empty fixture produces empty stdout across every shape" {
|
|
366
|
+
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
367
|
+
[ -z "$output" ]
|
|
368
|
+
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
369
|
+
[ -z "$output" ]
|
|
370
|
+
run bash -c 'ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null'
|
|
371
|
+
[ -z "$output" ]
|
|
372
|
+
run bash -c 'ls docs/problems/100-*.md docs/problems/*/100-*.md 2>/dev/null'
|
|
373
|
+
[ -z "$output" ]
|
|
374
|
+
}
|
|
@@ -23,7 +23,7 @@ This skill is the foreground-lightweight-capture variant of `/wr-itil:manage-pro
|
|
|
23
23
|
|
|
24
24
|
## Rule 6 audit (per ADR-032 + ADR-013)
|
|
25
25
|
|
|
26
|
-
This skill has **
|
|
26
|
+
This skill has **one classification-only AskUserQuestion (type-tag, taste authority per ADR-044 category 5) and zero control-flow branches keyed on the answer**. Each potentially-interactive decision is framework-mediated per ADR-044:
|
|
27
27
|
|
|
28
28
|
| Decision | Resolution |
|
|
29
29
|
|----------|-----------|
|
|
@@ -32,8 +32,9 @@ This skill has **zero AskUserQuestion branches** by design. Each potentially-int
|
|
|
32
32
|
| Effort default | Framework-policy: `M` flagged "deferred — re-rate at next /wr-itil:review-problems". |
|
|
33
33
|
| Multi-concern split | Out of scope: capture-problem creates one ticket per invocation. Multi-concern observations route to `/wr-itil:manage-problem` (its Step 4b owns the split). |
|
|
34
34
|
| Empty `$ARGUMENTS` | Halt-with-stderr-directive: print "capture-problem requires a description in $ARGUMENTS — invoke /wr-itil:manage-problem instead for the full intake flow" and exit. AFK orchestrators MUST NOT invoke capture-problem with empty arguments — caller-side contract. |
|
|
35
|
+
| Type classification (P170 / ADR-060 item 8c) | Taste authority per ADR-044 category 5. AskUserQuestion fires for `type` ∈ {`technical`, `user-business`} when no caller-side flag pre-resolved it. `--type=<value>` flag pre-resolves the answer (silent-proceed). `--no-prompt` flag defaults to `technical` (silent-proceed). Maintainer-side ONLY: this prompt is paired with JTBD-301 protection — `.github/ISSUE_TEMPLATE/problem-report.yml` (plugin-user-side intake) MUST NOT carry an equivalent type selector; triage assigns the type during `/wr-itil:manage-problem` ingestion of user-reported issues. **I2 invariant** (ADR-060 line 98): the prompt is a classification facet, not a workflow split — Steps 0-7 control-flow is identical regardless of the chosen `type_value`; only the substituted value in the Step 4 skeleton template differs. |
|
|
35
36
|
|
|
36
|
-
Per ADR-013 Rule 6 fail-safe: every
|
|
37
|
+
Per ADR-013 Rule 6 fail-safe: every decision above resolves without interactive user input in non-interactive contexts (the type-tag carve-out resolves to `technical` via `--no-prompt` or `--type=` caller-side pre-resolution). AFK orchestrators MUST pass `--no-prompt` or `--type=<value>` per JTBD-006 § Persona Constraints; AFK callers that omit both flags violate the caller-side contract. Interactive and pre-resolved AFK paths produce identical observable outputs except for the `**Type**:` field value, satisfying the I2 invariant by construction.
|
|
37
38
|
|
|
38
39
|
## Steps
|
|
39
40
|
|
|
@@ -54,18 +55,42 @@ if [ "$reconcile_exit" -eq 1 ]; then
|
|
|
54
55
|
fi
|
|
55
56
|
```
|
|
56
57
|
|
|
57
|
-
### 1. Parse the description from `$ARGUMENTS`
|
|
58
|
+
### 1. Parse the description and flags from `$ARGUMENTS`
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
`$ARGUMENTS` may carry up to two leading flags before the free-text description (caller-side pre-resolution per ADR-044 silent-proceed shape):
|
|
61
|
+
|
|
62
|
+
| Flag | Effect on Step 1.5 |
|
|
63
|
+
|------|-------------------|
|
|
64
|
+
| `--type=technical` | Pre-resolves type to `technical`; Step 1.5 skips the AskUserQuestion. |
|
|
65
|
+
| `--type=user-business` | Pre-resolves type to `user-business`; Step 1.5 skips the AskUserQuestion. |
|
|
66
|
+
| `--no-prompt` | Pre-resolves type to `technical` (default); Step 1.5 skips the AskUserQuestion. |
|
|
67
|
+
|
|
68
|
+
Strip recognised leading flags from `$ARGUMENTS`; the remainder (after flags) is the free-text description. If both `--type=<value>` and `--no-prompt` are present, `--type=<value>` wins (more specific). Unknown leading flags halt-with-stderr-directive: print "capture-problem: unknown flag '<flag>' — recognised flags: --type=technical, --type=user-business, --no-prompt" and exit.
|
|
69
|
+
|
|
70
|
+
Empty description (post-flag-strip) halts per the Rule 6 audit above.
|
|
60
71
|
|
|
61
72
|
Derive a kebab-case title slug from the first 8-10 non-stopword tokens of the description (matching the existing `manage-problem` slug derivation pattern).
|
|
62
73
|
|
|
74
|
+
### 1.5 Type classification (taste authority per ADR-044 category 5)
|
|
75
|
+
|
|
76
|
+
Resolve `type_value` ∈ {`technical`, `user-business`} per the following framework-mediated dispatch:
|
|
77
|
+
|
|
78
|
+
1. **If `--type=<value>` was set in Step 1**: use that value; do NOT fire AskUserQuestion (silent-proceed per ADR-013 Rule 5).
|
|
79
|
+
2. **Else if `--no-prompt` was set in Step 1**: default `type_value = technical`; do NOT fire AskUserQuestion. JTBD-006 protection: AFK orchestrators MUST pass this flag (or `--type=<value>`).
|
|
80
|
+
3. **Else** (interactive context, no caller-side pre-resolution): fire AskUserQuestion with options `technical` (default) and `user-business`. Question text: *"What type of problem is this?"* Per-option descriptions:
|
|
81
|
+
- `technical` — *"Bug, defect, broken behaviour, framework drift — root cause sits in code or process."*
|
|
82
|
+
- `user-business` — *"Missing capability, UX gap, adopter friction, JTBD-shaped need — root cause sits in unmet user need."*
|
|
83
|
+
|
|
84
|
+
**I2 invariant guard (ADR-060 line 98)**: the resolved `type_value` is used at Step 4 ONLY as a substituted string in the skeleton template's `**Type**:` body field. Steps 2, 3, 4 (other than the `**Type**:` substitution), 5, 6, 7 execute identically regardless of `type_value`. The skill carries NO control-flow branch keyed on `type` — that would convert classification into a workflow split and violate I2. Pure-bash supporting-script enforcement of this invariant lives in `packages/itil/scripts/test/i2-no-type-branching.bats`; the SKILL.md surface coverage gap is named at P176 (descendant of P012 master harness).
|
|
85
|
+
|
|
86
|
+
**JTBD-301 scope guard**: this prompt fires on the maintainer-side `/wr-itil:capture-problem` skill only. The plugin-user-side intake (`.github/ISSUE_TEMPLATE/problem-report.yml`) MUST NOT carry an equivalent type selector — plugin-user persona constraint is "no pre-classification". Triage assigns `type` during `/wr-itil:manage-problem` ingestion of user-reported issues, not at user-report time.
|
|
87
|
+
|
|
63
88
|
### 2. Minimal-grep duplicate check (3-keyword title-only)
|
|
64
89
|
|
|
65
|
-
Extract up to **3 distinct kebab-cased non-stopword keywords** from the description. Grep the **filenames** of `docs/problems/*.md` (NOT bodies — title-only is the conservative threshold per architect verdict on Q1):
|
|
90
|
+
Extract up to **3 distinct kebab-cased non-stopword keywords** from the description. Grep the **filenames** of `docs/problems/*.md` AND `docs/problems/<state>/*.md` (NOT bodies — title-only is the conservative threshold per architect verdict on Q1; dual-tolerant per RFC-002 migration window):
|
|
66
91
|
|
|
67
92
|
```bash
|
|
68
|
-
match_count=$(ls docs/problems/*.md 2>/dev/null \
|
|
93
|
+
match_count=$(ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null \
|
|
69
94
|
| grep -ciE 'kw1|kw2|kw3' || true)
|
|
70
95
|
```
|
|
71
96
|
|
|
@@ -90,8 +115,16 @@ The marker is shared between `manage-problem` and `capture-problem` per ADR-032
|
|
|
90
115
|
Same P056-safe local_max + origin_max formula as `/wr-itil:manage-problem` Step 3:
|
|
91
116
|
|
|
92
117
|
```bash
|
|
93
|
-
|
|
94
|
-
|
|
118
|
+
# Dual-tolerant ticket enumeration (RFC-002 migration window). Both
|
|
119
|
+
# halves of the OR contribute to next-ID compute — flat-layout 104 +
|
|
120
|
+
# per-state 204 BOTH appear in `local_max` so the next-ID compute
|
|
121
|
+
# never re-allocates an already-taken ID. Architect finding 2 (RFC-002
|
|
122
|
+
# T2) — capture-problem's next-ID surface is a separate ADR-031
|
|
123
|
+
# contract from generic enumeration; missing the per-state half
|
|
124
|
+
# regresses ID allocation. The `git ls-tree -r` recursive flag
|
|
125
|
+
# extends the same coverage to the origin tree.
|
|
126
|
+
local_max=$(ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1)
|
|
127
|
+
origin_max=$(git ls-tree -r --name-only origin/main docs/problems/ 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1)
|
|
95
128
|
next=$(printf '%03d' $(( $(echo -e "${local_max:-0}\n${origin_max:-0}" | sort -n | tail -1) + 1 )))
|
|
96
129
|
```
|
|
97
130
|
|
|
@@ -110,10 +143,11 @@ Log the renumber decision in the operation report if origin and local diverged.
|
|
|
110
143
|
**Reported**: <YYYY-MM-DD>
|
|
111
144
|
**Priority**: 3 (Medium) — Impact: 3 x Likelihood: 1 (deferred — re-rate at next /wr-itil:review-problems)
|
|
112
145
|
**Effort**: M (deferred — re-rate at next /wr-itil:review-problems)
|
|
146
|
+
**Type**: <type_value>
|
|
113
147
|
|
|
114
148
|
## Description
|
|
115
149
|
|
|
116
|
-
<full description from $ARGUMENTS>
|
|
150
|
+
<full description from $ARGUMENTS, with leading recognised flags stripped>
|
|
117
151
|
|
|
118
152
|
## Symptoms
|
|
119
153
|
|
|
@@ -192,7 +226,9 @@ The trailing pointer is **not optional** — it is the user-visible signal that
|
|
|
192
226
|
|---------|----------------|-----------------|
|
|
193
227
|
| Duplicate-check | Wide-net grep + AskUserQuestion branch on matches | 3-keyword title-only grep, list-only (no branch) |
|
|
194
228
|
| Multi-concern split | Step 4b AskUserQuestion | Out of scope (one ticket per invocation) |
|
|
195
|
-
| Skeleton-fill | Full-intake; AskUserQuestion for missing fields | Deferred-placeholder pattern
|
|
229
|
+
| Skeleton-fill | Full-intake; AskUserQuestion for missing fields | Deferred-placeholder pattern + one classification-only AskUserQuestion (type-tag) |
|
|
230
|
+
| Type-tag prompt | Step 4-equivalent AskUserQuestion fires alongside other intake fields | Step 1.5 classification-only AskUserQuestion; `--type=` and `--no-prompt` flags pre-resolve for non-interactive callers; I2 invariant: no control-flow branch keyed on type |
|
|
231
|
+
| AskUserQuestion authority | Multiple branches (deviation-approval / direction-setting / taste / mechanical) | Exactly one classification-only fire (taste, ADR-044 cat. 5); zero control-flow branches |
|
|
196
232
|
| README refresh | P094 inline (regenerate + stage in same commit) | Deferred to next `/wr-itil:review-problems` |
|
|
197
233
|
| Status transitions | Step 7 owns Open → Known Error → Verifying → Closed | Out of scope (creation only) |
|
|
198
234
|
| Commit grain | One commit per intake (or per split-concern set) | One commit per capture |
|
|
@@ -206,12 +242,17 @@ The two skills share the `/tmp/manage-problem-grep-${SESSION_ID}` create-gate ma
|
|
|
206
242
|
- **P014** (`docs/problems/014-aside-invocation-for-governance-skills.open.md`) — parent / master tracker.
|
|
207
243
|
- **P078** — capture-on-correction OFFER pattern; depends on capture-problem shipping.
|
|
208
244
|
- **P119** — manage-problem create-gate hook; capture-problem composes with the same marker.
|
|
245
|
+
- **P170** (`docs/problems/170-...open.md`) — RFC framework driver; Slice 4 B7.T3 / item 8c authored the type-classification prompt at Step 1.5.
|
|
246
|
+
- **P176** — agent-side I2 (no type-branching) coverage gap on the SKILL.md surface (this file's surface); descendant of P012 master harness ticket. The Step 1.5 I2 invariant guard is enforced by audit-trailed prose here per ADR-052 § Surface 2 escape-hatch contract; behavioural enforcement awaits the master harness.
|
|
209
247
|
- **ADR-032** (`docs/decisions/032-governance-skill-invocation-patterns.proposed.md`) — foreground-lightweight-capture variant amendment.
|
|
210
248
|
- **ADR-038** — progressive-disclosure pattern (SKILL.md + REFERENCE.md split).
|
|
211
|
-
- **ADR-044** — decision-delegation contract
|
|
249
|
+
- **ADR-044** — decision-delegation contract; type classification is taste authority per category 5; `--no-prompt` / `--type=<value>` are policy-authorised silent-proceed shapes per category 4.
|
|
212
250
|
- **ADR-049** — bin/ on PATH; capture-problem reuses the existing `wr-itil-reconcile-readme` shim.
|
|
213
|
-
- **ADR-052** — behavioural-tests-default for skill testing.
|
|
251
|
+
- **ADR-052** — behavioural-tests-default for skill testing; SKILL.md I2 surface coverage gap is named, not silent (P176 + ADR-052 § Surface 2).
|
|
252
|
+
- **ADR-060** (`docs/decisions/060-...accepted.md`) — Phase 1 item 8c authored Step 1.5 here; I2 invariant (line 98) governs the no-control-flow-branch contract; line 132 names the maintainer-side-only / JTBD-301-protection scope; line 160 (Confirmation criterion 4) gates the type-prompt placement.
|
|
253
|
+
- **JTBD-301** (`docs/jtbd/plugin-user/JTBD-301-...md`) — plugin-user no-pre-classification persona constraint; protected by the Step 1.5 maintainer-side scope guard.
|
|
214
254
|
- `packages/itil/skills/manage-problem/SKILL.md` — heavyweight intake counterpart.
|
|
215
255
|
- `packages/itil/skills/review-problems/SKILL.md` — re-rates the deferred placeholders + refreshes README.md.
|
|
256
|
+
- `packages/itil/scripts/test/i2-no-type-branching.bats` — pure-bash supporting-script enforcement of the I2 invariant; this SKILL.md change does not affect any pure-bash script and so does not change the bats outcome (still green).
|
|
216
257
|
|
|
217
258
|
$ARGUMENTS
|
|
@@ -89,8 +89,10 @@ Derive a kebab-case title slug from the first 8-10 non-stopword tokens of `$desc
|
|
|
89
89
|
For each `P<NNN>` in the trace list:
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
|
-
# Check existence in any lifecycle status
|
|
93
|
-
|
|
92
|
+
# Check existence in any lifecycle status (dual-tolerant — RFC-002
|
|
93
|
+
# migration window covers BOTH flat `docs/problems/<NNN>-<title>.<state>.md`
|
|
94
|
+
# AND per-state subdir `docs/problems/<state>/<NNN>-<title>.md` layouts).
|
|
95
|
+
trace_files=$(ls docs/problems/<NNN>-*.md docs/problems/*/<NNN>-*.md 2>/dev/null)
|
|
94
96
|
```
|
|
95
97
|
|
|
96
98
|
**I1 hard-block (per ADR-060 § Confirmation criterion 1)**:
|
|
@@ -198,7 +200,8 @@ For each problem ID in `$problem_trace`, invoke the helper before commit:
|
|
|
198
200
|
```bash
|
|
199
201
|
for pid_token in $(echo "$problem_trace" | tr ',' ' '); do
|
|
200
202
|
pid_num="${pid_token#P}"
|
|
201
|
-
|
|
203
|
+
# Dual-tolerant ticket discovery (RFC-002 migration window).
|
|
204
|
+
problem_file=$(ls docs/problems/${pid_num}-*.md docs/problems/*/${pid_num}-*.md 2>/dev/null | head -1)
|
|
202
205
|
[ -z "$problem_file" ] && continue
|
|
203
206
|
bash "$(wr-itil-script-path 2>/dev/null || echo packages/itil/scripts)/update-problem-rfcs-section.sh" "$problem_file" docs/rfcs
|
|
204
207
|
git add "$problem_file"
|
|
@@ -63,10 +63,10 @@ Branch on which section is present:
|
|
|
63
63
|
**Case A — `## Linked Problem` present**:
|
|
64
64
|
|
|
65
65
|
1. Extract the problem ID `P<NNN>` from the section.
|
|
66
|
-
2. Locate the problem file:
|
|
66
|
+
2. Locate the problem file. Dual-tolerant lookup spans flat layout AND per-state subdir layout (RFC-002 migration window):
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
ls docs/problems/<NNN>-*.md 2>/dev/null | head -1
|
|
69
|
+
ls docs/problems/<NNN>-*.md docs/problems/*/<NNN>-*.md 2>/dev/null | head -1
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
Accept both `P<NNN>-*.md` and `<NNN>-*.md` naming conventions for robustness.
|
|
@@ -42,11 +42,13 @@ The link operation works on any incident status — investigating, mitigating, r
|
|
|
42
42
|
|
|
43
43
|
### 3. Locate the problem file
|
|
44
44
|
|
|
45
|
+
Dual-tolerant lookup spans flat layout AND per-state subdir layout (RFC-002 migration window):
|
|
46
|
+
|
|
45
47
|
```bash
|
|
46
|
-
ls docs/problems/<MMM>-*.md 2>/dev/null | head -1
|
|
48
|
+
ls docs/problems/<MMM>-*.md docs/problems/*/<MMM>-*.md 2>/dev/null | head -1
|
|
47
49
|
```
|
|
48
50
|
|
|
49
|
-
Accept any lifecycle suffix: `.open.md`, `.known-error.md`, `.verifying.md`, `.closed.md
|
|
51
|
+
Accept any lifecycle suffix: `.open.md`, `.known-error.md`, `.verifying.md`, `.closed.md` in flat layout; bare `<MMM>-<title>.md` under `docs/problems/<state>/` in per-state layout.
|
|
50
52
|
|
|
51
53
|
- If no file matches, report "No problem `P<MMM>` found. Check `/wr-itil:list-problems` for the current backlog." and exit.
|
|
52
54
|
- Read the problem file's title from the `# Problem <MMM>: <Title>` header line.
|
|
@@ -12,15 +12,16 @@ This skill is the P071 phased-landing split of `/wr-itil:manage-problem list` pe
|
|
|
12
12
|
|
|
13
13
|
## Scope
|
|
14
14
|
|
|
15
|
-
Included in the ranking table:
|
|
16
|
-
|
|
17
|
-
- `docs/problems/*.
|
|
15
|
+
Included in the ranking table (RFC-002 migration window — each glob is dual-tolerant, covering BOTH the flat `docs/problems/<NNN>-<title>.<state>.md` filename-suffix layout AND the per-state subdir `docs/problems/<state>/<NNN>-<title>.md` layout):
|
|
16
|
+
|
|
17
|
+
- `docs/problems/*.open.md` + `docs/problems/open/*.md` — open tickets (under investigation)
|
|
18
|
+
- `docs/problems/*.known-error.md` + `docs/problems/known-error/*.md` — known errors (root cause confirmed, fix NOT yet released)
|
|
18
19
|
|
|
19
20
|
Shown in separate sections, excluded from the dev-work WSJF ranking per ADR-022:
|
|
20
|
-
- `docs/problems/*.verifying.md` — Verification Pending (fix released, awaiting user verification; WSJF multiplier 0)
|
|
21
|
-
- `docs/problems/*.parked.md` — Parked on upstream or user-suspended (WSJF multiplier 0)
|
|
21
|
+
- `docs/problems/*.verifying.md` + `docs/problems/verifying/*.md` — Verification Pending (fix released, awaiting user verification; WSJF multiplier 0)
|
|
22
|
+
- `docs/problems/*.parked.md` + `docs/problems/parked/*.md` — Parked on upstream or user-suspended (WSJF multiplier 0)
|
|
22
23
|
|
|
23
|
-
`docs/problems/*.closed.md` is omitted entirely (the view is of active backlog, not the closed archive).
|
|
24
|
+
`docs/problems/*.closed.md` + `docs/problems/closed/*.md` is omitted entirely (the view is of active backlog, not the closed archive).
|
|
24
25
|
|
|
25
26
|
## Steps
|
|
26
27
|
|
|
@@ -31,7 +32,10 @@ Reuse the same `git log`-based freshness test as `/wr-itil:manage-problem review
|
|
|
31
32
|
```bash
|
|
32
33
|
readme_commit=$(git log -1 --format=%H -- docs/problems/README.md 2>/dev/null)
|
|
33
34
|
if [ -z "$readme_commit" ] || \
|
|
34
|
-
git log --oneline "${readme_commit}..HEAD" -- 'docs/problems/*.md' ':!docs/problems/README.md' 2>/dev/null | grep -q .; then
|
|
35
|
+
git log --oneline "${readme_commit}..HEAD" -- 'docs/problems/*.md' 'docs/problems/*/*.md' ':!docs/problems/README.md' 2>/dev/null | grep -q .; then
|
|
36
|
+
# Pathspec pair `'docs/problems/*.md' 'docs/problems/*/*.md'` is the
|
|
37
|
+
# RFC-002 dual-tolerant transitional shape — covers BOTH the flat
|
|
38
|
+
# layout AND the per-state subdir layout.
|
|
35
39
|
echo "stale"
|
|
36
40
|
fi
|
|
37
41
|
```
|
|
@@ -42,12 +46,12 @@ fi
|
|
|
42
46
|
|
|
43
47
|
### 2. Live scan (cache-stale fallback)
|
|
44
48
|
|
|
45
|
-
Enumerate the backlog files via
|
|
49
|
+
Enumerate the backlog files via dual-tolerant globs (RFC-002 migration window — each line covers BOTH the flat `<NNN>-<title>.<state>.md` filename-suffix layout AND the per-state subdir `<state>/<NNN>-<title>.md` layout):
|
|
46
50
|
|
|
47
51
|
```bash
|
|
48
|
-
ls docs/problems/*.open.md docs/problems/*.known-error.md 2>/dev/null
|
|
49
|
-
ls docs/problems/*.verifying.md 2>/dev/null # for Verification Queue section
|
|
50
|
-
ls docs/problems/*.parked.md 2>/dev/null
|
|
52
|
+
ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null
|
|
53
|
+
ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null # for Verification Queue section
|
|
54
|
+
ls docs/problems/*.parked.md docs/problems/parked/*.md 2>/dev/null # for Parked section
|
|
51
55
|
```
|
|
52
56
|
|
|
53
57
|
For each `.open.md` and `.known-error.md` file, read the `**Status**`, `**Priority**`, `**Effort**`, and `**WSJF**` lines from the frontmatter section. Compute WSJF if missing: `WSJF = (Severity × StatusMultiplier) / EffortDivisor` per `/wr-itil:manage-problem` WSJF Prioritisation. Default to M (divisor 2) when Effort is absent; flag missing scores so the user knows a review is overdue.
|