@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,178 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# P170 / Phase 4 P4.1 — behavioural fixture for the
|
|
4
|
-
# update-jtbd-references-section.sh "Related problems" extension.
|
|
5
|
-
# Adds a fourth lookup-table row (alongside RFCs / Story Maps /
|
|
6
|
-
# Stories) so JTBD files auto-maintain a `## Related problems`
|
|
7
|
-
# reverse-trace section sourced from problem-ticket frontmatter
|
|
8
|
-
# `jtbd:` arrays. Mirrors the parallel-existence one-way reverse-
|
|
9
|
-
# trace shape from ADR-060 § Phase 3 + Phase 4 in-scope amendment
|
|
10
|
-
# (2026-05-13) P4.1.
|
|
11
|
-
#
|
|
12
|
-
# Per ADR-060 architect finding A4 + JTBD finding F5: lookup-table
|
|
13
|
-
# row addition, NOT a new helper. The body MUST remain
|
|
14
|
-
# per-section-name-branchless (assertion in
|
|
15
|
-
# update-references-section-sibling-helpers.bats).
|
|
16
|
-
|
|
17
|
-
setup() {
|
|
18
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
19
|
-
SCRIPT="$REPO_ROOT/packages/itil/scripts/update-jtbd-references-section.sh"
|
|
20
|
-
|
|
21
|
-
WORKSPACE="$(mktemp -d)"
|
|
22
|
-
cd "$WORKSPACE"
|
|
23
|
-
mkdir -p docs/problems/open docs/problems/known-error docs/jtbd/solo-developer
|
|
24
|
-
|
|
25
|
-
cat > docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md <<'EOF'
|
|
26
|
-
---
|
|
27
|
-
status: proposed
|
|
28
|
-
job-id: sample-job
|
|
29
|
-
persona: solo-developer
|
|
30
|
-
date-created: 2026-05-13
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
# JTBD-999: Sample Job
|
|
34
|
-
|
|
35
|
-
## Job Statement
|
|
36
|
-
|
|
37
|
-
Sample.
|
|
38
|
-
|
|
39
|
-
## Desired Outcomes
|
|
40
|
-
|
|
41
|
-
- Outcome A.
|
|
42
|
-
EOF
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
teardown() {
|
|
46
|
-
if [ -n "${WORKSPACE:-}" ] && [ -d "$WORKSPACE" ]; then
|
|
47
|
-
rm -rf "$WORKSPACE"
|
|
48
|
-
fi
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@test "Related problems: extracts user-business problem citing the JTBD" {
|
|
52
|
-
cat > docs/problems/open/501-business-problem.md <<'EOF'
|
|
53
|
-
---
|
|
54
|
-
type: user-business
|
|
55
|
-
jtbd: [JTBD-999]
|
|
56
|
-
persona: solo-developer
|
|
57
|
-
---
|
|
58
|
-
# Problem 501: Business problem citing JTBD-999
|
|
59
|
-
|
|
60
|
-
**Status**: Open
|
|
61
|
-
|
|
62
|
-
## Description
|
|
63
|
-
|
|
64
|
-
Business problem.
|
|
65
|
-
EOF
|
|
66
|
-
|
|
67
|
-
run bash "$SCRIPT" docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md "Related problems"
|
|
68
|
-
[ "$status" -eq 0 ]
|
|
69
|
-
grep -q '^## Related problems' docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md
|
|
70
|
-
grep -q '| P501 |' docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
@test "Related problems: ignores problems that don't cite the JTBD" {
|
|
74
|
-
cat > docs/problems/open/502-unrelated.md <<'EOF'
|
|
75
|
-
---
|
|
76
|
-
type: technical
|
|
77
|
-
---
|
|
78
|
-
# Problem 502: Unrelated technical problem
|
|
79
|
-
|
|
80
|
-
**Status**: Open
|
|
81
|
-
|
|
82
|
-
## Description
|
|
83
|
-
|
|
84
|
-
Unrelated.
|
|
85
|
-
EOF
|
|
86
|
-
|
|
87
|
-
run bash "$SCRIPT" docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md "Related problems"
|
|
88
|
-
[ "$status" -eq 0 ]
|
|
89
|
-
! grep -q '^## Related problems' docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@test "Related problems: lazy-empty when no problem cites the JTBD" {
|
|
93
|
-
cat > docs/problems/open/503-something-else.md <<'EOF'
|
|
94
|
-
---
|
|
95
|
-
type: user-business
|
|
96
|
-
jtbd: [JTBD-001]
|
|
97
|
-
---
|
|
98
|
-
# Problem 503: Cites a different JTBD
|
|
99
|
-
|
|
100
|
-
**Status**: Open
|
|
101
|
-
EOF
|
|
102
|
-
|
|
103
|
-
run bash "$SCRIPT" docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md "Related problems"
|
|
104
|
-
[ "$status" -eq 0 ]
|
|
105
|
-
! grep -q '^## Related problems' docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@test "Related problems: searches per-state subdirs (RFC-002 layout)" {
|
|
109
|
-
cat > docs/problems/known-error/504-business-known-error.md <<'EOF'
|
|
110
|
-
---
|
|
111
|
-
type: user-business
|
|
112
|
-
jtbd: [JTBD-999]
|
|
113
|
-
persona: solo-developer
|
|
114
|
-
---
|
|
115
|
-
# Problem 504: Known-error business problem
|
|
116
|
-
|
|
117
|
-
**Status**: Known Error
|
|
118
|
-
EOF
|
|
119
|
-
|
|
120
|
-
run bash "$SCRIPT" docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md "Related problems"
|
|
121
|
-
[ "$status" -eq 0 ]
|
|
122
|
-
grep -q '| P504 |' docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
@test "Related problems: idempotent across re-runs" {
|
|
126
|
-
cat > docs/problems/open/505-idempotent.md <<'EOF'
|
|
127
|
-
---
|
|
128
|
-
type: user-business
|
|
129
|
-
jtbd: [JTBD-999]
|
|
130
|
-
persona: solo-developer
|
|
131
|
-
---
|
|
132
|
-
# Problem 505: Idempotent test
|
|
133
|
-
|
|
134
|
-
**Status**: Open
|
|
135
|
-
EOF
|
|
136
|
-
|
|
137
|
-
run bash "$SCRIPT" docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md "Related problems"
|
|
138
|
-
[ "$status" -eq 0 ]
|
|
139
|
-
before_hash=$(md5 -q docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md 2>/dev/null || md5sum docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md | awk '{print $1}')
|
|
140
|
-
|
|
141
|
-
run bash "$SCRIPT" docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md "Related problems"
|
|
142
|
-
[ "$status" -eq 0 ]
|
|
143
|
-
after_hash=$(md5 -q docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md 2>/dev/null || md5sum docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md | awk '{print $1}')
|
|
144
|
-
|
|
145
|
-
[ "$before_hash" = "$after_hash" ]
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
@test "Related problems: unknown section-name still fails" {
|
|
149
|
-
run bash "$SCRIPT" docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md "Bogus Section"
|
|
150
|
-
[ "$status" -ne 0 ]
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
@test "Related problems: helper still no per-section-name branch (P4.1 lookup-table-row addition only)" {
|
|
154
|
-
! grep -E 'case[[:space:]]+"\$\{?section[_-]?name\}?"|if[[:space:]]+\[[[:space:]]+"\$\{?section[_-]?name\}?"[[:space:]]+=' "$SCRIPT"
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
@test "Related problems: extracts problem using body-field **JTBD**: convention (capture-problem schema P3.1)" {
|
|
158
|
-
# P3.1 capture-problem skeleton writes body-field **JTBD**: (matches
|
|
159
|
-
# existing **Status**: / **Type**: schema); helper must accept both
|
|
160
|
-
# frontmatter `jtbd:` arrays AND body-field **JTBD**: lines.
|
|
161
|
-
cat > docs/problems/open/506-body-field-business-problem.md <<'EOF'
|
|
162
|
-
# Problem 506: Body-field business problem
|
|
163
|
-
|
|
164
|
-
**Status**: Open
|
|
165
|
-
**Reported**: 2026-05-13
|
|
166
|
-
**Type**: user-business
|
|
167
|
-
**JTBD**: JTBD-999
|
|
168
|
-
**Persona**: solo-developer
|
|
169
|
-
|
|
170
|
-
## Description
|
|
171
|
-
|
|
172
|
-
Problem captured via Phase 4 P3.1 capture-problem with body-field JTBD trace.
|
|
173
|
-
EOF
|
|
174
|
-
|
|
175
|
-
run bash "$SCRIPT" docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md "Related problems"
|
|
176
|
-
[ "$status" -eq 0 ]
|
|
177
|
-
grep -q '| P506 |' docs/jtbd/solo-developer/JTBD-999-sample-job.proposed.md
|
|
178
|
-
}
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# P170 / Phase 2 Slice 2 — behavioural fixture for the generalised
|
|
4
|
-
# update-problem-references-section.sh helper. Covers polymorphic
|
|
5
|
-
# extraction (HTML data attributes for Story Maps; markdown frontmatter
|
|
6
|
-
# for Stories + RFCs) feeding a uniform markdown-row render into the
|
|
7
|
-
# target problem ticket's ## <section-name> section. Per ADR-060
|
|
8
|
-
# § Phase 2 encoding amendment 2026-05-12 architect finding 4: helper
|
|
9
|
-
# body MUST NOT carry per-section-name branching; section-name is a
|
|
10
|
-
# positional argument; per-extension dispatch is the only branch.
|
|
11
|
-
|
|
12
|
-
setup() {
|
|
13
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
14
|
-
SCRIPT="$REPO_ROOT/packages/itil/scripts/update-problem-references-section.sh"
|
|
15
|
-
|
|
16
|
-
# Build an isolated workspace mirroring the docs layout.
|
|
17
|
-
WORKSPACE="$(mktemp -d)"
|
|
18
|
-
cd "$WORKSPACE"
|
|
19
|
-
mkdir -p docs/problems/open docs/rfcs docs/story-maps/in-progress docs/stories/accepted
|
|
20
|
-
|
|
21
|
-
# Sample problem ticket
|
|
22
|
-
cat > docs/problems/open/200-sample-problem.md <<'EOF'
|
|
23
|
-
# Problem 200: Sample problem ticket
|
|
24
|
-
|
|
25
|
-
**Status**: Open
|
|
26
|
-
**Reported**: 2026-05-12
|
|
27
|
-
|
|
28
|
-
## Description
|
|
29
|
-
|
|
30
|
-
Sample description.
|
|
31
|
-
|
|
32
|
-
## Related
|
|
33
|
-
|
|
34
|
-
Sibling refs.
|
|
35
|
-
EOF
|
|
36
|
-
|
|
37
|
-
# Sample RFC tracing problem 200
|
|
38
|
-
cat > docs/rfcs/RFC-100-sample-rfc.in-progress.md <<'EOF'
|
|
39
|
-
---
|
|
40
|
-
status: in-progress
|
|
41
|
-
rfc-id: sample-rfc
|
|
42
|
-
problems: [P200]
|
|
43
|
-
adrs: []
|
|
44
|
-
jtbd: []
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
# RFC-100: Sample RFC
|
|
48
|
-
EOF
|
|
49
|
-
|
|
50
|
-
# Sample HTML story map tracing problem 200
|
|
51
|
-
cat > docs/story-maps/in-progress/STORY-MAP-050-sample-map.html <<'EOF'
|
|
52
|
-
<!DOCTYPE html>
|
|
53
|
-
<html lang="en">
|
|
54
|
-
<head>
|
|
55
|
-
<meta charset="UTF-8">
|
|
56
|
-
<title>STORY-MAP-050: Sample map</title>
|
|
57
|
-
<meta name="story-map-id" content="STORY-MAP-050">
|
|
58
|
-
<meta name="status" content="in-progress">
|
|
59
|
-
<meta name="problems" content="P200">
|
|
60
|
-
<meta name="rfcs" content="RFC-100">
|
|
61
|
-
<meta name="jtbd" content="JTBD-008">
|
|
62
|
-
</head>
|
|
63
|
-
<body>
|
|
64
|
-
<h1>STORY-MAP-050: Sample map</h1>
|
|
65
|
-
</body>
|
|
66
|
-
</html>
|
|
67
|
-
EOF
|
|
68
|
-
|
|
69
|
-
# Sample markdown story tracing problem 200
|
|
70
|
-
cat > docs/stories/accepted/STORY-300-sample-story.md <<'EOF'
|
|
71
|
-
---
|
|
72
|
-
status: accepted
|
|
73
|
-
story-id: sample-story
|
|
74
|
-
problems: [P200]
|
|
75
|
-
jtbd: [JTBD-008]
|
|
76
|
-
rfcs: [RFC-100]
|
|
77
|
-
story-maps: [STORY-MAP-050]
|
|
78
|
-
estimated-effort: M
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
# STORY-300: Sample story
|
|
82
|
-
EOF
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
teardown() {
|
|
86
|
-
rm -rf "$WORKSPACE"
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
@test "helper: script exists and is executable" {
|
|
90
|
-
[ -x "$SCRIPT" ]
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
@test "helper: requires problem-file argument; bare invocation halts" {
|
|
94
|
-
run bash "$SCRIPT"
|
|
95
|
-
[ "$status" -ne 0 ]
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@test "helper: requires section-name argument" {
|
|
99
|
-
run bash "$SCRIPT" docs/problems/open/200-sample-problem.md
|
|
100
|
-
[ "$status" -ne 0 ]
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
@test "helper: refresh ## RFCs section from docs/rfcs/*.md frontmatter (markdown-extraction path)" {
|
|
104
|
-
cd "$WORKSPACE"
|
|
105
|
-
run bash "$SCRIPT" docs/problems/open/200-sample-problem.md RFCs
|
|
106
|
-
[ "$status" -eq 0 ]
|
|
107
|
-
grep -q '^## RFCs$' docs/problems/open/200-sample-problem.md
|
|
108
|
-
grep -q 'RFC-100' docs/problems/open/200-sample-problem.md
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
@test "helper: refresh ## Story Maps section from docs/story-maps/*.html data attributes (HTML-extraction path)" {
|
|
112
|
-
cd "$WORKSPACE"
|
|
113
|
-
run bash "$SCRIPT" docs/problems/open/200-sample-problem.md "Story Maps"
|
|
114
|
-
[ "$status" -eq 0 ]
|
|
115
|
-
grep -q '^## Story Maps$' docs/problems/open/200-sample-problem.md
|
|
116
|
-
grep -q 'STORY-MAP-050' docs/problems/open/200-sample-problem.md
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@test "helper: refresh ## Stories section from docs/stories/*.md frontmatter (markdown-extraction path)" {
|
|
120
|
-
cd "$WORKSPACE"
|
|
121
|
-
run bash "$SCRIPT" docs/problems/open/200-sample-problem.md Stories
|
|
122
|
-
[ "$status" -eq 0 ]
|
|
123
|
-
grep -q '^## Stories$' docs/problems/open/200-sample-problem.md
|
|
124
|
-
grep -q 'STORY-300' docs/problems/open/200-sample-problem.md
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
@test "helper: lazy-empty — section removed entirely when no traces match" {
|
|
128
|
-
cd "$WORKSPACE"
|
|
129
|
-
# Create a problem ticket nothing references
|
|
130
|
-
cat > docs/problems/open/201-unreferenced-problem.md <<'EOF'
|
|
131
|
-
# Problem 201: Unreferenced
|
|
132
|
-
|
|
133
|
-
**Status**: Open
|
|
134
|
-
|
|
135
|
-
## Related
|
|
136
|
-
|
|
137
|
-
Some related content.
|
|
138
|
-
|
|
139
|
-
## Story Maps
|
|
140
|
-
|
|
141
|
-
| ID | Title |
|
|
142
|
-
|----|-------|
|
|
143
|
-
| STORY-MAP-999 | stale entry |
|
|
144
|
-
EOF
|
|
145
|
-
run bash "$SCRIPT" docs/problems/open/201-unreferenced-problem.md "Story Maps"
|
|
146
|
-
[ "$status" -eq 0 ]
|
|
147
|
-
! grep -q '^## Story Maps$' docs/problems/open/201-unreferenced-problem.md
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
@test "helper: idempotent — running twice produces no change on second invocation" {
|
|
151
|
-
cd "$WORKSPACE"
|
|
152
|
-
bash "$SCRIPT" docs/problems/open/200-sample-problem.md RFCs
|
|
153
|
-
local first_hash
|
|
154
|
-
first_hash=$(md5 -q docs/problems/open/200-sample-problem.md 2>/dev/null || md5sum docs/problems/open/200-sample-problem.md | cut -d' ' -f1)
|
|
155
|
-
bash "$SCRIPT" docs/problems/open/200-sample-problem.md RFCs
|
|
156
|
-
local second_hash
|
|
157
|
-
second_hash=$(md5 -q docs/problems/open/200-sample-problem.md 2>/dev/null || md5sum docs/problems/open/200-sample-problem.md | cut -d' ' -f1)
|
|
158
|
-
[ "$first_hash" = "$second_hash" ]
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
@test "helper: HTML path uses literal data-attribute grep (NOT inline-style match)" {
|
|
162
|
-
# Architect finding 5 (Prohibition reinforcement): the helper MUST
|
|
163
|
-
# grep on `<meta name="problems" content="...">` literal, not on any
|
|
164
|
-
# `style=` attribute. Verify by injecting a fake inline-style on a
|
|
165
|
-
# data-bearing element and asserting the helper's extraction is
|
|
166
|
-
# unaffected (the prohibition is enforced separately by a doc-lint
|
|
167
|
-
# bats; this test asserts the helper's parsing is style-agnostic).
|
|
168
|
-
cd "$WORKSPACE"
|
|
169
|
-
# The fixture's HTML map already lacks any `style=""` — that's the
|
|
170
|
-
# canonical shape. The helper must extract the same set whether the
|
|
171
|
-
# map has style or not. Adding a benign body-level style to the
|
|
172
|
-
# fixture (NOT on a data-bearing element) and re-running the helper
|
|
173
|
-
# must yield the same Story Maps section.
|
|
174
|
-
bash "$SCRIPT" docs/problems/open/200-sample-problem.md "Story Maps"
|
|
175
|
-
local first_body
|
|
176
|
-
first_body=$(grep -A 5 '^## Story Maps$' docs/problems/open/200-sample-problem.md)
|
|
177
|
-
# Inject benign body-level style — NOT on a data-bearing element
|
|
178
|
-
sed -i.bak 's|<body>|<body style="font-family: sans-serif">|' docs/story-maps/in-progress/STORY-MAP-050-sample-map.html
|
|
179
|
-
rm -f docs/story-maps/in-progress/STORY-MAP-050-sample-map.html.bak
|
|
180
|
-
bash "$SCRIPT" docs/problems/open/200-sample-problem.md "Story Maps"
|
|
181
|
-
local second_body
|
|
182
|
-
second_body=$(grep -A 5 '^## Story Maps$' docs/problems/open/200-sample-problem.md)
|
|
183
|
-
[ "$first_body" = "$second_body" ]
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
@test "helper: multi-line section inserts before ## Fix Released under host awk (P392 BSD-awk getline fix)" {
|
|
187
|
-
# P392 — the insert-before-## Fix Released branch passed the multi-line
|
|
188
|
-
# new_section via `awk -v section=...`; BSD awk (macOS) rejects embedded
|
|
189
|
-
# newlines in a -v assignment and aborts (`awk: newline in string`),
|
|
190
|
-
# silently dropping the section refresh. This exercises that branch under
|
|
191
|
-
# the host awk: it must exit 0 AND place the rendered ## RFCs table
|
|
192
|
-
# immediately before ## Fix Released with the table rows intact.
|
|
193
|
-
cd "$WORKSPACE"
|
|
194
|
-
cat > docs/problems/open/202-released-problem.md <<'EOF'
|
|
195
|
-
# Problem 202: Released problem ticket
|
|
196
|
-
|
|
197
|
-
**Status**: Verifying
|
|
198
|
-
|
|
199
|
-
## Description
|
|
200
|
-
|
|
201
|
-
Sample description.
|
|
202
|
-
|
|
203
|
-
## Fix Released
|
|
204
|
-
|
|
205
|
-
Released in v1.2.3.
|
|
206
|
-
EOF
|
|
207
|
-
# RFC tracing problem 202 so a non-empty multi-line section is rendered
|
|
208
|
-
cat > docs/rfcs/RFC-100-sample-rfc.in-progress.md <<'EOF'
|
|
209
|
-
---
|
|
210
|
-
status: in-progress
|
|
211
|
-
rfc-id: sample-rfc
|
|
212
|
-
problems: [P202]
|
|
213
|
-
adrs: []
|
|
214
|
-
jtbd: []
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
# RFC-100: Sample RFC
|
|
218
|
-
EOF
|
|
219
|
-
run bash "$SCRIPT" docs/problems/open/202-released-problem.md RFCs
|
|
220
|
-
[ "$status" -eq 0 ]
|
|
221
|
-
grep -q '^## RFCs$' docs/problems/open/202-released-problem.md
|
|
222
|
-
grep -q 'RFC-100' docs/problems/open/202-released-problem.md
|
|
223
|
-
grep -q '^## Fix Released$' docs/problems/open/202-released-problem.md
|
|
224
|
-
# ## RFCs must precede ## Fix Released (inserted at the anchor, not at EOF)
|
|
225
|
-
local rfcs_line fix_line
|
|
226
|
-
rfcs_line=$(grep -n '^## RFCs$' docs/problems/open/202-released-problem.md | cut -d: -f1)
|
|
227
|
-
fix_line=$(grep -n '^## Fix Released$' docs/problems/open/202-released-problem.md | cut -d: -f1)
|
|
228
|
-
[ "$rfcs_line" -lt "$fix_line" ]
|
|
229
|
-
# The multi-line table row must survive intact
|
|
230
|
-
grep -q '| RFC-100 |' docs/problems/open/202-released-problem.md
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
@test "helper: body does NOT contain a per-section-name branch (architect finding 4)" {
|
|
234
|
-
# Structural test (tdd-review: structural-permitted —
|
|
235
|
-
# justification: P176 SKILL.md I-invariant harness gap is the
|
|
236
|
-
# canonical pattern for asserting no-branching contracts via
|
|
237
|
-
# source grep; behavioural enforcement awaits the master harness
|
|
238
|
-
# at P012). Asserts the helper body does NOT carry a literal
|
|
239
|
-
# `case "$section_name"` or `if [ "$section_name" = "..." ]`
|
|
240
|
-
# branch keyed on the section-name value.
|
|
241
|
-
! grep -E 'case[[:space:]]+"\$\{?section[_-]?name\}?"|if[[:space:]]+\[[[:space:]]+"\$\{?section[_-]?name\}?"[[:space:]]+=' "$SCRIPT"
|
|
242
|
-
}
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P170 — Slice 3 second half (B5.T8): the auto-maintained
|
|
4
|
-
# `## RFCs` section refresh contract on problem ticket bodies. Library
|
|
5
|
-
# helper called inline by /wr-itil:capture-rfc Step 6 and
|
|
6
|
-
# /wr-itil:manage-rfc Step 7+9 so the cross-tier reverse-trace stays
|
|
7
|
-
# current at every commit per ADR-014 single-commit grain.
|
|
8
|
-
#
|
|
9
|
-
# Behavioural per ADR-052: assert on file output state (idempotent
|
|
10
|
-
# table; lazy empty discipline; placement) — not on script source
|
|
11
|
-
# content (no structural greps per P081).
|
|
12
|
-
#
|
|
13
|
-
# Contract (per architect Q3 verdict):
|
|
14
|
-
# - Section position: between `## Related` and `## Fix Released`
|
|
15
|
-
# (or at EOF if neither sentinel present).
|
|
16
|
-
# - Table format: `| RFC | Status | Title |` with separator row.
|
|
17
|
-
# - Sort: RFC ID asc.
|
|
18
|
-
# - Lazy empty: zero traced RFCs → section absent (no header,
|
|
19
|
-
# no `_None._` prose).
|
|
20
|
-
# - Idempotent: re-run over current state is a no-op (cmp -s holds).
|
|
21
|
-
#
|
|
22
|
-
# @adr ADR-060 (Phase 1 item 10 + Confirmation criterion 3)
|
|
23
|
-
# @adr ADR-052 (behavioural bats default)
|
|
24
|
-
# @adr ADR-022 (`## Fix Released` is the trailing closure section)
|
|
25
|
-
# @jtbd JTBD-008 (Decompose a Fix Into Coordinated Changes — reverse
|
|
26
|
-
# trace surface)
|
|
27
|
-
# @jtbd JTBD-101 (atomic-fix-adopter friction guard — lazy empty)
|
|
28
|
-
|
|
29
|
-
setup() {
|
|
30
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
31
|
-
HELPER="$SCRIPTS_DIR/update-problem-rfcs-section.sh"
|
|
32
|
-
RFCS_DIR="$(mktemp -d)"
|
|
33
|
-
PROBLEMS_DIR="$(mktemp -d)"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
teardown() {
|
|
37
|
-
rm -rf "$RFCS_DIR" "$PROBLEMS_DIR"
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
write_rfc() {
|
|
41
|
-
local id="$1" slug="$2" status="$3"
|
|
42
|
-
local problems="${4:-[P168]}"
|
|
43
|
-
cat > "$RFCS_DIR/RFC-${id}-${slug}.${status}.md" <<EOF
|
|
44
|
-
---
|
|
45
|
-
status: ${status}
|
|
46
|
-
rfc-id: ${slug}
|
|
47
|
-
reported: 2026-05-05
|
|
48
|
-
decision-makers: [test]
|
|
49
|
-
problems: ${problems}
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
# RFC-${id}: ${slug}
|
|
53
|
-
|
|
54
|
-
stub
|
|
55
|
-
EOF
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
write_problem() {
|
|
59
|
-
local num="$1" slug="$2" trailing="${3:-}"
|
|
60
|
-
local file="$PROBLEMS_DIR/${num}-${slug}.open.md"
|
|
61
|
-
cat > "$file" <<EOF
|
|
62
|
-
# Problem ${num}: ${slug}
|
|
63
|
-
|
|
64
|
-
**Status**: Open
|
|
65
|
-
|
|
66
|
-
## Description
|
|
67
|
-
|
|
68
|
-
stub
|
|
69
|
-
|
|
70
|
-
## Related
|
|
71
|
-
|
|
72
|
-
stub
|
|
73
|
-
EOF
|
|
74
|
-
if [ -n "$trailing" ]; then
|
|
75
|
-
printf '\n%s\n' "$trailing" >> "$file"
|
|
76
|
-
fi
|
|
77
|
-
echo "$file"
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
81
|
-
|
|
82
|
-
@test "helper exists" {
|
|
83
|
-
[ -f "$HELPER" ]
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
@test "helper is executable" {
|
|
87
|
-
[ -x "$HELPER" ]
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# ── Lazy-empty discipline (JTBD-101 friction guard) ─────────────────────────
|
|
91
|
-
|
|
92
|
-
@test "no RFCs trace → section absent (lazy empty)" {
|
|
93
|
-
pf=$(write_problem "168" "p168")
|
|
94
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
95
|
-
! grep -q '^## RFCs' "$pf"
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@test "no RFCs trace and section exists → section removed" {
|
|
99
|
-
# A pre-existing stale section gets cleaned out when zero RFCs claim.
|
|
100
|
-
pf=$(write_problem "168" "p168" $'## RFCs\n\n| RFC | Status | Title |\n|-----|--------|-------|\n| RFC-001 | accepted | foo |')
|
|
101
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
102
|
-
! grep -q '^## RFCs' "$pf"
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
# ── Single-RFC trace ────────────────────────────────────────────────────────
|
|
106
|
-
|
|
107
|
-
@test "one RFC traces P → section appears with one row" {
|
|
108
|
-
write_rfc "001" "foo" "accepted"
|
|
109
|
-
pf=$(write_problem "168" "p168")
|
|
110
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
111
|
-
grep -q '^## RFCs' "$pf"
|
|
112
|
-
grep -q '| RFC-001 | accepted | foo |' "$pf"
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
@test "table includes header + separator + data row" {
|
|
116
|
-
write_rfc "001" "foo" "accepted"
|
|
117
|
-
pf=$(write_problem "168" "p168")
|
|
118
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
119
|
-
grep -q '| RFC | Status | Title |' "$pf"
|
|
120
|
-
grep -q '|-----|--------|-------|' "$pf"
|
|
121
|
-
grep -q '| RFC-001 | accepted | foo |' "$pf"
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
# ── Multi-RFC trace + sort order ─────────────────────────────────────────────
|
|
125
|
-
|
|
126
|
-
@test "multiple RFCs trace P → all rows present, sorted by RFC ID asc" {
|
|
127
|
-
write_rfc "002" "second" "proposed"
|
|
128
|
-
write_rfc "001" "first" "accepted"
|
|
129
|
-
pf=$(write_problem "168" "p168")
|
|
130
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
131
|
-
# Both rows present.
|
|
132
|
-
grep -q '| RFC-001 | accepted | first |' "$pf"
|
|
133
|
-
grep -q '| RFC-002 | proposed | second |' "$pf"
|
|
134
|
-
# RFC-001 appears before RFC-002.
|
|
135
|
-
rfc_001_line=$(grep -n '| RFC-001 |' "$pf" | head -1 | cut -d: -f1)
|
|
136
|
-
rfc_002_line=$(grep -n '| RFC-002 |' "$pf" | head -1 | cut -d: -f1)
|
|
137
|
-
[ "$rfc_001_line" -lt "$rfc_002_line" ]
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
# ── Idempotency ─────────────────────────────────────────────────────────────
|
|
141
|
-
|
|
142
|
-
@test "re-running with no claim change is a no-op (idempotent)" {
|
|
143
|
-
write_rfc "001" "foo" "accepted"
|
|
144
|
-
pf=$(write_problem "168" "p168")
|
|
145
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
146
|
-
hash1=$(shasum "$pf" | cut -d' ' -f1)
|
|
147
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
148
|
-
hash2=$(shasum "$pf" | cut -d' ' -f1)
|
|
149
|
-
[ "$hash1" = "$hash2" ]
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
# ── Status update on existing row ────────────────────────────────────────────
|
|
153
|
-
|
|
154
|
-
@test "RFC status changes (proposed → accepted) → table row reflects new status" {
|
|
155
|
-
write_rfc "001" "foo" "proposed"
|
|
156
|
-
pf=$(write_problem "168" "p168")
|
|
157
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
158
|
-
grep -q '| RFC-001 | proposed | foo |' "$pf"
|
|
159
|
-
# Now transition the RFC to accepted (simulate by renaming on disk).
|
|
160
|
-
mv "$RFCS_DIR/RFC-001-foo.proposed.md" "$RFCS_DIR/RFC-001-foo.accepted.md"
|
|
161
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
162
|
-
grep -q '| RFC-001 | accepted | foo |' "$pf"
|
|
163
|
-
# Old status should no longer be present for that RFC row.
|
|
164
|
-
! grep -q '| RFC-001 | proposed |' "$pf"
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
# ── Re-trace add/remove ─────────────────────────────────────────────────────
|
|
168
|
-
|
|
169
|
-
@test "RFC newly added trace → row appended" {
|
|
170
|
-
write_rfc "001" "foo" "accepted"
|
|
171
|
-
pf=$(write_problem "168" "p168")
|
|
172
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
173
|
-
grep -q '| RFC-001 |' "$pf"
|
|
174
|
-
|
|
175
|
-
# Add a second RFC traced to P168.
|
|
176
|
-
write_rfc "002" "bar" "proposed"
|
|
177
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
178
|
-
grep -q '| RFC-001 |' "$pf"
|
|
179
|
-
grep -q '| RFC-002 |' "$pf"
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
@test "RFC trace removed (frontmatter no longer claims P) → row drops" {
|
|
183
|
-
write_rfc "001" "foo" "accepted" "[P168]"
|
|
184
|
-
write_rfc "002" "bar" "proposed" "[P168]"
|
|
185
|
-
pf=$(write_problem "168" "p168")
|
|
186
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
187
|
-
grep -q '| RFC-001 |' "$pf"
|
|
188
|
-
grep -q '| RFC-002 |' "$pf"
|
|
189
|
-
|
|
190
|
-
# Re-trace RFC-002 to P169 only.
|
|
191
|
-
rm -f "$RFCS_DIR/RFC-002-bar.proposed.md"
|
|
192
|
-
write_rfc "002" "bar" "proposed" "[P169]"
|
|
193
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
194
|
-
grep -q '| RFC-001 |' "$pf"
|
|
195
|
-
! grep -q '| RFC-002 |' "$pf"
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
# ── Section placement ───────────────────────────────────────────────────────
|
|
199
|
-
|
|
200
|
-
@test "## RFCs section sits before ## Fix Released when present" {
|
|
201
|
-
write_rfc "001" "foo" "verifying"
|
|
202
|
-
pf=$(write_problem "168" "p168" $'## Fix Released\n\nReleased trailer prose.')
|
|
203
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
204
|
-
rfcs_line=$(grep -n '^## RFCs' "$pf" | head -1 | cut -d: -f1)
|
|
205
|
-
fix_released_line=$(grep -n '^## Fix Released' "$pf" | head -1 | cut -d: -f1)
|
|
206
|
-
[ "$rfcs_line" -lt "$fix_released_line" ]
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
@test "## RFCs section appears at EOF when no ## Fix Released section" {
|
|
210
|
-
write_rfc "001" "foo" "accepted"
|
|
211
|
-
pf=$(write_problem "168" "p168")
|
|
212
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
213
|
-
# ## RFCs is the last `## ` heading in the file.
|
|
214
|
-
last_section=$(grep -E '^## ' "$pf" | tail -1)
|
|
215
|
-
[[ "$last_section" == "## RFCs" ]]
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
# ── Multi-problem RFC composition ────────────────────────────────────────────
|
|
219
|
-
|
|
220
|
-
@test "RFC tracing two problems updates both ## RFCs sections" {
|
|
221
|
-
write_rfc "001" "foo" "accepted" "[P168, P169]"
|
|
222
|
-
pf168=$(write_problem "168" "p168")
|
|
223
|
-
pf169=$(write_problem "169" "p169")
|
|
224
|
-
bash "$HELPER" "$pf168" "$RFCS_DIR"
|
|
225
|
-
bash "$HELPER" "$pf169" "$RFCS_DIR"
|
|
226
|
-
grep -q '| RFC-001 |' "$pf168"
|
|
227
|
-
grep -q '| RFC-001 |' "$pf169"
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
# ── ## Related preservation ─────────────────────────────────────────────────
|
|
231
|
-
|
|
232
|
-
@test "existing ## Related section is preserved when ## RFCs is added" {
|
|
233
|
-
write_rfc "001" "foo" "accepted"
|
|
234
|
-
pf=$(write_problem "168" "p168")
|
|
235
|
-
bash "$HELPER" "$pf" "$RFCS_DIR"
|
|
236
|
-
grep -q '^## Related' "$pf"
|
|
237
|
-
grep -q '^## RFCs' "$pf"
|
|
238
|
-
related_line=$(grep -n '^## Related' "$pf" | head -1 | cut -d: -f1)
|
|
239
|
-
rfcs_line=$(grep -n '^## RFCs' "$pf" | head -1 | cut -d: -f1)
|
|
240
|
-
# ## Related comes before ## RFCs.
|
|
241
|
-
[ "$related_line" -lt "$rfcs_line" ]
|
|
242
|
-
}
|