@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,291 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P328 — BSD `grep` / `sed` / `awk` on macOS silently mis-process
|
|
4
|
-
# UTF-8 multi-byte characters (em-dash, smart quotes) without
|
|
5
|
-
# `LC_ALL=en_US.UTF-8` set. Lint detects unprotected invocations so the
|
|
6
|
-
# class of silent-wrong-result bugs can't reach the codebase undetected.
|
|
7
|
-
#
|
|
8
|
-
# Contract: `check-locale-discipline.sh [<repo-root>]` walks scripts under
|
|
9
|
-
# `packages/*/scripts/`, `packages/*/hooks/` (incl. nested `lib/`), and
|
|
10
|
-
# `packages/*/lib/`, then emits one WARN line per unprotected grep/sed/awk
|
|
11
|
-
# invocation. Default Phase 1 advisory exits 0; `WR_LOCALE_DISCIPLINE_WARN_ONLY=0`
|
|
12
|
-
# promotes to Phase 2 load-bearing (exit 1 on any violation).
|
|
13
|
-
#
|
|
14
|
-
# Behavioural fixture (ADR-052 default): every test exercises the script
|
|
15
|
-
# against a synthesised packages/ fixture tree containing known-state
|
|
16
|
-
# scripts. No grep of SKILL.md / agent prose / source content.
|
|
17
|
-
#
|
|
18
|
-
# @adr ADR-040 (advisory-then-load-bearing reusable pattern)
|
|
19
|
-
# @adr ADR-049 (plugin-bundled scripts; PATH shim)
|
|
20
|
-
# @adr ADR-052 (behavioural-tests-default — temp script with known violations)
|
|
21
|
-
# @adr ADR-080 (highest-version-wins shim wrapper)
|
|
22
|
-
# @adr ADR-005 (Plugin testing strategy — bats coverage)
|
|
23
|
-
# @jtbd JTBD-001 (Enforce Governance Without Slowing Down)
|
|
24
|
-
# @jtbd JTBD-101 (Extend the Suite with New Plugins)
|
|
25
|
-
|
|
26
|
-
setup() {
|
|
27
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
28
|
-
SCRIPT="$SCRIPTS_DIR/check-locale-discipline.sh"
|
|
29
|
-
FIXTURE_ROOT="$(mktemp -d)"
|
|
30
|
-
mkdir -p "$FIXTURE_ROOT/packages/demo/scripts"
|
|
31
|
-
mkdir -p "$FIXTURE_ROOT/packages/demo/hooks"
|
|
32
|
-
mkdir -p "$FIXTURE_ROOT/packages/demo/hooks/lib"
|
|
33
|
-
mkdir -p "$FIXTURE_ROOT/packages/demo/lib"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
teardown() {
|
|
37
|
-
rm -rf "$FIXTURE_ROOT"
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
41
|
-
|
|
42
|
-
@test "check-locale-discipline: script exists" {
|
|
43
|
-
[ -f "$SCRIPT" ]
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@test "check-locale-discipline: script is executable" {
|
|
47
|
-
[ -x "$SCRIPT" ]
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
# ── Negative cases (violations expected) ────────────────────────────────────
|
|
51
|
-
|
|
52
|
-
@test "check-locale-discipline: grep without LC_ALL emits WARN and counts violation" {
|
|
53
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/raw-grep.sh" <<'EOF'
|
|
54
|
-
#!/usr/bin/env bash
|
|
55
|
-
grep -c '^### ' README.md
|
|
56
|
-
EOF
|
|
57
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
58
|
-
[ "$status" -eq 0 ] # Phase 1 advisory
|
|
59
|
-
echo "$output" | grep -E "WARN.*raw-grep.sh:2.*grep without preceding LC_ALL"
|
|
60
|
-
echo "$output" | grep -E "1 violation"
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@test "check-locale-discipline: sed without LC_ALL emits WARN" {
|
|
64
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/raw-sed.sh" <<'EOF'
|
|
65
|
-
#!/usr/bin/env bash
|
|
66
|
-
sed -n '/^### /p' README.md
|
|
67
|
-
EOF
|
|
68
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
69
|
-
[ "$status" -eq 0 ]
|
|
70
|
-
echo "$output" | grep -E "WARN.*raw-sed.sh:2.*sed without preceding LC_ALL"
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
@test "check-locale-discipline: awk without LC_ALL emits WARN" {
|
|
74
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/raw-awk.sh" <<'EOF'
|
|
75
|
-
#!/usr/bin/env bash
|
|
76
|
-
awk '/^### /' README.md
|
|
77
|
-
EOF
|
|
78
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
79
|
-
[ "$status" -eq 0 ]
|
|
80
|
-
echo "$output" | grep -E "WARN.*raw-awk.sh:2.*awk without preceding LC_ALL"
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
# ── Positive cases (file-wide protection — silent pass) ─────────────────────
|
|
84
|
-
|
|
85
|
-
@test "check-locale-discipline: file-wide export LC_ALL above grep — silent pass" {
|
|
86
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/protected.sh" <<'EOF'
|
|
87
|
-
#!/usr/bin/env bash
|
|
88
|
-
export LC_ALL=en_US.UTF-8
|
|
89
|
-
grep -c '^### ' README.md
|
|
90
|
-
sed -n '/^### /p' README.md
|
|
91
|
-
awk '/^### /' README.md
|
|
92
|
-
EOF
|
|
93
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
94
|
-
[ "$status" -eq 0 ]
|
|
95
|
-
! echo "$output" | grep -qE "protected.sh.*WARN"
|
|
96
|
-
echo "$output" | grep -E "clean"
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
@test "check-locale-discipline: inline LC_ALL= prefix on same line — silent pass" {
|
|
100
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/inline.sh" <<'EOF'
|
|
101
|
-
#!/usr/bin/env bash
|
|
102
|
-
LC_ALL=en_US.UTF-8 grep -c '^### ' README.md
|
|
103
|
-
LC_ALL=en_US.UTF-8 sed -n '/^### /p' README.md
|
|
104
|
-
LC_ALL=en_US.UTF-8 awk '/^### /' README.md
|
|
105
|
-
EOF
|
|
106
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
107
|
-
[ "$status" -eq 0 ]
|
|
108
|
-
! echo "$output" | grep -qE "inline.sh.*WARN"
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
# ── Edge cases ──────────────────────────────────────────────────────────────
|
|
112
|
-
|
|
113
|
-
@test "check-locale-discipline: multiple grep/sed/awk on one line — line is flagged" {
|
|
114
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/multi.sh" <<'EOF'
|
|
115
|
-
#!/usr/bin/env bash
|
|
116
|
-
grep -c '^### ' README.md | sed 's/ //g' | awk '{print $1}'
|
|
117
|
-
EOF
|
|
118
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
119
|
-
[ "$status" -eq 0 ]
|
|
120
|
-
# At least one tool is reported; we don't over-specify the count.
|
|
121
|
-
echo "$output" | grep -E "WARN.*multi.sh:2.*(grep|sed|awk) without preceding LC_ALL"
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
@test "check-locale-discipline: git grep is skipped" {
|
|
125
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/git-grep.sh" <<'EOF'
|
|
126
|
-
#!/usr/bin/env bash
|
|
127
|
-
git grep -nE 'pattern' -- '*.md'
|
|
128
|
-
EOF
|
|
129
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
130
|
-
[ "$status" -eq 0 ]
|
|
131
|
-
! echo "$output" | grep -qE "git-grep.sh.*WARN"
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
@test "check-locale-discipline: heredoc body containing grep is not flagged" {
|
|
135
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/heredoc.sh" <<'EOF'
|
|
136
|
-
#!/usr/bin/env bash
|
|
137
|
-
cat <<'INNER'
|
|
138
|
-
The way to do this is to run: grep '^### ' README.md
|
|
139
|
-
And then: sed -n '/^### /p'
|
|
140
|
-
INNER
|
|
141
|
-
echo "done"
|
|
142
|
-
EOF
|
|
143
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
144
|
-
[ "$status" -eq 0 ]
|
|
145
|
-
# Heredoc body lines must NOT produce WARNs.
|
|
146
|
-
! echo "$output" | grep -qE "heredoc.sh:[34].*WARN"
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
@test "check-locale-discipline: comment-only line is not flagged" {
|
|
150
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/commented.sh" <<'EOF'
|
|
151
|
-
#!/usr/bin/env bash
|
|
152
|
-
# Future work: replace this awk with a sed | grep pipeline.
|
|
153
|
-
echo "no grep here"
|
|
154
|
-
EOF
|
|
155
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
156
|
-
[ "$status" -eq 0 ]
|
|
157
|
-
! echo "$output" | grep -qE "commented.sh.*WARN"
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
@test "check-locale-discipline: identifiers containing grep/sed/awk substrings are not flagged" {
|
|
161
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/identifiers.sh" <<'EOF'
|
|
162
|
-
#!/usr/bin/env bash
|
|
163
|
-
grep_helper="something"
|
|
164
|
-
result_from_sed=42
|
|
165
|
-
my_awkward_var="x"
|
|
166
|
-
echo "$grep_helper $result_from_sed $my_awkward_var"
|
|
167
|
-
EOF
|
|
168
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
169
|
-
[ "$status" -eq 0 ]
|
|
170
|
-
! echo "$output" | grep -qE "identifiers.sh.*WARN"
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
# ── Scope: hooks/ + lib/ + nested hooks/lib/ ────────────────────────────────
|
|
174
|
-
|
|
175
|
-
@test "check-locale-discipline: scans packages/*/hooks/ scripts" {
|
|
176
|
-
cat > "$FIXTURE_ROOT/packages/demo/hooks/raw-grep-hook.sh" <<'EOF'
|
|
177
|
-
#!/usr/bin/env bash
|
|
178
|
-
grep -c '^### ' README.md
|
|
179
|
-
EOF
|
|
180
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
181
|
-
[ "$status" -eq 0 ]
|
|
182
|
-
echo "$output" | grep -E "WARN.*hooks/raw-grep-hook.sh:2"
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
@test "check-locale-discipline: scans packages/*/hooks/lib/ scripts" {
|
|
186
|
-
cat > "$FIXTURE_ROOT/packages/demo/hooks/lib/nested.sh" <<'EOF'
|
|
187
|
-
#!/usr/bin/env bash
|
|
188
|
-
awk '/^### /' README.md
|
|
189
|
-
EOF
|
|
190
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
191
|
-
[ "$status" -eq 0 ]
|
|
192
|
-
echo "$output" | grep -E "WARN.*hooks/lib/nested.sh:2"
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
@test "check-locale-discipline: scans packages/*/lib/ scripts" {
|
|
196
|
-
cat > "$FIXTURE_ROOT/packages/demo/lib/raw-sed-lib.sh" <<'EOF'
|
|
197
|
-
#!/usr/bin/env bash
|
|
198
|
-
sed -n '/^### /p' README.md
|
|
199
|
-
EOF
|
|
200
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
201
|
-
[ "$status" -eq 0 ]
|
|
202
|
-
echo "$output" | grep -E "WARN.*lib/raw-sed-lib.sh:2"
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
# ── Phase 1 advisory vs Phase 2 load-bearing ────────────────────────────────
|
|
206
|
-
|
|
207
|
-
@test "check-locale-discipline: Phase 1 default exits 0 even with violations" {
|
|
208
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/violation.sh" <<'EOF'
|
|
209
|
-
#!/usr/bin/env bash
|
|
210
|
-
grep -c '^### ' README.md
|
|
211
|
-
EOF
|
|
212
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
213
|
-
[ "$status" -eq 0 ]
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
@test "check-locale-discipline: Phase 2 load-bearing exits 1 on violations" {
|
|
217
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/violation.sh" <<'EOF'
|
|
218
|
-
#!/usr/bin/env bash
|
|
219
|
-
grep -c '^### ' README.md
|
|
220
|
-
EOF
|
|
221
|
-
WR_LOCALE_DISCIPLINE_WARN_ONLY=0 run "$SCRIPT" "$FIXTURE_ROOT"
|
|
222
|
-
[ "$status" -eq 1 ]
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
@test "check-locale-discipline: Phase 2 load-bearing exits 0 on clean tree" {
|
|
226
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/clean.sh" <<'EOF'
|
|
227
|
-
#!/usr/bin/env bash
|
|
228
|
-
export LC_ALL=en_US.UTF-8
|
|
229
|
-
grep -c '^### ' README.md
|
|
230
|
-
EOF
|
|
231
|
-
WR_LOCALE_DISCIPLINE_WARN_ONLY=0 run "$SCRIPT" "$FIXTURE_ROOT"
|
|
232
|
-
[ "$status" -eq 0 ]
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
# ── Argument and error handling ─────────────────────────────────────────────
|
|
236
|
-
|
|
237
|
-
@test "check-locale-discipline: missing repo-root directory exits 2" {
|
|
238
|
-
run "$SCRIPT" "$FIXTURE_ROOT/does-not-exist"
|
|
239
|
-
[ "$status" -eq 2 ]
|
|
240
|
-
echo "$output" | grep -iE "not a directory"
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
@test "check-locale-discipline: repo-root without packages/ subdir exits 2" {
|
|
244
|
-
mkdir -p "$FIXTURE_ROOT/empty"
|
|
245
|
-
run "$SCRIPT" "$FIXTURE_ROOT/empty"
|
|
246
|
-
[ "$status" -eq 2 ]
|
|
247
|
-
echo "$output" | grep -iE "no packages/"
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
@test "check-locale-discipline: defaults to current working directory when no arg" {
|
|
251
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/violation.sh" <<'EOF'
|
|
252
|
-
#!/usr/bin/env bash
|
|
253
|
-
grep -c '^### ' README.md
|
|
254
|
-
EOF
|
|
255
|
-
cd "$FIXTURE_ROOT"
|
|
256
|
-
run "$SCRIPT"
|
|
257
|
-
[ "$status" -eq 0 ]
|
|
258
|
-
echo "$output" | grep -E "WARN.*scripts/violation.sh:2"
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
# ── Output shape ────────────────────────────────────────────────────────────
|
|
262
|
-
|
|
263
|
-
@test "check-locale-discipline: clean tree emits summary on stdout" {
|
|
264
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/clean.sh" <<'EOF'
|
|
265
|
-
#!/usr/bin/env bash
|
|
266
|
-
export LC_ALL=en_US.UTF-8
|
|
267
|
-
grep -c '^### ' README.md
|
|
268
|
-
EOF
|
|
269
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
270
|
-
[ "$status" -eq 0 ]
|
|
271
|
-
echo "$output" | grep -E "^check-locale-discipline: clean"
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
@test "check-locale-discipline: violation summary cites P328" {
|
|
275
|
-
cat > "$FIXTURE_ROOT/packages/demo/scripts/violation.sh" <<'EOF'
|
|
276
|
-
#!/usr/bin/env bash
|
|
277
|
-
grep -c '^### ' README.md
|
|
278
|
-
EOF
|
|
279
|
-
run "$SCRIPT" "$FIXTURE_ROOT"
|
|
280
|
-
[ "$status" -eq 0 ]
|
|
281
|
-
echo "$output" | grep -E "P328"
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
# ── Self-application: lint script itself is locale-discipline-compliant ─────
|
|
285
|
-
|
|
286
|
-
@test "check-locale-discipline: own script declares export LC_ALL at top" {
|
|
287
|
-
# The lint walks UTF-8 prose; it must lead by example. This guards
|
|
288
|
-
# against a future edit that strips the export and reintroduces P328
|
|
289
|
-
# in the lint itself.
|
|
290
|
-
head -80 "$SCRIPT" | grep -qE "^export LC_ALL=en_US.UTF-8$"
|
|
291
|
-
}
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P134 — docs/problems/README.md line 3 narrative-blob accumulator
|
|
4
|
-
# bloat. Sibling to P099 (briefing tier 3) on a different surface. The
|
|
5
|
-
# "Last reviewed" line accumulates session-summary fragments unbounded;
|
|
6
|
-
# at ~62 KB it breaks the Read tool entirely (25K-token limit on the
|
|
7
|
-
# whole file regardless of offset/limit). P134 promotes the same
|
|
8
|
-
# advisory-triplet pattern P099 documented (advisory script + behavioural
|
|
9
|
-
# bats + ADR-040-tier-budget enforcement clause) to this surface.
|
|
10
|
-
#
|
|
11
|
-
# Contract: `check-problems-readme-budget.sh [<readme-path>]` is a
|
|
12
|
-
# diagnose-only advisory script. It reads `docs/problems/README.md`
|
|
13
|
-
# (or the supplied path), measures the byte size of line 3, and reports
|
|
14
|
-
# overflow when line 3 is at or above the configured threshold (default
|
|
15
|
-
# 5120 bytes per ADR-040 Tier 3 envelope; overridable via the
|
|
16
|
-
# `PROBLEMS_README_LINE3_MAX_BYTES` env var).
|
|
17
|
-
#
|
|
18
|
-
# Exit codes:
|
|
19
|
-
# 0 = always (advisory only — overflow is signal, not failure)
|
|
20
|
-
# 2 = parse error (README path missing or unreadable)
|
|
21
|
-
#
|
|
22
|
-
# Output format on overflow (one line, terse machine-readable per
|
|
23
|
-
# ADR-038 progressive-disclosure budget):
|
|
24
|
-
# OVER <readme-path> line=3 bytes=<N> threshold=<N>
|
|
25
|
-
#
|
|
26
|
-
# Output is empty (no lines) when line 3 is under the threshold.
|
|
27
|
-
#
|
|
28
|
-
# The script is read-only — it does NOT mutate the README. Truncation
|
|
29
|
-
# is owned by the per-operation refresh contracts in `manage-problem`
|
|
30
|
-
# Step 5 P094 + Step 7 P062 (and the sibling skills `transition-problem`,
|
|
31
|
-
# `transition-problems`, `review-problems`, `reconcile-readme`).
|
|
32
|
-
#
|
|
33
|
-
# @jtbd JTBD-001 (Enforce Governance Without Slowing Down — restores
|
|
34
|
-
# Read-tool affordance to the highest-traffic problems-management surface)
|
|
35
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — every AFK iter's
|
|
36
|
-
# manage-problem call previously paid an awk/grep workaround tax)
|
|
37
|
-
# @jtbd JTBD-101 (Extend the Suite with Clear Patterns — re-applies P099's
|
|
38
|
-
# advisory-script + bats + ADR-tier-budget triplet to a new surface,
|
|
39
|
-
# exactly the reusable shape ADR-040 line 92 documents)
|
|
40
|
-
#
|
|
41
|
-
# Cross-reference:
|
|
42
|
-
# P134: docs/problems/134-docs-problems-readme-md-line-3-narrative-blob-accumulator-bloat-sibling-p099.*.md
|
|
43
|
-
# P099: docs/problems/099-briefing-md-grows-unbounded-via-run-retro-appends-violating-progressive-disclosure.*.md
|
|
44
|
-
# ADR-040 — Session-start briefing surface (Tier 3 budget; line 92's
|
|
45
|
-
# reusable-pattern note explicitly names "problems index" as a
|
|
46
|
-
# candidate surface for this triplet)
|
|
47
|
-
# ADR-038 — Progressive disclosure (per-row terse budget)
|
|
48
|
-
# ADR-013 Rule 6 — non-interactive fail-safe (advisory-only / exit 0)
|
|
49
|
-
# ADR-005 — Plugin testing strategy (script-level bats governance)
|
|
50
|
-
|
|
51
|
-
setup() {
|
|
52
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
53
|
-
SCRIPT="$SCRIPTS_DIR/check-problems-readme-budget.sh"
|
|
54
|
-
FIXTURE_DIR="$(mktemp -d)"
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
teardown() {
|
|
58
|
-
rm -rf "$FIXTURE_DIR"
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
# Helper: write a problems README fixture with the given line-3 byte size.
|
|
62
|
-
# Lines 1, 2 are short header; line 3 is the synthetic "Last reviewed"
|
|
63
|
-
# blob padded to target_bytes; lines 4+ contain a short stub so the
|
|
64
|
-
# multi-line shape mirrors the production README.
|
|
65
|
-
write_problems_readme() {
|
|
66
|
-
local path="$1"
|
|
67
|
-
local target_bytes="$2"
|
|
68
|
-
: > "$path"
|
|
69
|
-
printf '# Problem Backlog\n\n' >> "$path"
|
|
70
|
-
if [ "$target_bytes" -gt 0 ]; then
|
|
71
|
-
# Build a single line of exactly target_bytes bytes (no trailing
|
|
72
|
-
# newline before the byte budget completes). The newline at the
|
|
73
|
-
# end is part of the file structure but not counted in line 3's
|
|
74
|
-
# byte size — `awk 'NR==3' | wc -c` would include it; the script
|
|
75
|
-
# under test must strip it to match the threshold semantics.
|
|
76
|
-
local prefix='> Last reviewed: '
|
|
77
|
-
local prefix_size=${#prefix}
|
|
78
|
-
local body_target=$(( target_bytes - prefix_size ))
|
|
79
|
-
if [ "$body_target" -gt 0 ]; then
|
|
80
|
-
printf '%s' "$prefix" >> "$path"
|
|
81
|
-
# Append body_target dots — a single contiguous line.
|
|
82
|
-
printf '%.0s.' $(seq 1 "$body_target") >> "$path"
|
|
83
|
-
else
|
|
84
|
-
# target smaller than prefix — emit only the requested bytes
|
|
85
|
-
printf '%.0s.' $(seq 1 "$target_bytes") >> "$path"
|
|
86
|
-
fi
|
|
87
|
-
printf '\n' >> "$path"
|
|
88
|
-
else
|
|
89
|
-
printf '\n' >> "$path"
|
|
90
|
-
fi
|
|
91
|
-
printf '\n## WSJF Rankings\n\n(stub)\n' >> "$path"
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
95
|
-
|
|
96
|
-
@test "check-problems-readme-budget: script exists" {
|
|
97
|
-
[ -f "$SCRIPT" ]
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
@test "check-problems-readme-budget: script is executable" {
|
|
101
|
-
[ -x "$SCRIPT" ]
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# ── Default-threshold behaviour (5120 bytes per ADR-040 Tier 3 envelope) ────
|
|
105
|
-
|
|
106
|
-
@test "check-problems-readme-budget: line 3 well under threshold produces no output and exits 0" {
|
|
107
|
-
write_problems_readme "$FIXTURE_DIR/README.md" 1024
|
|
108
|
-
run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
109
|
-
[ "$status" -eq 0 ]
|
|
110
|
-
[ -z "$output" ]
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
@test "check-problems-readme-budget: line 3 at exactly the default threshold emits OVER (>= boundary)" {
|
|
114
|
-
write_problems_readme "$FIXTURE_DIR/README.md" 5120
|
|
115
|
-
run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
116
|
-
[ "$status" -eq 0 ]
|
|
117
|
-
echo "$output" | grep -E "^OVER .*README.md line=3 bytes=5120 threshold=5120$"
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
@test "check-problems-readme-budget: line 3 well over threshold emits OVER with bytes + threshold" {
|
|
121
|
-
write_problems_readme "$FIXTURE_DIR/README.md" 12000
|
|
122
|
-
run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
123
|
-
[ "$status" -eq 0 ]
|
|
124
|
-
echo "$output" | grep -E "^OVER .*README.md line=3 bytes=12000 threshold=5120$"
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
@test "check-problems-readme-budget: short line 3 (single fragment ~600 bytes) produces no output" {
|
|
128
|
-
write_problems_readme "$FIXTURE_DIR/README.md" 600
|
|
129
|
-
run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
130
|
-
[ "$status" -eq 0 ]
|
|
131
|
-
[ -z "$output" ]
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
# ── Configurable threshold via env var ──────────────────────────────────────
|
|
135
|
-
|
|
136
|
-
@test "check-problems-readme-budget: PROBLEMS_README_LINE3_MAX_BYTES env var overrides default" {
|
|
137
|
-
write_problems_readme "$FIXTURE_DIR/README.md" 3000
|
|
138
|
-
# Default 5120: under threshold, no output. With env var set to 2000:
|
|
139
|
-
# over threshold, expect OVER line.
|
|
140
|
-
PROBLEMS_README_LINE3_MAX_BYTES=2000 run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
141
|
-
[ "$status" -eq 0 ]
|
|
142
|
-
echo "$output" | grep -E "^OVER .*README.md line=3 bytes=3000 threshold=2000$"
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
@test "check-problems-readme-budget: env var threshold of 0 emits OVER for non-empty line 3 (sanity)" {
|
|
146
|
-
write_problems_readme "$FIXTURE_DIR/README.md" 100
|
|
147
|
-
PROBLEMS_README_LINE3_MAX_BYTES=0 run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
148
|
-
[ "$status" -eq 0 ]
|
|
149
|
-
echo "$output" | grep -E "^OVER .*README.md line=3 bytes=100 threshold=0$"
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
# ── Argument and error handling ─────────────────────────────────────────────
|
|
153
|
-
|
|
154
|
-
@test "check-problems-readme-budget: defaults to docs/problems/README.md when no arg provided" {
|
|
155
|
-
cd "$FIXTURE_DIR"
|
|
156
|
-
mkdir -p docs/problems
|
|
157
|
-
write_problems_readme docs/problems/README.md 8000
|
|
158
|
-
run "$SCRIPT"
|
|
159
|
-
[ "$status" -eq 0 ]
|
|
160
|
-
echo "$output" | grep -E "^OVER docs/problems/README.md line=3 bytes=8000 threshold=5120$"
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
@test "check-problems-readme-budget: missing README path exits 2 with parse error on stderr" {
|
|
164
|
-
run "$SCRIPT" "$FIXTURE_DIR/does-not-exist/README.md"
|
|
165
|
-
[ "$status" -eq 2 ]
|
|
166
|
-
echo "$output" | grep -iE "not found|missing|does not exist"
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
@test "check-problems-readme-budget: file with no line 3 (only 2 lines) exits 0 with no output" {
|
|
170
|
-
printf '# Problem Backlog\n\n' > "$FIXTURE_DIR/README.md"
|
|
171
|
-
run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
172
|
-
[ "$status" -eq 0 ]
|
|
173
|
-
[ -z "$output" ]
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
@test "check-problems-readme-budget: file with empty line 3 exits 0 with no output" {
|
|
177
|
-
printf '# Problem Backlog\n\n\n## WSJF Rankings\n\n(stub)\n' > "$FIXTURE_DIR/README.md"
|
|
178
|
-
run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
179
|
-
[ "$status" -eq 0 ]
|
|
180
|
-
[ -z "$output" ]
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
# ── Read-only contract ──────────────────────────────────────────────────────
|
|
184
|
-
|
|
185
|
-
@test "check-problems-readme-budget: script does not mutate the README under audit" {
|
|
186
|
-
write_problems_readme "$FIXTURE_DIR/README.md" 12000
|
|
187
|
-
pre_hash=$(shasum -a 256 "$FIXTURE_DIR/README.md" | awk '{print $1}')
|
|
188
|
-
run "$SCRIPT" "$FIXTURE_DIR/README.md"
|
|
189
|
-
[ "$status" -eq 0 ]
|
|
190
|
-
post_hash=$(shasum -a 256 "$FIXTURE_DIR/README.md" | awk '{print $1}')
|
|
191
|
-
[ "$pre_hash" = "$post_hash" ]
|
|
192
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Behavioural test for check-rfc-has-stories.sh (ADR-089 — every RFC has >=1 story).
|
|
3
|
-
# The predicate exits non-zero when an RFC's `stories:` frontmatter is empty or
|
|
4
|
-
# missing (the empty-stories fallback ADR-089 removes); exit 0 when >=1 story is
|
|
5
|
-
# listed. This is the load-bearing detection half of the proposed->accepted gate.
|
|
6
|
-
#
|
|
7
|
-
# @adr ADR-089 (every RFC has at least one story)
|
|
8
|
-
# @problem P404 (implement ADR-089 + ADR-090)
|
|
9
|
-
|
|
10
|
-
setup() {
|
|
11
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
12
|
-
SCRIPT="${REPO_ROOT}/packages/itil/scripts/check-rfc-has-stories.sh"
|
|
13
|
-
TMPD="$(mktemp -d)"
|
|
14
|
-
}
|
|
15
|
-
teardown() { rm -rf "$TMPD"; }
|
|
16
|
-
|
|
17
|
-
@test "check-rfc-has-stories: empty stories: [] is REJECTED (exit non-zero + directive)" {
|
|
18
|
-
cat > "$TMPD/RFC-901-empty.proposed.md" <<'EOF'
|
|
19
|
-
---
|
|
20
|
-
status: proposed
|
|
21
|
-
problems: [P170]
|
|
22
|
-
stories: []
|
|
23
|
-
---
|
|
24
|
-
# RFC-901: empty
|
|
25
|
-
EOF
|
|
26
|
-
run bash "$SCRIPT" "$TMPD/RFC-901-empty.proposed.md"
|
|
27
|
-
[ "$status" -ne 0 ]
|
|
28
|
-
[[ "$output" == *"stories"* ]]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@test "check-rfc-has-stories: missing stories: field is REJECTED" {
|
|
32
|
-
cat > "$TMPD/RFC-902-none.proposed.md" <<'EOF'
|
|
33
|
-
---
|
|
34
|
-
status: proposed
|
|
35
|
-
problems: [P170]
|
|
36
|
-
---
|
|
37
|
-
# RFC-902: no stories field
|
|
38
|
-
EOF
|
|
39
|
-
run bash "$SCRIPT" "$TMPD/RFC-902-none.proposed.md"
|
|
40
|
-
[ "$status" -ne 0 ]
|
|
41
|
-
[[ "$output" == *"stories"* ]]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@test "check-rfc-has-stories: inline >=1 story is ACCEPTED (exit 0)" {
|
|
45
|
-
cat > "$TMPD/RFC-903-ok.proposed.md" <<'EOF'
|
|
46
|
-
---
|
|
47
|
-
status: proposed
|
|
48
|
-
problems: [P170]
|
|
49
|
-
stories: [STORY-020, STORY-021]
|
|
50
|
-
---
|
|
51
|
-
# RFC-903: has stories
|
|
52
|
-
EOF
|
|
53
|
-
run bash "$SCRIPT" "$TMPD/RFC-903-ok.proposed.md"
|
|
54
|
-
[ "$status" -eq 0 ]
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@test "check-rfc-has-stories: block-list >=1 story is ACCEPTED (exit 0)" {
|
|
58
|
-
cat > "$TMPD/RFC-904-block.proposed.md" <<'EOF'
|
|
59
|
-
---
|
|
60
|
-
status: proposed
|
|
61
|
-
problems: [P170]
|
|
62
|
-
stories:
|
|
63
|
-
- STORY-020
|
|
64
|
-
---
|
|
65
|
-
# RFC-904: block-list stories
|
|
66
|
-
EOF
|
|
67
|
-
run bash "$SCRIPT" "$TMPD/RFC-904-block.proposed.md"
|
|
68
|
-
[ "$status" -eq 0 ]
|
|
69
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P310 — RFCs carry independent decisions invisible to the ADR-066
|
|
4
|
-
# human-oversight net. ADR-070 closes the blind spot; this lint enforces it.
|
|
5
|
-
# @adr ADR-070 (RFCs hold no independent decisions — the invariant under test)
|
|
6
|
-
# @adr ADR-052 (behavioural-tests-default — this is an artefact-state behavioural
|
|
7
|
-
# assertion: it RUNS the checker against fixture RFC corpora + the real corpus
|
|
8
|
-
# and asserts the verdict (exit code + output). It does NOT structurally grep
|
|
9
|
-
# the checker's own source, the SKILL.md, or any agent prose — that would be
|
|
10
|
-
# the P081 structural-test-disguised-as-behavioural anti-pattern.)
|
|
11
|
-
# @adr ADR-071 (every fix via RFC — composes; the lint guards the RFC corpus)
|
|
12
|
-
#
|
|
13
|
-
# Contract under test (ADR-070 § Confirmation): no RFC body in docs/rfcs/
|
|
14
|
-
# contains a "Considered Options / Alternatives Rejected" HEADING block
|
|
15
|
-
# without a matching `adrs:` frontmatter reference. The detector targets a
|
|
16
|
-
# markdown heading, never a prose mention of the phrase.
|
|
17
|
-
|
|
18
|
-
setup() {
|
|
19
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
20
|
-
SCRIPT="$REPO_ROOT/packages/itil/scripts/check-rfc-rejected-alternatives.sh"
|
|
21
|
-
FIXTURE_DIR="$(mktemp -d)"
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
teardown() {
|
|
25
|
-
rm -rf "$FIXTURE_DIR"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
# ── Fixture helper: write an RFC file with given adrs-line + body ────────────
|
|
29
|
-
write_rfc() {
|
|
30
|
-
local name="$1" adrs_line="$2" body="$3"
|
|
31
|
-
cat > "$FIXTURE_DIR/$name" <<EOF
|
|
32
|
-
---
|
|
33
|
-
status: accepted
|
|
34
|
-
rfc-id: ${name%.md}
|
|
35
|
-
problems: [P999]
|
|
36
|
-
$adrs_line
|
|
37
|
-
stories: []
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
# ${name%.md}: fixture
|
|
41
|
-
|
|
42
|
-
## Summary
|
|
43
|
-
|
|
44
|
-
A fixture RFC.
|
|
45
|
-
|
|
46
|
-
$body
|
|
47
|
-
EOF
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
@test "violation: rejected-alternatives heading block WITH empty adrs: -> exit 1 + VIOLATION" {
|
|
51
|
-
write_rfc "RFC-901-bad.md" "adrs: []" $'## Considered Options / Alternatives Rejected\n\n- F1 alternative rejected: foo.'
|
|
52
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
53
|
-
[ "$status" -eq 1 ]
|
|
54
|
-
[[ "$output" == *"VIOLATION"* ]]
|
|
55
|
-
[[ "$output" == *"RFC-901-bad.md"* ]]
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
@test "allowed: rejected-alternatives heading block WITH a matching adrs: reference -> exit 0 (clean)" {
|
|
59
|
-
write_rfc "RFC-902-homed.md" "adrs: [ADR-072, ADR-073]" $'## Considered Options / Alternatives Rejected\n\n- The contested choice is recorded in ADR-072; this block references it.'
|
|
60
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
61
|
-
[ "$status" -eq 0 ]
|
|
62
|
-
[[ "$output" == *"clean"* ]]
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@test "clean: no rejected-alternatives block, empty adrs: -> exit 0" {
|
|
66
|
-
write_rfc "RFC-903-scope.md" "adrs: []" $'## Scope\n\nPure scope + decomposition + traces. No decisions here.'
|
|
67
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
68
|
-
[ "$status" -eq 0 ]
|
|
69
|
-
[[ "$output" == *"clean"* ]]
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
@test "prose mention (not a heading) of the phrase does NOT trigger -> exit 0" {
|
|
73
|
-
# Guards the RFC-005 retrofit-banner false positive: a blockquote/prose line
|
|
74
|
-
# mentioning the struck section must not be flagged.
|
|
75
|
-
write_rfc "RFC-904-retrofit.md" "adrs: []" $'> Retrofitted: this RFC originally carried a "Considered Options / Alternatives Rejected" section, now struck per ADR-070.'
|
|
76
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
77
|
-
[ "$status" -eq 0 ]
|
|
78
|
-
[[ "$output" == *"clean"* ]]
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
@test "variant heading 'Alternatives Rejected' WITH empty adrs: -> exit 1" {
|
|
82
|
-
write_rfc "RFC-905-variant.md" "adrs: []" $'### Alternatives Rejected\n\n- rejected: bar.'
|
|
83
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
84
|
-
[ "$status" -eq 1 ]
|
|
85
|
-
[[ "$output" == *"RFC-905-variant.md"* ]]
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
@test "mixed corpus: one violation among clean RFCs -> exit 1, names only the offender" {
|
|
89
|
-
write_rfc "RFC-906-ok.md" "adrs: [ADR-001]" $'## Considered Options\n\n- references ADR-001.'
|
|
90
|
-
write_rfc "RFC-907-bad.md" "adrs: []" $'## Considered Options\n\n- no adr.'
|
|
91
|
-
write_rfc "RFC-908-scope.md" "adrs: []" $'## Scope\n\nclean.'
|
|
92
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
93
|
-
[ "$status" -eq 1 ]
|
|
94
|
-
[[ "$output" == *"RFC-907-bad.md"* ]]
|
|
95
|
-
[[ "$output" != *"RFC-906-ok.md"* ]]
|
|
96
|
-
[[ "$output" != *"RFC-908-scope.md"* ]]
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
@test "non-existent directory -> exit 2 (usage error)" {
|
|
100
|
-
run bash "$SCRIPT" "$FIXTURE_DIR/does-not-exist"
|
|
101
|
-
[ "$status" -eq 2 ]
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
@test "dogfood: the real docs/rfcs/ corpus is clean -> exit 0" {
|
|
105
|
-
run bash "$SCRIPT" "$REPO_ROOT/docs/rfcs"
|
|
106
|
-
[ "$status" -eq 0 ]
|
|
107
|
-
[[ "$output" == *"clean"* ]]
|
|
108
|
-
}
|