@windyroad/itil 0.35.10-preview.401 → 0.35.11-preview.403

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.
@@ -484,5 +484,5 @@
484
484
  }
485
485
  },
486
486
  "name": "wr-itil",
487
- "version": "0.35.10"
487
+ "version": "0.35.11"
488
488
  }
@@ -43,15 +43,18 @@
43
43
  # launching `claude` — inline-prefix syntax (`VAR=1 git commit ...`)
44
44
  # does NOT propagate from a Bash subshell to PreToolUse hooks (P173).
45
45
  # - Registered `RISK_BYPASS: <token>` commit-message trailer (P265) →
46
- # return 0 (allow). Narrow allow-list (currently only
47
- # `adr-031-migration`, the standalone ADR-031 layout-migration
48
- # commit, which is a rename-only change that legitimately stages no
49
- # README refresh). The trailer is read from the live `git commit`
50
- # command string at PreToolUse time (the commit message is not yet
51
- # written), matching the sibling `risk-score-commit-gate.sh`
52
- # recognition (P170 T11) so one logical migration commit clears both
53
- # gates. Registry of record: ADR-014 commit-message bypass-token
54
- # table.
46
+ # return 0 (allow). Narrow allow-list: `adr-031-migration` (the
47
+ # standalone ADR-031 layout-migration commit a rename-only change
48
+ # that legitimately stages no README refresh; also clears
49
+ # risk-score-commit-gate.sh) and `capture-deferred-readme` (the
50
+ # /wr-itil:capture-problem Step 6 commit, whose README refresh is
51
+ # deferred to /wr-itil:review-problems per ADR-032 — P262; this
52
+ # token clears THIS gate only, not the risk-score gate). The trailer
53
+ # is read from the live `git commit` command string at PreToolUse
54
+ # time (the commit message is not yet written), matching the sibling
55
+ # `risk-score-commit-gate.sh` recognition (P170 T11) for the shared
56
+ # `adr-031-migration` token. Registry of record: ADR-014
57
+ # commit-message bypass-token table.
55
58
  #
56
59
  # Narrative-only short-circuit (P230):
57
60
  # - When all staged ticket edits are purely narrative — no
@@ -129,7 +132,21 @@
129
132
  # risk-score-commit-gate.sh (P170 T11); both gates recognise it via
130
133
  # the identical grep below so one logical migration commit clears
131
134
  # both. Registry of record: ADR-014 commit-message bypass-token table.
132
- _README_REFRESH_BYPASS_TRAILERS=("adr-031-migration")
135
+ # capture-deferred-readme — the lightweight /wr-itil:capture-problem
136
+ # Step 6 commit (subject `docs(problems): capture P<NNN> ...`). Per
137
+ # ADR-032 the capture variant DEFERS the README refresh to the next
138
+ # /wr-itil:review-problems (capture-time speed is the load-bearing
139
+ # distinction from manage-problem's full-intake path), so the capture
140
+ # commit legitimately stages only the new ticket file. Without this
141
+ # token the P165 gate's new-ticket-is-ranking-bearing rule denied
142
+ # every capture commit (P262 — observed 4×/session). UNLIKE
143
+ # adr-031-migration this token clears the P165 README-refresh gate
144
+ # ONLY — it is intentionally NOT registered in
145
+ # risk-score-commit-gate.sh (a capture commit is real work and must
146
+ # be risk-scored normally; risk-score-commit-gate.sh hard-greps only
147
+ # `adr-031-migration`). Registry of record: ADR-014 commit-message
148
+ # bypass-token table (which documents the README-gate-only asymmetry).
149
+ _README_REFRESH_BYPASS_TRAILERS=("adr-031-migration" "capture-deferred-readme")
133
150
 
134
151
  # Returns 0 if the given `git commit` command string carries a
135
152
  # registered RISK_BYPASS trailer from the allow-list above. The grep
