@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.
Files changed (171) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +7 -2
  3. package/agents/test/fixtures/proceed-new-genuinely-new.md +0 -43
  4. package/agents/test/fixtures/proceed-new-subtle-sibling.md +0 -47
  5. package/agents/test/fixtures/regression-p347-vs-p346.md +0 -54
  6. package/agents/test/hang-off-check.bats +0 -225
  7. package/hooks/test/block-list.bats +0 -153
  8. package/hooks/test/command-detect.bats +0 -181
  9. package/hooks/test/itil-assistant-output-gate.bats +0 -114
  10. package/hooks/test/itil-assistant-output-review.bats +0 -224
  11. package/hooks/test/itil-bash-polling-antipattern-detect.bats +0 -154
  12. package/hooks/test/itil-changeset-discipline.bats +0 -603
  13. package/hooks/test/itil-claude-space-protection.bats +0 -294
  14. package/hooks/test/itil-commit-trailer-transition-advisory.bats +0 -80
  15. package/hooks/test/itil-correction-detect.bats +0 -189
  16. package/hooks/test/itil-deferral-cadence-gate.bats +0 -187
  17. package/hooks/test/itil-fictional-defer-detect.bats +0 -292
  18. package/hooks/test/itil-fix-title-lifecycle-advisory.bats +0 -129
  19. package/hooks/test/itil-mid-loop-ask-detect.bats +0 -220
  20. package/hooks/test/itil-no-implement-draft-gate.bats +0 -210
  21. package/hooks/test/itil-pending-questions-surface.bats +0 -307
  22. package/hooks/test/itil-readme-refresh-discipline.bats +0 -642
  23. package/hooks/test/itil-rfc-oversight-nudge.bats +0 -83
  24. package/hooks/test/itil-rfc-trailer-advisory.bats +0 -375
  25. package/hooks/test/itil-story-mirror-migration-nudge.bats +0 -122
  26. package/hooks/test/manage-problem-enforce-create.bats +0 -424
  27. package/hooks/test/p057-staging-trap-detect.bats +0 -231
  28. package/hooks/test/pre-publish-intake-gate.bats +0 -144
  29. package/hooks/test/runtime-sid-marker.bats +0 -90
  30. package/hooks/test/session-id.bats +0 -370
  31. package/scripts/migrate-problems-add-type.sh +0 -116
  32. package/scripts/test/catchup-scan.bats +0 -274
  33. package/scripts/test/check-afk-accept-eligible.bats +0 -310
  34. package/scripts/test/check-fail-soft-skip-discipline.bats +0 -172
  35. package/scripts/test/check-fix-rfc-trace.bats +0 -164
  36. package/scripts/test/check-locale-discipline.bats +0 -291
  37. package/scripts/test/check-problems-readme-budget.bats +0 -192
  38. package/scripts/test/check-rfc-has-stories.bats +0 -69
  39. package/scripts/test/check-rfc-rejected-alternatives.bats +0 -108
  40. package/scripts/test/check-rfc-stories-ratified.bats +0 -82
  41. package/scripts/test/check-upstream-responses.bats +0 -503
  42. package/scripts/test/classify-readme-drift.bats +0 -392
  43. package/scripts/test/derive-first-dispatch.bats +0 -274
  44. package/scripts/test/derive-release-vehicle.bats +0 -454
  45. package/scripts/test/detect-unratified-stories-maps.bats +0 -60
  46. package/scripts/test/dual-tolerant-glob-rfc-002-t2.bats +0 -309
  47. package/scripts/test/effort-tally.bats +0 -170
  48. package/scripts/test/evaluate-relevance.bats +0 -773
  49. package/scripts/test/kind-a-commands.bats +0 -46
  50. package/scripts/test/mark-create-gate.bats +0 -59
  51. package/scripts/test/mark-story-oversight-confirmed.bats +0 -53
  52. package/scripts/test/migrate-problems-add-type.bats +0 -280
  53. package/scripts/test/migrate-story-status-mirror.bats +0 -167
  54. package/scripts/test/no-type-regression-guard.bats +0 -74
  55. package/scripts/test/oversight-mirror-corpus-lint.bats +0 -150
  56. package/scripts/test/plugin-exercise-index.bats +0 -386
  57. package/scripts/test/plugin-maturity-doc-lint.bats +0 -470
  58. package/scripts/test/plugin-maturity-populate.bats +0 -631
  59. package/scripts/test/plugin-maturity-render.bats +0 -469
  60. package/scripts/test/plugin-validate-ci-gate.bats +0 -208
  61. package/scripts/test/reconcile-readme.bats +0 -1007
  62. package/scripts/test/reconcile-rfcs.bats +0 -496
  63. package/scripts/test/reconcile-stories.bats +0 -173
  64. package/scripts/test/reconcile-story-maps.bats +0 -74
  65. package/scripts/test/release-watch-poll-loop.bats +0 -180
  66. package/scripts/test/resolve-governance-plugin-dirs.bats +0 -78
  67. package/scripts/test/rfc-stories-extension.bats +0 -175
  68. package/scripts/test/skill-invocations.bats +0 -535
  69. package/scripts/test/skill-md-dual-tolerant-coverage-rfc-002-t3.bats +0 -374
  70. package/scripts/test/story-oversight-lib.bats +0 -190
  71. package/scripts/test/update-jtbd-references-related-problems.bats +0 -178
  72. package/scripts/test/update-problem-references-section.bats +0 -242
  73. package/scripts/test/update-problem-rfcs-section.bats +0 -242
  74. package/scripts/test/update-references-section-sibling-helpers.bats +0 -80
  75. package/scripts/test/update-rfc-commits-section.bats +0 -77
  76. package/scripts/test/verify-iter-summary.bats +0 -196
  77. package/scripts/test/working-the-problem-traversal.bats +0 -116
  78. package/skills/capture-problem/test/capture-problem-step-1-5b-jtbd-trace.bats +0 -398
  79. package/skills/capture-problem/test/capture-problem.bats +0 -389
  80. package/skills/capture-story/test/capture-story-behavioural.bats +0 -317
  81. package/skills/capture-story-map/test/capture-story-map-behavioural.bats +0 -98
  82. package/skills/close-incident/test/close-incident-contract.bats +0 -146
  83. package/skills/link-incident/test/link-incident-contract.bats +0 -125
  84. package/skills/list-incidents/test/list-incidents-contract.bats +0 -115
  85. package/skills/list-problems/test/list-problems-contract.bats +0 -100
  86. package/skills/list-stories/test/list-stories-contract.bats +0 -127
  87. package/skills/list-story-maps/test/list-story-maps-contract.bats +0 -46
  88. package/skills/manage-incident/test/manage-incident-adr-044-contract.bats +0 -206
  89. package/skills/manage-incident/test/manage-incident-close-forwarder.bats +0 -67
  90. package/skills/manage-incident/test/manage-incident-link-forwarder.bats +0 -67
  91. package/skills/manage-incident/test/manage-incident-list-forwarder.bats +0 -68
  92. package/skills/manage-incident/test/manage-incident-mitigate-forwarder.bats +0 -66
  93. package/skills/manage-incident/test/manage-incident-restore-forwarder.bats +0 -66
  94. package/skills/manage-incident/test/manage-incident.bats +0 -171
  95. package/skills/manage-problem/test/manage-problem-adr-044-step4-derive-first.bats +0 -151
  96. package/skills/manage-problem/test/manage-problem-auto-migrate-step.bats +0 -53
  97. package/skills/manage-problem/test/manage-problem-concern-boundary.bats +0 -64
  98. package/skills/manage-problem/test/manage-problem-effort-buckets.bats +0 -56
  99. package/skills/manage-problem/test/manage-problem-external-root-cause-detection.bats +0 -119
  100. package/skills/manage-problem/test/manage-problem-first-run-intake-prompt.bats +0 -43
  101. package/skills/manage-problem/test/manage-problem-git-mv-restage-reminder.bats +0 -48
  102. package/skills/manage-problem/test/manage-problem-id-collision-guard.bats +0 -39
  103. package/skills/manage-problem/test/manage-problem-list-forwarder.bats +0 -66
  104. package/skills/manage-problem/test/manage-problem-next-id-origin-lookup.bats +0 -50
  105. package/skills/manage-problem/test/manage-problem-no-prose-options.bats +0 -74
  106. package/skills/manage-problem/test/manage-problem-output-formatting.bats +0 -30
  107. package/skills/manage-problem/test/manage-problem-parked-and-cache.bats +0 -73
  108. package/skills/manage-problem/test/manage-problem-readme-refresh-on-transition.bats +0 -62
  109. package/skills/manage-problem/test/manage-problem-readme-tie-break-order.bats +0 -318
  110. package/skills/manage-problem/test/manage-problem-readme-vq-sort-order.bats +0 -206
  111. package/skills/manage-problem/test/manage-problem-release-vehicle-seed.bats +0 -83
  112. package/skills/manage-problem/test/manage-problem-review-forwarder.bats +0 -71
  113. package/skills/manage-problem/test/manage-problem-step-9d-recovery-path.bats +0 -97
  114. package/skills/manage-problem/test/manage-problem-transition-forwarder.bats +0 -96
  115. package/skills/manage-problem/test/manage-problem-transitive-dependencies.bats +0 -365
  116. package/skills/manage-problem/test/manage-problem-verification-detection.bats +0 -64
  117. package/skills/manage-problem/test/manage-problem-verification-pending.bats +0 -114
  118. package/skills/manage-problem/test/manage-problem-work-forwarder.bats +0 -88
  119. package/skills/manage-story/test/manage-story-contract.bats +0 -174
  120. package/skills/manage-story-map/test/manage-story-map-contract.bats +0 -63
  121. package/skills/mitigate-incident/test/mitigate-incident-contract.bats +0 -258
  122. package/skills/reconcile-readme/test/reconcile-readme-contract.bats +0 -201
  123. package/skills/report-upstream/test/report-upstream-contract.bats +0 -394
  124. package/skills/restore-incident/test/restore-incident-contract.bats +0 -170
  125. package/skills/review-problems/test/inbound-channels-cache-shape.bats +0 -127
  126. package/skills/review-problems/test/inbound-discovery-contract.bats +0 -383
  127. package/skills/review-problems/test/jtbd-301-verdict-shape-contract.bats +0 -225
  128. package/skills/review-problems/test/review-problems-contract.bats +0 -235
  129. package/skills/review-problems/test/review-problems-likely-verified-cell-shape.bats +0 -229
  130. package/skills/scaffold-intake/test/scaffold-intake-contract.bats +0 -126
  131. package/skills/scaffold-intake/test/scaffold-intake-fixture.bats +0 -164
  132. package/skills/scaffold-intake/test/scaffold-intake-secrets-absent.bats +0 -87
  133. package/skills/transition-problem/test/transition-problem-contract.bats +0 -285
  134. package/skills/transition-problems/test/transition-problems-contract.bats +0 -331
  135. package/skills/update-upstream/test/update-upstream-contract.bats +0 -375
  136. package/skills/work-problem/test/work-problem-contract.bats +0 -294
  137. package/skills/work-problems/test/work-problems-above-appetite-remediation.bats +0 -139
  138. package/skills/work-problems/test/work-problems-adr-013-rule-6-p352-amendment.bats +0 -166
  139. package/skills/work-problems/test/work-problems-auto-migrate-step.bats +0 -57
  140. package/skills/work-problems/test/work-problems-cost-logging.bats +0 -109
  141. package/skills/work-problems/test/work-problems-deviation-candidate-shape.bats +0 -121
  142. package/skills/work-problems/test/work-problems-first-run-intake-prompt.bats +0 -36
  143. package/skills/work-problems/test/work-problems-inter-iteration-verify.bats +0 -59
  144. package/skills/work-problems/test/work-problems-mid-loop-userpromptsubmit-handler.bats +0 -69
  145. package/skills/work-problems/test/work-problems-no-mid-loop-asking.bats +0 -192
  146. package/skills/work-problems/test/work-problems-p341-pre-all-done-gate.bats +0 -122
  147. package/skills/work-problems/test/work-problems-p342-r007-derive-then-pass-flags.bats +0 -170
  148. package/skills/work-problems/test/work-problems-p342-retro-auto-ticket-carveout.bats +0 -120
  149. package/skills/work-problems/test/work-problems-preflight-failure-handling.bats +0 -248
  150. package/skills/work-problems/test/work-problems-preflight-session-continuity.bats +0 -139
  151. package/skills/work-problems/test/work-problems-preflight.bats +0 -69
  152. package/skills/work-problems/test/work-problems-release-cadence.bats +0 -63
  153. package/skills/work-problems/test/work-problems-step-0-iter-error-staleness.bats +0 -93
  154. package/skills/work-problems/test/work-problems-step-0b-cache-staleness-behavioural.bats +0 -138
  155. package/skills/work-problems/test/work-problems-step-0c-deferred-placeholder-staleness-behavioural.bats +0 -238
  156. package/skills/work-problems/test/work-problems-step-0d-outbound-responses-staleness-behavioural.bats +0 -174
  157. package/skills/work-problems/test/work-problems-step-2-5-routing.bats +0 -80
  158. package/skills/work-problems/test/work-problems-step-2-5b-cross-halt-routing.bats +0 -149
  159. package/skills/work-problems/test/work-problems-step-3-5-jtbd-ratification-predicate.bats +0 -191
  160. package/skills/work-problems/test/work-problems-step-5-bats-polling-discipline.bats +0 -91
  161. package/skills/work-problems/test/work-problems-step-5-delegation.bats +0 -333
  162. package/skills/work-problems/test/work-problems-step-5-idle-timeout-sigterm.bats +0 -421
  163. package/skills/work-problems/test/work-problems-step-5-is-error-transient-halt.bats +0 -278
  164. package/skills/work-problems/test/work-problems-step-5-iter-changeset-required.bats +0 -95
  165. package/skills/work-problems/test/work-problems-step-5-prompt-body-re-grounding.bats +0 -128
  166. package/skills/work-problems/test/work-problems-step-5-stream-timeout-salvage.bats +0 -251
  167. package/skills/work-problems/test/work-problems-step-6-5-always-drain.bats +0 -203
  168. package/skills/work-problems/test/work-problems-step-6-5-cache-refresh-chain.bats +0 -174
  169. package/skills/work-problems/test/work-problems-step-6-5-fix-and-continue.bats +0 -254
  170. package/skills/work-problems/test/work-problems-step-6-5-postrelease-kv-callback.bats +0 -209
  171. package/skills/work-problems/test/work-problems-stop-condition-questions.bats +0 -85
