@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,1007 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P118 — docs/problems/README.md drifts from filesystem truth
|
|
4
|
-
# across sessions despite P094 (refresh-on-create) and P062 (refresh-on-
|
|
5
|
-
# transition) both being Closed. This script is the cross-session
|
|
6
|
-
# robustness layer ON TOP of those per-operation contracts.
|
|
7
|
-
#
|
|
8
|
-
# Contract: `reconcile-readme.sh [<problems-dir>]` is a diagnose-only
|
|
9
|
-
# mechanical drift detector. It reads `<problems-dir>/<NNN>-*.<status>.md`
|
|
10
|
-
# files (default `docs/problems`), parses the WSJF Rankings + Verification
|
|
11
|
-
# Queue + Closed tables in `<problems-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
|
-
# Diff output budget per ADR-038 progressive disclosure: each diff row
|
|
20
|
-
# ≤ 150 bytes; output is consumed by Claude in agent context, so it
|
|
21
|
-
# must stay terse and machine-readable, not narrative.
|
|
22
|
-
#
|
|
23
|
-
# The script is read-only — it does NOT mutate the README. Narrative
|
|
24
|
-
# content (the long "Last reviewed" prose paragraph, the Closed-section
|
|
25
|
-
# closure-via free text) is preserved by the agent-applied-edits pattern
|
|
26
|
-
# in the `/wr-itil:reconcile-readme` skill which wraps this script.
|
|
27
|
-
#
|
|
28
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — orchestrators
|
|
29
|
-
# read the README to pick the highest-WSJF actionable ticket; drift
|
|
30
|
-
# burns iterations on already-transitioned tickets)
|
|
31
|
-
# @jtbd JTBD-001 (Enforce Governance Without Slowing Down — read-only
|
|
32
|
-
# diagnostic, no interactive friction on the happy path)
|
|
33
|
-
#
|
|
34
|
-
# Cross-reference:
|
|
35
|
-
# P118: docs/problems/118-readme-drifts-from-filesystem-truth-despite-refresh-contracts-closed.open.md
|
|
36
|
-
# ADR-014 amended (Reconciliation as preflight robustness layer)
|
|
37
|
-
# ADR-022 — Verification Pending lifecycle status conventions
|
|
38
|
-
# ADR-038 — Progressive disclosure (per-row byte budget on diff output)
|
|
39
|
-
# ADR-005 — Plugin testing strategy (script-level bats governance)
|
|
40
|
-
|
|
41
|
-
setup() {
|
|
42
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
43
|
-
SCRIPT="$SCRIPTS_DIR/reconcile-readme.sh"
|
|
44
|
-
FIXTURE_DIR="$(mktemp -d)"
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
teardown() {
|
|
48
|
-
rm -rf "$FIXTURE_DIR"
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
@test "reconcile-readme: script exists" {
|
|
54
|
-
[ -f "$SCRIPT" ]
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@test "reconcile-readme: script is executable" {
|
|
58
|
-
[ -x "$SCRIPT" ]
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
# ── Exit code 0: clean state ─────────────────────────────────────────────────
|
|
62
|
-
|
|
63
|
-
@test "reconcile-readme: exit 0 when WSJF Rankings matches filesystem .open.md set" {
|
|
64
|
-
cat > "$FIXTURE_DIR/100-foo.open.md" <<EOF
|
|
65
|
-
# Problem 100: Foo
|
|
66
|
-
**Status**: Open
|
|
67
|
-
**WSJF**: 5.0
|
|
68
|
-
EOF
|
|
69
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
70
|
-
# Problem Backlog
|
|
71
|
-
|
|
72
|
-
## WSJF Rankings
|
|
73
|
-
|
|
74
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
75
|
-
|------|-----|-------|----------|--------|--------|
|
|
76
|
-
| 5.0 | P100 | Foo | 12 High | Open | M |
|
|
77
|
-
|
|
78
|
-
## Verification Queue
|
|
79
|
-
|
|
80
|
-
| ID | Title | Released | Likely verified? |
|
|
81
|
-
|----|-------|----------|------------------|
|
|
82
|
-
|
|
83
|
-
## Closed
|
|
84
|
-
|
|
85
|
-
| ID | Title | Closed via |
|
|
86
|
-
|----|-------|-----------|
|
|
87
|
-
EOF
|
|
88
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
89
|
-
[ "$status" -eq 0 ]
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
# ── Exit code 1: drift cases ─────────────────────────────────────────────────
|
|
93
|
-
|
|
94
|
-
@test "reconcile-readme: exit 1 when README ranks ticket Open but file is .closed.md (P074 case)" {
|
|
95
|
-
# The exact symptom this ticket addresses: a prior session closed the
|
|
96
|
-
# ticket without staging the README refresh, leaving the WSJF Rankings
|
|
97
|
-
# row stale in subsequent sessions.
|
|
98
|
-
cat > "$FIXTURE_DIR/074-foo.closed.md" <<EOF
|
|
99
|
-
# Problem 074: Foo
|
|
100
|
-
**Status**: Closed
|
|
101
|
-
EOF
|
|
102
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
103
|
-
# Problem Backlog
|
|
104
|
-
|
|
105
|
-
## WSJF Rankings
|
|
106
|
-
|
|
107
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
108
|
-
|------|-----|-------|----------|--------|--------|
|
|
109
|
-
| 6.0 | P074 | Foo | 12 High | Open | M |
|
|
110
|
-
|
|
111
|
-
## Verification Queue
|
|
112
|
-
|
|
113
|
-
| ID | Title | Released | Likely verified? |
|
|
114
|
-
|----|-------|----------|------------------|
|
|
115
|
-
|
|
116
|
-
## Closed
|
|
117
|
-
|
|
118
|
-
| ID | Title | Closed via |
|
|
119
|
-
|----|-------|-----------|
|
|
120
|
-
EOF
|
|
121
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
122
|
-
[ "$status" -eq 1 ]
|
|
123
|
-
# Output mentions P074 as the drift entry.
|
|
124
|
-
echo "$output" | grep -q "P074"
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
@test "reconcile-readme: exit 1 when ticket on disk as .open.md is missing from WSJF Rankings" {
|
|
128
|
-
# The other half of the drift class: a ticket created in a prior
|
|
129
|
-
# session that never refreshed README — the file exists but the
|
|
130
|
-
# row was never inserted.
|
|
131
|
-
cat > "$FIXTURE_DIR/079-bar.open.md" <<EOF
|
|
132
|
-
# Problem 079: Bar
|
|
133
|
-
**Status**: Open
|
|
134
|
-
**WSJF**: 3.0
|
|
135
|
-
EOF
|
|
136
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
137
|
-
# Problem Backlog
|
|
138
|
-
|
|
139
|
-
## WSJF Rankings
|
|
140
|
-
|
|
141
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
142
|
-
|------|-----|-------|----------|--------|--------|
|
|
143
|
-
|
|
144
|
-
## Verification Queue
|
|
145
|
-
|
|
146
|
-
| ID | Title | Released | Likely verified? |
|
|
147
|
-
|----|-------|----------|------------------|
|
|
148
|
-
|
|
149
|
-
## Closed
|
|
150
|
-
|
|
151
|
-
| ID | Title | Closed via |
|
|
152
|
-
|----|-------|-----------|
|
|
153
|
-
EOF
|
|
154
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
155
|
-
[ "$status" -eq 1 ]
|
|
156
|
-
echo "$output" | grep -q "P079"
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
@test "reconcile-readme: exit 1 when README ranks ticket Open but file is .verifying.md (P110 case)" {
|
|
160
|
-
cat > "$FIXTURE_DIR/110-baz.verifying.md" <<EOF
|
|
161
|
-
# Problem 110: Baz
|
|
162
|
-
**Status**: Verification Pending
|
|
163
|
-
EOF
|
|
164
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
165
|
-
# Problem Backlog
|
|
166
|
-
|
|
167
|
-
## WSJF Rankings
|
|
168
|
-
|
|
169
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
170
|
-
|------|-----|-------|----------|--------|--------|
|
|
171
|
-
| 4.0 | P110 | Baz | 8 Med | Open | M |
|
|
172
|
-
|
|
173
|
-
## Verification Queue
|
|
174
|
-
|
|
175
|
-
| ID | Title | Released | Likely verified? |
|
|
176
|
-
|----|-------|----------|------------------|
|
|
177
|
-
|
|
178
|
-
## Closed
|
|
179
|
-
|
|
180
|
-
| ID | Title | Closed via |
|
|
181
|
-
|----|-------|-----------|
|
|
182
|
-
EOF
|
|
183
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
184
|
-
[ "$status" -eq 1 ]
|
|
185
|
-
echo "$output" | grep -q "P110"
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
@test "reconcile-readme: exit 1 when Verification Queue lists ticket but file is .closed.md (stale VQ)" {
|
|
189
|
-
cat > "$FIXTURE_DIR/056-qux.closed.md" <<EOF
|
|
190
|
-
# Problem 056: Qux
|
|
191
|
-
**Status**: Closed
|
|
192
|
-
EOF
|
|
193
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
194
|
-
# Problem Backlog
|
|
195
|
-
|
|
196
|
-
## WSJF Rankings
|
|
197
|
-
|
|
198
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
199
|
-
|------|-----|-------|----------|--------|--------|
|
|
200
|
-
|
|
201
|
-
## Verification Queue
|
|
202
|
-
|
|
203
|
-
| ID | Title | Released | Likely verified? |
|
|
204
|
-
|----|-------|----------|------------------|
|
|
205
|
-
| P056 | Qux | 2026-01-01 | yes |
|
|
206
|
-
|
|
207
|
-
## Closed
|
|
208
|
-
|
|
209
|
-
| ID | Title | Closed via |
|
|
210
|
-
|----|-------|-----------|
|
|
211
|
-
EOF
|
|
212
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
213
|
-
[ "$status" -eq 1 ]
|
|
214
|
-
echo "$output" | grep -q "P056"
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
# ── Diff output is structured + within byte budget (ADR-038) ────────────────
|
|
218
|
-
|
|
219
|
-
@test "reconcile-readme: drift output emits one structured line per drift entry" {
|
|
220
|
-
# Two distinct drift entries; output should contain at least two
|
|
221
|
-
# rows (one per ID).
|
|
222
|
-
cat > "$FIXTURE_DIR/074-foo.closed.md" <<EOF
|
|
223
|
-
**Status**: Closed
|
|
224
|
-
EOF
|
|
225
|
-
cat > "$FIXTURE_DIR/079-bar.open.md" <<EOF
|
|
226
|
-
**WSJF**: 3.0
|
|
227
|
-
EOF
|
|
228
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
229
|
-
## WSJF Rankings
|
|
230
|
-
|
|
231
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
232
|
-
|------|-----|-------|----------|--------|--------|
|
|
233
|
-
| 6.0 | P074 | Foo | 12 High | Open | M |
|
|
234
|
-
|
|
235
|
-
## Verification Queue
|
|
236
|
-
|
|
237
|
-
| ID | Title | Released | Likely verified? |
|
|
238
|
-
|----|-------|----------|------------------|
|
|
239
|
-
|
|
240
|
-
## Closed
|
|
241
|
-
|
|
242
|
-
| ID | Title | Closed via |
|
|
243
|
-
|----|-------|-----------|
|
|
244
|
-
EOF
|
|
245
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
246
|
-
[ "$status" -eq 1 ]
|
|
247
|
-
# Both drift IDs surface in output.
|
|
248
|
-
echo "$output" | grep -q "P074"
|
|
249
|
-
echo "$output" | grep -q "P079"
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
@test "reconcile-readme: each diff row stays under 150 bytes (ADR-038 progressive-disclosure budget)" {
|
|
253
|
-
cat > "$FIXTURE_DIR/074-foo.closed.md" <<EOF
|
|
254
|
-
**Status**: Closed
|
|
255
|
-
EOF
|
|
256
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
257
|
-
## WSJF Rankings
|
|
258
|
-
|
|
259
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
260
|
-
|------|-----|-------|----------|--------|--------|
|
|
261
|
-
| 6.0 | P074 | Foo | 12 High | Open | M |
|
|
262
|
-
|
|
263
|
-
## Verification Queue
|
|
264
|
-
|
|
265
|
-
| ID | Title | Released | Likely verified? |
|
|
266
|
-
|----|-------|----------|------------------|
|
|
267
|
-
|
|
268
|
-
## Closed
|
|
269
|
-
|
|
270
|
-
| ID | Title | Closed via |
|
|
271
|
-
|----|-------|-----------|
|
|
272
|
-
EOF
|
|
273
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
274
|
-
[ "$status" -eq 1 ]
|
|
275
|
-
# Filter to data rows only (drift entries start with a marker char).
|
|
276
|
-
while IFS= read -r line; do
|
|
277
|
-
# Skip empty lines + the header line.
|
|
278
|
-
[ -z "$line" ] && continue
|
|
279
|
-
case "$line" in
|
|
280
|
-
DRIFT*|MISSING*|STALE*|MISMATCH*)
|
|
281
|
-
len=${#line}
|
|
282
|
-
[ "$len" -le 150 ] || {
|
|
283
|
-
echo "Diff row over 150 bytes ($len): $line" >&2
|
|
284
|
-
return 1
|
|
285
|
-
}
|
|
286
|
-
;;
|
|
287
|
-
esac
|
|
288
|
-
done <<< "$output"
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
# ── Exit code 2: parse error ────────────────────────────────────────────────
|
|
292
|
-
|
|
293
|
-
@test "reconcile-readme: exit 2 when README is missing" {
|
|
294
|
-
cat > "$FIXTURE_DIR/100-foo.open.md" <<EOF
|
|
295
|
-
**WSJF**: 5.0
|
|
296
|
-
EOF
|
|
297
|
-
# No README.md created.
|
|
298
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
299
|
-
[ "$status" -eq 2 ]
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
@test "reconcile-readme: exit 2 when README has no WSJF Rankings header (parse error)" {
|
|
303
|
-
cat > "$FIXTURE_DIR/100-foo.open.md" <<EOF
|
|
304
|
-
**WSJF**: 5.0
|
|
305
|
-
EOF
|
|
306
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
307
|
-
# Problem Backlog
|
|
308
|
-
|
|
309
|
-
This README has no WSJF Rankings section header.
|
|
310
|
-
EOF
|
|
311
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
312
|
-
[ "$status" -eq 2 ]
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
# ── Verification Pending tickets must NOT appear in WSJF Rankings (ADR-022) ─
|
|
316
|
-
|
|
317
|
-
@test "reconcile-readme: .verifying.md tickets in WSJF Rankings are flagged as drift" {
|
|
318
|
-
# ADR-022 — Verification Pending tickets are excluded from WSJF Rankings
|
|
319
|
-
# (they belong in the Verification Queue section). A .verifying.md row
|
|
320
|
-
# in the dev-work table is drift.
|
|
321
|
-
cat > "$FIXTURE_DIR/105-verify.verifying.md" <<EOF
|
|
322
|
-
**Status**: Verification Pending
|
|
323
|
-
EOF
|
|
324
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
325
|
-
## WSJF Rankings
|
|
326
|
-
|
|
327
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
328
|
-
|------|-----|-------|----------|--------|--------|
|
|
329
|
-
| 8.0 | P105 | Verify | 12 High | Open | M |
|
|
330
|
-
|
|
331
|
-
## Verification Queue
|
|
332
|
-
|
|
333
|
-
| ID | Title | Released | Likely verified? |
|
|
334
|
-
|----|-------|----------|------------------|
|
|
335
|
-
|
|
336
|
-
## Closed
|
|
337
|
-
|
|
338
|
-
| ID | Title | Closed via |
|
|
339
|
-
|----|-------|-----------|
|
|
340
|
-
EOF
|
|
341
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
342
|
-
[ "$status" -eq 1 ]
|
|
343
|
-
echo "$output" | grep -q "P105"
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
# ── Default problems-dir resolution ─────────────────────────────────────────
|
|
347
|
-
|
|
348
|
-
@test "reconcile-readme: defaults to ./docs/problems when no arg passed" {
|
|
349
|
-
# cd into a fixture root that has docs/problems/README.md to confirm
|
|
350
|
-
# the default-arg branch executes.
|
|
351
|
-
mkdir -p "$FIXTURE_DIR/docs/problems"
|
|
352
|
-
cat > "$FIXTURE_DIR/docs/problems/README.md" <<'EOF'
|
|
353
|
-
## WSJF Rankings
|
|
354
|
-
|
|
355
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
356
|
-
|------|-----|-------|----------|--------|--------|
|
|
357
|
-
|
|
358
|
-
## Verification Queue
|
|
359
|
-
|
|
360
|
-
| ID | Title | Released | Likely verified? |
|
|
361
|
-
|----|-------|----------|------------------|
|
|
362
|
-
|
|
363
|
-
## Closed
|
|
364
|
-
|
|
365
|
-
| ID | Title | Closed via |
|
|
366
|
-
|----|-------|-----------|
|
|
367
|
-
EOF
|
|
368
|
-
cd "$FIXTURE_DIR"
|
|
369
|
-
run "$SCRIPT"
|
|
370
|
-
[ "$status" -eq 0 ]
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
# ── Parked tickets are excluded (ADR-022 multiplier 0 + own section) ────────
|
|
374
|
-
|
|
375
|
-
@test "reconcile-readme: .parked.md tickets are not flagged as missing from WSJF Rankings" {
|
|
376
|
-
# Parked tickets live in their own section; they are NOT expected in
|
|
377
|
-
# WSJF Rankings. A .parked.md file with no WSJF Rankings row is
|
|
378
|
-
# correct, not drift.
|
|
379
|
-
cat > "$FIXTURE_DIR/005-parked.parked.md" <<EOF
|
|
380
|
-
**Status**: Parked
|
|
381
|
-
EOF
|
|
382
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
383
|
-
## WSJF Rankings
|
|
384
|
-
|
|
385
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
386
|
-
|------|-----|-------|----------|--------|--------|
|
|
387
|
-
|
|
388
|
-
## Verification Queue
|
|
389
|
-
|
|
390
|
-
| ID | Title | Released | Likely verified? |
|
|
391
|
-
|----|-------|----------|------------------|
|
|
392
|
-
|
|
393
|
-
## Closed
|
|
394
|
-
|
|
395
|
-
| ID | Title | Closed via |
|
|
396
|
-
|----|-------|-----------|
|
|
397
|
-
|
|
398
|
-
## Parked
|
|
399
|
-
|
|
400
|
-
| ID | Title | Reason | Parked since |
|
|
401
|
-
|----|-------|--------|-------------|
|
|
402
|
-
| P005 | Parked | Upstream | 2026-04-16 |
|
|
403
|
-
EOF
|
|
404
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
405
|
-
[ "$status" -eq 0 ]
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
# ── Closed tickets never tracked (P001-P028 don't all appear) ───────────────
|
|
409
|
-
|
|
410
|
-
@test "reconcile-readme: .closed.md tickets absent from Closed section are not drift (history is partial)" {
|
|
411
|
-
# The Closed section is curated narrative — it lists "recently closed
|
|
412
|
-
# this session" with closure-via prose. It is NOT exhaustive over
|
|
413
|
-
# every .closed.md file. A .closed.md file absent from the Closed
|
|
414
|
-
# section is allowed; the only Closed-section drift is when a row
|
|
415
|
-
# in that section names an ID that is NOT .closed.md on disk.
|
|
416
|
-
cat > "$FIXTURE_DIR/001-old.closed.md" <<EOF
|
|
417
|
-
**Status**: Closed
|
|
418
|
-
EOF
|
|
419
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
420
|
-
## WSJF Rankings
|
|
421
|
-
|
|
422
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
423
|
-
|------|-----|-------|----------|--------|--------|
|
|
424
|
-
|
|
425
|
-
## Verification Queue
|
|
426
|
-
|
|
427
|
-
| ID | Title | Released | Likely verified? |
|
|
428
|
-
|----|-------|----------|------------------|
|
|
429
|
-
|
|
430
|
-
## Closed
|
|
431
|
-
|
|
432
|
-
| ID | Title | Closed via |
|
|
433
|
-
|----|-------|-----------|
|
|
434
|
-
EOF
|
|
435
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
436
|
-
[ "$status" -eq 0 ]
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
# ── P133: defensive rename of `status` local → `ticket_status` ──────────────
|
|
440
|
-
|
|
441
|
-
@test "reconcile-readme: drift detection still works when caller-environment exports status=anything (P133 regression)" {
|
|
442
|
-
# P133 — `status` is a read-only built-in under zsh (alias for `$?`). The
|
|
443
|
-
# script's `#!/usr/bin/env bash` shebang means it never runs under zsh
|
|
444
|
-
# directly, but a caller may export `status=…` into the script's environment
|
|
445
|
-
# and the script must not depend on the bash-builtin name for its own state.
|
|
446
|
-
# After the P133 rename (`status` → `ticket_status`), the script's drift
|
|
447
|
-
# detection is independent of any caller-set `status` env var. This test
|
|
448
|
-
# asserts the behaviour: caller exports `status=junk`, script still emits
|
|
449
|
-
# correct drift output (does not pick up the caller's value).
|
|
450
|
-
cat > "$FIXTURE_DIR/074-foo.closed.md" <<EOF
|
|
451
|
-
**Status**: Closed
|
|
452
|
-
EOF
|
|
453
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
454
|
-
## WSJF Rankings
|
|
455
|
-
|
|
456
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
457
|
-
|------|-----|-------|----------|--------|--------|
|
|
458
|
-
| 6.0 | P074 | Foo | 12 High | Open | M |
|
|
459
|
-
|
|
460
|
-
## Verification Queue
|
|
461
|
-
|
|
462
|
-
| ID | Title | Released | Likely verified? |
|
|
463
|
-
|----|-------|----------|------------------|
|
|
464
|
-
|
|
465
|
-
## Closed
|
|
466
|
-
|
|
467
|
-
| ID | Title | Closed via |
|
|
468
|
-
|----|-------|-----------|
|
|
469
|
-
EOF
|
|
470
|
-
# `env status=junk` sets the env var on the script invocation; bats's
|
|
471
|
-
# `run` still captures the script exit code into the test-scope `$status`.
|
|
472
|
-
run env status=junk "$SCRIPT" "$FIXTURE_DIR"
|
|
473
|
-
[ "$status" -eq 1 ]
|
|
474
|
-
echo "$output" | grep -q "P074"
|
|
475
|
-
# Drift line must report actual filesystem status (`closed`), not the
|
|
476
|
-
# caller's bogus `junk` value — script reads from FS_STATUS, not env.
|
|
477
|
-
echo "$output" | grep -q "actual=closed"
|
|
478
|
-
! echo "$output" | grep -q "actual=junk"
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
# ── README Closed-section row pointing to non-existent or wrong-status file ──
|
|
482
|
-
|
|
483
|
-
@test "reconcile-readme: exit 1 when Closed section names ID that is .open.md on disk" {
|
|
484
|
-
cat > "$FIXTURE_DIR/099-still-open.open.md" <<EOF
|
|
485
|
-
**Status**: Open
|
|
486
|
-
**WSJF**: 3.0
|
|
487
|
-
EOF
|
|
488
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
489
|
-
## WSJF Rankings
|
|
490
|
-
|
|
491
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
492
|
-
|------|-----|-------|----------|--------|--------|
|
|
493
|
-
| 3.0 | P099 | Still Open | 15 High | Open | L |
|
|
494
|
-
|
|
495
|
-
## Verification Queue
|
|
496
|
-
|
|
497
|
-
| ID | Title | Released | Likely verified? |
|
|
498
|
-
|----|-------|----------|------------------|
|
|
499
|
-
|
|
500
|
-
## Closed
|
|
501
|
-
|
|
502
|
-
| ID | Title | Closed via |
|
|
503
|
-
|----|-------|-----------|
|
|
504
|
-
| P099 | Still Open | (incorrectly listed) |
|
|
505
|
-
EOF
|
|
506
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
507
|
-
[ "$status" -eq 1 ]
|
|
508
|
-
echo "$output" | grep -q "P099"
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
# ── RFC-002 T4: dual-tolerant layout enumeration ────────────────────────────
|
|
512
|
-
#
|
|
513
|
-
# Contract: during the P170/RFC-002 migration window, problem tickets MAY
|
|
514
|
-
# live under either the flat layout (`docs/problems/<NNN>-<title>.<state>.md`)
|
|
515
|
-
# OR the per-state subdir layout (`docs/problems/<state>/<NNN>-<title>.md`).
|
|
516
|
-
# `reconcile-readme.sh` MUST enumerate ground-truth status from both,
|
|
517
|
-
# otherwise:
|
|
518
|
-
# - tickets in the un-migrated layout-half show as MISSING in WSJF Rankings,
|
|
519
|
-
# - or tickets in the migrated layout-half are not validated against
|
|
520
|
-
# README claims, masking drift.
|
|
521
|
-
#
|
|
522
|
-
# Behavioural contract: drift output (or exit 0) MUST be IDENTICAL regardless
|
|
523
|
-
# of which layout the source tickets reside in. The script's stdout is the
|
|
524
|
-
# observable signal; tests assert against stdout content + exit code, NOT
|
|
525
|
-
# against script source (P081 — no structural-grep on script content).
|
|
526
|
-
#
|
|
527
|
-
# T6 (post-T5 verification) drops the flat-layout half. These tests update
|
|
528
|
-
# at T6 to single-layout fixtures, NOT removed — the contract becomes
|
|
529
|
-
# "per-state layout enumerates correctly" but remains behavioural.
|
|
530
|
-
#
|
|
531
|
-
# @rfc RFC-002 T4
|
|
532
|
-
# @adr ADR-031 (per-state subdir is post-migration ground truth)
|
|
533
|
-
# @adr ADR-051 (load-bearing-from-the-start — T4 ships with bats coverage)
|
|
534
|
-
# @adr ADR-052 (behavioural-tests-default — fixture-driven not source-grep)
|
|
535
|
-
|
|
536
|
-
@test "reconcile-readme T4: per-state subdir .open ticket recognised, no drift when README matches" {
|
|
537
|
-
# Per-state layout — same Open ticket as the flat-only baseline test
|
|
538
|
-
# at line ~63 ("WSJF Rankings matches filesystem .open.md set"). The
|
|
539
|
-
# rendered drift output (exit 0) MUST be identical regardless of which
|
|
540
|
-
# layout the ticket resides in.
|
|
541
|
-
mkdir -p "$FIXTURE_DIR/open"
|
|
542
|
-
cat > "$FIXTURE_DIR/open/100-foo.md" <<EOF
|
|
543
|
-
# Problem 100: Foo
|
|
544
|
-
**Status**: Open
|
|
545
|
-
**WSJF**: 5.0
|
|
546
|
-
EOF
|
|
547
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
548
|
-
# Problem Backlog
|
|
549
|
-
|
|
550
|
-
## WSJF Rankings
|
|
551
|
-
|
|
552
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
553
|
-
|------|-----|-------|----------|--------|--------|
|
|
554
|
-
| 5.0 | P100 | Foo | 12 High | Open | M |
|
|
555
|
-
|
|
556
|
-
## Verification Queue
|
|
557
|
-
|
|
558
|
-
| ID | Title | Released | Likely verified? |
|
|
559
|
-
|----|-------|----------|------------------|
|
|
560
|
-
|
|
561
|
-
## Closed
|
|
562
|
-
|
|
563
|
-
| ID | Title | Closed via |
|
|
564
|
-
|----|-------|-----------|
|
|
565
|
-
EOF
|
|
566
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
567
|
-
[ "$status" -eq 0 ]
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
@test "reconcile-readme T4: per-state subdir .closed ticket flagged when README ranks it Open (drift parity with flat)" {
|
|
571
|
-
# Mirrors the flat-layout P074 case at line ~94. Same drift, different
|
|
572
|
-
# source layout — drift output must surface P074 the same way.
|
|
573
|
-
mkdir -p "$FIXTURE_DIR/closed"
|
|
574
|
-
cat > "$FIXTURE_DIR/closed/074-foo.md" <<EOF
|
|
575
|
-
# Problem 074: Foo
|
|
576
|
-
**Status**: Closed
|
|
577
|
-
EOF
|
|
578
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
579
|
-
# Problem Backlog
|
|
580
|
-
|
|
581
|
-
## WSJF Rankings
|
|
582
|
-
|
|
583
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
584
|
-
|------|-----|-------|----------|--------|--------|
|
|
585
|
-
| 6.0 | P074 | Foo | 12 High | Open | M |
|
|
586
|
-
|
|
587
|
-
## Verification Queue
|
|
588
|
-
|
|
589
|
-
| ID | Title | Released | Likely verified? |
|
|
590
|
-
|----|-------|----------|------------------|
|
|
591
|
-
|
|
592
|
-
## Closed
|
|
593
|
-
|
|
594
|
-
| ID | Title | Closed via |
|
|
595
|
-
|----|-------|-----------|
|
|
596
|
-
EOF
|
|
597
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
598
|
-
[ "$status" -eq 1 ]
|
|
599
|
-
echo "$output" | grep -q "P074"
|
|
600
|
-
echo "$output" | grep -q "actual=closed"
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
@test "reconcile-readme T4: per-state subdir .verifying ticket in WSJF Rankings flagged as drift (ADR-022)" {
|
|
604
|
-
# Mirrors the flat-layout P105 case at line ~317 — Verification Pending
|
|
605
|
-
# tickets must NOT appear in WSJF Rankings (ADR-022).
|
|
606
|
-
mkdir -p "$FIXTURE_DIR/verifying"
|
|
607
|
-
cat > "$FIXTURE_DIR/verifying/105-verify.md" <<EOF
|
|
608
|
-
**Status**: Verification Pending
|
|
609
|
-
EOF
|
|
610
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
611
|
-
## WSJF Rankings
|
|
612
|
-
|
|
613
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
614
|
-
|------|-----|-------|----------|--------|--------|
|
|
615
|
-
| 8.0 | P105 | Verify | 12 High | Open | M |
|
|
616
|
-
|
|
617
|
-
## Verification Queue
|
|
618
|
-
|
|
619
|
-
| ID | Title | Released | Likely verified? |
|
|
620
|
-
|----|-------|----------|------------------|
|
|
621
|
-
|
|
622
|
-
## Closed
|
|
623
|
-
|
|
624
|
-
| ID | Title | Closed via |
|
|
625
|
-
|----|-------|-----------|
|
|
626
|
-
EOF
|
|
627
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
628
|
-
[ "$status" -eq 1 ]
|
|
629
|
-
echo "$output" | grep -q "P105"
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
@test "reconcile-readme T4: per-state subdir .open ticket missing from WSJF Rankings is flagged MISSING" {
|
|
633
|
-
# Mirrors the flat-layout P079 case at line ~127 — a ticket on disk
|
|
634
|
-
# but absent from README WSJF Rankings is drift.
|
|
635
|
-
mkdir -p "$FIXTURE_DIR/open"
|
|
636
|
-
cat > "$FIXTURE_DIR/open/079-bar.md" <<EOF
|
|
637
|
-
# Problem 079: Bar
|
|
638
|
-
**Status**: Open
|
|
639
|
-
**WSJF**: 3.0
|
|
640
|
-
EOF
|
|
641
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
642
|
-
## WSJF Rankings
|
|
643
|
-
|
|
644
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
645
|
-
|------|-----|-------|----------|--------|--------|
|
|
646
|
-
|
|
647
|
-
## Verification Queue
|
|
648
|
-
|
|
649
|
-
| ID | Title | Released | Likely verified? |
|
|
650
|
-
|----|-------|----------|------------------|
|
|
651
|
-
|
|
652
|
-
## Closed
|
|
653
|
-
|
|
654
|
-
| ID | Title | Closed via |
|
|
655
|
-
|----|-------|-----------|
|
|
656
|
-
EOF
|
|
657
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
658
|
-
[ "$status" -eq 1 ]
|
|
659
|
-
echo "$output" | grep -q "P079"
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
@test "reconcile-readme T4: per-state subdir .verifying ticket listed in Verification Queue is clean (no drift)" {
|
|
663
|
-
# Verification Queue expects .verifying.md tickets — per-state
|
|
664
|
-
# equivalent is docs/problems/verifying/<NNN>-*.md.
|
|
665
|
-
mkdir -p "$FIXTURE_DIR/verifying"
|
|
666
|
-
cat > "$FIXTURE_DIR/verifying/056-qux.md" <<EOF
|
|
667
|
-
**Status**: Verification Pending
|
|
668
|
-
EOF
|
|
669
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
670
|
-
## WSJF Rankings
|
|
671
|
-
|
|
672
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
673
|
-
|------|-----|-------|----------|--------|--------|
|
|
674
|
-
|
|
675
|
-
## Verification Queue
|
|
676
|
-
|
|
677
|
-
| ID | Title | Released | Likely verified? |
|
|
678
|
-
|----|-------|----------|------------------|
|
|
679
|
-
| P056 | Qux | 2026-01-01 | yes |
|
|
680
|
-
|
|
681
|
-
## Closed
|
|
682
|
-
|
|
683
|
-
| ID | Title | Closed via |
|
|
684
|
-
|----|-------|-----------|
|
|
685
|
-
EOF
|
|
686
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
687
|
-
[ "$status" -eq 0 ]
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
@test "reconcile-readme T4: mixed-layout fixture (flat + per-state) enumerates BOTH and stays clean" {
|
|
691
|
-
# Mid-migration race: some tickets already moved to per-state subdir,
|
|
692
|
-
# others still in flat layout. README accurately tracks both. Script
|
|
693
|
-
# must recognise both layout-halves as filesystem ground truth and
|
|
694
|
-
# report exit 0 (no drift) when README rows match.
|
|
695
|
-
cat > "$FIXTURE_DIR/100-foo.open.md" <<EOF
|
|
696
|
-
**Status**: Open
|
|
697
|
-
EOF
|
|
698
|
-
mkdir -p "$FIXTURE_DIR/open"
|
|
699
|
-
cat > "$FIXTURE_DIR/open/200-bar.md" <<EOF
|
|
700
|
-
**Status**: Open
|
|
701
|
-
EOF
|
|
702
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
703
|
-
## WSJF Rankings
|
|
704
|
-
|
|
705
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
706
|
-
|------|-----|-------|----------|--------|--------|
|
|
707
|
-
| 5.0 | P100 | Foo | 12 High | Open | M |
|
|
708
|
-
| 4.0 | P200 | Bar | 12 High | Open | M |
|
|
709
|
-
|
|
710
|
-
## Verification Queue
|
|
711
|
-
|
|
712
|
-
| ID | Title | Released | Likely verified? |
|
|
713
|
-
|----|-------|----------|------------------|
|
|
714
|
-
|
|
715
|
-
## Closed
|
|
716
|
-
|
|
717
|
-
| ID | Title | Closed via |
|
|
718
|
-
|----|-------|-----------|
|
|
719
|
-
EOF
|
|
720
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
721
|
-
[ "$status" -eq 0 ]
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
@test "reconcile-readme T4: mixed-layout fixture surfaces drift from BOTH halves" {
|
|
725
|
-
# Both layout-halves contain a drifting ticket; both surfaces in
|
|
726
|
-
# output. Confirms the script enumerates both, not just one or the
|
|
727
|
-
# other.
|
|
728
|
-
cat > "$FIXTURE_DIR/100-foo.closed.md" <<EOF
|
|
729
|
-
**Status**: Closed
|
|
730
|
-
EOF
|
|
731
|
-
mkdir -p "$FIXTURE_DIR/closed"
|
|
732
|
-
cat > "$FIXTURE_DIR/closed/200-bar.md" <<EOF
|
|
733
|
-
**Status**: Closed
|
|
734
|
-
EOF
|
|
735
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
736
|
-
## WSJF Rankings
|
|
737
|
-
|
|
738
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
739
|
-
|------|-----|-------|----------|--------|--------|
|
|
740
|
-
| 6.0 | P100 | Foo | 12 High | Open | M |
|
|
741
|
-
| 5.0 | P200 | Bar | 12 High | Open | M |
|
|
742
|
-
|
|
743
|
-
## Verification Queue
|
|
744
|
-
|
|
745
|
-
| ID | Title | Released | Likely verified? |
|
|
746
|
-
|----|-------|----------|------------------|
|
|
747
|
-
|
|
748
|
-
## Closed
|
|
749
|
-
|
|
750
|
-
| ID | Title | Closed via |
|
|
751
|
-
|----|-------|-----------|
|
|
752
|
-
EOF
|
|
753
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
754
|
-
[ "$status" -eq 1 ]
|
|
755
|
-
echo "$output" | grep -q "P100"
|
|
756
|
-
echo "$output" | grep -q "P200"
|
|
757
|
-
# Both surface as DRIFT (claims=open, actual=closed).
|
|
758
|
-
echo "$output" | grep -q "actual=closed"
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
@test "reconcile-readme T4: per-state subdir wins on cross-layout ID collision (post-migration is authoritative)" {
|
|
762
|
-
# Mid-migration race window: same ID may transiently appear in both
|
|
763
|
-
# layouts between the `git mv` and the README refresh in T5 bulk
|
|
764
|
-
# migration commit. Per-state subdir is the migration target —
|
|
765
|
-
# ADR-031 §"Authoritative state signal" treats subdirectory as
|
|
766
|
-
# authoritative. The script must therefore report per-state status,
|
|
767
|
-
# not flat-layout status, when both are present.
|
|
768
|
-
cat > "$FIXTURE_DIR/300-collision.open.md" <<EOF
|
|
769
|
-
**Status**: Open
|
|
770
|
-
EOF
|
|
771
|
-
mkdir -p "$FIXTURE_DIR/closed"
|
|
772
|
-
cat > "$FIXTURE_DIR/closed/300-collision.md" <<EOF
|
|
773
|
-
**Status**: Closed
|
|
774
|
-
EOF
|
|
775
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
776
|
-
## WSJF Rankings
|
|
777
|
-
|
|
778
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
779
|
-
|------|-----|-------|----------|--------|--------|
|
|
780
|
-
| 5.0 | P300 | Collision | 12 High | Open | M |
|
|
781
|
-
|
|
782
|
-
## Verification Queue
|
|
783
|
-
|
|
784
|
-
| ID | Title | Released | Likely verified? |
|
|
785
|
-
|----|-------|----------|------------------|
|
|
786
|
-
|
|
787
|
-
## Closed
|
|
788
|
-
|
|
789
|
-
| ID | Title | Closed via |
|
|
790
|
-
|----|-------|-----------|
|
|
791
|
-
EOF
|
|
792
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
793
|
-
# Per-state subdir is authoritative → README's "Open" claim drifts
|
|
794
|
-
# against actual=closed. If flat-layout were preferred, the script
|
|
795
|
-
# would report exit 0 (no drift). Asserting actual=closed proves
|
|
796
|
-
# per-state-wins semantics.
|
|
797
|
-
[ "$status" -eq 1 ]
|
|
798
|
-
echo "$output" | grep -q "P300"
|
|
799
|
-
echo "$output" | grep -q "actual=closed"
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
@test "reconcile-readme T4: per-state subdir .parked ticket excluded from WSJF Rankings (ADR-022 multiplier 0)" {
|
|
803
|
-
# Mirrors the flat-layout P005 case at line ~375 — Parked tickets
|
|
804
|
-
# have their own section; absence from WSJF Rankings is correct.
|
|
805
|
-
mkdir -p "$FIXTURE_DIR/parked"
|
|
806
|
-
cat > "$FIXTURE_DIR/parked/005-parked.md" <<EOF
|
|
807
|
-
**Status**: Parked
|
|
808
|
-
EOF
|
|
809
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
810
|
-
## WSJF Rankings
|
|
811
|
-
|
|
812
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
813
|
-
|------|-----|-------|----------|--------|--------|
|
|
814
|
-
|
|
815
|
-
## Verification Queue
|
|
816
|
-
|
|
817
|
-
| ID | Title | Released | Likely verified? |
|
|
818
|
-
|----|-------|----------|------------------|
|
|
819
|
-
|
|
820
|
-
## Closed
|
|
821
|
-
|
|
822
|
-
| ID | Title | Closed via |
|
|
823
|
-
|----|-------|-----------|
|
|
824
|
-
|
|
825
|
-
## Parked
|
|
826
|
-
|
|
827
|
-
| ID | Title | Reason | Parked since |
|
|
828
|
-
|----|-------|--------|-------------|
|
|
829
|
-
| P005 | Parked | Upstream | 2026-04-16 |
|
|
830
|
-
EOF
|
|
831
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
832
|
-
[ "$status" -eq 0 ]
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
@test "reconcile-readme T4: per-state subdir .known-error ticket recognised in WSJF Rankings as Open-class" {
|
|
836
|
-
# Known-error tickets belong in WSJF Rankings (ADR-022 — open + known-error
|
|
837
|
-
# are the dev-work classes). Per-state subdir equivalent is
|
|
838
|
-
# docs/problems/known-error/<NNN>-*.md.
|
|
839
|
-
mkdir -p "$FIXTURE_DIR/known-error"
|
|
840
|
-
cat > "$FIXTURE_DIR/known-error/150-ke.md" <<EOF
|
|
841
|
-
**Status**: Known Error
|
|
842
|
-
EOF
|
|
843
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
844
|
-
## WSJF Rankings
|
|
845
|
-
|
|
846
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
847
|
-
|------|-----|-------|----------|--------|--------|
|
|
848
|
-
| 4.0 | P150 | KE | 8 Med | Known Error | M |
|
|
849
|
-
|
|
850
|
-
## Verification Queue
|
|
851
|
-
|
|
852
|
-
| ID | Title | Released | Likely verified? |
|
|
853
|
-
|----|-------|----------|------------------|
|
|
854
|
-
|
|
855
|
-
## Closed
|
|
856
|
-
|
|
857
|
-
| ID | Title | Closed via |
|
|
858
|
-
|----|-------|-----------|
|
|
859
|
-
EOF
|
|
860
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
861
|
-
[ "$status" -eq 0 ]
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
# ── P252: Inbound Upstream Reports section excluded from VQ slice ───────────
|
|
865
|
-
#
|
|
866
|
-
# Contract: when `docs/problems/README.md` carries a `## Inbound Upstream
|
|
867
|
-
# Reports` section (per ADR-062 + RFC-004), its rows MUST NOT be counted as
|
|
868
|
-
# Verification Queue rows. Pre-fix the script slices VQ as
|
|
869
|
-
# `[VQ_START, CLOSED_START)`, which swallows the entire Inbound table and
|
|
870
|
-
# mis-attributes its `| P<NNN> |` cross-ref cells to the VQ. Post-fix the
|
|
871
|
-
# VQ slice terminates at `## Inbound Upstream Reports` when present.
|
|
872
|
-
#
|
|
873
|
-
# Behavioural assertion shape: reconcile against a README that has VQ
|
|
874
|
-
# matching filesystem ground truth AND an Inbound Upstream Reports table
|
|
875
|
-
# carrying cross-refs to Open tickets → exit 0. Pre-fix this would emit
|
|
876
|
-
# 31-ish STALE entries. Post-fix it emits none.
|
|
877
|
-
#
|
|
878
|
-
# @problem P252
|
|
879
|
-
# @adr ADR-062 (Inbound upstream-report discovery + assessment pipeline)
|
|
880
|
-
# @rfc RFC-004 (P079 inbound-upstream-report discovery)
|
|
881
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away)
|
|
882
|
-
# @jtbd JTBD-302 (Trust That the README Describes the Plugin I Just Installed)
|
|
883
|
-
|
|
884
|
-
@test "reconcile-readme P252: Inbound Upstream Reports cross-refs are NOT counted as Verification Queue rows" {
|
|
885
|
-
# Two Open tickets cross-referenced as inbound-mirror entries. Pre-fix
|
|
886
|
-
# the script slices VQ as [VQ_START, CLOSED_START), which swallows the
|
|
887
|
-
# Inbound table — both P-IDs get reported as STALE verification-queue.
|
|
888
|
-
# Post-fix the VQ slice terminates at Inbound; both IDs are correctly
|
|
889
|
-
# recognised as Open (their .open.md files exist) and no drift fires.
|
|
890
|
-
cat > "$FIXTURE_DIR/198-foo.open.md" <<EOF
|
|
891
|
-
**Status**: Open
|
|
892
|
-
EOF
|
|
893
|
-
cat > "$FIXTURE_DIR/199-bar.open.md" <<EOF
|
|
894
|
-
**Status**: Open
|
|
895
|
-
EOF
|
|
896
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
897
|
-
## WSJF Rankings
|
|
898
|
-
|
|
899
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
900
|
-
|------|-----|-------|----------|--------|--------|
|
|
901
|
-
| 5.0 | P198 | Foo | 12 High | Open | M |
|
|
902
|
-
| 4.0 | P199 | Bar | 12 High | Open | M |
|
|
903
|
-
|
|
904
|
-
## Verification Queue
|
|
905
|
-
|
|
906
|
-
| ID | Title | Released | Likely verified? |
|
|
907
|
-
|----|-------|----------|------------------|
|
|
908
|
-
|
|
909
|
-
## Inbound Upstream Reports
|
|
910
|
-
|
|
911
|
-
Inbound mirrors discovered via the discovery pipeline (ADR-062 / RFC-004).
|
|
912
|
-
The `Matched local ticket` column carries cross-refs that look like VQ rows
|
|
913
|
-
but live in a different section and MUST NOT be parsed as VQ entries.
|
|
914
|
-
|
|
915
|
-
| # | Inbound | Matched local ticket |
|
|
916
|
-
|---|---------|----------------------|
|
|
917
|
-
| 1 | upstream/issues/42 | P198 |
|
|
918
|
-
| 2 | upstream/issues/43 | P199 |
|
|
919
|
-
|
|
920
|
-
## Closed
|
|
921
|
-
|
|
922
|
-
| ID | Title | Closed via |
|
|
923
|
-
|----|-------|-----------|
|
|
924
|
-
EOF
|
|
925
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
926
|
-
# Clean state — both P-IDs are correctly Open on disk AND in WSJF
|
|
927
|
-
# Rankings; the Inbound section's cross-refs are scoped out.
|
|
928
|
-
[ "$status" -eq 0 ]
|
|
929
|
-
# Defensive: even if exit 0 lands by accident, output must not contain
|
|
930
|
-
# any false-positive STALE entries citing Inbound IDs.
|
|
931
|
-
! echo "$output" | grep -q "P198 verification-queue"
|
|
932
|
-
! echo "$output" | grep -q "P199 verification-queue"
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
@test "reconcile-readme P252: real VQ drift surfaces, Inbound cross-refs stay silent" {
|
|
936
|
-
# Mixed fixture: one genuine STALE VQ row (P056 — README lists in VQ,
|
|
937
|
-
# disk has it Closed) + an Inbound section with cross-refs to Open
|
|
938
|
-
# tickets. Drift output MUST cite P056 only; Inbound IDs MUST NOT
|
|
939
|
-
# appear in any verification-queue drift line.
|
|
940
|
-
cat > "$FIXTURE_DIR/056-qux.closed.md" <<EOF
|
|
941
|
-
**Status**: Closed
|
|
942
|
-
EOF
|
|
943
|
-
cat > "$FIXTURE_DIR/198-foo.open.md" <<EOF
|
|
944
|
-
**Status**: Open
|
|
945
|
-
EOF
|
|
946
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
947
|
-
## WSJF Rankings
|
|
948
|
-
|
|
949
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
950
|
-
|------|-----|-------|----------|--------|--------|
|
|
951
|
-
| 5.0 | P198 | Foo | 12 High | Open | M |
|
|
952
|
-
|
|
953
|
-
## Verification Queue
|
|
954
|
-
|
|
955
|
-
| ID | Title | Released | Likely verified? |
|
|
956
|
-
|----|-------|----------|------------------|
|
|
957
|
-
| P056 | Qux | 2026-01-01 | yes |
|
|
958
|
-
|
|
959
|
-
## Inbound Upstream Reports
|
|
960
|
-
|
|
961
|
-
| # | Inbound | Matched local ticket |
|
|
962
|
-
|---|---------|----------------------|
|
|
963
|
-
| 1 | upstream/issues/42 | P198 |
|
|
964
|
-
|
|
965
|
-
## Closed
|
|
966
|
-
|
|
967
|
-
| ID | Title | Closed via |
|
|
968
|
-
|----|-------|-----------|
|
|
969
|
-
EOF
|
|
970
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
971
|
-
[ "$status" -eq 1 ]
|
|
972
|
-
# P056 is the genuine drift (in VQ, file is Closed).
|
|
973
|
-
echo "$output" | grep -q "P056"
|
|
974
|
-
# P198 must NOT appear in any verification-queue drift line — it's an
|
|
975
|
-
# Inbound cross-ref, not a VQ row.
|
|
976
|
-
! echo "$output" | grep -q "P198 verification-queue"
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
@test "reconcile-readme P252: missing Inbound section preserves existing behaviour (back-compat)" {
|
|
980
|
-
# A README that does NOT have an Inbound Upstream Reports section must
|
|
981
|
-
# continue to slice VQ as [VQ_START, CLOSED_START) without regression.
|
|
982
|
-
# This guards against the fix accidentally requiring the Inbound header
|
|
983
|
-
# to exist.
|
|
984
|
-
cat > "$FIXTURE_DIR/056-qux.closed.md" <<EOF
|
|
985
|
-
**Status**: Closed
|
|
986
|
-
EOF
|
|
987
|
-
cat > "$FIXTURE_DIR/README.md" <<'EOF'
|
|
988
|
-
## WSJF Rankings
|
|
989
|
-
|
|
990
|
-
| WSJF | ID | Title | Severity | Status | Effort |
|
|
991
|
-
|------|-----|-------|----------|--------|--------|
|
|
992
|
-
|
|
993
|
-
## Verification Queue
|
|
994
|
-
|
|
995
|
-
| ID | Title | Released | Likely verified? |
|
|
996
|
-
|----|-------|----------|------------------|
|
|
997
|
-
| P056 | Qux | 2026-01-01 | yes |
|
|
998
|
-
|
|
999
|
-
## Closed
|
|
1000
|
-
|
|
1001
|
-
| ID | Title | Closed via |
|
|
1002
|
-
|----|-------|-----------|
|
|
1003
|
-
EOF
|
|
1004
|
-
run "$SCRIPT" "$FIXTURE_DIR"
|
|
1005
|
-
[ "$status" -eq 1 ]
|
|
1006
|
-
echo "$output" | grep -q "P056"
|
|
1007
|
-
}
|