@windyroad/itil 0.61.1 → 0.61.2

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.
Files changed (171) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +7 -2
  3. package/agents/test/fixtures/proceed-new-genuinely-new.md +0 -43
  4. package/agents/test/fixtures/proceed-new-subtle-sibling.md +0 -47
  5. package/agents/test/fixtures/regression-p347-vs-p346.md +0 -54
  6. package/agents/test/hang-off-check.bats +0 -225
  7. package/hooks/test/block-list.bats +0 -153
  8. package/hooks/test/command-detect.bats +0 -181
  9. package/hooks/test/itil-assistant-output-gate.bats +0 -114
  10. package/hooks/test/itil-assistant-output-review.bats +0 -224
  11. package/hooks/test/itil-bash-polling-antipattern-detect.bats +0 -154
  12. package/hooks/test/itil-changeset-discipline.bats +0 -603
  13. package/hooks/test/itil-claude-space-protection.bats +0 -294
  14. package/hooks/test/itil-commit-trailer-transition-advisory.bats +0 -80
  15. package/hooks/test/itil-correction-detect.bats +0 -189
  16. package/hooks/test/itil-deferral-cadence-gate.bats +0 -187
  17. package/hooks/test/itil-fictional-defer-detect.bats +0 -292
  18. package/hooks/test/itil-fix-title-lifecycle-advisory.bats +0 -129
  19. package/hooks/test/itil-mid-loop-ask-detect.bats +0 -220
  20. package/hooks/test/itil-no-implement-draft-gate.bats +0 -210
  21. package/hooks/test/itil-pending-questions-surface.bats +0 -307
  22. package/hooks/test/itil-readme-refresh-discipline.bats +0 -642
  23. package/hooks/test/itil-rfc-oversight-nudge.bats +0 -83
  24. package/hooks/test/itil-rfc-trailer-advisory.bats +0 -375
  25. package/hooks/test/itil-story-mirror-migration-nudge.bats +0 -122
  26. package/hooks/test/manage-problem-enforce-create.bats +0 -424
  27. package/hooks/test/p057-staging-trap-detect.bats +0 -231
  28. package/hooks/test/pre-publish-intake-gate.bats +0 -144
  29. package/hooks/test/runtime-sid-marker.bats +0 -90
  30. package/hooks/test/session-id.bats +0 -370
  31. package/scripts/migrate-problems-add-type.sh +0 -116
  32. package/scripts/test/catchup-scan.bats +0 -274
  33. package/scripts/test/check-afk-accept-eligible.bats +0 -310
  34. package/scripts/test/check-fail-soft-skip-discipline.bats +0 -172
  35. package/scripts/test/check-fix-rfc-trace.bats +0 -164
  36. package/scripts/test/check-locale-discipline.bats +0 -291
  37. package/scripts/test/check-problems-readme-budget.bats +0 -192
  38. package/scripts/test/check-rfc-has-stories.bats +0 -69
  39. package/scripts/test/check-rfc-rejected-alternatives.bats +0 -108
  40. package/scripts/test/check-rfc-stories-ratified.bats +0 -82
  41. package/scripts/test/check-upstream-responses.bats +0 -503
  42. package/scripts/test/classify-readme-drift.bats +0 -392
  43. package/scripts/test/derive-first-dispatch.bats +0 -274
  44. package/scripts/test/derive-release-vehicle.bats +0 -454
  45. package/scripts/test/detect-unratified-stories-maps.bats +0 -60
  46. package/scripts/test/dual-tolerant-glob-rfc-002-t2.bats +0 -309
  47. package/scripts/test/effort-tally.bats +0 -170
  48. package/scripts/test/evaluate-relevance.bats +0 -773
  49. package/scripts/test/kind-a-commands.bats +0 -46
  50. package/scripts/test/mark-create-gate.bats +0 -59
  51. package/scripts/test/mark-story-oversight-confirmed.bats +0 -53
  52. package/scripts/test/migrate-problems-add-type.bats +0 -280
  53. package/scripts/test/migrate-story-status-mirror.bats +0 -167
  54. package/scripts/test/no-type-regression-guard.bats +0 -74
  55. package/scripts/test/oversight-mirror-corpus-lint.bats +0 -150
  56. package/scripts/test/plugin-exercise-index.bats +0 -386
  57. package/scripts/test/plugin-maturity-doc-lint.bats +0 -470
  58. package/scripts/test/plugin-maturity-populate.bats +0 -631
  59. package/scripts/test/plugin-maturity-render.bats +0 -469
  60. package/scripts/test/plugin-validate-ci-gate.bats +0 -208
  61. package/scripts/test/reconcile-readme.bats +0 -1007
  62. package/scripts/test/reconcile-rfcs.bats +0 -496
  63. package/scripts/test/reconcile-stories.bats +0 -173
  64. package/scripts/test/reconcile-story-maps.bats +0 -74
  65. package/scripts/test/release-watch-poll-loop.bats +0 -180
  66. package/scripts/test/resolve-governance-plugin-dirs.bats +0 -78
  67. package/scripts/test/rfc-stories-extension.bats +0 -175
  68. package/scripts/test/skill-invocations.bats +0 -535
  69. package/scripts/test/skill-md-dual-tolerant-coverage-rfc-002-t3.bats +0 -374
  70. package/scripts/test/story-oversight-lib.bats +0 -190
  71. package/scripts/test/update-jtbd-references-related-problems.bats +0 -178
  72. package/scripts/test/update-problem-references-section.bats +0 -242
  73. package/scripts/test/update-problem-rfcs-section.bats +0 -242
  74. package/scripts/test/update-references-section-sibling-helpers.bats +0 -80
  75. package/scripts/test/update-rfc-commits-section.bats +0 -77
  76. package/scripts/test/verify-iter-summary.bats +0 -196
  77. package/scripts/test/working-the-problem-traversal.bats +0 -116
  78. package/skills/capture-problem/test/capture-problem-step-1-5b-jtbd-trace.bats +0 -398
  79. package/skills/capture-problem/test/capture-problem.bats +0 -389
  80. package/skills/capture-story/test/capture-story-behavioural.bats +0 -317
  81. package/skills/capture-story-map/test/capture-story-map-behavioural.bats +0 -98
  82. package/skills/close-incident/test/close-incident-contract.bats +0 -146
  83. package/skills/link-incident/test/link-incident-contract.bats +0 -125
  84. package/skills/list-incidents/test/list-incidents-contract.bats +0 -115
  85. package/skills/list-problems/test/list-problems-contract.bats +0 -100
  86. package/skills/list-stories/test/list-stories-contract.bats +0 -127
  87. package/skills/list-story-maps/test/list-story-maps-contract.bats +0 -46
  88. package/skills/manage-incident/test/manage-incident-adr-044-contract.bats +0 -206
  89. package/skills/manage-incident/test/manage-incident-close-forwarder.bats +0 -67
  90. package/skills/manage-incident/test/manage-incident-link-forwarder.bats +0 -67
  91. package/skills/manage-incident/test/manage-incident-list-forwarder.bats +0 -68
  92. package/skills/manage-incident/test/manage-incident-mitigate-forwarder.bats +0 -66
  93. package/skills/manage-incident/test/manage-incident-restore-forwarder.bats +0 -66
  94. package/skills/manage-incident/test/manage-incident.bats +0 -171
  95. package/skills/manage-problem/test/manage-problem-adr-044-step4-derive-first.bats +0 -151
  96. package/skills/manage-problem/test/manage-problem-auto-migrate-step.bats +0 -53
  97. package/skills/manage-problem/test/manage-problem-concern-boundary.bats +0 -64
  98. package/skills/manage-problem/test/manage-problem-effort-buckets.bats +0 -56
  99. package/skills/manage-problem/test/manage-problem-external-root-cause-detection.bats +0 -119
  100. package/skills/manage-problem/test/manage-problem-first-run-intake-prompt.bats +0 -43
  101. package/skills/manage-problem/test/manage-problem-git-mv-restage-reminder.bats +0 -48
  102. package/skills/manage-problem/test/manage-problem-id-collision-guard.bats +0 -39
  103. package/skills/manage-problem/test/manage-problem-list-forwarder.bats +0 -66
  104. package/skills/manage-problem/test/manage-problem-next-id-origin-lookup.bats +0 -50
  105. package/skills/manage-problem/test/manage-problem-no-prose-options.bats +0 -74
  106. package/skills/manage-problem/test/manage-problem-output-formatting.bats +0 -30
  107. package/skills/manage-problem/test/manage-problem-parked-and-cache.bats +0 -73
  108. package/skills/manage-problem/test/manage-problem-readme-refresh-on-transition.bats +0 -62
  109. package/skills/manage-problem/test/manage-problem-readme-tie-break-order.bats +0 -318
  110. package/skills/manage-problem/test/manage-problem-readme-vq-sort-order.bats +0 -206
  111. package/skills/manage-problem/test/manage-problem-release-vehicle-seed.bats +0 -83
  112. package/skills/manage-problem/test/manage-problem-review-forwarder.bats +0 -71
  113. package/skills/manage-problem/test/manage-problem-step-9d-recovery-path.bats +0 -97
  114. package/skills/manage-problem/test/manage-problem-transition-forwarder.bats +0 -96
  115. package/skills/manage-problem/test/manage-problem-transitive-dependencies.bats +0 -365
  116. package/skills/manage-problem/test/manage-problem-verification-detection.bats +0 -64
  117. package/skills/manage-problem/test/manage-problem-verification-pending.bats +0 -114
  118. package/skills/manage-problem/test/manage-problem-work-forwarder.bats +0 -88
  119. package/skills/manage-story/test/manage-story-contract.bats +0 -174
  120. package/skills/manage-story-map/test/manage-story-map-contract.bats +0 -63
  121. package/skills/mitigate-incident/test/mitigate-incident-contract.bats +0 -258
  122. package/skills/reconcile-readme/test/reconcile-readme-contract.bats +0 -201
  123. package/skills/report-upstream/test/report-upstream-contract.bats +0 -394
  124. package/skills/restore-incident/test/restore-incident-contract.bats +0 -170
  125. package/skills/review-problems/test/inbound-channels-cache-shape.bats +0 -127
  126. package/skills/review-problems/test/inbound-discovery-contract.bats +0 -383
  127. package/skills/review-problems/test/jtbd-301-verdict-shape-contract.bats +0 -225
  128. package/skills/review-problems/test/review-problems-contract.bats +0 -235
  129. package/skills/review-problems/test/review-problems-likely-verified-cell-shape.bats +0 -229
  130. package/skills/scaffold-intake/test/scaffold-intake-contract.bats +0 -126
  131. package/skills/scaffold-intake/test/scaffold-intake-fixture.bats +0 -164
  132. package/skills/scaffold-intake/test/scaffold-intake-secrets-absent.bats +0 -87
  133. package/skills/transition-problem/test/transition-problem-contract.bats +0 -285
  134. package/skills/transition-problems/test/transition-problems-contract.bats +0 -331
  135. package/skills/update-upstream/test/update-upstream-contract.bats +0 -375
  136. package/skills/work-problem/test/work-problem-contract.bats +0 -294
  137. package/skills/work-problems/test/work-problems-above-appetite-remediation.bats +0 -139
  138. package/skills/work-problems/test/work-problems-adr-013-rule-6-p352-amendment.bats +0 -166
  139. package/skills/work-problems/test/work-problems-auto-migrate-step.bats +0 -57
  140. package/skills/work-problems/test/work-problems-cost-logging.bats +0 -109
  141. package/skills/work-problems/test/work-problems-deviation-candidate-shape.bats +0 -121
  142. package/skills/work-problems/test/work-problems-first-run-intake-prompt.bats +0 -36
  143. package/skills/work-problems/test/work-problems-inter-iteration-verify.bats +0 -59
  144. package/skills/work-problems/test/work-problems-mid-loop-userpromptsubmit-handler.bats +0 -69
  145. package/skills/work-problems/test/work-problems-no-mid-loop-asking.bats +0 -192
  146. package/skills/work-problems/test/work-problems-p341-pre-all-done-gate.bats +0 -122
  147. package/skills/work-problems/test/work-problems-p342-r007-derive-then-pass-flags.bats +0 -170
  148. package/skills/work-problems/test/work-problems-p342-retro-auto-ticket-carveout.bats +0 -120
  149. package/skills/work-problems/test/work-problems-preflight-failure-handling.bats +0 -248
  150. package/skills/work-problems/test/work-problems-preflight-session-continuity.bats +0 -139
  151. package/skills/work-problems/test/work-problems-preflight.bats +0 -69
  152. package/skills/work-problems/test/work-problems-release-cadence.bats +0 -63
  153. package/skills/work-problems/test/work-problems-step-0-iter-error-staleness.bats +0 -93
  154. package/skills/work-problems/test/work-problems-step-0b-cache-staleness-behavioural.bats +0 -138
  155. package/skills/work-problems/test/work-problems-step-0c-deferred-placeholder-staleness-behavioural.bats +0 -238
  156. package/skills/work-problems/test/work-problems-step-0d-outbound-responses-staleness-behavioural.bats +0 -174
  157. package/skills/work-problems/test/work-problems-step-2-5-routing.bats +0 -80
  158. package/skills/work-problems/test/work-problems-step-2-5b-cross-halt-routing.bats +0 -149
  159. package/skills/work-problems/test/work-problems-step-3-5-jtbd-ratification-predicate.bats +0 -191
  160. package/skills/work-problems/test/work-problems-step-5-bats-polling-discipline.bats +0 -91
  161. package/skills/work-problems/test/work-problems-step-5-delegation.bats +0 -333
  162. package/skills/work-problems/test/work-problems-step-5-idle-timeout-sigterm.bats +0 -421
  163. package/skills/work-problems/test/work-problems-step-5-is-error-transient-halt.bats +0 -278
  164. package/skills/work-problems/test/work-problems-step-5-iter-changeset-required.bats +0 -95
  165. package/skills/work-problems/test/work-problems-step-5-prompt-body-re-grounding.bats +0 -128
  166. package/skills/work-problems/test/work-problems-step-5-stream-timeout-salvage.bats +0 -251
  167. package/skills/work-problems/test/work-problems-step-6-5-always-drain.bats +0 -203
  168. package/skills/work-problems/test/work-problems-step-6-5-cache-refresh-chain.bats +0 -174
  169. package/skills/work-problems/test/work-problems-step-6-5-fix-and-continue.bats +0 -254
  170. package/skills/work-problems/test/work-problems-step-6-5-postrelease-kv-callback.bats +0 -209
  171. package/skills/work-problems/test/work-problems-stop-condition-questions.bats +0 -85
