@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,392 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P149 — manage-problem Step 0 reconcile halt-on-drift directive
|
|
4
|
-
# doesn't distinguish uncommitted-rename-rooted drift (same-session pending,
|
|
5
|
-
# in-flow P094/P062 refresh will land it in the upcoming commit per ADR-014)
|
|
6
|
-
# from committed cross-session drift (must halt and route to
|
|
7
|
-
# /wr-itil:reconcile-readme).
|
|
8
|
-
#
|
|
9
|
-
# Contract: `classify-readme-drift.sh <drift-stdout-file> [<problems-dir>]`
|
|
10
|
-
# reads the captured stdout of reconcile-readme.sh exit-1 output AND the
|
|
11
|
-
# working-tree state via `git status --porcelain`, then classifies the drift.
|
|
12
|
-
#
|
|
13
|
-
# Output (stdout, one classification line):
|
|
14
|
-
# INLINE_REFRESH covered=<N> — every drift ID is the destination
|
|
15
|
-
# of a staged rename in the working
|
|
16
|
-
# tree; defer to in-flow P094/P062
|
|
17
|
-
# refresh per ADR-014.
|
|
18
|
-
# HALT_ROUTE_RECONCILE uncovered=<N> — at least one drift ID is NOT
|
|
19
|
-
# covered by a working-tree rename;
|
|
20
|
-
# committed cross-session drift OR
|
|
21
|
-
# mixed; route to
|
|
22
|
-
# /wr-itil:reconcile-readme.
|
|
23
|
-
#
|
|
24
|
-
# Exit codes:
|
|
25
|
-
# 0 = INLINE_REFRESH
|
|
26
|
-
# 1 = HALT_ROUTE_RECONCILE
|
|
27
|
-
# 2 = parse error (drift-stdout-file missing or empty)
|
|
28
|
-
#
|
|
29
|
-
# @adr ADR-014 (single-commit grain — the carve-out preserves it for the
|
|
30
|
-
# in-flow path while keeping cross-session drift safety)
|
|
31
|
-
# @adr ADR-005 (Plugin testing strategy — behavioural bats per P081)
|
|
32
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — AFK loop continuity)
|
|
33
|
-
# @jtbd JTBD-001 (Enforce Governance Without Slowing Down — single-commit grain)
|
|
34
|
-
|
|
35
|
-
setup() {
|
|
36
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
37
|
-
SCRIPT="$SCRIPTS_DIR/classify-readme-drift.sh"
|
|
38
|
-
FIXTURE_DIR="$(mktemp -d)"
|
|
39
|
-
cd "$FIXTURE_DIR"
|
|
40
|
-
git init -q
|
|
41
|
-
git config user.email test@example.com
|
|
42
|
-
git config user.name "Test"
|
|
43
|
-
mkdir -p docs/problems
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
teardown() {
|
|
47
|
-
cd /
|
|
48
|
-
rm -rf "$FIXTURE_DIR"
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
@test "classify-readme-drift: script exists" {
|
|
54
|
-
[ -f "$SCRIPT" ]
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@test "classify-readme-drift: script is executable" {
|
|
58
|
-
[ -x "$SCRIPT" ]
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
# ── Exit 0 (INLINE_REFRESH): every drift ID covered by staged rename ────────
|
|
62
|
-
|
|
63
|
-
@test "classify-readme-drift: single drift ID covered by staged rename → INLINE_REFRESH" {
|
|
64
|
-
# Simulate the P148 scenario: prior session staged a rename for a ticket
|
|
65
|
-
# transition; reconcile-readme observes the README is stale (still claims
|
|
66
|
-
# the old status) and emits a DRIFT line. The in-flow P094/P062 refresh
|
|
67
|
-
# at Step 5/Step 7 will reconcile the README in the same commit per
|
|
68
|
-
# ADR-014.
|
|
69
|
-
echo "stub" > docs/problems/148-foo.open.md
|
|
70
|
-
git add docs/problems/148-foo.open.md
|
|
71
|
-
git commit -q -m "init"
|
|
72
|
-
git mv docs/problems/148-foo.open.md docs/problems/148-foo.verifying.md
|
|
73
|
-
|
|
74
|
-
cat > drift.txt <<'EOF'
|
|
75
|
-
DRIFT P148 wsjf-rankings: claims=open actual=verifying
|
|
76
|
-
MISSING P148 verification-queue: actual=verifying
|
|
77
|
-
EOF
|
|
78
|
-
|
|
79
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
80
|
-
[ "$status" -eq 0 ]
|
|
81
|
-
echo "$output" | grep -q "INLINE_REFRESH"
|
|
82
|
-
echo "$output" | grep -q "covered=1"
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
@test "classify-readme-drift: multiple drift IDs all covered by staged renames → INLINE_REFRESH" {
|
|
86
|
-
echo "stub" > docs/problems/100-aaa.open.md
|
|
87
|
-
echo "stub" > docs/problems/101-bbb.open.md
|
|
88
|
-
git add docs/problems/
|
|
89
|
-
git commit -q -m "init"
|
|
90
|
-
|
|
91
|
-
git mv docs/problems/100-aaa.open.md docs/problems/100-aaa.known-error.md
|
|
92
|
-
git mv docs/problems/101-bbb.open.md docs/problems/101-bbb.verifying.md
|
|
93
|
-
|
|
94
|
-
cat > drift.txt <<'EOF'
|
|
95
|
-
DRIFT P100 wsjf-rankings: claims=open actual=known-error
|
|
96
|
-
DRIFT P101 wsjf-rankings: claims=open actual=verifying
|
|
97
|
-
MISSING P101 verification-queue: actual=verifying
|
|
98
|
-
EOF
|
|
99
|
-
|
|
100
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
101
|
-
[ "$status" -eq 0 ]
|
|
102
|
-
echo "$output" | grep -q "INLINE_REFRESH"
|
|
103
|
-
echo "$output" | grep -q "covered=2"
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
@test "classify-readme-drift: rename-with-modification (RM) is recognised as covered" {
|
|
107
|
-
# `git mv` followed by an `Edit` to the renamed file's body shows up as
|
|
108
|
-
# `RM` in `git status --porcelain` (rename + unstaged modification). The
|
|
109
|
-
# carve-out must treat both `R ` and `RM` as covered.
|
|
110
|
-
cat > docs/problems/200-xyz.open.md <<'EOF'
|
|
111
|
-
# Problem 200: XYZ
|
|
112
|
-
**Status**: Open
|
|
113
|
-
EOF
|
|
114
|
-
git add docs/problems/200-xyz.open.md
|
|
115
|
-
git commit -q -m "init"
|
|
116
|
-
|
|
117
|
-
git mv docs/problems/200-xyz.open.md docs/problems/200-xyz.verifying.md
|
|
118
|
-
# Modify the renamed file's content (without re-staging) — emits RM.
|
|
119
|
-
cat >> docs/problems/200-xyz.verifying.md <<'EOF'
|
|
120
|
-
|
|
121
|
-
## Fix Released
|
|
122
|
-
Deployed in v0.99.0.
|
|
123
|
-
EOF
|
|
124
|
-
|
|
125
|
-
cat > drift.txt <<'EOF'
|
|
126
|
-
DRIFT P200 wsjf-rankings: claims=open actual=verifying
|
|
127
|
-
EOF
|
|
128
|
-
|
|
129
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
130
|
-
[ "$status" -eq 0 ]
|
|
131
|
-
echo "$output" | grep -q "INLINE_REFRESH"
|
|
132
|
-
echo "$output" | grep -q "covered=1"
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
# ── P306: same-ID D+A pair coverage (substantial-body in-flight rename) ─────
|
|
136
|
-
# When `git mv` is followed by a substantial body edit, git's rename-detection
|
|
137
|
-
# may not match the old/new paths and emits a delete+add pair instead of an R
|
|
138
|
-
# entry. The classifier must recognise a same-ID D+A pair as same-session
|
|
139
|
-
# coverage — equivalent to an R/RM entry — and return INLINE_REFRESH.
|
|
140
|
-
|
|
141
|
-
@test "classify-readme-drift: same-ID D+A pair (substantial-body rename) → INLINE_REFRESH" {
|
|
142
|
-
# Seed an open ticket, commit, then `git mv` + substantial-body edit. With
|
|
143
|
-
# rename-detection thresholds, git may emit `D ` + `A ` (or `??`) rather
|
|
144
|
-
# than `R `. We force the D+A shape by writing wholly different content to
|
|
145
|
-
# the destination path.
|
|
146
|
-
cat > docs/problems/306-foo.open.md <<'EOF'
|
|
147
|
-
# Problem 306: Foo
|
|
148
|
-
|
|
149
|
-
**Status**: Open
|
|
150
|
-
|
|
151
|
-
Original body — short.
|
|
152
|
-
EOF
|
|
153
|
-
git add docs/problems/306-foo.open.md
|
|
154
|
-
git commit -q -m "init"
|
|
155
|
-
|
|
156
|
-
# Create the new file at the verifying path with substantially different
|
|
157
|
-
# body BEFORE removing the old path (avoid empty-dir prune). git's
|
|
158
|
-
# rename-detection then sees delete + add as distinct entries rather than
|
|
159
|
-
# an R-rename, because the bodies are wholly different.
|
|
160
|
-
cat > docs/problems/306-foo.verifying.md <<'EOF'
|
|
161
|
-
# Problem 306: Foo
|
|
162
|
-
|
|
163
|
-
**Status**: Verification Pending
|
|
164
|
-
|
|
165
|
-
Wholly rewritten body so git rename-detection does not match the source.
|
|
166
|
-
This is a multi-paragraph substantive rewrite that exercises the D+A path.
|
|
167
|
-
|
|
168
|
-
## Fix Released
|
|
169
|
-
|
|
170
|
-
Deployed in vX.Y.Z. Adds a behavioural fixture that exercises the
|
|
171
|
-
classifier across the D+A coverage gap that P306 captured.
|
|
172
|
-
EOF
|
|
173
|
-
git rm -q docs/problems/306-foo.open.md
|
|
174
|
-
git add docs/problems/306-foo.verifying.md
|
|
175
|
-
|
|
176
|
-
cat > drift.txt <<'EOF'
|
|
177
|
-
DRIFT P306 wsjf-rankings: claims=open actual=verifying
|
|
178
|
-
MISSING P306 verification-queue: actual=verifying
|
|
179
|
-
EOF
|
|
180
|
-
|
|
181
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
182
|
-
[ "$status" -eq 0 ]
|
|
183
|
-
echo "$output" | grep -q "INLINE_REFRESH"
|
|
184
|
-
echo "$output" | grep -q "covered=1"
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
@test "classify-readme-drift: same-ID D+A pair with untracked add (D + ??) → INLINE_REFRESH" {
|
|
188
|
-
# Variant: the new path is untracked (not yet `git add`-ed). git status
|
|
189
|
-
# emits `D ` for the old path and `??` for the new path. The classifier
|
|
190
|
-
# must still recognise the same-ID pair as same-session coverage.
|
|
191
|
-
cat > docs/problems/307-bar.open.md <<'EOF'
|
|
192
|
-
# Problem 307: Bar
|
|
193
|
-
**Status**: Open
|
|
194
|
-
EOF
|
|
195
|
-
git add docs/problems/307-bar.open.md
|
|
196
|
-
git commit -q -m "init"
|
|
197
|
-
|
|
198
|
-
cat > docs/problems/307-bar.verifying.md <<'EOF'
|
|
199
|
-
# Problem 307: Bar
|
|
200
|
-
|
|
201
|
-
**Status**: Verification Pending
|
|
202
|
-
|
|
203
|
-
Untracked add side of the D+?? pair.
|
|
204
|
-
EOF
|
|
205
|
-
git rm -q docs/problems/307-bar.open.md
|
|
206
|
-
|
|
207
|
-
cat > drift.txt <<'EOF'
|
|
208
|
-
DRIFT P307 wsjf-rankings: claims=open actual=verifying
|
|
209
|
-
EOF
|
|
210
|
-
|
|
211
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
212
|
-
[ "$status" -eq 0 ]
|
|
213
|
-
echo "$output" | grep -q "INLINE_REFRESH"
|
|
214
|
-
echo "$output" | grep -q "covered=1"
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
@test "classify-readme-drift: D-only (no matching A for same ID) → HALT_ROUTE_RECONCILE" {
|
|
218
|
-
# Negative case: a delete without a corresponding add for the same ID is
|
|
219
|
-
# NOT a rename — it is a genuine deletion. Must HALT.
|
|
220
|
-
cat > docs/problems/308-baz.open.md <<'EOF'
|
|
221
|
-
# Problem 308: Baz
|
|
222
|
-
**Status**: Open
|
|
223
|
-
EOF
|
|
224
|
-
git add docs/problems/308-baz.open.md
|
|
225
|
-
git commit -q -m "init"
|
|
226
|
-
|
|
227
|
-
git rm -q docs/problems/308-baz.open.md
|
|
228
|
-
|
|
229
|
-
cat > drift.txt <<'EOF'
|
|
230
|
-
DRIFT P308 wsjf-rankings: claims=open actual=verifying
|
|
231
|
-
EOF
|
|
232
|
-
|
|
233
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
234
|
-
[ "$status" -eq 1 ]
|
|
235
|
-
echo "$output" | grep -q "HALT_ROUTE_RECONCILE"
|
|
236
|
-
echo "$output" | grep -q "uncovered=1"
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
@test "classify-readme-drift: mismatched D + A (different IDs) → HALT_ROUTE_RECONCILE" {
|
|
240
|
-
# Negative case: a delete for one ID + an add for a different ID is NOT a
|
|
241
|
-
# rename of either ticket — both are uncovered.
|
|
242
|
-
cat > docs/problems/309-alpha.open.md <<'EOF'
|
|
243
|
-
# Problem 309: Alpha
|
|
244
|
-
**Status**: Open
|
|
245
|
-
EOF
|
|
246
|
-
git add docs/problems/309-alpha.open.md
|
|
247
|
-
git commit -q -m "init"
|
|
248
|
-
|
|
249
|
-
cat > docs/problems/310-beta.open.md <<'EOF'
|
|
250
|
-
# Problem 310: Beta
|
|
251
|
-
**Status**: Open
|
|
252
|
-
EOF
|
|
253
|
-
git rm -q docs/problems/309-alpha.open.md
|
|
254
|
-
git add docs/problems/310-beta.open.md
|
|
255
|
-
|
|
256
|
-
cat > drift.txt <<'EOF'
|
|
257
|
-
DRIFT P309 wsjf-rankings: claims=open actual=verifying
|
|
258
|
-
EOF
|
|
259
|
-
|
|
260
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
261
|
-
[ "$status" -eq 1 ]
|
|
262
|
-
echo "$output" | grep -q "HALT_ROUTE_RECONCILE"
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
# ── Exit 1 (HALT_ROUTE_RECONCILE): committed cross-session drift ────────────
|
|
266
|
-
|
|
267
|
-
@test "classify-readme-drift: single drift ID not covered by any rename → HALT_ROUTE_RECONCILE" {
|
|
268
|
-
# Simulate the P118 originating scenario: a prior session committed a
|
|
269
|
-
# ticket transition without staging the README refresh. The README is
|
|
270
|
-
# stale; the working tree is clean (no pending rename). Halt and route
|
|
271
|
-
# to /wr-itil:reconcile-readme.
|
|
272
|
-
cat > docs/problems/074-foo.closed.md <<'EOF'
|
|
273
|
-
# Problem 074: Foo
|
|
274
|
-
**Status**: Closed
|
|
275
|
-
EOF
|
|
276
|
-
git add docs/problems/074-foo.closed.md
|
|
277
|
-
git commit -q -m "init"
|
|
278
|
-
|
|
279
|
-
cat > drift.txt <<'EOF'
|
|
280
|
-
DRIFT P074 wsjf-rankings: claims=open actual=closed
|
|
281
|
-
EOF
|
|
282
|
-
|
|
283
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
284
|
-
[ "$status" -eq 1 ]
|
|
285
|
-
echo "$output" | grep -q "HALT_ROUTE_RECONCILE"
|
|
286
|
-
echo "$output" | grep -q "uncovered=1"
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
@test "classify-readme-drift: mixed (some covered, some uncovered) → HALT_ROUTE_RECONCILE" {
|
|
290
|
-
# Mixed case: one ID has a staged rename, another is committed drift.
|
|
291
|
-
# The architect's confirmation: mixed routes to halt (the safe path),
|
|
292
|
-
# because reconcile-readme will resolve both, and the in-flow refresh
|
|
293
|
-
# only handles the rename'd one.
|
|
294
|
-
cat > docs/problems/074-foo.closed.md <<'EOF'
|
|
295
|
-
# Problem 074: Foo
|
|
296
|
-
**Status**: Closed
|
|
297
|
-
EOF
|
|
298
|
-
cat > docs/problems/148-bar.open.md <<'EOF'
|
|
299
|
-
# Problem 148: Bar
|
|
300
|
-
**Status**: Open
|
|
301
|
-
EOF
|
|
302
|
-
git add docs/problems/
|
|
303
|
-
git commit -q -m "init"
|
|
304
|
-
|
|
305
|
-
git mv docs/problems/148-bar.open.md docs/problems/148-bar.verifying.md
|
|
306
|
-
|
|
307
|
-
cat > drift.txt <<'EOF'
|
|
308
|
-
DRIFT P074 wsjf-rankings: claims=open actual=closed
|
|
309
|
-
DRIFT P148 wsjf-rankings: claims=open actual=verifying
|
|
310
|
-
EOF
|
|
311
|
-
|
|
312
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
313
|
-
[ "$status" -eq 1 ]
|
|
314
|
-
echo "$output" | grep -q "HALT_ROUTE_RECONCILE"
|
|
315
|
-
# Only P074 is uncovered.
|
|
316
|
-
echo "$output" | grep -q "uncovered=1"
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
@test "classify-readme-drift: clean working tree (no renames) → HALT_ROUTE_RECONCILE for any drift" {
|
|
320
|
-
cat > docs/problems/050-zzz.verifying.md <<'EOF'
|
|
321
|
-
# Problem 050: Zzz
|
|
322
|
-
**Status**: Verification Pending
|
|
323
|
-
EOF
|
|
324
|
-
git add docs/problems/050-zzz.verifying.md
|
|
325
|
-
git commit -q -m "init"
|
|
326
|
-
|
|
327
|
-
cat > drift.txt <<'EOF'
|
|
328
|
-
MISSING P050 verification-queue: actual=verifying
|
|
329
|
-
EOF
|
|
330
|
-
|
|
331
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
332
|
-
[ "$status" -eq 1 ]
|
|
333
|
-
echo "$output" | grep -q "HALT_ROUTE_RECONCILE"
|
|
334
|
-
echo "$output" | grep -q "uncovered=1"
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
# ── Exit 2: parse errors ────────────────────────────────────────────────────
|
|
338
|
-
|
|
339
|
-
@test "classify-readme-drift: missing drift-stdout-file → exit 2" {
|
|
340
|
-
run "$SCRIPT" /nonexistent/drift.txt docs/problems
|
|
341
|
-
[ "$status" -eq 2 ]
|
|
342
|
-
echo "$output" | grep -qi "PARSE_ERROR"
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
@test "classify-readme-drift: empty drift-stdout-file → exit 2" {
|
|
346
|
-
: > drift.txt
|
|
347
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
348
|
-
[ "$status" -eq 2 ]
|
|
349
|
-
echo "$output" | grep -qi "PARSE_ERROR"
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
@test "classify-readme-drift: no arguments → exit 2 with usage" {
|
|
353
|
-
run "$SCRIPT"
|
|
354
|
-
[ "$status" -eq 2 ]
|
|
355
|
-
echo "$output" | grep -qi "USAGE"
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
# ── Default problems-dir resolution ─────────────────────────────────────────
|
|
359
|
-
|
|
360
|
-
@test "classify-readme-drift: defaults to ./docs/problems when problems-dir omitted" {
|
|
361
|
-
echo "stub" > docs/problems/300-default.open.md
|
|
362
|
-
git add docs/problems/300-default.open.md
|
|
363
|
-
git commit -q -m "init"
|
|
364
|
-
git mv docs/problems/300-default.open.md docs/problems/300-default.verifying.md
|
|
365
|
-
|
|
366
|
-
cat > drift.txt <<'EOF'
|
|
367
|
-
DRIFT P300 wsjf-rankings: claims=open actual=verifying
|
|
368
|
-
EOF
|
|
369
|
-
|
|
370
|
-
run "$SCRIPT" drift.txt
|
|
371
|
-
[ "$status" -eq 0 ]
|
|
372
|
-
echo "$output" | grep -q "INLINE_REFRESH"
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
# ── Non-git working tree (defensive — outside a repo) ───────────────────────
|
|
376
|
-
|
|
377
|
-
@test "classify-readme-drift: outside git repo with drift → HALT_ROUTE_RECONCILE (no rename evidence)" {
|
|
378
|
-
# If the script is invoked from outside a git repo (defensive — should not
|
|
379
|
-
# happen in the SKILL.md flow but safest fail-closed), there is no rename
|
|
380
|
-
# evidence, so all drift is treated as uncovered.
|
|
381
|
-
NON_GIT="$(mktemp -d)"
|
|
382
|
-
cd "$NON_GIT"
|
|
383
|
-
mkdir -p docs/problems
|
|
384
|
-
cat > drift.txt <<'EOF'
|
|
385
|
-
DRIFT P074 wsjf-rankings: claims=open actual=closed
|
|
386
|
-
EOF
|
|
387
|
-
run "$SCRIPT" drift.txt docs/problems
|
|
388
|
-
[ "$status" -eq 1 ]
|
|
389
|
-
echo "$output" | grep -q "HALT_ROUTE_RECONCILE"
|
|
390
|
-
cd /
|
|
391
|
-
rm -rf "$NON_GIT"
|
|
392
|
-
}
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
bats_require_minimum_version 1.5.0
|
|
4
|
-
|
|
5
|
-
# Behavioural assertions for packages/itil/lib/derive-first-dispatch.sh —
|
|
6
|
-
# the shared derive-first dispatch helper extracted in P132 Phase 2a-iii-A.
|
|
7
|
-
#
|
|
8
|
-
# The helper centralises the dispatch mechanism shipped across three
|
|
9
|
-
# declaration-skill surfaces (manage-incident Step 4, manage-problem
|
|
10
|
-
# Step 4, create-adr Step 2 — Phase 2a-iii-B 4th adopter). Each caller
|
|
11
|
-
# passes surface-specific signal definitions; the helper owns:
|
|
12
|
-
#
|
|
13
|
-
# - Slug derivation (Title) from prose
|
|
14
|
-
# - RISK-POLICY matrix lookup (Severity / Priority)
|
|
15
|
-
# - I2-isomorphic stderr advisory format
|
|
16
|
-
#
|
|
17
|
-
# P287 (2026-06-02) retired the two-sided lexical classifier (formerly
|
|
18
|
-
# used by capture-problem Step 1.5 Type classification — technical vs
|
|
19
|
-
# user-business). The type axis was removed as redundant with RFC/Story
|
|
20
|
-
# persona-anchoring per ADR-060 Phase 4; the function had no remaining
|
|
21
|
-
# consumer.
|
|
22
|
-
#
|
|
23
|
-
# @problem P132 (agents over-ask in interactive sessions — Phase 2a-iii-A
|
|
24
|
-
# shared helper extraction)
|
|
25
|
-
# @problem P185 (capture-problem Step 1.5 worked-example precedent — retired by P287)
|
|
26
|
-
# @problem P287 (type-classification retirement — lexical_classify_two_sided removed)
|
|
27
|
-
# @adr ADR-044 (Decision-Delegation Contract — derive-first framework
|
|
28
|
-
# resolution boundary)
|
|
29
|
-
# @adr ADR-026 (cost-source grounding — stderr advisory shape)
|
|
30
|
-
# @adr ADR-052 (behavioural-by-default — these are runtime behaviour
|
|
31
|
-
# assertions on the helper functions, NOT structural greps)
|
|
32
|
-
# @jtbd JTBD-001 (enforce governance without slowing down — primary)
|
|
33
|
-
# @jtbd JTBD-101 (extend the suite with consistent patterns)
|
|
34
|
-
|
|
35
|
-
setup() {
|
|
36
|
-
LIB_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../lib" && pwd)"
|
|
37
|
-
HELPER="${LIB_DIR}/derive-first-dispatch.sh"
|
|
38
|
-
[ -f "$HELPER" ]
|
|
39
|
-
# shellcheck disable=SC1090
|
|
40
|
-
source "$HELPER"
|
|
41
|
-
PKG_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)"
|
|
42
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
43
|
-
ARCHITECT_PKG_ROOT="$REPO_ROOT/packages/architect"
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
# ----------------------------------------------------------------------
|
|
47
|
-
# Stderr advisory contract (I2-isomorphic format across all 3 surfaces).
|
|
48
|
-
# Format: <skill>: derived <field>=<value> from <source>; <reversibility>
|
|
49
|
-
# ----------------------------------------------------------------------
|
|
50
|
-
|
|
51
|
-
@test "emit_stderr_advisory writes single canonical line to stderr" {
|
|
52
|
-
run -0 bash -c '
|
|
53
|
-
source "'"$HELPER"'"
|
|
54
|
-
emit_stderr_advisory manage-problem title my-slug "description tokens" \
|
|
55
|
-
"re-invoke with the desired title or rename the file if the slug is wrong"
|
|
56
|
-
'
|
|
57
|
-
# stderr captured in $output via run; assert structure
|
|
58
|
-
[[ "$output" == *"manage-problem: derived title=my-slug from description tokens; re-invoke with the desired title"* ]]
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
@test "emit_stderr_advisory uses default reversibility clause when omitted" {
|
|
62
|
-
run -0 bash -c '
|
|
63
|
-
source "'"$HELPER"'"
|
|
64
|
-
emit_stderr_advisory manage-incident severity "9 (Medium)" "RISK-POLICY matrix"
|
|
65
|
-
'
|
|
66
|
-
[[ "$output" == *"manage-incident: derived severity=9 (Medium) from RISK-POLICY matrix;"* ]]
|
|
67
|
-
[[ "$output" == *"re-invoke"* ]] || [[ "$output" == *"update"* ]]
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@test "emit_stderr_advisory shape is I2-isomorphic across surfaces (same sentence structure)" {
|
|
71
|
-
run -0 bash -c '
|
|
72
|
-
source "'"$HELPER"'"
|
|
73
|
-
emit_stderr_advisory capture-problem type technical "description signals" "re-invoke with --type=user-business to override"
|
|
74
|
-
emit_stderr_advisory manage-incident title incident-slug "description" "re-invoke or rename"
|
|
75
|
-
emit_stderr_advisory manage-problem priority "9 (Medium)" "RISK-POLICY matrix" "re-invoke or update if mis-rated"
|
|
76
|
-
'
|
|
77
|
-
# Each surface emits the same sentence shape: <skill>: derived <field>=<value> from <source>; <clause>
|
|
78
|
-
line_count=$(printf '%s\n' "$output" | grep -c "^[a-z-]*: derived ")
|
|
79
|
-
[ "$line_count" -eq 3 ]
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
# ----------------------------------------------------------------------
|
|
83
|
-
# Kebab-case slug derivation from prose.
|
|
84
|
-
# ----------------------------------------------------------------------
|
|
85
|
-
|
|
86
|
-
@test "derive_kebab_slug produces kebab-case from prose" {
|
|
87
|
-
run -0 bash -c '
|
|
88
|
-
source "'"$HELPER"'"
|
|
89
|
-
derive_kebab_slug "Agent over-asks during interactive sessions"
|
|
90
|
-
'
|
|
91
|
-
[[ "$output" == *"agent"* ]]
|
|
92
|
-
[[ "$output" == *"over"* ]] || [[ "$output" == *"asks"* ]]
|
|
93
|
-
[[ "$output" != *" "* ]]
|
|
94
|
-
[[ "$output" != *"_"* ]]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
@test "derive_kebab_slug drops stopwords" {
|
|
98
|
-
run -0 bash -c '
|
|
99
|
-
source "'"$HELPER"'"
|
|
100
|
-
derive_kebab_slug "The agent is asking the user a question"
|
|
101
|
-
'
|
|
102
|
-
# stopwords like "the", "a", "is" must NOT appear as standalone tokens
|
|
103
|
-
[[ "$output" != *"-the-"* ]]
|
|
104
|
-
[[ "$output" != "the-"* ]]
|
|
105
|
-
[[ "$output" == *"agent"* ]]
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@test "derive_kebab_slug caps token count (default 8)" {
|
|
109
|
-
run -0 bash -c '
|
|
110
|
-
source "'"$HELPER"'"
|
|
111
|
-
derive_kebab_slug "one two three four five six seven eight nine ten eleven twelve"
|
|
112
|
-
'
|
|
113
|
-
token_count=$(printf '%s\n' "$output" | tr '-' '\n' | wc -l | tr -d ' ')
|
|
114
|
-
[ "$token_count" -le 8 ]
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
@test "derive_kebab_slug accepts custom token count" {
|
|
118
|
-
run -0 bash -c '
|
|
119
|
-
source "'"$HELPER"'"
|
|
120
|
-
derive_kebab_slug "alpha beta gamma delta epsilon zeta" 3
|
|
121
|
-
'
|
|
122
|
-
token_count=$(printf '%s\n' "$output" | tr '-' '\n' | wc -l | tr -d ' ')
|
|
123
|
-
[ "$token_count" -le 3 ]
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
# ----------------------------------------------------------------------
|
|
127
|
-
# P287 (2026-06-02) retirement: lexical_classify_two_sided removed.
|
|
128
|
-
# Regression guard — the function must NOT exist in the helper.
|
|
129
|
-
# ----------------------------------------------------------------------
|
|
130
|
-
|
|
131
|
-
@test "P287: lexical_classify_two_sided is removed from the helper (regression guard)" {
|
|
132
|
-
# The function name must not appear as a function definition.
|
|
133
|
-
! grep -E '^lexical_classify_two_sided\(\)' "$HELPER"
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
@test "P287: helper still exports the three surviving functions" {
|
|
137
|
-
# emit_stderr_advisory, derive_kebab_slug, risk_policy_matrix_lookup
|
|
138
|
-
# serve manage-incident severity, manage-problem priority, and
|
|
139
|
-
# create-adr title derivation — they must stay.
|
|
140
|
-
grep -E '^emit_stderr_advisory\(\)' "$HELPER"
|
|
141
|
-
grep -E '^derive_kebab_slug\(\)' "$HELPER"
|
|
142
|
-
grep -E '^risk_policy_matrix_lookup\(\)' "$HELPER"
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
# ----------------------------------------------------------------------
|
|
146
|
-
# RISK-POLICY matrix lookup (manage-incident / manage-problem mechanism).
|
|
147
|
-
# Returns:
|
|
148
|
-
# <score>|<label>|impact=<L>+likelihood=<L> — clear single-cell match
|
|
149
|
-
# AMBIGUOUS|<reason> — multi-band or zero match
|
|
150
|
-
# ----------------------------------------------------------------------
|
|
151
|
-
|
|
152
|
-
@test "risk_policy_matrix_lookup returns clear cell on unambiguous impact + likelihood signals" {
|
|
153
|
-
run -0 bash -c '
|
|
154
|
-
source "'"$HELPER"'"
|
|
155
|
-
impact_high=("\\b(down|outage|data loss|unavailable)\\b")
|
|
156
|
-
impact_mod=("\\b(slow|latency|degraded)\\b")
|
|
157
|
-
impact_low=("\\b(typo|cosmetic)\\b")
|
|
158
|
-
likelihood_high=("\\b(every request|reproducible|always)\\b")
|
|
159
|
-
likelihood_med=("\\b(intermittent|flaky)\\b")
|
|
160
|
-
likelihood_low=("\\b(one-off|single)\\b")
|
|
161
|
-
risk_policy_matrix_lookup "service is down on every request" impact_high impact_mod impact_low likelihood_high likelihood_med likelihood_low
|
|
162
|
-
'
|
|
163
|
-
# Expect impact=high(5) + likelihood=high(5) -> score=25, label=Very High
|
|
164
|
-
[[ "$output" == "25|"* ]] || [[ "$output" == "20|"* ]] || [[ "$output" == "15|"* ]]
|
|
165
|
-
[[ "$output" == *"High"* ]] || [[ "$output" == *"Very High"* ]]
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
@test "risk_policy_matrix_lookup returns AMBIGUOUS on multi-band impact" {
|
|
169
|
-
run -0 bash -c '
|
|
170
|
-
source "'"$HELPER"'"
|
|
171
|
-
impact_high=("\\b(down)\\b")
|
|
172
|
-
impact_mod=("\\b(slow)\\b")
|
|
173
|
-
impact_low=("\\b(typo)\\b")
|
|
174
|
-
likelihood_high=("\\b(every request)\\b")
|
|
175
|
-
likelihood_med=("\\b(intermittent)\\b")
|
|
176
|
-
likelihood_low=("\\b(one-off)\\b")
|
|
177
|
-
risk_policy_matrix_lookup "service is down and slow with typo" impact_high impact_mod impact_low likelihood_high likelihood_med likelihood_low
|
|
178
|
-
'
|
|
179
|
-
[[ "$output" == "AMBIGUOUS|"* ]]
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
@test "risk_policy_matrix_lookup returns AMBIGUOUS when no signals match" {
|
|
183
|
-
run -0 bash -c '
|
|
184
|
-
source "'"$HELPER"'"
|
|
185
|
-
impact_high=("\\b(down)\\b")
|
|
186
|
-
impact_mod=("\\b(slow)\\b")
|
|
187
|
-
impact_low=("\\b(typo)\\b")
|
|
188
|
-
likelihood_high=("\\b(every request)\\b")
|
|
189
|
-
likelihood_med=("\\b(intermittent)\\b")
|
|
190
|
-
likelihood_low=("\\b(one-off)\\b")
|
|
191
|
-
risk_policy_matrix_lookup "totally bland text" impact_high impact_mod impact_low likelihood_high likelihood_med likelihood_low
|
|
192
|
-
'
|
|
193
|
-
[[ "$output" == "AMBIGUOUS|"* ]]
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
@test "risk_policy_matrix_lookup label band aligns with RISK-POLICY.md (Medium = 5-9)" {
|
|
197
|
-
# Verify a specific clear-cell mapping produces the RISK-POLICY-canonical label.
|
|
198
|
-
# impact=mod (3) * likelihood=high (5) = 15 -> "High" band (10-16)
|
|
199
|
-
run -0 bash -c '
|
|
200
|
-
source "'"$HELPER"'"
|
|
201
|
-
impact_high=("\\b(down)\\b")
|
|
202
|
-
impact_mod=("\\b(slow)\\b")
|
|
203
|
-
impact_low=("\\b(typo)\\b")
|
|
204
|
-
likelihood_high=("\\b(every request)\\b")
|
|
205
|
-
likelihood_med=("\\b(intermittent)\\b")
|
|
206
|
-
likelihood_low=("\\b(one-off)\\b")
|
|
207
|
-
risk_policy_matrix_lookup "the service is slow on every request" impact_high impact_mod impact_low likelihood_high likelihood_med likelihood_low
|
|
208
|
-
'
|
|
209
|
-
[[ "$output" == "15|High|"* ]]
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
# ----------------------------------------------------------------------
|
|
213
|
-
# Cross-skill consistency: all 4 SKILL.md surfaces reference the helper
|
|
214
|
-
# as the shared dispatch mechanism. The I2-isomorphic stderr advisory
|
|
215
|
-
# format is locked-in by reference to derive-first-dispatch.sh.
|
|
216
|
-
#
|
|
217
|
-
# Phase 2a-iii-B (2026-05-16): 4th adopter wr-architect:create-adr added.
|
|
218
|
-
# Helper canonical source moved to packages/shared/ per ADR-017 sync
|
|
219
|
-
# pattern; per-package lib/ copies in packages/itil/lib/ and
|
|
220
|
-
# packages/architect/lib/ stay byte-identical via scripts/sync-derive-first-dispatch.sh.
|
|
221
|
-
# ----------------------------------------------------------------------
|
|
222
|
-
|
|
223
|
-
@test "manage-incident Step 4 cross-references derive-first-dispatch.sh helper" {
|
|
224
|
-
run grep -c "derive-first-dispatch\\.sh\\|packages/itil/lib/derive-first-dispatch" \
|
|
225
|
-
"${PKG_ROOT}/skills/manage-incident/SKILL.md"
|
|
226
|
-
[ "$status" -eq 0 ]
|
|
227
|
-
[ "$output" -ge 1 ]
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
@test "manage-problem Step 4 cross-references derive-first-dispatch.sh helper" {
|
|
231
|
-
run grep -c "derive-first-dispatch\\.sh\\|packages/itil/lib/derive-first-dispatch" \
|
|
232
|
-
"${PKG_ROOT}/skills/manage-problem/SKILL.md"
|
|
233
|
-
[ "$status" -eq 0 ]
|
|
234
|
-
[ "$output" -ge 1 ]
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
@test "create-adr Step 2 cross-references derive-first-dispatch.sh helper (Phase 2a-iii-B 4th adopter)" {
|
|
238
|
-
# The 4th adopter (architect package) sources from its own per-package
|
|
239
|
-
# lib/ copy (NOT cross-package from itil) per ADR-017.
|
|
240
|
-
run grep -c "derive-first-dispatch\\.sh\\|packages/architect/lib/derive-first-dispatch" \
|
|
241
|
-
"${ARCHITECT_PKG_ROOT}/skills/create-adr/SKILL.md"
|
|
242
|
-
[ "$status" -eq 0 ]
|
|
243
|
-
[ "$output" -ge 1 ]
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
@test "helper file documents its four caller surfaces (audit trail)" {
|
|
247
|
-
# The helper's header comment must name the four SKILL.md surfaces it
|
|
248
|
-
# serves so the audit trail is recoverable from the helper itself.
|
|
249
|
-
# Phase 2a-iii-B adds create-adr as the 4th adopter.
|
|
250
|
-
run grep -E "capture-problem" "$HELPER"
|
|
251
|
-
[ "$status" -eq 0 ]
|
|
252
|
-
run grep -E "manage-incident" "$HELPER"
|
|
253
|
-
[ "$status" -eq 0 ]
|
|
254
|
-
run grep -E "manage-problem" "$HELPER"
|
|
255
|
-
[ "$status" -eq 0 ]
|
|
256
|
-
run grep -E "create-adr" "$HELPER"
|
|
257
|
-
[ "$status" -eq 0 ]
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
@test "per-package lib/ copies are byte-identical to canonical packages/shared/ source (ADR-017)" {
|
|
261
|
-
# Phase 2a-iii-B + ADR-017: canonical at packages/shared/, synced copies
|
|
262
|
-
# in per-package lib/. The sync script (scripts/sync-derive-first-dispatch.sh)
|
|
263
|
-
# in --check mode is the CI guard; this test asserts the post-condition.
|
|
264
|
-
local shared_src="${REPO_ROOT}/packages/shared/derive-first-dispatch.sh"
|
|
265
|
-
local itil_copy="${REPO_ROOT}/packages/itil/lib/derive-first-dispatch.sh"
|
|
266
|
-
local architect_copy="${REPO_ROOT}/packages/architect/lib/derive-first-dispatch.sh"
|
|
267
|
-
[ -f "$shared_src" ]
|
|
268
|
-
[ -f "$itil_copy" ]
|
|
269
|
-
[ -f "$architect_copy" ]
|
|
270
|
-
run diff -q "$shared_src" "$itil_copy"
|
|
271
|
-
[ "$status" -eq 0 ]
|
|
272
|
-
run diff -q "$shared_src" "$architect_copy"
|
|
273
|
-
[ "$status" -eq 0 ]
|
|
274
|
-
}
|