@windyroad/itil 0.56.0-preview.877 → 0.56.0-preview.879
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/bin/wr-itil-check-rfc-stories-ratified +51 -0
- package/bin/wr-itil-detect-unratified-stories-maps +51 -0
- package/package.json +1 -1
- package/scripts/check-rfc-stories-ratified.sh +57 -0
- package/scripts/detect-unratified-stories-maps.sh +44 -0
- package/scripts/test/check-rfc-stories-ratified.bats +70 -0
- package/scripts/test/detect-unratified-stories-maps.bats +50 -0
- package/skills/manage-rfc/SKILL.md +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Generated by scripts/sync-shim-wrappers.sh from
|
|
3
|
+
# packages/shared/lib/shim-wrapper-template.sh. DO NOT EDIT individual
|
|
4
|
+
# shim files in packages/*/bin/wr-* directly; edit the template + run
|
|
5
|
+
# `npm run sync:shim-wrappers` to regenerate.
|
|
6
|
+
#
|
|
7
|
+
# Resolution (ADR-080):
|
|
8
|
+
# 1. If the wrapper's parent dir is semver-shaped, treat as installed-
|
|
9
|
+
# cache execution and resolve to the highest-version sibling's
|
|
10
|
+
# scripts/ entry below.
|
|
11
|
+
# 2. Otherwise (parent dir is e.g. `architect`), treat as source-
|
|
12
|
+
# monorepo execution and dispatch to own scripts/. The source-repo-
|
|
13
|
+
# guard `exec` is the anchor parsed by
|
|
14
|
+
# packages/retrospective/scripts/check-tarball-shipped-shims.sh.
|
|
15
|
+
# 3. If the cache parent contains zero semver-shaped siblings, exit
|
|
16
|
+
# 127 with a stderr message naming the cache parent (per SQ-080-2).
|
|
17
|
+
#
|
|
18
|
+
# @adr ADR-080 (highest-version-wins shim wrapper plugin scaffold)
|
|
19
|
+
# @adr ADR-049 (plugin-bundled scripts resolve via bin/ on $PATH — amended)
|
|
20
|
+
# @problem P343 (mid-session staleness window)
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
SHIM_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
25
|
+
OWN_VERSION_DIR="$(dirname "$SHIM_DIR")"
|
|
26
|
+
OWN_VERSION_NAME="$(basename "$OWN_VERSION_DIR")"
|
|
27
|
+
CACHE_PARENT="$(dirname "$OWN_VERSION_DIR")"
|
|
28
|
+
|
|
29
|
+
SEMVER_RE='^[0-9]+\.[0-9]+\.[0-9]+([-+][0-9A-Za-z.-]+)?$'
|
|
30
|
+
|
|
31
|
+
# Source-repo guard: own parent dir is NOT semver → dispatch to own scripts/.
|
|
32
|
+
if ! [[ "$OWN_VERSION_NAME" =~ $SEMVER_RE ]]; then
|
|
33
|
+
exec "$SHIM_DIR/../scripts/check-rfc-stories-ratified.sh" "$@"
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Cache execution: pick the highest-semver sibling under CACHE_PARENT.
|
|
37
|
+
HIGHEST=""
|
|
38
|
+
while IFS= read -r dir; do
|
|
39
|
+
name="$(basename "$dir")"
|
|
40
|
+
[[ "$name" =~ $SEMVER_RE ]] || continue
|
|
41
|
+
if [[ -z "$HIGHEST" ]] || [[ "$(printf '%s\n%s\n' "$HIGHEST" "$name" | sort -V | tail -1)" == "$name" ]]; then
|
|
42
|
+
HIGHEST="$name"
|
|
43
|
+
fi
|
|
44
|
+
done < <(find "$CACHE_PARENT" -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
|
|
45
|
+
|
|
46
|
+
if [[ -z "$HIGHEST" ]]; then
|
|
47
|
+
printf 'wr-shim: no cached versions in %s\n' "$CACHE_PARENT" >&2
|
|
48
|
+
exit 127
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
exec "$CACHE_PARENT/$HIGHEST/scripts/check-rfc-stories-ratified.sh" "$@"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Generated by scripts/sync-shim-wrappers.sh from
|
|
3
|
+
# packages/shared/lib/shim-wrapper-template.sh. DO NOT EDIT individual
|
|
4
|
+
# shim files in packages/*/bin/wr-* directly; edit the template + run
|
|
5
|
+
# `npm run sync:shim-wrappers` to regenerate.
|
|
6
|
+
#
|
|
7
|
+
# Resolution (ADR-080):
|
|
8
|
+
# 1. If the wrapper's parent dir is semver-shaped, treat as installed-
|
|
9
|
+
# cache execution and resolve to the highest-version sibling's
|
|
10
|
+
# scripts/ entry below.
|
|
11
|
+
# 2. Otherwise (parent dir is e.g. `architect`), treat as source-
|
|
12
|
+
# monorepo execution and dispatch to own scripts/. The source-repo-
|
|
13
|
+
# guard `exec` is the anchor parsed by
|
|
14
|
+
# packages/retrospective/scripts/check-tarball-shipped-shims.sh.
|
|
15
|
+
# 3. If the cache parent contains zero semver-shaped siblings, exit
|
|
16
|
+
# 127 with a stderr message naming the cache parent (per SQ-080-2).
|
|
17
|
+
#
|
|
18
|
+
# @adr ADR-080 (highest-version-wins shim wrapper plugin scaffold)
|
|
19
|
+
# @adr ADR-049 (plugin-bundled scripts resolve via bin/ on $PATH — amended)
|
|
20
|
+
# @problem P343 (mid-session staleness window)
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
SHIM_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
25
|
+
OWN_VERSION_DIR="$(dirname "$SHIM_DIR")"
|
|
26
|
+
OWN_VERSION_NAME="$(basename "$OWN_VERSION_DIR")"
|
|
27
|
+
CACHE_PARENT="$(dirname "$OWN_VERSION_DIR")"
|
|
28
|
+
|
|
29
|
+
SEMVER_RE='^[0-9]+\.[0-9]+\.[0-9]+([-+][0-9A-Za-z.-]+)?$'
|
|
30
|
+
|
|
31
|
+
# Source-repo guard: own parent dir is NOT semver → dispatch to own scripts/.
|
|
32
|
+
if ! [[ "$OWN_VERSION_NAME" =~ $SEMVER_RE ]]; then
|
|
33
|
+
exec "$SHIM_DIR/../scripts/detect-unratified-stories-maps.sh" "$@"
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Cache execution: pick the highest-semver sibling under CACHE_PARENT.
|
|
37
|
+
HIGHEST=""
|
|
38
|
+
while IFS= read -r dir; do
|
|
39
|
+
name="$(basename "$dir")"
|
|
40
|
+
[[ "$name" =~ $SEMVER_RE ]] || continue
|
|
41
|
+
if [[ -z "$HIGHEST" ]] || [[ "$(printf '%s\n%s\n' "$HIGHEST" "$name" | sort -V | tail -1)" == "$name" ]]; then
|
|
42
|
+
HIGHEST="$name"
|
|
43
|
+
fi
|
|
44
|
+
done < <(find "$CACHE_PARENT" -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
|
|
45
|
+
|
|
46
|
+
if [[ -z "$HIGHEST" ]]; then
|
|
47
|
+
printf 'wr-shim: no cached versions in %s\n' "$CACHE_PARENT" >&2
|
|
48
|
+
exit 127
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
exec "$CACHE_PARENT/$HIGHEST/scripts/detect-unratified-stories-maps.sh" "$@"
|
package/package.json
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# check-rfc-stories-ratified.sh — ADR-090 (an RFC may reference only RATIFIED stories).
|
|
3
|
+
#
|
|
4
|
+
# For each STORY-NNN in the RFC's `stories:` frontmatter, resolve the story file
|
|
5
|
+
# under <stories-root>/*/STORY-NNN-*.md and verify it carries
|
|
6
|
+
# `human-oversight: confirmed`. Exit non-zero (with a stderr directive naming the
|
|
7
|
+
# offending stories) if any listed story is unratified, unconfirmed, or missing.
|
|
8
|
+
#
|
|
9
|
+
# Composes with check-rfc-has-stories.sh (ADR-089): has-stories checks >=1 story
|
|
10
|
+
# exists; this checks each listed story is ratified. An empty `stories:` passes
|
|
11
|
+
# vacuously here (the has-stories gate owns the emptiness rejection).
|
|
12
|
+
#
|
|
13
|
+
# Usage: check-rfc-stories-ratified.sh <rfc-file> [stories-root=docs/stories]
|
|
14
|
+
# Exit: 0 = all listed stories ratified (or none listed); 1 = >=1 unratified/missing;
|
|
15
|
+
# 2 = usage / file error.
|
|
16
|
+
#
|
|
17
|
+
# Authority: ADR-090. Driver: P404 Phase 2. Test: check-rfc-stories-ratified.bats.
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
rfc="${1:-}"
|
|
21
|
+
stories_root="${2:-docs/stories}"
|
|
22
|
+
if [ -z "$rfc" ]; then
|
|
23
|
+
echo "check-rfc-stories-ratified: usage: check-rfc-stories-ratified.sh <rfc-file> [stories-root]" >&2
|
|
24
|
+
exit 2
|
|
25
|
+
fi
|
|
26
|
+
if [ ! -f "$rfc" ]; then
|
|
27
|
+
echo "check-rfc-stories-ratified: file not found: $rfc" >&2
|
|
28
|
+
exit 2
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Collect STORY-NNN ids from the stories: frontmatter (inline list OR block list).
|
|
32
|
+
stories_line="$(awk '/^stories:/{print; exit}' "$rfc")"
|
|
33
|
+
ids="$(printf '%s' "$stories_line" | grep -oE 'STORY-[0-9]+' || true)"
|
|
34
|
+
if [ -z "$ids" ]; then
|
|
35
|
+
ids="$(awk '/^stories:/{f=1;next} f&&/^[[:space:]]*-/{print} f&&/^[^[:space:]-]/{exit}' "$rfc" | grep -oE 'STORY-[0-9]+' || true)"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# No stories listed → vacuously ratified (has-stories gate owns emptiness).
|
|
39
|
+
[ -z "$ids" ] && exit 0
|
|
40
|
+
|
|
41
|
+
unratified=""
|
|
42
|
+
for id in $ids; do
|
|
43
|
+
f="$(ls "$stories_root"/*/"$id"-*.md 2>/dev/null | head -1 || true)"
|
|
44
|
+
if [ -z "$f" ]; then
|
|
45
|
+
unratified="$unratified $id(missing)"
|
|
46
|
+
continue
|
|
47
|
+
fi
|
|
48
|
+
if ! grep -qE '^human-oversight:[[:space:]]*confirmed([[:space:]]|$)' "$f"; then
|
|
49
|
+
unratified="$unratified $id(unratified)"
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
if [ -n "$unratified" ]; then
|
|
54
|
+
echo "check-rfc-stories-ratified: $rfc references unratified stories:$unratified — ADR-090: an RFC may reference only ratified (human-oversight: confirmed) stories. Ratify them first." >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
exit 0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# detect-unratified-stories-maps.sh — ADR-090 detector.
|
|
3
|
+
#
|
|
4
|
+
# Token-cheap detection of story maps + stories lacking the ratified
|
|
5
|
+
# `human-oversight: confirmed` marker. Mirrors wr-architect detect-unoversighted.sh
|
|
6
|
+
# but spans two artefact types with different marker encodings:
|
|
7
|
+
# - stories: markdown YAML frontmatter `human-oversight: confirmed`
|
|
8
|
+
# - story-maps: HTML meta tag `<meta name="human-oversight" content="confirmed">`
|
|
9
|
+
#
|
|
10
|
+
# ADR-090's marker is DRIFT-INVALIDATED (unlike ADR-066 write-once): an edit
|
|
11
|
+
# re-opens it to `unconfirmed`, so this detector surfaces both the never-ratified
|
|
12
|
+
# (no marker) and the drift-reopened (`unconfirmed`) cases as the drain queue.
|
|
13
|
+
#
|
|
14
|
+
# Usage: detect-unratified-stories-maps.sh [STORIES_DIR=docs/stories] [MAPS_DIR=docs/story-maps]
|
|
15
|
+
# Output: one unratified artefact path per line, sorted. Empty = all confirmed.
|
|
16
|
+
# Always exits 0 (detector, not a gate). Consumed by the work-problems Step 2.4
|
|
17
|
+
# oversight-unconfirmed drain (mirror of the architect/jtbd detectors).
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
STORIES_DIR="${1:-docs/stories}"
|
|
21
|
+
MAPS_DIR="${2:-docs/story-maps}"
|
|
22
|
+
|
|
23
|
+
shopt -s nullglob
|
|
24
|
+
|
|
25
|
+
{
|
|
26
|
+
# Stories — markdown YAML frontmatter.
|
|
27
|
+
if [ -d "$STORIES_DIR" ]; then
|
|
28
|
+
for f in "$STORIES_DIR"/*.md "$STORIES_DIR"/*/*.md; do
|
|
29
|
+
[ "$(basename "$f")" = "README.md" ] && continue
|
|
30
|
+
fm="$(awk 'NR==1 && $0 != "---" { exit } NR==1 { next } /^---[[:space:]]*$/ { exit } { print }' "$f")"
|
|
31
|
+
printf '%s\n' "$fm" | grep -qiE '^human-oversight:[[:space:]]*confirmed[[:space:]]*$' && continue
|
|
32
|
+
echo "$f"
|
|
33
|
+
done
|
|
34
|
+
fi
|
|
35
|
+
# Story maps — HTML meta tag.
|
|
36
|
+
if [ -d "$MAPS_DIR" ]; then
|
|
37
|
+
for f in "$MAPS_DIR"/*.html "$MAPS_DIR"/*/*.html; do
|
|
38
|
+
grep -qiE '<meta[^>]*name="human-oversight"[^>]*content="confirmed"' "$f" && continue
|
|
39
|
+
echo "$f"
|
|
40
|
+
done
|
|
41
|
+
fi
|
|
42
|
+
} | sort
|
|
43
|
+
|
|
44
|
+
exit 0
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# Behavioural test for check-rfc-stories-ratified.sh (ADR-090 — an RFC may
|
|
3
|
+
# reference only RATIFIED stories). For each STORY-NNN in the RFC's stories:
|
|
4
|
+
# frontmatter, the predicate resolves the story file and verifies
|
|
5
|
+
# human-oversight: confirmed. Composes with check-rfc-has-stories (ADR-089):
|
|
6
|
+
# has-stories checks >=1 exists; this checks each listed one is ratified.
|
|
7
|
+
#
|
|
8
|
+
# @adr ADR-090 (story maps and stories carry a drift-invalidated human-oversight marker)
|
|
9
|
+
# @problem P404 (implement ADR-089 + ADR-090) — Phase 2
|
|
10
|
+
|
|
11
|
+
setup() {
|
|
12
|
+
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
13
|
+
SCRIPT="${REPO_ROOT}/packages/itil/scripts/check-rfc-stories-ratified.sh"
|
|
14
|
+
TMPD="$(mktemp -d)"
|
|
15
|
+
mkdir -p "$TMPD/stories/accepted"
|
|
16
|
+
}
|
|
17
|
+
teardown() { rm -rf "$TMPD"; }
|
|
18
|
+
|
|
19
|
+
mkstory() { # $1=id $2=oversight-value(or "none")
|
|
20
|
+
local f="$TMPD/stories/accepted/$1-x.md"
|
|
21
|
+
{ echo "---"; echo "status: accepted"; echo "story-id: x"
|
|
22
|
+
[ "$2" != "none" ] && echo "human-oversight: $2"
|
|
23
|
+
echo "---"; echo "# $1"; } > "$f"
|
|
24
|
+
}
|
|
25
|
+
mkrfc() { printf -- '---\nstatus: proposed\nstories: [%s]\n---\n# rfc\n' "$1" > "$TMPD/RFC.proposed.md"; }
|
|
26
|
+
|
|
27
|
+
@test "check-rfc-stories-ratified: empty stories: [] passes vacuously (exit 0)" {
|
|
28
|
+
printf -- '---\nstatus: proposed\nstories: []\n---\n# rfc\n' > "$TMPD/RFC.proposed.md"
|
|
29
|
+
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
30
|
+
[ "$status" -eq 0 ]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@test "check-rfc-stories-ratified: a confirmed story is ACCEPTED (exit 0)" {
|
|
34
|
+
mkstory STORY-020 confirmed
|
|
35
|
+
mkrfc STORY-020
|
|
36
|
+
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
37
|
+
[ "$status" -eq 0 ]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@test "check-rfc-stories-ratified: an unconfirmed story is REJECTED (exit non-zero)" {
|
|
41
|
+
mkstory STORY-020 unconfirmed
|
|
42
|
+
mkrfc STORY-020
|
|
43
|
+
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
44
|
+
[ "$status" -ne 0 ]
|
|
45
|
+
[[ "$output" == *"STORY-020"* ]]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@test "check-rfc-stories-ratified: a story with NO oversight marker is REJECTED" {
|
|
49
|
+
mkstory STORY-020 none
|
|
50
|
+
mkrfc STORY-020
|
|
51
|
+
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
52
|
+
[ "$status" -ne 0 ]
|
|
53
|
+
[[ "$output" == *"STORY-020"* ]]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@test "check-rfc-stories-ratified: a missing story file is REJECTED" {
|
|
57
|
+
mkrfc STORY-099
|
|
58
|
+
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
59
|
+
[ "$status" -ne 0 ]
|
|
60
|
+
[[ "$output" == *"STORY-099"* ]]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@test "check-rfc-stories-ratified: mixed — one confirmed one unconfirmed is REJECTED" {
|
|
64
|
+
mkstory STORY-020 confirmed
|
|
65
|
+
mkstory STORY-021 unconfirmed
|
|
66
|
+
mkrfc "STORY-020, STORY-021"
|
|
67
|
+
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
68
|
+
[ "$status" -ne 0 ]
|
|
69
|
+
[[ "$output" == *"STORY-021"* ]]
|
|
70
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# Behavioural test for detect-unratified-stories-maps.sh (ADR-090 detector).
|
|
3
|
+
# Mirrors wr-architect detect-unoversighted.sh, but spans TWO artefact types
|
|
4
|
+
# with DIFFERENT marker encodings:
|
|
5
|
+
# - stories: markdown YAML frontmatter `human-oversight: confirmed`
|
|
6
|
+
# - story-maps: HTML `<meta name="human-oversight" content="confirmed">`
|
|
7
|
+
# Lists every artefact whose marker is missing or not `confirmed`. Always exit 0.
|
|
8
|
+
#
|
|
9
|
+
# @adr ADR-090 (drift-invalidated story-map/story human-oversight marker)
|
|
10
|
+
# @problem P404 (implement ADR-089 + ADR-090) — Phase 2
|
|
11
|
+
|
|
12
|
+
setup() {
|
|
13
|
+
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
14
|
+
SCRIPT="${REPO_ROOT}/packages/itil/scripts/detect-unratified-stories-maps.sh"
|
|
15
|
+
TMPD="$(mktemp -d)"
|
|
16
|
+
mkdir -p "$TMPD/stories/accepted" "$TMPD/story-maps/draft"
|
|
17
|
+
# stories (markdown frontmatter)
|
|
18
|
+
printf -- '---\nstatus: accepted\nhuman-oversight: confirmed\n---\n# ok\n' > "$TMPD/stories/accepted/STORY-1-ok.md"
|
|
19
|
+
printf -- '---\nstatus: accepted\nhuman-oversight: unconfirmed\n---\n# no\n' > "$TMPD/stories/accepted/STORY-2-unconf.md"
|
|
20
|
+
printf -- '---\nstatus: accepted\n---\n# nomarker\n' > "$TMPD/stories/accepted/STORY-3-none.md"
|
|
21
|
+
# story-maps (HTML meta)
|
|
22
|
+
printf -- '<meta name="human-oversight" content="confirmed">\n' > "$TMPD/story-maps/draft/STORY-MAP-1-ok.html"
|
|
23
|
+
printf -- '<meta name="human-oversight" content="unconfirmed">\n' > "$TMPD/story-maps/draft/STORY-MAP-2-unconf.html"
|
|
24
|
+
printf -- '<h1>no meta</h1>\n' > "$TMPD/story-maps/draft/STORY-MAP-3-none.html"
|
|
25
|
+
}
|
|
26
|
+
teardown() { rm -rf "$TMPD"; }
|
|
27
|
+
|
|
28
|
+
@test "detect: lists unconfirmed + unmarked, omits confirmed; exits 0" {
|
|
29
|
+
run bash "$SCRIPT" "$TMPD/stories" "$TMPD/story-maps"
|
|
30
|
+
[ "$status" -eq 0 ]
|
|
31
|
+
[[ "$output" == *"STORY-2-unconf.md"* ]]
|
|
32
|
+
[[ "$output" == *"STORY-3-none.md"* ]]
|
|
33
|
+
[[ "$output" == *"STORY-MAP-2-unconf.html"* ]]
|
|
34
|
+
[[ "$output" == *"STORY-MAP-3-none.html"* ]]
|
|
35
|
+
[[ "$output" != *"STORY-1-ok.md"* ]]
|
|
36
|
+
[[ "$output" != *"STORY-MAP-1-ok.html"* ]]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@test "detect: all-confirmed set yields empty output, exit 0" {
|
|
40
|
+
rm "$TMPD/stories/accepted/STORY-2-unconf.md" "$TMPD/stories/accepted/STORY-3-none.md" \
|
|
41
|
+
"$TMPD/story-maps/draft/STORY-MAP-2-unconf.html" "$TMPD/story-maps/draft/STORY-MAP-3-none.html"
|
|
42
|
+
run bash "$SCRIPT" "$TMPD/stories" "$TMPD/story-maps"
|
|
43
|
+
[ "$status" -eq 0 ]
|
|
44
|
+
[ -z "$output" ]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@test "detect: missing dirs are tolerated (exit 0, no crash)" {
|
|
48
|
+
run bash "$SCRIPT" "$TMPD/nope-stories" "$TMPD/nope-maps"
|
|
49
|
+
[ "$status" -eq 0 ]
|
|
50
|
+
}
|
|
@@ -118,7 +118,7 @@ Each transition is a `git mv` + Edit + `git add` (P057 staging trap) + README re
|
|
|
118
118
|
|
|
119
119
|
| Transition | Checks |
|
|
120
120
|
|------------|--------|
|
|
121
|
-
| `proposed → accepted` | All `problems:` entries resolve. Architect re-review PASS. JTBD re-review PASS. `## Scope` populated (not "deferred"). `## Tasks` decomposed (≥ 1 task; not just deferred placeholder). **`stories:` non-empty — run `wr-itil-check-rfc-has-stories <rfc-file>`; hard-block on non-zero exit (empty `stories: []` or missing).** Per **ADR-089** the empty-stories fallback is removed: an atomic fix is an RFC with exactly one full story; an empty `stories:` is permitted only on a `proposed`/draft RFC before the fix is scoped, never at `accepted`. |
|
|
121
|
+
| `proposed → accepted` | All `problems:` entries resolve. Architect re-review PASS. JTBD re-review PASS. `## Scope` populated (not "deferred"). `## Tasks` decomposed (≥ 1 task; not just deferred placeholder). **`stories:` non-empty — run `wr-itil-check-rfc-has-stories <rfc-file>`; hard-block on non-zero exit (empty `stories: []` or missing).** Per **ADR-089** the empty-stories fallback is removed: an atomic fix is an RFC with exactly one full story; an empty `stories:` is permitted only on a `proposed`/draft RFC before the fix is scoped, never at `accepted`. **Every listed story ratified — run `wr-itil-check-rfc-stories-ratified <rfc-file>`; hard-block on non-zero (any listed story carries `human-oversight: unconfirmed`, has no marker, or is missing).** Per **ADR-090** an RFC may reference only ratified stories; composes with the has-stories gate (has-stories checks ≥1 exists, ratified checks each is confirmed). |
|
|
122
122
|
| `accepted → in-progress` | First commit referencing `Refs: RFC-<NNN>` exists OR is being authored in this same commit. I1 hard-block on missing/orphan trace. |
|
|
123
123
|
| `in-progress → verifying` | All `## Tasks` checked. `## Verification` section drafted (release marker, user-side check, trace closure path). I1 hard-block on missing/orphan trace. |
|
|
124
124
|
| `verifying → closed` | User explicitly confirms (or AFK Rule 6 fallback for evidence-based close per ADR-022 / ADR-044 framework-resolved silent dispatch). I1 advisory-with-escalation if driving problems Closed/Parked. |
|