@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,496 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P170 — docs/rfcs/README.md needs a sibling drift-detector to
|
|
4
|
-
# reconcile-readme.sh once `/wr-itil:capture-rfc` and `/wr-itil:manage-rfc`
|
|
5
|
-
# start writing RFC files. P170 Slice 3 task B5.T6 ships this script;
|
|
6
|
-
# B5.T7 ships the `wr-itil-reconcile-rfcs` $PATH shim per ADR-049.
|
|
7
|
-
#
|
|
8
|
-
# Contract: `reconcile-rfcs.sh [<rfcs-dir>]` is a diagnose-only mechanical
|
|
9
|
-
# drift detector. It reads `<rfcs-dir>/RFC-<NNN>-*.<status>.md` files
|
|
10
|
-
# (default `docs/rfcs`), parses the WSJF Rankings + Verification Queue
|
|
11
|
-
# + Closed tables in `<rfcs-dir>/README.md`, and reports each
|
|
12
|
-
# disagreement between README claim and filesystem ground truth.
|
|
13
|
-
#
|
|
14
|
-
# Exit codes:
|
|
15
|
-
# 0 = clean (README matches filesystem for every parsed row)
|
|
16
|
-
# 1 = drift detected (structured diff to stdout, one row per drift)
|
|
17
|
-
# 2 = parse error (README missing or malformed beyond recovery)
|
|
18
|
-
#
|
|
19
|
-
# Drift line format per ADR-038 progressive-disclosure budget (≤150 bytes/row):
|
|
20
|
-
# DRIFT RFC-<NNN> wsjf-rankings: claims=open actual=<status>
|
|
21
|
-
# MISSING RFC-<NNN> wsjf-rankings: actual=<status>
|
|
22
|
-
# STALE RFC-<NNN> verification-queue: actual=<status>
|
|
23
|
-
# MISMATCH RFC-<NNN> closed: actual=<status>
|
|
24
|
-
#
|
|
25
|
-
# Sibling to packages/itil/scripts/reconcile-readme.sh (P118) — same
|
|
26
|
-
# parse + diff structure applied at the RFC tier instead of the
|
|
27
|
-
# problems tier.
|
|
28
|
-
#
|
|
29
|
-
# @jtbd JTBD-008 (Decompose a Fix Into Coordinated Changes — RFC ranking
|
|
30
|
-
# integrity supports the capture-time decomposition surface)
|
|
31
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — orchestrators
|
|
32
|
-
# composing with RFC-level WSJF rankings need them to match disk truth)
|
|
33
|
-
#
|
|
34
|
-
# Cross-reference:
|
|
35
|
-
# P170: docs/problems/170-...open.md
|
|
36
|
-
# ADR-060 (Problem-RFC-Story framework — Phase 1 item 5)
|
|
37
|
-
# ADR-049 (Plugin script resolution via bin/ on PATH — paired bin shim)
|
|
38
|
-
# ADR-005 — Plugin testing strategy (script-level bats governance)
|
|
39
|
-
|
|
40
|
-
setup() {
|
|
41
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
42
|
-
SCRIPT="$SCRIPTS_DIR/reconcile-rfcs.sh"
|
|
43
|
-
FIXTURE_DIR="$(mktemp -d)"
|
|
44
|
-
PROBLEMS_DIR="$(mktemp -d)"
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
teardown() {
|
|
48
|
-
rm -rf "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# Helper: write a minimal valid RFC README to fixture dir.
|
|
52
|
-
write_minimal_readme() {
|
|
53
|
-
local body="$1"
|
|
54
|
-
cat > "$FIXTURE_DIR/README.md" <<EOF
|
|
55
|
-
# RFC Backlog
|
|
56
|
-
|
|
57
|
-
> Last reviewed: 2026-05-05
|
|
58
|
-
|
|
59
|
-
## Status
|
|
60
|
-
|
|
61
|
-
(intro)
|
|
62
|
-
|
|
63
|
-
## RFC Rankings
|
|
64
|
-
|
|
65
|
-
| WSJF | ID | Title | Severity | Status | Effort | Reported |
|
|
66
|
-
|------|-----|-------|----------|--------|--------|----------|
|
|
67
|
-
${body}
|
|
68
|
-
|
|
69
|
-
## Verification Queue
|
|
70
|
-
|
|
71
|
-
| ID | Title | Released | Verification check |
|
|
72
|
-
|----|-------|----------|--------------------|
|
|
73
|
-
|
|
74
|
-
## Closed
|
|
75
|
-
|
|
76
|
-
| ID | Title | Closed | Driving problems |
|
|
77
|
-
|----|-------|--------|------------------|
|
|
78
|
-
EOF
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
# Helper: write an RFC ticket file with the given status suffix.
|
|
82
|
-
# Optional 4th arg overrides the `problems:` list (default `[P168]`).
|
|
83
|
-
write_rfc() {
|
|
84
|
-
local id="$1" slug="$2" status="$3"
|
|
85
|
-
local problems="${4:-[P168]}"
|
|
86
|
-
cat > "$FIXTURE_DIR/RFC-${id}-${slug}.${status}.md" <<EOF
|
|
87
|
-
---
|
|
88
|
-
status: ${status}
|
|
89
|
-
rfc-id: ${slug}
|
|
90
|
-
reported: 2026-05-05
|
|
91
|
-
decision-makers: [test]
|
|
92
|
-
problems: ${problems}
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
# RFC-${id}: ${slug}
|
|
96
|
-
|
|
97
|
-
stub
|
|
98
|
-
EOF
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
# Helper: write a problem ticket file with optional `## RFCs` table rows.
|
|
102
|
-
# Args: <pid-num> <slug> <status> <rfcs-rows-block>
|
|
103
|
-
# rfcs-rows-block is the markdown rows (already pipe-formatted) inserted under
|
|
104
|
-
# the `## RFCs` table header — pass an empty string to omit the section
|
|
105
|
-
# entirely (lazy-empty discipline per JTBD-101 atomic-fix-adopter friction guard).
|
|
106
|
-
write_problem() {
|
|
107
|
-
local num="$1" slug="$2" status="$3" rfcs_rows="${4:-}"
|
|
108
|
-
local file="$PROBLEMS_DIR/${num}-${slug}.${status}.md"
|
|
109
|
-
cat > "$file" <<EOF
|
|
110
|
-
# Problem ${num}: ${slug}
|
|
111
|
-
|
|
112
|
-
**Status**: ${status}
|
|
113
|
-
|
|
114
|
-
## Description
|
|
115
|
-
|
|
116
|
-
stub
|
|
117
|
-
|
|
118
|
-
## Related
|
|
119
|
-
|
|
120
|
-
stub
|
|
121
|
-
EOF
|
|
122
|
-
if [ -n "$rfcs_rows" ]; then
|
|
123
|
-
cat >> "$file" <<EOF
|
|
124
|
-
|
|
125
|
-
## RFCs
|
|
126
|
-
|
|
127
|
-
| RFC | Status | Title |
|
|
128
|
-
|-----|--------|-------|
|
|
129
|
-
${rfcs_rows}
|
|
130
|
-
EOF
|
|
131
|
-
fi
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
# Helper: write a problem ticket under the per-state subdir layout per
|
|
135
|
-
# ADR-031 (state is the parent directory; filename has NO `.state.md` suffix).
|
|
136
|
-
# Args: <pid-num> <slug> <state> <rfcs-rows-block>
|
|
137
|
-
# Used to regression-test P312 — reconcile-rfcs reverse-trace must traverse
|
|
138
|
-
# docs/problems/<state>/<NNN>-*.md, not just flat docs/problems/<NNN>-*.<state>.md.
|
|
139
|
-
write_problem_subdir() {
|
|
140
|
-
local num="$1" slug="$2" state="$3" rfcs_rows="${4:-}"
|
|
141
|
-
mkdir -p "$PROBLEMS_DIR/$state"
|
|
142
|
-
local file="$PROBLEMS_DIR/$state/${num}-${slug}.md"
|
|
143
|
-
cat > "$file" <<EOF
|
|
144
|
-
# Problem ${num}: ${slug}
|
|
145
|
-
|
|
146
|
-
**Status**: ${state}
|
|
147
|
-
|
|
148
|
-
## Description
|
|
149
|
-
|
|
150
|
-
stub
|
|
151
|
-
|
|
152
|
-
## Related
|
|
153
|
-
|
|
154
|
-
stub
|
|
155
|
-
EOF
|
|
156
|
-
if [ -n "$rfcs_rows" ]; then
|
|
157
|
-
cat >> "$file" <<EOF
|
|
158
|
-
|
|
159
|
-
## RFCs
|
|
160
|
-
|
|
161
|
-
| RFC | Status | Title |
|
|
162
|
-
|-----|--------|-------|
|
|
163
|
-
${rfcs_rows}
|
|
164
|
-
EOF
|
|
165
|
-
fi
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
169
|
-
|
|
170
|
-
@test "reconcile-rfcs: script exists" {
|
|
171
|
-
[ -f "$SCRIPT" ]
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
@test "reconcile-rfcs: script is executable" {
|
|
175
|
-
[ -x "$SCRIPT" ]
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
# ── Parse-error path ────────────────────────────────────────────────────────
|
|
179
|
-
|
|
180
|
-
@test "reconcile-rfcs: missing README → exit 2 (parse error)" {
|
|
181
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
182
|
-
[ "$status" -eq 2 ]
|
|
183
|
-
[[ "$output" == *"PARSE_ERROR"* ]]
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
@test "reconcile-rfcs: README without RFC Rankings header → exit 2" {
|
|
187
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
188
|
-
# RFC Backlog
|
|
189
|
-
|
|
190
|
-
(no Rankings section)
|
|
191
|
-
EOF
|
|
192
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
193
|
-
[ "$status" -eq 2 ]
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
# ── Clean path ──────────────────────────────────────────────────────────────
|
|
197
|
-
|
|
198
|
-
@test "reconcile-rfcs: empty filesystem + empty README → exit 0 (clean)" {
|
|
199
|
-
write_minimal_readme ""
|
|
200
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
201
|
-
[ "$status" -eq 0 ]
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
@test "reconcile-rfcs: README and filesystem agree on one proposed RFC → exit 0" {
|
|
205
|
-
write_rfc "001" "foo" "proposed"
|
|
206
|
-
write_minimal_readme "| 1.5 | RFC-001 | foo | 3 Med | Proposed | M | 2026-05-05 |"
|
|
207
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
208
|
-
[ "$status" -eq 0 ]
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
@test "reconcile-rfcs: accepted RFC matches Rankings (proposed/accepted/in-progress are all WSJF queue)" {
|
|
212
|
-
write_rfc "002" "bar" "accepted"
|
|
213
|
-
write_minimal_readme "| 2.0 | RFC-002 | bar | 4 High | Accepted | M | 2026-05-05 |"
|
|
214
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
215
|
-
[ "$status" -eq 0 ]
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
@test "reconcile-rfcs: in-progress RFC matches Rankings" {
|
|
219
|
-
write_rfc "003" "baz" "in-progress"
|
|
220
|
-
write_minimal_readme "| 1.5 | RFC-003 | baz | 3 Med | In-Progress | M | 2026-05-05 |"
|
|
221
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
222
|
-
[ "$status" -eq 0 ]
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
# ── Drift paths ─────────────────────────────────────────────────────────────
|
|
226
|
-
|
|
227
|
-
@test "reconcile-rfcs: filesystem RFC missing from README → MISSING drift" {
|
|
228
|
-
write_rfc "004" "qux" "proposed"
|
|
229
|
-
write_minimal_readme ""
|
|
230
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
231
|
-
[ "$status" -eq 1 ]
|
|
232
|
-
[[ "$output" == *"MISSING RFC-004"* ]]
|
|
233
|
-
[[ "$output" == *"actual=proposed"* ]]
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
@test "reconcile-rfcs: README claims RFC in Rankings but filesystem says verifying → DRIFT" {
|
|
237
|
-
write_rfc "005" "blip" "verifying"
|
|
238
|
-
write_minimal_readme "| 0 | RFC-005 | blip | 3 Med | Proposed | M | 2026-05-05 |"
|
|
239
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
240
|
-
[ "$status" -eq 1 ]
|
|
241
|
-
[[ "$output" == *"DRIFT RFC-005"* ]]
|
|
242
|
-
[[ "$output" == *"actual=verifying"* ]]
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
@test "reconcile-rfcs: verifying RFC missing from Verification Queue → MISSING in queue" {
|
|
246
|
-
write_rfc "006" "ver" "verifying"
|
|
247
|
-
write_minimal_readme ""
|
|
248
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
249
|
-
[ "$status" -eq 1 ]
|
|
250
|
-
[[ "$output" == *"MISSING RFC-006"* ]]
|
|
251
|
-
[[ "$output" == *"verification-queue"* ]]
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
@test "reconcile-rfcs: closed RFC listed in Verification Queue → STALE" {
|
|
255
|
-
write_rfc "007" "stale" "closed"
|
|
256
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
257
|
-
# RFC Backlog
|
|
258
|
-
|
|
259
|
-
## RFC Rankings
|
|
260
|
-
|
|
261
|
-
| WSJF | ID | Title | Severity | Status | Effort | Reported |
|
|
262
|
-
|------|-----|-------|----------|--------|--------|----------|
|
|
263
|
-
|
|
264
|
-
## Verification Queue
|
|
265
|
-
|
|
266
|
-
| ID | Title | Released | Verification check |
|
|
267
|
-
|----|-------|----------|--------------------|
|
|
268
|
-
| RFC-007 | stale | 2026-05-05 | check |
|
|
269
|
-
|
|
270
|
-
## Closed
|
|
271
|
-
|
|
272
|
-
| ID | Title | Closed | Driving problems |
|
|
273
|
-
|----|-------|--------|------------------|
|
|
274
|
-
EOF
|
|
275
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
276
|
-
[ "$status" -eq 1 ]
|
|
277
|
-
[[ "$output" == *"STALE RFC-007"* ]]
|
|
278
|
-
[[ "$output" == *"actual=closed"* ]]
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
@test "reconcile-rfcs: open-shape RFC listed in Closed section → MISMATCH" {
|
|
282
|
-
write_rfc "008" "mis" "proposed"
|
|
283
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
284
|
-
# RFC Backlog
|
|
285
|
-
|
|
286
|
-
## RFC Rankings
|
|
287
|
-
|
|
288
|
-
| WSJF | ID | Title | Severity | Status | Effort | Reported |
|
|
289
|
-
|------|-----|-------|----------|--------|--------|----------|
|
|
290
|
-
| 1.5 | RFC-008 | mis | 3 Med | Proposed | M | 2026-05-05 |
|
|
291
|
-
|
|
292
|
-
## Verification Queue
|
|
293
|
-
|
|
294
|
-
| ID | Title | Released | Verification check |
|
|
295
|
-
|----|-------|----------|--------------------|
|
|
296
|
-
|
|
297
|
-
## Closed
|
|
298
|
-
|
|
299
|
-
| ID | Title | Closed | Driving problems |
|
|
300
|
-
|----|-------|--------|------------------|
|
|
301
|
-
| RFC-008 | mis | 2026-05-05 | P168 |
|
|
302
|
-
EOF
|
|
303
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
304
|
-
[ "$status" -eq 1 ]
|
|
305
|
-
[[ "$output" == *"MISMATCH RFC-008"* ]]
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
# ── Output format ───────────────────────────────────────────────────────────
|
|
309
|
-
|
|
310
|
-
@test "reconcile-rfcs: drift output is per-line and ≤150 bytes per line (ADR-038)" {
|
|
311
|
-
write_rfc "010" "byte-budget-test-with-an-extra-long-slug-to-stress-row-width" "proposed"
|
|
312
|
-
write_minimal_readme ""
|
|
313
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
314
|
-
[ "$status" -eq 1 ]
|
|
315
|
-
while IFS= read -r line; do
|
|
316
|
-
[ ${#line} -le 150 ] || { echo "row exceeds 150 bytes: '$line' (${#line} bytes)"; return 1; }
|
|
317
|
-
done <<< "$output"
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
@test "reconcile-rfcs: stable sort order (deterministic for snapshot diffing)" {
|
|
321
|
-
write_rfc "020" "second" "proposed"
|
|
322
|
-
write_rfc "010" "first" "proposed"
|
|
323
|
-
write_minimal_readme ""
|
|
324
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
325
|
-
[ "$status" -eq 1 ]
|
|
326
|
-
# Both should appear; lower ID first per sort.
|
|
327
|
-
first_line=$(echo "$output" | head -1)
|
|
328
|
-
second_line=$(echo "$output" | sed -n '2p')
|
|
329
|
-
[[ "$first_line" == *"RFC-010"* ]]
|
|
330
|
-
[[ "$second_line" == *"RFC-020"* ]]
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
# ── Reverse-trace drift detection (B5.T8 — closes ADR-060 Confirmation criterion 3) ──
|
|
334
|
-
#
|
|
335
|
-
# Per architect Q5 verdict: when a problems-dir is provided as second positional
|
|
336
|
-
# arg, reconcile-rfcs.sh extends to detect drift in the `## RFCs` reverse-trace
|
|
337
|
-
# section on driving problem tickets. Three new drift conditions:
|
|
338
|
-
#
|
|
339
|
-
# MISSING_REVERSE_TRACE RFC-<NNN> in P<NNN> ## RFCs
|
|
340
|
-
# RFC frontmatter `problems:` claims P<NNN> but P<NNN>'s `## RFCs` table
|
|
341
|
-
# does not list RFC-<NNN>.
|
|
342
|
-
#
|
|
343
|
-
# STALE_REVERSE_TRACE RFC-<NNN> in P<NNN> ## RFCs
|
|
344
|
-
# P<NNN>'s `## RFCs` table lists RFC-<NNN> but the RFC's frontmatter
|
|
345
|
-
# `problems:` no longer claims P<NNN>.
|
|
346
|
-
#
|
|
347
|
-
# STATUS_MISMATCH RFC-<NNN> in P<NNN> ## RFCs claims=<X> actual=<Y>
|
|
348
|
-
# P<NNN>'s `## RFCs` row claims status <X> but RFC's filesystem suffix is <Y>.
|
|
349
|
-
#
|
|
350
|
-
# Backward-compat: when no problems-dir arg is supplied (or the dir is absent),
|
|
351
|
-
# the script preserves the single-arg behaviour from B5.T6 (existing 18 cases
|
|
352
|
-
# above pass unchanged).
|
|
353
|
-
|
|
354
|
-
@test "reverse-trace: clean — RFC traces P, P has matching ## RFCs row → no drift" {
|
|
355
|
-
write_rfc "001" "foo" "accepted"
|
|
356
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
357
|
-
write_problem "168" "p168" "verifying" "| RFC-001 | accepted | foo |"
|
|
358
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
359
|
-
[ "$status" -eq 0 ]
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
@test "reverse-trace: MISSING_REVERSE_TRACE — RFC claims P, P has no ## RFCs section" {
|
|
363
|
-
write_rfc "001" "foo" "accepted"
|
|
364
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
365
|
-
write_problem "168" "p168" "verifying" ""
|
|
366
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
367
|
-
[ "$status" -eq 1 ]
|
|
368
|
-
[[ "$output" == *"MISSING_REVERSE_TRACE"* ]]
|
|
369
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
370
|
-
[[ "$output" == *"P168"* ]]
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
@test "reverse-trace: MISSING_REVERSE_TRACE — RFC claims P, P has ## RFCs but RFC absent from table" {
|
|
374
|
-
write_rfc "001" "foo" "accepted"
|
|
375
|
-
write_rfc "002" "bar" "proposed"
|
|
376
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
377
|
-
# P168 has ## RFCs section listing RFC-002 but not RFC-001
|
|
378
|
-
write_problem "168" "p168" "verifying" "| RFC-002 | proposed | bar |"
|
|
379
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
380
|
-
[ "$status" -eq 1 ]
|
|
381
|
-
[[ "$output" == *"MISSING_REVERSE_TRACE"* ]]
|
|
382
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
383
|
-
[[ "$output" == *"P168"* ]]
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
@test "reverse-trace: STALE_REVERSE_TRACE — P lists RFC, RFC frontmatter no longer claims P" {
|
|
387
|
-
# RFC-001 traces P169 only; P168's ## RFCs table still lists RFC-001
|
|
388
|
-
write_rfc "001" "foo" "accepted" "[P169]"
|
|
389
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
390
|
-
write_problem "168" "p168" "verifying" "| RFC-001 | accepted | foo |"
|
|
391
|
-
write_problem "169" "p169" "open" "| RFC-001 | accepted | foo |"
|
|
392
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
393
|
-
[ "$status" -eq 1 ]
|
|
394
|
-
[[ "$output" == *"STALE_REVERSE_TRACE"* ]]
|
|
395
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
396
|
-
[[ "$output" == *"P168"* ]]
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
@test "reverse-trace: STATUS_MISMATCH — P ## RFCs row claims status X but RFC suffix is Y" {
|
|
400
|
-
write_rfc "001" "foo" "in-progress"
|
|
401
|
-
write_minimal_readme "| 1.5 | RFC-001 | foo | 3 Med | In-Progress | M | 2026-05-05 |"
|
|
402
|
-
# P168's ## RFCs table claims RFC-001 is `accepted` but the on-disk suffix is in-progress
|
|
403
|
-
write_problem "168" "p168" "verifying" "| RFC-001 | accepted | foo |"
|
|
404
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
405
|
-
[ "$status" -eq 1 ]
|
|
406
|
-
[[ "$output" == *"STATUS_MISMATCH"* ]]
|
|
407
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
408
|
-
[[ "$output" == *"P168"* ]]
|
|
409
|
-
[[ "$output" == *"claims=accepted"* ]]
|
|
410
|
-
[[ "$output" == *"actual=in-progress"* ]]
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
@test "reverse-trace: backward-compat — single-arg invocation skips reverse-trace check" {
|
|
414
|
-
# No problems-dir → existing 18-case behaviour
|
|
415
|
-
write_rfc "001" "foo" "accepted"
|
|
416
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
417
|
-
run bash "$SCRIPT" "$FIXTURE_DIR"
|
|
418
|
-
[ "$status" -eq 0 ]
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
@test "reverse-trace: problems-dir absent on disk → reverse-trace check skipped (warn-only)" {
|
|
422
|
-
write_rfc "001" "foo" "accepted"
|
|
423
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
424
|
-
rm -rf "$PROBLEMS_DIR"
|
|
425
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
426
|
-
# absent problems-dir does not promote to drift; treat as backward-compat
|
|
427
|
-
[ "$status" -eq 0 ]
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
@test "reverse-trace: RFC has no problems frontmatter → reverse-trace skipped for that RFC" {
|
|
431
|
-
# Empty problems list; RFC-001 frontmatter has no claims to validate
|
|
432
|
-
write_rfc "001" "foo" "accepted" "[]"
|
|
433
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
434
|
-
write_problem "168" "p168" "verifying" ""
|
|
435
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
436
|
-
[ "$status" -eq 0 ]
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
@test "reverse-trace: drift output is per-line and ≤150 bytes per line (ADR-038)" {
|
|
440
|
-
write_rfc "001" "byte-budget-test-with-an-extra-long-slug-to-stress-row-width" "accepted"
|
|
441
|
-
write_minimal_readme "| 2.0 | RFC-001 | byte-budget-test-with-an-extra-long-slug-to-stress-row-width | 3 Med | Accepted | M | 2026-05-05 |"
|
|
442
|
-
write_problem "168" "p168" "verifying" ""
|
|
443
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
444
|
-
[ "$status" -eq 1 ]
|
|
445
|
-
while IFS= read -r line; do
|
|
446
|
-
[ ${#line} -le 150 ] || { echo "row exceeds 150 bytes: '$line' (${#line} bytes)"; return 1; }
|
|
447
|
-
done <<< "$output"
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
# ── P312: per-state subdir reverse-trace (ADR-031 layout) ───────────────────
|
|
451
|
-
# Closes P312 — reconcile-rfcs reported spurious MISSING_REVERSE_TRACE for
|
|
452
|
-
# tickets that live under docs/problems/<state>/<NNN>-*.md because the
|
|
453
|
-
# reverse-trace pass only globbed the flat docs/problems/<NNN>-*.md layout.
|
|
454
|
-
# RFC-002-class dual-tolerant-glob fix mirroring the sibling already shipped
|
|
455
|
-
# in reconcile-readme.sh (P118).
|
|
456
|
-
|
|
457
|
-
@test "P312: reverse-trace clean when problem ticket lives in per-state subdir" {
|
|
458
|
-
write_rfc "001" "foo" "accepted"
|
|
459
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
460
|
-
# Ticket lives under docs/problems/verifying/168-p168.md (no .state suffix).
|
|
461
|
-
write_problem_subdir "168" "p168" "verifying" "| RFC-001 | accepted | foo |"
|
|
462
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
463
|
-
[ "$status" -eq 0 ]
|
|
464
|
-
[[ "$output" != *"MISSING_REVERSE_TRACE"* ]]
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
@test "P312: reverse-trace detects missing trace when problem ticket lives in per-state subdir" {
|
|
468
|
-
write_rfc "001" "foo" "accepted"
|
|
469
|
-
write_minimal_readme "| 2.0 | RFC-001 | foo | 3 Med | Accepted | M | 2026-05-05 |"
|
|
470
|
-
# Subdir ticket WITHOUT a `## RFCs` section → MISSING_REVERSE_TRACE must fire.
|
|
471
|
-
write_problem_subdir "168" "p168" "verifying" ""
|
|
472
|
-
run bash "$SCRIPT" "$FIXTURE_DIR" "$PROBLEMS_DIR"
|
|
473
|
-
[ "$status" -eq 1 ]
|
|
474
|
-
[[ "$output" == *"MISSING_REVERSE_TRACE"* ]]
|
|
475
|
-
[[ "$output" == *"RFC-001"* ]]
|
|
476
|
-
[[ "$output" == *"P168"* ]]
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
# ── ADR-049 bin shim contract ───────────────────────────────────────────────
|
|
480
|
-
|
|
481
|
-
@test "wr-itil-reconcile-rfcs bin shim exists" {
|
|
482
|
-
BIN_SHIM="$(cd "$SCRIPTS_DIR/../bin" && pwd)/wr-itil-reconcile-rfcs"
|
|
483
|
-
[ -f "$BIN_SHIM" ]
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
@test "wr-itil-reconcile-rfcs bin shim is executable" {
|
|
487
|
-
BIN_SHIM="$(cd "$SCRIPTS_DIR/../bin" && pwd)/wr-itil-reconcile-rfcs"
|
|
488
|
-
[ -x "$BIN_SHIM" ]
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
@test "wr-itil-reconcile-rfcs bin shim dispatches to canonical script" {
|
|
492
|
-
BIN_SHIM="$(cd "$SCRIPTS_DIR/../bin" && pwd)/wr-itil-reconcile-rfcs"
|
|
493
|
-
write_minimal_readme ""
|
|
494
|
-
run bash "$BIN_SHIM" "$FIXTURE_DIR"
|
|
495
|
-
[ "$status" -eq 0 ]
|
|
496
|
-
}
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Behavioural fixtures for reconcile-stories.sh + bin shim + skill
|
|
3
|
-
# (P170 Phase 2 Slice 9 — ADR-060 amendment 2026-05-10 line 270 +
|
|
4
|
-
# reconcile-rfcs.sh / reconcile-readme.sh sibling).
|
|
5
|
-
#
|
|
6
|
-
# Per ADR-052: behavioural tests on observable script outputs. The
|
|
7
|
-
# load-bearing surfaces under test are:
|
|
8
|
-
# 1. Script existence + executable + valid Bash.
|
|
9
|
-
# 2. README parse error (exit 2) on missing README or missing
|
|
10
|
-
# Story Rankings header.
|
|
11
|
-
# 3. Clean run (exit 0) on a fresh stories directory + empty README.
|
|
12
|
-
# 4. Drift detection (exit 1) when README claims a story that isn't
|
|
13
|
-
# on filesystem in the right lifecycle state.
|
|
14
|
-
# 5. STALE detection when filesystem has a story not listed in
|
|
15
|
-
# either Story Rankings (active) or Done section.
|
|
16
|
-
# 6. Bin shim resolves to the script.
|
|
17
|
-
# 7. SKILL.md presence + canonical name + read-only contract.
|
|
18
|
-
|
|
19
|
-
setup() {
|
|
20
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
21
|
-
SCRIPT="${REPO_ROOT}/packages/itil/scripts/reconcile-stories.sh"
|
|
22
|
-
BIN_SHIM="${REPO_ROOT}/packages/itil/bin/wr-itil-reconcile-stories"
|
|
23
|
-
SKILL_FILE="${REPO_ROOT}/packages/itil/skills/reconcile-stories/SKILL.md"
|
|
24
|
-
|
|
25
|
-
TMPROOT=$(mktemp -d)
|
|
26
|
-
ORIG_DIR="$PWD"
|
|
27
|
-
cd "$TMPROOT"
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
teardown() {
|
|
31
|
-
cd "$ORIG_DIR"
|
|
32
|
-
rm -rf "$TMPROOT"
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
# ---------------------------------------------------------------------------
|
|
36
|
-
# Surface 1: Script + bin shim existence
|
|
37
|
-
# ---------------------------------------------------------------------------
|
|
38
|
-
|
|
39
|
-
@test "reconcile-stories: script exists and is executable" {
|
|
40
|
-
[ -f "$SCRIPT" ]
|
|
41
|
-
[ -x "$SCRIPT" ]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@test "reconcile-stories: bin shim exists, is executable, and exec's the script" {
|
|
45
|
-
[ -f "$BIN_SHIM" ]
|
|
46
|
-
[ -x "$BIN_SHIM" ]
|
|
47
|
-
run grep -E 'exec.*scripts/reconcile-stories\.sh' "$BIN_SHIM"
|
|
48
|
-
[ "$status" -eq 0 ]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# ---------------------------------------------------------------------------
|
|
52
|
-
# Surface 2: Parse errors (exit 2)
|
|
53
|
-
# ---------------------------------------------------------------------------
|
|
54
|
-
|
|
55
|
-
@test "reconcile-stories: exits 2 when README is missing" {
|
|
56
|
-
mkdir -p docs/stories
|
|
57
|
-
run bash "$SCRIPT" docs/stories
|
|
58
|
-
[ "$status" -eq 2 ]
|
|
59
|
-
[[ "$output" == *"PARSE_ERROR"* ]] || [[ "$stderr" == *"PARSE_ERROR"* ]]
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
@test "reconcile-stories: exits 2 when README missing Story Rankings header" {
|
|
63
|
-
mkdir -p docs/stories
|
|
64
|
-
echo "# Stories" > docs/stories/README.md
|
|
65
|
-
run bash "$SCRIPT" docs/stories
|
|
66
|
-
[ "$status" -eq 2 ]
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
# ---------------------------------------------------------------------------
|
|
70
|
-
# Surface 3: Clean run (exit 0)
|
|
71
|
-
# ---------------------------------------------------------------------------
|
|
72
|
-
|
|
73
|
-
@test "reconcile-stories: exits 0 on empty stories dir with empty README tables" {
|
|
74
|
-
mkdir -p docs/stories/draft docs/stories/accepted docs/stories/in-progress docs/stories/done docs/stories/archived
|
|
75
|
-
cat > docs/stories/README.md <<'EOF'
|
|
76
|
-
# Story Backlog
|
|
77
|
-
|
|
78
|
-
## Story Rankings
|
|
79
|
-
|
|
80
|
-
| ID | Title | Status |
|
|
81
|
-
|----|-------|--------|
|
|
82
|
-
|
|
83
|
-
## Done
|
|
84
|
-
|
|
85
|
-
| ID | Title | Done |
|
|
86
|
-
|----|-------|------|
|
|
87
|
-
EOF
|
|
88
|
-
run bash "$SCRIPT" docs/stories
|
|
89
|
-
[ "$status" -eq 0 ]
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
# ---------------------------------------------------------------------------
|
|
93
|
-
# Surface 4: Drift detection on filesystem vs README mismatch (exit 1)
|
|
94
|
-
# ---------------------------------------------------------------------------
|
|
95
|
-
|
|
96
|
-
@test "reconcile-stories: detects STALE when filesystem has a draft story not in README" {
|
|
97
|
-
mkdir -p docs/stories/draft docs/stories/done
|
|
98
|
-
touch docs/stories/draft/STORY-007-foo.md
|
|
99
|
-
cat > docs/stories/README.md <<'EOF'
|
|
100
|
-
# Story Backlog
|
|
101
|
-
|
|
102
|
-
## Story Rankings
|
|
103
|
-
|
|
104
|
-
| ID | Title | Status |
|
|
105
|
-
|----|-------|--------|
|
|
106
|
-
|
|
107
|
-
## Done
|
|
108
|
-
|
|
109
|
-
| ID | Title | Done |
|
|
110
|
-
|----|-------|------|
|
|
111
|
-
EOF
|
|
112
|
-
run bash "$SCRIPT" docs/stories
|
|
113
|
-
[ "$status" -eq 1 ]
|
|
114
|
-
[[ "$output" == *"STALE"* ]]
|
|
115
|
-
[[ "$output" == *"STORY-007"* ]]
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
@test "reconcile-stories: detects DRIFT when README claims a story in Rankings but it's actually done on disk" {
|
|
119
|
-
mkdir -p docs/stories/draft docs/stories/done
|
|
120
|
-
touch docs/stories/done/STORY-007-foo.md
|
|
121
|
-
cat > docs/stories/README.md <<'EOF'
|
|
122
|
-
# Story Backlog
|
|
123
|
-
|
|
124
|
-
## Story Rankings
|
|
125
|
-
|
|
126
|
-
| ID | Title | Status |
|
|
127
|
-
|----|-------|--------|
|
|
128
|
-
| STORY-007 | Foo | draft |
|
|
129
|
-
|
|
130
|
-
## Done
|
|
131
|
-
|
|
132
|
-
| ID | Title | Done |
|
|
133
|
-
|----|-------|------|
|
|
134
|
-
EOF
|
|
135
|
-
run bash "$SCRIPT" docs/stories
|
|
136
|
-
[ "$status" -eq 1 ]
|
|
137
|
-
[[ "$output" == *"DRIFT"* ]]
|
|
138
|
-
[[ "$output" == *"STORY-007"* ]]
|
|
139
|
-
[[ "$output" == *"actual=done"* ]]
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
@test "reconcile-stories: archived stories are hidden from both tables (no drift)" {
|
|
143
|
-
mkdir -p docs/stories/archived
|
|
144
|
-
touch docs/stories/archived/STORY-007-foo.md
|
|
145
|
-
cat > docs/stories/README.md <<'EOF'
|
|
146
|
-
# Story Backlog
|
|
147
|
-
|
|
148
|
-
## Story Rankings
|
|
149
|
-
|
|
150
|
-
| ID | Title | Status |
|
|
151
|
-
|----|-------|--------|
|
|
152
|
-
|
|
153
|
-
## Done
|
|
154
|
-
|
|
155
|
-
| ID | Title | Done |
|
|
156
|
-
|----|-------|------|
|
|
157
|
-
EOF
|
|
158
|
-
run bash "$SCRIPT" docs/stories
|
|
159
|
-
[ "$status" -eq 0 ]
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
# ---------------------------------------------------------------------------
|
|
163
|
-
# Surface 5: SKILL.md presence + read-only contract
|
|
164
|
-
# ---------------------------------------------------------------------------
|
|
165
|
-
|
|
166
|
-
@test "reconcile-stories: SKILL.md exists" {
|
|
167
|
-
[ -f "$SKILL_FILE" ]
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
@test "reconcile-stories: SKILL.md declares canonical name wr-itil:reconcile-stories" {
|
|
171
|
-
run grep -E '^name: wr-itil:reconcile-stories$' "$SKILL_FILE"
|
|
172
|
-
[ "$status" -eq 0 ]
|
|
173
|
-
}
|