@windyroad/itil 0.61.1 → 0.61.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/package.json +7 -2
- package/agents/test/fixtures/proceed-new-genuinely-new.md +0 -43
- package/agents/test/fixtures/proceed-new-subtle-sibling.md +0 -47
- package/agents/test/fixtures/regression-p347-vs-p346.md +0 -54
- package/agents/test/hang-off-check.bats +0 -225
- package/hooks/test/block-list.bats +0 -153
- package/hooks/test/command-detect.bats +0 -181
- package/hooks/test/itil-assistant-output-gate.bats +0 -114
- package/hooks/test/itil-assistant-output-review.bats +0 -224
- package/hooks/test/itil-bash-polling-antipattern-detect.bats +0 -154
- package/hooks/test/itil-changeset-discipline.bats +0 -603
- package/hooks/test/itil-claude-space-protection.bats +0 -294
- package/hooks/test/itil-commit-trailer-transition-advisory.bats +0 -80
- package/hooks/test/itil-correction-detect.bats +0 -189
- package/hooks/test/itil-deferral-cadence-gate.bats +0 -187
- package/hooks/test/itil-fictional-defer-detect.bats +0 -292
- package/hooks/test/itil-fix-title-lifecycle-advisory.bats +0 -129
- package/hooks/test/itil-mid-loop-ask-detect.bats +0 -220
- package/hooks/test/itil-no-implement-draft-gate.bats +0 -210
- package/hooks/test/itil-pending-questions-surface.bats +0 -307
- package/hooks/test/itil-readme-refresh-discipline.bats +0 -642
- package/hooks/test/itil-rfc-oversight-nudge.bats +0 -83
- package/hooks/test/itil-rfc-trailer-advisory.bats +0 -375
- package/hooks/test/itil-story-mirror-migration-nudge.bats +0 -122
- package/hooks/test/manage-problem-enforce-create.bats +0 -424
- package/hooks/test/p057-staging-trap-detect.bats +0 -231
- package/hooks/test/pre-publish-intake-gate.bats +0 -144
- package/hooks/test/runtime-sid-marker.bats +0 -90
- package/hooks/test/session-id.bats +0 -370
- package/scripts/migrate-problems-add-type.sh +0 -116
- package/scripts/test/catchup-scan.bats +0 -274
- package/scripts/test/check-afk-accept-eligible.bats +0 -310
- package/scripts/test/check-fail-soft-skip-discipline.bats +0 -172
- package/scripts/test/check-fix-rfc-trace.bats +0 -164
- package/scripts/test/check-locale-discipline.bats +0 -291
- package/scripts/test/check-problems-readme-budget.bats +0 -192
- package/scripts/test/check-rfc-has-stories.bats +0 -69
- package/scripts/test/check-rfc-rejected-alternatives.bats +0 -108
- package/scripts/test/check-rfc-stories-ratified.bats +0 -82
- package/scripts/test/check-upstream-responses.bats +0 -503
- package/scripts/test/classify-readme-drift.bats +0 -392
- package/scripts/test/derive-first-dispatch.bats +0 -274
- package/scripts/test/derive-release-vehicle.bats +0 -454
- package/scripts/test/detect-unratified-stories-maps.bats +0 -60
- package/scripts/test/dual-tolerant-glob-rfc-002-t2.bats +0 -309
- package/scripts/test/effort-tally.bats +0 -170
- package/scripts/test/evaluate-relevance.bats +0 -773
- package/scripts/test/kind-a-commands.bats +0 -46
- package/scripts/test/mark-create-gate.bats +0 -59
- package/scripts/test/mark-story-oversight-confirmed.bats +0 -53
- package/scripts/test/migrate-problems-add-type.bats +0 -280
- package/scripts/test/migrate-story-status-mirror.bats +0 -167
- package/scripts/test/no-type-regression-guard.bats +0 -74
- package/scripts/test/oversight-mirror-corpus-lint.bats +0 -150
- package/scripts/test/plugin-exercise-index.bats +0 -386
- package/scripts/test/plugin-maturity-doc-lint.bats +0 -470
- package/scripts/test/plugin-maturity-populate.bats +0 -631
- package/scripts/test/plugin-maturity-render.bats +0 -469
- package/scripts/test/plugin-validate-ci-gate.bats +0 -208
- package/scripts/test/reconcile-readme.bats +0 -1007
- package/scripts/test/reconcile-rfcs.bats +0 -496
- package/scripts/test/reconcile-stories.bats +0 -173
- package/scripts/test/reconcile-story-maps.bats +0 -74
- package/scripts/test/release-watch-poll-loop.bats +0 -180
- package/scripts/test/resolve-governance-plugin-dirs.bats +0 -78
- package/scripts/test/rfc-stories-extension.bats +0 -175
- package/scripts/test/skill-invocations.bats +0 -535
- package/scripts/test/skill-md-dual-tolerant-coverage-rfc-002-t3.bats +0 -374
- package/scripts/test/story-oversight-lib.bats +0 -190
- package/scripts/test/update-jtbd-references-related-problems.bats +0 -178
- package/scripts/test/update-problem-references-section.bats +0 -242
- package/scripts/test/update-problem-rfcs-section.bats +0 -242
- package/scripts/test/update-references-section-sibling-helpers.bats +0 -80
- package/scripts/test/update-rfc-commits-section.bats +0 -77
- package/scripts/test/verify-iter-summary.bats +0 -196
- package/scripts/test/working-the-problem-traversal.bats +0 -116
- package/skills/capture-problem/test/capture-problem-step-1-5b-jtbd-trace.bats +0 -398
- package/skills/capture-problem/test/capture-problem.bats +0 -389
- package/skills/capture-story/test/capture-story-behavioural.bats +0 -317
- package/skills/capture-story-map/test/capture-story-map-behavioural.bats +0 -98
- package/skills/close-incident/test/close-incident-contract.bats +0 -146
- package/skills/link-incident/test/link-incident-contract.bats +0 -125
- package/skills/list-incidents/test/list-incidents-contract.bats +0 -115
- package/skills/list-problems/test/list-problems-contract.bats +0 -100
- package/skills/list-stories/test/list-stories-contract.bats +0 -127
- package/skills/list-story-maps/test/list-story-maps-contract.bats +0 -46
- package/skills/manage-incident/test/manage-incident-adr-044-contract.bats +0 -206
- package/skills/manage-incident/test/manage-incident-close-forwarder.bats +0 -67
- package/skills/manage-incident/test/manage-incident-link-forwarder.bats +0 -67
- package/skills/manage-incident/test/manage-incident-list-forwarder.bats +0 -68
- package/skills/manage-incident/test/manage-incident-mitigate-forwarder.bats +0 -66
- package/skills/manage-incident/test/manage-incident-restore-forwarder.bats +0 -66
- package/skills/manage-incident/test/manage-incident.bats +0 -171
- package/skills/manage-problem/test/manage-problem-adr-044-step4-derive-first.bats +0 -151
- package/skills/manage-problem/test/manage-problem-auto-migrate-step.bats +0 -53
- package/skills/manage-problem/test/manage-problem-concern-boundary.bats +0 -64
- package/skills/manage-problem/test/manage-problem-effort-buckets.bats +0 -56
- package/skills/manage-problem/test/manage-problem-external-root-cause-detection.bats +0 -119
- package/skills/manage-problem/test/manage-problem-first-run-intake-prompt.bats +0 -43
- package/skills/manage-problem/test/manage-problem-git-mv-restage-reminder.bats +0 -48
- package/skills/manage-problem/test/manage-problem-id-collision-guard.bats +0 -39
- package/skills/manage-problem/test/manage-problem-list-forwarder.bats +0 -66
- package/skills/manage-problem/test/manage-problem-next-id-origin-lookup.bats +0 -50
- package/skills/manage-problem/test/manage-problem-no-prose-options.bats +0 -74
- package/skills/manage-problem/test/manage-problem-output-formatting.bats +0 -30
- package/skills/manage-problem/test/manage-problem-parked-and-cache.bats +0 -73
- package/skills/manage-problem/test/manage-problem-readme-refresh-on-transition.bats +0 -62
- package/skills/manage-problem/test/manage-problem-readme-tie-break-order.bats +0 -318
- package/skills/manage-problem/test/manage-problem-readme-vq-sort-order.bats +0 -206
- package/skills/manage-problem/test/manage-problem-release-vehicle-seed.bats +0 -83
- package/skills/manage-problem/test/manage-problem-review-forwarder.bats +0 -71
- package/skills/manage-problem/test/manage-problem-step-9d-recovery-path.bats +0 -97
- package/skills/manage-problem/test/manage-problem-transition-forwarder.bats +0 -96
- package/skills/manage-problem/test/manage-problem-transitive-dependencies.bats +0 -365
- package/skills/manage-problem/test/manage-problem-verification-detection.bats +0 -64
- package/skills/manage-problem/test/manage-problem-verification-pending.bats +0 -114
- package/skills/manage-problem/test/manage-problem-work-forwarder.bats +0 -88
- package/skills/manage-story/test/manage-story-contract.bats +0 -174
- package/skills/manage-story-map/test/manage-story-map-contract.bats +0 -63
- package/skills/mitigate-incident/test/mitigate-incident-contract.bats +0 -258
- package/skills/reconcile-readme/test/reconcile-readme-contract.bats +0 -201
- package/skills/report-upstream/test/report-upstream-contract.bats +0 -394
- package/skills/restore-incident/test/restore-incident-contract.bats +0 -170
- package/skills/review-problems/test/inbound-channels-cache-shape.bats +0 -127
- package/skills/review-problems/test/inbound-discovery-contract.bats +0 -383
- package/skills/review-problems/test/jtbd-301-verdict-shape-contract.bats +0 -225
- package/skills/review-problems/test/review-problems-contract.bats +0 -235
- package/skills/review-problems/test/review-problems-likely-verified-cell-shape.bats +0 -229
- package/skills/scaffold-intake/test/scaffold-intake-contract.bats +0 -126
- package/skills/scaffold-intake/test/scaffold-intake-fixture.bats +0 -164
- package/skills/scaffold-intake/test/scaffold-intake-secrets-absent.bats +0 -87
- package/skills/transition-problem/test/transition-problem-contract.bats +0 -285
- package/skills/transition-problems/test/transition-problems-contract.bats +0 -331
- package/skills/update-upstream/test/update-upstream-contract.bats +0 -375
- package/skills/work-problem/test/work-problem-contract.bats +0 -294
- package/skills/work-problems/test/work-problems-above-appetite-remediation.bats +0 -139
- package/skills/work-problems/test/work-problems-adr-013-rule-6-p352-amendment.bats +0 -166
- package/skills/work-problems/test/work-problems-auto-migrate-step.bats +0 -57
- package/skills/work-problems/test/work-problems-cost-logging.bats +0 -109
- package/skills/work-problems/test/work-problems-deviation-candidate-shape.bats +0 -121
- package/skills/work-problems/test/work-problems-first-run-intake-prompt.bats +0 -36
- package/skills/work-problems/test/work-problems-inter-iteration-verify.bats +0 -59
- package/skills/work-problems/test/work-problems-mid-loop-userpromptsubmit-handler.bats +0 -69
- package/skills/work-problems/test/work-problems-no-mid-loop-asking.bats +0 -192
- package/skills/work-problems/test/work-problems-p341-pre-all-done-gate.bats +0 -122
- package/skills/work-problems/test/work-problems-p342-r007-derive-then-pass-flags.bats +0 -170
- package/skills/work-problems/test/work-problems-p342-retro-auto-ticket-carveout.bats +0 -120
- package/skills/work-problems/test/work-problems-preflight-failure-handling.bats +0 -248
- package/skills/work-problems/test/work-problems-preflight-session-continuity.bats +0 -139
- package/skills/work-problems/test/work-problems-preflight.bats +0 -69
- package/skills/work-problems/test/work-problems-release-cadence.bats +0 -63
- package/skills/work-problems/test/work-problems-step-0-iter-error-staleness.bats +0 -93
- package/skills/work-problems/test/work-problems-step-0b-cache-staleness-behavioural.bats +0 -138
- package/skills/work-problems/test/work-problems-step-0c-deferred-placeholder-staleness-behavioural.bats +0 -238
- package/skills/work-problems/test/work-problems-step-0d-outbound-responses-staleness-behavioural.bats +0 -174
- package/skills/work-problems/test/work-problems-step-2-5-routing.bats +0 -80
- package/skills/work-problems/test/work-problems-step-2-5b-cross-halt-routing.bats +0 -149
- package/skills/work-problems/test/work-problems-step-3-5-jtbd-ratification-predicate.bats +0 -191
- package/skills/work-problems/test/work-problems-step-5-bats-polling-discipline.bats +0 -91
- package/skills/work-problems/test/work-problems-step-5-delegation.bats +0 -333
- package/skills/work-problems/test/work-problems-step-5-idle-timeout-sigterm.bats +0 -421
- package/skills/work-problems/test/work-problems-step-5-is-error-transient-halt.bats +0 -278
- package/skills/work-problems/test/work-problems-step-5-iter-changeset-required.bats +0 -95
- package/skills/work-problems/test/work-problems-step-5-prompt-body-re-grounding.bats +0 -128
- package/skills/work-problems/test/work-problems-step-5-stream-timeout-salvage.bats +0 -251
- package/skills/work-problems/test/work-problems-step-6-5-always-drain.bats +0 -203
- package/skills/work-problems/test/work-problems-step-6-5-cache-refresh-chain.bats +0 -174
- package/skills/work-problems/test/work-problems-step-6-5-fix-and-continue.bats +0 -254
- package/skills/work-problems/test/work-problems-step-6-5-postrelease-kv-callback.bats +0 -209
- package/skills/work-problems/test/work-problems-stop-condition-questions.bats +0 -85
|
@@ -1,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
|
-
}
|