@@ -581,3 +581,62 @@ EOF
581
581
  [[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
582
582
  [ "${#output}" -eq 0 ]
583
583
  }
584
+
585
+ # --- P262: capture-deferred-readme RISK_BYPASS trailer allow-list bypass ---
586
+ #
587
+ # /wr-itil:capture-problem SKILL.md Step 6 deliberately stages ONLY the new
588
+ # ticket file and NOT docs/problems/README.md — the deferred-README-refresh
589
+ # contract is the load-bearing capture-time-speed distinction from
590
+ # /wr-itil:manage-problem (ADR-032). The P165 gate treats any new ticket
591
+ # file (status A) as ranking-bearing, so a bare capture commit was denied
592
+ # 4×/session. Architect verdict (P262): register a reason-named token
593
+ # `capture-deferred-readme` into the same P265 allow-list mechanism; the
594
+ # capture commit carries `RISK_BYPASS: capture-deferred-readme` in its
595
+ # message body. The carve-out is scoped to the TOKEN, not the commit
596
+ # subject — a `docs(problems): capture` subject WITHOUT the trailer still
597
+ # denies (proves the bypass cannot be self-claimed by message prose, and
598
+ # manage-problem's full-intake `docs(problems): open` path still enforces
599
+ # the refresh).
600
+
601
+ @test "P262 allow: capture commit with RISK_BYPASS: capture-deferred-readme trailer → allow silently" {
602
+ echo "# Problem 999" > docs/problems/open/999-capture.md
603
+ git add docs/problems/open/999-capture.md
604
+ run run_bash_hook "git commit -m 'docs(problems): capture P999 some-thing' -m 'RISK_BYPASS: capture-deferred-readme'"
605
+ [ "$status" -eq 0 ]
606
+ [[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
607
+ # Bypass is an allow path — silent per ADR-045 Pattern 1.
608
+ [ "${#output}" -eq 0 ]
609
+ }
610
+
611
+ @test "P262 deny: capture-subject commit WITHOUT the trailer still denies (token-scoped, not subject-scoped)" {
612
+ echo "# Problem 999" > docs/problems/open/999-capture.md
613
+ git add docs/problems/open/999-capture.md
614
+ run run_bash_hook "git commit -m 'docs(problems): capture P999 some-thing'"
615
+ [ "$status" -eq 0 ]
616
+ [[ "$output" == *"\"permissionDecision\": \"deny\""* ]]
617
+ [[ "$output" == *"P165"* ]]
618
+ }
619
+
620
+ @test "P262 deny: subject merely contains the word capture but no registered trailer still denies" {
621
+ echo "# Problem 999" > docs/problems/open/999-x.md
622
+ git add docs/problems/open/999-x.md
623
+ run run_bash_hook "git commit -m 'fix(itil): handle the capture edge case'"
624
+ [ "$status" -eq 0 ]
625
+ [[ "$output" == *"\"permissionDecision\": \"deny\""* ]]
626
+ }
627
+
628
+ @test "P262 deny: docs(problems): open (manage-problem full intake) without README still denies" {
629
+ echo "# Problem 999" > docs/problems/open/999-x.md
630
+ git add docs/problems/open/999-x.md
631
+ run run_bash_hook "git commit -m 'docs(problems): open P999 some-thing'"
632
+ [ "$status" -eq 0 ]
633
+ [[ "$output" == *"\"permissionDecision\": \"deny\""* ]]
634
+ }
635
+
636
+ @test "P262 deny: unregistered capture-ish token does NOT bypass (allow-list scope)" {
637
+ echo "# Problem 999" > docs/problems/open/999-x.md
638
+ git add docs/problems/open/999-x.md
639
+ run run_bash_hook "git commit -m 'docs(problems): capture P999 x' -m 'RISK_BYPASS: capture-something-else'"
640
+ [ "$status" -eq 0 ]
641
+ [[ "$output" == *"\"permissionDecision\": \"deny\""* ]]
642
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/itil",
3
- "version": "0.35.10-preview.401",
3
+ "version": "0.35.11-preview.403",
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"
@@ -257,14 +257,24 @@ Satisfy the commit gate per ADR-014 — same two-path pattern as manage-problem
257
257
  - **Primary**: delegate to subagent type `wr-risk-scorer:pipeline` via the Agent tool.
258
258
  - **Fallback**: invoke `/wr-risk-scorer:assess-release` via the Skill tool when the subagent type is unavailable in the current tool surface.
259
259
 
260
- Commit message:
260
+ Commit message — the body MUST carry the `RISK_BYPASS: capture-deferred-readme` trailer:
261
261
 
262
262
  ```
263
263
  docs(problems): capture P<NNN> <title>
264
+
265
+ RISK_BYPASS: capture-deferred-readme
264
266
  ```
265
267
 
266
268
  The `capture` verb in the message is the audit signal that this ticket landed via the lightweight aside path (vs. `open` for manage-problem's full intake).
267
269
 
270
+ **Why the trailer (P262)**: the P165 README-refresh-discipline hook (`packages/itil/hooks/itil-readme-refresh-discipline.sh`) treats any newly-staged ticket file as ranking-bearing and DENIES a `git commit` that does not also stage `docs/problems/README.md`. That enforcement is correct for `/wr-itil:manage-problem`'s full-intake path (P094 refresh-on-create) but conflicts with this skill's deliberate deferred-README-refresh contract. The `RISK_BYPASS: capture-deferred-readme` trailer is a registered allow-list token (P265 mechanism; registry of record is the ADR-014 commit-message bypass-token table) that clears the **README-refresh gate ONLY** — the commit is still risk-scored normally (`risk-score-commit-gate.sh` does not recognise this token). Emit the trailer via a second `-m` paragraph so the literal token appears in the `git commit` command string the PreToolUse hook inspects:
271
+
272
+ ```bash
273
+ git commit -m "docs(problems): capture P<NNN> <title>" -m "RISK_BYPASS: capture-deferred-readme"
274
+ ```
275
+
276
+ Do NOT drop the trailer and stage the README instead — that would silently abandon the deferred-README-refresh contract (the capture-time-speed distinction this skill exists to provide per ADR-032). The README is reconciled at the next `/wr-itil:review-problems` per Step 7's trailing pointer.
277
+
268
278
  ### 7. Report
269
279
 
270
280
  After the commit, report:
@@ -297,6 +307,8 @@ The two skills share the `/tmp/manage-problem-grep-${SESSION_ID}` create-gate ma
297
307
  - **P014** (`docs/problems/014-aside-invocation-for-governance-skills.open.md`) — parent / master tracker.
298
308
  - **P078** — capture-on-correction OFFER pattern; depends on capture-problem shipping.
299
309
  - **P119** — manage-problem create-gate hook; capture-problem composes with the same marker.
310
+ - **P262** — the P165 README-refresh-discipline hook conflicted with this skill's deferred-README-refresh contract (Step 6 "do NOT stage README" was denied by the hook on every capture commit). Resolved by the `RISK_BYPASS: capture-deferred-readme` allow-list token (Step 6 trailer above); clears the README-refresh gate only, not the risk-score gate.
311
+ - **P265** — the RISK_BYPASS-trailer allow-list mechanism in `readme-refresh-detect.sh` that P262's `capture-deferred-readme` token registers into.
300
312
  - **P170** (`docs/problems/170-...open.md`) — RFC framework driver; Slice 4 B7.T3 / item 8c authored the type-classification prompt at Step 1.5.
301
313
  - **P176** — agent-side I2 (no type-branching) coverage gap on the SKILL.md surface (this file's surface); descendant of P012 master harness ticket. The Step 1.5 I2 invariant guard is enforced by audit-trailed prose here per ADR-052 § Surface 2 escape-hatch contract; behavioural enforcement awaits the master harness.
302
314
  - **ADR-032** (`docs/decisions/032-governance-skill-invocation-patterns.proposed.md`) — foreground-lightweight-capture variant amendment.