@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,46 +0,0 @@
1
- #!/usr/bin/env bats
2
- # P317 / RFC-009 T2 + ADR-049: the KIND A wrapper commands resolve their
3
- # canonical lib RELATIVE TO THE SCRIPT (`$(dirname)/../lib`), so they work in an
4
- # adopter install — not just the source monorepo where `source packages/...`
5
- # happened to resolve. Behavioural: simulate an install tree, invoke from a
6
- # FOREIGN cwd, assert clean lib resolution.
7
-
8
- setup() {
9
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
10
- INSTALL="$(mktemp -d)"
11
- mkdir -p "$INSTALL/scripts" "$INSTALL/lib" "$INSTALL/bin"
12
- cp "$REPO_ROOT/packages/itil/scripts/run-migrate-problems-layout.sh" "$INSTALL/scripts/" 2>/dev/null || true
13
- cp "$REPO_ROOT/packages/itil/scripts/run-check-upstream-cache-staleness.sh" "$INSTALL/scripts/" 2>/dev/null || true
14
- cp "$REPO_ROOT/packages/itil/bin/wr-itil-migrate-problems-layout" "$INSTALL/bin/" 2>/dev/null || true
15
- cp "$REPO_ROOT/packages/itil/bin/wr-itil-check-upstream-cache-staleness" "$INSTALL/bin/" 2>/dev/null || true
16
- cp "$REPO_ROOT"/packages/itil/lib/*.sh "$INSTALL/lib/" 2>/dev/null || true
17
- FOREIGN="$(mktemp -d)" # adopter repo cwd — no packages/ tree
18
- }
19
-
20
- teardown() {
21
- rm -rf "$INSTALL" "$FOREIGN"
22
- }
23
-
24
- @test "wr-itil-migrate-problems-layout resolves its lib from a foreign cwd, no-ops on empty dir (P317)" {
25
- cd "$FOREIGN"
26
- run bash "$INSTALL/bin/wr-itil-migrate-problems-layout" "$FOREIGN"
27
- [ "$status" -eq 0 ]
28
- [[ "$output" != *"No such file"* ]]
29
- [[ "$output" != *"command not found"* ]]
30
- }
31
-
32
- @test "wr-itil-check-upstream-cache-staleness resolves its lib from a foreign cwd (P317)" {
33
- cd "$FOREIGN"
34
- run bash "$INSTALL/bin/wr-itil-check-upstream-cache-staleness" "$FOREIGN"
35
- [ "$status" -eq 0 ]
36
- [[ "$output" != *"No such file"* ]]
37
- [[ "$output" != *"command not found"* ]]
38
- [[ "$output" != *"migrate_problems_to_per_state_layout: command not found"* ]]
39
- }
40
-
41
- @test "the direct script (not just the shim) also resolves its lib from a foreign cwd (P317)" {
42
- cd "$FOREIGN"
43
- run bash "$INSTALL/scripts/run-migrate-problems-layout.sh" "$FOREIGN"
44
- [ "$status" -eq 0 ]
45
- [[ "$output" != *"No such file"* ]]
46
- }
@@ -1,59 +0,0 @@
1
- #!/usr/bin/env bats
2
- # P317 / RFC-009 T1 + ADR-049: the create-gate marker commands resolve their
3
- # sibling libs RELATIVE TO THE SCRIPT (adopter-safe), not relative to cwd. The
4
- # bug they fix: SKILLs did `source packages/itil/hooks/lib/*.sh`, which only
5
- # resolves in the source monorepo and breaks in adopter installs.
6
- #
7
- # Behavioural — simulates an adopter install by copying the shipped script +
8
- # lib tree to a temp dir in the SAME relative layout, then invokes from a
9
- # FOREIGN cwd (an "adopter repo" with no packages/ tree) and asserts success.
10
-
11
- setup() {
12
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
13
- INSTALL="$(mktemp -d)"
14
- mkdir -p "$INSTALL/scripts" "$INSTALL/hooks/lib" "$INSTALL/bin"
15
- cp "$REPO_ROOT/packages/itil/scripts/mark-create-gate.sh" "$INSTALL/scripts/" 2>/dev/null || true
16
- cp "$REPO_ROOT/packages/itil/scripts/mark-rfc-capture-gate.sh" "$INSTALL/scripts/" 2>/dev/null || true
17
- cp "$REPO_ROOT/packages/itil/bin/wr-itil-mark-create-gate" "$INSTALL/bin/" 2>/dev/null || true
18
- cp "$REPO_ROOT/packages/itil/bin/wr-itil-mark-rfc-capture-gate" "$INSTALL/bin/" 2>/dev/null || true
19
- cp "$REPO_ROOT"/packages/itil/hooks/lib/*.sh "$INSTALL/hooks/lib/" 2>/dev/null || true
20
- FOREIGN="$(mktemp -d)" # an adopter repo cwd — no packages/ tree
21
- MARKERS="$(mktemp -d)" # empty announce-marker dir so candidates = CLAUDE_SESSION_ID only
22
- SID="p317-test-$$-${RANDOM}"
23
- }
24
-
25
- teardown() {
26
- rm -rf "$INSTALL" "$FOREIGN" "$MARKERS"
27
- rm -f "/tmp/manage-problem-grep-$SID" "/tmp/wr-itil-rfc-capture-grep-$SID"
28
- }
29
-
30
- @test "mark-create-gate.sh runs from a foreign cwd, resolving libs from its own location (P317)" {
31
- cd "$FOREIGN"
32
- run env CLAUDE_SESSION_ID="$SID" SESSION_MARKER_DIR="$MARKERS" bash "$INSTALL/scripts/mark-create-gate.sh"
33
- [ "$status" -eq 0 ]
34
- [[ "$output" != *"No such file"* ]]
35
- [[ "$output" != *"command not found"* ]]
36
- [ -f "/tmp/manage-problem-grep-$SID" ]
37
- }
38
-
39
- @test "wr-itil-mark-create-gate shim dispatches the script from a foreign cwd (P317/ADR-049)" {
40
- cd "$FOREIGN"
41
- run env CLAUDE_SESSION_ID="$SID" SESSION_MARKER_DIR="$MARKERS" bash "$INSTALL/bin/wr-itil-mark-create-gate"
42
- [ "$status" -eq 0 ]
43
- [ -f "/tmp/manage-problem-grep-$SID" ]
44
- }
45
-
46
- @test "mark-rfc-capture-gate.sh writes the RFC-tier marker from a foreign cwd (P317)" {
47
- cd "$FOREIGN"
48
- run env CLAUDE_SESSION_ID="$SID" SESSION_MARKER_DIR="$MARKERS" bash "$INSTALL/scripts/mark-rfc-capture-gate.sh"
49
- [ "$status" -eq 0 ]
50
- [[ "$output" != *"No such file"* ]]
51
- [ -f "/tmp/wr-itil-rfc-capture-grep-$SID" ]
52
- }
53
-
54
- @test "wr-itil-mark-rfc-capture-gate shim dispatches from a foreign cwd (P317/ADR-049)" {
55
- cd "$FOREIGN"
56
- run env CLAUDE_SESSION_ID="$SID" SESSION_MARKER_DIR="$MARKERS" bash "$INSTALL/bin/wr-itil-mark-rfc-capture-gate"
57
- [ "$status" -eq 0 ]
58
- [ -f "/tmp/wr-itil-rfc-capture-grep-$SID" ]
59
- }
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Behavioural test for mark-story-oversight-confirmed.sh (ADR-090 ratify write-path).
3
- # Writes `confirmed` + the content fingerprint into a story (md frontmatter) or a
4
- # story-map (HTML meta). After marking, is_story_map_ratified is true; a later
5
- # content edit drifts it back to not-ratified.
6
- #
7
- # @adr ADR-090
8
- # @problem P404 (Phase 2)
9
-
10
- setup() {
11
- REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
12
- SCRIPT="${REPO_ROOT}/packages/itil/scripts/mark-story-oversight-confirmed.sh"
13
- # shellcheck source=/dev/null
14
- source "${REPO_ROOT}/packages/itil/lib/story-oversight.sh"
15
- TMPD="$(mktemp -d)"
16
- }
17
- teardown() { rm -rf "$TMPD"; }
18
-
19
- @test "mark: md story with no marker → ratified after mark" {
20
- printf -- '---\nstatus: accepted\n---\n# body\n' > "$TMPD/s.md"
21
- run bash "$SCRIPT" "$TMPD/s.md"; [ "$status" -eq 0 ]
22
- run is_story_map_ratified "$TMPD/s.md"; [ "$status" -eq 0 ]
23
- }
24
-
25
- @test "mark: md story with existing unconfirmed marker → confirmed + ratified" {
26
- printf -- '---\nstatus: accepted\nhuman-oversight: unconfirmed\n---\n# body\n' > "$TMPD/s.md"
27
- bash "$SCRIPT" "$TMPD/s.md"
28
- grep -qE '^human-oversight:[[:space:]]*confirmed' "$TMPD/s.md"
29
- run is_story_map_ratified "$TMPD/s.md"; [ "$status" -eq 0 ]
30
- # no duplicate marker line left behind
31
- [ "$(grep -cE '^human-oversight:' "$TMPD/s.md")" -eq 1 ]
32
- }
33
-
34
- @test "mark: idempotent — marking twice stays ratified, single marker" {
35
- printf -- '---\nstatus: accepted\n---\n# body\n' > "$TMPD/s.md"
36
- bash "$SCRIPT" "$TMPD/s.md"; bash "$SCRIPT" "$TMPD/s.md"
37
- run is_story_map_ratified "$TMPD/s.md"; [ "$status" -eq 0 ]
38
- [ "$(grep -cE '^oversight-hash:' "$TMPD/s.md")" -eq 1 ]
39
- }
40
-
41
- @test "mark: drift — mark then edit body → not ratified" {
42
- printf -- '---\nstatus: accepted\n---\n# body\n' > "$TMPD/s.md"
43
- bash "$SCRIPT" "$TMPD/s.md"
44
- printf -- '---\nstatus: accepted\nhuman-oversight: confirmed\n---\n# body EDITED\n' > "$TMPD/s.md"
45
- run is_story_map_ratified "$TMPD/s.md"; [ "$status" -ne 0 ]
46
- }
47
-
48
- @test "mark: HTML map → ratified after mark" {
49
- printf -- '<!doctype html>\n<head><title>map</title></head>\n<body><h1>map</h1></body>\n' > "$TMPD/m.html"
50
- run bash "$SCRIPT" "$TMPD/m.html"; [ "$status" -eq 0 ]
51
- grep -qE '<meta[^>]*name="human-oversight"[^>]*content="confirmed"' "$TMPD/m.html"
52
- run is_story_map_ratified "$TMPD/m.html"; [ "$status" -eq 0 ]
53
- }
@@ -1,280 +0,0 @@
1
- #!/usr/bin/env bats
2
-
3
- # @problem P170 — Slice 4 B7.T2 (item 8b): bulk-migrate existing
4
- # problem tickets to the type-tag schema with default `type: technical`.
5
- # Script-driven, idempotent, no per-ticket judgement (per ADR-060
6
- # § Type-tag schema migration line; architect finding 10 split).
7
- #
8
- # @adr ADR-060 (type-tag schema introduction; Phase 1 item 8b)
9
- # @adr ADR-052 (behavioural bats default; observable file-state
10
- # assertions, not source greps per P081)
11
- # @adr ADR-014 (single-purpose script; one mechanical migration)
12
- #
13
- # Contract:
14
- # - Input: a problems-dir containing `<NNN>-*.<status>.md` files.
15
- # - Diagnose mode (default): exit 0 if every ticket carries
16
- # `**Type**: <value>` body field; exit 1 if any ticket needs
17
- # migration (tickets needing migration listed on stdout, one per
18
- # line, ≤150 bytes per ADR-038 progressive disclosure budget).
19
- # - Apply mode (--apply flag): inserts `**Type**: technical` after
20
- # the LAST present body field marker among
21
- # `**Status**` / `**Reported**` / `**Priority**` / `**Effort**` /
22
- # `**WSJF**`. Idempotent (re-running is no-op).
23
- # - Tickets with no recognisable header field block are skipped with
24
- # a `SKIP` line on stderr (does not fail the run).
25
- # - Default value: `technical` per ADR-060 line 92.
26
-
27
- setup() {
28
- SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
29
- SCRIPT="$SCRIPTS_DIR/migrate-problems-add-type.sh"
30
- FIXTURE_DIR="$(mktemp -d)"
31
- }
32
-
33
- teardown() {
34
- rm -rf "$FIXTURE_DIR"
35
- }
36
-
37
- write_ticket() {
38
- local id="$1" slug="$2" status="$3" body="$4"
39
- local file="$FIXTURE_DIR/${id}-${slug}.${status}.md"
40
- printf '%s' "$body" > "$file"
41
- echo "$file"
42
- }
43
-
44
- # ── Existence + executable ──────────────────────────────────────────────────
45
-
46
- @test "migrate-problems-add-type: script exists" {
47
- [ -f "$SCRIPT" ]
48
- }
49
-
50
- @test "migrate-problems-add-type: script is executable" {
51
- [ -x "$SCRIPT" ]
52
- }
53
-
54
- # ── Diagnose mode (default) ──────────────────────────────────────────────────
55
-
56
- @test "diagnose: exit 0 when every ticket already carries Type field" {
57
- write_ticket "100" "foo" "open" "$(cat <<'EOF'
58
- # Problem 100: Foo
59
-
60
- **Status**: Open
61
- **Type**: technical
62
- EOF
63
- )"
64
- run bash "$SCRIPT" "$FIXTURE_DIR"
65
- [ "$status" -eq 0 ]
66
- }
67
-
68
- @test "diagnose: exit 1 when at least one ticket lacks Type field" {
69
- write_ticket "100" "foo" "open" "$(cat <<'EOF'
70
- # Problem 100: Foo
71
-
72
- **Status**: Open
73
- **WSJF**: 5.0
74
- EOF
75
- )"
76
- run bash "$SCRIPT" "$FIXTURE_DIR"
77
- [ "$status" -eq 1 ]
78
- }
79
-
80
- @test "diagnose: lists each ticket needing migration on stdout" {
81
- write_ticket "100" "foo" "open" "$(cat <<'EOF'
82
- # Problem 100: Foo
83
-
84
- **Status**: Open
85
- **WSJF**: 5.0
86
- EOF
87
- )"
88
- write_ticket "101" "bar" "closed" "$(cat <<'EOF'
89
- # Problem 101: Bar
90
-
91
- **Status**: Closed
92
- **Priority**: 6
93
- EOF
94
- )"
95
- run bash "$SCRIPT" "$FIXTURE_DIR"
96
- [ "$status" -eq 1 ]
97
- echo "$output" | grep -q '100-foo'
98
- echo "$output" | grep -q '101-bar'
99
- }
100
-
101
- @test "diagnose: read-only — does not mutate any ticket file" {
102
- ticket=$(write_ticket "100" "foo" "open" "$(cat <<'EOF'
103
- # Problem 100: Foo
104
-
105
- **Status**: Open
106
- **WSJF**: 5.0
107
- EOF
108
- )")
109
- hash_before=$(shasum "$ticket" | cut -d' ' -f1)
110
- run bash "$SCRIPT" "$FIXTURE_DIR"
111
- hash_after=$(shasum "$ticket" | cut -d' ' -f1)
112
- [ "$hash_before" = "$hash_after" ]
113
- }
114
-
115
- # ── Apply mode (--apply) ─────────────────────────────────────────────────────
116
-
117
- @test "apply: inserts Type: technical after WSJF line when WSJF present" {
118
- ticket=$(write_ticket "100" "foo" "open" "$(cat <<'EOF'
119
- # Problem 100: Foo
120
-
121
- **Status**: Open
122
- **WSJF**: 5.0
123
-
124
- ## Description
125
- EOF
126
- )")
127
- run bash "$SCRIPT" --apply "$FIXTURE_DIR"
128
- [ "$status" -eq 0 ]
129
- grep -q '^\*\*Type\*\*: technical$' "$ticket"
130
- # Type sits AFTER WSJF (highest field marker present).
131
- wsjf_line=$(grep -n '^\*\*WSJF\*\*:' "$ticket" | head -1 | cut -d: -f1)
132
- type_line=$(grep -n '^\*\*Type\*\*:' "$ticket" | head -1 | cut -d: -f1)
133
- [ "$type_line" -gt "$wsjf_line" ]
134
- }
135
-
136
- @test "apply: inserts Type after Effort when WSJF absent" {
137
- ticket=$(write_ticket "100" "foo" "open" "$(cat <<'EOF'
138
- # Problem 100: Foo
139
-
140
- **Status**: Open
141
- **Reported**: 2026-01-01
142
- **Priority**: 6
143
- **Effort**: M
144
-
145
- ## Description
146
- EOF
147
- )")
148
- run bash "$SCRIPT" --apply "$FIXTURE_DIR"
149
- [ "$status" -eq 0 ]
150
- effort_line=$(grep -n '^\*\*Effort\*\*:' "$ticket" | head -1 | cut -d: -f1)
151
- type_line=$(grep -n '^\*\*Type\*\*:' "$ticket" | head -1 | cut -d: -f1)
152
- [ "$type_line" -gt "$effort_line" ]
153
- }
154
-
155
- @test "apply: inserts Type after Priority when WSJF + Effort absent" {
156
- ticket=$(write_ticket "100" "foo" "closed" "$(cat <<'EOF'
157
- # Problem 100: Foo
158
-
159
- **Status**: Closed
160
- **Priority**: 6
161
-
162
- ## Description
163
- EOF
164
- )")
165
- run bash "$SCRIPT" --apply "$FIXTURE_DIR"
166
- [ "$status" -eq 0 ]
167
- priority_line=$(grep -n '^\*\*Priority\*\*:' "$ticket" | head -1 | cut -d: -f1)
168
- type_line=$(grep -n '^\*\*Type\*\*:' "$ticket" | head -1 | cut -d: -f1)
169
- [ "$type_line" -gt "$priority_line" ]
170
- }
171
-
172
- @test "apply: idempotent — re-running with Type already present is no-op" {
173
- ticket=$(write_ticket "100" "foo" "open" "$(cat <<'EOF'
174
- # Problem 100: Foo
175
-
176
- **Status**: Open
177
- **WSJF**: 5.0
178
-
179
- ## Description
180
- EOF
181
- )")
182
- bash "$SCRIPT" --apply "$FIXTURE_DIR"
183
- hash1=$(shasum "$ticket" | cut -d' ' -f1)
184
- bash "$SCRIPT" --apply "$FIXTURE_DIR"
185
- hash2=$(shasum "$ticket" | cut -d' ' -f1)
186
- [ "$hash1" = "$hash2" ]
187
- }
188
-
189
- @test "apply: default value is 'technical'" {
190
- ticket=$(write_ticket "100" "foo" "open" "$(cat <<'EOF'
191
- # Problem 100: Foo
192
-
193
- **Status**: Open
194
- **WSJF**: 5.0
195
- EOF
196
- )")
197
- bash "$SCRIPT" --apply "$FIXTURE_DIR"
198
- grep -q '^\*\*Type\*\*: technical$' "$ticket"
199
- ! grep -q '^\*\*Type\*\*: user-business$' "$ticket"
200
- }
201
-
202
- @test "apply: handles all five lifecycle file extensions" {
203
- i=100
204
- for state in open known-error verifying parked closed; do
205
- write_ticket "$i" "t-${state}" "$state" "$(cat <<EOF
206
- # Problem $i: stub
207
-
208
- **Status**: stub
209
- **WSJF**: 5.0
210
- EOF
211
- )" > /dev/null
212
- i=$((i+1))
213
- done
214
- bash "$SCRIPT" --apply "$FIXTURE_DIR"
215
- count=$(grep -l '^\*\*Type\*\*: technical$' "$FIXTURE_DIR"/*.md | wc -l | tr -d ' ')
216
- [ "$count" -eq 5 ]
217
- }
218
-
219
- @test "apply: preserves all original content (line-count grows by exactly 1 per migrated ticket)" {
220
- # Use printf with explicit trailing newline to mirror real ticket-file
221
- # convention (POSIX text-file trailing newline). awk normalizes EOF
222
- # to a trailing newline; fixture must match so the +1-line invariant
223
- # holds.
224
- ticket="$FIXTURE_DIR/100-foo.open.md"
225
- printf '%s\n' \
226
- '# Problem 100: Foo' \
227
- '' \
228
- '**Status**: Open' \
229
- '**WSJF**: 5.0' \
230
- '' \
231
- '## Description' \
232
- '' \
233
- 'Body text line.' \
234
- '' \
235
- '## Related' \
236
- '' \
237
- 'stub' > "$ticket"
238
- before=$(wc -l < "$ticket" | tr -d ' ')
239
- bash "$SCRIPT" --apply "$FIXTURE_DIR"
240
- after=$(wc -l < "$ticket" | tr -d ' ')
241
- [ "$after" -eq "$((before + 1))" ]
242
- # Original content sentinels survive.
243
- grep -q '^# Problem 100: Foo$' "$ticket"
244
- grep -q '^## Description$' "$ticket"
245
- grep -q '^Body text line\.$' "$ticket"
246
- grep -q '^## Related$' "$ticket"
247
- }
248
-
249
- # ── Skip / malformed handling ────────────────────────────────────────────────
250
-
251
- @test "apply: skips ticket with no recognisable header field block (warning to stderr)" {
252
- ticket=$(write_ticket "100" "foo" "open" "$(cat <<'EOF'
253
- # Problem 100: Foo
254
-
255
- Just a body, no field markers at all.
256
- EOF
257
- )")
258
- hash_before=$(shasum "$ticket" | cut -d' ' -f1)
259
- run bash "$SCRIPT" --apply "$FIXTURE_DIR"
260
- [ "$status" -eq 0 ]
261
- hash_after=$(shasum "$ticket" | cut -d' ' -f1)
262
- [ "$hash_before" = "$hash_after" ]
263
- # SKIP marker on stderr.
264
- echo "$output" | grep -qi 'skip'
265
- }
266
-
267
- # ── Default problems-dir ─────────────────────────────────────────────────────
268
-
269
- @test "diagnose: defaults problems-dir to ./docs/problems when no arg given" {
270
- cd "$FIXTURE_DIR"
271
- mkdir -p docs/problems
272
- cat > docs/problems/100-foo.open.md <<'EOF'
273
- # Problem 100: Foo
274
-
275
- **Status**: Open
276
- **Type**: technical
277
- EOF
278
- run bash "$SCRIPT"
279
- [ "$status" -eq 0 ]
280
- }
@@ -1,167 +0,0 @@
1
- #!/usr/bin/env bats
2
- # Behavioural tests for migrate-story-status-mirror.sh — the P474 one-time
3
- # migration that removes the redundant `**Status**:` body mirror from story
4
- # artefacts and carries their existing ratification forward.
5
- #
6
- # Why the mirror goes rather than getting normalised out of the hash: the body
7
- # line only repeats the frontmatter `status:` the fingerprint already excludes,
8
- # and every mirror discovered otherwise costs another normaliser rule (this was
9
- # the fourth in a family of three). Maintainer direction 2026-07-29 — kill the
10
- # class, not the instance.
11
- #
12
- # The load-bearing safety property is that this RE-FINGERPRINTS, never
13
- # RE-RATIFIES. `human-oversight: confirmed` records that a human confirmed
14
- # something and is never written here; `oversight-hash` only identifies WHICH
15
- # content that confirmation covered. Recomputing it over content whose only
16
- # delta is an excluded mechanical mirror removes zero ratified substance. The
17
- # `stored == hash(before)` gate is what makes that provable per artefact — drop
18
- # the gate and this becomes a blanket re-bless, i.e. the P348 hollow-marker
19
- # class.
20
- #
21
- # @problem P474 @adr ADR-090 ADR-101
22
-
23
- setup() {
24
- SCRIPTS="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
25
- MIGRATE="$SCRIPTS/migrate-story-status-mirror.sh"
26
- # shellcheck source=/dev/null
27
- source "$SCRIPTS/../lib/story-oversight.sh"
28
- TMPD="$(mktemp -d)"; cd "$TMPD"
29
- mkdir -p docs/stories/draft docs/stories/accepted
30
- }
31
- teardown() { cd /; rm -rf "$TMPD"; }
32
-
33
- # Independent mode probe for assertions. Shape-validated for the same reason the
34
- # script's own helper is: GNU `stat -f` prints a filesystem blob with exit 0, so
35
- # an exit-status-only chain silently accepts garbage as a mode.
36
- mode_of() {
37
- local m
38
- for m in "$(stat -c %a "$1" 2>/dev/null)" "$(stat -f %Lp "$1" 2>/dev/null)"; do
39
- case "$m" in [0-7][0-7][0-7] | [0-7][0-7][0-7][0-7]) printf '%s' "$m"; return 0 ;; esac
40
- done
41
- printf 'UNKNOWN'
42
- }
43
-
44
- # Write a story whose stored hash is valid for its current content.
45
- seed_ratified() {
46
- local path="$1" fm_status="$2" body_status="$3"
47
- printf -- '---\nstatus: %s\nstory-id: x\nhuman-oversight: confirmed\noversight-hash: PLACEHOLDER\n---\n\n# STORY-901: a story\n\n**Status**: %s\n**Reported**: 2026-07-29\n\n## User value\n\nvalue prose.\n\n## Acceptance criteria\n\n- [ ] a criterion\n' \
48
- "$fm_status" "$body_status" > "$path"
49
- local h; h="$(oversight_content_hash "$path")"
50
- sed -i.bak "s/oversight-hash: PLACEHOLDER/oversight-hash: $h/" "$path" && rm -f "$path.bak"
51
- }
52
-
53
- @test "removes the body Status mirror when it agrees with frontmatter" {
54
- seed_ratified docs/stories/draft/STORY-901-x.md draft draft
55
- run bash "$MIGRATE" docs/stories
56
- [ "$status" -eq 0 ]
57
- ! grep -qE '^\*\*Status\*\*:' docs/stories/draft/STORY-901-x.md
58
- # Everything else survives.
59
- grep -q '^\*\*Reported\*\*: 2026-07-29' docs/stories/draft/STORY-901-x.md
60
- grep -q 'value prose.' docs/stories/draft/STORY-901-x.md
61
- }
62
-
63
- @test "a currently-ratified story is still ratified after migration" {
64
- seed_ratified docs/stories/draft/STORY-901-x.md draft draft
65
- run is_story_map_ratified docs/stories/draft/STORY-901-x.md
66
- [ "$status" -eq 0 ]
67
- run bash "$MIGRATE" docs/stories
68
- [ "$status" -eq 0 ]
69
- run is_story_map_ratified docs/stories/draft/STORY-901-x.md
70
- [ "$status" -eq 0 ]
71
- }
72
-
73
- # The whole point: after migration, the accept transition must stop drifting.
74
- @test "after migration an accept transition does NOT drift the hash" {
75
- seed_ratified docs/stories/draft/STORY-901-x.md draft draft
76
- bash "$MIGRATE" docs/stories
77
- # Advance status the way manage-story does: frontmatter + a criterion tick.
78
- sed -i.bak 's/^status: draft/status: accepted/; s/- \[ \] a criterion/- [x] a criterion/' \
79
- docs/stories/draft/STORY-901-x.md && rm -f docs/stories/draft/STORY-901-x.md.bak
80
- run is_story_map_ratified docs/stories/draft/STORY-901-x.md
81
- [ "$status" -eq 0 ]
82
- }
83
-
84
- @test "SKIPS and REPORTS a story whose body Status carries extra information" {
85
- # `superseded (was: draft)` and `in-progress (2026-07-23)` both exist in the
86
- # real corpus — the line is carrying provenance the frontmatter does not, so
87
- # deleting it would lose content rather than de-duplicate it.
88
- seed_ratified docs/stories/draft/STORY-902-y.md superseded 'superseded (was: draft)'
89
- run bash "$MIGRATE" docs/stories
90
- [ "$status" -eq 0 ]
91
- grep -qE '^\*\*Status\*\*: superseded \(was: draft\)' docs/stories/draft/STORY-902-y.md
92
- [[ "$output" == *"STORY-902"* ]]
93
- [[ "$output" == *"disagree"* ]] || [[ "$output" == *"SKIP"* ]]
94
- }
95
-
96
- @test "does NOT revive an already-drifted story" {
97
- seed_ratified docs/stories/draft/STORY-903-z.md draft draft
98
- # Real substance edit after ratification → drifted before migration runs.
99
- printf '\nAn edit made after ratification.\n' >> docs/stories/draft/STORY-903-z.md
100
- run is_story_map_ratified docs/stories/draft/STORY-903-z.md
101
- [ "$status" -ne 0 ]
102
- run bash "$MIGRATE" docs/stories
103
- [ "$status" -eq 0 ]
104
- run is_story_map_ratified docs/stories/draft/STORY-903-z.md
105
- [ "$status" -ne 0 ]
106
- }
107
-
108
- @test "never writes human-oversight — an unconfirmed story stays unconfirmed" {
109
- printf -- '---\nstatus: draft\nhuman-oversight: unconfirmed\n---\n\n# STORY-904\n\n**Status**: draft\n\n## User value\n\nv.\n' \
110
- > docs/stories/draft/STORY-904-w.md
111
- run bash "$MIGRATE" docs/stories
112
- [ "$status" -eq 0 ]
113
- grep -q '^human-oversight: unconfirmed' docs/stories/draft/STORY-904-w.md
114
- ! grep -q '^human-oversight: confirmed' docs/stories/draft/STORY-904-w.md
115
- }
116
-
117
- # ADR-101: the post-hoc drain finds AFK-accepted stories via oversight-basis.
118
- # Migration must not strip it, or those stories stop surfacing for review.
119
- @test "preserves oversight-basis so the ADR-101 post-hoc drain still finds it" {
120
- seed_ratified docs/stories/accepted/STORY-905-v.md accepted accepted
121
- printf -- '%s\n' "$(sed 's/^human-oversight: confirmed/human-oversight: confirmed\noversight-basis: pure-decomposition/' docs/stories/accepted/STORY-905-v.md)" \
122
- > docs/stories/accepted/STORY-905-v.md
123
- run bash "$MIGRATE" docs/stories
124
- [ "$status" -eq 0 ]
125
- grep -q '^oversight-basis: pure-decomposition' docs/stories/accepted/STORY-905-v.md
126
- }
127
-
128
- @test "is idempotent — a second run changes nothing" {
129
- seed_ratified docs/stories/draft/STORY-901-x.md draft draft
130
- bash "$MIGRATE" docs/stories
131
- cp docs/stories/draft/STORY-901-x.md /tmp/after-first-$$.md
132
- run bash "$MIGRATE" docs/stories
133
- [ "$status" -eq 0 ]
134
- diff /tmp/after-first-$$.md docs/stories/draft/STORY-901-x.md
135
- rm -f /tmp/after-first-$$.md
136
- }
137
-
138
- @test "leaves README.md alone — it documents the template, it is not a story" {
139
- printf -- '# Stories\n\n**Status**: <status>\n\nTemplate docs.\n' > docs/stories/README.md
140
- run bash "$MIGRATE" docs/stories
141
- [ "$status" -eq 0 ]
142
- grep -qE '^\*\*Status\*\*: <status>' docs/stories/README.md
143
- [[ "$output" != *"README.md"* ]]
144
- }
145
-
146
- @test "reports the touched set so the re-fingerprint is auditable" {
147
- seed_ratified docs/stories/draft/STORY-901-x.md draft draft
148
- run bash "$MIGRATE" docs/stories
149
- [ "$status" -eq 0 ]
150
- [[ "$output" == *"STORY-901"* ]]
151
- }
152
-
153
- # The migration writes via mktemp+mv, and mktemp creates 0600. Without an
154
- # explicit mode carry-over every migrated story loses its group/other read bit.
155
- # `chmod --reference` is GNU-only, so the portable stat read is what makes this
156
- # hold on darwin — where the earlier --reference form silently fell through to a
157
- # hardcoded 644 while the call site claimed to preserve the mode.
158
- @test "preserves the story file's mode across the rewrite" {
159
- seed_ratified docs/stories/draft/STORY-906-mode.md draft draft
160
- chmod 640 docs/stories/draft/STORY-906-mode.md
161
- before="$(mode_of docs/stories/draft/STORY-906-mode.md)"
162
- [ "$before" = "640" ]
163
- run bash "$MIGRATE" docs/stories
164
- [ "$status" -eq 0 ]
165
- after="$(mode_of docs/stories/draft/STORY-906-mode.md)"
166
- [ "$after" = "640" ]
167
- }