@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.
- package/.claude-plugin/plugin.json +1 -1
- package/package.json +7 -2
- package/agents/test/fixtures/proceed-new-genuinely-new.md +0 -43
- package/agents/test/fixtures/proceed-new-subtle-sibling.md +0 -47
- package/agents/test/fixtures/regression-p347-vs-p346.md +0 -54
- package/agents/test/hang-off-check.bats +0 -225
- package/hooks/test/block-list.bats +0 -153
- package/hooks/test/command-detect.bats +0 -181
- package/hooks/test/itil-assistant-output-gate.bats +0 -114
- package/hooks/test/itil-assistant-output-review.bats +0 -224
- package/hooks/test/itil-bash-polling-antipattern-detect.bats +0 -154
- package/hooks/test/itil-changeset-discipline.bats +0 -603
- package/hooks/test/itil-claude-space-protection.bats +0 -294
- package/hooks/test/itil-commit-trailer-transition-advisory.bats +0 -80
- package/hooks/test/itil-correction-detect.bats +0 -189
- package/hooks/test/itil-deferral-cadence-gate.bats +0 -187
- package/hooks/test/itil-fictional-defer-detect.bats +0 -292
- package/hooks/test/itil-fix-title-lifecycle-advisory.bats +0 -129
- package/hooks/test/itil-mid-loop-ask-detect.bats +0 -220
- package/hooks/test/itil-no-implement-draft-gate.bats +0 -210
- package/hooks/test/itil-pending-questions-surface.bats +0 -307
- package/hooks/test/itil-readme-refresh-discipline.bats +0 -642
- package/hooks/test/itil-rfc-oversight-nudge.bats +0 -83
- package/hooks/test/itil-rfc-trailer-advisory.bats +0 -375
- package/hooks/test/itil-story-mirror-migration-nudge.bats +0 -122
- package/hooks/test/manage-problem-enforce-create.bats +0 -424
- package/hooks/test/p057-staging-trap-detect.bats +0 -231
- package/hooks/test/pre-publish-intake-gate.bats +0 -144
- package/hooks/test/runtime-sid-marker.bats +0 -90
- package/hooks/test/session-id.bats +0 -370
- package/scripts/migrate-problems-add-type.sh +0 -116
- package/scripts/test/catchup-scan.bats +0 -274
- package/scripts/test/check-afk-accept-eligible.bats +0 -310
- package/scripts/test/check-fail-soft-skip-discipline.bats +0 -172
- package/scripts/test/check-fix-rfc-trace.bats +0 -164
- package/scripts/test/check-locale-discipline.bats +0 -291
- package/scripts/test/check-problems-readme-budget.bats +0 -192
- package/scripts/test/check-rfc-has-stories.bats +0 -69
- package/scripts/test/check-rfc-rejected-alternatives.bats +0 -108
- package/scripts/test/check-rfc-stories-ratified.bats +0 -82
- package/scripts/test/check-upstream-responses.bats +0 -503
- package/scripts/test/classify-readme-drift.bats +0 -392
- package/scripts/test/derive-first-dispatch.bats +0 -274
- package/scripts/test/derive-release-vehicle.bats +0 -454
- package/scripts/test/detect-unratified-stories-maps.bats +0 -60
- package/scripts/test/dual-tolerant-glob-rfc-002-t2.bats +0 -309
- package/scripts/test/effort-tally.bats +0 -170
- package/scripts/test/evaluate-relevance.bats +0 -773
- package/scripts/test/kind-a-commands.bats +0 -46
- package/scripts/test/mark-create-gate.bats +0 -59
- package/scripts/test/mark-story-oversight-confirmed.bats +0 -53
- package/scripts/test/migrate-problems-add-type.bats +0 -280
- package/scripts/test/migrate-story-status-mirror.bats +0 -167
- package/scripts/test/no-type-regression-guard.bats +0 -74
- package/scripts/test/oversight-mirror-corpus-lint.bats +0 -150
- package/scripts/test/plugin-exercise-index.bats +0 -386
- package/scripts/test/plugin-maturity-doc-lint.bats +0 -470
- package/scripts/test/plugin-maturity-populate.bats +0 -631
- package/scripts/test/plugin-maturity-render.bats +0 -469
- package/scripts/test/plugin-validate-ci-gate.bats +0 -208
- package/scripts/test/reconcile-readme.bats +0 -1007
- package/scripts/test/reconcile-rfcs.bats +0 -496
- package/scripts/test/reconcile-stories.bats +0 -173
- package/scripts/test/reconcile-story-maps.bats +0 -74
- package/scripts/test/release-watch-poll-loop.bats +0 -180
- package/scripts/test/resolve-governance-plugin-dirs.bats +0 -78
- package/scripts/test/rfc-stories-extension.bats +0 -175
- package/scripts/test/skill-invocations.bats +0 -535
- package/scripts/test/skill-md-dual-tolerant-coverage-rfc-002-t3.bats +0 -374
- package/scripts/test/story-oversight-lib.bats +0 -190
- package/scripts/test/update-jtbd-references-related-problems.bats +0 -178
- package/scripts/test/update-problem-references-section.bats +0 -242
- package/scripts/test/update-problem-rfcs-section.bats +0 -242
- package/scripts/test/update-references-section-sibling-helpers.bats +0 -80
- package/scripts/test/update-rfc-commits-section.bats +0 -77
- package/scripts/test/verify-iter-summary.bats +0 -196
- package/scripts/test/working-the-problem-traversal.bats +0 -116
- package/skills/capture-problem/test/capture-problem-step-1-5b-jtbd-trace.bats +0 -398
- package/skills/capture-problem/test/capture-problem.bats +0 -389
- package/skills/capture-story/test/capture-story-behavioural.bats +0 -317
- package/skills/capture-story-map/test/capture-story-map-behavioural.bats +0 -98
- package/skills/close-incident/test/close-incident-contract.bats +0 -146
- package/skills/link-incident/test/link-incident-contract.bats +0 -125
- package/skills/list-incidents/test/list-incidents-contract.bats +0 -115
- package/skills/list-problems/test/list-problems-contract.bats +0 -100
- package/skills/list-stories/test/list-stories-contract.bats +0 -127
- package/skills/list-story-maps/test/list-story-maps-contract.bats +0 -46
- package/skills/manage-incident/test/manage-incident-adr-044-contract.bats +0 -206
- package/skills/manage-incident/test/manage-incident-close-forwarder.bats +0 -67
- package/skills/manage-incident/test/manage-incident-link-forwarder.bats +0 -67
- package/skills/manage-incident/test/manage-incident-list-forwarder.bats +0 -68
- package/skills/manage-incident/test/manage-incident-mitigate-forwarder.bats +0 -66
- package/skills/manage-incident/test/manage-incident-restore-forwarder.bats +0 -66
- package/skills/manage-incident/test/manage-incident.bats +0 -171
- package/skills/manage-problem/test/manage-problem-adr-044-step4-derive-first.bats +0 -151
- package/skills/manage-problem/test/manage-problem-auto-migrate-step.bats +0 -53
- package/skills/manage-problem/test/manage-problem-concern-boundary.bats +0 -64
- package/skills/manage-problem/test/manage-problem-effort-buckets.bats +0 -56
- package/skills/manage-problem/test/manage-problem-external-root-cause-detection.bats +0 -119
- package/skills/manage-problem/test/manage-problem-first-run-intake-prompt.bats +0 -43
- package/skills/manage-problem/test/manage-problem-git-mv-restage-reminder.bats +0 -48
- package/skills/manage-problem/test/manage-problem-id-collision-guard.bats +0 -39
- package/skills/manage-problem/test/manage-problem-list-forwarder.bats +0 -66
- package/skills/manage-problem/test/manage-problem-next-id-origin-lookup.bats +0 -50
- package/skills/manage-problem/test/manage-problem-no-prose-options.bats +0 -74
- package/skills/manage-problem/test/manage-problem-output-formatting.bats +0 -30
- package/skills/manage-problem/test/manage-problem-parked-and-cache.bats +0 -73
- package/skills/manage-problem/test/manage-problem-readme-refresh-on-transition.bats +0 -62
- package/skills/manage-problem/test/manage-problem-readme-tie-break-order.bats +0 -318
- package/skills/manage-problem/test/manage-problem-readme-vq-sort-order.bats +0 -206
- package/skills/manage-problem/test/manage-problem-release-vehicle-seed.bats +0 -83
- package/skills/manage-problem/test/manage-problem-review-forwarder.bats +0 -71
- package/skills/manage-problem/test/manage-problem-step-9d-recovery-path.bats +0 -97
- package/skills/manage-problem/test/manage-problem-transition-forwarder.bats +0 -96
- package/skills/manage-problem/test/manage-problem-transitive-dependencies.bats +0 -365
- package/skills/manage-problem/test/manage-problem-verification-detection.bats +0 -64
- package/skills/manage-problem/test/manage-problem-verification-pending.bats +0 -114
- package/skills/manage-problem/test/manage-problem-work-forwarder.bats +0 -88
- package/skills/manage-story/test/manage-story-contract.bats +0 -174
- package/skills/manage-story-map/test/manage-story-map-contract.bats +0 -63
- package/skills/mitigate-incident/test/mitigate-incident-contract.bats +0 -258
- package/skills/reconcile-readme/test/reconcile-readme-contract.bats +0 -201
- package/skills/report-upstream/test/report-upstream-contract.bats +0 -394
- package/skills/restore-incident/test/restore-incident-contract.bats +0 -170
- package/skills/review-problems/test/inbound-channels-cache-shape.bats +0 -127
- package/skills/review-problems/test/inbound-discovery-contract.bats +0 -383
- package/skills/review-problems/test/jtbd-301-verdict-shape-contract.bats +0 -225
- package/skills/review-problems/test/review-problems-contract.bats +0 -235
- package/skills/review-problems/test/review-problems-likely-verified-cell-shape.bats +0 -229
- package/skills/scaffold-intake/test/scaffold-intake-contract.bats +0 -126
- package/skills/scaffold-intake/test/scaffold-intake-fixture.bats +0 -164
- package/skills/scaffold-intake/test/scaffold-intake-secrets-absent.bats +0 -87
- package/skills/transition-problem/test/transition-problem-contract.bats +0 -285
- package/skills/transition-problems/test/transition-problems-contract.bats +0 -331
- package/skills/update-upstream/test/update-upstream-contract.bats +0 -375
- package/skills/work-problem/test/work-problem-contract.bats +0 -294
- package/skills/work-problems/test/work-problems-above-appetite-remediation.bats +0 -139
- package/skills/work-problems/test/work-problems-adr-013-rule-6-p352-amendment.bats +0 -166
- package/skills/work-problems/test/work-problems-auto-migrate-step.bats +0 -57
- package/skills/work-problems/test/work-problems-cost-logging.bats +0 -109
- package/skills/work-problems/test/work-problems-deviation-candidate-shape.bats +0 -121
- package/skills/work-problems/test/work-problems-first-run-intake-prompt.bats +0 -36
- package/skills/work-problems/test/work-problems-inter-iteration-verify.bats +0 -59
- package/skills/work-problems/test/work-problems-mid-loop-userpromptsubmit-handler.bats +0 -69
- package/skills/work-problems/test/work-problems-no-mid-loop-asking.bats +0 -192
- package/skills/work-problems/test/work-problems-p341-pre-all-done-gate.bats +0 -122
- package/skills/work-problems/test/work-problems-p342-r007-derive-then-pass-flags.bats +0 -170
- package/skills/work-problems/test/work-problems-p342-retro-auto-ticket-carveout.bats +0 -120
- package/skills/work-problems/test/work-problems-preflight-failure-handling.bats +0 -248
- package/skills/work-problems/test/work-problems-preflight-session-continuity.bats +0 -139
- package/skills/work-problems/test/work-problems-preflight.bats +0 -69
- package/skills/work-problems/test/work-problems-release-cadence.bats +0 -63
- package/skills/work-problems/test/work-problems-step-0-iter-error-staleness.bats +0 -93
- package/skills/work-problems/test/work-problems-step-0b-cache-staleness-behavioural.bats +0 -138
- package/skills/work-problems/test/work-problems-step-0c-deferred-placeholder-staleness-behavioural.bats +0 -238
- package/skills/work-problems/test/work-problems-step-0d-outbound-responses-staleness-behavioural.bats +0 -174
- package/skills/work-problems/test/work-problems-step-2-5-routing.bats +0 -80
- package/skills/work-problems/test/work-problems-step-2-5b-cross-halt-routing.bats +0 -149
- package/skills/work-problems/test/work-problems-step-3-5-jtbd-ratification-predicate.bats +0 -191
- package/skills/work-problems/test/work-problems-step-5-bats-polling-discipline.bats +0 -91
- package/skills/work-problems/test/work-problems-step-5-delegation.bats +0 -333
- package/skills/work-problems/test/work-problems-step-5-idle-timeout-sigterm.bats +0 -421
- package/skills/work-problems/test/work-problems-step-5-is-error-transient-halt.bats +0 -278
- package/skills/work-problems/test/work-problems-step-5-iter-changeset-required.bats +0 -95
- package/skills/work-problems/test/work-problems-step-5-prompt-body-re-grounding.bats +0 -128
- package/skills/work-problems/test/work-problems-step-5-stream-timeout-salvage.bats +0 -251
- package/skills/work-problems/test/work-problems-step-6-5-always-drain.bats +0 -203
- package/skills/work-problems/test/work-problems-step-6-5-cache-refresh-chain.bats +0 -174
- package/skills/work-problems/test/work-problems-step-6-5-fix-and-continue.bats +0 -254
- package/skills/work-problems/test/work-problems-step-6-5-postrelease-kv-callback.bats +0 -209
- package/skills/work-problems/test/work-problems-stop-condition-questions.bats +0 -85
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# P132 Phase 2b: itil-mid-loop-ask-detect.sh Stop hook detects
|
|
4
|
-
# orchestrator main-turn AskUserQuestion calls fired mid-loop inside
|
|
5
|
-
# /wr-itil:work-problems — the regression class P132 captures
|
|
6
|
-
# (2026-05-17 reopen: orchestrator asked iter-target selection between
|
|
7
|
-
# iters 3 and 4; halted the loop for hours of AFK time).
|
|
8
|
-
#
|
|
9
|
-
# Detection signal:
|
|
10
|
-
# 1. Last assistant turn contains an AskUserQuestion tool_use
|
|
11
|
-
# 2. Earlier transcript contains a Skill tool_use to wr-itil:work-problems
|
|
12
|
-
# 3. No `ALL_DONE` / `## Work Problems Summary` marker has been emitted
|
|
13
|
-
# since the skill activation (mid-loop, not post-loop wrap)
|
|
14
|
-
#
|
|
15
|
-
# When all three match the hook emits a structured `stopReason`
|
|
16
|
-
# advisory citing P130 + the Mid-loop ask discipline subsection of
|
|
17
|
-
# work-problems SKILL.md. Advisory only — never blocks. Mirrors the
|
|
18
|
-
# itil-assistant-output-review.sh Stop hook precedent (P085 prose-ask
|
|
19
|
-
# detection) but on a different signal class.
|
|
20
|
-
#
|
|
21
|
-
# Per ADR-005 / ADR-052 — bats live under packages/<plugin>/hooks/test/
|
|
22
|
-
# and assert behaviour on emitted JSON, not source-content. Per
|
|
23
|
-
# feedback_behavioural_tests.md (P081) — no source-grep on hook text.
|
|
24
|
-
|
|
25
|
-
setup() {
|
|
26
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
27
|
-
HOOK="$REPO_ROOT/packages/itil/hooks/itil-mid-loop-ask-detect.sh"
|
|
28
|
-
TMPDIR_="$(mktemp -d)"
|
|
29
|
-
TRANSCRIPT="$TMPDIR_/transcript.jsonl"
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
teardown() {
|
|
33
|
-
rm -rf "$TMPDIR_"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
# Helper: emit the JSONL transcript line for an assistant turn
|
|
37
|
-
# containing a Skill tool_use to wr-itil:work-problems.
|
|
38
|
-
emit_orchestrator_activation() {
|
|
39
|
-
cat <<'JSON'
|
|
40
|
-
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Skill","input":{"skill":"wr-itil:work-problems"}}]}}
|
|
41
|
-
JSON
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
# Helper: emit a benign assistant text turn (no tool_use).
|
|
45
|
-
emit_text_turn() {
|
|
46
|
-
local text="$1"
|
|
47
|
-
printf '{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":%s}]}}\n' \
|
|
48
|
-
"$(printf '%s' "$text" | jq -Rs .)"
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# Helper: emit an assistant turn containing an AskUserQuestion tool_use.
|
|
52
|
-
emit_ask_turn() {
|
|
53
|
-
local header="${1:-Next problem}"
|
|
54
|
-
cat <<JSON
|
|
55
|
-
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"AskUserQuestion","input":{"questions":[{"question":"Pick next iter","header":"${header}","options":[{"label":"A","description":"x"},{"label":"B","description":"y"}]}]}}]}}
|
|
56
|
-
JSON
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
run_hook() {
|
|
60
|
-
echo "{\"session_id\":\"mid-loop-test\",\"transcript_path\":$(printf '%s' "$TRANSCRIPT" | jq -Rs .)}" | bash "$HOOK"
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
# --- Positive detection ---
|
|
64
|
-
|
|
65
|
-
@test "detect: orchestrator activation + final AskUserQuestion + no terminal marker emits stopReason" {
|
|
66
|
-
{
|
|
67
|
-
printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
|
|
68
|
-
emit_orchestrator_activation
|
|
69
|
-
emit_text_turn "Iter 1 complete. Dispatching iter 2."
|
|
70
|
-
emit_text_turn "Iter 2 complete. Dispatching iter 3."
|
|
71
|
-
emit_ask_turn "Pick next iter"
|
|
72
|
-
} > "$TRANSCRIPT"
|
|
73
|
-
run run_hook
|
|
74
|
-
[ "$status" -eq 0 ]
|
|
75
|
-
[[ "$output" == *"stopReason"* ]]
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
@test "detect: stopReason cites P130 + framework-prescribed halt points" {
|
|
79
|
-
{
|
|
80
|
-
printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
|
|
81
|
-
emit_orchestrator_activation
|
|
82
|
-
emit_text_turn "Iter 1 done."
|
|
83
|
-
emit_ask_turn "Next problem"
|
|
84
|
-
} > "$TRANSCRIPT"
|
|
85
|
-
run run_hook
|
|
86
|
-
[ "$status" -eq 0 ]
|
|
87
|
-
[[ "$output" == *"P130"* ]]
|
|
88
|
-
[[ "$output" == *"halt point"* ]]
|
|
89
|
-
[[ "$output" == *"outstanding_questions"* ]]
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@test "detect: stopReason cites ADR-044 framework-resolution boundary" {
|
|
93
|
-
{
|
|
94
|
-
printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
|
|
95
|
-
emit_orchestrator_activation
|
|
96
|
-
emit_text_turn "Iter 1 done."
|
|
97
|
-
emit_ask_turn "Pick"
|
|
98
|
-
} > "$TRANSCRIPT"
|
|
99
|
-
run run_hook
|
|
100
|
-
[ "$status" -eq 0 ]
|
|
101
|
-
[[ "$output" == *"ADR-044"* ]]
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# --- Negative paths: silent exit ---
|
|
105
|
-
|
|
106
|
-
@test "allow: transcript with no orchestrator activation exits silently" {
|
|
107
|
-
# User asked a question outside /wr-itil:work-problems context;
|
|
108
|
-
# AskUserQuestion in this case is unrelated to mid-loop discipline.
|
|
109
|
-
{
|
|
110
|
-
printf '{"type":"user","message":{"role":"user","content":"help me design a feature"}}\n'
|
|
111
|
-
emit_text_turn "Two paths come to mind."
|
|
112
|
-
emit_ask_turn "Design choice"
|
|
113
|
-
} > "$TRANSCRIPT"
|
|
114
|
-
run run_hook
|
|
115
|
-
[ "$status" -eq 0 ]
|
|
116
|
-
[[ "$output" != *"stopReason"* ]]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@test "allow: orchestrator activated then ALL_DONE emitted (post-loop wrap)" {
|
|
120
|
-
# The orchestrator has emitted its terminal summary; subsequent
|
|
121
|
-
# AskUserQuestion is post-loop interactive follow-up, not mid-loop.
|
|
122
|
-
{
|
|
123
|
-
printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
|
|
124
|
-
emit_orchestrator_activation
|
|
125
|
-
emit_text_turn "Iter 1 complete."
|
|
126
|
-
emit_text_turn "## Work Problems Summary
|
|
127
|
-
All iters complete.
|
|
128
|
-
ALL_DONE"
|
|
129
|
-
emit_ask_turn "Follow-up question"
|
|
130
|
-
} > "$TRANSCRIPT"
|
|
131
|
-
run run_hook
|
|
132
|
-
[ "$status" -eq 0 ]
|
|
133
|
-
[[ "$output" != *"stopReason"* ]]
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
@test "allow: orchestrator activated then Work Problems Summary header emitted (post-loop)" {
|
|
137
|
-
{
|
|
138
|
-
printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
|
|
139
|
-
emit_orchestrator_activation
|
|
140
|
-
emit_text_turn "## Work Problems Summary
|
|
141
|
-
|
|
142
|
-
Completed: 3 iters."
|
|
143
|
-
emit_ask_turn "Next steps?"
|
|
144
|
-
} > "$TRANSCRIPT"
|
|
145
|
-
run run_hook
|
|
146
|
-
[ "$status" -eq 0 ]
|
|
147
|
-
[[ "$output" != *"stopReason"* ]]
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
@test "allow: last assistant turn does not contain AskUserQuestion" {
|
|
151
|
-
{
|
|
152
|
-
printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
|
|
153
|
-
emit_orchestrator_activation
|
|
154
|
-
emit_text_turn "Iter 2 dispatched."
|
|
155
|
-
} > "$TRANSCRIPT"
|
|
156
|
-
run run_hook
|
|
157
|
-
[ "$status" -eq 0 ]
|
|
158
|
-
[[ "$output" != *"stopReason"* ]]
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
@test "allow: missing transcript_path exits silently" {
|
|
162
|
-
run bash -c 'echo "{\"session_id\":\"sid\"}" | bash "$1"' -- "$HOOK"
|
|
163
|
-
[ "$status" -eq 0 ]
|
|
164
|
-
[[ "$output" != *"stopReason"* ]]
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
@test "allow: non-existent transcript file exits silently" {
|
|
168
|
-
run bash -c "echo '{\"session_id\":\"sid\",\"transcript_path\":\"/tmp/does-not-exist-$RANDOM\"}' | bash '$HOOK'"
|
|
169
|
-
[ "$status" -eq 0 ]
|
|
170
|
-
[[ "$output" != *"stopReason"* ]]
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
@test "allow: empty transcript exits silently" {
|
|
174
|
-
: > "$TRANSCRIPT"
|
|
175
|
-
run run_hook
|
|
176
|
-
[ "$status" -eq 0 ]
|
|
177
|
-
[[ "$output" != *"stopReason"* ]]
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
@test "allow: malformed JSONL lines do not crash the hook" {
|
|
181
|
-
{
|
|
182
|
-
echo "not-json"
|
|
183
|
-
emit_orchestrator_activation
|
|
184
|
-
emit_text_turn "Iter 2"
|
|
185
|
-
} > "$TRANSCRIPT"
|
|
186
|
-
run run_hook
|
|
187
|
-
[ "$status" -eq 0 ]
|
|
188
|
-
# Either silent OR stopReason — but never a crash. We assert no
|
|
189
|
-
# non-zero exit; the silent-vs-stopReason split is incidental here.
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
# --- Advisory budget per ADR-045 ---
|
|
193
|
-
|
|
194
|
-
@test "advisory output stays under ADR-045 800-byte honour-system band" {
|
|
195
|
-
{
|
|
196
|
-
printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
|
|
197
|
-
emit_orchestrator_activation
|
|
198
|
-
emit_text_turn "Iter 1 done."
|
|
199
|
-
emit_ask_turn "Pick"
|
|
200
|
-
} > "$TRANSCRIPT"
|
|
201
|
-
run run_hook
|
|
202
|
-
[ "$status" -eq 0 ]
|
|
203
|
-
[[ "$output" == *"stopReason"* ]]
|
|
204
|
-
[ "${#output}" -lt 1000 ]
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
# --- Distinguishing-marker: tool_name for AskUserQuestion --
|
|
208
|
-
|
|
209
|
-
@test "detect: matches even when AskUserQuestion is intermixed with text blocks" {
|
|
210
|
-
{
|
|
211
|
-
printf '{"type":"user","message":{"role":"user","content":"/wr-itil:work-problems"}}\n'
|
|
212
|
-
emit_orchestrator_activation
|
|
213
|
-
cat <<'JSON'
|
|
214
|
-
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"Two iter targets are tied on WSJF:"},{"type":"tool_use","name":"AskUserQuestion","input":{"questions":[{"question":"Pick next iter","header":"Next iter","options":[{"label":"P132","description":"x"},{"label":"P130","description":"y"}]}]}}]}}
|
|
215
|
-
JSON
|
|
216
|
-
} > "$TRANSCRIPT"
|
|
217
|
-
run run_hook
|
|
218
|
-
[ "$status" -eq 0 ]
|
|
219
|
-
[[ "$output" == *"stopReason"* ]]
|
|
220
|
-
}
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Behavioural tests for itil-no-implement-draft-gate.sh (ADR-096 / P404).
|
|
3
|
-
# PreToolUse:Bash — reads a JSON envelope on stdin, emits permissionDecision:deny
|
|
4
|
-
# (exit 0, deny in the JSON) when a commit references a DRAFT story.
|
|
5
|
-
# @adr ADR-096 @adr ADR-052 @problem P404
|
|
6
|
-
|
|
7
|
-
setup() {
|
|
8
|
-
HOOK="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)/itil-no-implement-draft-gate.sh"
|
|
9
|
-
MARK="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../scripts" && pwd)/mark-story-oversight-confirmed.sh"
|
|
10
|
-
TMP="$(mktemp -d)"; cd "$TMP"; git init -q .
|
|
11
|
-
mkdir -p docs/stories/draft docs/stories/accepted docs/stories/in-progress
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
# Seed a minimally well-formed story. Since ADR-101 the gate is ratification-
|
|
15
|
-
# aware, so a bare `touch` no longer produces a story it will pass.
|
|
16
|
-
seed_story() { printf -- '---\nstatus: accepted\n---\n\n# %s\n' "$1" > "$2"; }
|
|
17
|
-
# Ratify via the real write path, never a hand-written marker — the hash has one
|
|
18
|
-
# definition and a hand-rolled fixture would drift from it.
|
|
19
|
-
ratify() { bash "$MARK" "$@" >/dev/null 2>&1; }
|
|
20
|
-
teardown() { cd /; rm -rf "$TMP"; }
|
|
21
|
-
|
|
22
|
-
# write env.json carrying the given command string
|
|
23
|
-
env_cmd() { python3 -c 'import json,sys; open("env.json","w").write(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$1"; }
|
|
24
|
-
|
|
25
|
-
@test "blocks a commit referencing a DRAFT story" {
|
|
26
|
-
touch docs/stories/draft/STORY-042-foo.md
|
|
27
|
-
env_cmd 'git commit -m "fix: thing
|
|
28
|
-
|
|
29
|
-
Refs: STORY-042"'
|
|
30
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
31
|
-
[ "$status" -eq 0 ]
|
|
32
|
-
echo "$output" | grep -q '"permissionDecision": "deny"'
|
|
33
|
-
echo "$output" | grep -q 'STORY-042'
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
# This case previously seeded an EMPTY, unratified accepted story and asserted
|
|
37
|
-
# allow — the P465 hole encoded as a test rather than behaviour anyone chose.
|
|
38
|
-
# ADR-096 always claimed no unratified story could be implemented; nothing
|
|
39
|
-
# enforced it. Split into both directions, flipped in the slice that ships the
|
|
40
|
-
# behaviour (the ADR-089 precedent).
|
|
41
|
-
|
|
42
|
-
@test "allows a commit referencing an ACCEPTED and RATIFIED story" {
|
|
43
|
-
seed_story STORY-042 docs/stories/accepted/STORY-042-foo.md
|
|
44
|
-
ratify docs/stories/accepted/STORY-042-foo.md
|
|
45
|
-
env_cmd 'git commit -m "fix: thing
|
|
46
|
-
|
|
47
|
-
Refs: STORY-042"'
|
|
48
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
49
|
-
[ "$status" -eq 0 ]
|
|
50
|
-
! echo "$output" | grep -q 'deny'
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@test "blocks a commit referencing an ACCEPTED but UNRATIFIED story (P465)" {
|
|
54
|
-
seed_story STORY-042 docs/stories/accepted/STORY-042-foo.md
|
|
55
|
-
env_cmd 'git commit -m "fix: thing
|
|
56
|
-
|
|
57
|
-
Refs: STORY-042"'
|
|
58
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
59
|
-
[ "$status" -eq 0 ]
|
|
60
|
-
echo "$output" | grep -q '"permissionDecision": "deny"'
|
|
61
|
-
echo "$output" | grep -q 'not ratified'
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@test "blocks a commit referencing an IN-PROGRESS story whose content has drifted since ratification" {
|
|
65
|
-
seed_story STORY-042 docs/stories/in-progress/STORY-042-foo.md
|
|
66
|
-
ratify docs/stories/in-progress/STORY-042-foo.md
|
|
67
|
-
printf -- '\nA substance edit made after ratification.\n' >> docs/stories/in-progress/STORY-042-foo.md
|
|
68
|
-
env_cmd 'git commit -m "fix: thing
|
|
69
|
-
|
|
70
|
-
Refs: STORY-042"'
|
|
71
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
72
|
-
[ "$status" -eq 0 ]
|
|
73
|
-
echo "$output" | grep -q '"permissionDecision": "deny"'
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@test "ticking an acceptance criterion is progress, not drift — commit still allowed" {
|
|
77
|
-
cat > docs/stories/in-progress/STORY-042-foo.md <<'EOF'
|
|
78
|
-
---
|
|
79
|
-
status: in-progress
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
# STORY-042
|
|
83
|
-
|
|
84
|
-
## Acceptance criteria (accepted-gate, INVEST Testable)
|
|
85
|
-
|
|
86
|
-
- [ ] The step happens.
|
|
87
|
-
EOF
|
|
88
|
-
ratify docs/stories/in-progress/STORY-042-foo.md
|
|
89
|
-
sed -i.bak 's/- \[ \] The step happens./- [x] The step happens./' docs/stories/in-progress/STORY-042-foo.md
|
|
90
|
-
rm -f docs/stories/in-progress/*.bak
|
|
91
|
-
env_cmd 'git commit -m "fix: thing
|
|
92
|
-
|
|
93
|
-
Refs: STORY-042"'
|
|
94
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
95
|
-
[ "$status" -eq 0 ]
|
|
96
|
-
! echo "$output" | grep -q 'deny'
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
@test "ADR-101: a pure-decomposition story whose basis no longer matches its criteria is blocked" {
|
|
100
|
-
cat > docs/stories/accepted/STORY-042-foo.md <<'EOF'
|
|
101
|
-
---
|
|
102
|
-
status: accepted
|
|
103
|
-
afk-accept: pure-decomposition
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
# STORY-042
|
|
107
|
-
|
|
108
|
-
## Acceptance criteria (accepted-gate, INVEST Testable)
|
|
109
|
-
|
|
110
|
-
- [ ] One.
|
|
111
|
-
- [ ] Two.
|
|
112
|
-
|
|
113
|
-
## Decomposition basis
|
|
114
|
-
|
|
115
|
-
- One decomposes ADR-900.
|
|
116
|
-
EOF
|
|
117
|
-
bash "$MARK" --pure-decomposition docs/stories/accepted/STORY-042-foo.md >/dev/null 2>&1
|
|
118
|
-
env_cmd 'git commit -m "fix: thing
|
|
119
|
-
|
|
120
|
-
Refs: STORY-042"'
|
|
121
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
122
|
-
[ "$status" -eq 0 ]
|
|
123
|
-
echo "$output" | grep -q '"permissionDecision": "deny"'
|
|
124
|
-
echo "$output" | grep -q 'Decomposition basis'
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
@test "ADR-101: a well-formed pure-decomposition story is allowed" {
|
|
128
|
-
cat > docs/stories/accepted/STORY-042-foo.md <<'EOF'
|
|
129
|
-
---
|
|
130
|
-
status: accepted
|
|
131
|
-
afk-accept: pure-decomposition
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
# STORY-042
|
|
135
|
-
|
|
136
|
-
## Acceptance criteria (accepted-gate, INVEST Testable)
|
|
137
|
-
|
|
138
|
-
- [ ] One.
|
|
139
|
-
- [ ] Two.
|
|
140
|
-
|
|
141
|
-
## Decomposition basis
|
|
142
|
-
|
|
143
|
-
- One decomposes ADR-900.
|
|
144
|
-
- Two decomposes ADR-900.
|
|
145
|
-
EOF
|
|
146
|
-
bash "$MARK" --pure-decomposition docs/stories/accepted/STORY-042-foo.md >/dev/null 2>&1
|
|
147
|
-
env_cmd 'git commit -m "fix: thing
|
|
148
|
-
|
|
149
|
-
Refs: STORY-042"'
|
|
150
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
151
|
-
[ "$status" -eq 0 ]
|
|
152
|
-
! echo "$output" | grep -q 'deny'
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
@test "a DONE story is past implementation and is not ratification-gated" {
|
|
156
|
-
mkdir -p docs/stories/done
|
|
157
|
-
touch docs/stories/done/STORY-042-foo.md
|
|
158
|
-
env_cmd 'git commit -m "fix: thing
|
|
159
|
-
|
|
160
|
-
Refs: STORY-042"'
|
|
161
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
162
|
-
[ "$status" -eq 0 ]
|
|
163
|
-
! echo "$output" | grep -q 'deny'
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
@test "exempts a capture commit even for a draft story" {
|
|
167
|
-
touch docs/stories/draft/STORY-042-foo.md
|
|
168
|
-
env_cmd 'git commit -m "feat(itil): capture STORY-042 foo
|
|
169
|
-
|
|
170
|
-
Refs: STORY-042"'
|
|
171
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
172
|
-
[ "$status" -eq 0 ]
|
|
173
|
-
! echo "$output" | grep -q 'deny'
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
@test "bootstrap-exempt commit bypasses" {
|
|
177
|
-
touch docs/stories/draft/STORY-042-foo.md
|
|
178
|
-
env_cmd 'git commit -m "migrate
|
|
179
|
-
|
|
180
|
-
Refs: STORY-042
|
|
181
|
-
bootstrap-exempt: STORY-MAP-001"'
|
|
182
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
183
|
-
[ "$status" -eq 0 ]
|
|
184
|
-
! echo "$output" | grep -q 'deny'
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
@test "non-commit command is a no-op" {
|
|
188
|
-
touch docs/stories/draft/STORY-042-foo.md
|
|
189
|
-
env_cmd 'echo Refs: STORY-042'
|
|
190
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
191
|
-
[ "$status" -eq 0 ]
|
|
192
|
-
! echo "$output" | grep -q 'deny'
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
@test "commit with no story trailer is a no-op" {
|
|
196
|
-
env_cmd 'git commit -m "fix: no story ref"'
|
|
197
|
-
run bash -c "bash '$HOOK' < env.json"
|
|
198
|
-
[ "$status" -eq 0 ]
|
|
199
|
-
! echo "$output" | grep -q 'deny'
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
@test "BYPASS env allows the commit" {
|
|
203
|
-
touch docs/stories/draft/STORY-042-foo.md
|
|
204
|
-
env_cmd 'git commit -m "fix
|
|
205
|
-
|
|
206
|
-
Refs: STORY-042"'
|
|
207
|
-
BYPASS_NO_IMPLEMENT_DRAFT=1 run bash -c "BYPASS_NO_IMPLEMENT_DRAFT=1 bash '$HOOK' < env.json"
|
|
208
|
-
[ "$status" -eq 0 ]
|
|
209
|
-
! echo "$output" | grep -q 'deny'
|
|
210
|
-
}
|