@windyroad/jtbd 0.13.1 → 0.13.2-preview.1058
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 +5 -2
- package/agents/test/jtbd-output-formatting.bats +0 -26
- package/agents/test/jtbd-pre-edit-review-mode.bats +0 -48
- package/agents/test/jtbd-unratified-dependency-verdict.bats +0 -62
- package/agents/test/jtbd-verdict-contract.bats +0 -57
- package/hooks/test/jtbd-enforce-scope.bats +0 -199
- package/hooks/test/jtbd-eval-once-per-session.bats +0 -87
- package/hooks/test/jtbd-eval-scope.bats +0 -45
- package/hooks/test/jtbd-eval.bats +0 -69
- package/hooks/test/jtbd-mark-reviewed.bats +0 -160
- package/hooks/test/jtbd-marker-only-exempt.bats +0 -140
- package/hooks/test/jtbd-no-stop-hook.bats +0 -15
- package/hooks/test/jtbd-oversight-marker-discipline.bats +0 -216
- package/hooks/test/jtbd-oversight-nudge.bats +0 -74
- package/hooks/test/jtbd-project-root.bats +0 -60
- package/hooks/test/slide-marker-on-subprocess-return.bats +0 -118
- package/hooks/test/substance-aware-drift.bats +0 -139
- package/scripts/test/detect-unoversighted.bats +0 -113
- package/scripts/test/is-job-or-persona-unconfirmed.bats +0 -198
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windyroad/jtbd",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2-preview.1058",
|
|
4
4
|
"description": "Jobs-to-be-done enforcement for UI changes",
|
|
5
5
|
"bin": {
|
|
6
6
|
"windyroad-jtbd": "./bin/install.mjs"
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
"scripts/",
|
|
27
27
|
".claude-plugin/",
|
|
28
28
|
"lib/",
|
|
29
|
-
"!agents/eval/"
|
|
29
|
+
"!agents/eval/",
|
|
30
|
+
"!agents/test/",
|
|
31
|
+
"!hooks/test/",
|
|
32
|
+
"!scripts/test/"
|
|
30
33
|
]
|
|
31
34
|
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Doc-lint guard: jtbd agent.md must include the output formatting rule
|
|
3
|
-
# requiring human-readable titles alongside bare IDs (P032).
|
|
4
|
-
#
|
|
5
|
-
# Structural assertion — Permitted Exception to the source-grep ban (ADR-005 / P011).
|
|
6
|
-
#
|
|
7
|
-
# Cross-reference:
|
|
8
|
-
# P032 (agent output uses opaque IDs without titles)
|
|
9
|
-
# @jtbd JTBD-001 (enforce governance without slowing down)
|
|
10
|
-
|
|
11
|
-
setup() {
|
|
12
|
-
AGENT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
13
|
-
AGENT_FILE="${AGENT_DIR}/agent.md"
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
@test "agent.md contains output formatting section" {
|
|
17
|
-
run grep -n "## Output Formatting" "$AGENT_FILE"
|
|
18
|
-
[ "$status" -eq 0 ]
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@test "agent.md output formatting rule requires titles with IDs (P032)" {
|
|
22
|
-
run grep -n "title" "$AGENT_FILE"
|
|
23
|
-
[ "$status" -eq 0 ]
|
|
24
|
-
run grep -n "Output Formatting" "$AGENT_FILE"
|
|
25
|
-
[ "$status" -eq 0 ]
|
|
26
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Doc-lint guard: jtbd agent.md must carry an explicit pre-edit /
|
|
3
|
-
# proposed-change review-mode carve-out so the agent classifies alignment
|
|
4
|
-
# of the PROPOSAL when the calling prompt describes a not-yet-applied
|
|
5
|
-
# change, instead of mis-classifying not-yet-applied state as ISSUES FOUND
|
|
6
|
-
# (P313 catch-22: gate blocks edits; reviewer wants edits done first).
|
|
7
|
-
#
|
|
8
|
-
# tdd-review: structural-permitted (justification: P176 — agent behaviour is
|
|
9
|
-
# prompt-driven with no skill-invocation harness to exercise the verdict
|
|
10
|
-
# behaviourally; ADR-052 Surface 2 structural-justified case, NOT an ADR-005
|
|
11
|
-
# Permitted Exception — ADR-052 narrows ADR-005 to exclude prose-doc greps).
|
|
12
|
-
# When P176 lands, upgrade to a behavioural test that feeds the agent a
|
|
13
|
-
# pre-edit proposal and asserts the PASS verdict.
|
|
14
|
-
#
|
|
15
|
-
# Cross-reference:
|
|
16
|
-
# P313 (Pre-edit governance-gate catch-22 — pass withheld pending edits)
|
|
17
|
-
# ADR-052 Surface 2 (structural-justified verdict) + P176 (harness gap)
|
|
18
|
-
# @jtbd JTBD-001 (Enforce Governance Without Slowing Down)
|
|
19
|
-
|
|
20
|
-
setup() {
|
|
21
|
-
AGENT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
22
|
-
AGENT_FILE="${AGENT_DIR}/agent.md"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@test "agent.md carries a Review Mode section distinguishing pre-edit from post-edit (P313)" {
|
|
26
|
-
run grep -nE "^## Review Mode: Pre-edit / proposed-change vs\. Post-edit / applied" "$AGENT_FILE"
|
|
27
|
-
[ "$status" -eq 0 ]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@test "agent.md classifies alignment of the PROPOSAL in pre-edit mode (P313 verbatim core sentence)" {
|
|
31
|
-
run grep -nE "classify alignment of the PROPOSAL itself" "$AGENT_FILE"
|
|
32
|
-
[ "$status" -eq 0 ]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@test "agent.md treats not-yet-applied state as the EXPECTED baseline of a pre-edit gate (P313)" {
|
|
36
|
-
run grep -nE "EXPECTED baseline of a pre-edit gate" "$AGENT_FILE"
|
|
37
|
-
[ "$status" -eq 0 ]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@test "agent.md explicitly rejects 'edits aren't applied yet' as a valid ISSUES FOUND substance (P313)" {
|
|
41
|
-
run grep -nE "Do NOT treat .edits aren't applied yet" "$AGENT_FILE"
|
|
42
|
-
[ "$status" -eq 0 ]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@test "agent.md cites P313 as the catch-22 closure (audit-trail)" {
|
|
46
|
-
run grep -nE "P313" "$AGENT_FILE"
|
|
47
|
-
[ "$status" -eq 0 ]
|
|
48
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Doc-lint guard: jtbd agent.md must carry the [Unratified Dependency] verdict
|
|
3
|
-
# (ADR-068 enforcement surface 3 / RFC-011 / P323) — flag a change or plan that
|
|
4
|
-
# explicitly cites/implements/serves a persona or job lacking `human-oversight:
|
|
5
|
-
# confirmed` (unratified, non-superseded), keyed on the oversight marker NOT
|
|
6
|
-
# `status:`. The JTBD twin of the architect side's surface 3 (RFC-010 / P318).
|
|
7
|
-
#
|
|
8
|
-
# tdd-review: structural-permitted (justification: P176 — agent behaviour is
|
|
9
|
-
# prompt-driven with no skill-invocation harness to exercise the verdict
|
|
10
|
-
# behaviourally; ADR-052 Surface 2 structural-justified case, NOT an ADR-005
|
|
11
|
-
# Permitted Exception). When P176 lands, upgrade to a behavioural test that
|
|
12
|
-
# feeds the agent a change citing an unratified persona/job and asserts the
|
|
13
|
-
# verdict. The single-artifact predicate IS behaviourally tested today — see
|
|
14
|
-
# packages/jtbd/scripts/test/is-job-or-persona-unconfirmed.bats.
|
|
15
|
-
#
|
|
16
|
-
# Cross-reference:
|
|
17
|
-
# ADR-068 (JTBD oversight marker + drain — surface 3 amendment 2026-05-27)
|
|
18
|
-
# ADR-074 (Confirm a decision's substance before building dependent work)
|
|
19
|
-
# ADR-066 (oversight marker; orthogonal status/oversight axes)
|
|
20
|
-
# RFC-011 / P323 (this enforcement surface); RFC-010 / P318 (the ADR-side twin)
|
|
21
|
-
# ADR-052 Surface 2 (structural-justified verdict) + P176 (harness gap)
|
|
22
|
-
# @jtbd JTBD-202 (pre-flight governance checks) / JTBD-101 (extend the suite)
|
|
23
|
-
|
|
24
|
-
setup() {
|
|
25
|
-
AGENT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
26
|
-
AGENT_FILE="${AGENT_DIR}/agent.md"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
@test "agent.md lists [Unratified Dependency] as a verdict/issue type (ADR-068 surface 3)" {
|
|
30
|
-
run grep -n '\[Unratified Dependency\]' "$AGENT_FILE"
|
|
31
|
-
[ "$status" -eq 0 ]
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
@test "agent.md has an 'Unratified Dependency (build-upon guard' section citing ADR-068" {
|
|
35
|
-
run grep -niE "Unratified Dependency \(build-upon guard" "$AGENT_FILE"
|
|
36
|
-
[ "$status" -eq 0 ]
|
|
37
|
-
run grep -n "ADR-068" "$AGENT_FILE"
|
|
38
|
-
[ "$status" -eq 0 ]
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@test "agent.md keys the flag on the oversight marker, NOT on status (orthogonal axes)" {
|
|
42
|
-
# ADR-066 / user correction 2026-05-27: building on a ratified-but-proposed job is fine.
|
|
43
|
-
run grep -niE "NEVER on .?status|not .?\`?status|orthogonal" "$AGENT_FILE"
|
|
44
|
-
[ "$status" -eq 0 ]
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
@test "agent.md invokes the predicate by exit code (the jtbd agent has Bash; not a prose-grep mirror)" {
|
|
48
|
-
run grep -n "wr-jtbd-is-job-or-persona-unconfirmed" "$AGENT_FILE"
|
|
49
|
-
[ "$status" -eq 0 ]
|
|
50
|
-
run grep -niE "exit code|exit 0|exit 1" "$AGENT_FILE"
|
|
51
|
-
[ "$status" -eq 0 ]
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
@test "agent.md guards against over-firing on ambient alignment (inverse-P078 / explicit cite)" {
|
|
55
|
-
run grep -niE "explicit(ly)? cite|ambient alignment|over-?fire|NOT fire on that mere match" "$AGENT_FILE"
|
|
56
|
-
[ "$status" -eq 0 ]
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@test "agent.md routes the fix to /wr-jtbd:confirm-jobs-and-personas (the surface-2 drain)" {
|
|
60
|
-
run grep -n "/wr-jtbd:confirm-jobs-and-personas" "$AGENT_FILE"
|
|
61
|
-
[ "$status" -eq 0 ]
|
|
62
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Doc-lint guard: wr-jtbd:agent output contract — the agent MUST emit a
|
|
3
|
-
# structured inline verdict in every response, regardless of the
|
|
4
|
-
# /tmp/jtbd-verdict file write. Closes P037 (JTBD reviewer sometimes
|
|
5
|
-
# returns a bare verdict without remediation reason).
|
|
6
|
-
#
|
|
7
|
-
# Structural assertion — Permitted Exception to the source-grep ban
|
|
8
|
-
# (ADR-005 / P011).
|
|
9
|
-
#
|
|
10
|
-
# Cross-reference:
|
|
11
|
-
# P037 (JTBD reviewer bare-verdict bug)
|
|
12
|
-
# @jtbd JTBD-001 (enforce governance without slowing down)
|
|
13
|
-
|
|
14
|
-
setup() {
|
|
15
|
-
AGENT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
16
|
-
AGENT_FILE="${AGENT_DIR}/agent.md"
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
@test "agent.md contains inline verdict templates (How to Report section)" {
|
|
20
|
-
run grep -n "How to Report" "$AGENT_FILE"
|
|
21
|
-
[ "$status" -eq 0 ]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
@test "agent.md declares inline output is REQUIRED in every response (P037)" {
|
|
25
|
-
# Must say inline output is required / must be emitted every time.
|
|
26
|
-
run grep -niE "(always|every|must|required).*inline|inline.*(always|every|must|required)" "$AGENT_FILE"
|
|
27
|
-
[ "$status" -eq 0 ]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@test "agent.md declares the primary communication channel is inline, not the file (P037)" {
|
|
31
|
-
# Must clarify the verdict file is an internal signal, not a replacement for inline output
|
|
32
|
-
run grep -niE "(primary|authoritative).*(inline|user-facing|response)|inline.*(primary|authoritative)" "$AGENT_FILE"
|
|
33
|
-
[ "$status" -eq 0 ]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@test "agent.md requires a specific verdict line on every response (PASS or ISSUES FOUND)" {
|
|
37
|
-
# The verdict line is explicit - bold JTBD Review: PASS / ISSUES FOUND
|
|
38
|
-
run grep -nE "JTBD Review: (PASS|ISSUES FOUND|JOB UPDATE NEEDED|PERSONA UPDATE NEEDED)" "$AGENT_FILE"
|
|
39
|
-
[ "$status" -eq 0 ]
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@test "agent.md requires remediation guidance on every FAIL verdict (P037)" {
|
|
43
|
-
# On ISSUES FOUND the agent must include actionable guidance (what to change / what job / what fix)
|
|
44
|
-
run grep -niE "remediation|actionable|what (should|would need)|fix:|issue:" "$AGENT_FILE"
|
|
45
|
-
[ "$status" -eq 0 ]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@test "agent.md cross-references P037 so readers can trace the contract's origin" {
|
|
49
|
-
run grep -n "P037" "$AGENT_FILE"
|
|
50
|
-
[ "$status" -eq 0 ]
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@test "agent.md explicitly forbids bare verdict without reason (P037)" {
|
|
54
|
-
# Directly addresses the observed bug: verdict without body
|
|
55
|
-
run grep -niE "(must not|MUST NOT|do not|DO NOT|never) (emit|return|produce) (a )?bare|without (reason|remediation|detail|actionable|explanation)" "$AGENT_FILE"
|
|
56
|
-
[ "$status" -eq 0 ]
|
|
57
|
-
}
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# Tests for jtbd-enforce-edit.sh — verifies broadened scope with exclusions.
|
|
4
|
-
# All tests are functional: they execute the hook with mock JSON input
|
|
5
|
-
# and assert on exit status and BLOCKED output. Source-grep assertions
|
|
6
|
-
# were removed (P011) — they over-specified the implementation and
|
|
7
|
-
# false-positived on legitimate refactors.
|
|
8
|
-
|
|
9
|
-
setup() {
|
|
10
|
-
SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
11
|
-
HOOK="$SCRIPT_DIR/jtbd-enforce-edit.sh"
|
|
12
|
-
ORIG_DIR="$PWD"
|
|
13
|
-
TEST_DIR=$(mktemp -d)
|
|
14
|
-
cd "$TEST_DIR"
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
teardown() {
|
|
18
|
-
cd "$ORIG_DIR"
|
|
19
|
-
rm -rf "$TEST_DIR"
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
# Helper: run the hook with a mock JSON input for a given file path
|
|
23
|
-
run_hook_with_file() {
|
|
24
|
-
local file_path="$1"
|
|
25
|
-
local json="{\"tool_input\":{\"file_path\":\"${file_path}\"},\"session_id\":\"test-session-$$\"}"
|
|
26
|
-
echo "$json" | bash "$HOOK"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
# Helper: assert the hook exits 0 and does NOT emit BLOCKED for the given path
|
|
30
|
-
assert_path_allowed() {
|
|
31
|
-
local file_path="$1"
|
|
32
|
-
run run_hook_with_file "$file_path"
|
|
33
|
-
[ "$status" -eq 0 ]
|
|
34
|
-
[[ "$output" != *"BLOCKED"* ]]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
# Helper: assert the hook BLOCKS the given path
|
|
38
|
-
assert_path_blocked() {
|
|
39
|
-
local file_path="$1"
|
|
40
|
-
run run_hook_with_file "$file_path"
|
|
41
|
-
[ "$status" -eq 0 ]
|
|
42
|
-
[[ "$output" == *"BLOCKED"* ]]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
# --- Exclusion tests (functional) ---
|
|
46
|
-
|
|
47
|
-
# Claude Code passes absolute file paths in tool_input.file_path, so tests
|
|
48
|
-
# use $PWD-prefixed paths to match the real shape (after the P004 root check).
|
|
49
|
-
|
|
50
|
-
@test "enforce: excludes VCS-internal .git/ plumbing files (P458)" {
|
|
51
|
-
assert_path_allowed "$PWD/.git/cruise-brake-commit-msg.txt"
|
|
52
|
-
assert_path_allowed "$PWD/.git/COMMIT_EDITMSG"
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
@test "enforce: excludes CSS files" {
|
|
56
|
-
assert_path_allowed "$PWD/src/styles.css"
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@test "enforce: excludes image files" {
|
|
60
|
-
assert_path_allowed "$PWD/public/logo.png"
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@test "enforce: excludes font files" {
|
|
64
|
-
assert_path_allowed "$PWD/public/fonts/regular.woff"
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
@test "enforce: excludes lockfiles" {
|
|
68
|
-
assert_path_allowed "$PWD/package-lock.json"
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@test "enforce: excludes changeset files" {
|
|
72
|
-
assert_path_allowed "$PWD/.changeset/some-change.md"
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@test "enforce: excludes memory files" {
|
|
76
|
-
assert_path_allowed "$PWD/MEMORY.md"
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
@test "enforce: excludes plan files" {
|
|
80
|
-
assert_path_allowed "$PWD/.claude/plans/2026-01-01-plan.md"
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@test "enforce: excludes risk reports" {
|
|
84
|
-
assert_path_allowed "$PWD/.risk-reports/2026-01-01.md"
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
@test "enforce: excludes RISK-POLICY.md" {
|
|
88
|
-
assert_path_allowed "$PWD/RISK-POLICY.md"
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
@test "enforce: does NOT exempt by UI-only extension (ADR-007/008)" {
|
|
92
|
-
# ADR-007/008 broadened scope: the hook must gate UI files like any
|
|
93
|
-
# other source file, not silently allow them.
|
|
94
|
-
assert_path_blocked "$PWD/src/Component.tsx"
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
@test "enforce: does NOT exempt .html files (ADR-007/008)" {
|
|
98
|
-
assert_path_blocked "$PWD/public/index.html"
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
@test "enforce: does NOT exempt .vue files (ADR-007/008)" {
|
|
102
|
-
assert_path_blocked "$PWD/src/App.vue"
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
# --- Functional tests (execute hook with mock JSON) ---
|
|
106
|
-
|
|
107
|
-
@test "functional: exempts docs/jtbd/ files" {
|
|
108
|
-
run run_hook_with_file "docs/jtbd/solo-developer/persona.md"
|
|
109
|
-
[ "$status" -eq 0 ]
|
|
110
|
-
[[ "$output" != *"BLOCKED"* ]]
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
@test "functional: exempts docs/jtbd/ job files" {
|
|
114
|
-
run run_hook_with_file "docs/jtbd/solo-developer/JTBD-001-governance.proposed.md"
|
|
115
|
-
[ "$status" -eq 0 ]
|
|
116
|
-
[[ "$output" != *"BLOCKED"* ]]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@test "functional: exempts docs/jtbd/README.md" {
|
|
120
|
-
run run_hook_with_file "docs/jtbd/README.md"
|
|
121
|
-
[ "$status" -eq 0 ]
|
|
122
|
-
[[ "$output" != *"BLOCKED"* ]]
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
@test "functional: docs/JOBS_TO_BE_DONE.md is NOT an exempt governance artefact (ADR-008 Option 3, P019)" {
|
|
126
|
-
# Legacy single-file path is no longer a recognised governance artefact.
|
|
127
|
-
# When docs/jtbd/ exists the gate should fire against edits to the
|
|
128
|
-
# legacy file (it is not exempt). When docs/jtbd/ does not exist the
|
|
129
|
-
# gate blocks with an update-guide suggestion (covered separately).
|
|
130
|
-
mkdir -p docs/jtbd
|
|
131
|
-
echo "# Index" > docs/jtbd/README.md
|
|
132
|
-
run run_hook_with_file "docs/JOBS_TO_BE_DONE.md"
|
|
133
|
-
[ "$status" -eq 0 ]
|
|
134
|
-
[[ "$output" == *"BLOCKED"* ]]
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
@test "functional: blocks src/index.ts when no JTBD docs exist" {
|
|
138
|
-
run run_hook_with_file "src/index.ts"
|
|
139
|
-
[ "$status" -eq 0 ]
|
|
140
|
-
[[ "$output" == *"BLOCKED"* ]]
|
|
141
|
-
[[ "$output" == *"wr-jtbd:update-guide"* ]]
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
@test "functional: blocks src/index.ts when docs/jtbd exists (needs review)" {
|
|
145
|
-
mkdir -p docs/jtbd
|
|
146
|
-
echo "# Index" > docs/jtbd/README.md
|
|
147
|
-
run run_hook_with_file "src/index.ts"
|
|
148
|
-
[ "$status" -eq 0 ]
|
|
149
|
-
[[ "$output" == *"BLOCKED"* ]]
|
|
150
|
-
[[ "$output" == *"wr-jtbd:agent"* ]]
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
# --- Story maps + stories exemptions (P170 Phase 2 Slice 2.5 / ADR-060 amendment 2026-05-12) ---
|
|
154
|
-
# ADR-060 § Phase 2 encoding amendment lines 481-496 mandates exempting
|
|
155
|
-
# `docs/story-maps/**/*.html` and `docs/stories/**/*.md` from the 5
|
|
156
|
-
# enforce-edit gates. Mirrors the docs/problems and docs/jtbd exemptions —
|
|
157
|
-
# these are governance-managed surfaces with their own capture/manage skills.
|
|
158
|
-
|
|
159
|
-
@test "functional: exempts docs/story-maps/ HTML in per-state subdir (P170 / ADR-060)" {
|
|
160
|
-
assert_path_allowed "$PWD/docs/story-maps/draft/STORY-MAP-001-rfc-framework.html"
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
@test "functional: exempts docs/story-maps/ HTML in completed subdir (P170 / ADR-060)" {
|
|
164
|
-
assert_path_allowed "$PWD/docs/story-maps/completed/STORY-MAP-002-foo.html"
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
@test "functional: exempts docs/story-maps/README.md (P170 / ADR-060)" {
|
|
168
|
-
assert_path_allowed "$PWD/docs/story-maps/README.md"
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
@test "functional: exempts docs/stories/ markdown in per-state subdir (P170 / ADR-060)" {
|
|
172
|
-
assert_path_allowed "$PWD/docs/stories/draft/STORY-001-some-slice.md"
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
@test "functional: exempts docs/stories/ markdown in done subdir (P170 / ADR-060)" {
|
|
176
|
-
assert_path_allowed "$PWD/docs/stories/done/STORY-002-other.md"
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
@test "functional: exempts docs/stories/README.md (P170 / ADR-060)" {
|
|
180
|
-
assert_path_allowed "$PWD/docs/stories/README.md"
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
# --- Retros exemption (P203) ---
|
|
184
|
-
# `docs/retros/*` is the ask-hygiene + run-retro narrative trail written
|
|
185
|
-
# routinely by `/wr-retrospective:run-retro` Step 2d + Step 5. Routine
|
|
186
|
-
# appends should not fire the JTBD gate — they are not user-job content.
|
|
187
|
-
# Mirrors the docs/problems and docs/jtbd peer-plugin-policy exemptions.
|
|
188
|
-
|
|
189
|
-
@test "functional: exempts docs/retros/ ask-hygiene file (P203)" {
|
|
190
|
-
assert_path_allowed "$PWD/docs/retros/2026-06-06-some-iter-ask-hygiene.md"
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
@test "functional: exempts docs/retros/ analyze-context file (P203)" {
|
|
194
|
-
assert_path_allowed "$PWD/docs/retros/2026-06-06-context-analysis.md"
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
@test "functional: exempts docs/retros/ retro narrative file (P203)" {
|
|
198
|
-
assert_path_allowed "$PWD/docs/retros/2026-06-06-session-wrap.md"
|
|
199
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# P095 / ADR-038: jtbd-eval.sh UserPromptSubmit hook must emit the full
|
|
4
|
-
# MANDATORY block only on the first prompt of a session; subsequent
|
|
5
|
-
# prompts emit a terse reminder.
|
|
6
|
-
|
|
7
|
-
setup() {
|
|
8
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
9
|
-
HOOK="$REPO_ROOT/packages/jtbd/hooks/jtbd-eval.sh"
|
|
10
|
-
|
|
11
|
-
WORKDIR="$(mktemp -d)"
|
|
12
|
-
mkdir -p "$WORKDIR/docs/jtbd"
|
|
13
|
-
: > "$WORKDIR/docs/jtbd/README.md"
|
|
14
|
-
|
|
15
|
-
SID="jtbd-eval-test-$$-$RANDOM"
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
teardown() {
|
|
19
|
-
rm -f "/tmp/jtbd-announced-${SID}"
|
|
20
|
-
rm -f "/tmp/jtbd-announced-${SID}-alt"
|
|
21
|
-
rm -rf "$WORKDIR"
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
run_hook() {
|
|
25
|
-
local sid="$1"
|
|
26
|
-
(cd "$WORKDIR" && echo "{\"session_id\":\"$sid\"}" | bash "$HOOK")
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
@test "jtbd-eval: first invocation emits the full MANDATORY block" {
|
|
30
|
-
run run_hook "$SID"
|
|
31
|
-
[ "$status" -eq 0 ]
|
|
32
|
-
[ "${#output}" -gt 400 ]
|
|
33
|
-
[[ "$output" == *"MANDATORY JTBD CHECK"* ]]
|
|
34
|
-
[[ "$output" == *"wr-jtbd:agent"* ]]
|
|
35
|
-
[[ "$output" == *"SCOPE:"* ]]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
@test "jtbd-eval: first invocation writes the announcement marker" {
|
|
39
|
-
run run_hook "$SID"
|
|
40
|
-
[ -f "/tmp/jtbd-announced-${SID}" ]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@test "jtbd-eval: second invocation emits only a terse reminder" {
|
|
44
|
-
run_hook "$SID" >/dev/null
|
|
45
|
-
run run_hook "$SID"
|
|
46
|
-
[ "$status" -eq 0 ]
|
|
47
|
-
[ "${#output}" -lt 250 ]
|
|
48
|
-
[[ "$output" == *"jtbd"* ]] || [[ "$output" == *"JTBD"* ]]
|
|
49
|
-
[[ "$output" == *"wr-jtbd:agent"* ]]
|
|
50
|
-
[[ "$output" != *"Does NOT apply to"* ]]
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@test "jtbd-eval: terse reminder preserves the MANDATORY signal word" {
|
|
54
|
-
run_hook "$SID" >/dev/null
|
|
55
|
-
run run_hook "$SID"
|
|
56
|
-
[[ "$output" == *"MANDATORY"* ]] || [[ "$output" == *"REQUIRED"* ]] || [[ "$output" == *"NON-OPTIONAL"* ]]
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@test "jtbd-eval: terse reminder names the trigger artifact" {
|
|
60
|
-
run_hook "$SID" >/dev/null
|
|
61
|
-
run run_hook "$SID"
|
|
62
|
-
[[ "$output" == *"docs/jtbd"* ]]
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@test "jtbd-eval: different session_id re-emits the full block" {
|
|
66
|
-
run_hook "$SID" >/dev/null
|
|
67
|
-
local SID2="${SID}-alt"
|
|
68
|
-
run run_hook "$SID2"
|
|
69
|
-
[ "${#output}" -gt 400 ]
|
|
70
|
-
[[ "$output" == *"MANDATORY JTBD CHECK"* ]]
|
|
71
|
-
rm -f "/tmp/jtbd-announced-${SID2}"
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
@test "jtbd-eval: empty session_id emits the full block and writes no marker" {
|
|
75
|
-
run run_hook ""
|
|
76
|
-
[ "${#output}" -gt 400 ]
|
|
77
|
-
[[ "$output" == *"MANDATORY JTBD CHECK"* ]]
|
|
78
|
-
[ ! -f "/tmp/jtbd-announced-" ]
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
@test "jtbd-eval: absent docs/jtbd/ emits the no-docs NOTE (unchanged by this ADR)" {
|
|
82
|
-
local NO_JTBD="$(mktemp -d)"
|
|
83
|
-
run bash -c "cd '$NO_JTBD' && echo '{\"session_id\":\"$SID\"}' | bash '$HOOK'"
|
|
84
|
-
[[ "$output" == *"no docs/jtbd/ directory"* ]]
|
|
85
|
-
[[ "$output" != *"MANDATORY JTBD CHECK"* ]]
|
|
86
|
-
rm -rf "$NO_JTBD"
|
|
87
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# Tests for jtbd-eval.sh (UserPromptSubmit) — verifies the injected scope
|
|
4
|
-
# exclusion text lists governance docs that the PreToolUse gate already
|
|
5
|
-
# exempts (P029). Without this, the LLM wastes time delegating to the
|
|
6
|
-
# jtbd-lead for files the edit gate would allow anyway.
|
|
7
|
-
|
|
8
|
-
setup() {
|
|
9
|
-
SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
10
|
-
HOOK="$SCRIPT_DIR/jtbd-eval.sh"
|
|
11
|
-
ORIG_DIR="$PWD"
|
|
12
|
-
TEST_DIR=$(mktemp -d)
|
|
13
|
-
cd "$TEST_DIR"
|
|
14
|
-
mkdir -p docs/jtbd
|
|
15
|
-
echo "# Index" > docs/jtbd/README.md
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
teardown() {
|
|
19
|
-
cd "$ORIG_DIR"
|
|
20
|
-
rm -rf "$TEST_DIR"
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
@test "eval: scope text mentions problem files exemption (P029)" {
|
|
24
|
-
run bash "$HOOK" </dev/null
|
|
25
|
-
[ "$status" -eq 0 ]
|
|
26
|
-
[[ "$output" == *"docs/problems/"* ]] || [[ "$output" == *"problem tickets"* ]]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
@test "eval: scope text mentions BRIEFING.md exemption (P029)" {
|
|
30
|
-
run bash "$HOOK" </dev/null
|
|
31
|
-
[ "$status" -eq 0 ]
|
|
32
|
-
[[ "$output" == *"BRIEFING"* ]]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@test "eval: scope text mentions docs/briefing/ exemption (P100)" {
|
|
36
|
-
run bash "$HOOK" </dev/null
|
|
37
|
-
[ "$status" -eq 0 ]
|
|
38
|
-
[[ "$output" == *"docs/briefing/"* ]]
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@test "eval: scope text mentions RISK-POLICY exemption (P029)" {
|
|
42
|
-
run bash "$HOOK" </dev/null
|
|
43
|
-
[ "$status" -eq 0 ]
|
|
44
|
-
[[ "$output" == *"RISK-POLICY"* ]]
|
|
45
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# Tests for jtbd-eval.sh — verifies JTBD suggestion fires for any project.
|
|
4
|
-
# Canonical layout is docs/jtbd/ only (ADR-008 Option 3 chosen 2026-04-20).
|
|
5
|
-
# Legacy docs/JOBS_TO_BE_DONE.md is NOT consulted at runtime (P019).
|
|
6
|
-
|
|
7
|
-
setup() {
|
|
8
|
-
SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
9
|
-
HOOK="$SCRIPT_DIR/jtbd-eval.sh"
|
|
10
|
-
ORIG_DIR="$PWD"
|
|
11
|
-
TEST_DIR=$(mktemp -d)
|
|
12
|
-
cd "$TEST_DIR"
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
teardown() {
|
|
16
|
-
cd "$ORIG_DIR"
|
|
17
|
-
rm -rf "$TEST_DIR"
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
@test "eval: suggests update-guide when docs/jtbd/ missing (no UI files)" {
|
|
21
|
-
# No UI files, no docs — should still suggest
|
|
22
|
-
run bash "$HOOK" </dev/null
|
|
23
|
-
[ "$status" -eq 0 ]
|
|
24
|
-
[[ "$output" == *"wr-jtbd:update-guide"* ]]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@test "eval: suggests update-guide when docs/jtbd/ missing (with UI files)" {
|
|
28
|
-
mkdir -p src
|
|
29
|
-
touch src/App.tsx
|
|
30
|
-
run bash "$HOOK" </dev/null
|
|
31
|
-
[ "$status" -eq 0 ]
|
|
32
|
-
[[ "$output" == *"wr-jtbd:update-guide"* ]]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@test "eval: injects enforcement when docs/jtbd/README.md exists" {
|
|
36
|
-
mkdir -p docs/jtbd
|
|
37
|
-
echo "# Index" > docs/jtbd/README.md
|
|
38
|
-
run bash "$HOOK" </dev/null
|
|
39
|
-
[ "$status" -eq 0 ]
|
|
40
|
-
[[ "$output" == *"MANDATORY JTBD CHECK"* ]]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@test "eval: does NOT consult legacy docs/JOBS_TO_BE_DONE.md (ADR-008 Option 3, P019)" {
|
|
44
|
-
# Legacy single-file layout — gate must NOT inject the enforcement
|
|
45
|
-
# instruction; instead it should suggest update-guide so the project
|
|
46
|
-
# migrates into the directory layout.
|
|
47
|
-
mkdir -p docs
|
|
48
|
-
echo "# Jobs" > docs/JOBS_TO_BE_DONE.md
|
|
49
|
-
run bash "$HOOK" </dev/null
|
|
50
|
-
[ "$status" -eq 0 ]
|
|
51
|
-
[[ "$output" != *"MANDATORY JTBD CHECK"* ]]
|
|
52
|
-
[[ "$output" == *"wr-jtbd:update-guide"* ]]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
@test "eval: uses docs/jtbd/ when both layouts coexist (ADR-008 Option 3)" {
|
|
56
|
-
mkdir -p docs/jtbd
|
|
57
|
-
echo "# Index" > docs/jtbd/README.md
|
|
58
|
-
echo "# Jobs" > docs/JOBS_TO_BE_DONE.md
|
|
59
|
-
run bash "$HOOK" </dev/null
|
|
60
|
-
[ "$status" -eq 0 ]
|
|
61
|
-
[[ "$output" == *"docs/jtbd"* ]]
|
|
62
|
-
[[ "$output" == *"MANDATORY JTBD CHECK"* ]]
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@test "eval: does not reference UI-only scoping in output" {
|
|
66
|
-
run bash "$HOOK" </dev/null
|
|
67
|
-
[ "$status" -eq 0 ]
|
|
68
|
-
[[ "$output" != *"UI files"* ]]
|
|
69
|
-
}
|