@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,310 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Behavioural tests for check-afk-accept-eligible.sh (ADR-101 / P456 / P465).
|
|
3
|
-
# Each case maps onto an ADR-101 Confirmation item. Behavioural, not structural:
|
|
4
|
-
# every test runs the real script against a real fixture tree and asserts on its
|
|
5
|
-
# exit status and stderr, never on its source text (ADR-052 / P081).
|
|
6
|
-
#
|
|
7
|
-
# The POSITIVE case is the load-bearing one. An earlier revision shipped an
|
|
8
|
-
# `awk -v` escape bug that made the checker permanently inert — it fails closed,
|
|
9
|
-
# so no negative test could ever have caught it. Only asserting that a
|
|
10
|
-
# well-formed story IS eligible surfaces that class of bug.
|
|
11
|
-
#
|
|
12
|
-
# @adr ADR-101 ADR-090 ADR-095 ADR-096 ADR-098 ADR-052 @problem P456 P465
|
|
13
|
-
|
|
14
|
-
setup() {
|
|
15
|
-
SCRIPTS="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
16
|
-
CHECK="$SCRIPTS/check-afk-accept-eligible.sh"
|
|
17
|
-
MARK="$SCRIPTS/mark-story-oversight-confirmed.sh"
|
|
18
|
-
TMP="$(mktemp -d)"; cd "$TMP"
|
|
19
|
-
mkdir -p docs/stories/draft docs/story-maps/draft docs/rfcs docs/jtbd/dev docs/problems/open docs/decisions
|
|
20
|
-
export HOME="$TMP/home"; mkdir -p "$HOME/.claude"
|
|
21
|
-
|
|
22
|
-
# --- confirmed parents -----------------------------------------------------
|
|
23
|
-
printf -- '---\nhuman-oversight: confirmed\n---\n\n# ADR-900\n' > docs/decisions/900-a-confirmed-decision.proposed.md
|
|
24
|
-
printf -- '---\nhuman-oversight: confirmed\n---\n\n# JTBD-900\n' > docs/jtbd/dev/JTBD-900-a-job.proposed.md
|
|
25
|
-
printf -- '---\nhuman-oversight: confirmed\n---\n\n# persona\n' > docs/jtbd/dev/persona.md
|
|
26
|
-
printf -- '---\nadrs: [ADR-900]\n---\n\n# RFC-900\n' > docs/rfcs/RFC-900-a-vehicle.proposed.md
|
|
27
|
-
printf -- '# P900\n' > docs/problems/open/900-a-problem.md
|
|
28
|
-
|
|
29
|
-
# A map that was ratified BEFORE the story's card was added — the common case,
|
|
30
|
-
# since ADR-095 compels the card at capture.
|
|
31
|
-
MAP=docs/story-maps/draft/STORY-MAP-900-a-map.html
|
|
32
|
-
printf '<html><head>\n<a class="slice" data-story-id="STORY-800">old</a>\n</head></html>\n' > "$MAP"
|
|
33
|
-
bash "$MARK" "$MAP" 2>/dev/null
|
|
34
|
-
# Now add STORY-901's card, drifting the map exactly as capture would.
|
|
35
|
-
python3 - "$MAP" <<'PY'
|
|
36
|
-
import sys
|
|
37
|
-
p=sys.argv[1]; s=open(p).read()
|
|
38
|
-
open(p,"w").write(s.replace('</head>',' <a class="slice" data-story-id="STORY-901">new</a>\n</head>'))
|
|
39
|
-
PY
|
|
40
|
-
|
|
41
|
-
export WR_ITIL_AFK_ACCEPT=1
|
|
42
|
-
}
|
|
43
|
-
teardown() { cd /; rm -rf "$TMP"; }
|
|
44
|
-
|
|
45
|
-
# A well-formed pure-decomposition story: 2 criteria, 2 basis entries, all
|
|
46
|
-
# citations traced and confirmed.
|
|
47
|
-
seed_story() {
|
|
48
|
-
cat > docs/stories/draft/STORY-901-a-story.md <<'EOF'
|
|
49
|
-
---
|
|
50
|
-
status: draft
|
|
51
|
-
problems: [P900]
|
|
52
|
-
jtbd: [JTBD-900]
|
|
53
|
-
rfcs: [RFC-900]
|
|
54
|
-
story-maps: [STORY-MAP-900]
|
|
55
|
-
adrs: [ADR-900]
|
|
56
|
-
afk-accept: pure-decomposition
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
# STORY-901: A story
|
|
60
|
-
|
|
61
|
-
## User value
|
|
62
|
-
|
|
63
|
-
In order to land confirmed work, as a developer, I want the loop to proceed.
|
|
64
|
-
|
|
65
|
-
## Acceptance criteria (accepted-gate, INVEST Testable)
|
|
66
|
-
|
|
67
|
-
- [ ] The first step happens.
|
|
68
|
-
- [ ] The second step happens.
|
|
69
|
-
|
|
70
|
-
## Decomposition basis
|
|
71
|
-
|
|
72
|
-
- Criterion 1 decomposes ADR-900's rule about the first step.
|
|
73
|
-
- Criterion 2 decomposes ADR-900's rule about the second step.
|
|
74
|
-
EOF
|
|
75
|
-
}
|
|
76
|
-
run_check() { run bash "$CHECK" docs/stories/draft/STORY-901-a-story.md \
|
|
77
|
-
docs/story-maps docs/rfcs docs/jtbd docs/problems docs/decisions; }
|
|
78
|
-
|
|
79
|
-
# --- ADR-101 Confirmation: eligibility ---------------------------------------
|
|
80
|
-
|
|
81
|
-
@test "ELIGIBLE: pure-decomposition story whose parents are all confirmed" {
|
|
82
|
-
seed_story; run_check
|
|
83
|
-
[ "$status" -eq 0 ]
|
|
84
|
-
echo "$output" | grep -q 'ELIGIBLE'
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
@test "NOT eligible: a traced ADR parent is unconfirmed" {
|
|
88
|
-
seed_story
|
|
89
|
-
printf -- '---\nhuman-oversight: unconfirmed\n---\n\n# ADR-900\n' > docs/decisions/900-a-confirmed-decision.proposed.md
|
|
90
|
-
run_check
|
|
91
|
-
[ "$status" -eq 1 ]
|
|
92
|
-
echo "$output" | grep -q 'ADR-900'
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
@test "NOT eligible: a traced JTBD's persona is unconfirmed" {
|
|
96
|
-
seed_story
|
|
97
|
-
printf -- '---\nhuman-oversight: unconfirmed\n---\n\n# persona\n' > docs/jtbd/dev/persona.md
|
|
98
|
-
run_check
|
|
99
|
-
[ "$status" -eq 1 ]
|
|
100
|
-
echo "$output" | grep -qi 'persona'
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
@test "NOT eligible: a traced artefact does not resolve (new substance)" {
|
|
104
|
-
seed_story
|
|
105
|
-
rm docs/decisions/900-a-confirmed-decision.proposed.md
|
|
106
|
-
run_check
|
|
107
|
-
[ "$status" -eq 1 ]
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
@test "NOT eligible: basis entries do not match the criteria count" {
|
|
111
|
-
seed_story
|
|
112
|
-
printf -- '- [ ] A third step nobody accounted for.\n' >> docs/stories/draft/STORY-901-a-story.md
|
|
113
|
-
run_check
|
|
114
|
-
[ "$status" -eq 1 ]
|
|
115
|
-
echo "$output" | grep -q 'Decomposition basis'
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
@test "NOT eligible: basis cites an artefact condition (a) never verified" {
|
|
119
|
-
seed_story
|
|
120
|
-
sed -i.bak 's/ADR-900.s rule about the first step/ADR-999 rule about the first step/' docs/stories/draft/STORY-901-a-story.md
|
|
121
|
-
run_check
|
|
122
|
-
[ "$status" -eq 1 ]
|
|
123
|
-
echo "$output" | grep -q 'ADR-999'
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
@test "NOT eligible: the story does not declare the carve-out" {
|
|
127
|
-
seed_story
|
|
128
|
-
sed -i.bak '/^afk-accept:/d' docs/stories/draft/STORY-901-a-story.md
|
|
129
|
-
run_check
|
|
130
|
-
[ "$status" -eq 1 ]
|
|
131
|
-
echo "$output" | grep -q 'afk-accept'
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
@test "NOT eligible: no acceptance criteria at all (fail-closed on zero)" {
|
|
135
|
-
seed_story
|
|
136
|
-
sed -i.bak 's/^- \[ \] The first step happens.//; s/^- \[ \] The second step happens.//' docs/stories/draft/STORY-901-a-story.md
|
|
137
|
-
run_check
|
|
138
|
-
[ "$status" -eq 1 ]
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
# --- ADR-101 Confirmation: the secondary blacklist ---------------------------
|
|
142
|
-
|
|
143
|
-
@test "NOT eligible: an open-decision marker in ordinary prose" {
|
|
144
|
-
seed_story
|
|
145
|
-
printf -- '\nThe storage locus is still to be decided.\n' >> docs/stories/draft/STORY-901-a-story.md
|
|
146
|
-
run_check
|
|
147
|
-
[ "$status" -eq 1 ]
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
@test "ELIGIBLE: the same vocabulary inside a fenced or backticked span" {
|
|
151
|
-
seed_story
|
|
152
|
-
printf -- '\nThe checker rejects the phrase `to be decided` when it appears in prose:\n\n```\nopen question / TBD / decision needed\n```\n' \
|
|
153
|
-
>> docs/stories/draft/STORY-901-a-story.md
|
|
154
|
-
run_check
|
|
155
|
-
[ "$status" -eq 0 ]
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# --- ADR-101 Confirmation: the map leg disjunction ---------------------------
|
|
159
|
-
|
|
160
|
-
@test "ELIGIBLE: map re-ratified WITH the story's card already present" {
|
|
161
|
-
seed_story
|
|
162
|
-
bash "$MARK" "$MAP" 2>/dev/null # re-ratify now that STORY-901's card exists
|
|
163
|
-
run_check
|
|
164
|
-
[ "$status" -eq 0 ]
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
@test "NOT eligible: map drifted for a reason OTHER than the story's own card" {
|
|
168
|
-
seed_story
|
|
169
|
-
printf '<p>an unrelated edit</p>\n' >> "$MAP"
|
|
170
|
-
run_check
|
|
171
|
-
[ "$status" -eq 1 ]
|
|
172
|
-
echo "$output" | grep -q 'STORY-MAP-900'
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
@test "NOT eligible: map carries no human-oversight marker at all" {
|
|
176
|
-
seed_story
|
|
177
|
-
grep -v 'oversight' "$MAP" > "$MAP.tmp" && mv "$MAP.tmp" "$MAP"
|
|
178
|
-
run_check
|
|
179
|
-
[ "$status" -eq 1 ]
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
# --- ADR-101 Confirmation: the opt-in split ----------------------------------
|
|
183
|
-
|
|
184
|
-
@test "NOT eligible without opt-in, even when (a) and (b) both hold" {
|
|
185
|
-
seed_story
|
|
186
|
-
unset WR_ITIL_AFK_ACCEPT
|
|
187
|
-
run_check
|
|
188
|
-
[ "$status" -eq 1 ]
|
|
189
|
-
echo "$output" | grep -q 'opted in'
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
@test "project config opts in" {
|
|
193
|
-
seed_story
|
|
194
|
-
unset WR_ITIL_AFK_ACCEPT
|
|
195
|
-
mkdir -p .claude
|
|
196
|
-
printf '{ "afk_accept_pure_decomposition": true }\n' > .claude/itil.config.json
|
|
197
|
-
run_check
|
|
198
|
-
[ "$status" -eq 0 ]
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
@test "a non-boolean config value does NOT opt in" {
|
|
202
|
-
seed_story
|
|
203
|
-
unset WR_ITIL_AFK_ACCEPT
|
|
204
|
-
mkdir -p .claude
|
|
205
|
-
printf '{ "afk_accept_pure_decomposition": "true" }\n' > .claude/itil.config.json
|
|
206
|
-
run_check
|
|
207
|
-
[ "$status" -eq 1 ]
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
@test "an unparseable config does NOT opt in" {
|
|
211
|
-
seed_story
|
|
212
|
-
unset WR_ITIL_AFK_ACCEPT
|
|
213
|
-
mkdir -p .claude
|
|
214
|
-
printf 'not json at all\n' > .claude/itil.config.json
|
|
215
|
-
run_check
|
|
216
|
-
[ "$status" -eq 1 ]
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
@test "ADR-098 per-key fallback: a project file omitting the key falls through to machine" {
|
|
220
|
-
seed_story
|
|
221
|
-
unset WR_ITIL_AFK_ACCEPT
|
|
222
|
-
mkdir -p .claude
|
|
223
|
-
printf '{ "some_other_key": 1 }\n' > .claude/itil.config.json
|
|
224
|
-
printf '{ "afk_accept_pure_decomposition": true }\n' > "$HOME/.claude/itil.config.json"
|
|
225
|
-
run_check
|
|
226
|
-
[ "$status" -eq 0 ]
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
@test "a project file setting the key FALSE wins over a machine TRUE" {
|
|
230
|
-
seed_story
|
|
231
|
-
unset WR_ITIL_AFK_ACCEPT
|
|
232
|
-
mkdir -p .claude
|
|
233
|
-
printf '{ "afk_accept_pure_decomposition": false }\n' > .claude/itil.config.json
|
|
234
|
-
printf '{ "afk_accept_pure_decomposition": true }\n' > "$HOME/.claude/itil.config.json"
|
|
235
|
-
run_check
|
|
236
|
-
[ "$status" -eq 1 ]
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
@test "jq absent resolves to the built-in default: NOT eligible" {
|
|
240
|
-
seed_story
|
|
241
|
-
unset WR_ITIL_AFK_ACCEPT
|
|
242
|
-
mkdir -p .claude bin
|
|
243
|
-
printf '{ "afk_accept_pure_decomposition": true }\n' > .claude/itil.config.json
|
|
244
|
-
run env PATH="/usr/bin:/bin" bash "$CHECK" docs/stories/draft/STORY-901-a-story.md \
|
|
245
|
-
docs/story-maps docs/rfcs docs/jtbd docs/problems docs/decisions
|
|
246
|
-
# Only meaningful where jq is genuinely off PATH; skip otherwise.
|
|
247
|
-
if PATH="/usr/bin:/bin" command -v jq >/dev/null 2>&1; then skip "jq is on the minimal PATH here"; fi
|
|
248
|
-
[ "$status" -eq 1 ]
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
# --- ADR-101 Confirmation: no automated path writes a `true` opt-in ----------
|
|
252
|
-
|
|
253
|
-
@test "no shipped installer or scaffold writes an opt-in value" {
|
|
254
|
-
# The guard that keeps opt-in from becoming opt-out-by-stealth. Any shipped
|
|
255
|
-
# code that WRITES this key would defeat the split; reading it is fine.
|
|
256
|
-
cd "$(dirname "$CHECK")/.."
|
|
257
|
-
# Guard the search roots. Pointed at a directory that does not exist, grep
|
|
258
|
-
# matches nothing and the assertion below passes for the wrong reason — and
|
|
259
|
-
# whether it passes at all then depends on which grep merges its warning into
|
|
260
|
-
# bats' $output.
|
|
261
|
-
[ -d bin ] && [ -d hooks ]
|
|
262
|
-
run grep -rIlE 'afk_accept_pure_decomposition' --include='*.mjs' --include='*.js' bin/ hooks/
|
|
263
|
-
[ -z "$output" ]
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
# --- ADR-101 Confirmation: detector stdout contract --------------------------
|
|
267
|
-
|
|
268
|
-
@test "detect-unratified-stories-maps stdout is byte-identical with and without the flag" {
|
|
269
|
-
seed_story
|
|
270
|
-
a="$(bash "$SCRIPTS/detect-unratified-stories-maps.sh" docs/stories docs/story-maps 2>/dev/null)"
|
|
271
|
-
b="$(bash "$SCRIPTS/detect-unratified-stories-maps.sh" --with-afk-accepted docs/stories docs/story-maps 2>/dev/null)"
|
|
272
|
-
[ "$a" = "$b" ]
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
@test "--with-afk-accepted surfaces the machine-accepted story on stderr" {
|
|
276
|
-
seed_story
|
|
277
|
-
run bash -c "bash '$SCRIPTS/detect-unratified-stories-maps.sh' --with-afk-accepted docs/stories docs/story-maps 2>&1 >/dev/null"
|
|
278
|
-
echo "$output" | grep -q 'STORY-901'
|
|
279
|
-
echo "$output" | grep -q 'AFK-ACCEPTED'
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
@test "the post-hoc drain still finds the story when oversight-basis is stripped" {
|
|
283
|
-
# The union key. `oversight-basis` is excluded from the content hash, so
|
|
284
|
-
# stripping it would otherwise hide a machine-accepted story from the drain;
|
|
285
|
-
# the authored `afk-accept:` declaration is inside the hash and closes that.
|
|
286
|
-
seed_story
|
|
287
|
-
bash "$MARK" --pure-decomposition docs/stories/draft/STORY-901-a-story.md 2>/dev/null
|
|
288
|
-
sed -i.bak '/^oversight-basis:/d' docs/stories/draft/STORY-901-a-story.md
|
|
289
|
-
run bash -c "bash '$SCRIPTS/detect-unratified-stories-maps.sh' --with-afk-accepted docs/stories docs/story-maps 2>&1 >/dev/null"
|
|
290
|
-
echo "$output" | grep -q 'STORY-901'
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
# --- the marker write path ---------------------------------------------------
|
|
294
|
-
|
|
295
|
-
@test "--pure-decomposition records the basis AND leaves the story ratified" {
|
|
296
|
-
seed_story
|
|
297
|
-
bash "$MARK" --pure-decomposition docs/stories/draft/STORY-901-a-story.md 2>/dev/null
|
|
298
|
-
grep -q '^oversight-basis: pure-decomposition' docs/stories/draft/STORY-901-a-story.md
|
|
299
|
-
# The basis line is excluded from the hash, so the story must NOT read as
|
|
300
|
-
# drifted the instant it is marked.
|
|
301
|
-
run bash -c "source '$SCRIPTS/../lib/story-oversight.sh'; is_story_map_ratified docs/stories/draft/STORY-901-a-story.md"
|
|
302
|
-
[ "$status" -eq 0 ]
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
@test "a plain re-ratify CLEARS a stale pure-decomposition basis" {
|
|
306
|
-
seed_story
|
|
307
|
-
bash "$MARK" --pure-decomposition docs/stories/draft/STORY-901-a-story.md 2>/dev/null
|
|
308
|
-
bash "$MARK" docs/stories/draft/STORY-901-a-story.md 2>/dev/null
|
|
309
|
-
! grep -q '^oversight-basis:' docs/stories/draft/STORY-901-a-story.md
|
|
310
|
-
}
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P351 — skills fail-soft-skip when their precondition config is
|
|
4
|
-
# missing — should auto-bootstrap with user input as needed
|
|
5
|
-
# rather than silently skipping.
|
|
6
|
-
#
|
|
7
|
-
# Contract: `check-fail-soft-skip-discipline.sh <repo-root>` walks
|
|
8
|
-
# `<repo-root>/packages/*/skills/*/SKILL.md`, greps each file for the
|
|
9
|
-
# tightened fail-soft-skip pattern set
|
|
10
|
-
# (fail-soft skip|silently skip|skipping.*config|skipping.*not configured|
|
|
11
|
-
# not configured.*skip), emits one `WARN <relpath>:<line> <pat>: ...`
|
|
12
|
-
# line per match on stderr, and exits 0 in Phase 1 advisory mode
|
|
13
|
-
# regardless of whether violations were found.
|
|
14
|
-
#
|
|
15
|
-
# @adr ADR-049 (bin/ on PATH shim — adopter-safe script resolution)
|
|
16
|
-
# @adr ADR-052 (Behavioural bats default)
|
|
17
|
-
# @adr ADR-040 (Advisory-then-load-bearing reusable pattern)
|
|
18
|
-
# @adr ADR-013 Rule 6 (Non-interactive fail-safe — advisory exit 0)
|
|
19
|
-
# @jtbd JTBD-001 (Enforce Governance — pattern-discipline lint)
|
|
20
|
-
# @jtbd JTBD-101 (Extend the Suite — extensible pattern per skill site)
|
|
21
|
-
|
|
22
|
-
setup() {
|
|
23
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
24
|
-
SCRIPT="$SCRIPTS_DIR/check-fail-soft-skip-discipline.sh"
|
|
25
|
-
FIXTURE_ROOT="$(mktemp -d)"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
teardown() {
|
|
29
|
-
rm -rf "$FIXTURE_ROOT"
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
@test "check-fail-soft-skip-discipline: script exists" {
|
|
35
|
-
[ -f "$SCRIPT" ]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
@test "check-fail-soft-skip-discipline: script is executable" {
|
|
39
|
-
[ -x "$SCRIPT" ]
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
# ── Phase 1 advisory exit-code contract ─────────────────────────────────────
|
|
43
|
-
|
|
44
|
-
@test "Phase 1 advisory: exits 0 on a clean fixture" {
|
|
45
|
-
mkdir -p "$FIXTURE_ROOT/packages/sample/skills/clean-skill"
|
|
46
|
-
cat > "$FIXTURE_ROOT/packages/sample/skills/clean-skill/SKILL.md" <<'EOF'
|
|
47
|
-
# Sample clean skill
|
|
48
|
-
|
|
49
|
-
This skill auto-bootstraps any missing precondition config via
|
|
50
|
-
AskUserQuestion. No fail-soft pattern present.
|
|
51
|
-
EOF
|
|
52
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
53
|
-
[ "$status" -eq 0 ]
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@test "Phase 1 advisory: exits 0 even when violations present (default WR_FAIL_SOFT_SKIP_WARN_ONLY=1)" {
|
|
57
|
-
mkdir -p "$FIXTURE_ROOT/packages/sample/skills/dirty-skill"
|
|
58
|
-
cat > "$FIXTURE_ROOT/packages/sample/skills/dirty-skill/SKILL.md" <<'EOF'
|
|
59
|
-
# Sample dirty skill
|
|
60
|
-
|
|
61
|
-
This skill performs a fail-soft skip when the config is missing.
|
|
62
|
-
EOF
|
|
63
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
64
|
-
[ "$status" -eq 0 ]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
# ── WARN-on-fixture: behavioural ────────────────────────────────────────────
|
|
68
|
-
|
|
69
|
-
@test "WARN-on-fixture: matches 'fail-soft skip' literal" {
|
|
70
|
-
mkdir -p "$FIXTURE_ROOT/packages/sample/skills/dirty-skill"
|
|
71
|
-
cat > "$FIXTURE_ROOT/packages/sample/skills/dirty-skill/SKILL.md" <<'EOF'
|
|
72
|
-
# Dirty skill
|
|
73
|
-
|
|
74
|
-
When the file is missing emit a fail-soft skip and continue.
|
|
75
|
-
EOF
|
|
76
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
77
|
-
[ "$status" -eq 0 ]
|
|
78
|
-
[[ "$output" == *"WARN"* ]]
|
|
79
|
-
[[ "$output" == *"packages/sample/skills/dirty-skill/SKILL.md"* ]]
|
|
80
|
-
[[ "$output" == *"fail-soft skip"* ]]
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@test "WARN-on-fixture: matches 'silently skip' synonym" {
|
|
84
|
-
mkdir -p "$FIXTURE_ROOT/packages/sample/skills/silent-skill"
|
|
85
|
-
cat > "$FIXTURE_ROOT/packages/sample/skills/silent-skill/SKILL.md" <<'EOF'
|
|
86
|
-
# Silent skill
|
|
87
|
-
|
|
88
|
-
If config missing, silently skip the pass.
|
|
89
|
-
EOF
|
|
90
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
91
|
-
[ "$status" -eq 0 ]
|
|
92
|
-
[[ "$output" == *"silently skip"* ]]
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
@test "WARN-on-fixture: matches tightened 'skipping.*config' shape" {
|
|
96
|
-
mkdir -p "$FIXTURE_ROOT/packages/sample/skills/skipper-skill"
|
|
97
|
-
cat > "$FIXTURE_ROOT/packages/sample/skills/skipper-skill/SKILL.md" <<'EOF'
|
|
98
|
-
# Skipper skill
|
|
99
|
-
|
|
100
|
-
Skipping the pass because the channels config is absent.
|
|
101
|
-
EOF
|
|
102
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
103
|
-
[ "$status" -eq 0 ]
|
|
104
|
-
[[ "$output" == *"skipper-skill/SKILL.md"* ]]
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
# ── CLEAN-on-fixture: behavioural negative ──────────────────────────────────
|
|
108
|
-
|
|
109
|
-
@test "CLEAN-on-fixture: no WARN emitted when SKILL.md is fail-soft-skip free" {
|
|
110
|
-
mkdir -p "$FIXTURE_ROOT/packages/sample/skills/auto-bootstrap-skill"
|
|
111
|
-
cat > "$FIXTURE_ROOT/packages/sample/skills/auto-bootstrap-skill/SKILL.md" <<'EOF'
|
|
112
|
-
# Auto-bootstrap skill
|
|
113
|
-
|
|
114
|
-
When the config file is missing, auto-bootstrap it via AskUserQuestion
|
|
115
|
-
(interactive mode) or queue a config-direction outstanding_question
|
|
116
|
-
(AFK mode). The skill resumes the original pass after bootstrap.
|
|
117
|
-
EOF
|
|
118
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
119
|
-
[ "$status" -eq 0 ]
|
|
120
|
-
! [[ "$output" == *"WARN"* ]]
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
@test "CLEAN-on-fixture: does NOT false-positive on legitimate per-channel skip prose (architect tightening)" {
|
|
124
|
-
mkdir -p "$FIXTURE_ROOT/packages/sample/skills/per-channel-skill"
|
|
125
|
-
cat > "$FIXTURE_ROOT/packages/sample/skills/per-channel-skill/SKILL.md" <<'EOF'
|
|
126
|
-
# Per-channel skill
|
|
127
|
-
|
|
128
|
-
On rate-limit, log advisory and skip that channel only — skipping the
|
|
129
|
-
failing channel/report is fine because other channels proceed. This
|
|
130
|
-
prose is the inverse of fail-soft-skip-on-missing-config and must NOT
|
|
131
|
-
fire a WARN per the architect-tightened pattern set.
|
|
132
|
-
EOF
|
|
133
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
134
|
-
[ "$status" -eq 0 ]
|
|
135
|
-
# The "fail-soft-skip-on-missing-config" hyphenated literal in the
|
|
136
|
-
# prose does NOT contain a literal space-separated "fail-soft skip"
|
|
137
|
-
# phrase, but the descriptive text does. Verify the script catches the
|
|
138
|
-
# descriptive use and does NOT mistake the per-channel skip-prose for
|
|
139
|
-
# the load-bearing pattern.
|
|
140
|
-
# We expect EITHER zero WARNs (if the descriptive use is the only
|
|
141
|
-
# hit) OR exactly the descriptive lines. Either way the per-channel
|
|
142
|
-
# "skipping the failing channel/report" prose alone must NOT generate
|
|
143
|
-
# a WARN.
|
|
144
|
-
channel_only_warns=$(echo "$output" | grep -c "skipping the failing channel" || true)
|
|
145
|
-
[ "$channel_only_warns" = "0" ]
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
# ── Phase 2 promotion: behavioural ──────────────────────────────────────────
|
|
149
|
-
|
|
150
|
-
@test "Phase 2 promotion: exits 1 when WR_FAIL_SOFT_SKIP_WARN_ONLY=0 + violations present" {
|
|
151
|
-
mkdir -p "$FIXTURE_ROOT/packages/sample/skills/dirty-skill"
|
|
152
|
-
cat > "$FIXTURE_ROOT/packages/sample/skills/dirty-skill/SKILL.md" <<'EOF'
|
|
153
|
-
# Dirty skill
|
|
154
|
-
|
|
155
|
-
Fail-soft skip when missing.
|
|
156
|
-
EOF
|
|
157
|
-
WR_FAIL_SOFT_SKIP_WARN_ONLY=0 run "$SCRIPT" "$FIXTURE_ROOT"
|
|
158
|
-
[ "$status" -eq 1 ]
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
# ── Usage / path-error contract ─────────────────────────────────────────────
|
|
162
|
-
|
|
163
|
-
@test "Usage: exits 2 on missing repo-root directory" {
|
|
164
|
-
run "$SCRIPT" "$FIXTURE_ROOT/does-not-exist"
|
|
165
|
-
[ "$status" -eq 2 ]
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
@test "Usage: exits 2 on repo-root without packages/ subdir" {
|
|
169
|
-
mkdir -p "$FIXTURE_ROOT/no-packages-here"
|
|
170
|
-
run "$SCRIPT" "$FIXTURE_ROOT/no-packages-here"
|
|
171
|
-
[ "$status" -eq 2 ]
|
|
172
|
-
}
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P314 — Phase 2 (RFC-005 B3/B4): the fix-time propose-fix
|
|
4
|
-
# RFC-trace gate. Before fix work commences on a Known Error, the
|
|
5
|
-
# framework requires an RFC tracing the problem; if none exists, a
|
|
6
|
-
# problem-traced skeleton RFC is auto-created (per ADR-073) rather than
|
|
7
|
-
# blocked. This script is the load-bearing PREDICATE half of that gate
|
|
8
|
-
# (ADR-060 I1 load-bearing-from-the-start carried forward): it detects
|
|
9
|
-
# whether any RFC traces the problem and emits an auto-create directive
|
|
10
|
-
# on stdout when none does. The CREATE half is skill-orchestrated
|
|
11
|
-
# (delegates to /wr-itil:capture-rfc — the canonical ADR-070-compliant
|
|
12
|
-
# problem-traced-skeleton vehicle, no duplication).
|
|
13
|
-
#
|
|
14
|
-
# Behavioural per ADR-052: assert on the script's exit code + stdout
|
|
15
|
-
# directive given fixture RFC corpora — not on script source content
|
|
16
|
-
# (no structural greps per P081).
|
|
17
|
-
#
|
|
18
|
-
# Contract:
|
|
19
|
-
# - <problem-file> whose basename is `<NNN>-<slug>.md` → PID = P<NNN>.
|
|
20
|
-
# - An RFC traces the problem when its frontmatter `problems:` array
|
|
21
|
-
# contains the exact PID (boundary-safe: P31 / P3140 must NOT match
|
|
22
|
-
# a P314 query).
|
|
23
|
-
# - Trace present → exit 0, EMPTY stdout (fix proceeds; no auto-create).
|
|
24
|
-
# - Trace absent → exit 0, stdout carries `no-rfc-trace: P<NNN>` directive
|
|
25
|
-
# (NEVER a non-zero/block exit — ADR-073 auto-create-not-block).
|
|
26
|
-
# - Missing problem file / no args → exit 2 (caller misuse), stderr usage.
|
|
27
|
-
#
|
|
28
|
-
# @adr ADR-072 (RFC required at the propose-fix step on a Known Error)
|
|
29
|
-
# @adr ADR-073 (fix-time gate auto-creates a missing RFC, everywhere —
|
|
30
|
-
# never blocks; hence exit 0 on the absent branch)
|
|
31
|
-
# @adr ADR-071 (every fix goes through an RFC — unconditional, no carve-out)
|
|
32
|
-
# @adr ADR-060 (I1 load-bearing-from-the-start; I13 fix-proposal invariant)
|
|
33
|
-
# @adr ADR-052 (behavioural bats default)
|
|
34
|
-
# @jtbd JTBD-008 (Decompose a Fix Into Coordinated Changes — trace invariant)
|
|
35
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — never stall/skip)
|
|
36
|
-
|
|
37
|
-
setup() {
|
|
38
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
39
|
-
SCRIPT="$SCRIPTS_DIR/check-fix-rfc-trace.sh"
|
|
40
|
-
RFCS_DIR="$(mktemp -d)"
|
|
41
|
-
PROBLEMS_DIR="$(mktemp -d)"
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
teardown() {
|
|
45
|
-
rm -rf "$RFCS_DIR" "$PROBLEMS_DIR"
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
# Write an RFC fixture whose frontmatter `problems:` array is set verbatim.
|
|
49
|
-
write_rfc() {
|
|
50
|
-
local id="$1" slug="$2" status="$3" problems="$4"
|
|
51
|
-
cat > "$RFCS_DIR/RFC-${id}-${slug}.${status}.md" <<EOF
|
|
52
|
-
---
|
|
53
|
-
status: ${status}
|
|
54
|
-
rfc-id: ${slug}
|
|
55
|
-
problems: ${problems}
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
# RFC-${id}: ${slug}
|
|
59
|
-
EOF
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
# Write a problem fixture; returns the path on stdout.
|
|
63
|
-
write_problem() {
|
|
64
|
-
local num="$1" slug="${2:-some-problem}"
|
|
65
|
-
local f="$PROBLEMS_DIR/${num}-${slug}.md"
|
|
66
|
-
cat > "$f" <<EOF
|
|
67
|
-
# Problem ${num}: ${slug}
|
|
68
|
-
|
|
69
|
-
**Status**: Known Error
|
|
70
|
-
EOF
|
|
71
|
-
printf '%s' "$f"
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
@test "trace present (single-PID array) → exit 0, empty stdout" {
|
|
75
|
-
write_rfc 005 some-fix accepted "[P314]"
|
|
76
|
-
pf="$(write_problem 314)"
|
|
77
|
-
run "$SCRIPT" "$pf" "$RFCS_DIR"
|
|
78
|
-
[ "$status" -eq 0 ]
|
|
79
|
-
[ -z "$output" ]
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
@test "trace present (multi-PID array) → exit 0, empty stdout" {
|
|
83
|
-
write_rfc 005 some-fix accepted "[P100, P314, P200]"
|
|
84
|
-
pf="$(write_problem 314)"
|
|
85
|
-
run "$SCRIPT" "$pf" "$RFCS_DIR"
|
|
86
|
-
[ "$status" -eq 0 ]
|
|
87
|
-
[ -z "$output" ]
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
@test "trace absent (empty rfcs dir) → exit 0, auto-create directive on stdout" {
|
|
91
|
-
pf="$(write_problem 314)"
|
|
92
|
-
run "$SCRIPT" "$pf" "$RFCS_DIR"
|
|
93
|
-
[ "$status" -eq 0 ]
|
|
94
|
-
[[ "$output" == *"no-rfc-trace: P314"* ]]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
@test "trace absent (RFCs exist but none claim this PID) → exit 0, directive" {
|
|
98
|
-
write_rfc 005 other-fix accepted "[P251]"
|
|
99
|
-
write_rfc 013 another accepted "[P346]"
|
|
100
|
-
pf="$(write_problem 314)"
|
|
101
|
-
run "$SCRIPT" "$pf" "$RFCS_DIR"
|
|
102
|
-
[ "$status" -eq 0 ]
|
|
103
|
-
[[ "$output" == *"no-rfc-trace: P314"* ]]
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
@test "PID boundary: P31 in an RFC does NOT satisfy a P314 query" {
|
|
107
|
-
write_rfc 005 short-pid accepted "[P31]"
|
|
108
|
-
pf="$(write_problem 314)"
|
|
109
|
-
run "$SCRIPT" "$pf" "$RFCS_DIR"
|
|
110
|
-
[ "$status" -eq 0 ]
|
|
111
|
-
[[ "$output" == *"no-rfc-trace: P314"* ]]
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
@test "PID boundary: P3140 in an RFC does NOT satisfy a P314 query" {
|
|
115
|
-
write_rfc 005 long-pid accepted "[P3140]"
|
|
116
|
-
pf="$(write_problem 314)"
|
|
117
|
-
run "$SCRIPT" "$pf" "$RFCS_DIR"
|
|
118
|
-
[ "$status" -eq 0 ]
|
|
119
|
-
[[ "$output" == *"no-rfc-trace: P314"* ]]
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@test "exact match works for a zero-padded low PID (P080 ← [P080])" {
|
|
123
|
-
# PIDs are canonically 3-digit zero-padded (filenames 080-..., citations P080).
|
|
124
|
-
write_rfc 005 padded-pid accepted "[P080]"
|
|
125
|
-
pf="$(write_problem 080)"
|
|
126
|
-
run "$SCRIPT" "$pf" "$RFCS_DIR"
|
|
127
|
-
[ "$status" -eq 0 ]
|
|
128
|
-
[ -z "$output" ]
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
@test "default rfcs-dir is docs/rfcs when second arg omitted" {
|
|
132
|
-
# Run from a temp cwd containing docs/rfcs with a tracing RFC.
|
|
133
|
-
workdir="$(mktemp -d)"
|
|
134
|
-
mkdir -p "$workdir/docs/rfcs"
|
|
135
|
-
cat > "$workdir/docs/rfcs/RFC-005-x.accepted.md" <<'EOF'
|
|
136
|
-
---
|
|
137
|
-
problems: [P314]
|
|
138
|
-
---
|
|
139
|
-
# RFC-005: x
|
|
140
|
-
EOF
|
|
141
|
-
pf="$(write_problem 314)"
|
|
142
|
-
run bash -c "cd '$workdir' && '$SCRIPT' '$pf'"
|
|
143
|
-
[ "$status" -eq 0 ]
|
|
144
|
-
[ -z "$output" ]
|
|
145
|
-
rm -rf "$workdir"
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
@test "missing problem file → exit 2, stderr usage" {
|
|
149
|
-
run "$SCRIPT" "$PROBLEMS_DIR/999-nonexistent.md" "$RFCS_DIR"
|
|
150
|
-
[ "$status" -eq 2 ]
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
@test "no args → exit 2" {
|
|
154
|
-
run "$SCRIPT"
|
|
155
|
-
[ "$status" -eq 2 ]
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
@test "directive names the canonical auto-create vehicle (capture-rfc) and ADRs" {
|
|
159
|
-
pf="$(write_problem 314)"
|
|
160
|
-
run "$SCRIPT" "$pf" "$RFCS_DIR"
|
|
161
|
-
[ "$status" -eq 0 ]
|
|
162
|
-
[[ "$output" == *"capture-rfc"* ]]
|
|
163
|
-
[[ "$output" == *"ADR-073"* ]]
|
|
164
|
-
}
|