@windyroad/itil 0.19.7 → 0.20.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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "wr-itil",
3
- "version": "0.19.7",
3
+ "version": "0.20.0",
4
4
  "description": "ITIL-aligned IT service management for Claude Code"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/itil",
3
- "version": "0.19.7",
3
+ "version": "0.20.0",
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"
@@ -0,0 +1,290 @@
1
+ ---
2
+ name: wr-itil:transition-problems
3
+ description: Batch-advance multiple problem tickets through the lifecycle in one invocation — Open → Known Error, Known Error → Verification Pending, Verification Pending → Closed. Loops the per-ticket /wr-itil:transition-problem mechanic (rename, Status edit, P057 re-stage, P063 external-root-cause detection, P062 README refresh) without paying N× SKILL.md reload latency or violating split-skill execution ownership. Produces ONE shared commit covering all surviving transitions per ADR-014 batch-grain. Use when closing the Verification Queue at the end of a `/wr-retrospective:run-retro` Step 4a pass, batch-closing release-aged verifyings during `/wr-itil:work-problems` AFK orchestration, or confirming multiple Step 9d verifications in `/wr-itil:manage-problem review`. Singular sibling: `/wr-itil:transition-problem` (one ticket per invocation).
4
+ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Skill, Agent
5
+ ---
6
+
7
+ # Transition Problems — Batch Lifecycle Advance
8
+
9
+ Advance multiple problem tickets along the ITIL lifecycle in one invocation. The skill is the **batch executor** for the user-initiated transition path — it accepts a list of `<NNN> <status>` pairs, runs each pair's per-ticket mechanic inline (pre-flight checks, P063 external-root-cause detection, `git mv` + Status edit + P057 re-stage, `## Fix Released` for the `verifying` destination), refreshes `docs/problems/README.md` ONCE at the end (P062 at batch grain), and commits all surviving transitions in ONE commit per ADR-014.
10
+
11
+ This skill is the plural sibling of `/wr-itil:transition-problem`, mirroring the P071 singular/plural split precedent established by `/wr-itil:work-problem` (singular) and `/wr-itil:work-problems` (plural). Per ADR-010 amended Skill Granularity rule, batch-transition is a distinct user intent from single-transition (different ergonomics, different commit grain, different cost profile) and therefore lives on its own skill surface.
12
+
13
+ ## Why this skill exists (P117)
14
+
15
+ Closing N tickets via the singular skill costs N× SKILL.md reload into the caller's context every time the singular is invoked from a batch caller (run-retro Step 4a, manage-problem review Step 9d, work-problems release-batched closures). This is the very SKILL.md-runtime-size pressure P097 captures, and the inline-batch workaround documented in P117 (running `git mv` + Edit + commit outside the singular skill's authoritative-executor scope) violates the ADR-010 amended ownership boundary.
16
+
17
+ The plural surface eliminates both costs: ONE SKILL.md load (this file), N pair iterations in-band, ONE commit at the end. Per ADR-010 amended "Split-skill execution ownership", the plural carries an inline scoped copy of the singular's per-ticket mechanic ("copy, not move") rather than re-invoking the singular via the Skill tool — Skill-tool re-invocation N times would reintroduce the very N× reload cost the ticket targets.
18
+
19
+ ## Name distinction (transition-problem vs transition-problems)
20
+
21
+ - **`/wr-itil:transition-problem`** (singular) — one ticket per invocation. The authoritative executor for the single-transition user-initiated path (P093 / ADR-010 amended). Use when the user wants to transition one specific ticket and stop.
22
+ - **`/wr-itil:transition-problems`** (plural, this skill) — batch transition. Accepts a list of `<NNN> <status>` pairs and runs each through an inline copy of the per-ticket mechanic, single commit at the end. Use when closing multiple verifyings at once or batch-marking known-error after a multi-ticket review.
23
+
24
+ Both names coexist intentionally per the P071 singular/plural precedent. Plugin-developers reading this skill should recognise the same shape as `work-problem`/`work-problems`, `list-problems`, and `review-problems` — distinct intents for distinct ergonomic surfaces.
25
+
26
+ ## Arguments
27
+
28
+ A space-separated list of `<NNN> <status>` pairs. Repeating the singular skill's argument shape N times — same convention, no new syntax. No `P` prefix on the ID; no `=`/`:` separator inside a pair; no CLI flag-style (`--pairs`).
29
+
30
+ ```
31
+ /wr-itil:transition-problems <NNN> <status> [<NNN> <status>] ...
32
+ ```
33
+
34
+ - `<NNN>` — three-digit ticket ID (e.g. `063`).
35
+ - `<status>` — destination status. One of:
36
+ - `known-error` — Open → Known Error (root cause + workaround documented).
37
+ - `verifying` — Known Error → Verification Pending (fix released; awaiting user verification per ADR-022).
38
+ - `close` — Verification Pending → Closed (user has confirmed the fix works in production).
39
+
40
+ **Examples:**
41
+
42
+ ```
43
+ /wr-itil:transition-problems 063 close 067 close 092 close 094 close
44
+ /wr-itil:transition-problems 070 known-error 080 verifying 094 close
45
+ ```
46
+
47
+ The pair tokens are **data parameters**, not word-subcommands — the same shape rule the singular's argument table cites against P071. Pairs are processed in argument order; each runs the full per-pair mechanic independently.
48
+
49
+ If the argument count is odd, or any pair's tokens are malformed (`<NNN>` not three digits; `<status>` not in the enum), emit a usage message and stop without touching git.
50
+
51
+ ## Scope
52
+
53
+ **In scope:**
54
+ - Parse the pair list and validate each pair's argument shape (count is even; IDs are `\d{3}`; statuses are in the enum).
55
+ - For each pair, run the per-ticket mechanic inline: ticket-file discovery, transition-path validation, pre-flight checks, P063 external-root-cause detection (Open → Known Error only), `git mv` to the new suffix, Status field edit, `## Fix Released` section write (Known Error → Verification Pending only), explicit P057 re-stage.
56
+ - After the loop, refresh `docs/problems/README.md` ONCE per P062 (single render reflecting all surviving renames).
57
+ - Commit ALL surviving transitions + the refreshed README in ONE commit per ADR-014 batch-grain unit-of-work.
58
+ - Report the per-pair outcome: succeeded pairs, failed pairs (with reason category), commit SHA.
59
+
60
+ **Out of scope:**
61
+ - Per-pair commits — replaced by the single batch commit at the end. The singular skill's per-invocation commit semantics are deliberately re-aggregated at this batch grain.
62
+ - Backlog re-ranking — that's `/wr-itil:review-problems`.
63
+ - Ticket creation or bare-update flows — those stay on `/wr-itil:manage-problem`.
64
+ - Parking — the `.parked.md` suffix has its own path on `/wr-itil:manage-problem`.
65
+ - Auto-transitions inside review — Step 9b uses manage-problem's in-skill Step 7 block ("copy, not move") per ADR-010 amended.
66
+ - Release draining — `push:watch` / `release:watch` are owned by the caller (`/wr-itil:work-problems` orchestrator Step 6.5, or `/wr-itil:manage-problem` Step 12).
67
+
68
+ ## Steps
69
+
70
+ ### 1. Parse the pair list
71
+
72
+ From `$ARGUMENTS`, tokenise by whitespace and pair off tokens (0,1) / (2,3) / ... Validate:
73
+
74
+ - Token count is even and ≥ 2. If odd or zero, emit the usage message and stop.
75
+ - Each `<NNN>` matches `^\d{3}$`. If any does not, emit the usage message naming the bad token and stop.
76
+ - Each `<status>` is one of `known-error`, `verifying`, `close`. If any is not, emit the usage message naming the bad token and stop.
77
+
78
+ If parsing fails at this stage, NO git operations have run. The user can re-invoke with corrected arguments cleanly.
79
+
80
+ ### 2. Per-pair execution loop (inline copy of the singular's per-ticket mechanic)
81
+
82
+ > **Copy, not move (per ADR-010 amended Split-skill execution ownership).** The body below is a scoped inline copy of `/wr-itil:transition-problem` Steps 2–6 (discovery, validation, pre-flight, P063 detection, rename + Edit + re-stage). The per-pair commit step (singular Step 8) is INTENTIONALLY OMITTED — batch semantics replace it with the single commit in Step 4 below.
83
+ >
84
+ > Drift between the singular and this inline copy is detected by the contract-assertion bats (`packages/itil/skills/transition-problems/test/transition-problems-contract.bats`) which asserts shared substring presence (e.g. the `git add docs/problems/` re-stage phrase) in BOTH files. If you edit one, edit the other.
85
+
86
+ For each pair `(NNN, status)` in argument order:
87
+
88
+ **2a. Discover the ticket file.**
89
+
90
+ ```bash
91
+ ls docs/problems/<NNN>-*.md 2>/dev/null
92
+ ```
93
+
94
+ If no file is found OR multiple files are found (suffix-exclusive lifecycle violation), record the pair as a failure with reason `discovery-failed` and continue to the next pair. Do NOT touch git.
95
+
96
+ **2b. Validate the transition path.** Compare the current filename suffix against the destination:
97
+
98
+ | Current suffix | `<status>` | Valid? |
99
+ |----------------|------------|--------|
100
+ | `.open.md` | `known-error` | yes |
101
+ | `.known-error.md` | `verifying` | yes |
102
+ | `.verifying.md` | `close` | yes |
103
+ | any other pairing | — | no — record as `invalid-transition` and continue |
104
+
105
+ **2c. Run pre-flight checks** for the destination (same gating as the singular):
106
+
107
+ - Open → Known Error (`known-error`): root cause documented; ≥ 1 investigation task ticked; reproduction test or reference; workaround documented; effort bucket re-rated if scope shifted (P047).
108
+ - Known Error → Verification Pending (`verifying`): fix implemented; release marker available (version, commit SHA, or date) for the `## Fix Released` section.
109
+ - Verification Pending → Closed (`close`): user has explicitly confirmed the fix works in production. AFK callers (work-problems orchestrator) MUST supply the close pair via prior user authorisation (e.g. an `AskUserQuestion`-batched closure prompt at the orchestrator layer); this skill never auto-closes on inference.
110
+
111
+ If any pre-flight fails, record the pair as `pre-flight-failed` with the failed-check list and continue to the next pair.
112
+
113
+ **2d. P063 external-root-cause detection** (Open → Known Error only — fires per pair).
114
+
115
+ Strict tokens (within Root Cause Analysis): `upstream`, `third-party`, `external`, `vendor`; or scoped npm package pattern `@[\w-]+/[\w-]+`.
116
+
117
+ ```bash
118
+ if grep -iE '\b(upstream|third-party|external|vendor)\b|@[[:alnum:]_-]+/[[:alnum:]_-]+' "$problem_file"; then
119
+ external_root_cause_detected=1
120
+ fi
121
+ ```
122
+
123
+ **Already-noted check** — before firing, grep for `- **Upstream report pending** —` or `- **Reported Upstream:**` or a `## Reported Upstream` section. If present, skip the prompt for this pair.
124
+
125
+ **Branch on interactivity (per ADR-013 Rule 1 / Rule 6):**
126
+
127
+ - **Interactive** (`AskUserQuestion` available): use the same three-option prompt the singular's Step 5 documents (invoke /wr-itil:report-upstream / defer-and-note / not-actually-upstream).
128
+ - **AFK / non-interactive** (orchestrator markers — "AFK", "work-problems", "batch-work", "ALL_DONE" — present in the invoking context): default to defer-and-note. Append `- **Upstream report pending** — external dependency identified; invoke /wr-itil:report-upstream when ready` to the ticket's `## Related` section. Do NOT auto-invoke `/wr-itil:report-upstream` (its Step 6 security branch is interactive — per ADR-024).
129
+
130
+ The detection is per-pair; each Open → Known Error pair runs its own check independently.
131
+
132
+ **2e. Rename, edit, re-stage** (P057 staging-trap rule applied per pair).
133
+
134
+ > **Staging trap (P057).** `git mv` stages only the rename. After the `Edit` tool modifies the renamed file, you MUST explicitly `git add` it before continuing — without the explicit re-stage, the content edit leaks into the next commit. The plural inherits this rule per pair; the per-pair re-stage is non-negotiable.
135
+
136
+ ```bash
137
+ # Open → Known Error
138
+ git mv docs/problems/<NNN>-<title>.open.md docs/problems/<NNN>-<title>.known-error.md
139
+ # Edit Status field to "Known Error"
140
+ git add docs/problems/<NNN>-<title>.known-error.md
141
+ ```
142
+
143
+ ```bash
144
+ # Known Error → Verification Pending (per ADR-022)
145
+ git mv docs/problems/<NNN>-<title>.known-error.md docs/problems/<NNN>-<title>.verifying.md
146
+ # Edit Status to "Verification Pending" AND add ## Fix Released section
147
+ # (release marker, one-sentence summary, Awaiting user verification)
148
+ git add docs/problems/<NNN>-<title>.verifying.md
149
+ ```
150
+
151
+ ```bash
152
+ # Verification Pending → Closed
153
+ git mv docs/problems/<NNN>-<title>.verifying.md docs/problems/<NNN>-<title>.closed.md
154
+ # Edit Status field to "Closed"
155
+ git add docs/problems/<NNN>-<title>.closed.md
156
+ ```
157
+
158
+ If `git mv` or `git add` fails for a pair (e.g. the file has been moved by a parallel process), record the pair as `git-failed` with the error and continue to the next pair. Do NOT attempt to roll back prior pairs' staged renames — those are now part of the in-progress batch.
159
+
160
+ Record each pair's outcome (succeeded / failed-with-reason) for the summary in Step 5.
161
+
162
+ ### 3. Partial-failure semantics (skip-and-surface)
163
+
164
+ Per architect-resolved design (2026-04-26): if a pair fails in any of the substeps above (discovery, validation, pre-flight, git-op), it is skipped and recorded as a failed pair. The loop continues with the next pair. There is NO halt, NO rollback of previously-staged surviving pairs.
165
+
166
+ Rationale grounded in existing decisions:
167
+ - ADR-014's "complete unit of work" boundary is the BATCH at this grain — a partial batch (succeeded subset) is a legitimate unit. Halting and discarding succeeded pairs (option a) loses validated work the user already authorised.
168
+ - ADR-013 Rule 6 forbids non-interactive destructive operations; rolling back staged renames (option c) requires `git reset` which is exactly the destructive class Rule 6 names.
169
+ - Mirrors the `/wr-itil:work-problems` Step 4 classifier precedent (skip-and-surface; commit succeeded work; failed pairs surfaced in summary).
170
+
171
+ **Zero-success path.** If ALL pairs failed (no pair survived to the staging step), DO NOT commit. Skip Steps 4 and 5's commit branches; emit a failure summary listing each failed pair's reason and stop without touching git.
172
+
173
+ ### 4. Refresh README + commit ONCE (single commit at batch grain per ADR-014)
174
+
175
+ After the per-pair loop finishes, IF AT LEAST ONE PAIR SUCCEEDED:
176
+
177
+ **4a. Refresh `docs/problems/README.md` ONCE (P062 at batch grain).**
178
+
179
+ Per P062, every Step 7 status transition refreshes README.md. At the batch grain, the refresh runs ONCE — a single render reflecting ALL surviving renames + Status updates. Not N refreshes (that would force the README to thrash N times mid-batch and amplify diff noise).
180
+
181
+ The refresh follows the same render rules as `/wr-itil:review-problems` Step 9e (glob `docs/problems/*.open.md` / `*.known-error.md` / `*.verifying.md` / `*.parked.md`; rank open + known-error by WSJF; Verification Queue ordered by release age; Parked section). It does NOT re-rank — existing WSJF values on ticket files are trusted; the refresh is a render, not a re-rank.
182
+
183
+ ```bash
184
+ git add docs/problems/README.md
185
+ ```
186
+
187
+ Update the "Last reviewed" parenthetical to name the batch (e.g. `batch transition: P063 close, P067 close, P092 close, P094 close`).
188
+
189
+ **4b. Commit gate (per ADR-014).**
190
+
191
+ Satisfy via one of two paths (either produces a bypass marker):
192
+
193
+ - **Primary**: delegate to subagent type `wr-risk-scorer:pipeline` via the Agent tool.
194
+ - **Fallback** (per ADR-015 / P035): if `wr-risk-scorer:pipeline` is unavailable in the current tool set, invoke `/wr-risk-scorer:assess-release` via the Skill tool — `PostToolUse:Agent` writes the equivalent bypass marker. Do NOT silently skip the gate.
195
+
196
+ **4c. Commit ONCE.**
197
+
198
+ ONE commit covers: every surviving renamed ticket file + every Status edit + every `## Fix Released` section + the refreshed `docs/problems/README.md`. NO per-pair commits.
199
+
200
+ **Commit message conventions** (batch variants extending ADR-014's table):
201
+
202
+ - Homogeneous-destination batch: `docs(problems): batch transition — close P063, P067, P092, P094 (4 tickets)`
203
+ - Mixed-destination batch: `docs(problems): batch transition — P063 close, P070 known-error, P094 verifying (3 tickets)`
204
+ - If the batch destination is `verifying` and rides with a fix commit, the commit-message scope follows the singular's pattern: `fix(<scope>): <description> (closes P063, P067)` — but the batch surface is unusual in the riding-with-fix shape; the canonical caller is verification-close housekeeping, not fix-release.
205
+
206
+ If risk is above appetite and `AskUserQuestion` is available: ask whether to commit anyway, remediate first, or park. If `AskUserQuestion` is unavailable (AFK), skip the commit and report the uncommitted state per ADR-013 Rule 6 fail-safe — apply the same rule the singular does at the same gate.
207
+
208
+ ### 5. Report the outcome
209
+
210
+ Emit a structured summary:
211
+
212
+ ```
213
+ ## Batch transition summary
214
+
215
+ ### Succeeded ({N})
216
+ | Ticket | Previous status | New status | New filename |
217
+ |--------|-----------------|------------|--------------|
218
+ | P063 | Verification Pending | Closed | docs/problems/063-...closed.md |
219
+ | P067 | Verification Pending | Closed | docs/problems/067-...closed.md |
220
+ | ...
221
+
222
+ ### Failed ({M})
223
+ | Ticket | Destination | Reason |
224
+ |--------|-------------|--------|
225
+ | P099 | known-error | discovery-failed: no ticket found |
226
+ | P101 | verifying | invalid-transition: ticket is .open.md (must go to known-error first) |
227
+ | ...
228
+
229
+ Commit: {sha} ({N tickets committed in one batch})
230
+ ```
231
+
232
+ If zero pairs succeeded, the summary contains the Failed table only and explicitly notes "No commit — all pairs failed".
233
+
234
+ Release draining is owned by the caller (orchestrator Step 6.5 / manage-problem Step 12). This skill does NOT invoke `npm run push:watch` / `release:watch` on its own.
235
+
236
+ ## Ownership boundary
237
+
238
+ `transition-problems` (plural) owns:
239
+ - Pair-list parse + per-pair argument validation.
240
+ - Per-pair execution (inline copy of singular Steps 2–6) — discovery, transition-path validation, pre-flight, P063 detection, rename + Edit + P057 re-stage.
241
+ - Per-pair partial-failure tracking (skip-and-surface).
242
+ - ONE README.md refresh at the end (P062 at batch grain).
243
+ - ONE ADR-014 commit at the end through the risk-scorer commit gate.
244
+ - Structured per-pair outcome summary.
245
+
246
+ `transition-problems` does NOT:
247
+ - Re-invoke `/wr-itil:transition-problem` per pair via the Skill tool — that would re-introduce the N×SKILL.md-reload cost P117 targets. Inline copy per ADR-010 amended "copy, not move".
248
+ - Run per-pair commits — only the single batch commit at the end is permitted. The singular's per-invocation commit grain is deliberately re-aggregated at this skill's batch grain.
249
+ - Re-rank the backlog (use `/wr-itil:review-problems`).
250
+ - Create tickets or run the bare-`<NNN>` update flow (use `/wr-itil:manage-problem`).
251
+ - Park tickets (use `/wr-itil:manage-problem` — `.parked.md` has its own path).
252
+ - Drain the release queue (caller owns it).
253
+
254
+ ## Drift management (singular ↔ plural inline copy)
255
+
256
+ Per ADR-010 amended "Split-skill execution ownership", three call sites now share the per-ticket transition mechanic via "copy, not move":
257
+
258
+ 1. `/wr-itil:transition-problem` Steps 2–8 (singular, user-initiated single).
259
+ 2. `/wr-itil:transition-problems` Step 2 (this skill, user-initiated batch — inline copy of the singular's Steps 2–6, batch-aggregated commit replacing Step 8).
260
+ 3. `/wr-itil:manage-problem` in-skill Step 7 block (auto-transitions, Parked path, Step 9d closure).
261
+
262
+ Drift detection lives in the contract-assertion bats. `packages/itil/skills/transition-problems/test/transition-problems-contract.bats` asserts shared substring presence (e.g. the `git add docs/problems/` re-stage phrase) in both this file and the singular SKILL.md so a future edit that drops the re-stage rule from one is immediately visible.
263
+
264
+ When the per-ticket mechanic changes (e.g. a new pre-flight check or P063 token added), update ALL THREE copies in lockstep — the contract bats will fail otherwise, surfacing the drift.
265
+
266
+ ## Related
267
+
268
+ - **P117** (`docs/problems/117-no-batch-transition-for-multiple-problem-tickets.open.md`) — originating ticket. Closing 4+ tickets in one run-retro / manage-problem review costs N×SKILL.md reload OR an ownership-boundary violation; this skill closes that gap.
269
+ - **P071** (`docs/problems/071-argument-based-skill-subcommands-are-not-discoverable.open.md`) — singular/plural split precedent; established `work-problem`/`work-problems` and `list-problems`/`review-problems` siblings.
270
+ - **P093** (`docs/problems/093-transition-problem-and-manage-problem-circular-delegation-for-nnn-status-args.*.md`) — the circular-delegation ticket whose resolution gave the singular `transition-problem` ownership of the per-ticket mechanic. This skill extends that ownership to the batch grain.
271
+ - **P097** (`docs/problems/097-skill-md-runtime-size.open.md`) — the SKILL.md-runtime-size pressure cluster. P117 is a concrete cost case of P097's broader concern; this plural skill addresses the cost case directly.
272
+ - **ADR-010 amended** (`docs/decisions/010-rename-wr-problem-to-wr-itil.proposed.md` — Skill Granularity + Split-skill execution ownership) — authorises the singular/plural split AND the "copy, not move" inline-copy pattern.
273
+ - **ADR-013** — Rule 1 for interactive prompts; Rule 6 for the AFK non-interactive branch (P063 fallback inherited from the singular per pair).
274
+ - **ADR-014** — governance skills commit their own work. Batch grain is one unit of work — ONE commit at the end covering all surviving transitions.
275
+ - **ADR-022** — `.verifying.md` suffix on release; Verification Pending is a first-class status. Batch verification-close is a common caller (release-aged verifyings drained at the end of a session).
276
+ - **ADR-032** — governance skill invocation patterns. `/wr-itil:work-problems` may delegate batch closures here during AFK orchestration; this skill is foreground-synchronous in that delegation.
277
+ - **ADR-037** — contract-assertion bats pattern. The contract-bats for this skill ALSO performs cross-file drift detection between this SKILL.md and the singular's SKILL.md (the inline-copy invariant).
278
+ - **P057** — `git mv` + Edit staging trap; the per-pair re-stage rule applied N times in this skill's loop.
279
+ - **P062** — README.md refresh on every transition. At batch grain, the refresh fires ONCE at the end (single render covers all surviving renames).
280
+ - **P063** — external-root-cause detection at Open → Known Error. Fires per pair; AFK fallback inherited from the singular (append the stable Upstream report pending marker).
281
+ - **JTBD-001** (`docs/jtbd/solo-developer/JTBD-001-enforce-governance.proposed.md`) — eliminates the N×SKILL.md reload tax + ownership-boundary violation at batch closures; serves the "without slowing down" half of the job.
282
+ - **JTBD-006** (`docs/jtbd/solo-developer/JTBD-006-work-backlog-afk.proposed.md`) — work-problems orchestrator may delegate release-batched closures through this surface during extended AFK runs.
283
+ - **JTBD-101** (`docs/jtbd/plugin-developer/JTBD-101-extend-suite.proposed.md`) — singular/plural split is the established pattern; plugin-developers reading this should immediately recognise the shape.
284
+ - `packages/itil/skills/transition-problem/SKILL.md` — singular sibling. Source-of-truth for the per-ticket mechanic this skill carries an inline copy of. When the mechanic changes, update both files in lockstep.
285
+ - `packages/itil/skills/manage-problem/SKILL.md` — third call site of the per-ticket mechanic (in-skill Step 7 block). Per ADR-010 amended "copy, not move", three inline copies coexist.
286
+ - `packages/itil/skills/review-problems/SKILL.md` — sibling refresh skill; same README render contract this skill uses for the Step 4a refresh.
287
+ - `packages/itil/skills/work-problem/SKILL.md` and `packages/itil/skills/work-problems/SKILL.md` — singular/plural pair this skill mirrors.
288
+ - `packages/retrospective/skills/run-retro/SKILL.md` — Step 4a verification-close housekeeping is the canonical caller of this batch surface.
289
+
290
+ $ARGUMENTS
@@ -0,0 +1,276 @@
1
+ #!/usr/bin/env bats
2
+ # Contract assertions for /wr-itil:transition-problems (P117 plural sibling).
3
+ #
4
+ # This skill is the BATCH variant of /wr-itil:transition-problem — it
5
+ # advances multiple problem tickets through the lifecycle in one
6
+ # invocation. Mirrors the P071 singular/plural split precedent
7
+ # (work-problem vs work-problems) at a new grain: per-ticket transition
8
+ # (singular) vs batch transition (plural).
9
+ #
10
+ # Why this skill exists (P117):
11
+ # Closing N tickets via the singular skill costs N× SKILL.md reload
12
+ # into the caller's context — this is the very SKILL.md-runtime-size
13
+ # pressure P097 captures. The plural surface eliminates the N× cost
14
+ # by inlining the per-ticket mechanic and looping in-band, single
15
+ # commit at the end per ADR-014 batch grain.
16
+ #
17
+ # Architect-resolved design points (2026-04-26):
18
+ # 1. Partial-failure semantics: skip-and-surface (succeeded pairs
19
+ # commit at end; failed pairs surfaced in summary; zero successes
20
+ # means no commit).
21
+ # 2. Argument shape: space-separated `<NNN> <status> <NNN> <status>`
22
+ # pairs — same shape as singular repeated N times. No P prefix,
23
+ # no = separator, no CLI flags.
24
+ # 3. Inline per-ticket mechanic — "copy, not move" per ADR-010
25
+ # amended Split-skill execution ownership. NOT Skill-tool
26
+ # re-invocation back into the singular (would reintroduce the
27
+ # N×SKILL.md-reload cost the ticket targets).
28
+ # 4. Single commit at end + single README refresh at end (P062
29
+ # mechanic applied at batch grain).
30
+ # 5. Three call sites now share the per-ticket mechanic via "copy,
31
+ # not move": singular transition-problem, plural
32
+ # transition-problems (this skill), and manage-problem in-skill
33
+ # Step 7 block.
34
+ #
35
+ # Structural assertion — Permitted Exception to the source-grep ban
36
+ # (ADR-005 / P011 / ADR-037 contract-assertion pattern). SKILL.md is
37
+ # explicitly a contract document.
38
+ #
39
+ # @problem P117
40
+ # @problem P071
41
+ # @problem P093
42
+ # @jtbd JTBD-001 (enforce governance without slowing down — eliminates
43
+ # N×SKILL.md reload tax + ownership-boundary violation)
44
+ # @jtbd JTBD-006 (progress backlog while AFK — work-problems may
45
+ # delegate batch closures here without the per-ticket
46
+ # reload cost)
47
+ # @jtbd JTBD-101 (extend the suite with clear patterns — singular/plural
48
+ # split mirrors the P071 work-problem/work-problems
49
+ # precedent)
50
+ #
51
+ # Cross-reference:
52
+ # P117: docs/problems/117-no-batch-transition-for-multiple-problem-tickets.open.md
53
+ # P071: docs/problems/071-argument-based-skill-subcommands-are-not-discoverable.open.md
54
+ # P093: docs/problems/093-transition-problem-and-manage-problem-circular-delegation-for-nnn-status-args.*.md
55
+ # ADR-010 amended (Skill Granularity + Split-skill execution ownership) — copy-not-move guidance
56
+ # ADR-013 Rule 6 — AFK non-interactive fallback
57
+ # ADR-014 — single commit at batch-grain unit of work
58
+ # ADR-022 — .verifying.md suffix
59
+ # ADR-037 — contract-assertion bats pattern; canonical <skill>-contract.bats naming
60
+ # P057 — git mv + Edit staging trap (re-stage per pair)
61
+ # P062 — README.md refresh on transition (applied once at batch grain)
62
+ # P063 — external-root-cause detection at Open → Known Error
63
+
64
+ setup() {
65
+ SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
66
+ SKILL_FILE="${SKILL_DIR}/SKILL.md"
67
+ SINGULAR_SKILL_FILE="${SKILL_DIR}/../transition-problem/SKILL.md"
68
+ }
69
+
70
+ @test "SKILL.md exists and has frontmatter" {
71
+ [ -f "$SKILL_FILE" ]
72
+ run head -1 "$SKILL_FILE"
73
+ [ "$status" -eq 0 ]
74
+ [ "$output" = "---" ]
75
+ }
76
+
77
+ @test "SKILL.md frontmatter name is wr-itil:transition-problems (plural sibling)" {
78
+ # Plural naming convention per ADR-010 amended Skill Granularity rule.
79
+ # The trailing 's' marks the plural sibling — same shape as
80
+ # list-problems, review-problems, work-problems.
81
+ run grep -n "^name: wr-itil:transition-problems$" "$SKILL_FILE"
82
+ [ "$status" -eq 0 ]
83
+ }
84
+
85
+ @test "SKILL.md frontmatter description names the batch intent (P117)" {
86
+ # Description must name "batch" / "multiple" / "many" so Claude Code
87
+ # autocomplete distinguishes the plural from the singular at the
88
+ # autocomplete-discoverability surface.
89
+ run grep -inE "^description:.*(batch|multiple|many)" "$SKILL_FILE"
90
+ [ "$status" -eq 0 ]
91
+ # Description must also surface at least one of the destination
92
+ # status names so the user can correlate the skill with the
93
+ # lifecycle it operates on.
94
+ run grep -inE "^description:.*(known.error|verification|verifying|closed|close|lifecycle|transition|advance)" "$SKILL_FILE"
95
+ [ "$status" -eq 0 ]
96
+ }
97
+
98
+ @test "SKILL.md frontmatter allowed-tools includes Bash + Edit + Read + Skill + Agent" {
99
+ # Bash: ticket-file discovery + git mv + git add + git commit.
100
+ # Edit: Status field updates + ## Fix Released section writes.
101
+ # Read: ticket file inspection + README.md refresh source-of-truth.
102
+ # Skill: orchestrator composition (work-problems may delegate here).
103
+ # Agent: risk-scorer commit-gate delegation per ADR-014 + ADR-015.
104
+ run grep -nE "^allowed-tools:.*Bash" "$SKILL_FILE"
105
+ [ "$status" -eq 0 ]
106
+ run grep -nE "^allowed-tools:.*Edit" "$SKILL_FILE"
107
+ [ "$status" -eq 0 ]
108
+ run grep -nE "^allowed-tools:.*Read" "$SKILL_FILE"
109
+ [ "$status" -eq 0 ]
110
+ run grep -nE "^allowed-tools:.*Skill" "$SKILL_FILE"
111
+ [ "$status" -eq 0 ]
112
+ run grep -nE "^allowed-tools:.*Agent" "$SKILL_FILE"
113
+ [ "$status" -eq 0 ]
114
+ }
115
+
116
+ @test "SKILL.md cites P117 (originating ticket) and ADR-010 amended (split authorisation)" {
117
+ run grep -inE "P117" "$SKILL_FILE"
118
+ [ "$status" -eq 0 ]
119
+ run grep -inE "ADR-010" "$SKILL_FILE"
120
+ [ "$status" -eq 0 ]
121
+ }
122
+
123
+ @test "SKILL.md cites the work-problem/work-problems precedent (P071 singular/plural split)" {
124
+ # Plugin-developers reading this skill should immediately recognise
125
+ # the singular/plural split pattern. P071 + the work-problem/
126
+ # work-problems precedent is the explicit source.
127
+ run grep -inE "P071|work-problem" "$SKILL_FILE"
128
+ [ "$status" -eq 0 ]
129
+ }
130
+
131
+ @test "SKILL.md documents inline per-ticket mechanic — no Skill-tool delegation back to singular" {
132
+ # Architect-resolved design point 3: inline per-ticket mechanic per
133
+ # ADR-010 amended "copy, not move". Delegating back to the singular
134
+ # via the Skill tool would re-introduce the N×SKILL.md-reload cost
135
+ # this ticket targets — the core motivation for P117. The skill must
136
+ # NOT contain delegation-imperative language routing pair execution
137
+ # back to /wr-itil:transition-problem via Skill-tool invocation.
138
+ #
139
+ # Citations to the singular in the Related section or as a sibling
140
+ # source-of-truth are PERMITTED — this assertion targets
141
+ # delegation-imperative wording only.
142
+ run grep -inE "delegate.{0,40}(to |/)?/?wr-itil:transition-problem|Skill tool.{0,40}transition-problem|invoke /?wr-itil:transition-problem.{0,40}per pair|loop.{0,40}invoke /?wr-itil:transition-problem" "$SKILL_FILE"
143
+ [ "$status" -ne 0 ]
144
+ }
145
+
146
+ @test "SKILL.md documents the per-pair mechanic inline (Step 7 staging-trap rule + ## Fix Released)" {
147
+ # Positive assertion: the skill must describe the per-pair mechanic
148
+ # inline so a contract-literal agent has enough information to
149
+ # execute the batch without reading the singular's SKILL.md.
150
+ # Each mechanic is represented by at least one identifying phrase.
151
+ run grep -inE "pre-flight|pre.flight" "$SKILL_FILE"
152
+ [ "$status" -eq 0 ]
153
+ run grep -inE "git mv" "$SKILL_FILE"
154
+ [ "$status" -eq 0 ]
155
+ run grep -inE "git add" "$SKILL_FILE"
156
+ [ "$status" -eq 0 ]
157
+ run grep -inE "Fix Released" "$SKILL_FILE"
158
+ [ "$status" -eq 0 ]
159
+ }
160
+
161
+ @test "SKILL.md documents single-commit-at-end batch semantics (ADR-014 batch grain)" {
162
+ # Architect-resolved design point 4 + user direction: ONE commit
163
+ # covering all surviving transitions. The skill must say so
164
+ # explicitly and must NOT instruct per-pair commits.
165
+ run grep -inE "single commit|one commit|commit.{0,15}(at the )?end|batch commit|one (shared )?commit covering" "$SKILL_FILE"
166
+ [ "$status" -eq 0 ]
167
+ # Negative: no per-pair-commit instruction. Match wording like
168
+ # "commit each pair", "commit per pair", "commit per ticket".
169
+ run grep -inE "commit (each|per) (pair|ticket|transition)" "$SKILL_FILE"
170
+ [ "$status" -ne 0 ]
171
+ }
172
+
173
+ @test "SKILL.md documents single README refresh at end (P062 at batch grain)" {
174
+ # Architect-resolved design point 4: single render reflecting all
175
+ # surviving renames, not N renders. Cite P062 explicitly so the
176
+ # transitive contract is legible.
177
+ run grep -inE "P062" "$SKILL_FILE"
178
+ [ "$status" -eq 0 ]
179
+ run grep -inE "(refresh|render|regenerate).{0,50}(README|once|at end|at the end)|README.{0,80}(once|at end|at the end)" "$SKILL_FILE"
180
+ [ "$status" -eq 0 ]
181
+ }
182
+
183
+ @test "SKILL.md documents partial-failure skip-and-surface semantics" {
184
+ # Architect-resolved design point 1: failed pairs are skipped, NOT
185
+ # halted; succeeded pairs commit at end; zero successes means no
186
+ # commit. The skill must make this explicit so users know what
187
+ # outcome to expect when one ID is mistyped or one ticket is missing.
188
+ run grep -inE "partial.failure|partial failure|failed pair|skip.{0,30}(failed|invalid)|surface.{0,30}(failure|failed)|succeeded pair" "$SKILL_FILE"
189
+ [ "$status" -eq 0 ]
190
+ # Zero-success path must be explicit: no commit if zero pairs
191
+ # succeeded.
192
+ run grep -inE "zero (pairs )?succeed|no successful|no pairs? succeed|all (pairs? )?fail" "$SKILL_FILE"
193
+ [ "$status" -eq 0 ]
194
+ }
195
+
196
+ @test "SKILL.md cites P057 staging-trap rule (per-pair re-stage)" {
197
+ # The per-pair mechanic implements P057's re-stage rule (git add
198
+ # after Edit). Citation makes the transitive contract dependency
199
+ # legible.
200
+ run grep -inE "P057|staging.trap|re-stage" "$SKILL_FILE"
201
+ [ "$status" -eq 0 ]
202
+ }
203
+
204
+ @test "SKILL.md cites P063 external-root-cause detection (Open → Known Error per pair)" {
205
+ # P063 detection fires on every Open → Known Error transition,
206
+ # including those done via batch. The plural inherits the singular's
207
+ # AFK fallback (append the stable Upstream report pending marker).
208
+ run grep -inE "P063|external.root.cause|upstream report pending" "$SKILL_FILE"
209
+ [ "$status" -eq 0 ]
210
+ }
211
+
212
+ @test "SKILL.md cites ADR-022 (.verifying.md suffix on release)" {
213
+ # Known Error → Verification Pending is a common batch transition
214
+ # destination (release-batched closures). ADR-022 governs the
215
+ # .verifying.md suffix + ## Fix Released section semantics.
216
+ run grep -inE "ADR-022" "$SKILL_FILE"
217
+ [ "$status" -eq 0 ]
218
+ }
219
+
220
+ @test "SKILL.md cites ADR-013 Rule 6 AFK fallback (inherited from singular)" {
221
+ run grep -inE "AFK|non-interactive|ADR-013 Rule 6|Rule 6" "$SKILL_FILE"
222
+ [ "$status" -eq 0 ]
223
+ }
224
+
225
+ @test "SKILL.md cites ADR-037 / contract-assertion drift detection note (split-skill ownership)" {
226
+ # ADR-010 amended "copy, not move" creates drift risk between
227
+ # singular and plural. The skill's documentation should name the
228
+ # drift management strategy so future maintainers know how the
229
+ # copies stay in sync.
230
+ run grep -inE "ADR-010 amended|Split-skill execution ownership|copy.{0,5}not.{0,5}move" "$SKILL_FILE"
231
+ [ "$status" -eq 0 ]
232
+ }
233
+
234
+ @test "SKILL.md documents the argument shape (space-separated <NNN> <status> pairs)" {
235
+ # Argument shape per architect-resolved design point 2: repeating
236
+ # the singular's shape, no P prefix, no = separator, no CLI flags.
237
+ run grep -inE "<NNN>.{0,30}<status>|space.separated|pair.{0,5}of (arguments|tokens)|repeating .{0,30}arguments" "$SKILL_FILE"
238
+ [ "$status" -eq 0 ]
239
+ # Negative: no flag-style or = separator should be documented as
240
+ # the canonical shape.
241
+ run grep -inE "^\s*--pairs\b|<NNN>=<status>|<NNN>:<status>" "$SKILL_FILE"
242
+ [ "$status" -ne 0 ]
243
+ }
244
+
245
+ @test "SKILL.md does not carry a deprecated-arguments frontmatter flag (clean-split sibling)" {
246
+ # Architect: transition-problems is a clean-split sibling. The
247
+ # deprecated-arguments flag is only valid on host skills with
248
+ # forwarder routes — transition-problems is a clean addition with
249
+ # no prior subcommand surface to deprecate.
250
+ run grep -E "^deprecated-arguments:" "$SKILL_FILE"
251
+ [ "$status" -ne 0 ]
252
+ }
253
+
254
+ @test "SKILL.md names singular sibling in Related (ADR-037 traceability + drift management)" {
255
+ # Drift management: the plural carries an inline copy of the
256
+ # singular's per-ticket mechanic. The Related section must name the
257
+ # singular as the source-of-truth for the mechanic so future
258
+ # maintainers know where to update both copies in sync.
259
+ run grep -inE "wr-itil:transition-problem\b|/wr-itil:transition-problem|transition-problem/SKILL\.md|packages/itil/skills/transition-problem" "$SKILL_FILE"
260
+ [ "$status" -eq 0 ]
261
+ }
262
+
263
+ @test "SKILL.md and singular SKILL.md share the staging-trap pattern wording (drift detection)" {
264
+ # The per-pair mechanic on the plural carries an inline copy of the
265
+ # singular's git mv + Edit + git add re-stage rule. Drift detection
266
+ # at the contract level: the canonical 'git add' phrase must appear
267
+ # in both files so a future edit that drops the re-stage from one
268
+ # is immediately visible.
269
+ [ -f "$SINGULAR_SKILL_FILE" ]
270
+ run grep -cE "git add docs/problems/" "$SINGULAR_SKILL_FILE"
271
+ singular_count="$output"
272
+ run grep -cE "git add docs/problems/" "$SKILL_FILE"
273
+ plural_count="$output"
274
+ [ "$singular_count" -ge 1 ]
275
+ [ "$plural_count" -ge 1 ]
276
+ }