@@ -1,116 +0,0 @@
1
- #!/usr/bin/env bash
2
- # packages/itil/scripts/migrate-problems-add-type.sh
3
- #
4
- # One-shot bulk migration: ensure every `<problems-dir>/<NNN>-*.<status>.md`
5
- # carries a `**Type**: technical` body field per ADR-060 Phase 1 item 8b.
6
- #
7
- # Default `**Type**: technical` per ADR-060 line 92 (existing tickets
8
- # bulk-migrate to default; per-ticket judgement comes later via
9
- # capture-problem AskUserQuestion in item 8c — out of scope here).
10
- #
11
- # Usage:
12
- # migrate-problems-add-type.sh [--apply] [<problems-dir>]
13
- #
14
- # Default <problems-dir> is ./docs/problems.
15
- #
16
- # Modes:
17
- # diagnose (default): read-only. Lists each ticket needing migration on
18
- # stdout (one per line, basename only). Exit 0 = clean, 1 = drift.
19
- # --apply: writes `**Type**: technical` after the LAST present body
20
- # field marker in {Status, Reported, Priority, Effort, WSJF}.
21
- # Idempotent — re-running with Type already present is a no-op.
22
- #
23
- # Exit codes:
24
- # 0 = clean (diagnose: no migration needed; apply: completed)
25
- # 1 = drift (diagnose only; tickets needing migration listed)
26
- # 2 = parse error
27
- #
28
- # Tickets with NO recognisable header field markers are skipped with a
29
- # `SKIP <basename>` warning on stderr — these are typically malformed
30
- # scaffold leftovers and should not be auto-migrated.
31
- #
32
- # @problem P170 (Slice 4 B7.T2 / item 8b)
33
- # @adr ADR-060 (type-tag schema; default `technical`; spec line 91 amended
34
- # 2026-05-06: header field block in body, NOT YAML frontmatter)
35
- # @adr ADR-014 (one bounded sub-task per script)
36
-
37
- set -uo pipefail
38
-
39
- APPLY=0
40
- PROBLEMS_DIR=""
41
-
42
- for arg in "$@"; do
43
- case "$arg" in
44
- --apply) APPLY=1 ;;
45
- -*) echo "PARSE_ERROR: unknown flag: $arg" >&2; exit 2 ;;
46
- *)
47
- if [ -z "$PROBLEMS_DIR" ]; then
48
- PROBLEMS_DIR="$arg"
49
- else
50
- echo "PARSE_ERROR: multiple positional args: $arg" >&2
51
- exit 2
52
- fi
53
- ;;
54
- esac
55
- done
56
-
57
- PROBLEMS_DIR="${PROBLEMS_DIR:-docs/problems}"
58
-
59
- if [ ! -d "$PROBLEMS_DIR" ]; then
60
- echo "PARSE_ERROR: problems-dir not found: $PROBLEMS_DIR" >&2
61
- exit 2
62
- fi
63
-
64
- drift=0
65
- shopt -s nullglob
66
- for f in "$PROBLEMS_DIR"/[0-9][0-9][0-9]-*.open.md \
67
- "$PROBLEMS_DIR"/[0-9][0-9][0-9]-*.known-error.md \
68
- "$PROBLEMS_DIR"/[0-9][0-9][0-9]-*.verifying.md \
69
- "$PROBLEMS_DIR"/[0-9][0-9][0-9]-*.parked.md \
70
- "$PROBLEMS_DIR"/[0-9][0-9][0-9]-*.closed.md; do
71
- base="$(basename "$f")"
72
-
73
- # Idempotency check: any line matching `**Type**: <value>` in the
74
- # first 30 lines counts as already-migrated.
75
- if head -n 30 "$f" | grep -q '^\*\*Type\*\*:'; then
76
- continue
77
- fi
78
-
79
- # Find the LAST body-field marker line (Status / Reported / Priority /
80
- # Effort / WSJF) in the first 30 lines. Insertion anchor.
81
- anchor=$(head -n 30 "$f" \
82
- | grep -n -E '^\*\*(Status|Reported|Priority|Effort|WSJF)\*\*:' \
83
- | tail -1 | cut -d: -f1)
84
-
85
- if [ -z "$anchor" ]; then
86
- echo "SKIP $base (no recognisable header field markers)" >&2
87
- continue
88
- fi
89
-
90
- drift=1
91
-
92
- if [ "$APPLY" -eq 0 ]; then
93
- echo "$base"
94
- continue
95
- fi
96
-
97
- # Apply: insert `**Type**: technical` after line $anchor.
98
- # Use a temp file for atomic replace.
99
- tmp=$(mktemp)
100
- awk -v anchor="$anchor" '
101
- NR == anchor { print; print "**Type**: technical"; next }
102
- { print }
103
- ' "$f" > "$tmp"
104
- mv "$tmp" "$f"
105
- done
106
- shopt -u nullglob
107
-
108
- if [ "$APPLY" -eq 1 ]; then
109
- exit 0
110
- fi
111
-
112
- if [ "$drift" -eq 1 ]; then
113
- exit 1
114
- fi
115
-
116
- exit 0
@@ -1,274 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # Behavioural test for packages/itil/scripts/catchup-scan.sh — the P080
4
- # Phase 2 `--catchup` worklist scanner. Exercises the script against a
5
- # synthetic `.verifying.md` / `.closed.md` fixture corpus and asserts on
6
- # its emitted worklist (stdout) + summary (stderr) — NOT on SKILL.md prose.
7
- # This is a genuinely behavioural test per ADR-052: it runs the target and
8
- # asserts on its outputs, covering acceptance criterion 6 (fixture +
9
- # idempotency assertion).
10
- #
11
- # Coverage:
12
- # - CATCHUP emitted for a post-fix ticket with `## Reported Upstream` and
13
- # no lifecycle log entry for the target state.
14
- # - SKIP/already-logged (idempotency) for a ticket whose
15
- # `## Upstream Lifecycle Updates` log already records the target state.
16
- # - Silent skip for tickets without a `## Reported Upstream` section.
17
- # - SKIP/out-of-band for out-of-band / mailbox disclosure paths.
18
- # - Open / Known-Error / Parked tickets are out of the catchup corpus.
19
- # - Dual-tolerant flat-layout AND per-state subdir layout (RFC-002).
20
- # - --ticket restricts the scan; bad args / missing dir error cleanly.
21
- #
22
- # @problem P080 (Phase 2 --catchup)
23
- # @adr ADR-052 (behavioural-tests default)
24
-
25
- setup() {
26
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
27
- SCRIPT="$REPO_ROOT/packages/itil/scripts/catchup-scan.sh"
28
- FIX="$BATS_TEST_TMPDIR/problems"
29
- mkdir -p "$FIX"
30
- }
31
-
32
- # Write a ticket with a `## Reported Upstream` section. Args:
33
- # $1 = filename (relative to $FIX)
34
- # $2 = upstream URL (or "" for none)
35
- # $3 = disclosure path text
36
- make_reported_ticket() {
37
- local path="$FIX/$1" url="$2" disclosure="$3"
38
- mkdir -p "$(dirname "$path")"
39
- {
40
- echo "# Problem: fixture"
41
- echo ""
42
- echo "**Status**: fixture"
43
- echo ""
44
- echo "## Reported Upstream"
45
- echo ""
46
- [ -n "$url" ] && echo "- **URL**: $url"
47
- echo "- **Reported**: 2026-01-01"
48
- echo "- **Disclosure path**: $disclosure"
49
- } > "$path"
50
- }
51
-
52
- # Append an `## Upstream Lifecycle Updates` log entry recording a target.
53
- append_lifecycle_log() {
54
- local path="$FIX/$1" transition="$2"
55
- {
56
- echo ""
57
- echo "## Upstream Lifecycle Updates"
58
- echo ""
59
- echo "- **2026-02-02** — $transition"
60
- echo " - **Disclosure path**: posted-comment"
61
- } >> "$path"
62
- }
63
-
64
- # Write a ticket carrying an inbound `**Origin**: inbound-reported (<ref>)`
65
- # field (ADR-076) — the INBOUND surface. Args:
66
- # $1 = filename (relative to $FIX)
67
- # $2 = origin-paren content (e.g. "#63", "bbstats#195", "relayed from other projects")
68
- make_inbound_ticket() {
69
- local path="$FIX/$1" ref="$2"
70
- mkdir -p "$(dirname "$path")"
71
- {
72
- echo "# Problem: inbound fixture"
73
- echo ""
74
- echo "**Status**: fixture"
75
- echo "**Origin**: inbound-reported ($ref)"
76
- echo ""
77
- echo "## Description"
78
- echo ""
79
- echo "fixture body"
80
- } > "$path"
81
- }
82
-
83
- @test "catchup-scan: emits CATCHUP for a closed ticket with Reported Upstream and no lifecycle log" {
84
- make_reported_ticket "113-foo.closed.md" "https://github.com/o/r/issues/5" "public issue"
85
- run bash "$SCRIPT" --problems-dir "$FIX"
86
- [ "$status" -eq 0 ]
87
- [[ "$output" == *"CATCHUP P113 https://github.com/o/r/issues/5 state=closed transition=Verifying->Closed"* ]]
88
- }
89
-
90
- @test "catchup-scan: emits CATCHUP for a verifying ticket with the KE->Verifying transition" {
91
- make_reported_ticket "090-bar.verifying.md" "https://github.com/o/r/issues/9" "public issue"
92
- run bash "$SCRIPT" --problems-dir "$FIX"
93
- [ "$status" -eq 0 ]
94
- [[ "$output" == *"CATCHUP P090 https://github.com/o/r/issues/9 state=verifying transition=KE->Verifying"* ]]
95
- }
96
-
97
- @test "catchup-scan: idempotency — SKIP/already-logged when log records the target state (closed)" {
98
- make_reported_ticket "113-foo.closed.md" "https://github.com/o/r/issues/5" "public issue"
99
- append_lifecycle_log "113-foo.closed.md" "Verification Pending → Closed"
100
- run bash "$SCRIPT" --problems-dir "$FIX"
101
- [ "$status" -eq 0 ]
102
- [[ "$output" == *"SKIP P113 https://github.com/o/r/issues/5 reason=already-logged"* ]]
103
- [[ "$output" != *"CATCHUP P113"* ]]
104
- }
105
-
106
- @test "catchup-scan: idempotency — SKIP/already-logged when log records the target state (verifying)" {
107
- make_reported_ticket "090-bar.verifying.md" "https://github.com/o/r/issues/9" "public issue"
108
- append_lifecycle_log "090-bar.verifying.md" "Known Error → Verification Pending"
109
- run bash "$SCRIPT" --problems-dir "$FIX"
110
- [ "$status" -eq 0 ]
111
- [[ "$output" == *"SKIP P090 https://github.com/o/r/issues/9 reason=already-logged"* ]]
112
- [[ "$output" != *"CATCHUP P090"* ]]
113
- }
114
-
115
- @test "catchup-scan: idempotency is re-run-safe — a logged closed ticket alongside a fresh one" {
116
- make_reported_ticket "113-done.closed.md" "https://github.com/o/r/issues/5" "public issue"
117
- append_lifecycle_log "113-done.closed.md" "Verification Pending → Closed"
118
- make_reported_ticket "114-fresh.closed.md" "https://github.com/o/r/issues/6" "public issue"
119
- run bash "$SCRIPT" --problems-dir "$FIX"
120
- [ "$status" -eq 0 ]
121
- [[ "$output" == *"SKIP P113 https://github.com/o/r/issues/5 reason=already-logged"* ]]
122
- [[ "$output" == *"CATCHUP P114 https://github.com/o/r/issues/6"* ]]
123
- }
124
-
125
- @test "catchup-scan: silently skips tickets with no Reported Upstream section" {
126
- mkdir -p "$FIX"
127
- printf '# Problem\n\n**Status**: Closed\n\nNo upstream link here.\n' > "$FIX/200-nolink.closed.md"
128
- run bash "$SCRIPT" --problems-dir "$FIX"
129
- [ "$status" -eq 0 ]
130
- [[ "$output" != *"P200"* ]]
131
- }
132
-
133
- @test "catchup-scan: SKIP/out-of-band for a mailbox / out-of-band disclosure path" {
134
- make_reported_ticket "150-sec.closed.md" "" "drafted-and-saved (mailbox / out-of-band)"
135
- run bash "$SCRIPT" --problems-dir "$FIX"
136
- [ "$status" -eq 0 ]
137
- [[ "$output" == *"SKIP P150"* ]]
138
- [[ "$output" == *"reason=out-of-band"* ]]
139
- }
140
-
141
- @test "catchup-scan: Open / Known-Error / Parked tickets are out of the catchup corpus" {
142
- make_reported_ticket "300-open.open.md" "https://github.com/o/r/issues/3" "public issue"
143
- make_reported_ticket "301-ke.known-error.md" "https://github.com/o/r/issues/4" "public issue"
144
- make_reported_ticket "302-park.parked.md" "https://github.com/o/r/issues/7" "public issue"
145
- run bash "$SCRIPT" --problems-dir "$FIX"
146
- [ "$status" -eq 0 ]
147
- [[ "$output" != *"P300"* ]]
148
- [[ "$output" != *"P301"* ]]
149
- [[ "$output" != *"P302"* ]]
150
- }
151
-
152
- @test "catchup-scan: dual-tolerant — per-state subdir layout (RFC-002) is scanned" {
153
- make_reported_ticket "closed/113-sub.md" "https://github.com/o/r/issues/8" "public issue"
154
- run bash "$SCRIPT" --problems-dir "$FIX"
155
- [ "$status" -eq 0 ]
156
- [[ "$output" == *"CATCHUP P113 https://github.com/o/r/issues/8 state=closed transition=Verifying->Closed"* ]]
157
- }
158
-
159
- @test "catchup-scan: --ticket restricts the scan to one ticket" {
160
- make_reported_ticket "113-foo.closed.md" "https://github.com/o/r/issues/5" "public issue"
161
- make_reported_ticket "114-bar.closed.md" "https://github.com/o/r/issues/6" "public issue"
162
- run bash "$SCRIPT" --problems-dir "$FIX" --ticket P114
163
- [ "$status" -eq 0 ]
164
- [[ "$output" == *"CATCHUP P114"* ]]
165
- [[ "$output" != *"P113"* ]]
166
- }
167
-
168
- @test "catchup-scan: SUMMARY line reports counts on stderr" {
169
- make_reported_ticket "113-foo.closed.md" "https://github.com/o/r/issues/5" "public issue"
170
- make_reported_ticket "114-bar.closed.md" "https://github.com/o/r/issues/6" "public issue"
171
- append_lifecycle_log "114-bar.closed.md" "Verification Pending → Closed"
172
- run bash -c "bash '$SCRIPT' --problems-dir '$FIX' 2>&1 1>/dev/null"
173
- [ "$status" -eq 0 ]
174
- [[ "$output" == *"SUMMARY scanned=2 catchup=1 skip-logged=1 skip-out-of-band=0"* ]]
175
- }
176
-
177
- @test "catchup-scan: missing problems-dir exits 1 with error" {
178
- run bash "$SCRIPT" --problems-dir "$BATS_TEST_TMPDIR/does-not-exist"
179
- [ "$status" -eq 1 ]
180
- [[ "$output" == *"ERROR"* ]]
181
- }
182
-
183
- @test "catchup-scan: unknown argument exits 1" {
184
- run bash "$SCRIPT" --bogus
185
- [ "$status" -eq 1 ]
186
- [[ "$output" == *"ERROR"* ]]
187
- }
188
-
189
- @test "catchup-scan: --help prints usage and exits 0" {
190
- run bash "$SCRIPT" --help
191
- [ "$status" -eq 0 ]
192
- [[ "$output" == *"Usage:"* ]]
193
- [[ "$output" == *"--catchup"* ]] || [[ "$output" == *"catchup-scan"* ]]
194
- }
195
-
196
- # ── Inbound direction (P376) ────────────────────────────────────────────────
197
- # The scanner must ALSO enumerate inbound-reported tickets (`**Origin**:
198
- # inbound-reported (#NN)`, ADR-076) so the maintainer no longer hand-greps
199
- # them after each catchup run. Direction-tagged so the worklist stays
200
- # unambiguous; idempotency re-checks the `(inbound)`-tagged lifecycle log.
201
-
202
- @test "catchup-scan: emits inbound CATCHUP for a verifying ticket with Origin inbound-reported (KE->Verifying)" {
203
- make_inbound_ticket "220-inbound.verifying.md" "#63"
204
- run bash "$SCRIPT" --problems-dir "$FIX"
205
- [ "$status" -eq 0 ]
206
- [[ "$output" == *"CATCHUP P220 inbound-#63 state=verifying transition=KE->Verifying direction=inbound"* ]]
207
- }
208
-
209
- @test "catchup-scan: emits inbound CATCHUP for a closed ticket with Origin inbound-reported (Verifying->Closed)" {
210
- make_inbound_ticket "211-inbound.closed.md" "#97"
211
- run bash "$SCRIPT" --problems-dir "$FIX"
212
- [ "$status" -eq 0 ]
213
- [[ "$output" == *"CATCHUP P211 inbound-#97 state=closed transition=Verifying->Closed direction=inbound"* ]]
214
- }
215
-
216
- @test "catchup-scan: inbound idempotency — SKIP/already-logged when an (inbound)-tagged log records the target" {
217
- make_inbound_ticket "220-inbound.verifying.md" "#63"
218
- append_lifecycle_log "220-inbound.verifying.md" "Known Error → Verification Pending (inbound)"
219
- run bash "$SCRIPT" --problems-dir "$FIX"
220
- [ "$status" -eq 0 ]
221
- [[ "$output" == *"SKIP P220 inbound-#63 reason=already-logged"* ]]
222
- [[ "$output" != *"CATCHUP P220"* ]]
223
- }
224
-
225
- @test "catchup-scan: inbound idempotency does NOT match an outbound-tagged log for the same target" {
226
- # A Closed log entry without (inbound) is the outbound leg's marker; the
227
- # inbound leg must still emit CATCHUP (its own verdict was never posted).
228
- make_inbound_ticket "228-inbound.closed.md" "#42"
229
- append_lifecycle_log "228-inbound.closed.md" "Verification Pending → Closed"
230
- run bash "$SCRIPT" --problems-dir "$FIX"
231
- [ "$status" -eq 0 ]
232
- [[ "$output" == *"CATCHUP P228 inbound-#42 state=closed transition=Verifying->Closed direction=inbound"* ]]
233
- }
234
-
235
- @test "catchup-scan: non-actionable Origin (no #NN) emits no inbound line" {
236
- make_inbound_ticket "300-relayed.verifying.md" "relayed from other projects"
237
- run bash "$SCRIPT" --problems-dir "$FIX"
238
- [ "$status" -eq 0 ]
239
- [[ "$output" != *"P300"* ]]
240
- }
241
-
242
- @test "catchup-scan: cross-repo inbound ref is preserved in the worklist line" {
243
- make_inbound_ticket "250-xrepo.closed.md" "bbstats#195"
244
- run bash "$SCRIPT" --problems-dir "$FIX"
245
- [ "$status" -eq 0 ]
246
- [[ "$output" == *"CATCHUP P250 inbound-bbstats#195 state=closed transition=Verifying->Closed direction=inbound"* ]]
247
- }
248
-
249
- @test "catchup-scan: a ticket with BOTH surfaces emits an outbound AND an inbound line" {
250
- make_reported_ticket "330-both.closed.md" "https://github.com/o/r/issues/5" "public issue"
251
- printf '**Origin**: inbound-reported (#71)\n' >> "$FIX/330-both.closed.md"
252
- run bash "$SCRIPT" --problems-dir "$FIX"
253
- [ "$status" -eq 0 ]
254
- [[ "$output" == *"CATCHUP P330 https://github.com/o/r/issues/5 state=closed transition=Verifying->Closed"* ]]
255
- [[ "$output" == *"CATCHUP P330 inbound-#71 state=closed transition=Verifying->Closed direction=inbound"* ]]
256
- }
257
-
258
- @test "catchup-scan: inbound worklist line stays within the ADR-038 150-byte budget" {
259
- make_inbound_ticket "999-long.closed.md" "averylongupstreamreponame/withdeepsubpath#123456"
260
- run bash "$SCRIPT" --problems-dir "$FIX"
261
- [ "$status" -eq 0 ]
262
- line="$(printf '%s\n' "$output" | grep '^CATCHUP P999')"
263
- [ -n "$line" ]
264
- [ "${#line}" -le 150 ]
265
- }
266
-
267
- @test "catchup-scan: inbound-only Open/Known-Error tickets are out of the catchup corpus" {
268
- make_inbound_ticket "400-open.open.md" "#12"
269
- make_inbound_ticket "401-ke.known-error.md" "#13"
270
- run bash "$SCRIPT" --problems-dir "$FIX"
271
- [ "$status" -eq 0 ]
272
- [[ "$output" != *"P400"* ]]
273
- [[ "$output" != *"P401"* ]]
274
- }