@windyroad/itil 0.35.3-preview.352 → 0.35.4-preview.357

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.
@@ -2,479 +2,481 @@
2
2
  "description": "ITIL-aligned IT service management for Claude Code",
3
3
  "maturity": {
4
4
  "band": "Experimental",
5
- "schema_version": "2.0",
5
+ "bootstrapping": true,
6
6
  "hooks": {
7
7
  "itil-assistant-output-gate": {
8
8
  "band": "Experimental",
9
- "computed_at": "2026-05-18T01:29:14Z",
9
+ "computed_at": "2026-05-18T11:42:50Z",
10
10
  "evidence": {
11
11
  "breaking_change_age_days": null,
12
- "closed_tickets_window": 92,
13
- "days_shipped": 32,
12
+ "closed_tickets_window": 99,
13
+ "days_shipped": 33,
14
14
  "invocations_30d": null
15
15
  },
16
16
  "schema_version": "2.0"
17
17
  },
18
18
  "itil-assistant-output-review": {
19
19
  "band": "Experimental",
20
- "computed_at": "2026-05-18T01:29:14Z",
20
+ "computed_at": "2026-05-18T11:42:50Z",
21
21
  "evidence": {
22
22
  "breaking_change_age_days": null,
23
- "closed_tickets_window": 92,
24
- "days_shipped": 32,
23
+ "closed_tickets_window": 99,
24
+ "days_shipped": 33,
25
25
  "invocations_30d": null
26
26
  },
27
27
  "schema_version": "2.0"
28
28
  },
29
29
  "itil-bash-polling-antipattern-detect": {
30
30
  "band": "Experimental",
31
- "computed_at": "2026-05-18T01:29:14Z",
31
+ "computed_at": "2026-05-18T11:42:50Z",
32
32
  "evidence": {
33
33
  "breaking_change_age_days": null,
34
- "closed_tickets_window": 92,
35
- "days_shipped": 32,
34
+ "closed_tickets_window": 99,
35
+ "days_shipped": 33,
36
36
  "invocations_30d": null
37
37
  },
38
38
  "schema_version": "2.0"
39
39
  },
40
40
  "itil-changeset-discipline": {
41
41
  "band": "Experimental",
42
- "computed_at": "2026-05-18T01:29:14Z",
42
+ "computed_at": "2026-05-18T11:42:50Z",
43
43
  "evidence": {
44
44
  "breaking_change_age_days": null,
45
- "closed_tickets_window": 92,
46
- "days_shipped": 32,
45
+ "closed_tickets_window": 99,
46
+ "days_shipped": 33,
47
47
  "invocations_30d": null
48
48
  },
49
49
  "schema_version": "2.0"
50
50
  },
51
51
  "itil-claude-space-protection": {
52
52
  "band": "Experimental",
53
- "computed_at": "2026-05-18T01:29:14Z",
53
+ "computed_at": "2026-05-18T11:42:50Z",
54
54
  "evidence": {
55
55
  "breaking_change_age_days": null,
56
- "closed_tickets_window": 92,
57
- "days_shipped": 32,
56
+ "closed_tickets_window": 99,
57
+ "days_shipped": 33,
58
58
  "invocations_30d": null
59
59
  },
60
60
  "schema_version": "2.0"
61
61
  },
62
62
  "itil-correction-detect": {
63
63
  "band": "Experimental",
64
- "computed_at": "2026-05-18T01:29:14Z",
64
+ "computed_at": "2026-05-18T11:42:50Z",
65
65
  "evidence": {
66
66
  "breaking_change_age_days": null,
67
- "closed_tickets_window": 92,
68
- "days_shipped": 32,
67
+ "closed_tickets_window": 99,
68
+ "days_shipped": 33,
69
69
  "invocations_30d": null
70
70
  },
71
71
  "schema_version": "2.0"
72
72
  },
73
73
  "itil-fictional-defer-detect": {
74
74
  "band": "Experimental",
75
- "computed_at": "2026-05-18T01:29:14Z",
75
+ "computed_at": "2026-05-18T11:42:50Z",
76
76
  "evidence": {
77
77
  "breaking_change_age_days": null,
78
- "closed_tickets_window": 92,
79
- "days_shipped": 32,
78
+ "closed_tickets_window": 99,
79
+ "days_shipped": 33,
80
80
  "invocations_30d": null
81
81
  },
82
82
  "schema_version": "2.0"
83
83
  },
84
84
  "itil-mid-loop-ask-detect": {
85
85
  "band": "Experimental",
86
- "computed_at": "2026-05-18T01:29:14Z",
86
+ "computed_at": "2026-05-18T11:42:50Z",
87
87
  "evidence": {
88
88
  "breaking_change_age_days": null,
89
- "closed_tickets_window": 92,
90
- "days_shipped": 32,
89
+ "closed_tickets_window": 99,
90
+ "days_shipped": 33,
91
91
  "invocations_30d": null
92
92
  },
93
93
  "schema_version": "2.0"
94
94
  },
95
95
  "itil-pending-questions-surface": {
96
96
  "band": "Experimental",
97
- "computed_at": "2026-05-18T01:29:14Z",
97
+ "computed_at": "2026-05-18T11:42:50Z",
98
98
  "evidence": {
99
99
  "breaking_change_age_days": null,
100
- "closed_tickets_window": 92,
101
- "days_shipped": 32,
100
+ "closed_tickets_window": 99,
101
+ "days_shipped": 33,
102
102
  "invocations_30d": null
103
103
  },
104
104
  "schema_version": "2.0"
105
105
  },
106
106
  "itil-readme-refresh-discipline": {
107
107
  "band": "Experimental",
108
- "computed_at": "2026-05-18T01:29:14Z",
108
+ "computed_at": "2026-05-18T11:42:50Z",
109
109
  "evidence": {
110
110
  "breaking_change_age_days": null,
111
- "closed_tickets_window": 92,
112
- "days_shipped": 32,
111
+ "closed_tickets_window": 99,
112
+ "days_shipped": 33,
113
113
  "invocations_30d": null
114
114
  },
115
115
  "schema_version": "2.0"
116
116
  },
117
117
  "itil-rfc-trailer-advisory": {
118
118
  "band": "Experimental",
119
- "computed_at": "2026-05-18T01:29:14Z",
119
+ "computed_at": "2026-05-18T11:42:50Z",
120
120
  "evidence": {
121
121
  "breaking_change_age_days": null,
122
- "closed_tickets_window": 92,
123
- "days_shipped": 32,
122
+ "closed_tickets_window": 99,
123
+ "days_shipped": 33,
124
124
  "invocations_30d": null
125
125
  },
126
126
  "schema_version": "2.0"
127
127
  },
128
128
  "itil-runtime-sid-marker": {
129
129
  "band": "Experimental",
130
- "computed_at": "2026-05-18T01:29:14Z",
130
+ "computed_at": "2026-05-18T11:42:50Z",
131
131
  "evidence": {
132
132
  "breaking_change_age_days": null,
133
- "closed_tickets_window": 92,
134
- "days_shipped": 32,
133
+ "closed_tickets_window": 99,
134
+ "days_shipped": 33,
135
135
  "invocations_30d": null
136
136
  },
137
137
  "schema_version": "2.0"
138
138
  },
139
139
  "manage-problem-enforce-create": {
140
140
  "band": "Experimental",
141
- "computed_at": "2026-05-18T01:29:14Z",
141
+ "computed_at": "2026-05-18T11:42:50Z",
142
142
  "evidence": {
143
143
  "breaking_change_age_days": null,
144
- "closed_tickets_window": 92,
145
- "days_shipped": 32,
144
+ "closed_tickets_window": 99,
145
+ "days_shipped": 33,
146
146
  "invocations_30d": null
147
147
  },
148
148
  "schema_version": "2.0"
149
149
  },
150
150
  "p057-staging-trap-detect": {
151
151
  "band": "Experimental",
152
- "computed_at": "2026-05-18T01:29:14Z",
152
+ "computed_at": "2026-05-18T11:42:50Z",
153
153
  "evidence": {
154
154
  "breaking_change_age_days": null,
155
- "closed_tickets_window": 92,
156
- "days_shipped": 32,
155
+ "closed_tickets_window": 99,
156
+ "days_shipped": 33,
157
157
  "invocations_30d": null
158
158
  },
159
159
  "schema_version": "2.0"
160
160
  },
161
161
  "pre-publish-intake-gate": {
162
162
  "band": "Experimental",
163
- "computed_at": "2026-05-18T01:29:14Z",
163
+ "computed_at": "2026-05-18T11:42:50Z",
164
164
  "evidence": {
165
165
  "breaking_change_age_days": null,
166
- "closed_tickets_window": 92,
167
- "days_shipped": 32,
166
+ "closed_tickets_window": 99,
167
+ "days_shipped": 33,
168
168
  "invocations_30d": null
169
169
  },
170
170
  "schema_version": "2.0"
171
171
  }
172
172
  },
173
+ "rollup_invocations_30d": 327,
174
+ "schema_version": "2.0",
173
175
  "skills": {
174
176
  "capture-problem": {
175
177
  "band": "Experimental",
176
- "computed_at": "2026-05-18T01:29:14Z",
178
+ "computed_at": "2026-05-18T11:42:50Z",
177
179
  "evidence": {
178
180
  "breaking_change_age_days": null,
179
- "closed_tickets_window": 92,
180
- "days_shipped": 32,
181
- "invocations_30d": 57
181
+ "closed_tickets_window": 99,
182
+ "days_shipped": 33,
183
+ "invocations_30d": 61
182
184
  },
183
185
  "schema_version": "2.0"
184
186
  },
185
187
  "capture-rfc": {
186
188
  "band": "Experimental",
187
- "computed_at": "2026-05-18T01:29:14Z",
189
+ "computed_at": "2026-05-18T11:42:50Z",
188
190
  "evidence": {
189
191
  "breaking_change_age_days": null,
190
- "closed_tickets_window": 92,
191
- "days_shipped": 32,
192
+ "closed_tickets_window": 99,
193
+ "days_shipped": 33,
192
194
  "invocations_30d": 2
193
195
  },
194
196
  "schema_version": "2.0"
195
197
  },
196
198
  "capture-story": {
197
199
  "band": "Experimental",
198
- "computed_at": "2026-05-18T01:29:14Z",
200
+ "computed_at": "2026-05-18T11:42:50Z",
199
201
  "evidence": {
200
202
  "breaking_change_age_days": null,
201
- "closed_tickets_window": 92,
202
- "days_shipped": 32,
203
+ "closed_tickets_window": 99,
204
+ "days_shipped": 33,
203
205
  "invocations_30d": 0
204
206
  },
205
207
  "schema_version": "2.0"
206
208
  },
207
209
  "capture-story-map": {
208
210
  "band": "Experimental",
209
- "computed_at": "2026-05-18T01:29:14Z",
211
+ "computed_at": "2026-05-18T11:42:50Z",
210
212
  "evidence": {
211
213
  "breaking_change_age_days": null,
212
- "closed_tickets_window": 92,
213
- "days_shipped": 32,
214
+ "closed_tickets_window": 99,
215
+ "days_shipped": 33,
214
216
  "invocations_30d": 0
215
217
  },
216
218
  "schema_version": "2.0"
217
219
  },
218
220
  "check-upstream-responses": {
219
221
  "band": "Experimental",
220
- "computed_at": "2026-05-18T01:29:14Z",
222
+ "computed_at": "2026-05-18T11:42:50Z",
221
223
  "evidence": {
222
224
  "breaking_change_age_days": null,
223
- "closed_tickets_window": 92,
224
- "days_shipped": 32,
225
+ "closed_tickets_window": 99,
226
+ "days_shipped": 33,
225
227
  "invocations_30d": 0
226
228
  },
227
229
  "schema_version": "2.0"
228
230
  },
229
231
  "close-incident": {
230
232
  "band": "Experimental",
231
- "computed_at": "2026-05-18T01:29:14Z",
233
+ "computed_at": "2026-05-18T11:42:50Z",
232
234
  "evidence": {
233
235
  "breaking_change_age_days": null,
234
- "closed_tickets_window": 92,
235
- "days_shipped": 32,
236
+ "closed_tickets_window": 99,
237
+ "days_shipped": 33,
236
238
  "invocations_30d": 0
237
239
  },
238
240
  "schema_version": "2.0"
239
241
  },
240
242
  "link-incident": {
241
243
  "band": "Experimental",
242
- "computed_at": "2026-05-18T01:29:14Z",
244
+ "computed_at": "2026-05-18T11:42:50Z",
243
245
  "evidence": {
244
246
  "breaking_change_age_days": null,
245
- "closed_tickets_window": 92,
246
- "days_shipped": 32,
247
+ "closed_tickets_window": 99,
248
+ "days_shipped": 33,
247
249
  "invocations_30d": 0
248
250
  },
249
251
  "schema_version": "2.0"
250
252
  },
251
253
  "list-incidents": {
252
254
  "band": "Experimental",
253
- "computed_at": "2026-05-18T01:29:14Z",
255
+ "computed_at": "2026-05-18T11:42:50Z",
254
256
  "evidence": {
255
257
  "breaking_change_age_days": null,
256
- "closed_tickets_window": 92,
257
- "days_shipped": 32,
258
+ "closed_tickets_window": 99,
259
+ "days_shipped": 33,
258
260
  "invocations_30d": 0
259
261
  },
260
262
  "schema_version": "2.0"
261
263
  },
262
264
  "list-problems": {
263
265
  "band": "Experimental",
264
- "computed_at": "2026-05-18T01:29:14Z",
266
+ "computed_at": "2026-05-18T11:42:50Z",
265
267
  "evidence": {
266
268
  "breaking_change_age_days": null,
267
- "closed_tickets_window": 92,
268
- "days_shipped": 32,
269
+ "closed_tickets_window": 99,
270
+ "days_shipped": 33,
269
271
  "invocations_30d": 1
270
272
  },
271
273
  "schema_version": "2.0"
272
274
  },
273
275
  "list-stories": {
274
276
  "band": "Experimental",
275
- "computed_at": "2026-05-18T01:29:14Z",
277
+ "computed_at": "2026-05-18T11:42:50Z",
276
278
  "evidence": {
277
279
  "breaking_change_age_days": null,
278
- "closed_tickets_window": 92,
279
- "days_shipped": 32,
280
+ "closed_tickets_window": 99,
281
+ "days_shipped": 33,
280
282
  "invocations_30d": 0
281
283
  },
282
284
  "schema_version": "2.0"
283
285
  },
284
286
  "list-story-maps": {
285
287
  "band": "Experimental",
286
- "computed_at": "2026-05-18T01:29:14Z",
288
+ "computed_at": "2026-05-18T11:42:50Z",
287
289
  "evidence": {
288
290
  "breaking_change_age_days": null,
289
- "closed_tickets_window": 92,
290
- "days_shipped": 32,
291
+ "closed_tickets_window": 99,
292
+ "days_shipped": 33,
291
293
  "invocations_30d": 0
292
294
  },
293
295
  "schema_version": "2.0"
294
296
  },
295
297
  "manage-incident": {
296
298
  "band": "Experimental",
297
- "computed_at": "2026-05-18T01:29:14Z",
299
+ "computed_at": "2026-05-18T11:42:50Z",
298
300
  "evidence": {
299
301
  "breaking_change_age_days": null,
300
- "closed_tickets_window": 92,
301
- "days_shipped": 32,
302
+ "closed_tickets_window": 99,
303
+ "days_shipped": 33,
302
304
  "invocations_30d": 1
303
305
  },
304
306
  "schema_version": "2.0"
305
307
  },
306
308
  "manage-problem": {
307
309
  "band": "Alpha",
308
- "computed_at": "2026-05-18T01:29:14Z",
310
+ "computed_at": "2026-05-18T11:42:50Z",
309
311
  "evidence": {
310
312
  "breaking_change_age_days": null,
311
- "closed_tickets_window": 92,
312
- "days_shipped": 32,
313
- "invocations_30d": 153
313
+ "closed_tickets_window": 99,
314
+ "days_shipped": 33,
315
+ "invocations_30d": 148
314
316
  },
315
317
  "schema_version": "2.0"
316
318
  },
317
319
  "manage-rfc": {
318
320
  "band": "Experimental",
319
- "computed_at": "2026-05-18T01:29:14Z",
321
+ "computed_at": "2026-05-18T11:42:50Z",
320
322
  "evidence": {
321
323
  "breaking_change_age_days": null,
322
- "closed_tickets_window": 92,
323
- "days_shipped": 32,
324
+ "closed_tickets_window": 99,
325
+ "days_shipped": 33,
324
326
  "invocations_30d": 2
325
327
  },
326
328
  "schema_version": "2.0"
327
329
  },
328
330
  "manage-story": {
329
331
  "band": "Experimental",
330
- "computed_at": "2026-05-18T01:29:14Z",
332
+ "computed_at": "2026-05-18T11:42:50Z",
331
333
  "evidence": {
332
334
  "breaking_change_age_days": null,
333
- "closed_tickets_window": 92,
334
- "days_shipped": 32,
335
+ "closed_tickets_window": 99,
336
+ "days_shipped": 33,
335
337
  "invocations_30d": 0
336
338
  },
337
339
  "schema_version": "2.0"
338
340
  },
339
341
  "manage-story-map": {
340
342
  "band": "Experimental",
341
- "computed_at": "2026-05-18T01:29:14Z",
343
+ "computed_at": "2026-05-18T11:42:50Z",
342
344
  "evidence": {
343
345
  "breaking_change_age_days": null,
344
- "closed_tickets_window": 92,
345
- "days_shipped": 32,
346
+ "closed_tickets_window": 99,
347
+ "days_shipped": 33,
346
348
  "invocations_30d": 0
347
349
  },
348
350
  "schema_version": "2.0"
349
351
  },
350
352
  "mitigate-incident": {
351
353
  "band": "Experimental",
352
- "computed_at": "2026-05-18T01:29:14Z",
354
+ "computed_at": "2026-05-18T11:42:50Z",
353
355
  "evidence": {
354
356
  "breaking_change_age_days": null,
355
- "closed_tickets_window": 92,
356
- "days_shipped": 32,
357
+ "closed_tickets_window": 99,
358
+ "days_shipped": 33,
357
359
  "invocations_30d": 3
358
360
  },
359
361
  "schema_version": "2.0"
360
362
  },
361
363
  "reconcile-readme": {
362
364
  "band": "Experimental",
363
- "computed_at": "2026-05-18T01:29:14Z",
365
+ "computed_at": "2026-05-18T11:42:50Z",
364
366
  "evidence": {
365
367
  "breaking_change_age_days": null,
366
- "closed_tickets_window": 92,
367
- "days_shipped": 32,
368
- "invocations_30d": 36
368
+ "closed_tickets_window": 99,
369
+ "days_shipped": 33,
370
+ "invocations_30d": 38
369
371
  },
370
372
  "schema_version": "2.0"
371
373
  },
372
374
  "reconcile-stories": {
373
375
  "band": "Experimental",
374
- "computed_at": "2026-05-18T01:29:14Z",
376
+ "computed_at": "2026-05-18T11:42:50Z",
375
377
  "evidence": {
376
378
  "breaking_change_age_days": null,
377
- "closed_tickets_window": 92,
378
- "days_shipped": 32,
379
+ "closed_tickets_window": 99,
380
+ "days_shipped": 33,
379
381
  "invocations_30d": 0
380
382
  },
381
383
  "schema_version": "2.0"
382
384
  },
383
385
  "reconcile-story-maps": {
384
386
  "band": "Experimental",
385
- "computed_at": "2026-05-18T01:29:14Z",
387
+ "computed_at": "2026-05-18T11:42:50Z",
386
388
  "evidence": {
387
389
  "breaking_change_age_days": null,
388
- "closed_tickets_window": 92,
389
- "days_shipped": 32,
390
+ "closed_tickets_window": 99,
391
+ "days_shipped": 33,
390
392
  "invocations_30d": 0
391
393
  },
392
394
  "schema_version": "2.0"
393
395
  },
394
396
  "report-upstream": {
395
397
  "band": "Experimental",
396
- "computed_at": "2026-05-18T01:29:14Z",
398
+ "computed_at": "2026-05-18T11:42:50Z",
397
399
  "evidence": {
398
400
  "breaking_change_age_days": null,
399
- "closed_tickets_window": 92,
400
- "days_shipped": 32,
401
+ "closed_tickets_window": 99,
402
+ "days_shipped": 33,
401
403
  "invocations_30d": 15
402
404
  },
403
405
  "schema_version": "2.0"
404
406
  },
405
407
  "restore-incident": {
406
408
  "band": "Experimental",
407
- "computed_at": "2026-05-18T01:29:14Z",
409
+ "computed_at": "2026-05-18T11:42:50Z",
408
410
  "evidence": {
409
411
  "breaking_change_age_days": null,
410
- "closed_tickets_window": 92,
411
- "days_shipped": 32,
412
+ "closed_tickets_window": 99,
413
+ "days_shipped": 33,
412
414
  "invocations_30d": 4
413
415
  },
414
416
  "schema_version": "2.0"
415
417
  },
416
418
  "review-problems": {
417
419
  "band": "Experimental",
418
- "computed_at": "2026-05-18T01:29:14Z",
420
+ "computed_at": "2026-05-18T11:42:50Z",
419
421
  "evidence": {
420
422
  "breaking_change_age_days": null,
421
- "closed_tickets_window": 92,
422
- "days_shipped": 32,
423
+ "closed_tickets_window": 99,
424
+ "days_shipped": 33,
423
425
  "invocations_30d": 9
424
426
  },
425
427
  "schema_version": "2.0"
426
428
  },
427
429
  "scaffold-intake": {
428
430
  "band": "Experimental",
429
- "computed_at": "2026-05-18T01:29:14Z",
431
+ "computed_at": "2026-05-18T11:42:50Z",
430
432
  "evidence": {
431
433
  "breaking_change_age_days": null,
432
- "closed_tickets_window": 92,
433
- "days_shipped": 32,
434
+ "closed_tickets_window": 99,
435
+ "days_shipped": 33,
434
436
  "invocations_30d": 1
435
437
  },
436
438
  "schema_version": "2.0"
437
439
  },
438
440
  "transition-problem": {
439
441
  "band": "Experimental",
440
- "computed_at": "2026-05-18T01:29:14Z",
442
+ "computed_at": "2026-05-18T11:42:50Z",
441
443
  "evidence": {
442
444
  "breaking_change_age_days": null,
443
- "closed_tickets_window": 92,
444
- "days_shipped": 32,
445
- "invocations_30d": 27
445
+ "closed_tickets_window": 99,
446
+ "days_shipped": 33,
447
+ "invocations_30d": 28
446
448
  },
447
449
  "schema_version": "2.0"
448
450
  },
449
451
  "transition-problems": {
450
452
  "band": "Experimental",
451
- "computed_at": "2026-05-18T01:29:14Z",
453
+ "computed_at": "2026-05-18T11:42:50Z",
452
454
  "evidence": {
453
455
  "breaking_change_age_days": null,
454
- "closed_tickets_window": 92,
455
- "days_shipped": 32,
456
+ "closed_tickets_window": 99,
457
+ "days_shipped": 33,
456
458
  "invocations_30d": 6
457
459
  },
458
460
  "schema_version": "2.0"
459
461
  },
460
462
  "work-problem": {
461
463
  "band": "Experimental",
462
- "computed_at": "2026-05-18T01:29:14Z",
464
+ "computed_at": "2026-05-18T11:42:50Z",
463
465
  "evidence": {
464
466
  "breaking_change_age_days": null,
465
- "closed_tickets_window": 92,
466
- "days_shipped": 32,
467
+ "closed_tickets_window": 99,
468
+ "days_shipped": 33,
467
469
  "invocations_30d": 2
468
470
  },
469
471
  "schema_version": "2.0"
470
472
  },
471
473
  "work-problems": {
472
474
  "band": "Experimental",
473
- "computed_at": "2026-05-18T01:29:14Z",
475
+ "computed_at": "2026-05-18T11:42:50Z",
474
476
  "evidence": {
475
477
  "breaking_change_age_days": null,
476
- "closed_tickets_window": 92,
477
- "days_shipped": 32,
478
+ "closed_tickets_window": 99,
479
+ "days_shipped": 33,
478
480
  "invocations_30d": 6
479
481
  },
480
482
  "schema_version": "2.0"
@@ -482,5 +484,5 @@
482
484
  }
483
485
  },
484
486
  "name": "wr-itil",
485
- "version": "0.35.3"
487
+ "version": "0.35.4"
486
488
  }
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @windyroad/itil
2
2
 
