@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,83 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# P378/RFC-030: itil-rfc-oversight-nudge.sh (SessionStart) emits a one-line
|
|
4
|
-
# nudge when RFCs lack the human-oversight marker, is silent when none do, and
|
|
5
|
-
# self-suppresses under the shared AFK guard (WR_SUPPRESS_OVERSIGHT_NUDGE=1).
|
|
6
|
-
# Behavioural — exercises the hook against fixture docs/rfcs/ trees. Clone of
|
|
7
|
-
# the architect/jtbd oversight-nudge contract (ADR-066/068).
|
|
8
|
-
|
|
9
|
-
setup() {
|
|
10
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
11
|
-
HOOK="$REPO_ROOT/packages/itil/hooks/itil-rfc-oversight-nudge.sh"
|
|
12
|
-
PLUGIN_ROOT="$REPO_ROOT/packages/itil"
|
|
13
|
-
DIR="$(mktemp -d)"
|
|
14
|
-
mkdir -p "$DIR/docs/rfcs"
|
|
15
|
-
# Hermeticity (P391): the AFK work-problems orchestrator exports
|
|
16
|
-
# WR_SUPPRESS_OVERSIGHT_NUDGE=1, which the hook self-suppresses on. Unset it so
|
|
17
|
-
# count-emitting tests assert real behaviour; guard-specific tests set it
|
|
18
|
-
# per-invocation via `run env WR_SUPPRESS_OVERSIGHT_NUDGE=...`.
|
|
19
|
-
unset WR_SUPPRESS_OVERSIGHT_NUDGE
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
teardown() { rm -rf "$DIR"; }
|
|
23
|
-
|
|
24
|
-
mk_unconfirmed() {
|
|
25
|
-
{ echo "---"; echo "status: proposed"; echo "human-oversight: unconfirmed"; echo "---"; echo "# $1"; } \
|
|
26
|
-
> "$DIR/docs/rfcs/$1"
|
|
27
|
-
}
|
|
28
|
-
mk_confirmed() {
|
|
29
|
-
{ echo "---"; echo "status: proposed"; echo "human-oversight: confirmed"; echo "---"; echo "# $1"; } \
|
|
30
|
-
> "$DIR/docs/rfcs/$1"
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
run_hook() { run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" "$@" bash "$HOOK"; }
|
|
34
|
-
|
|
35
|
-
@test "emits a count line when there are unoversighted RFCs" {
|
|
36
|
-
mk_unconfirmed "RFC-201-foo.proposed.md"
|
|
37
|
-
mk_unconfirmed "RFC-202-bar.proposed.md"
|
|
38
|
-
run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
|
|
39
|
-
[ "$status" -eq 0 ]
|
|
40
|
-
[[ "$output" == *"2 RFCs lack human oversight"* ]]
|
|
41
|
-
[[ "$output" == *"/wr-itil:manage-rfc"* ]]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@test "singular wording for exactly one unoversighted RFC" {
|
|
45
|
-
mk_unconfirmed "RFC-201-foo.proposed.md"
|
|
46
|
-
run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
|
|
47
|
-
[[ "$output" == *"1 RFC lacks human oversight"* ]]
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
@test "silent when every RFC is confirmed" {
|
|
51
|
-
mk_confirmed "RFC-201-foo.proposed.md"
|
|
52
|
-
run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
|
|
53
|
-
[ "$status" -eq 0 ]
|
|
54
|
-
[ -z "$output" ]
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@test "excludes superseded and closed RFCs from the count" {
|
|
58
|
-
mk_unconfirmed "RFC-201-foo.superseded.md"
|
|
59
|
-
mk_unconfirmed "RFC-202-bar.closed.md"
|
|
60
|
-
run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
|
|
61
|
-
[ "$status" -eq 0 ]
|
|
62
|
-
[ -z "$output" ]
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@test "shared AFK guard suppresses the nudge entirely" {
|
|
66
|
-
mk_unconfirmed "RFC-201-foo.proposed.md"
|
|
67
|
-
run env WR_SUPPRESS_OVERSIGHT_NUDGE=1 CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
|
|
68
|
-
[ "$status" -eq 0 ]
|
|
69
|
-
[ -z "$output" ]
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
@test "guard value other than 1 does not suppress" {
|
|
73
|
-
mk_unconfirmed "RFC-201-foo.proposed.md"
|
|
74
|
-
run env WR_SUPPRESS_OVERSIGHT_NUDGE=yes CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
|
|
75
|
-
[[ "$output" == *"lack"*"human oversight"* ]] || [[ "$output" == *"lacks human oversight"* ]]
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
@test "silent when docs/rfcs does not exist (framework not adopted)" {
|
|
79
|
-
rm -rf "$DIR/docs/rfcs"
|
|
80
|
-
run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
|
|
81
|
-
[ "$status" -eq 0 ]
|
|
82
|
-
[ -z "$output" ]
|
|
83
|
-
}
|
|
@@ -1,375 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P170 — Slice 3 second half (B5.T9): PostToolUse:Bash hook
|
|
4
|
-
# detects `git commit` invocations whose HEAD commit message carries
|
|
5
|
-
# a `Refs: RFC-<NNN>` trailer, and emits a stderr advisory when the
|
|
6
|
-
# corresponding driving-problem ticket's `## RFCs` table is stale.
|
|
7
|
-
#
|
|
8
|
-
# Architect Q1 verdict: skill-side refresh primary; hook-side advisory
|
|
9
|
-
# for arbitrary commits (e.g. feat/fix/chore commits with `Refs:` trailer
|
|
10
|
-
# authored outside the RFC skills).
|
|
11
|
-
# Architect Q2 verdict: PostToolUse:Bash; advisory-only; silent-on-pass
|
|
12
|
-
# per ADR-045 Pattern 1; fail-open per ADR-013 Rule 6.
|
|
13
|
-
# Architect Q4 verdict: parse via `git interpret-trailers`; multi-`Refs:`
|
|
14
|
-
# trailers emit malformed-per-finding-8 advisory.
|
|
15
|
-
#
|
|
16
|
-
# Behavioural per ADR-052 + P081: assert on emitted stderr / exit code
|
|
17
|
-
# in response to simulated PostToolUse:Bash payload — no structural
|
|
18
|
-
# greps on hook source.
|
|
19
|
-
#
|
|
20
|
-
# @adr ADR-014 (single-commit grain — hook never auto-fixes via follow-up commit)
|
|
21
|
-
# @adr ADR-013 Rule 6 (fail-open)
|
|
22
|
-
# @adr ADR-045 (silent-on-pass; advisory band ≤300 bytes)
|
|
23
|
-
# @adr ADR-051 (load-bearing-from-the-start)
|
|
24
|
-
# @adr ADR-060 (Phase 1 item 12 + Confirmation criterion 3)
|
|
25
|
-
# @jtbd JTBD-006 (advisory does not block AFK loop — exit 0; stderr only)
|
|
26
|
-
# @jtbd JTBD-008 (reverse-trace surface JTBD-008 names — drift detection)
|
|
27
|
-
|
|
28
|
-
setup() {
|
|
29
|
-
SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
30
|
-
HOOK="$SCRIPT_DIR/itil-rfc-trailer-advisory.sh"
|
|
31
|
-
ORIG_DIR="$PWD"
|
|
32
|
-
TEST_DIR=$(mktemp -d)
|
|
33
|
-
cd "$TEST_DIR"
|
|
34
|
-
git init --quiet -b main
|
|
35
|
-
git config user.email "test@example.com"
|
|
36
|
-
git config user.name "Test"
|
|
37
|
-
mkdir -p docs/rfcs docs/problems
|
|
38
|
-
echo "seed" > seed.txt
|
|
39
|
-
git add seed.txt
|
|
40
|
-
git -c commit.gpgsign=false commit --quiet -m "initial"
|
|
41
|
-
unset BYPASS_RFC_TRAILER_ADVISORY
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
teardown() {
|
|
45
|
-
cd "$ORIG_DIR"
|
|
46
|
-
rm -rf "$TEST_DIR"
|
|
47
|
-
unset BYPASS_RFC_TRAILER_ADVISORY
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
write_rfc() {
|
|
51
|
-
local id="$1" slug="$2" status="$3"
|
|
52
|
-
local problems="${4:-[P168]}"
|
|
53
|
-
cat > "docs/rfcs/RFC-${id}-${slug}.${status}.md" <<EOF
|
|
54
|
-
---
|
|
55
|
-
status: ${status}
|
|
56
|
-
rfc-id: ${slug}
|
|
57
|
-
reported: 2026-05-05
|
|
58
|
-
decision-makers: [test]
|
|
59
|
-
problems: ${problems}
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
# RFC-${id}: ${slug}
|
|
63
|
-
|
|
64
|
-
stub
|
|
65
|
-
EOF
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
write_problem_with_rfcs_section() {
|
|
69
|
-
local num="$1" rows="$2"
|
|
70
|
-
local file="docs/problems/${num}-stub.open.md"
|
|
71
|
-
cat > "$file" <<EOF
|
|
72
|
-
# Problem ${num}: stub
|
|
73
|
-
|
|
74
|
-
**Status**: Open
|
|
75
|
-
|
|
76
|
-
## Description
|
|
77
|
-
|
|
78
|
-
stub
|
|
79
|
-
|
|
80
|
-
## Related
|
|
81
|
-
|
|
82
|
-
stub
|
|
83
|
-
|
|
84
|
-
## RFCs
|
|
85
|
-
|
|
86
|
-
| RFC | Status | Title |
|
|
87
|
-
|-----|--------|-------|
|
|
88
|
-
${rows}
|
|
89
|
-
EOF
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
write_problem_without_rfcs_section() {
|
|
93
|
-
local num="$1"
|
|
94
|
-
cat > "docs/problems/${num}-stub.open.md" <<EOF
|
|
95
|
-
# Problem ${num}: stub
|
|
96
|
-
|
|
97
|
-
**Status**: Open
|
|
98
|
-
|
|
99
|
-
## Description
|
|
100
|
-
|
|
101
|
-
stub
|
|
102
|
-
|
|
103
|
-
## Related
|
|
104
|
-
|
|
105
|
-
stub
|
|
106
|
-
EOF
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
run_post_bash_hook() {
|
|
110
|
-
local cmd="$1"
|
|
111
|
-
local json
|
|
112
|
-
json=$(printf '{"tool_name":"Bash","tool_input":{"command":"%s"}}' "$cmd")
|
|
113
|
-
echo "$json" | bash "$HOOK"
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
117
|
-
|
|
118
|
-
@test "hook exists" {
|
|
119
|
-
[ -f "$HOOK" ]
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@test "hook is executable" {
|
|
123
|
-
[ -x "$HOOK" ]
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
# ── Silent paths ────────────────────────────────────────────────────────────
|
|
127
|
-
|
|
128
|
-
@test "non-Bash tool → silent (exit 0; no output)" {
|
|
129
|
-
json='{"tool_name":"Write","tool_input":{"file_path":"foo.txt","content":"x"}}'
|
|
130
|
-
run bash -c "echo '$json' | bash '$HOOK'"
|
|
131
|
-
[ "$status" -eq 0 ]
|
|
132
|
-
[ -z "$output" ]
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
@test "non-commit Bash command → silent" {
|
|
136
|
-
run run_post_bash_hook "git status"
|
|
137
|
-
[ "$status" -eq 0 ]
|
|
138
|
-
[ -z "$output" ]
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
@test "BYPASS_RFC_TRAILER_ADVISORY=1 → silent regardless of drift" {
|
|
142
|
-
write_rfc "001" "foo" "accepted"
|
|
143
|
-
write_problem_without_rfcs_section "168"
|
|
144
|
-
echo "x" > stub.txt
|
|
145
|
-
git add stub.txt
|
|
146
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
147
|
-
BYPASS_RFC_TRAILER_ADVISORY=1 run run_post_bash_hook "git commit -m foo"
|
|
148
|
-
[ "$status" -eq 0 ]
|
|
149
|
-
[ -z "$output" ]
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
@test "outside git work tree → silent" {
|
|
153
|
-
cd "$ORIG_DIR"
|
|
154
|
-
TMP_NONGIT=$(mktemp -d)
|
|
155
|
-
cd "$TMP_NONGIT"
|
|
156
|
-
run run_post_bash_hook "git commit -m foo"
|
|
157
|
-
[ "$status" -eq 0 ]
|
|
158
|
-
[ -z "$output" ]
|
|
159
|
-
cd "$ORIG_DIR"
|
|
160
|
-
rm -rf "$TMP_NONGIT"
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
@test "no docs/rfcs/ → silent (project has not adopted RFC framework)" {
|
|
164
|
-
rm -rf docs/rfcs
|
|
165
|
-
echo "x" > stub.txt
|
|
166
|
-
git add stub.txt
|
|
167
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub"
|
|
168
|
-
run run_post_bash_hook "git commit -m foo"
|
|
169
|
-
[ "$status" -eq 0 ]
|
|
170
|
-
[ -z "$output" ]
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
@test "no docs/problems/ → silent (project has not adopted problem framework)" {
|
|
174
|
-
rm -rf docs/problems
|
|
175
|
-
echo "x" > stub.txt
|
|
176
|
-
git add stub.txt
|
|
177
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub"
|
|
178
|
-
run run_post_bash_hook "git commit -m foo"
|
|
179
|
-
[ "$status" -eq 0 ]
|
|
180
|
-
[ -z "$output" ]
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
@test "commit without Refs: RFC trailer → silent" {
|
|
184
|
-
write_rfc "001" "foo" "accepted"
|
|
185
|
-
write_problem_without_rfcs_section "168"
|
|
186
|
-
echo "x" > stub.txt
|
|
187
|
-
git add stub.txt
|
|
188
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: no trailer"
|
|
189
|
-
run run_post_bash_hook "git commit -m foo"
|
|
190
|
-
[ "$status" -eq 0 ]
|
|
191
|
-
[ -z "$output" ]
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
# ── Advisory paths ──────────────────────────────────────────────────────────
|
|
195
|
-
|
|
196
|
-
@test "Refs: RFC-NNN trailer + stale problem (no ## RFCs section) → stderr advisory" {
|
|
197
|
-
write_rfc "001" "foo" "accepted"
|
|
198
|
-
write_problem_without_rfcs_section "168"
|
|
199
|
-
echo "x" > stub.txt
|
|
200
|
-
git add stub.txt
|
|
201
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
202
|
-
run run_post_bash_hook "git commit -m foo"
|
|
203
|
-
[ "$status" -eq 0 ]
|
|
204
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
205
|
-
[[ "$output" == *"P168"* ]]
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
@test "Refs: RFC-NNN trailer + stale problem (## RFCs section missing this RFC) → stderr advisory" {
|
|
209
|
-
write_rfc "001" "foo" "accepted"
|
|
210
|
-
write_problem_with_rfcs_section "168" "| RFC-002 | proposed | other |"
|
|
211
|
-
echo "x" > stub.txt
|
|
212
|
-
git add stub.txt
|
|
213
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
214
|
-
run run_post_bash_hook "git commit -m foo"
|
|
215
|
-
[ "$status" -eq 0 ]
|
|
216
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
217
|
-
[[ "$output" == *"P168"* ]]
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
@test "Refs: RFC-NNN trailer + current problem ## RFCs (RFC listed) → silent" {
|
|
221
|
-
write_rfc "001" "foo" "accepted"
|
|
222
|
-
write_problem_with_rfcs_section "168" "| RFC-001 | accepted | foo |"
|
|
223
|
-
echo "x" > stub.txt
|
|
224
|
-
git add stub.txt
|
|
225
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
226
|
-
run run_post_bash_hook "git commit -m foo"
|
|
227
|
-
[ "$status" -eq 0 ]
|
|
228
|
-
[ -z "$output" ]
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
# ── Multi-RFC malformed-per-finding-8 ──────────────────────────────────────
|
|
232
|
-
|
|
233
|
-
@test "multiple Refs: RFC trailers → malformed advisory (architect Q4 / finding 8)" {
|
|
234
|
-
write_rfc "001" "foo" "accepted"
|
|
235
|
-
write_rfc "002" "bar" "accepted"
|
|
236
|
-
write_problem_with_rfcs_section "168" "| RFC-001 | accepted | foo |"
|
|
237
|
-
echo "x" > stub.txt
|
|
238
|
-
git add stub.txt
|
|
239
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001
|
|
240
|
-
Refs: RFC-002"
|
|
241
|
-
run run_post_bash_hook "git commit -m foo"
|
|
242
|
-
[ "$status" -eq 0 ]
|
|
243
|
-
# The advisory names finding-8 / split / mis-scoped vocabulary.
|
|
244
|
-
[[ "$output" == *"finding-8"* || "$output" == *"split"* || "$output" == *"mis-scoped"* ]]
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
# ── Trailer to non-existent RFC ──────────────────────────────────────────────
|
|
248
|
-
|
|
249
|
-
@test "Refs: RFC trailer with no matching file → silent (RFC may be in flight elsewhere)" {
|
|
250
|
-
write_problem_without_rfcs_section "168"
|
|
251
|
-
echo "x" > stub.txt
|
|
252
|
-
git add stub.txt
|
|
253
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-999"
|
|
254
|
-
run run_post_bash_hook "git commit -m foo"
|
|
255
|
-
[ "$status" -eq 0 ]
|
|
256
|
-
# Fail-open: missing RFC files don't promote to advisory (could be capture-rfc invocation in flight).
|
|
257
|
-
[ -z "$output" ]
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
# ── Advisory budget ─────────────────────────────────────────────────────────
|
|
261
|
-
|
|
262
|
-
@test "advisory message stays within ADR-045 advisory band (≤300 bytes)" {
|
|
263
|
-
write_rfc "001" "byte-budget-test-with-an-extra-long-slug-to-stress-row-width" "accepted"
|
|
264
|
-
write_problem_without_rfcs_section "168"
|
|
265
|
-
echo "x" > stub.txt
|
|
266
|
-
git add stub.txt
|
|
267
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
268
|
-
run run_post_bash_hook "git commit -m foo"
|
|
269
|
-
[ "$status" -eq 0 ]
|
|
270
|
-
[ -n "$output" ]
|
|
271
|
-
# Permit per-line overhead; the advisory should remain readable.
|
|
272
|
-
[ "${#output}" -le 600 ]
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
# ── P274 / P268 leading-executable regression cases ─────────────────────────
|
|
276
|
-
#
|
|
277
|
-
# The hook must fire on ACTUAL `git commit` invocations, NOT on Bash that
|
|
278
|
-
# merely MENTIONS the phrase "git commit" in argument vectors or heredoc
|
|
279
|
-
# bodies. Mirrors the P268 regression fixtures in command-detect.bats and
|
|
280
|
-
# the P272 sibling fixtures in itil-changeset-discipline.bats.
|
|
281
|
-
#
|
|
282
|
-
# Setup constructs a drift state (RFC + stale problem) — the hook would
|
|
283
|
-
# emit an advisory on any `git commit` after `Refs: RFC-001` lands in HEAD.
|
|
284
|
-
# These tests confirm non-commit Bash that mentions "git commit" does NOT
|
|
285
|
-
# emit the advisory.
|
|
286
|
-
|
|
287
|
-
@test "P274 allow: grep with literal 'git commit' pattern in drift state → silent" {
|
|
288
|
-
write_rfc "001" "foo" "accepted"
|
|
289
|
-
write_problem_without_rfcs_section "168"
|
|
290
|
-
echo "x" > stub.txt
|
|
291
|
-
git add stub.txt
|
|
292
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
293
|
-
run run_post_bash_hook "grep -r 'git commit' ."
|
|
294
|
-
[ "$status" -eq 0 ]
|
|
295
|
-
[ -z "$output" ]
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
@test "P274 allow: sed pattern containing 'git commit' in drift state → silent" {
|
|
299
|
-
write_rfc "001" "foo" "accepted"
|
|
300
|
-
write_problem_without_rfcs_section "168"
|
|
301
|
-
echo "x" > stub.txt
|
|
302
|
-
git add stub.txt
|
|
303
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
304
|
-
run run_post_bash_hook "sed -n 's/git commit/X/p' stub.txt"
|
|
305
|
-
[ "$status" -eq 0 ]
|
|
306
|
-
[ -z "$output" ]
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
@test "P274 allow: echo with literal 'git commit' string in drift state → silent" {
|
|
310
|
-
write_rfc "001" "foo" "accepted"
|
|
311
|
-
write_problem_without_rfcs_section "168"
|
|
312
|
-
echo "x" > stub.txt
|
|
313
|
-
git add stub.txt
|
|
314
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
315
|
-
run run_post_bash_hook "echo 'run git commit -m foo'"
|
|
316
|
-
[ "$status" -eq 0 ]
|
|
317
|
-
[ -z "$output" ]
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
@test "P274 allow: git log --grep with 'git commit' search term in drift state → silent" {
|
|
321
|
-
write_rfc "001" "foo" "accepted"
|
|
322
|
-
write_problem_without_rfcs_section "168"
|
|
323
|
-
echo "x" > stub.txt
|
|
324
|
-
git add stub.txt
|
|
325
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
326
|
-
run run_post_bash_hook "git log --grep='git commit'"
|
|
327
|
-
[ "$status" -eq 0 ]
|
|
328
|
-
[ -z "$output" ]
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
@test "P274 allow: git commit-tree plumbing in drift state → silent (boundary)" {
|
|
332
|
-
write_rfc "001" "foo" "accepted"
|
|
333
|
-
write_problem_without_rfcs_section "168"
|
|
334
|
-
echo "x" > stub.txt
|
|
335
|
-
git add stub.txt
|
|
336
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
337
|
-
run run_post_bash_hook "git commit-tree HEAD^{tree} -m 'msg'"
|
|
338
|
-
[ "$status" -eq 0 ]
|
|
339
|
-
[ -z "$output" ]
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
# ── P274 positive leading-executable cases still emit advisory ──────────────
|
|
343
|
-
|
|
344
|
-
@test "P274 advisory: env-var-prefixed git commit in drift state still emits advisory" {
|
|
345
|
-
write_rfc "001" "foo" "accepted"
|
|
346
|
-
write_problem_without_rfcs_section "168"
|
|
347
|
-
echo "x" > stub.txt
|
|
348
|
-
git add stub.txt
|
|
349
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
350
|
-
run run_post_bash_hook "GIT_AUTHOR_NAME=foo git commit -m foo"
|
|
351
|
-
[ "$status" -eq 0 ]
|
|
352
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
@test "P274 advisory: cd-prefixed git commit in drift state still emits advisory" {
|
|
356
|
-
write_rfc "001" "foo" "accepted"
|
|
357
|
-
write_problem_without_rfcs_section "168"
|
|
358
|
-
echo "x" > stub.txt
|
|
359
|
-
git add stub.txt
|
|
360
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
361
|
-
run run_post_bash_hook "cd . && git commit -m foo"
|
|
362
|
-
[ "$status" -eq 0 ]
|
|
363
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
@test "P274 advisory: leading-whitespace git commit in drift state still emits advisory" {
|
|
367
|
-
write_rfc "001" "foo" "accepted"
|
|
368
|
-
write_problem_without_rfcs_section "168"
|
|
369
|
-
echo "x" > stub.txt
|
|
370
|
-
git add stub.txt
|
|
371
|
-
git -c commit.gpgsign=false commit --quiet -m "feat: stub" -m "" -m "Refs: RFC-001"
|
|
372
|
-
run run_post_bash_hook " git commit -m foo"
|
|
373
|
-
[ "$status" -eq 0 ]
|
|
374
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
375
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Behavioural tests for itil-story-mirror-migration-nudge.sh — the P474 / RFC-059
|
|
3
|
-
# self-firing cadence for the story `**Status**:` mirror migration.
|
|
4
|
-
#
|
|
5
|
-
# Why this exists: the migration is a PATH shim, so it does not surface in
|
|
6
|
-
# autocomplete, and its only announcement was the release note. Release notes
|
|
7
|
-
# cannot fire in an adopter's repo — prose counts as zero control paths — so
|
|
8
|
-
# artefacts predating the fix would keep the defect indefinitely while newly
|
|
9
|
-
# captured stories were immune. A maintenance action with no automatic trigger
|
|
10
|
-
# does not happen.
|
|
11
|
-
#
|
|
12
|
-
# Three contract conditions this suite locks, per the JTBD-009 review:
|
|
13
|
-
# 1. Nudge-only, never auto-run — JTBD-009's "I review the rewritten artefacts
|
|
14
|
-
# before they ship" is a ratified outcome, so the hook must not migrate.
|
|
15
|
-
# 2. Names the PATH shim, never a repo-relative `packages/...` path, which
|
|
16
|
-
# would only resolve in the source monorepo (P151/P153/P219/P317).
|
|
17
|
-
# 3. Silent when clean, so steady state costs nothing.
|
|
18
|
-
#
|
|
19
|
-
# @problem P474 @adr ADR-049 ADR-090 @story STORY-054
|
|
20
|
-
|
|
21
|
-
setup() {
|
|
22
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
23
|
-
HOOK="$REPO_ROOT/packages/itil/hooks/itil-story-mirror-migration-nudge.sh"
|
|
24
|
-
TMPD="$(mktemp -d)"
|
|
25
|
-
mkdir -p "$TMPD/docs/stories/draft" "$TMPD/docs/stories/accepted"
|
|
26
|
-
# AFK iters export the shared oversight guard; unset so the positive cases do
|
|
27
|
-
# not false-RED inside one (the P391 hermeticity class).
|
|
28
|
-
unset WR_SUPPRESS_OVERSIGHT_NUDGE
|
|
29
|
-
}
|
|
30
|
-
teardown() { unset WR_SUPPRESS_OVERSIGHT_NUDGE; rm -rf "$TMPD"; }
|
|
31
|
-
|
|
32
|
-
seed_with_mirror() {
|
|
33
|
-
printf -- '---\nstatus: draft\n---\n\n# STORY-901: x\n\n**Status**: draft\n**Reported**: 2026-07-30\n' \
|
|
34
|
-
> "$TMPD/docs/stories/draft/STORY-901-x.md"
|
|
35
|
-
}
|
|
36
|
-
seed_clean() {
|
|
37
|
-
printf -- '---\nstatus: draft\n---\n\n# STORY-902: y\n\n**Reported**: 2026-07-30\n' \
|
|
38
|
-
> "$TMPD/docs/stories/draft/STORY-902-y.md"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@test "fires when a story still carries the **Status** mirror" {
|
|
42
|
-
seed_with_mirror
|
|
43
|
-
run env CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
44
|
-
[ "$status" -eq 0 ]
|
|
45
|
-
[ -n "$output" ]
|
|
46
|
-
[[ "$output" == *"[wr-itil]"* ]]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@test "names the PATH shim so it resolves in an adopter install" {
|
|
50
|
-
seed_with_mirror
|
|
51
|
-
run env CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
52
|
-
[[ "$output" == *"wr-itil-migrate-story-status-mirror"* ]]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
# The recurring adopter-portability class: a repo-relative path resolves only in
|
|
56
|
-
# the source monorepo, so source-repo dogfooding hides the breakage.
|
|
57
|
-
@test "never emits a repo-relative packages/ path" {
|
|
58
|
-
seed_with_mirror
|
|
59
|
-
run env CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
60
|
-
[[ "$output" != *"packages/itil"* ]]
|
|
61
|
-
[[ "$output" != *"scripts/migrate-story-status-mirror.sh"* ]]
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@test "silent when no story carries the mirror" {
|
|
65
|
-
seed_clean
|
|
66
|
-
run env CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
67
|
-
[ "$status" -eq 0 ]
|
|
68
|
-
[ -z "$output" ]
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@test "silent when there is no stories directory at all" {
|
|
72
|
-
run env CLAUDE_PROJECT_DIR="$(mktemp -d)" bash "$HOOK"
|
|
73
|
-
[ "$status" -eq 0 ]
|
|
74
|
-
[ -z "$output" ]
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
@test "counts affected stories rather than reporting a bare flag" {
|
|
78
|
-
seed_with_mirror
|
|
79
|
-
printf -- '---\nstatus: draft\n---\n\n# STORY-903: z\n\n**Status**: draft\n' \
|
|
80
|
-
> "$TMPD/docs/stories/accepted/STORY-903-z.md"
|
|
81
|
-
run env CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
82
|
-
[[ "$output" == *"2"* ]]
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
# Ratified JTBD-009 outcome: the developer reviews the rewrite before it ships.
|
|
86
|
-
# A nudge that migrated on its own would breach that, so assert the file is
|
|
87
|
-
# untouched — this is the condition that keeps the hook inside the job.
|
|
88
|
-
@test "NEVER migrates — the story file is left exactly as found" {
|
|
89
|
-
seed_with_mirror
|
|
90
|
-
local before; before="$(cat "$TMPD/docs/stories/draft/STORY-901-x.md")"
|
|
91
|
-
run env CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
92
|
-
[ "$status" -eq 0 ]
|
|
93
|
-
[ "$before" = "$(cat "$TMPD/docs/stories/draft/STORY-901-x.md")" ]
|
|
94
|
-
grep -qE '^\*\*Status\*\*: draft' "$TMPD/docs/stories/draft/STORY-901-x.md"
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
@test "self-suppresses under the shared AFK oversight guard" {
|
|
98
|
-
seed_with_mirror
|
|
99
|
-
run env WR_SUPPRESS_OVERSIGHT_NUDGE=1 CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
100
|
-
[ "$status" -eq 0 ]
|
|
101
|
-
[ -z "$output" ]
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
@test "only the literal value 1 suppresses" {
|
|
105
|
-
seed_with_mirror
|
|
106
|
-
run env WR_SUPPRESS_OVERSIGHT_NUDGE=yes CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
107
|
-
[ -n "$output" ]
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
# README documents the template and legitimately shows the field; scanning it
|
|
111
|
-
# would make the nudge fire forever on a clean corpus.
|
|
112
|
-
@test "ignores docs/stories/README.md" {
|
|
113
|
-
printf -- '# Stories\n\n**Status**: <status>\n' > "$TMPD/docs/stories/README.md"
|
|
114
|
-
run env CLAUDE_PROJECT_DIR="$TMPD" bash "$HOOK"
|
|
115
|
-
[ "$status" -eq 0 ]
|
|
116
|
-
[ -z "$output" ]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@test "registered on SessionStart startup in hooks.json" {
|
|
120
|
-
run grep -c 'itil-story-mirror-migration-nudge.sh' "$REPO_ROOT/packages/itil/hooks/hooks.json"
|
|
121
|
-
[ "$output" -ge 1 ]
|
|
122
|
-
}
|