@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,93 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Contract-assertion bats for work-problems Step 0 session-continuity
3
- # detection — staleness filter on .afk-run-state/iter-*.json error markers
4
- # (per P333).
5
- #
6
- # Per ADR-037 SKILL.md is a contract document; these assertions check the
7
- # contract strings the skill prose authoritatively pins for the staleness
8
- # filter that distinguishes load-bearing partial-work markers from stale
9
- # residuals. Companion to work-problems-preflight-session-continuity.bats
10
- # (which covers the broader signal-enumeration + interactive/AFK routing
11
- # invariants from P109).
12
- #
13
- # Cross-reference:
14
- # @problem P333 (Step 0 session-continuity has no staleness filter on
15
- # .afk-run-state/iter-*.json error markers — stale residuals
16
- # indefinitely false-positive the halt/ask gate)
17
- # @problem P109 (parent session-continuity detection extension)
18
- # ADR-019 (AFK orchestrator preflight — extension surface)
19
- # ADR-032 (subprocess artefact contract — iter-*.json shape)
20
- # ADR-037 (skill testing strategy — contract-assertion framing)
21
- # @jtbd JTBD-006 (Progress the Backlog While I'm Away — false-positive
22
- # halts violate the AFK forward-progress outcome)
23
-
24
- setup() {
25
- SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
26
- SKILL_FILE="${SKILL_DIR}/SKILL.md"
27
- }
28
-
29
- @test "SKILL.md exists" {
30
- [ -f "$SKILL_FILE" ]
31
- }
32
-
33
- @test "SKILL.md Step 0 cites P333 as the staleness-filter driver" {
34
- # Contract criterion: the staleness predicate is traceable to its
35
- # driver ticket so a reader can find the failure mode the filter
36
- # closes.
37
- run grep -nE "P333" "$SKILL_FILE"
38
- [ "$status" -eq 0 ]
39
- }
40
-
41
- @test "SKILL.md Step 0 names the staleness filter for iter-*.json markers" {
42
- # Contract criterion: the iter-*.json error-marker row names a
43
- # staleness / freshness predicate (not merely the is_error /
44
- # api_error_status field check).
45
- run grep -niE "stale|staleness|freshness|fresh per" "$SKILL_FILE"
46
- [ "$status" -eq 0 ]
47
- }
48
-
49
- @test "SKILL.md Step 0 names mtime + HEAD-commit-time as the staleness primitive" {
50
- # Contract criterion: the staleness predicate is specified as mtime
51
- # vs HEAD-commit-time (the engineering primitive). The "more
52
- # permissive of two" disjunction is asserted in a sibling test below.
53
- run grep -niE "mtime" "$SKILL_FILE"
54
- [ "$status" -eq 0 ]
55
- run grep -niE "HEAD.commit|HEAD's commit|commit.time" "$SKILL_FILE"
56
- [ "$status" -eq 0 ]
57
- }
58
-
59
- @test "SKILL.md Step 0 names the 24h fallback for the staleness predicate" {
60
- # Contract criterion: the "OR within 24h" disjunction protects the
61
- # fresh-repo-no-commits-since-marker edge case.
62
- run grep -niE "24h|24 hour|last 24" "$SKILL_FILE"
63
- [ "$status" -eq 0 ]
64
- }
65
-
66
- @test "SKILL.md Step 0 names the silent-skip directive for stale residuals" {
67
- # Contract criterion: the action on stale-classified markers is
68
- # silent-skip, not halt-with-report. This is the directional
69
- # asymmetry the contract pins (fresh = halt, stale = skip).
70
- run grep -niE "skip.*silent|silently.*skip|silent skip" "$SKILL_FILE"
71
- [ "$status" -eq 0 ]
72
- }
73
-
74
- @test "SKILL.md Step 0 retains the is_error / api_error_status field names alongside the staleness filter" {
75
- # Contract criterion: the existing P109 signal field-name contract
76
- # MUST coexist with the new staleness predicate — the staleness
77
- # filter narrows the load-bearing signal, it does not replace the
78
- # field check.
79
- run grep -niE "is_error.*true|api_error_status" "$SKILL_FILE"
80
- [ "$status" -eq 0 ]
81
- }
82
-
83
- @test "SKILL.md Step 0 names the iter-summary annotation for skipped stale markers" {
84
- # Contract criterion per JTBD-006 audit-trail outcome (line 34 of
85
- # docs/jtbd/developer/JTBD-006.md): "every action taken during AFK
86
- # mode should be traceable via git history and the progress
87
- # summary". A silent-skip without an iter-summary annotation drops
88
- # an action from the audit trail; the contract names the annotation
89
- # shape so a stale-skipped-but-actually-load-bearing marker is
90
- # recoverable on user return.
91
- run grep -niE "stale iter.error|stale.*marker.*skip|iter.error.markers? skipped" "$SKILL_FILE"
92
- [ "$status" -eq 0 ]
93
- }
@@ -1,138 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # Step 0b behavioural fixture per ADR-062 § JTBD-006 driver:
4
- # work-problems pre-flights /wr-itil:review-problems when the
5
- # upstream inbound-discovery cache is stale or missing. The
6
- # staleness decision lives in
7
- # `packages/itil/lib/check-upstream-cache-staleness.sh::should_promote_inbound_discovery_preflight`
8
- # so the SKILL.md Step 0b prose is a thin source-and-call wrapper
9
- # around a behaviorally-testable shell function (P081 / user
10
- # feedback: prefer behavioural over structural-grep tests).
11
- #
12
- # Cases covered:
13
- # 1. No channels-config file → "no-channels-config" (downstream-adopter non-obligation, ADR-062 § Downstream-adopter contract).
14
- # 2. Channels-config present, cache file absent → "first-run-cache-absent".
15
- # 3. Channels-config present, cache present, last_checked null → "first-run-last-checked-null".
16
- # 4. Channels-config present, cache fresh within TTL → "fresh-within-ttl".
17
- # 5. Channels-config present, cache older than TTL → "ttl-expiry" (with age + ttl in the reason).
18
- # 6. Custom ttl_seconds in channels-config is respected (not hardcoded default).
19
-
20
- setup() {
21
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
22
- HELPER="$REPO_ROOT/packages/itil/lib/check-upstream-cache-staleness.sh"
23
-
24
- FIXTURE="$(mktemp -d)"
25
- mkdir -p "$FIXTURE/docs/problems"
26
- }
27
-
28
- teardown() {
29
- rm -rf "$FIXTURE"
30
- }
31
-
32
- @test "helper exists at the contracted path" {
33
- [ -f "$HELPER" ]
34
- }
35
-
36
- @test "case 1: no channels-config → no-channels-config" {
37
- # shellcheck disable=SC1090
38
- source "$HELPER"
39
- run should_promote_inbound_discovery_preflight "$FIXTURE"
40
- [ "$status" -eq 0 ]
41
- [ "$output" = "no-channels-config" ]
42
- }
43
-
44
- @test "case 2: channels-config present, cache absent → first-run-cache-absent" {
45
- cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
46
- { "channels": [], "ttl_seconds": 86400 }
47
- EOF
48
- # shellcheck disable=SC1090
49
- source "$HELPER"
50
- run should_promote_inbound_discovery_preflight "$FIXTURE"
51
- [ "$status" -eq 0 ]
52
- [ "$output" = "first-run-cache-absent" ]
53
- }
54
-
55
- @test "case 3: cache present, last_checked null → first-run-last-checked-null" {
56
- cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
57
- { "channels": [], "ttl_seconds": 86400 }
58
- EOF
59
- cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<'EOF'
60
- { "last_checked": null, "channels": [] }
61
- EOF
62
- # shellcheck disable=SC1090
63
- source "$HELPER"
64
- run should_promote_inbound_discovery_preflight "$FIXTURE"
65
- [ "$status" -eq 0 ]
66
- [ "$output" = "first-run-last-checked-null" ]
67
- }
68
-
69
- @test "case 4: cache fresh within TTL → fresh-within-ttl (silent-pass)" {
70
- cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
71
- { "channels": [], "ttl_seconds": 86400 }
72
- EOF
73
- # last_checked 1 hour ago — well within 24h TTL.
74
- local recent_iso
75
- recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
76
- cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<EOF
77
- { "last_checked": "$recent_iso", "channels": [] }
78
- EOF
79
- # shellcheck disable=SC1090
80
- source "$HELPER"
81
- run should_promote_inbound_discovery_preflight "$FIXTURE"
82
- [ "$status" -eq 0 ]
83
- [ "$output" = "fresh-within-ttl" ]
84
- }
85
-
86
- @test "case 5: cache older than TTL → ttl-expiry with age + ttl in the reason" {
87
- cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
88
- { "channels": [], "ttl_seconds": 86400 }
89
- EOF
90
- # last_checked 2 days ago — past 24h TTL.
91
- local stale_iso
92
- stale_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=2)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
93
- cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<EOF
94
- { "last_checked": "$stale_iso", "channels": [] }
95
- EOF
96
- # shellcheck disable=SC1090
97
- source "$HELPER"
98
- run should_promote_inbound_discovery_preflight "$FIXTURE"
99
- [ "$status" -eq 0 ]
100
- # Format: "ttl-expiry age=<N>s ttl=<M>s"
101
- [[ "$output" =~ ^ttl-expiry\ age=[0-9]+s\ ttl=86400s$ ]]
102
- }
103
-
104
- @test "case 6: custom ttl_seconds is honored (not hardcoded default)" {
105
- # 1-hour TTL; last_checked 90 minutes ago → stale under the custom TTL,
106
- # but would be FRESH under the 86400s default. Confirms the helper reads
107
- # ttl_seconds from channels-config rather than hardcoding 86400.
108
- cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
109
- { "channels": [], "ttl_seconds": 3600 }
110
- EOF
111
- local mid_iso
112
- mid_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(minutes=90)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
113
- cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<EOF
114
- { "last_checked": "$mid_iso", "channels": [] }
115
- EOF
116
- # shellcheck disable=SC1090
117
- source "$HELPER"
118
- run should_promote_inbound_discovery_preflight "$FIXTURE"
119
- [ "$status" -eq 0 ]
120
- [[ "$output" =~ ^ttl-expiry\ age=[0-9]+s\ ttl=3600s$ ]]
121
- }
122
-
123
- @test "case 7: missing ttl_seconds field defaults to 86400 (24h)" {
124
- cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
125
- { "channels": [] }
126
- EOF
127
- # last_checked 1 hour ago — fresh under the default 86400s TTL.
128
- local recent_iso
129
- recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
130
- cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<EOF
131
- { "last_checked": "$recent_iso", "channels": [] }
132
- EOF
133
- # shellcheck disable=SC1090
134
- source "$HELPER"
135
- run should_promote_inbound_discovery_preflight "$FIXTURE"
136
- [ "$status" -eq 0 ]
137
- [ "$output" = "fresh-within-ttl" ]
138
- }
@@ -1,238 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # Step 0c behavioural fixture per P271:
4
- # work-problems pre-flights /wr-itil:review-problems when deferred-placeholder
5
- # tickets accumulate AND the docs/problems/README.md "Last reviewed" line is
6
- # stale. Mirrors the Step 0b cache-staleness shape (helper-in-lib + 5-outcome
7
- # enum + behavioural bats) so the SKILL.md Step 0c prose stays a thin
8
- # source-and-call wrapper around a behaviorally-testable shell function.
9
- #
10
- # Trigger rule — two-axis AND per P271 § Recommended fix shape (architect
11
- # Condition 2 — both axes are load-bearing; either alone over-fires):
12
- # - count of deferred-placeholder tickets ≥ 3 (signal: there is work to
13
- # re-rate), AND
14
- # - README.md "Last reviewed" line-3 age > 7 days (signal: cadence has
15
- # slipped).
16
- #
17
- # Cases covered:
18
- # 1. No deferred placeholders → "no-deferred-placeholders"
19
- # 2. Count below threshold (1 or 2) → "below-threshold count=<N> threshold=3"
20
- # 3. Count ≥ 3 + README absent → "no-readme count=<N>"
21
- # 4. Count ≥ 3 + README fresh (< 7 days) → "fresh-readme count=<N> age=<X>s threshold=<Y>s"
22
- # 5. Count ≥ 3 + README stale (> 7 days) → "stale-readme count=<N> age=<X>s threshold=<Y>s"
23
- # 6. Dual-tolerant glob (per ADR-031 RFC-002 migration window — both flat
24
- # docs/problems/<NNN>-*.<state>.md AND per-state docs/problems/<state>/<NNN>-*.md
25
- # contribute to count)
26
-
27
- setup() {
28
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
29
- HELPER="$REPO_ROOT/packages/itil/lib/check-deferred-placeholder-staleness.sh"
30
-
31
- FIXTURE="$(mktemp -d)"
32
- mkdir -p "$FIXTURE/docs/problems/open"
33
- mkdir -p "$FIXTURE/docs/problems/known-error"
34
- }
35
-
36
- teardown() {
37
- rm -rf "$FIXTURE"
38
- }
39
-
40
- # Helper — write a problem ticket with the deferred-placeholder marker.
41
- write_deferred_ticket() {
42
- local path="$1"
43
- cat > "$path" <<'EOF'
44
- # Problem 999: test
45
-
46
- **Status**: Open
47
- **Priority**: 3 (Medium) — Impact: 3 x Likelihood: 1 (deferred — re-rate at next /wr-itil:review-problems)
48
- **Effort**: M (deferred — re-rate at next /wr-itil:review-problems)
49
-
50
- ## Description
51
-
52
- test fixture
53
- EOF
54
- }
55
-
56
- # Helper — write a non-deferred (already-rated) ticket.
57
- write_rated_ticket() {
58
- local path="$1"
59
- cat > "$path" <<'EOF'
60
- # Problem 998: test
61
-
62
- **Status**: Open
63
- **Priority**: 6 (Medium) — Impact: 3 x Likelihood: 2
64
- **Effort**: S
65
-
66
- ## Description
67
-
68
- test fixture
69
- EOF
70
- }
71
-
72
- # Helper — write a README.md with a known "Last reviewed" date on line 3.
73
- write_readme_with_date() {
74
- local path="$1"
75
- local iso_date="$2"
76
- cat > "$path" <<EOF
77
- # Problem Backlog
78
-
79
- > Last reviewed: $iso_date **review** — test fixture
80
- > Run \`/wr-itil:review-problems\` to refresh WSJF rankings.
81
-
82
- ## WSJF Rankings
83
- EOF
84
- }
85
-
86
- @test "helper exists at the contracted path" {
87
- [ -f "$HELPER" ]
88
- }
89
-
90
- @test "case 1: no deferred placeholders → no-deferred-placeholders" {
91
- write_rated_ticket "$FIXTURE/docs/problems/open/001-foo.md"
92
- write_rated_ticket "$FIXTURE/docs/problems/open/002-bar.md"
93
- # shellcheck disable=SC1090
94
- source "$HELPER"
95
- run should_promote_review_problems_dispatch "$FIXTURE"
96
- [ "$status" -eq 0 ]
97
- [ "$output" = "no-deferred-placeholders" ]
98
- }
99
-
100
- @test "case 2: count below threshold (1) → below-threshold" {
101
- write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
102
- write_rated_ticket "$FIXTURE/docs/problems/open/002-bar.md"
103
- # shellcheck disable=SC1090
104
- source "$HELPER"
105
- run should_promote_review_problems_dispatch "$FIXTURE"
106
- [ "$status" -eq 0 ]
107
- [[ "$output" =~ ^below-threshold\ count=1\ threshold=3$ ]]
108
- }
109
-
110
- @test "case 2b: count below threshold (2) → below-threshold" {
111
- write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
112
- write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
113
- # shellcheck disable=SC1090
114
- source "$HELPER"
115
- run should_promote_review_problems_dispatch "$FIXTURE"
116
- [ "$status" -eq 0 ]
117
- [[ "$output" =~ ^below-threshold\ count=2\ threshold=3$ ]]
118
- }
119
-
120
- @test "case 3: count ≥ 3 + README absent → no-readme (first-run dispatch trigger)" {
121
- write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
122
- write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
123
- write_deferred_ticket "$FIXTURE/docs/problems/open/003-baz.md"
124
- # No README written.
125
- # shellcheck disable=SC1090
126
- source "$HELPER"
127
- run should_promote_review_problems_dispatch "$FIXTURE"
128
- [ "$status" -eq 0 ]
129
- [[ "$output" =~ ^no-readme\ count=3$ ]]
130
- }
131
-
132
- @test "case 4: count ≥ 3 + README fresh (< 7 days) → fresh-readme silent-pass" {
133
- write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
134
- write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
135
- write_deferred_ticket "$FIXTURE/docs/problems/open/003-baz.md"
136
- # README dated 3 days ago — fresh under 7-day threshold.
137
- local recent_iso
138
- recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=3)).strftime('%Y-%m-%d'))")"
139
- write_readme_with_date "$FIXTURE/docs/problems/README.md" "$recent_iso"
140
- # shellcheck disable=SC1090
141
- source "$HELPER"
142
- run should_promote_review_problems_dispatch "$FIXTURE"
143
- [ "$status" -eq 0 ]
144
- [[ "$output" =~ ^fresh-readme\ count=3\ age=[0-9]+s\ threshold=604800s$ ]]
145
- }
146
-
147
- @test "case 5: count ≥ 3 + README stale (> 7 days) → stale-readme (dispatch trigger)" {
148
- write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
149
- write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
150
- write_deferred_ticket "$FIXTURE/docs/problems/open/003-baz.md"
151
- # README dated 14 days ago — stale under 7-day threshold.
152
- local stale_iso
153
- stale_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=14)).strftime('%Y-%m-%d'))")"
154
- write_readme_with_date "$FIXTURE/docs/problems/README.md" "$stale_iso"
155
- # shellcheck disable=SC1090
156
- source "$HELPER"
157
- run should_promote_review_problems_dispatch "$FIXTURE"
158
- [ "$status" -eq 0 ]
159
- [[ "$output" =~ ^stale-readme\ count=3\ age=[0-9]+s\ threshold=604800s$ ]]
160
- }
161
-
162
- @test "case 6: dual-tolerant glob — per-state subdir layout (ADR-031 post-migration)" {
163
- # Per-state subdir tickets (post-RFC-002-migration shape — the dominant
164
- # shape in this monorepo).
165
- write_deferred_ticket "$FIXTURE/docs/problems/open/100-foo.md"
166
- write_deferred_ticket "$FIXTURE/docs/problems/open/101-bar.md"
167
- write_deferred_ticket "$FIXTURE/docs/problems/known-error/102-baz.md"
168
- # No README → first-run dispatch.
169
- # shellcheck disable=SC1090
170
- source "$HELPER"
171
- run should_promote_review_problems_dispatch "$FIXTURE"
172
- [ "$status" -eq 0 ]
173
- [[ "$output" =~ ^no-readme\ count=3$ ]]
174
- }
175
-
176
- @test "case 6b: dual-tolerant glob — flat layout (ADR-031 pre-migration window)" {
177
- # Flat-layout tickets (pre-RFC-002-migration shape — the legacy shape).
178
- write_deferred_ticket "$FIXTURE/docs/problems/200-foo.open.md"
179
- write_deferred_ticket "$FIXTURE/docs/problems/201-bar.open.md"
180
- write_deferred_ticket "$FIXTURE/docs/problems/202-baz.known-error.md"
181
- # No README → first-run dispatch.
182
- # shellcheck disable=SC1090
183
- source "$HELPER"
184
- run should_promote_review_problems_dispatch "$FIXTURE"
185
- [ "$status" -eq 0 ]
186
- [[ "$output" =~ ^no-readme\ count=3$ ]]
187
- }
188
-
189
- @test "case 6c: dual-tolerant glob — mixed layout (RFC-002 migration in progress)" {
190
- # Mixed-layout tickets — both shapes contribute to the count.
191
- write_deferred_ticket "$FIXTURE/docs/problems/open/100-foo.md"
192
- write_deferred_ticket "$FIXTURE/docs/problems/200-bar.open.md"
193
- write_deferred_ticket "$FIXTURE/docs/problems/known-error/300-baz.md"
194
- # shellcheck disable=SC1090
195
- source "$HELPER"
196
- run should_promote_review_problems_dispatch "$FIXTURE"
197
- [ "$status" -eq 0 ]
198
- [[ "$output" =~ ^no-readme\ count=3$ ]]
199
- }
200
-
201
- @test "case 7: README missing 'Last reviewed' line → no-readme (defensive fallback)" {
202
- write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
203
- write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
204
- write_deferred_ticket "$FIXTURE/docs/problems/open/003-baz.md"
205
- # README exists but no "Last reviewed:" marker on line 3.
206
- cat > "$FIXTURE/docs/problems/README.md" <<'EOF'
207
- # Problem Backlog
208
-
209
- Some other line that does not have the Last reviewed marker.
210
-
211
- ## WSJF Rankings
212
- EOF
213
- # shellcheck disable=SC1090
214
- source "$HELPER"
215
- run should_promote_review_problems_dispatch "$FIXTURE"
216
- [ "$status" -eq 0 ]
217
- # Defensive: parse failure routes to no-readme (forces a fresh dispatch
218
- # rather than silently silent-passing on malformed README).
219
- [[ "$output" =~ ^no-readme\ count=3$ ]]
220
- }
221
-
222
- @test "case 8: closed and verifying tickets do NOT contribute to count" {
223
- # Only open + known-error tickets are eligible re-rate candidates.
224
- # .verifying.md and .closed.md tickets carry no WSJF (excluded from
225
- # dev-work ranking per ADR-022); their deferred-placeholders must not
226
- # influence the dispatch.
227
- mkdir -p "$FIXTURE/docs/problems/closed"
228
- mkdir -p "$FIXTURE/docs/problems/verifying"
229
- write_deferred_ticket "$FIXTURE/docs/problems/closed/100-foo.md"
230
- write_deferred_ticket "$FIXTURE/docs/problems/verifying/101-bar.md"
231
- write_deferred_ticket "$FIXTURE/docs/problems/open/102-baz.md"
232
- # shellcheck disable=SC1090
233
- source "$HELPER"
234
- run should_promote_review_problems_dispatch "$FIXTURE"
235
- [ "$status" -eq 0 ]
236
- # Only the open/ ticket counts → below threshold.
237
- [[ "$output" =~ ^below-threshold\ count=1\ threshold=3$ ]]
238
- }
@@ -1,174 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # Step 0d behavioural fixture per P220 + ADR-062 § JTBD-006 driver:
4
- # work-problems pre-flights /wr-itil:check-upstream-responses when the
5
- # outbound-responses cache is stale or missing AND there exist local
6
- # tickets carrying `## Reported Upstream` back-link sections. The
7
- # staleness decision lives in
8
- # `packages/itil/lib/check-outbound-responses-staleness.sh::should_promote_outbound_responses_preflight`
9
- # so the SKILL.md Step 0d prose is a thin source-and-call wrapper
10
- # around a behaviorally-testable shell function (P081 / user feedback:
11
- # prefer behavioural over structural-grep tests).
12
- #
13
- # Cases covered (symmetric to Step 0b cases plus the back-link discovery
14
- # axis that replaces channels-config):
15
- # 1. No tickets with `## Reported Upstream` section → "no-back-link-tickets"
16
- # (downstream-adopter non-obligation; analogue to no-channels-config).
17
- # 2. Back-link ticket present, cache absent → "first-run-cache-absent".
18
- # 3. Back-link ticket present, cache present, last_checked null → "first-run-last-checked-null".
19
- # 4. Back-link ticket present, cache fresh within TTL → "fresh-within-ttl".
20
- # 5. Back-link ticket present, cache older than TTL → "ttl-expiry" (with age + ttl in the reason).
21
- # 6. Custom ttl_seconds in cache honored (not hardcoded default).
22
- # 7. Missing ttl_seconds field defaults to 86400 (24h symmetric with inbound).
23
-
24
- setup() {
25
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
26
- HELPER="$REPO_ROOT/packages/itil/lib/check-outbound-responses-staleness.sh"
27
-
28
- FIXTURE="$(mktemp -d)"
29
- mkdir -p "$FIXTURE/docs/problems"
30
- }
31
-
32
- teardown() {
33
- rm -rf "$FIXTURE"
34
- }
35
-
36
- # Helper: write a back-link ticket fixture under docs/problems/.
37
- _write_backlink_ticket() {
38
- local ticket_path="$1"
39
- cat > "$ticket_path" <<'EOF'
40
- # Problem 999: example back-link fixture
41
-
42
- **Status**: Open
43
-
44
- ## Description
45
-
46
- Fixture for Step 0d behavioural test.
47
-
48
- ## Reported Upstream
49
-
50
- - **Repo**: example/upstream
51
- - **URL**: https://github.com/example/upstream/issues/999
52
- - **Filed**: 2026-06-08
53
- EOF
54
- }
55
-
56
- @test "helper exists at the contracted path" {
57
- [ -f "$HELPER" ]
58
- }
59
-
60
- @test "case 1: no back-link tickets → no-back-link-tickets" {
61
- # shellcheck disable=SC1090
62
- source "$HELPER"
63
- run should_promote_outbound_responses_preflight "$FIXTURE"
64
- [ "$status" -eq 0 ]
65
- [ "$output" = "no-back-link-tickets" ]
66
- }
67
-
68
- @test "case 1b: tickets without ## Reported Upstream section → no-back-link-tickets" {
69
- cat > "$FIXTURE/docs/problems/100-no-back-link.open.md" <<'EOF'
70
- # Problem 100: no upstream link
71
-
72
- ## Description
73
-
74
- Local-only ticket.
75
- EOF
76
- # shellcheck disable=SC1090
77
- source "$HELPER"
78
- run should_promote_outbound_responses_preflight "$FIXTURE"
79
- [ "$status" -eq 0 ]
80
- [ "$output" = "no-back-link-tickets" ]
81
- }
82
-
83
- @test "case 2: back-link ticket present, cache absent → first-run-cache-absent" {
84
- _write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
85
- # shellcheck disable=SC1090
86
- source "$HELPER"
87
- run should_promote_outbound_responses_preflight "$FIXTURE"
88
- [ "$status" -eq 0 ]
89
- [ "$output" = "first-run-cache-absent" ]
90
- }
91
-
92
- @test "case 2b: back-link in per-state subdir layout (RFC-002) is discovered" {
93
- mkdir -p "$FIXTURE/docs/problems/known-error"
94
- _write_backlink_ticket "$FIXTURE/docs/problems/known-error/220-cadence-gap.md"
95
- # shellcheck disable=SC1090
96
- source "$HELPER"
97
- run should_promote_outbound_responses_preflight "$FIXTURE"
98
- [ "$status" -eq 0 ]
99
- [ "$output" = "first-run-cache-absent" ]
100
- }
101
-
102
- @test "case 3: cache present, last_checked null → first-run-last-checked-null" {
103
- _write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
104
- cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<'EOF'
105
- { "last_checked": null, "tickets": {} }
106
- EOF
107
- # shellcheck disable=SC1090
108
- source "$HELPER"
109
- run should_promote_outbound_responses_preflight "$FIXTURE"
110
- [ "$status" -eq 0 ]
111
- [ "$output" = "first-run-last-checked-null" ]
112
- }
113
-
114
- @test "case 4: cache fresh within TTL → fresh-within-ttl (silent-pass)" {
115
- _write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
116
- # last_checked 1 hour ago — well within 24h default TTL.
117
- local recent_iso
118
- recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
119
- cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<EOF
120
- { "last_checked": "$recent_iso", "tickets": {} }
121
- EOF
122
- # shellcheck disable=SC1090
123
- source "$HELPER"
124
- run should_promote_outbound_responses_preflight "$FIXTURE"
125
- [ "$status" -eq 0 ]
126
- [ "$output" = "fresh-within-ttl" ]
127
- }
128
-
129
- @test "case 5: cache older than TTL → ttl-expiry with age + ttl in the reason" {
130
- _write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
131
- # last_checked 2 days ago — past 24h default TTL.
132
- local stale_iso
133
- stale_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=2)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
134
- cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<EOF
135
- { "last_checked": "$stale_iso", "tickets": {} }
136
- EOF
137
- # shellcheck disable=SC1090
138
- source "$HELPER"
139
- run should_promote_outbound_responses_preflight "$FIXTURE"
140
- [ "$status" -eq 0 ]
141
- # Format: "ttl-expiry age=<N>s ttl=<M>s"
142
- [[ "$output" =~ ^ttl-expiry\ age=[0-9]+s\ ttl=86400s$ ]]
143
- }
144
-
145
- @test "case 6: custom ttl_seconds in cache is honored (not hardcoded default)" {
146
- # 1-hour TTL; last_checked 90 minutes ago → stale under the custom TTL,
147
- # but would be FRESH under the 86400s default. Confirms the helper reads
148
- # ttl_seconds from cache rather than hardcoding 86400.
149
- _write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
150
- local mid_iso
151
- mid_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(minutes=90)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
152
- cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<EOF
153
- { "last_checked": "$mid_iso", "tickets": {}, "ttl_seconds": 3600 }
154
- EOF
155
- # shellcheck disable=SC1090
156
- source "$HELPER"
157
- run should_promote_outbound_responses_preflight "$FIXTURE"
158
- [ "$status" -eq 0 ]
159
- [[ "$output" =~ ^ttl-expiry\ age=[0-9]+s\ ttl=3600s$ ]]
160
- }
161
-
162
- @test "case 7: missing ttl_seconds defaults to 86400 (symmetric with inbound)" {
163
- _write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
164
- local recent_iso
165
- recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
166
- cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<EOF
167
- { "last_checked": "$recent_iso", "tickets": {} }
168
- EOF
169
- # shellcheck disable=SC1090
170
- source "$HELPER"
171
- run should_promote_outbound_responses_preflight "$FIXTURE"
172
- [ "$status" -eq 0 ]
173
- [ "$output" = "fresh-within-ttl" ]
174
- }