3
- **ITIL-aligned IT service management for Claude Code.** Track recurring incidents, perform root cause analysis, and prioritise fixes using WSJF -- all inside your coding sessions. *Maturity: Experimental.*
3
+ **ITIL-aligned IT service management for Claude Code.** Track recurring incidents, perform root cause analysis, and prioritise fixes using WSJF -- all inside your coding sessions. *Maturity: Experimental (suite-bootstrap window; 327 invocations / 30d).*
4
4
 
5
5
  Part of [Windy Road Agent Plugins](../../README.md).
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/itil",
3
- "version": "0.35.3-preview.352",
3
+ "version": "0.35.4-preview.357",
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"
@@ -418,6 +418,12 @@ for pkg_dir in plugin_dirs:
418
418
  # NOT additive per ADR-058 §Confirmation #8.
419
419
  kind_to_key = {"skill": "skills", "agent": "agents", "hook": "hooks", "command": "commands"}
420
420
  surface_bands_for_rollup = []
421
+ # P269: collect per-surface invocations_30d across the populate pass so
422
+ # the rollup can carry the sum. Non-null integers participate in the sum;
423
+ # nulls (hook sentinel — architect §C) are excluded. All-null surface
424
+ # set yields a null rollup_invocations_30d to preserve the "not
425
+ # measurable" vs "measurably zero" honesty contract.
426
+ surface_invocations_for_rollup = []
421
427
 
