@windyroad/architect 0.20.2-preview.1014 → 0.20.3-preview.1030
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/.codex-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/scripts/check-amends-backreference.sh +55 -0
- package/scripts/test/check-amends-backreference.bats +68 -0
- package/skills/capture-adr/agents/openai.yaml +3 -0
- package/skills/create-adr/agents/openai.yaml +3 -0
- package/skills/review-decisions/agents/openai.yaml +3 -0
- package/skills/review-design/agents/openai.yaml +3 -0
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# check-amends-backreference.sh — load-bearing detector for lockstep-amendment drift.
|
|
3
|
+
#
|
|
4
|
+
# An ADR that declares `amends: [ADR-NNN, ...]` is asserting that it changed those
|
|
5
|
+
# decisions' meaning. A reader who lands on the AMENDED ADR must be able to find
|
|
6
|
+
# that out from the amended ADR itself — otherwise the old text reads as current
|
|
7
|
+
# and the amendment is invisible from the only direction that matters.
|
|
8
|
+
#
|
|
9
|
+
# This checks the back-reference exists: for every `amends:` entry, the amended
|
|
10
|
+
# ADR's body must mention the amending ADR by ID. Cheap, mechanical, and it fires
|
|
11
|
+
# at the moment the drift is introduced rather than at a retro months later
|
|
12
|
+
# (ADR-051 load-bearing-from-the-start; the R002 sub-class with no detector).
|
|
13
|
+
#
|
|
14
|
+
# Usage: check-amends-backreference.sh [decisions-dir=docs/decisions]
|
|
15
|
+
# Exit: 0 = every declared amendment is back-referenced; 1 = >=1 missing
|
|
16
|
+
# (offenders on stderr); 2 = usage / dir error.
|
|
17
|
+
#
|
|
18
|
+
# @adr ADR-051 (load-bearing from the start) ADR-031 (per-ADR body authoritative)
|
|
19
|
+
# ADR-052 (behavioural bats) ADR-101 (the five-artefact lockstep that
|
|
20
|
+
# surfaced the gap)
|
|
21
|
+
# @problem P456
|
|
22
|
+
set -uo pipefail
|
|
23
|
+
|
|
24
|
+
dir="${1:-docs/decisions}"
|
|
25
|
+
[ -d "$dir" ] || { echo "check-amends-backreference: not a directory: $dir" >&2; exit 2; }
|
|
26
|
+
|
|
27
|
+
missing=""
|
|
28
|
+
shopt -s nullglob
|
|
29
|
+
for f in "$dir"/[0-9]*.md; do
|
|
30
|
+
self="ADR-$(basename "$f" | grep -oE '^[0-9]+')"
|
|
31
|
+
# `amends:` is frontmatter-only; stop at the closing delimiter so a body
|
|
32
|
+
# mention of the word cannot be mistaken for a declaration.
|
|
33
|
+
amends_line="$(awk 'NR==1&&$0=="---"{fm=1;next} fm&&/^---[[:space:]]*$/{exit} fm&&/^amends:/{print;exit}' "$f")"
|
|
34
|
+
[ -n "$amends_line" ] || continue
|
|
35
|
+
for target in $(printf '%s' "$amends_line" | grep -oE 'ADR-[0-9]+'); do
|
|
36
|
+
# nullglob array, not `ls` — an unmatched glob passes through to ls as a
|
|
37
|
+
# literal and its diagnostics can land in the capture.
|
|
38
|
+
shopt -s nullglob; hits=("$dir"/"${target#ADR-}"-*.md); shopt -u nullglob
|
|
39
|
+
tf="${hits[0]:-}"
|
|
40
|
+
if [ -z "$tf" ]; then
|
|
41
|
+
missing="$missing\n $self declares amends: $target, which does not resolve in $dir"
|
|
42
|
+
continue
|
|
43
|
+
fi
|
|
44
|
+
grep -qF "$self" "$tf" || \
|
|
45
|
+
missing="$missing\n $(basename "$tf") is amended by $self but never mentions it — a reader of the amended decision cannot discover the amendment"
|
|
46
|
+
done
|
|
47
|
+
done
|
|
48
|
+
shopt -u nullglob
|
|
49
|
+
|
|
50
|
+
if [ -n "$missing" ]; then
|
|
51
|
+
# shellcheck disable=SC2059
|
|
52
|
+
printf "check-amends-backreference: lockstep-amendment drift:$missing\n" >&2
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# Behavioural tests for check-amends-backreference.sh.
|
|
3
|
+
# Runs the real script against real fixture trees and asserts on exit status and
|
|
4
|
+
# stderr — never on the script's source text (ADR-052 / P081).
|
|
5
|
+
#
|
|
6
|
+
# @adr ADR-051 ADR-052 @problem P456
|
|
7
|
+
|
|
8
|
+
setup() {
|
|
9
|
+
CHECK="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)/check-amends-backreference.sh"
|
|
10
|
+
TMP="$(mktemp -d)"; cd "$TMP"; mkdir -p d
|
|
11
|
+
}
|
|
12
|
+
teardown() { cd /; rm -rf "$TMP"; }
|
|
13
|
+
|
|
14
|
+
amender() { printf -- '---\nstatus: "proposed"\namends: [%s]\n---\n\n# ADR-%s\n' "$2" "$1" > "d/$1-amender.md"; }
|
|
15
|
+
amended() { printf -- '---\nstatus: "proposed"\n---\n\n# ADR-%s\n\n%s\n' "$1" "$2" > "d/$1-amended.md"; }
|
|
16
|
+
|
|
17
|
+
@test "passes when the amended ADR back-references the amending one" {
|
|
18
|
+
amender 101 "ADR-090"
|
|
19
|
+
amended 090 "Exercised 2026-07-26 by ADR-101, which coarsens this rule."
|
|
20
|
+
run bash "$CHECK" d
|
|
21
|
+
[ "$status" -eq 0 ]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@test "fails when the amended ADR never mentions the amending one" {
|
|
25
|
+
amender 101 "ADR-090"
|
|
26
|
+
amended 090 "This decision stands unqualified."
|
|
27
|
+
run bash "$CHECK" d
|
|
28
|
+
[ "$status" -eq 1 ]
|
|
29
|
+
echo "$output" | grep -q '090'
|
|
30
|
+
echo "$output" | grep -q 'ADR-101'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@test "checks EVERY entry in a multi-target amends list, not just the first" {
|
|
34
|
+
amender 101 "ADR-090, ADR-095, ADR-096"
|
|
35
|
+
amended 090 "Amended by ADR-101."
|
|
36
|
+
amended 095 "Amended by ADR-101."
|
|
37
|
+
amended 096 "This decision stands unqualified."
|
|
38
|
+
run bash "$CHECK" d
|
|
39
|
+
[ "$status" -eq 1 ]
|
|
40
|
+
echo "$output" | grep -q '096'
|
|
41
|
+
! echo "$output" | grep -q '095'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@test "fails when an amends: target does not resolve at all" {
|
|
45
|
+
amender 101 "ADR-777"
|
|
46
|
+
run bash "$CHECK" d
|
|
47
|
+
[ "$status" -eq 1 ]
|
|
48
|
+
echo "$output" | grep -q 'ADR-777'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@test "an ADR with no amends: declaration is not checked" {
|
|
52
|
+
amended 090 "A decision that amends nothing."
|
|
53
|
+
run bash "$CHECK" d
|
|
54
|
+
[ "$status" -eq 0 ]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@test "a body mention of the word amends is not read as a declaration" {
|
|
58
|
+
printf -- '---\nstatus: "proposed"\n---\n\n# ADR-101\n\nThis amends: nothing in particular, per ADR-999.\n' > d/101-prose.md
|
|
59
|
+
run bash "$CHECK" d
|
|
60
|
+
[ "$status" -eq 0 ]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@test "the live corpus satisfies the invariant" {
|
|
64
|
+
repo="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
65
|
+
[ -d "$repo/docs/decisions" ] || skip "not running in the source repo"
|
|
66
|
+
run bash "$CHECK" "$repo/docs/decisions"
|
|
67
|
+
[ "$status" -eq 0 ]
|
|
68
|
+
}
|