@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,375 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # tdd-review: structural-permitted (justification: P012 skill testing
4
- # harness scope is open; no behavioural alternative for SKILL.md prose-
5
- # template structural assertions today. ADR-052 Migration clause permits
6
- # structural retrofit-via-justification when the linked harness-gap ticket
7
- # has not yet shipped the primitives. The paired promptfoo eval at
8
- # packages/itil/skills/update-upstream/eval/promptfooconfig.yaml carries
9
- # the behavioural Tier-A/B coverage per ADR-075 Amendment 2026-06-02.
10
- # Provenance: P080 (original bidirectional contract) + P363 / ADR-024
11
- # amendment 2026-06-22 (inbound-origin verdict dispatch leg) + P363 rework
12
- # 2026-06-23 (four user directives — LLM-generated verdict, workaround
13
- # provenance-credit, visibility-gated anti-leakage, cog-a11y gate),
14
- # behaviourally paired by the inbound eval cases in promptfooconfig.yaml.
15
- # The lockstep transition-problem/manage-problem grep check is an inherent
16
- # copy-not-move drift detector (ADR-010/P362) with no behavioural form.)
17
- #
18
- # Doc-lint structural test (Permitted Exception per ADR-005 — structural
19
- # SKILL.md content checks, not behavioural). Mirrors the doc-lint pattern
20
- # established in ADR-011 and ADR-027 Confirmation tests and used by the
21
- # sibling report-upstream contract test.
22
- #
23
- # Asserts the update-upstream skill's SKILL.md encodes the contract
24
- # documented in ADR-024 amendment (P080):
25
- # - sibling-skill split per ADR-010 amended
26
- # - reads ## Reported Upstream from the local ticket
27
- # - three transition templates (Open→KE, KE→Verifying, Verifying→Closed)
28
- # - composes through external-comms + voice-tone gates (AND, not OR)
29
- # - within appetite → gh issue comment; on Verifying→Closed also gh issue close
30
- # - above appetite → silent risk-reduce + re-score; if still above, queue
31
- # to ## Queued Upstream Update + outstanding_questions (NOT halt the loop)
32
- # - back-writes to ## Upstream Lifecycle Updates (append-only log)
33
- # - ADR-014 single-commit grain when fired from transition-problem Step 7
34
-
35
- setup() {
36
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
37
- SKILL_MD="$REPO_ROOT/packages/itil/skills/update-upstream/SKILL.md"
38
- EVAL_CONFIG="$REPO_ROOT/packages/itil/skills/update-upstream/eval/promptfooconfig.yaml"
39
- TRANSITION_MD="$REPO_ROOT/packages/itil/skills/transition-problem/SKILL.md"
40
- MANAGE_MD="$REPO_ROOT/packages/itil/skills/manage-problem/SKILL.md"
41
- }
42
-
43
- @test "update-upstream: SKILL.md exists" {
44
- [ -f "$SKILL_MD" ]
45
- }
46
-
47
- @test "update-upstream: SKILL.md declares sibling-skill split per ADR-010 amended (P080 user direction (a))" {
48
- # User direction (a) — new sibling skill, not a mode flag on report-upstream.
49
- run grep -F 'sibling' "$SKILL_MD"
50
- [ "$status" -eq 0 ]
51
- run grep -F 'ADR-010' "$SKILL_MD"
52
- [ "$status" -eq 0 ]
53
- }
54
-
55
- @test "update-upstream: SKILL.md cross-references ADR-024 amendment (P080)" {
56
- run grep -F 'ADR-024' "$SKILL_MD"
57
- [ "$status" -eq 0 ]
58
- run grep -iE 'P080' "$SKILL_MD"
59
- [ "$status" -eq 0 ]
60
- }
61
-
62
- @test "update-upstream: SKILL.md reads ## Reported Upstream from the local ticket (P080 contract)" {
63
- # The skill reads the section that /wr-itil:report-upstream Step 7
64
- # writes (per ADR-024 Confirmation criterion 3a). Without this read, the
65
- # skill has no upstream URL to comment on.
66
- run grep -F '## Reported Upstream' "$SKILL_MD"
67
- [ "$status" -eq 0 ]
68
- }
69
-
70
- @test "update-upstream: SKILL.md documents three transition templates (Open→KE, KE→Verifying, Verifying→Closed)" {
71
- # Each transition has its own template — investigation findings vs release
72
- # info vs closure thanks. ADR-024 amendment authority pins all three.
73
- run grep -iE 'Open[[:space:]]*[—\-][[:space:]]*[>›]?[[:space:]]*Known Error|Open[[:space:]]*→[[:space:]]*Known Error' "$SKILL_MD"
74
- [ "$status" -eq 0 ]
75
- run grep -iE 'Known Error[[:space:]]*[—\-][[:space:]]*[>›]?[[:space:]]*Verification Pending|Known Error[[:space:]]*→[[:space:]]*Verification Pending' "$SKILL_MD"
76
- [ "$status" -eq 0 ]
77
- run grep -iE 'Verification Pending[[:space:]]*[—\-][[:space:]]*[>›]?[[:space:]]*Closed|Verification Pending[[:space:]]*→[[:space:]]*Closed' "$SKILL_MD"
78
- [ "$status" -eq 0 ]
79
- }
80
-
81
- @test "update-upstream: SKILL.md composes through external-comms gate (P080 user direction (b) + ADR-028)" {
82
- # User direction (b) — risk-gated. The gate is wr-risk-scorer:external-comms
83
- # per ADR-028's third-evaluator extension point (the same gate the post-
84
- # P270 amendment uses for the initial-filing path).
85
- run grep -F 'wr-risk-scorer:external-comms' "$SKILL_MD"
86
- [ "$status" -eq 0 ]
87
- }
88
-
89
- @test "update-upstream: SKILL.md composes through voice-tone gate (P080 user direction (b) + ADR-028)" {
90
- # User direction (b) — voice-tone gated. The gate is wr-voice-tone:agent
91
- # firing on gh issue comment / gh issue close per ADR-028.
92
- run grep -F 'ADR-028' "$SKILL_MD"
93
- [ "$status" -eq 0 ]
94
- run grep -iE 'voice-tone gate' "$SKILL_MD"
95
- [ "$status" -eq 0 ]
96
- }
97
-
98
- @test "update-upstream: SKILL.md gates compose AND (both must pass) not OR (P080 user direction (c))" {
99
- # User direction (c) — same external-comms gate composition pattern as
100
- # inbound (P079). That pattern is AND, not OR — one fail blocks the post.
101
- # The SKILL.md must frame composition explicitly so adopters do not read
102
- # it as independent gates.
103
- run grep -iE 'voice-tone fail.*queue|voice-tone.*FAIL.*queue|FAIL.*identically' "$SKILL_MD"
104
- [ "$status" -eq 0 ]
105
- }
106
-
107
- @test "update-upstream: SKILL.md within-appetite posts via gh issue comment" {
108
- # Within-appetite path posts via gh issue comment with the matched URL's
109
- # issue number — same gh CLI surface as report-upstream Step 5c.
110
- run grep -F 'gh issue comment' "$SKILL_MD"
111
- [ "$status" -eq 0 ]
112
- }
113
-
114
- @test "update-upstream: SKILL.md Verifying→Closed also runs gh issue close (symmetric audit trail)" {
115
- # JTBD-201 symmetric audit trail outcome — when the local ticket goes
116
- # .closed.md the upstream issue must also close. Without gh issue close
117
- # the upstream tracker accumulates stale-looking open issues.
118
- run grep -F 'gh issue close' "$SKILL_MD"
119
- [ "$status" -eq 0 ]
120
- }
121
-
122
- @test "update-upstream: SKILL.md above-appetite saves to ## Queued Upstream Update (not the report rename)" {
123
- # ADR-024 amendment (P080) — the lifecycle-update queue section is named
124
- # ## Queued Upstream Update, distinct from the initial-filing ## Queued
125
- # Upstream Report (renamed per the 2026-06-04 second-amendment leaf (c)).
126
- # Distinct sections so a single local ticket can carry both without collision.
127
- run grep -F '## Queued Upstream Update' "$SKILL_MD"
128
- [ "$status" -eq 0 ]
129
- }
130
-
131
- @test "update-upstream: SKILL.md above-appetite queues outstanding_questions (does NOT halt the orchestrator per P352)" {
132
- # P352 queue-and-continue — same shape as the post-P270 initial-filing
133
- # path. The above-appetite branch must NOT halt the loop; the queued
134
- # entry surfaces at the existing batched-AskUserQuestion end-of-loop gate.
135
- run grep -iE 'outstanding_questions|queue-and-continue|P352' "$SKILL_MD"
136
- [ "$status" -eq 0 ]
137
- }
138
-
139
- @test "update-upstream: SKILL.md silent risk-reduce + re-score is mechanical per ADR-044 (no per-iter AskUserQuestion)" {
140
- # ADR-044 framework-resolution boundary — the risk-reduce + re-score is
141
- # silent (mechanical); per-iter AskUserQuestion for risk-reduce vocabulary
142
- # is the lazy-deferral anti-pattern P132 closes.
143
- run grep -iE 'silent risk-reduce|mechanical.*ADR-044|ADR-044.*mechanical' "$SKILL_MD"
144
- [ "$status" -eq 0 ]
145
- }
146
-
147
- @test "update-upstream: SKILL.md back-writes to ## Upstream Lifecycle Updates (append-only log)" {
148
- # The audit-trail back-write mirrors the ## Reported Upstream back-write
149
- # in report-upstream Step 7 (per ADR-024 Confirmation criterion 3a),
150
- # extended to log every transition.
151
- run grep -F '## Upstream Lifecycle Updates' "$SKILL_MD"
152
- [ "$status" -eq 0 ]
153
- run grep -iE 'append-only|never overwritten|append.*entry' "$SKILL_MD"
154
- [ "$status" -eq 0 ]
155
- }
156
-
157
- @test "update-upstream: SKILL.md AFK behaviour summary table exists (architect review)" {
158
- # Mirrors report-upstream's AFK behaviour summary table — the canonical
159
- # place where adopters look up the AFK routing for each branch.
160
- run grep -F 'AFK behaviour summary' "$SKILL_MD"
161
- [ "$status" -eq 0 ]
162
- }
163
-
164
- @test "update-upstream: SKILL.md cites ADR-014 single-commit grain (transition + back-write + upstream post)" {
165
- # When fired from transition-problem Step 7, the upstream comment +
166
- # back-write + ticket rename + README refresh ride the SAME commit per
167
- # ADR-014 single-commit grain.
168
- run grep -F 'ADR-014' "$SKILL_MD"
169
- [ "$status" -eq 0 ]
170
- run grep -iE 'single-commit|same single commit|same commit' "$SKILL_MD"
171
- [ "$status" -eq 0 ]
172
- }
173
-
174
- @test "update-upstream: SKILL.md no-op exit on missing ## Reported Upstream (cheap unconditional firing)" {
175
- # The trigger fires on every transition unconditionally; the no-op exit
176
- # absorbs the misses (most tickets have no ## Reported Upstream). Without
177
- # the no-op exit, every transition pays a decision cost.
178
- run grep -iE 'no-op exit|nothing to update|exit cleanly' "$SKILL_MD"
179
- [ "$status" -eq 0 ]
180
- }
181
-
182
- @test "update-upstream: SKILL.md no-invention rule on template-filling (reporter-trust guard)" {
183
- # If a cited local-ticket section is absent, write the explicit "absent"
184
- # phrasing rather than invent content. The risk + voice-tone gates cannot
185
- # guard against invented technical claims; the no-invention rule does.
186
- run grep -iE 'no.invention|do not invent|never invent|rather than invent|absent.*phrasing|"absent"' "$SKILL_MD"
187
- [ "$status" -eq 0 ]
188
- }
189
-
190
- @test "update-upstream: SKILL.md annotates JTBD-301 + JTBD-001 (jtbd-lead review)" {
191
- # JTBD-301 plugin-user reporter feedback loop AND JTBD-001 solo-developer
192
- # without-slowing-down are the load-bearing JTBDs. The jtbd-lead review
193
- # required both annotations.
194
- run grep -F 'JTBD-301' "$SKILL_MD"
195
- [ "$status" -eq 0 ]
196
- run grep -F 'JTBD-001' "$SKILL_MD"
197
- [ "$status" -eq 0 ]
198
- }
199
-
200
- @test "update-upstream: SKILL.md documents transition-problem Step 7 trigger wire-in (P080 invocation contract)" {
201
- # The advisory subsection in transition-problem Step 7 fires this skill
202
- # when ## Reported Upstream is present. The SKILL.md must reference the
203
- # trigger surface so adopters understand the invocation contract.
204
- run grep -iE 'transition-problem.*Step 7|Step 7.*transition-problem|fired from.*transition' "$SKILL_MD"
205
- [ "$status" -eq 0 ]
206
- }
207
-
208
- # ─── Inbound-origin verdict dispatch leg (P363 / ADR-024 amendment 2026-06-22) ─
209
-
210
- @test "update-upstream: SKILL.md documents the inbound-origin verdict dispatch leg (P363)" {
211
- # The skill reads the **Origin**: inbound-reported (#NN) field (ADR-076)
212
- # in addition to ## Reported Upstream, so inbound reporters get a verdict.
213
- run grep -iE 'Inbound-origin verdict dispatch' "$SKILL_MD"
214
- [ "$status" -eq 0 ]
215
- run grep -F 'inbound-reported (#NN)' "$SKILL_MD"
216
- [ "$status" -eq 0 ]
217
- }
218
-
219
- @test "update-upstream: SKILL.md no-op exit requires BOTH surfaces absent (section AND inbound Origin)" {
220
- # The dual-direction no-op exit fires only when NEITHER the outbound
221
- # ## Reported Upstream section NOR the inbound **Origin** field is present.
222
- run grep -iE 'no inbound Origin|NEITHER .*Reported Upstream.*Origin|both are absent' "$SKILL_MD"
223
- [ "$status" -eq 0 ]
224
- }
225
-
226
- @test "update-upstream: SKILL.md inbound leg resolves the originating issue on OUR OWN repo (not external upstream)" {
227
- # Inbound issues are filed AGAINST us — the comment posts on our own repo,
228
- # resolved via gh default / gh repo view, NOT an external upstream owner/repo.
229
- run grep -iE 'gh repo view|our own repo|own repo' "$SKILL_MD"
230
- [ "$status" -eq 0 ]
231
- }
232
-
233
- @test "update-upstream: SKILL.md inbound leg has an idempotency guard (gh issue view --json comments)" {
234
- # Before posting, scan existing comments for the verdict marker
235
- # (package@version + commit SHA) and skip if already posted.
236
- run grep -F 'gh issue view' "$SKILL_MD"
237
- [ "$status" -eq 0 ]
238
- run grep -iE 'idempoten' "$SKILL_MD"
239
- [ "$status" -eq 0 ]
240
- }
241
-
242
- @test "update-upstream: SKILL.md inbound templates carry the P229 anti-leakage rule (reporter-facing, no internal vocab)" {
243
- # Reporter-facing comment bodies on our own repo MUST NOT leak Step IDs,
244
- # branch names, classification tokens, or P/ADR/JTBD IDs as carriers of
245
- # meaning. The released @windyroad/<pkg>@<version> is the only permitted
246
- # structured token. Mirrors ADR-062 safe-and-valid acknowledgement shape.
247
- run grep -iE 'anti-leakage|reporter-surface prose|reporter-facing' "$SKILL_MD"
248
- [ "$status" -eq 0 ]
249
- run grep -F 'P229' "$SKILL_MD"
250
- [ "$status" -eq 0 ]
251
- }
252
-
253
- @test "update-upstream: SKILL.md inbound leg keeps the SAME dual gate composition (no weaker path)" {
254
- # The inbound comment routes through the SAME external-comms + voice-tone
255
- # dual gate as the outbound path — no weaker path for inbound.
256
- run grep -iE 'SAME .*external-comms .*voice-tone|same.*dual gate' "$SKILL_MD"
257
- [ "$status" -eq 0 ]
258
- }
259
-
260
- @test "update-upstream: SKILL.md inbound Verifying→Closed also closes the own-repo issue (addresses #97-unclosed witness)" {
261
- # P211 #97 was silent AND unclosed. The inbound leg runs gh issue close
262
- # on the own repo on the Verifying→Closed transition.
263
- run grep -iE 'posted-inbound-comment-and-closed|gh issue close .*OWN' "$SKILL_MD"
264
- [ "$status" -eq 0 ]
265
- }
266
-
267
- @test "update-upstream: SKILL.md both-direction tickets fire both legs independently" {
268
- # A ticket reported upstream AND reported against us inbound fires both
269
- # dispatches independently — one above-appetite leg queues only itself.
270
- run grep -iE 'Both-direction|both.*legs.*independent|fire .*independently' "$SKILL_MD"
271
- [ "$status" -eq 0 ]
272
- }
273
-
274
- @test "update-upstream: SKILL.md back-writes inbound entries direction-tagged so P249 poller is uncontaminated" {
275
- # Inbound entries log to ## Upstream Lifecycle Updates (NOT ## Reported
276
- # Upstream) so /wr-itil:check-upstream-responses (P249) is not contaminated.
277
- run grep -F 'P249' "$SKILL_MD"
278
- [ "$status" -eq 0 ]
279
- run grep -iE 'inbound.*disclosure path|posted-inbound-comment' "$SKILL_MD"
280
- [ "$status" -eq 0 ]
281
- }
282
-
283
- # ─── P363 rework 2026-06-23 — four user directives ────────────────────────────
284
-
285
- @test "update-upstream: SKILL.md inbound verdict is LLM-generated per-context, not templated (Directive 1)" {
286
- # Directive 1 — templates produce cold, patterned prose; the inbound verdict
287
- # is GENERATED from ticket context via per-transition generation prompts the
288
- # agent reads at runtime, NOT filled from canned template bodies.
289
- run grep -iE 'LLM-generated|generated from the local ticket|generation prompt' "$SKILL_MD"
290
- [ "$status" -eq 0 ]
291
- run grep -F 'no templates' "$SKILL_MD"
292
- [ "$status" -eq 0 ]
293
- }
294
-
295
- @test "update-upstream: SKILL.md O→KE prompt shares the workaround + scans issue comments for provenance (Directive 2/4)" {
296
- # Directive 2 — a Known Error comment shares the WORKAROUND, not just root
297
- # cause. Directive 4 — provenance: read ## Workaround AND scan the originating
298
- # issue's body+comments (gh issue view --json comments,body) to attribute it.
299
- run grep -F 'share it with correct PROVENANCE' "$SKILL_MD"
300
- [ "$status" -eq 0 ]
301
- run grep -F 'comments,body' "$SKILL_MD"
302
- [ "$status" -eq 0 ]
303
- run grep -F '## Workaround' "$SKILL_MD"
304
- [ "$status" -eq 0 ]
305
- }
306
-
307
- @test "update-upstream: SKILL.md O→KE prompt names four provenance branches + credit shape + confirm-exact (Directive 4)" {
308
- # The prompt must branch on who provided the workaround and credit per branch,
309
- # always confirming the exact validated details.
310
- run grep -F 'MAINTAINER-AUTHORED' "$SKILL_MD"; [ "$status" -eq 0 ]
311
- run grep -F 'REPORTER-PROVIDED' "$SKILL_MD"; [ "$status" -eq 0 ]
312
- run grep -F 'COMMENTER-PROVIDED' "$SKILL_MD"; [ "$status" -eq 0 ]
313
- run grep -F 'BOTH-SOURCE' "$SKILL_MD"; [ "$status" -eq 0 ]
314
- run grep -iE 'credit the reporter|credit them by @handle|credit.*both' "$SKILL_MD"; [ "$status" -eq 0 ]
315
- run grep -iE 'CONFIRM THE EXACT|Confirmed the details|confirm the details' "$SKILL_MD"; [ "$status" -eq 0 ]
316
- }
317
-
318
- @test "update-upstream: SKILL.md inbound anti-leakage is visibility-gated — PUBLIC titled+linked, PRIVATE strict ban (Directive 3)" {
319
- # Directive 3 — for PUBLIC repos refer to problems/ADRs/RFCs by title AND link
320
- # (never bare ID); for PRIVATE/INTERNAL/indeterminate fall back to strict ban.
321
- run grep -F 'gh repo view --json visibility' "$SKILL_MD"; [ "$status" -eq 0 ]
322
- run grep -iE 'title AND as a link|titled\+linked' "$SKILL_MD"; [ "$status" -eq 0 ]
323
- run grep -iE 'PRIVATE / INTERNAL / indeterminate|strict ban' "$SKILL_MD"; [ "$status" -eq 0 ]
324
- # classification tokens / step IDs / internal vocab stay banned regardless.
325
- run grep -iE 'Always banned' "$SKILL_MD"; [ "$status" -eq 0 ]
326
- # grounded in ADR-055's permalink-progressive-enhancement.
327
- run grep -F 'ADR-055' "$SKILL_MD"; [ "$status" -eq 0 ]
328
- }
329
-
330
- @test "update-upstream: SKILL.md inbound gate chain rides cog-a11y first (when-available, P338-gated, do-not-block)" {
331
- # Directive 1's "run cog-a11y, risk, voice and tone" — cog-a11y rides FIRST,
332
- # gated on P338 (plugin not yet shipped); the chain degrades to the dual gate
333
- # today and does NOT block on P338.
334
- run grep -iE 'cog-a11y → risk → voice-tone|cognitive-accessibility → external-comms' "$SKILL_MD"; [ "$status" -eq 0 ]
335
- run grep -F 'P338' "$SKILL_MD"; [ "$status" -eq 0 ]
336
- run grep -iE 'do NOT block|when-available' "$SKILL_MD"; [ "$status" -eq 0 ]
337
- }
338
-
339
- @test "transition-problem + manage-problem Step 7 greps match the inbound Origin alternation in LOCKSTEP (P363/P362)" {
340
- # Both lockstep pre-checks must match ^## Reported Upstream OR
341
- # ^\*\*Origin\*\*: inbound-reported \(# — drift re-opens the P363 gap on
342
- # whichever surface lacks the alternation (ADR-010 copy-not-move / P362).
343
- run grep -F 'inbound-reported \(#' "$TRANSITION_MD"
344
- [ "$status" -eq 0 ]
345
- run grep -F 'inbound-reported \(#' "$MANAGE_MD"
346
- [ "$status" -eq 0 ]
347
- }
348
-
349
- # ─── Paired promptfoo eval (ADR-075 Amendment 2026-06-02) ────────────────────
350
- #
351
- # The paired promptfoo eval at packages/itil/skills/update-upstream/eval/
352
- # discharges the R009 prose-floor for this SKILL surface atomically per
353
- # ADR-075 evidence floor.
354
-
355
- @test "update-upstream: paired promptfoo eval config exists (ADR-075 Amendment 2026-06-02)" {
356
- [ -f "$EVAL_CONFIG" ]
357
- }
358
-
359
- @test "update-upstream: paired eval uses exec:bash provider per ADR-075 §6 (no API key)" {
360
- # ADR-075 §6 — subscription auth via claude -p, no ANTHROPIC_API_KEY.
361
- # The provider must be exec:bash invoking ./run-skill-eval.sh.
362
- run grep -F "exec:bash ./run-skill-eval.sh" "$EVAL_CONFIG"
363
- [ "$status" -eq 0 ]
364
- }
365
-
366
- @test "update-upstream: paired eval ships Tier-B llm-rubric grader for negative clauses" {
367
- # Negative clauses (must NOT halt; must NOT invent) cannot be Tier-A
368
- # graded — a not-regex for "halt" false-fails the correct "does NOT halt".
369
- # The grader script + llm-rubric assertions discharge those clauses.
370
- GRADER="$REPO_ROOT/packages/itil/skills/update-upstream/eval/grade-llm-rubric.sh"
371
- [ -f "$GRADER" ]
372
- [ -x "$GRADER" ]
373
- run grep -F 'llm-rubric' "$EVAL_CONFIG"
374
- [ "$status" -eq 0 ]
375
- }
@@ -1,294 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Contract assertions for /wr-itil:work-problem (P071 split slice 3).
3
- #
4
- # This skill hosts the "pick the highest-WSJF ticket and work it" user
5
- # intent previously hidden behind /wr-itil:manage-problem work. Unlike
6
- # the plural orchestrator (/wr-itil:work-problems — batch AFK loop),
7
- # this singular skill runs exactly one ticket per invocation and fires
8
- # the AskUserQuestion selection prompt in interactive mode. Execution
9
- # is delegated to /wr-itil:manage-problem <NNN> to avoid forking the
10
- # per-ticket workflow.
11
- #
12
- # Structural assertion — Permitted Exception to the source-grep ban
13
- # (ADR-005 / P011 / ADR-037 contract-assertion pattern).
14
- #
15
- # tdd-review: structural-permitted (justification: SKILL.md prose contract
16
- # assertions; behavioural skill-runtime harness pending P012 + P081 Phase 2;
17
- # expected to migrate to behavioural form once the harness exists. Touched
18
- # during P136 Phase 2 ADR-044 alignment audit per the inline plan's
19
- # bridge-marker rule.)
20
- #
21
- # @problem P071 (originating split)
22
- # @problem P136 (ADR-044 alignment audit master — Phase 2 work-problem singular)
23
- # @adr ADR-044 (Decision-Delegation Contract — framework-mediated Prioritisation surface)
24
- # @jtbd JTBD-001 (enforce governance without slowing down — discoverable surface)
25
- # @jtbd JTBD-101 (extend the suite with clear patterns — one skill per distinct user intent)
26
- # @jtbd JTBD-201 (audit trail — selection cites the deciding tie-break rung)
27
- #
28
- # Cross-reference:
29
- # P071: docs/problems/071-argument-based-skill-subcommands-are-not-discoverable.open.md
30
- # P136: docs/problems/136-adr-044-alignment-audit-master.open.md
31
- # ADR-010 amended (Skill Granularity section) — split naming + forwarder contract
32
- # ADR-013 amended Rule 1 — structured user interaction; framework-resolution narrowing per ADR-044
33
- # ADR-013 Rule 6 — AFK non-interactive fallback (Step 4 scope-expansion only)
34
- # ADR-014 — governance skills commit their own work (delegated target owns commits)
35
- # ADR-032 — governance skill invocation patterns (plural orchestrator delegates here)
36
- # ADR-037 — contract-assertion bats pattern
37
- # ADR-044 — Decision-Delegation Contract; Step 2 selection is framework-mediated
38
-
39
- setup() {
40
- SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
41
- SKILL_FILE="${SKILL_DIR}/SKILL.md"
42
- }
43
-
44
- @test "SKILL.md exists and has frontmatter" {
45
- [ -f "$SKILL_FILE" ]
46
- run head -1 "$SKILL_FILE"
47
- [ "$status" -eq 0 ]
48
- [ "$output" = "---" ]
49
- }
50
-
51
- @test "SKILL.md frontmatter name is wr-itil:work-problem (singular, P071 + ADR-010 amended)" {
52
- # Split naming convention per ADR-010 amendment: <verb>-<object>.
53
- # CRITICAL: singular "work-problem", NOT plural "work-problems" — the
54
- # plural name is reserved for the AFK orchestrator that already exists.
55
- # Name coexistence is a P071 acknowledged trade-off.
56
- run grep -n "^name: wr-itil:work-problem$" "$SKILL_FILE"
57
- [ "$status" -eq 0 ]
58
- }
59
-
60
- @test "SKILL.md frontmatter name is NOT wr-itil:work-problems (regression guard for name collision)" {
61
- # Guard against the easy slip of renaming this skill to match the
62
- # plural orchestrator. If the name drifts to plural, `/wr-itil:`
63
- # autocomplete shows two plural-looking skills side by side and users
64
- # cannot tell which is interactive vs batch.
65
- run grep -n "^name: wr-itil:work-problems$" "$SKILL_FILE"
66
- [ "$status" -ne 0 ]
67
- }
68
-
69
- @test "SKILL.md frontmatter description names the pick-and-run intent (P071)" {
70
- # Description must name "pick" / "work" / "highest-WSJF" so Claude
71
- # Code autocomplete surfaces the user intent rather than a generic
72
- # name. Also must mention "singular" or distinguish from the plural
73
- # orchestrator so users pick the right one.
74
- run grep -inE "^description:.*(pick|highest.wsjf|work.*problem)" "$SKILL_FILE"
75
- [ "$status" -eq 0 ]
76
- run grep -inE "^description:.*(singular|one ticket|distinct from.*work-problems)" "$SKILL_FILE"
77
- [ "$status" -eq 0 ]
78
- }
79
-
80
- @test "SKILL.md frontmatter allowed-tools includes AskUserQuestion (selection prompt)" {
81
- # Step 2 fires AskUserQuestion for the selection in interactive mode
82
- # (ADR-013 Rule 1). Without the tool the structured-interaction
83
- # contract cannot hold.
84
- run grep -nE "^allowed-tools:.*AskUserQuestion" "$SKILL_FILE"
85
- [ "$status" -eq 0 ]
86
- }
87
-
88
- @test "SKILL.md frontmatter allowed-tools includes Skill (delegation to manage-problem + review-problems)" {
89
- # Step 1 delegates the cache refresh to /wr-itil:review-problems when
90
- # stale; Step 3 delegates the per-ticket execution to
91
- # /wr-itil:manage-problem <NNN>. Both use the Skill tool per ADR-010's
92
- # thin-router discipline.
93
- run grep -nE "^allowed-tools:.*Skill" "$SKILL_FILE"
94
- [ "$status" -eq 0 ]
95
- }
96
-
97
- @test "SKILL.md documents the singular-vs-plural naming distinction (P071 coexistence)" {
98
- # The most common user confusion will be work-problem vs
99
- # work-problems. The SKILL.md must name the distinction explicitly
100
- # so `/wr-itil:` autocomplete readers can tell them apart. Without
101
- # this, users will pick the wrong one and either run a single ticket
102
- # when they wanted the AFK loop or vice-versa.
103
- run grep -inE "work-problems.*plural|plural.*work-problems|AFK orchestrator" "$SKILL_FILE"
104
- [ "$status" -eq 0 ]
105
- }
106
-
107
- @test "SKILL.md delegates execution to /wr-itil:manage-problem (anti-fork discipline)" {
108
- # Per ADR-010 thin-router: the split skill owns selection, NOT
109
- # execution. The per-ticket investigate/transition/fix/release flow
110
- # stays on /wr-itil:manage-problem <NNN>. If this skill re-implements
111
- # the execution inline, the deprecation window hardens into a
112
- # permanent fork.
113
- run grep -inE "/wr-itil:manage-problem" "$SKILL_FILE"
114
- [ "$status" -eq 0 ]
115
- run grep -inE "delegate.*manage-problem|Skill tool.*manage-problem|manage-problem.*Skill tool" "$SKILL_FILE"
116
- [ "$status" -eq 0 ]
117
- }
118
-
119
- @test "SKILL.md defers README.md cache refresh to /wr-itil:review-problems (P062 ownership)" {
120
- # P062 makes /wr-itil:review-problems the canonical README.md cache
121
- # writer. This skill reads the cache but must NOT rewrite it —
122
- # re-implementing the refresh here would break the one-canonical-
123
- # writer invariant.
124
- run grep -inE "/wr-itil:review-problems" "$SKILL_FILE"
125
- [ "$status" -eq 0 ]
126
- run grep -inE "(delegate|defer|refresh).*review-problems|review-problems.*(refresh|delegate|defer)" "$SKILL_FILE"
127
- [ "$status" -eq 0 ]
128
- }
129
-
130
- @test "SKILL.md reads README.md cache via the git-history freshness test (P031)" {
131
- # Same freshness check as list-problems and review-problems — mtime
132
- # is unreliable in worktrees per P031. Drift here means false
133
- # cache-hit (serving a stale ranking) or false cache-miss (spamming
134
- # review refreshes).
135
- run grep -inE "docs/problems/README\.md" "$SKILL_FILE"
136
- [ "$status" -eq 0 ]
137
- run grep -inE "git log.*--format.*README\.md|readme_commit" "$SKILL_FILE"
138
- [ "$status" -eq 0 ]
139
- }
140
-
141
- @test "SKILL.md fires the AskUserQuestion selection prompt (ADR-013 Rule 1)" {
142
- # Step 2 is the structured-interaction path: single top-WSJF ticket
143
- # shown as Recommended, or tied tickets shown as peer options. Never
144
- # prose "(a)/(b)/(c)".
145
- run grep -inE "AskUserQuestion" "$SKILL_FILE"
146
- [ "$status" -eq 0 ]
147
- run grep -inE "Next problem|Recommended|tied" "$SKILL_FILE"
148
- [ "$status" -eq 0 ]
149
- }
150
-
151
- @test "SKILL.md forbids prose selection fallback (P053 + ADR-013 Rule 1 regression guard)" {
152
- # Prose "which would you like?" or "(a)/(b)/(c)" is the anti-pattern
153
- # ADR-013 Rule 1 and P053 codify against. The SKILL.md must say
154
- # "never" so the contract is legible at the spec level.
155
- run grep -inE "never.*prose|never.*\(a\)/\(b\)" "$SKILL_FILE"
156
- [ "$status" -eq 0 ]
157
- }
158
-
159
- @test "SKILL.md documents the AFK non-interactive branch (ADR-013 Rule 6)" {
160
- # When /wr-itil:work-problems invokes this skill inside an AFK
161
- # subagent iteration, AskUserQuestion is unavailable — the selection
162
- # has already happened at the orchestrator level. The skill must
163
- # degrade gracefully per Rule 6.
164
- run grep -inE "AFK|non-interactive|ADR-013 Rule 6|Rule 6" "$SKILL_FILE"
165
- [ "$status" -eq 0 ]
166
- }
167
-
168
- @test "SKILL.md documents the scope-expansion AskUserQuestion (3-option shape)" {
169
- # Effort drift during investigation or architect review must fire the
170
- # standard Continue / Re-rank / Pick-different three-option prompt,
171
- # same as /wr-itil:manage-problem's Working a Problem section.
172
- run grep -inE "Scope change|scope.expansion" "$SKILL_FILE"
173
- [ "$status" -eq 0 ]
174
- run grep -inE "Continue with expanded scope|Update problem and re-rank|Pick a different problem" "$SKILL_FILE"
175
- [ "$status" -eq 0 ]
176
- }
177
-
178
- @test "SKILL.md runs exactly one ticket per invocation (singular contract)" {
179
- # The whole point of the singular skill: one ticket, then stop. The
180
- # SKILL.md must say "do not loop automatically" or equivalent so the
181
- # contract is explicit. Looping is the plural orchestrator's job.
182
- run grep -inE "do not loop automatically|one ticket per invocation|singular" "$SKILL_FILE"
183
- [ "$status" -eq 0 ]
184
- }
185
-
186
- @test "SKILL.md does not carry a deprecated-arguments frontmatter flag (clean-split skill)" {
187
- # Architect advisory: work-problem is a clean-split skill with no
188
- # argument-subcommands itself. ADR-010 amendment's
189
- # `deprecated-arguments: true` flag is only valid on host skills with
190
- # forwarder routes — work-problem is a forwarder TARGET, not a host.
191
- run grep -E "^deprecated-arguments:" "$SKILL_FILE"
192
- [ "$status" -ne 0 ]
193
- }
194
-
195
- @test "SKILL.md does not use word-argument subcommand branching (P071 regression guard)" {
196
- # The whole point of P071: Claude Code autocomplete does not surface
197
- # arguments. A clean-split skill must not reintroduce word-arg
198
- # subcommand routing.
199
- run grep -inE "If arguments start with|If arguments contain" "$SKILL_FILE"
200
- [ "$status" -ne 0 ]
201
- }
202
-
203
- @test "SKILL.md cites P071 and ADR-010 amended (traceability per ADR-037)" {
204
- # ADR-037 traceability: the skill spec cites the problem it closes
205
- # and the ADR that authorises the split.
206
- run grep -inE "P071|ADR-010" "$SKILL_FILE"
207
- [ "$status" -eq 0 ]
208
- }
209
-
210
- @test "SKILL.md cites ADR-032 + P077 (AFK orchestrator delegation target)" {
211
- # /wr-itil:work-problems Step 5 delegates iterations via the Agent
212
- # tool (P077). This skill is the execution unit those iterations
213
- # invoke. The cross-reference documents the pair relationship so
214
- # future drift to /wr-itil:work-problems doesn't orphan this skill.
215
- run grep -inE "P077|ADR-032" "$SKILL_FILE"
216
- [ "$status" -eq 0 ]
217
- }
218
-
219
- # ----------------------------------------------------------------------
220
- # P136 Phase 2 — ADR-044 alignment audit (added 2026-04-27)
221
- #
222
- # These assertions land the framework-mediated-selection contract for
223
- # Step 2 and the ADR-044 category-2 cross-reference for Step 4. They
224
- # replace the prior assertions that mandated AskUserQuestion-driven
225
- # selection (which was the lazy-deferral surface ADR-044 was written to
226
- # close).
227
- # ----------------------------------------------------------------------
228
-
229
- @test "SKILL.md Step 2 specifies framework-mediated selection (ADR-044 Prioritisation)" {
230
- # Per ADR-044 Framework-Mediated Surface row "Prioritisation — WSJF
231
- # formula + documented tie-breaks (Known Error > Open; smaller effort
232
- # first; older reported date). Pick + work." Step 2 must apply the
233
- # tie-break ladder mechanically rather than defer to AskUserQuestion.
234
- run awk '/^### 2\./,/^### 3\./' "$SKILL_FILE"
235
- [ "$status" -eq 0 ]
236
- [[ "$output" == *"framework-mediated"* ]] || [[ "$output" == *"tie-break ladder"* ]]
237
- [[ "$output" == *"Known Error"* ]]
238
- [[ "$output" == *"smaller"* ]]
239
- [[ "$output" == *"older reported date"* ]]
240
- [[ "$output" == *"ADR-044"* ]]
241
- }
242
-
243
- @test "SKILL.md Step 2 reports the chosen ticket + tie-break rung that decided (JTBD-201 audit-trail)" {
244
- # Audit-trail outcome: the agent must cite which rung of the ladder
245
- # decided the selection so the choice is reproducible from the README
246
- # state at the time of the report.
247
- run awk '/^### 2\./,/^### 3\./' "$SKILL_FILE"
248
- [ "$status" -eq 0 ]
249
- [[ "$output" == *"report"* ]]
250
- [[ "$output" == *"tie-break"* ]] || [[ "$output" == *"ladder rung"* ]]
251
- }
252
-
253
- @test "SKILL.md Step 2 documents user-override path via direct NNN invocation" {
254
- # Selection is framework-mediated, but the user retains agency via
255
- # /wr-itil:work-problem <NNN> direct invocation. Without the
256
- # documented escape hatch, the user has no way to redirect except via
257
- # post-hoc correction (ADR-044 category 6). The literal-form
258
- # assertion guards against the substring trap where /wr-itil:work-
259
- # problems (plural) accidentally satisfies a /wr-itil:work-problem
260
- # substring check.
261
- run awk '/^### 2\./,/^### 3\./' "$SKILL_FILE"
262
- [ "$status" -eq 0 ]
263
- [[ "$output" == *"/wr-itil:work-problem <NNN>"* ]] || [[ "$output" == *"/wr-itil:work-problem <ID>"* ]] || [[ "$output" == *"\`/wr-itil:work-problem 042\`"* ]]
264
- }
265
-
266
- @test "SKILL.md Step 2 does NOT fire AskUserQuestion as the selection mechanism (regression guard)" {
267
- # The AskUserQuestion-driven selection prompt was the lazy-deferral
268
- # surface ADR-044 closed. If it returns to Step 2 the lazy-count
269
- # metric (Step 2d "Ask Hygiene Pass") will spike. AskUserQuestion may
270
- # appear elsewhere (Step 4 scope-expansion) but NOT inside Step 2.
271
- run awk '/^### 2\./,/^### 3\./' "$SKILL_FILE"
272
- [ "$status" -eq 0 ]
273
- ! echo "$output" | grep -qE "Selection via .?AskUserQuestion|Use .header: .Next problem"
274
- }
275
-
276
- @test "SKILL.md Step 4 cross-references ADR-044 category-2 (deviation-approval)" {
277
- # Effort growth IS the contradicting evidence against the WSJF score
278
- # that ranked this ticket at the top — it's a deviation-approval
279
- # surface in the ADR-044 taxonomy. The inline cross-reference makes
280
- # the framework-resolution boundary visible at the call site.
281
- run awk '/^### 4\./,/^### 5\./' "$SKILL_FILE"
282
- [ "$status" -eq 0 ]
283
- [[ "$output" == *"ADR-044"* ]]
284
- [[ "$output" == *"deviation-approval"* ]] || [[ "$output" == *"category 2"* ]] || [[ "$output" == *"category-2"* ]]
285
- }
286
-
287
- @test "bats file carries the tdd-review: structural-permitted marker (P081 + P136 bridge)" {
288
- # Per P136 Phase 2 inline plan: bats touched during the audit get
289
- # the structural-permitted marker as the bridge until P081 Phase 2's
290
- # canonical retrofit. Without the marker, future TDD agent reviews
291
- # will flag the file as a P081 violation.
292
- run grep -nE "tdd-review:[[:space:]]+structural-permitted" "${BATS_TEST_FILENAME}"
293
- [ "$status" -eq 0 ]
294
- }