422
428
  # Pre-read existing nested maturity payload so re-runs preserve any
423
429
  # forward-compat extras (architect issue 2: read-side line 417 fix).
@@ -450,6 +456,8 @@ for pkg_dir in plugin_dirs:
450
456
  maturity_record["schema_version"] = "2.0"
451
457
  new_map[name] = maturity_record
452
458
  surface_bands_for_rollup.append(maturity_record.get("band"))
459
+ rec_inv = maturity_record.get("evidence", {}).get("invocations_30d")
460
+ surface_invocations_for_rollup.append(rec_inv)
453
461
  new_maturity_kinds[key] = new_map
454
462
  wrote_records += len(new_map)
455
463
 
@@ -458,9 +466,31 @@ for pkg_dir in plugin_dirs:
458
466
  # at top level. Write-ordering fix (architect issue 2 line 441): build
459
467
  # the entire `maturity:` dict in a single assignment so the rollup
460
468
  # write does not clobber the per-kind nested maps.
469
+ #
470
+ # ADR-063 Amendment 2026-05-18 (P269 — rollup compound-evidence write):
471
+ # rollup additionally carries `rollup_invocations_30d` + `bootstrapping`
472
+ # so the Phase 3b renderer's AND-gated compound predicate
473
+ # (plugin-maturity-render.sh:146) can fire the
474
+ # `*Maturity: <Band> (suite-bootstrap window; <N> invocations / 30d).*`
475
+ # form during the bootstrapping window. Without these two fields the
476
+ # renderer falls through to bare-band, violating ADR-053 §Bootstrapping
477
+ # clause Phase 3 rendering requirement (line 88). Additive-within-2.0
478
+ # per ADR-058 §Confirmation #8 — old consumers reading
479
+ # `{schema_version, band}` continue to work; new consumers get the
480
+ # additional fields where present.
461
481
  rollup = rollup_band(surface_bands_for_rollup)