@@ -1,251 +0,0 @@
1
- #!/usr/bin/env bats
2
- # tdd-review: structural-permitted (justification: the doc-lint slice below
3
- # asserts SKILL.md / ADR-032 prose contract — SKILL.md is the contract
4
- # document per ADR-037 Permitted Exception; these guards catch prose drift
5
- # away from the behavioural SALVAGE/HALT contract exercised above. The
6
- # load-bearing core of this fixture is behavioural per ADR-052. harness-gap P012)
7
- #
8
- # Behavioural test: work-problems Step 5 exit-code semantics — the is_error:true
9
- # stream-timeout SALVAGE carve-out (P261). When an iter subprocess returns
10
- # `is_error: true` (e.g. `API Error: Stream idle timeout - partial response
11
- # received`) AFTER staging coherent work but BEFORE `git commit`, the staged
12
- # work survives in the working tree. The orchestrator's salvage decision logic
13
- # is: IF is_error:true AND staged files exist AND iter-authored bats pass →
14
- # SALVAGE (commit the staged work from the main turn with iter-attribution; the
15
- # commit gate fires fresh). ELSE → HALT per the existing exit-code contract.
16
- #
17
- # This is a NEW recovery branch, distinct from:
18
- # - P121 (SIGTERM idle-timeout — is_error:false clean exit-flush; subprocess
19
- # HAD committed before going idle)
20
- # - P147 (SIGTERM stuck-before-emit — exit 143 + 0-byte JSON; metadata lost)
21
- # - P146 (bash-polling antipattern — the deadlock mechanism behind P147)
22
- # The stream-timeout class preserves metadata in the JSON envelope AND the
23
- # staged files; the iter exits on its own with is_error:true (no SIGTERM).
24
- #
25
- # The fake-stuck-shim below re-creates the production shape: it stages coherent
26
- # work in the repo, then emits an is_error:true stream-timeout JSON envelope
27
- # (no ITERATION_SUMMARY, no commit). The harness re-implements the orchestrator's
28
- # SALVAGE-vs-HALT decision contract (faithful to SKILL.md Step 5) and asserts the
29
- # branch outcome across the four input shapes. Adopters who copy the SKILL.md
30
- # Step 5 exit-code block into their orchestrator should observe the same outcomes.
31
- #
32
- # @problem P261
33
- # @jtbd JTBD-006
34
- # @jtbd JTBD-001
35
- #
36
- # Cross-reference:
37
- # P261 (iter subprocess API stream-timeout salvage path) — driver ticket
38
- # ADR-032 (governance skill invocation patterns — is_error:true stream-timeout
39
- # salvage sub-variant, P261 amendment) — the carved-out commit-authorship
40
- # contract this fixture pins
41
- # ADR-009 (gate-marker-lifecycle — is_error:true subprocess MUST NOT extend
42
- # parent trust window; salvage commit fires the gate fresh on the
43
- # orchestrator's own SESSION_ID)
44
- # ADR-014 (single-commit grain — the salvage commit IS the iteration's one
45
- # commit; amend-folding is inapplicable because no iter commit exists)
46
- # ADR-037 / ADR-052 (skill testing strategy — behavioural default; doc-lint
47
- # contract assertion is the Permitted Exception, marked above)
48
-
49
- setup() {
50
- TEST_TMP="$(mktemp -d)"
51
- FAKE_BIN="${TEST_TMP}/bin"
52
- mkdir -p "$FAKE_BIN"
53
-
54
- # Fake `claude` binary simulating a stuck iteration subprocess of the
55
- # stream-timeout class: it stages coherent work in the CWD git repo, then
56
- # emits an is_error:true JSON envelope carrying the stream-timeout error
57
- # string in `.result`. No ITERATION_SUMMARY; no commit. This matches the
58
- # 2026-05-18 session-6 iter-4 shape captured in P261: 7 files staged, then
59
- # `API Error: Stream idle timeout - partial response received`.
60
- cat > "$FAKE_BIN/claude" <<'FAKE_EOF'
61
- #!/usr/bin/env bash
62
- # Test fake for work-problems Step 5 P261 stream-timeout salvage fixture.
63
- # Stages coherent work, then emits is_error:true stream-timeout JSON.
64
- if [ "${FAKE_STAGE_WORK:-1}" = "1" ]; then
65
- printf 'salvaged SKILL amendment + bats fixture\n' > staged-iter-work.txt
66
- git add staged-iter-work.txt 2>/dev/null || true
67
- fi
68
- if [ "${FAKE_IS_ERROR:-true}" = "true" ]; then
69
- printf '%s\n' '{"is_error":true,"result":"API Error: Stream idle timeout - partial response received","total_cost_usd":12.91,"duration_ms":300000,"usage":{"input_tokens":1000,"output_tokens":2000,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}'
70
- else
71
- printf '%s\n' '{"is_error":false,"result":"ITERATION_SUMMARY\nticket_id: P000\naction: worked\noutcome: investigated\ncommitted: true\nremaining_backlog_count: 0\nnotes: normal exit","total_cost_usd":0.5,"duration_ms":1000,"usage":{"input_tokens":10,"output_tokens":20,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}'
72
- fi
73
- FAKE_EOF
74
- chmod +x "$FAKE_BIN/claude"
75
-
76
- # Fake `iter_bats` stub — stands in for running the iter-authored bats
77
- # fixtures as the salvage path's step-1 structural sanity check. Its exit
78
- # code is controlled by FAKE_BATS_EXIT (0 = green, 1 = fail) so the harness
79
- # can exercise both the bats-green and bats-fail branches behaviourally.
80
- cat > "$FAKE_BIN/iter_bats" <<'FAKE_EOF'
81
- #!/usr/bin/env bash
82
- exit "${FAKE_BATS_EXIT:-0}"
83
- FAKE_EOF
84
- chmod +x "$FAKE_BIN/iter_bats"
85
- export PATH="$FAKE_BIN:$PATH"
86
-
87
- # A throwaway git repo so staged-work detection + the salvage commit are real.
88
- REPO="${TEST_TMP}/repo"
89
- mkdir -p "$REPO"
90
- git -C "$REPO" init -q
91
- git -C "$REPO" config user.email "test@example.com"
92
- git -C "$REPO" config user.name "Test"
93
- git -C "$REPO" commit -q --allow-empty -m "root"
94
-
95
- SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
96
- SKILL_FILE="${SKILL_DIR}/SKILL.md"
97
- ADR_FILE="$(cd "${SKILL_DIR}/../../../.." && pwd)/docs/decisions/032-governance-skill-invocation-patterns.proposed.md"
98
- }
99
-
100
- teardown() {
101
- if [ -n "${TEST_TMP:-}" ] && [ -d "$TEST_TMP" ]; then
102
- rm -rf "$TEST_TMP"
103
- fi
104
- }
105
-
106
- # Faithful re-implementation of SKILL.md Step 5's is_error:true salvage decision
107
- # contract. Consumes the iter JSON envelope + the repo working-tree state and
108
- # returns the orchestrator's branch decision. The SALVAGE branch performs the
109
- # real 4-step path's commit (step 3) so the commit is observable; the bats
110
- # sanity check (step 1) is exercised via the FAKE_BATS_EXIT-controlled stub.
111
- salvage_decision() {
112
- local json="$1"
113
- local repo="$2"
114
-
115
- local is_error
116
- is_error=$(printf '%s' "$json" | python3 -c 'import json,sys; print(str(json.load(sys.stdin).get("is_error")).lower())')
117
-
118
- # is_error:false → normal exit-code path; not the salvage branch.
119
- if [ "$is_error" != "true" ]; then
120
- printf 'DECISION=PARSE_SUMMARY\n'
121
- return 0
122
- fi
123
-
124
- # is_error:true with no staged work → halt per the existing exit-code contract.
125
- local staged
126
- staged=$(git -C "$repo" diff --cached --name-only)
127
- if [ -z "$staged" ]; then
128
- printf 'DECISION=HALT reason=no-staged-work\n'
129
- return 0
130
- fi
131
-
132
- # is_error:true with staged work → run the iter-authored bats as the
133
- # structural sanity check (step 1). Green → SALVAGE; fail → HALT.
134
- if iter_bats; then
135
- # Step 3: commit the staged work from the orchestrator main turn with
136
- # explicit iter-attribution. (Step 4 — fresh commit gate — is the runtime
137
- # orchestrator's concern, asserted via the doc-lint slice below.)
138
- git -C "$repo" commit -q -m "salvage(P000): iter hit API stream timeout before commit — committed staged work from orchestrator main turn; iter-authored bats green"
139
- printf 'DECISION=SALVAGE\n'
140
- else
141
- printf 'DECISION=HALT reason=bats-fail\n'
142
- fi
143
- return 0
144
- }
145
-
146
- # ---------------------------------------------------------------------------
147
- # Behavioural cases (the load-bearing core per ADR-052).
148
- # ---------------------------------------------------------------------------
149
-
150
- @test "P261: is_error:true + staged work + bats green -> SALVAGE (commit from main turn)" {
151
- export FAKE_IS_ERROR=true FAKE_STAGE_WORK=1 FAKE_BATS_EXIT=0
152
- local json
153
- json=$( cd "$REPO" && claude -p --output-format json "TEST" < /dev/null )
154
- run salvage_decision "$json" "$REPO"
155
- [ "$status" -eq 0 ]
156
- [[ "$output" == *"DECISION=SALVAGE"* ]]
157
- # The salvage commit must have landed, carrying the staged work + attribution.
158
- run git -C "$REPO" log -1 --format=%s
159
- [[ "$output" == *"salvage"* ]]
160
- [[ "$output" == *"orchestrator main turn"* ]]
161
- run git -C "$REPO" show --stat HEAD
162
- [[ "$output" == *"staged-iter-work.txt"* ]]
163
- }
164
-
165
- @test "P261: is_error:true + staged work + bats FAIL -> HALT (incoherent work not salvaged)" {
166
- export FAKE_IS_ERROR=true FAKE_STAGE_WORK=1 FAKE_BATS_EXIT=1
167
- local json
168
- json=$( cd "$REPO" && claude -p --output-format json "TEST" < /dev/null )
169
- run salvage_decision "$json" "$REPO"
170
- [ "$status" -eq 0 ]
171
- [[ "$output" == *"DECISION=HALT"* ]]
172
- [[ "$output" == *"reason=bats-fail"* ]]
173
- # No salvage commit landed — HEAD is still the root commit.
174
- run git -C "$REPO" log --oneline
175
- [ "$(printf '%s\n' "$output" | grep -c .)" -eq 1 ]
176
- }
177
-
178
- @test "P261: is_error:true + NO staged work -> HALT per existing exit-code contract" {
179
- export FAKE_IS_ERROR=true FAKE_STAGE_WORK=0 FAKE_BATS_EXIT=0
180
- local json
181
- json=$( cd "$REPO" && claude -p --output-format json "TEST" < /dev/null )
182
- run salvage_decision "$json" "$REPO"
183
- [ "$status" -eq 0 ]
184
- [[ "$output" == *"DECISION=HALT"* ]]
185
- [[ "$output" == *"reason=no-staged-work"* ]]
186
- }
187
-
188
- @test "P261: is_error:false (normal exit) -> PARSE_SUMMARY, NOT the salvage branch" {
189
- export FAKE_IS_ERROR=false FAKE_STAGE_WORK=0
190
- local json
191
- json=$( cd "$REPO" && claude -p --output-format json "TEST" < /dev/null )
192
- run salvage_decision "$json" "$REPO"
193
- [ "$status" -eq 0 ]
194
- [[ "$output" == *"DECISION=PARSE_SUMMARY"* ]]
195
- }
196
-
197
- # ---------------------------------------------------------------------------
198
- # Doc-lint contract assertions (Permitted Exception per ADR-037; structural
199
- # slice marked at top of file per ADR-052 Surface 2). These guard the SKILL.md
200
- # / ADR-032 prose against drift away from the behavioural contract above.
201
- # ---------------------------------------------------------------------------
202
-
203
- @test "P261: SKILL.md Step 5 exit-code semantics documents the is_error:true salvage carve-out" {
204
- run grep -niE "is_error.{0,30}salvage|salvage.{0,40}is_error|stream.?idle.?timeout.{0,80}salvage|salvage.{0,80}stream.?(idle.?)?timeout" "$SKILL_FILE"
205
- [ "$status" -eq 0 ]
206
- }
207
-
208
- @test "P261: SKILL.md salvage carve-out names the staged-work + bats-pass gate condition" {
209
- run grep -niE "staged.{0,40}(file|work).{0,80}bats|bats.{0,80}(pass|green).{0,80}salvage|salvage.{0,120}staged" "$SKILL_FILE"
210
- [ "$status" -eq 0 ]
211
- }
212
-
213
- @test "P261: SKILL.md salvage carve-out documents the commit-from-main-turn + fresh-gate steps" {
214
- run grep -niE "(orchestrator|main turn).{0,80}commit.{0,120}(attribut|fresh)|commit gate fires fresh|fresh.{0,30}commit gate" "$SKILL_FILE"
215
- [ "$status" -eq 0 ]
216
- }
217
-
218
- @test "P261: SKILL.md salvage carve-out distinguishes the class from P147 / P121 / P146" {
219
- run grep -niE "P147" "$SKILL_FILE"
220
- [ "$status" -eq 0 ]
221
- run grep -niE "P146" "$SKILL_FILE"
222
- [ "$status" -eq 0 ]
223
- }
224
-
225
- @test "P261: SKILL.md Step 5 cites P261 (salvage-carve-out driver)" {
226
- run grep -nE "P261" "$SKILL_FILE"
227
- [ "$status" -eq 0 ]
228
- }
229
-
230
- @test "P261: SKILL.md line ~486 orchestrator-commit rule carries the salvage exception cross-reference" {
231
- # The 'orchestrator does NOT commit from its main turn' rule must no longer
232
- # read as unqualified — it must name the salvage carve-out as the one
233
- # bounded exception so SKILL.md and ADR-032 stay in agreement.
234
- run grep -niE "orchestrator does NOT commit from its main turn.{0,200}(except|salvage)|salvage.{0,80}(except|one case).{0,120}main turn" "$SKILL_FILE"
235
- [ "$status" -eq 0 ]
236
- }
237
-
238
- @test "P261: ADR-032 carries the is_error:true stream-timeout salvage sub-variant amendment" {
239
- run grep -niE "is_error.{0,30}(stream.?timeout)?.{0,30}salvage|stream.?timeout salvage|P261 amendment" "$ADR_FILE"
240
- [ "$status" -eq 0 ]
241
- }
242
-
243
- @test "P261: ADR-032 salvage amendment preserves one-commit-per-iteration grain (amend-folding inapplicable)" {
244
- run grep -niE "amend.?(based)?.?folding.{0,80}(inapplicable|no iter commit|not apply)|salvage commit IS the iteration|no iter commit.{0,40}amend" "$ADR_FILE"
245
- [ "$status" -eq 0 ]
246
- }
247
-
248
- @test "P261: ADR-032 salvage amendment confirms fresh-gate-marker behaviour per ADR-009" {
249
- run grep -niE "ADR-009|fresh.{0,30}(gate|commit gate)|own SESSION_ID|trust window" "$ADR_FILE"
250
- [ "$status" -eq 0 ]
251
- }
@@ -1,203 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # P250: /wr-itil:work-problems Step 6.5 release-cadence classification must
4
- # pivot on releasable material, not residual band. The defective prior
5
- # clause "Within appetite (≤ 3/25) — no drain needed" encoded
6
- # accumulation-permitted-below-threshold semantics that violated the
7
- # user's verbatim direction: "If it's low risk, you should release."
8
- #
9
- # Amended contract (three-band):
10
- # 1. Above appetite (≥ 5/25) → ADR-042 auto-apply (unchanged).
11
- # 2. Within appetite (≤ 4/25) AND releasable material → drain.
12
- # 3. Within appetite (≤ 4/25) AND empty queue → no drain (no-op fast-path).
13
- #
14
- # The trigger for the drain action is *presence of releasable material*
15
- # (any unpushed commits OR any .changeset/ entries). The residual band remains
16
- # the safety check (above-appetite never releases) but is no longer the
17
- # action gate for the within-appetite branch.
18
- #
19
- # Doc-lint contract assertions per ADR-037 Permitted Exception (contract-
20
- # assertion class). The asserted prose IS the load-bearing policy surface
21
- # — re-reading SKILL.md is the only way an AFK reader (and the iteration
22
- # subprocess) learns the new classification. Behavioural verification
23
- # would require executing the orchestrator's decision tree, which is not
24
- # scriptable until the Phase 2 advisory-classifier from P081 ships. These
25
- # tests function as regression guards against re-introducing the
26
- # "Within appetite (≤ 3/25) — no drain needed" wording or any equivalent
27
- # threshold-as-action-gate framing.
28
- #
29
- # @problem P250
30
- # @adr ADR-018 (release-cadence policy parent — amended in same commit)
31
- # @adr ADR-037 (skill-testing strategy — contract-assertion class)
32
- # @adr ADR-042 (above-appetite branch — preserved unchanged)
33
- # @jtbd JTBD-006 (Progress the Backlog While I'm Away — primary)
34
- # @jtbd JTBD-002 (Ship with Confidence — composes; small frequent releases)
35
-
36
- setup() {
37
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
38
- SKILL_MD="$REPO_ROOT/packages/itil/skills/work-problems/SKILL.md"
39
- ADR_018="$REPO_ROOT/docs/decisions/018-inter-iteration-release-cadence-for-afk-loops.proposed.md"
40
- }
41
-
42
- # ── Preconditions ──────────────────────────────────────────────────────────
43
-
44
- @test "work-problems P250: SKILL.md exists" {
45
- [ -f "$SKILL_MD" ]
46
- }
47
-
48
- @test "work-problems P250: ADR-018 exists" {
49
- [ -f "$ADR_018" ]
50
- }
51
-
52
- # ── Regression guard: defective prior wording is gone ──────────────────────
53
-
54
- @test "work-problems P250: SKILL.md no longer contains 'Within appetite (≤ 3/25) — no drain needed' clause" {
55
- # The defective clause. Re-introducing it regresses to accumulation-
56
- # permitted-below-threshold semantics.
57
- run grep -nE 'Within appetite \(≤ 3/25\).*no drain needed' "$SKILL_MD"
58
- [ "$status" -ne 0 ]
59
- }
60
-
61
- @test "work-problems P250: SKILL.md no longer treats '= 4/25' as a discrete drain trigger band" {
62
- # The prior "At appetite (= 4/25) — drain" band is collapsed into the
63
- # new "≤ 4/25 AND releasable material" branch. The discrete = 4/25
64
- # framing should be absent from the Step 6.5 classification.
65
- run grep -nE 'At appetite \(= 4/25\) — drain' "$SKILL_MD"
66
- [ "$status" -ne 0 ]
67
- }
68
-
69
- # ── Above-appetite branch preserved (ADR-042) ──────────────────────────────
70
-
71
- @test "work-problems P250: Above-appetite (≥ 5/25) branch routes to ADR-042 auto-apply (preserved)" {
72
- run grep -nE 'Above appetite \(≥ 5/25\).*Above-appetite branch' "$SKILL_MD"
73
- [ "$status" -eq 0 ]
74
- }
75
-
76
- @test "work-problems P250: Above-appetite branch references the auto-apply loop (ADR-042 intact)" {
77
- run grep -nE 'auto-apply loop|ADR-042' "$SKILL_MD"
78
- [ "$status" -eq 0 ]
79
- }
80
-
81
- # ── Within-appetite + releasable material drains ──────────────────────────
82
-
83
- @test "work-problems P250: Within-appetite + releasable material triggers drain" {
84
- # The load-bearing positive contract: within appetite AND any unpushed
85
- # commits OR changeset entry → drain.
86
- run grep -nE 'Within appetite \(≤ 4/25\) AND there is releasable material' "$SKILL_MD"
87
- [ "$status" -eq 0 ]
88
- }
89
-
90
- @test "work-problems P250: releasable-material clause enumerates unpushed commits" {
91
- run grep -nE 'releasable material.*unpushed commits|unpushed commits.*releasable material|any unpushed commits' "$SKILL_MD"
92
- [ "$status" -eq 0 ]
93
- }
94
-
95
- @test "work-problems P250: releasable-material clause enumerates .changeset/ entries" {
96
- run grep -nE 'any entries in `\.changeset/`|`\.changeset/` non-empty|entries in `\.changeset/`' "$SKILL_MD"
97
- [ "$status" -eq 0 ]
98
- }
99
-
100
- # ── Within-appetite + empty queue no-op fast-path ─────────────────────────
101
-
102
- @test "work-problems P250: Within-appetite + empty queue does NOT drain (no-op fast-path)" {
103
- # The genuine fast-path: nothing to release. Gate is *absence of
104
- # releasable material*, not residual band.
105
- run grep -nE 'Within appetite \(≤ 4/25\) AND empty queue' "$SKILL_MD"
106
- [ "$status" -eq 0 ]
107
- }
108
-
109
- @test "work-problems P250: empty-queue branch is framed as 'literally nothing to release', not a threshold deferral" {
110
- # Regression guard: the no-drain branch must NOT be reframed as a
111
- # threshold-based defer. The gate is queue emptiness, not residual.
112
- run grep -nE 'literally nothing to release|nothing to release.*genuine no-op' "$SKILL_MD"
113
- [ "$status" -eq 0 ]
114
- }
115
-
116
- # ── User-direction citation preserved ─────────────────────────────────────
117
-
118
- @test "work-problems P250: amended classification cites user direction verbatim ('If it's low risk, you should release.')" {
119
- # The user's verbatim direction is the load-bearing rationale. Future
120
- # readers tracing the amendment back must find the citation without
121
- # keyword-guessing.
122
- run grep -nE 'If it.s low risk, you should release' "$SKILL_MD"
123
- [ "$status" -eq 0 ]
124
- }
125
-
126
- @test "work-problems P250: classification cites P250 by ticket ID" {
127
- # ADR-022 amendment trail: the amended clause must self-identify
128
- # so future readers tracing back from the ticket find it.
129
- run grep -nE 'P250' "$SKILL_MD"
130
- [ "$status" -eq 0 ]
131
- }
132
-
133
- # ── Non-Interactive Decision Making table reflects amendment ──────────────
134
-
135
- @test "work-problems P250: Decision Making table carries the within-appetite-with-releasable-material row" {
136
- # The decision table is the AFK reader's quick-reference; the
137
- # amendment must surface here too, otherwise the table contradicts
138
- # Step 6.5's classification.
139
- run grep -nE '\| Pipeline risk within appetite \(≤ 4/25\) with releasable material' "$SKILL_MD"
140
- [ "$status" -eq 0 ]
141
- }
142
-
143
- @test "work-problems P250: Decision Making table carries the empty-queue no-drain row" {
144
- run grep -nE '\| Pipeline risk within appetite \(≤ 4/25\) AND empty queue' "$SKILL_MD"
145
- [ "$status" -eq 0 ]
146
- }
147
-
148
- @test "work-problems P250: Decision Making table row cites 'presence of releasable material', not 'residual reaching appetite'" {
149
- # The trigger semantics must be explicit in the table row, not
150
- # buried in Step 6.5 prose 100+ lines above.
151
- run grep -nE 'presence of releasable material|releasable material.*not residual band|Trigger is.*presence' "$SKILL_MD"
152
- [ "$status" -eq 0 ]
153
- }
154
-
155
- # ── ADR-018 amendment (in same commit per ADR-014) ────────────────────────
156
-
157
- @test "work-problems P250: ADR-018 contains the 2026-05-18 Drain-trigger amendment heading" {
158
- # ADR-014 single-unit-of-work: the ADR amendment lands in the same
159
- # commit as the SKILL change. ADR-018's Mechanism without this
160
- # amendment contradicts SKILL.md Step 6.5.
161
- run grep -nE 'Amendment 2026-05-18.*Drain trigger is releasable material' "$ADR_018"
162
- [ "$status" -eq 0 ]
163
- }
164
-
165
- @test "work-problems P250: ADR-018 amendment cites P250 by ticket ID" {
166
- run grep -nE 'P250' "$ADR_018"
167
- [ "$status" -eq 0 ]
168
- }
169
-
170
- @test "work-problems P250: ADR-018 amendment quotes the user direction" {
171
- run grep -nE 'If it.s low risk, you should release' "$ADR_018"
172
- [ "$status" -eq 0 ]
173
- }
174
-
175
- @test "work-problems P250: ADR-018 amendment encodes the new drain condition shape" {
176
- # The amendment must contain the conjunction "≤ 4/25 AND (releasable
177
- # material disjunct)" so future readers tracing the policy chain
178
- # find the rule in the load-bearing ADR, not just in the SKILL.
179
- run grep -nE 'residual ≤ 4/25 AND' "$ADR_018"
180
- [ "$status" -eq 0 ]
181
- }
182
-
183
- @test "work-problems P250: ADR-018 amendment preserves Above-appetite delegation to ADR-042" {
184
- # The amendment MUST NOT touch the above-appetite invariant. ADR-042
185
- # remains the safety gate.
186
- run grep -nE 'Above-appetite states \(≥ 5/25\) route to ADR-042|Above-appetite.*ADR-042' "$ADR_018"
187
- [ "$status" -eq 0 ]
188
- }
189
-
190
- # ── Cross-references intact ───────────────────────────────────────────────
191
-
192
- @test "work-problems P250: SKILL.md Step 6.5 still cites ADR-018 (parent policy intact)" {
193
- run grep -nE 'Step 6\.5.*ADR-018|ADR-018.*Step 6\.5|Release-cadence check.*ADR-018' "$SKILL_MD"
194
- [ "$status" -eq 0 ]
195
- }
196
-
197
- @test "work-problems P250: SKILL.md Step 6.5 still cites P041 (accumulation root cause cross-reference)" {
198
- # P041 is the ancestor that established Step 6.5 itself. The
199
- # amendment refines P041's solution; the cross-reference must
200
- # survive.
201
- run grep -nE 'P041' "$SKILL_MD"
202
- [ "$status" -eq 0 ]
203
- }
@@ -1,174 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # P233: /wr-itil:work-problems Step 6.5 Drain action must chain
4
- # /install-updates AFTER successful release:watch so the next iter
5
- # subprocess loads the just-shipped plugin from cache rather than the
6
- # pre-release cached version.
7
- #
8
- # Empirical driver (briefing/afk-subprocess.md:18): iter subprocesses
9
- # re-resolve plugin cache on spawn; without cache refresh between
10
- # release:watch and next-iter dispatch, the just-shipped hook is
11
- # inactive in the next iter — defeating the "ship a hook to prevent
12
- # recurrence" pattern for the immediate-next-iter case.
13
- #
14
- # Doc-lint contract assertions per ADR-037 Permitted Exception
15
- # (contract-assertion class — same shape as the P140 / P130 / P126 / P135
16
- # sibling fixtures). The asserted prose IS the load-bearing policy
17
- # surface — the chained invocation is documentation-only (the orchestrator
18
- # is a prose-driven agent, not a script); the SKILL.md is the contract.
19
- # Behavioural assertion would require a fixture project + real claude -p
20
- # subprocess that observes a freshly-installed plugin — outside scope.
21
- #
22
- # @problem P233
23
- # @adr ADR-013 (Rule 5 — policy-authorised silent action; chains the
24
- # same authorisation that covers push:watch / release:watch)
25
- # @adr ADR-014 (one-commit-per-iter; this edit lands in one commit)
26
- # @adr ADR-018 (inter-iteration release cadence; this refines its
27
- # Drain action sub-block with the post-release cache refresh)
28
- # @adr ADR-030 (repo-local skills — install-updates is the chained
29
- # skill)
30
- # @adr ADR-037 (skill-testing strategy — contract-assertion class)
31
- # @adr ADR-044 (decision-delegation contract — framework-resolution
32
- # boundary; install-updates' AskUserQuestion-bearing branches
33
- # fall through to its Non-interactive fallback under P130)
34
- # @jtbd JTBD-006 (Progress the Backlog While I'm Away — primary;
35
- # outcome 7 "risk never silently accumulates across AFK iterations"
36
- # extends to "just-shipped hooks effective on next iter")
37
- # @jtbd JTBD-001 (Enforce Governance Without Slowing Down — composes;
38
- # just-shipped governance hooks become effective immediately,
39
- # not after manual /install-updates re-run)
40
- # @jtbd JTBD-007 (Keep Plugins Current Across Projects — persona-level
41
- # currency anchor that JTBD-006's AFK use case extends)
42
-
43
- setup() {
44
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
45
- SKILL_MD="$REPO_ROOT/packages/itil/skills/work-problems/SKILL.md"
46
- }
47
-
48
- @test "work-problems P233: SKILL.md exists" {
49
- [ -f "$SKILL_MD" ]
50
- }
51
-
52
- # ── Cache-refresh chain identity ───────────────────────────────────────────
53
-
54
- @test "work-problems P233: Step 6.5 Drain action carries a post-release cache-refresh subsection citing P233" {
55
- # The amendment must self-identify so future readers tracing back from
56
- # the ticket find the load-bearing prose without keyword-guessing.
57
- run grep -nE 'cache.refresh.*P233|P233.*cache.refresh|post.release.cache.*P233|P233.*post.release.cache' "$SKILL_MD"
58
- [ "$status" -eq 0 ]
59
- }
60
-
61
- @test "work-problems P233: Drain action chains /install-updates after successful release:watch" {
62
- # Core contract: after release:watch returns success, the orchestrator
63
- # invokes /install-updates to refresh the plugin cache. Without this
64
- # chain, the next iter subprocess loads the pre-release cached version
65
- # (P233's empirical root cause).
66
- run grep -nE '/install-updates|install-updates skill' "$SKILL_MD"
67
- [ "$status" -eq 0 ]
68
- }
69
-
70
- @test "work-problems P233: cache-refresh is conditional on actual release (skipped when no changeset)" {
71
- # The chain MUST NOT fire when release:watch was a no-op (empty
72
- # .changeset/ after push). No new plugin version exists → nothing to
73
- # refresh. Without this guard, the orchestrator burns wall-clock and
74
- # noise on a no-op /install-updates invocation every iter.
75
- run grep -niE 'only.*release.*actually|when.*release.*shipped|skip.*when.*no.changeset|conditional on.*release' "$SKILL_MD"
76
- [ "$status" -eq 0 ]
77
- }
78
-
79
- @test "work-problems P233: cache-refresh is non-blocking on /install-updates failure" {
80
- # If /install-updates fails (cache miss + non-interactive fallback,
81
- # marketplace fetch error, transient flake), the orchestrator MUST NOT
82
- # halt the loop. Degrades to current behaviour — cache stays stale;
83
- # equivalent to pre-amendment behaviour. Loop continues.
84
- run grep -niE 'non.blocking.*install.updates|install.updates.*non.blocking|do not halt.*install.updates|install.updates.*failure.*continue' "$SKILL_MD"
85
- [ "$status" -eq 0 ]
86
- }
87
-
88
- # ── Empirical evidence citation ────────────────────────────────────────────
89
-
90
- @test "work-problems P233: cache-refresh subsection cites briefing/afk-subprocess.md evidence" {
91
- # The architect FLAG resolution required the evidence that subprocesses
92
- # re-resolve cache on spawn (rather than inherit parent-resolved
93
- # plugins). The briefing entry is dispositive — cite it inline so
94
- # future readers don't re-litigate the question.
95
- run grep -nE 'afk-subprocess|briefing.*subprocess.*cache' "$SKILL_MD"
96
- [ "$status" -eq 0 ]
97
- }
98
-
99
- # ── ADR-013 Rule 5 policy authorisation ────────────────────────────────────
100
-
101
- @test "work-problems P233: cache-refresh chain rides ADR-013 Rule 5 (same authorisation as push:watch / release:watch)" {
102
- # The chain MUST be silent — invocation between iters is a mechanical
103
- # post-release step the framework has resolved. Same ADR-013 Rule 5
104
- # citation already covers push:watch / release:watch in the within-
105
- # appetite drain; the cache-refresh extends the same authorisation.
106
- run grep -nE 'ADR-013 Rule 5|Rule 5 policy-authorised|policy-authorised.*ADR-013' "$SKILL_MD"
107
- [ "$status" -eq 0 ]
108
- }
109
-
110
- # ── Mid-loop ask discipline preservation (P130) ────────────────────────────
111
-
112
- @test "work-problems P233: cache-refresh prose cites install-updates Non-interactive fallback for AskUserQuestion routing" {
113
- # If install-updates' Step 5b/5c consent gate fires (cache miss /
114
- # scope delta / INSTALL_UPDATES_RECONFIRM=1), the orchestrator main
115
- # turn MUST NOT surface AskUserQuestion mid-loop per P130. Cite the
116
- # install-updates Non-interactive fallback as the routing.
117
- run grep -niE 'Non.interactive fallback|non-interactive fallback' "$SKILL_MD"
118
- [ "$status" -eq 0 ]
119
- }
120
-
121
- @test "work-problems P233: cache-refresh prose cites ADR-044 framework-resolution boundary for AskUserQuestion-available-but-forbidden routing" {
122
- # Architect advisory: cite ADR-044 alongside the Non-interactive
123
- # fallback ref so future readers can trace the "AskUserQuestion-
124
- # available-but-forbidden" reasoning back to the framework-resolution
125
- # boundary — not just the install-updates-side dry-run mechanic.
126
- run grep -nE 'ADR-044' "$SKILL_MD"
127
- [ "$status" -eq 0 ]
128
- }
129
-
130
- # ── Composition with above-appetite branch ─────────────────────────────────
131
-
132
- @test "work-problems P233: cache-refresh fires only after within-appetite Drain action (not after above-appetite Rule 5 halt)" {
133
- # Above-appetite Rule 5 halt terminates without a release; no cache
134
- # refresh fires. Within-appetite convergence loops back to Drain
135
- # action; cache refresh fires there. The prose must not place the
136
- # chain inside the above-appetite branch.
137
- run grep -niE 'within.appetite.*drain.*cache|cache.refresh.*within.appetite|after.*drain.*action' "$SKILL_MD"
138
- [ "$status" -eq 0 ]
139
- }
140
-
141
- # ── Non-Interactive Decision Making table row ──────────────────────────────
142
-
143
- @test "work-problems P233: Decision Making table carries a post-release cache-refresh row" {
144
- # The decision table is the AFK reader's quick-reference; without a
145
- # row here the cache-refresh chain is buried in Step 6.5.
146
- run grep -nE '\|.*[Pp]ost.release cache|\|.*[Cc]ache refresh|\|.*[Pp]lugin cache refresh' "$SKILL_MD"
147
- [ "$status" -eq 0 ]
148
- }
149
-
150
- @test "work-problems P233: Decision Making table row cites P233" {
151
- # Per ADR-037 doc-lint pattern + existing P140 / P126 / P135 sibling
152
- # rows — every Decision Making table row that documents a P-driven
153
- # refinement cites the driver ticket.
154
- run grep -nE '\|.*cache refresh.*P233|\|.*P233.*cache refresh|\|.*post.release.*P233|\|.*P233.*post.release' "$SKILL_MD"
155
- [ "$status" -eq 0 ]
156
- }
157
-
158
- # ── Composition cross-references ───────────────────────────────────────────
159
-
160
- @test "work-problems P233: cache-refresh prose cross-references P106 (claude plugin install no-op-when-already-installed)" {
161
- # P106 is the compounding factor that makes /install-updates' explicit
162
- # uninstall + install dance necessary (vs. naive claude plugin
163
- # install which silent-no-ops). Cite it so future readers don't try
164
- # to simplify the chain.
165
- run grep -nE 'P106' "$SKILL_MD"
166
- [ "$status" -eq 0 ]
167
- }
168
-
169
- @test "work-problems P233: cache-refresh prose cross-references P130 (orchestrator main-turn ask discipline preserved)" {
170
- # P130 is the constraint the Non-interactive fallback routing exists
171
- # to satisfy. Citation makes the dependency auditable.
172
- run grep -nE 'P130' "$SKILL_MD"
173
- [ "$status" -eq 0 ]
174
- }