@windyroad/itil 2.0.0 → 2.1.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/.codex-plugin/plugin.json +1 -1
- package/bin/wr-itil-is-close-blocked +51 -0
- package/package.json +1 -1
- package/scripts/is-close-blocked.sh +93 -0
- package/skills/manage-problem/SKILL.md +34 -11
- package/skills/review-problems/SKILL.md +2 -2
- package/skills/transition-problem/SKILL.md +41 -5
- package/skills/transition-problems/SKILL.md +17 -3
- package/skills/update-upstream/SKILL.md +81 -9
- package/skills/work-problems/SKILL.md +52 -10
- package/skills-codex/manage-problem/SKILL.md +34 -11
- package/skills-codex/review-problems/SKILL.md +2 -2
- package/skills-codex/transition-problem/SKILL.md +41 -5
- package/skills-codex/transition-problems/SKILL.md +17 -3
- package/skills-codex/update-upstream/SKILL.md +81 -9
|
@@ -46,7 +46,7 @@ A space-separated list of `<NNN> <status>` pairs. Repeating the singular skill's
|
|
|
46
46
|
- `<status>` — destination status. One of:
|
|
47
47
|
- `known-error` — Open → Known Error (root cause + workaround documented).
|
|
48
48
|
- `verifying` — Known Error → Verification Pending (fix released; awaiting user verification per the "Problem lifecycle — add a Verification Pending status between Known Error and Closed" architecture rule).
|
|
49
|
-
- `close` — Verification Pending → Closed (user has confirmed the fix works in production).
|
|
49
|
+
- `close` — Verification Pending → Closed (cited evidence meets the ticket's own close criterion, OR the user has confirmed the fix works in production — see Step 2c).
|
|
50
50
|
|
|
51
51
|
**Examples:**
|
|
52
52
|
|
|
@@ -111,13 +111,19 @@ If no file is found OR multiple files are found (suffix-exclusive lifecycle viol
|
|
|
111
111
|
| `.open.md` | `known-error` | yes |
|
|
112
112
|
| `.known-error.md` | `verifying` | yes |
|
|
113
113
|
| `.verifying.md` | `close` | yes |
|
|
114
|
+
| `.verifying.md` | `known-error` | yes — **flip-back**: the fix recurred or proved incomplete. `review-problems` Bucket 3 already instructs this and had no batch path. |
|
|
115
|
+
| `.closed.md` | `known-error` | yes — **reopen**: a close was wrong. The recovery path every evidence-authorised close reports (the "The Verification Pending → Closed transition is reserved for the maintainer, so evidence-based closure never fires and the verification queue grows without bound" problem). |
|
|
114
116
|
| any other pairing | — | no — record as `invalid-transition` and continue |
|
|
115
117
|
|
|
118
|
+
Lockstep with `/wr-itil:transition-problem` Step 3 per the drift clause below — the singular and plural tables move together or neither moves. The two backward pairings are what make an agent-authorised close safe: the argument for closing on evidence without asking is that the close is cheap and reversible, and a reopen route either skill refuses would make that argument false. Both are ordinary renames; neither re-runs the Open → Known Error pre-flight (root cause and workaround were established the first time round) and neither fires the "Problem 063: manage-problem does not trigger /wr-itil:report-upstream when root cause is external" problem detection at 2d.
|
|
119
|
+
|
|
116
120
|
**2c. Run pre-flight checks** for the destination (same gating as the singular):
|
|
117
121
|
|
|
118
122
|
- 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 (the "Problem 047: WSJF effort buckets are coarse and not re-rated at lifecycle transitions" problem); status multiplier re-rated from Open 1.0 to Known Error 2.0 and WSJF recomputed with the post-transition status and current Effort (the "WSJF uses the pre-transition status multiplier" problem).
|
|
119
123
|
- Known Error → Verification Pending (`verifying`): fix implemented; release marker available (version, commit SHA, or date) for the `## Fix Released` section.
|
|
120
|
-
- Verification Pending → Closed (`close`): user
|
|
124
|
+
- Verification Pending → Closed (`close`): cited observed evidence or explicit user confirmation authorizes closure. Evidence-backed closure is mechanical and does not require another question. Record the citation and recovery path (`/wr-itil:transition-problem <NNN> known-error`) in each ticket's Status line. A provenance-proven GitHub issue on this project's tracker receives the gated comment and closes; unresolved or non-issue inbound provenance performs no issue mutation. A foreign issue receives the comment but stays open on local evidence alone; that upstream party's confirmation may authorize closure. Pull requests remain comment-only.
|
|
125
|
+
|
|
126
|
+
**Never close on inference** — absence of evidence is not evidence. A pair whose ticket carries no citation records as `pre-flight-failed` with reason `no-evidence` and stays Verification Pending; age, plausibility, and "the fix is on disk" are not observations. **Do-not-close marker check** — run `<itil-plugin-root>/bin/wr-itil-is-close-blocked <NNN> docs/problems` per pair before closing. Exit 0 → record the pair as `pre-flight-failed` with reason `close-blocked` plus the matched marker line, and continue to the next pair; do NOT close it whatever the evidence says. Exit 2 (unresolvable ref) is a pre-flight failure, not permission.
|
|
121
127
|
|
|
122
128
|
If any pre-flight fails, record the pair as `pre-flight-failed` with the failed-check list and continue to the next pair.
|
|
123
129
|
|
|
@@ -162,10 +168,18 @@ git add docs/problems/verifying/<NNN>-<title>.md
|
|
|
162
168
|
```bash
|
|
163
169
|
# Verification Pending → Closed
|
|
164
170
|
git mv docs/problems/verifying/<NNN>-<title>.md docs/problems/closed/<NNN>-<title>.md
|
|
165
|
-
# Edit Status field
|
|
171
|
+
# Edit Status field per the shape below
|
|
166
172
|
git add docs/problems/closed/<NNN>-<title>.md
|
|
167
173
|
```
|
|
168
174
|
|
|
175
|
+
**Write the close's authority basis into the Status field.** The Status line is the only place the basis survives — the `Likely verified?` cell lives in the README's Verification Queue table, and that row is deleted by this very transition, so a downstream reader (Step 7b's upstream leg) would find nothing there. Shape, matching what the 2026-07-15 closes already wrote (`docs/problems/closed/186-*.md:3`):
|
|
176
|
+
|
|
177
|
+
- Evidence-authorised: `**Status**: Closed (closed-on-evidence <YYYY-MM-DD> — <citation>. Recovery: rerun /wr-itil:transition-problem <NNN> known-error to reopen)`
|
|
178
|
+
- User-confirmed: `**Status**: Closed (user-confirmed <YYYY-MM-DD>)`
|
|
179
|
+
|
|
180
|
+
`closed-on-evidence` is what the outbound leg reads to keep a foreign issue open on our evidence alone. The inbound leg uses committed issue-channel provenance instead: ambiguity fails closed before any issue operation.
|
|
181
|
+
|
|
182
|
+
|
|
169
183
|
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.
|
|
170
184
|
|
|
171
185
|
Record each pair's outcome (succeeded / failed-with-reason) for the summary in Step 5.
|
|
@@ -178,7 +178,7 @@ Update from <downstream-repo-url>/<local-ticket-relative-path>:
|
|
|
178
178
|
|
|
179
179
|
<one-sentence summary from the local ticket's ## Fix Released section>
|
|
180
180
|
|
|
181
|
-
Please upgrade and verify when convenient. We'll close this issue after your confirmation
|
|
181
|
+
Please upgrade and verify when convenient. We'll close this issue after your confirmation. If you'd rather we closed it without one, say so here. Local tracking: P<NNN>.
|
|
182
182
|
```
|
|
183
183
|
|
|
184
184
|
#### Verification Pending → Closed template
|
|
@@ -186,12 +186,38 @@ Please upgrade and verify when convenient. We'll close this issue after your con
|
|
|
186
186
|
```markdown
|
|
187
187
|
Update from <downstream-repo-url>/<local-ticket-relative-path>:
|
|
188
188
|
|
|
189
|
-
**Status**: Closed locally after
|
|
189
|
+
**Status**: Closed locally after verification.
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
Thanks for the report — your filing is what got this on the queue. Local tracking: P<NNN>.
|
|
192
192
|
```
|
|
193
193
|
|
|
194
|
-
After posting the Verifying → Closed comment, the
|
|
194
|
+
After posting the Verifying → Closed comment, leave the foreign issue open by default. Closing it requires the target-bound upstream-party confirmation below.
|
|
195
|
+
|
|
196
|
+
#### Foreign issues close only on target-bound upstream-party confirmation
|
|
197
|
+
|
|
198
|
+
Local evidence or local user confirmation can close our ticket, but neither decides another maintainer's tracker state. Post the lifecycle comment and **stop there** unless the local ticket's `## Reported Upstream` section carries this durable, target-bound signal:
|
|
199
|
+
|
|
200
|
+
```markdown
|
|
201
|
+
- **Closure authority**: upstream-confirmed <exact GitHub issue-comment URL>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Before running `gh issue close`, validate that URL read-only: it MUST be an `#issuecomment-<id>` URL on the exact `UPSTREAM_OWNER_REPO/issues/UPSTREAM_ISSUE_NUMBER` target; `gh api repos/<owner>/<repo>/issues/comments/<id>` MUST return that exact issue URL; `author_association` MUST be `OWNER`, `MEMBER`, or `COLLABORATOR`; and the comment body MUST unambiguously authorize closing this issue. A missing marker, URL mismatch, API failure, non-maintainer association, or ambiguous body leaves the issue open. Never infer this authority from a local `user-confirmed` Status marker.
|
|
205
|
+
|
|
206
|
+
Read the Status line, not the README's `Likely verified?` cell: the close deletes that row from the Verification Queue before this step runs, so the cell is gone by the time anything could read it.
|
|
207
|
+
|
|
208
|
+
Confirmation from the upstream party may authorize closing their issue; their word, not our evidence, supplies the missing authority. Do not promise a quiet-period close that no mechanism delivers.
|
|
209
|
+
|
|
210
|
+
When target-bound confirmation is absent, use the evidence-authorised local-close-only variant below and record `posted-comment-local-close-only` in the back-write disclosure path. When validation succeeds, use the ordinary Closed template and record `posted-comment-and-closed`.
|
|
211
|
+
|
|
212
|
+
```markdown
|
|
213
|
+
Update from <downstream-repo-url>/<local-ticket-relative-path>:
|
|
214
|
+
|
|
215
|
+
**Status**: Closed locally. We verified the fix on our side — <one-line evidence citation>.
|
|
216
|
+
|
|
217
|
+
Leaving this issue open for you. Close it whenever you have confirmed the fix works in your setup. Local tracking: P<NNN>.
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
On this leg, without validated target-bound confirmation from them: comment, do not close. Pull requests are always comment-only, even if they carry a confirmation marker.
|
|
195
221
|
|
|
196
222
|
#### Template-filling rules
|
|
197
223
|
|
|
@@ -267,7 +293,7 @@ gh issue comment "${UPSTREAM_ISSUE_NUMBER}" \
|
|
|
267
293
|
|
|
268
294
|
Capture the returned comment URL (gh prints `https://github.com/<owner>/<repo>/issues/<n>#issuecomment-<id>`).
|
|
269
295
|
|
|
270
|
-
On the **Verifying → Closed** transition, after posting the comment,
|
|
296
|
+
On the **Verifying → Closed** transition, after posting the comment, close the upstream issue only when the target-bound `Closure authority` validation above passed:
|
|
271
297
|
|
|
272
298
|
```bash
|
|
273
299
|
gh issue close "${UPSTREAM_ISSUE_NUMBER}" \
|
|
@@ -298,7 +324,7 @@ Append a log entry to the local ticket's `## Upstream Lifecycle Updates` section
|
|
|
298
324
|
- **<YYYY-MM-DD>** — Open → Known Error
|
|
299
325
|
- **Target URL**: <upstream-issue-url>
|
|
300
326
|
- **Comment URL**: <posted-comment-url> (or "queued — see ## Queued Upstream Update" when above-appetite)
|
|
301
|
-
- **Disclosure path**: posted-comment | posted-pr-comment (pull-request target
|
|
327
|
+
- **Disclosure path**: posted-comment | posted-pr-comment (pull-request target — never closed) | posted-comment-and-closed (confirmed Verifying → Closed, issue targets only) | posted-comment-local-close-only (outbound evidence-authorised close) | queued-above-appetite | closed-already-upstream | skipped-out-of-band
|
|
302
328
|
- **Gate verdict**: external-comms <band/score> + voice-tone <pass|fail>
|
|
303
329
|
|
|
304
330
|
- **<YYYY-MM-DD>** — Known Error → Verification Pending
|
|
@@ -317,7 +343,51 @@ This leg runs **in addition to** Steps 2–6 (the outbound `## Reported Upstream
|
|
|
317
343
|
|
|
318
344
|
#### I1. Parse the inbound origin
|
|
319
345
|
|
|
320
|
-
From the `**Origin**: inbound-reported (#NN)` field, extract the
|
|
346
|
+
From the `**Origin**: inbound-reported (#NN)` field, extract the candidate number `NN`. That untyped number is not proof of an issue: issues, discussions, and advisories have distinct mutation paths, and numeric identifiers can collide.
|
|
347
|
+
|
|
348
|
+
Before any inbound `gh issue view`, `gh issue comment`, or `gh issue close`, prove the channel from the committed discovery cache:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
OWN_OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
|
|
352
|
+
LOCAL_TICKET_ID="P${LOCAL_ID}"
|
|
353
|
+
ISSUE_CHANNEL="github-issues:${OWN_OWNER_REPO}"
|
|
354
|
+
CACHE_REF="HEAD:docs/problems/.upstream-cache.json"
|
|
355
|
+
CACHE_JSON=$(git show "${CACHE_REF}" 2>/dev/null) || CACHE_JSON='{}'
|
|
356
|
+
|
|
357
|
+
ISSUE_NUMBER_MATCHES=$(printf '%s' "${CACHE_JSON}" | jq \
|
|
358
|
+
--arg channel "${ISSUE_CHANNEL}" \
|
|
359
|
+
--argjson number "${NN}" \
|
|
360
|
+
'[.channels[$channel].reports[]? | select(.number == $number)] | length' \
|
|
361
|
+
2>/dev/null) || ISSUE_NUMBER_MATCHES=0
|
|
362
|
+
|
|
363
|
+
ISSUE_TICKET_MATCHES=$(printf '%s' "${CACHE_JSON}" | jq \
|
|
364
|
+
--arg channel "${ISSUE_CHANNEL}" \
|
|
365
|
+
--argjson number "${NN}" \
|
|
366
|
+
--arg ticket "${LOCAL_TICKET_ID}" \
|
|
367
|
+
'[.channels[$channel].reports[]? |
|
|
368
|
+
select(.number == $number and .matched_local_ticket == $ticket)] | length' \
|
|
369
|
+
2>/dev/null) || ISSUE_TICKET_MATCHES=0
|
|
370
|
+
|
|
371
|
+
NON_ISSUE_MATCHES=$(printf '%s' "${CACHE_JSON}" | jq \
|
|
372
|
+
--arg issue_channel "${ISSUE_CHANNEL}" \
|
|
373
|
+
--arg repo_suffix ":${OWN_OWNER_REPO}" \
|
|
374
|
+
--argjson number "${NN}" \
|
|
375
|
+
'[.channels | to_entries[] |
|
|
376
|
+
select(.key != $issue_channel and (.key | endswith($repo_suffix))) |
|
|
377
|
+
.value.reports[]? | select(.number == $number)] | length' \
|
|
378
|
+
2>/dev/null) || NON_ISSUE_MATCHES=0
|
|
379
|
+
|
|
380
|
+
if [ "${ISSUE_NUMBER_MATCHES}" -ne 1 ] || \
|
|
381
|
+
[ "${ISSUE_TICKET_MATCHES}" -ne 1 ] || \
|
|
382
|
+
[ "${NON_ISSUE_MATCHES}" -ne 0 ]; then
|
|
383
|
+
echo "inbound-channel-unresolved: ${LOCAL_TICKET_ID} #${NN}"
|
|
384
|
+
INBOUND_CHANNEL_RESOLVED=0
|
|
385
|
+
else
|
|
386
|
+
INBOUND_CHANNEL_RESOLVED=1
|
|
387
|
+
fi
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
When `INBOUND_CHANNEL_RESOLVED=0`, skip I2–I6 and perform no inbound issue operation; an independent outbound leg may still continue. Missing committed cache data, zero or multiple issue matches, a repository mismatch, a wrong `matched_local_ticket`, or a discussion/advisory collision all take this path. If the Origin field is `internal` or absent, this leg does not run.
|
|
321
391
|
|
|
322
392
|
#### I2. Determine the transition (same suffix logic as Step 3)
|
|
323
393
|
|
|
@@ -441,12 +511,14 @@ Above-appetite handling is identical to Step 5c (silent risk-reduce + re-score;
|
|
|
441
511
|
gh issue comment "${NN}" --repo "${OWN_OWNER_REPO}" --body "${INBOUND_BODY}"
|
|
442
512
|
```
|
|
443
513
|
|
|
444
|
-
On the **Verification Pending → Closed** transition, after the comment,
|
|
514
|
+
On the **Verification Pending → Closed** transition, after the comment, close the provenance-proven issue on this project's tracker whether the local close was confirmed or evidence-authorised:
|
|
445
515
|
|
|
446
516
|
```bash
|
|
447
517
|
gh issue close "${NN}" --repo "${OWN_OWNER_REPO}" --comment "" --reason completed
|
|
448
518
|
```
|
|
449
519
|
|
|
520
|
+
This outbound guard does not apply to a provenance-proven GitHub issue on this project's own repository. After the gated comment, close it whether the local close was evidence-authorised or confirmed; the reporter can reopen it. Unknown or non-issue inbound channels already stopped at the provenance guard.
|
|
521
|
+
|
|
450
522
|
If the issue is already closed (someone closed it manually), `gh issue close` returns a benign error — record `closed-already` in the disclosure path and continue.
|
|
451
523
|
|
|
452
524
|
#### I6. Back-write to the lifecycle log
|
|
@@ -457,7 +529,7 @@ Append to the same `## Upstream Lifecycle Updates` log (Step 6 shape), tagged fo
|
|
|
457
529
|
- **<YYYY-MM-DD>** — Known Error → Verification Pending (inbound)
|
|
458
530
|
- **Target**: inbound #<NN> (own repo <OWN_OWNER_REPO>)
|
|
459
531
|
- **Comment URL**: <posted-comment-url> (or "skipped — already-posted-inbound" when the idempotency guard matched, or "queued — see ## Queued Upstream Update" when above-appetite)
|
|
460
|
-
- **Disclosure path**: posted-inbound-comment | posted-inbound-comment-and-closed (
|
|
532
|
+
- **Disclosure path**: posted-inbound-comment | posted-inbound-comment-and-closed (proven owned issue, confirmed or evidence-authorised close) | already-posted-inbound | queued-above-appetite | closed-already | inbound-channel-unresolved
|
|
461
533
|
- **Gate verdict**: external-comms <band/score> + voice-tone <pass|fail>
|
|
462
534
|
```
|
|
463
535
|
|