462
482
  if rollup is not None:
463
- maturity_doc = {"schema_version": "2.0", "band": rollup}
483
+ non_null_invs = [v for v in surface_invocations_for_rollup if isinstance(v, int)]
484
+ if non_null_invs:
485
+ rollup_invocations_30d = sum(non_null_invs)
486
+ else:
487
+ rollup_invocations_30d = None
488
+ maturity_doc = {
489
+ "schema_version": "2.0",
490
+ "band": rollup,
491
+ "rollup_invocations_30d": rollup_invocations_30d,
492
+ "bootstrapping": bootstrapping_active,
493
+ }
464
494
  maturity_doc.update(new_maturity_kinds)
465
495
  plugin_doc["maturity"] = maturity_doc
466
496
  else:
@@ -173,6 +173,60 @@ PYEOF
173
173
  done
174
174
  }
175
175
 
176
+ # ── P269 — rollup compound-evidence fields shape (when present) ─────────────
177
+
178
+ @test "plugin-maturity-doc-lint: rollup rollup_invocations_30d is int or null (when present)" {
179
+ # ADR-063 §Amendment 2026-05-18 (P269 — rollup compound-evidence write):
180
+ # the rollup carries `rollup_invocations_30d: integer | null`. Integer when
181
+ # at least one per-surface entry has a non-null invocations_30d; null when
182
+ # ALL per-surface entries are null (e.g. hook-only plugins) — preserves the
183
+ # "not measurable" vs "measurably zero" honesty contract per architect §C.
184
+ # Per ADR-063 §Confirmation #10 (shape-when-present), this lint asserts
185
+ # type-shape when the field is present and tolerates absence for plugins
186
+ # that haven't been re-populated since the P269 amendment.
187
+ local plugin
188
+ for plugin in $(plugins_with_maturity); do
189
+ local pj="$REPO_ROOT/packages/$plugin/.claude-plugin/plugin.json"
190
+ python3 <<PYEOF
191
+ import json, sys
192
+ d = json.load(open("$pj"))
193
+ m = d["maturity"]
194
+ if "rollup_invocations_30d" not in m:
195
+ sys.exit(0) # field absent — tolerated per shape-when-present
196
+ v = m["rollup_invocations_30d"]
197
+ if v is None:
198
+ sys.exit(0)
199
+ if not isinstance(v, int) or isinstance(v, bool):
200
+ sys.exit(f"$plugin: maturity.rollup_invocations_30d = {v!r} ({type(v).__name__}); must be int or null")
201
+ if v < 0:
202
+ sys.exit(f"$plugin: maturity.rollup_invocations_30d = {v!r}; must be non-negative")
203
+ PYEOF
204
+ done
205
+ }
206
+
207
+ @test "plugin-maturity-doc-lint: rollup bootstrapping is bool (when present)" {
208
+ # ADR-063 §Amendment 2026-05-18 (P269 — rollup compound-evidence write):
209
+ # the rollup carries `bootstrapping: bool` — populate-time snapshot of the
210
+ # bootstrapping-window state. The renderer's AND-gated compound predicate
211
+ # (plugin-maturity-render.sh:146) reads this flag to decide whether to
212
+ # emit the compound form. Shape-when-present per the same tolerance as
213
+ # rollup_invocations_30d above.
214
+ local plugin
215
+ for plugin in $(plugins_with_maturity); do
216
+ local pj="$REPO_ROOT/packages/$plugin/.claude-plugin/plugin.json"
217
+ python3 <<PYEOF
218
+ import json, sys
219
+ d = json.load(open("$pj"))
220
+ m = d["maturity"]
221
+ if "bootstrapping" not in m:
222
+ sys.exit(0)
223
+ v = m["bootstrapping"]
224
+ if not isinstance(v, bool):
225
+ sys.exit(f"$plugin: maturity.bootstrapping = {v!r} ({type(v).__name__}); must be bool")
226
+ PYEOF
227
+ done
228
+ }
229
+
176
230
  # ── Regression fence (architect adjustment A1, iter-11): no top-level kind maps ─
177
231
 
178
232
  @test "plugin-maturity-doc-lint: no top-level skills/agents/hooks/commands maturity-shaped records (iter-10 P0 hotfix fence)" {
@@ -343,9 +397,15 @@ PYEOF
343
397
  [ -f "$rdm" ] || continue # README absent — skip (no marker to check)
344
398
  local band
345
399
  band=$(python3 -c "import json; print(json.load(open('$pj'))['maturity']['band'])")
346
- # Anchored regex: `*Maturity: <band>` followed by `.` OR `(`.
347
- if ! grep -qE "\\*Maturity: ${band}[.(]" "$rdm"; then
348
- echo "$plugin: README missing badge marker *Maturity: ${band}<.|(>" >&2
400
+ # Anchored regex: `*Maturity: <band>` followed by `.` (bare form) OR
401
+ # ` (` (compound prefix space + open paren per the renderer's
402
+ # `*Maturity: <Band> (suite-bootstrap window; <N> invocations / 30d).*`
403
+ # output shape at plugin-maturity-render.sh line 147). P269 fold-fix:
404
+ # the previous `[.(]` character class missed the space-before-paren
405
+ # case that became visible across the live monorepo once compound
406
+ # rendering started firing post-rollout.
407
+ if ! grep -qE "\\*Maturity: ${band}(\\.| \\()" "$rdm"; then
408
+ echo "$plugin: README missing badge marker *Maturity: ${band}<.|space-paren>" >&2
349
409
  false
350
410
  fi
351
411
  done
@@ -298,7 +298,12 @@ print(obj if not isinstance(obj, (dict, list)) else json.dumps(obj))
298
298
  [ "$(get_json_field "$pj" "maturity.skills.manage-problem.evidence.closed_tickets_window")" = "5" ]
299
299
  }
300
300
 
301
- @test "plugin-maturity-populate: plugin root rollup carries schema_version + band only, no evidence" {
301
+ @test "plugin-maturity-populate: plugin root rollup carries schema_version + band + rollup_invocations_30d + bootstrapping, no evidence" {
302
+ # P269 amendment: rollup now carries rollup_invocations_30d (sum of non-null
303
+ # per-surface invocations_30d) + bootstrapping (snapshot of window state at
304
+ # populate time) so the renderer's AND-gated compound predicate
305
+ # (plugin-maturity-render.sh:146) can fire. The §evidence dict is still NOT
306
+ # written on the rollup — only at per-surface entries.
302
307
  make_plugin "rollupp" "skill:s1" "skill:s2"
303
308
  local trans="$FIXTURE_DIR/transcript.ndjson"
304
309
  local exer="$FIXTURE_DIR/exercise.ndjson"
@@ -318,6 +323,141 @@ print(obj if not isinstance(obj, (dict, list)) else json.dumps(obj))
318
323
  [ "$(get_json_field "$pj" "maturity.schema_version")" = "2.0" ]
319
324
  [ "$(get_json_field "$pj" "maturity.band")" != "MISSING" ]
320
325
  [ "$(get_json_field "$pj" "maturity.evidence")" = "MISSING" ]
326
+ [ "$(get_json_field "$pj" "maturity.rollup_invocations_30d")" != "MISSING" ]
327
+ [ "$(get_json_field "$pj" "maturity.bootstrapping")" != "MISSING" ]
328
+ }
329
+
330
+ # ── P269: rollup_invocations_30d sums non-null per-surface entries ───────────
331
+
332
+ @test "plugin-maturity-populate: rollup_invocations_30d equals sum of non-null per-surface invocations" {
333
+ # P269 fix details step 1: rollup_invocations_30d = sum across non-null
334
+ # per-surface entries. 200 + 1 = 201.
335
+ make_plugin "summp" "skill:s1" "skill:s2"
336
+ local trans="$FIXTURE_DIR/transcript.ndjson"
337
+ local exer="$FIXTURE_DIR/exercise.ndjson"
338
+ write_transcript_ndjson "$trans" \
339
+ "skill" "wr-summp:s1" 200 \
340
+ "skill" "wr-summp:s2" 1
341
+ write_exercise_ndjson "$exer" "summp" 10 20 2 NULL
342
+
343
+ run "$SCRIPT" \
344
+ --transcript-ndjson="$trans" \
345
+ --exercise-ndjson="$exer" \
346
+ --project-root="$PROJECT_ROOT" \
347
+ --now=2026-05-17T12:00:00Z
348
+ [ "$status" -eq 0 ]
349
+
350
+ local pj="$PROJECT_ROOT/packages/summp/.claude-plugin/plugin.json"
351
+ [ "$(get_json_field "$pj" "maturity.rollup_invocations_30d")" = "201" ]
352
+ }
353
+
354
+ # ── P269: rollup_invocations_30d sums non-null only (hooks excluded) ────────
355
+
356
+ @test "plugin-maturity-populate: rollup_invocations_30d excludes null hook surfaces from sum" {
357
+ # Mixed surfaces — a skill with invocations + a hook with null sentinel.
358
+ # The sum should equal the skill invocations alone; the null hook does NOT
359
+ # participate in the sum (architect §C null sentinel preserves
360
+ # "not measurable" vs "measurably zero" semantics).
361
+ make_plugin "mixp" "skill:thing" "hook:somehook"
362
+ local trans="$FIXTURE_DIR/transcript.ndjson"
363
+ local exer="$FIXTURE_DIR/exercise.ndjson"
364
+ write_transcript_ndjson "$trans" "skill" "wr-mixp:thing" 75
365
+ write_exercise_ndjson "$exer" "mixp" 10 20 2 NULL
366
+
367
+ run "$SCRIPT" \
368
+ --transcript-ndjson="$trans" \
369
+ --exercise-ndjson="$exer" \
370
+ --project-root="$PROJECT_ROOT" \
371
+ --now=2026-05-17T12:00:00Z
372
+ [ "$status" -eq 0 ]
373
+
374
+ local pj="$PROJECT_ROOT/packages/mixp/.claude-plugin/plugin.json"
375
+ [ "$(get_json_field "$pj" "maturity.rollup_invocations_30d")" = "75" ]
376
+ }
377
+
378
+ # ── P269: rollup_invocations_30d is null when ALL per-surface entries are null ─
379
+
380
+ @test "plugin-maturity-populate: rollup_invocations_30d is null on hook-only plugin" {
381
+ # Hook-only plugin: every per-surface invocations_30d is null. The rollup
382
+ # MUST emit null (not 0) so the renderer's AND-gated compound predicate
383
+ # falls through correctly — `0 invocations / 30d` would lie.
384
+ make_plugin "hookonly" "hook:a" "hook:b"
385
+ local trans="$FIXTURE_DIR/transcript.ndjson"
386
+ local exer="$FIXTURE_DIR/exercise.ndjson"
387
+ : >"$trans" # empty transcript — hooks never appear there
388
+ write_exercise_ndjson "$exer" "hookonly" 5 30 1 NULL
389
+
390
+ run "$SCRIPT" \
391
+ --transcript-ndjson="$trans" \
392
+ --exercise-ndjson="$exer" \
393
+ --project-root="$PROJECT_ROOT" \
394
+ --now=2026-05-17T12:00:00Z
395
+ [ "$status" -eq 0 ]
396
+
397
+ local pj="$PROJECT_ROOT/packages/hookonly/.claude-plugin/plugin.json"
398
+ # `get_json_field` collapses null to display "None"; check the raw JSON.
399
+ local raw
400
+ raw=$(python3 -c "
401
+ import json
402
+ obj = json.load(open('$pj'))
403
+ print(json.dumps(obj['maturity']['rollup_invocations_30d']))
404
+ ")
405
+ [ "$raw" = "null" ]
406
+ }
407
+
408
+ # ── P269: bootstrapping flag write — true during bootstrapping window ───────
409
+
410
+ @test "plugin-maturity-populate: rollup bootstrapping=true during bootstrapping window" {
411
+ # suite_oldest_days < 60 → bootstrapping active → rollup carries true.
412
+ make_plugin "bsp" "skill:s1"
413
+ local trans="$FIXTURE_DIR/transcript.ndjson"
414
+ local exer="$FIXTURE_DIR/exercise.ndjson"
415
+ write_transcript_ndjson "$trans" "skill" "wr-bsp:s1" 50
416
+ write_exercise_ndjson "$exer" "bsp" 10 20 2 NULL # days_shipped=20 < 60
417
+
418
+ run "$SCRIPT" \
419
+ --transcript-ndjson="$trans" \
420
+ --exercise-ndjson="$exer" \
421
+ --project-root="$PROJECT_ROOT" \
422
+ --now=2026-05-17T12:00:00Z
423
+ [ "$status" -eq 0 ]
424
+
425
+ local pj="$PROJECT_ROOT/packages/bsp/.claude-plugin/plugin.json"
426
+ local raw
427
+ raw=$(python3 -c "
428
+ import json
429
+ obj = json.load(open('$pj'))
430
+ print(json.dumps(obj['maturity']['bootstrapping']))
431
+ ")
432
+ [ "$raw" = "true" ]
433
+ }
434
+
435
+ # ── P269: bootstrapping flag write — false once max(days_shipped) ≥ 60 ──────
436
+
437
+ @test "plugin-maturity-populate: rollup bootstrapping=false once suite_oldest_days >= 60" {
438
+ # max(days_shipped) >= 60 → bootstrapping inactive → rollup carries false.
439
+ # Independent of --now (auto-derives from data per architect §D).
440
+ make_plugin "stp" "skill:s1"
441
+ local trans="$FIXTURE_DIR/transcript.ndjson"
442
+ local exer="$FIXTURE_DIR/exercise.ndjson"
443
+ write_transcript_ndjson "$trans" "skill" "wr-stp:s1" 50
444
+ write_exercise_ndjson "$exer" "stp" 100 200 15 NULL # days_shipped=200 >= 60
445
+
446
+ run "$SCRIPT" \
447
+ --transcript-ndjson="$trans" \
448
+ --exercise-ndjson="$exer" \
449
+ --project-root="$PROJECT_ROOT" \
450
+ --now=2026-05-17T12:00:00Z
451
+ [ "$status" -eq 0 ]
452
+
453
+ local pj="$PROJECT_ROOT/packages/stp/.claude-plugin/plugin.json"
454
+ local raw
455
+ raw=$(python3 -c "
456
+ import json
457
+ obj = json.load(open('$pj'))
458
+ print(json.dumps(obj['maturity']['bootstrapping']))
459
+ ")
460
+ [ "$raw" = "false" ]
321
461
  }
322
462
 
323
463
  # ── Granularity contract (ADR-063 #10): rollup = worst-case among surfaces ──
@@ -151,6 +151,64 @@ make_plugin() {
151
151
  [[ "$out" != *"invocations"* ]]
152
152
  }
153
153
 
154
+ # ── P269: AND-gated compound predicate — null rollup_invocations_30d → bare ─
155
+
156
+ @test "rollup badge: bootstrapping=true + rollup_invocations_30d=null → bare-band (hook-only plugin)" {
157
+ # P269: when populate writes bootstrapping=true but rollup_invocations_30d
158
+ # is null (hook-only plugin — no countable surfaces), the renderer's
159
+ # AND-gated compound predicate at plugin-maturity-render.sh:146 must fall
160
+ # through to bare-band. `0 invocations / 30d` would lie; bare-band is the
161
+ # honest fall-through.
162
+ make_plugin "hookonly" '{"name":"wr-hookonly","version":"0.1.0","description":"Hook-only","maturity":{"schema_version":"2.0","band":"Experimental","bootstrapping":true,"rollup_invocations_30d":null}}' \
163
+ "# @windyroad/hookonly
164
+
165
+ **Hook-only plugin description.**
166
+
167
+ ## Skills
168
+
169
+ | Skill | Purpose |
170
+ |-------|---------|
171
+ | /wr-hookonly:thing | Does a thing |
172
+ "
173
+
174
+ run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
175
+ [ "$status" -eq 0 ]
176
+
177
+ local out; out="$(cat "$PROJECT_ROOT/packages/hookonly/README.md")"
178
+ [[ "$out" == *"*Maturity: Experimental.*"* ]]
179
+ [[ "$out" != *"suite-bootstrap"* ]]
180
+ [[ "$out" != *"invocations"* ]]
181
+ }
182
+
183
+ # ── P269: AND-gated compound predicate — bootstrapping=false → bare-band ────
184
+
185
+ @test "rollup badge: bootstrapping=false + rollup_invocations_30d=integer → bare-band (post-sunset)" {
186
+ # P269: when bootstrapping has lapsed (suite_oldest_days >= 60), populate
187
+ # writes bootstrapping=false. Even with a non-null rollup_invocations_30d,
188
+ # the AND-gated predicate falls through to bare-band — the compound
189
+ # rendering is scoped to the bootstrapping window per ADR-053 §Bootstrapping
190
+ # clause Phase 3 rendering requirement.
191
+ make_plugin "stedp" '{"name":"wr-stedp","version":"0.1.0","description":"Steady","maturity":{"schema_version":"2.0","band":"Beta","bootstrapping":false,"rollup_invocations_30d":1500}}' \
192
+ "# @windyroad/stedp
193
+
194
+ **Steady-state plugin description.**
195
+
196
+ ## Skills
197
+
198
+ | Skill | Purpose |
199
+ |-------|---------|
200
+ | /wr-stedp:thing | Does a thing |
201
+ "
202
+
203
+ run bash "$SCRIPT" --project-root="$PROJECT_ROOT"
204
+ [ "$status" -eq 0 ]
205
+
206
+ local out; out="$(cat "$PROJECT_ROOT/packages/stedp/README.md")"
207
+ [[ "$out" == *"*Maturity: Beta.*"* ]]
208
+ [[ "$out" != *"suite-bootstrap"* ]]
209
+ [[ "$out" != *"invocations"* ]]
210
+ }
211
+
154
212
  # ── Confirmation #2 (ADR-063): per-skill Maturity column populated ──────────
155
213
 
156
214
  @test "per-skill column: adds Maturity column to existing Skills table" {