@windyroad/jtbd 0.8.3-preview.428 → 0.8.4-preview.430
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/agents/agent.md +19 -3
- package/agents/test/jtbd-unratified-dependency-verdict.bats +62 -0
- package/bin/wr-jtbd-is-job-or-persona-unconfirmed +3 -0
- package/package.json +1 -1
- package/scripts/is-job-or-persona-unconfirmed.sh +89 -0
- package/scripts/test/is-job-or-persona-unconfirmed.bats +126 -0
- package/skills/update-guide/SKILL.md +1 -1
package/agents/agent.md
CHANGED
|
@@ -44,6 +44,22 @@ All review criteria come from the JTBD documentation. Read the docs first and ap
|
|
|
44
44
|
- If the change involves API interactions, do the actions align with the job's expected flow?
|
|
45
45
|
- Are new actions documented in the relevant job's action list?
|
|
46
46
|
|
|
47
|
+
### Unratified Dependency (build-upon guard — ADR-068 enforcement surface 3)
|
|
48
|
+
|
|
49
|
+
When the change or plan under review **explicitly cites, implements, or serves** a specific persona or job — an `@jtbd JTBD-NNN` annotation, a `persona: <name>` reference, or it is authoring that artifact's own flow — check whether that persona/job has been **ratified** (carries `human-oversight: confirmed` in its frontmatter) before letting the change stand. You have `Bash`, so run the predicate by **exit code** (you do NOT need to grep frontmatter yourself):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
wr-jtbd-is-job-or-persona-unconfirmed <persona-name | JTBD-NNN>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- **Exit 0** (frontmatter lacks the marker AND the artifact is not superseded) → the artifact is **unratified**. Emit **ISSUES FOUND / [Unratified Dependency]** with action: "ratify `<persona | JTBD-NNN>` via `/wr-jtbd:confirm-jobs-and-personas` before this lands." (The predicate prints the resolved path on stdout.)
|
|
56
|
+
- **Exit 1** (ratified, or superseded) → do NOT flag.
|
|
57
|
+
- **Exit 2** (ref not found) → the change cites a persona/job that does not exist; that is a separate Job Gap / Persona Mismatch, not an Unratified Dependency.
|
|
58
|
+
|
|
59
|
+
**Key the flag on the oversight marker, NEVER on `status:`.** `status: proposed`/`accepted` and `human-oversight:` are orthogonal axes (ADR-066). Building on a **ratified** job whose `status` is still `proposed` is fine — do NOT flag it; only the *unratified* (marker-absent, non-superseded) case flags.
|
|
60
|
+
|
|
61
|
+
**Bound to explicit cite/implement — NOT ambient alignment.** You already match every change to a job ID for the PASS verdict (see Job Alignment above); the `[Unratified Dependency]` flag must NOT fire on that mere match — only on an **explicit** dependency the change names. This is the inverse-P078 / P132 over-fire guard. Note: the JTBD unratified set is currently large (the P288 drain is in progress), so unlike the architect surface this will fire more often until that drain completes — that is the intended forcing function, not noise. The `developer`-persona jobs still pending the P288 drain (e.g. `JTBD-001`) are the canonical first-fire cases — the `developer` persona itself was ratified via P289.
|
|
62
|
+
|
|
47
63
|
## Output Formatting
|
|
48
64
|
|
|
49
65
|
When referencing JTBD IDs, problem IDs (P<NNN>), or ADR IDs in prose output, always include the human-readable title on first mention. Use the format `JTBD-001 (Enforce Governance Without Slowing Down)`, not bare `JTBD-001`.
|
|
@@ -59,11 +75,11 @@ If there are misalignments or gaps:
|
|
|
59
75
|
|
|
60
76
|
> **JTBD Review: ISSUES FOUND**
|
|
61
77
|
>
|
|
62
|
-
> 1. **[Job Gap / Persona Mismatch / Missing Annotation]**
|
|
78
|
+
> 1. **[Job Gap / Persona Mismatch / Missing Annotation / Unratified Dependency]**
|
|
63
79
|
> - **File**: `path`, Line ~N
|
|
64
|
-
> - **Issue**: What is misaligned
|
|
80
|
+
> - **Issue**: What is misaligned (for **Unratified Dependency**: the change builds on `<persona | JTBD-NNN>` which lacks `human-oversight: confirmed`)
|
|
65
81
|
> - **Job**: Which job is affected (or "no matching job")
|
|
66
|
-
> - **Fix**: Suggested resolution (update JTBD doc, adjust UI, add annotation)
|
|
82
|
+
> - **Fix**: Suggested resolution (update JTBD doc, adjust UI, add annotation; for **Unratified Dependency**: ratify via `/wr-jtbd:confirm-jobs-and-personas` before this lands)
|
|
67
83
|
>
|
|
68
84
|
> 2. ...
|
|
69
85
|
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# wr-jtbd — predicate: is a referenced persona or job unconfirmed? (ADR-068 surface 3)
|
|
3
|
+
#
|
|
4
|
+
# Single-artifact sibling of detect-unoversighted.sh (ADR-068). Where the
|
|
5
|
+
# detector LISTS the whole unoversighted set and always exits 0, this answers
|
|
6
|
+
# ONE question for ONE persona/job via its EXIT CODE — for the build-upon guard
|
|
7
|
+
# the wr-jtbd:agent runs (the [Unratified Dependency] verdict, RFC-011 / P323).
|
|
8
|
+
# The JTBD twin of packages/architect/scripts/is-decision-unconfirmed.sh
|
|
9
|
+
# (ADR-074). A separate script (not a mode flag on the detector) keeps the
|
|
10
|
+
# detector's "always exit 0, path-list on stdout" contract intact.
|
|
11
|
+
#
|
|
12
|
+
# "Unconfirmed" mirrors detect-unoversighted.sh EXACTLY:
|
|
13
|
+
# - the artifact's frontmatter lacks `human-oversight: confirmed`, AND
|
|
14
|
+
# - the artifact is not superseded.
|
|
15
|
+
# CANONICAL SHAPE: detect-unoversighted.sh. Keep the frontmatter-extraction
|
|
16
|
+
# awk block + the `human-oversight: confirmed` grep + the superseded skip in
|
|
17
|
+
# sync with that script. The `@test "agrees with detect-unoversighted ..."`
|
|
18
|
+
# case in test/is-job-or-persona-unconfirmed.bats fails if these two drift.
|
|
19
|
+
#
|
|
20
|
+
# Usage:
|
|
21
|
+
# is-job-or-persona-unconfirmed.sh <ref> [JTBD_DIR]
|
|
22
|
+
# <ref> = JTBD-NNN | NNN | <persona-name> | path/to/<file>.md
|
|
23
|
+
# JTBD_DIR defaults to docs/jtbd
|
|
24
|
+
#
|
|
25
|
+
# Ref resolution (ADR-008 layout: docs/jtbd/<persona>/persona.md +
|
|
26
|
+
# docs/jtbd/<persona>/JTBD-NNN-*.md):
|
|
27
|
+
# - a path to an existing file → that file
|
|
28
|
+
# - JTBD-NNN or a bare NNN → docs/jtbd/*/JTBD-NNN-*.md (first match)
|
|
29
|
+
# - anything else (a persona name) → docs/jtbd/<name>/persona.md
|
|
30
|
+
#
|
|
31
|
+
# Exit codes:
|
|
32
|
+
# 0 = unconfirmed — the build-upon guard SHOULD fire. Prints the resolved path.
|
|
33
|
+
# 1 = confirmed OR superseded — guard should NOT fire. No stdout.
|
|
34
|
+
# 2 = not found / unparseable ref. No stdout; reason on stderr.
|
|
35
|
+
|
|
36
|
+
set -uo pipefail
|
|
37
|
+
|
|
38
|
+
REF="${1:-}"
|
|
39
|
+
JTBD_DIR="${2:-docs/jtbd}"
|
|
40
|
+
|
|
41
|
+
[ -n "$REF" ] || { echo "is-job-or-persona-unconfirmed: missing <ref>" >&2; exit 2; }
|
|
42
|
+
|
|
43
|
+
# ── Resolve the persona/job file ──────────────────────────────────────────
|
|
44
|
+
file=""
|
|
45
|
+
if [ -f "$REF" ]; then
|
|
46
|
+
file="$REF"
|
|
47
|
+
elif printf '%s' "$REF" | grep -qiE 'JTBD-?[0-9]+|^[0-9]+$'; then
|
|
48
|
+
# Job ref: JTBD-NNN or a bare numeric. Match the per-persona job file.
|
|
49
|
+
num="$(printf '%s' "$REF" | grep -oE '[0-9]+' | head -1)"
|
|
50
|
+
[ -n "$num" ] || { echo "is-job-or-persona-unconfirmed: cannot parse job id from '$REF'" >&2; exit 2; }
|
|
51
|
+
shopt -s nullglob
|
|
52
|
+
for cand in "$JTBD_DIR"/*/JTBD-"$num"-*.md "$JTBD_DIR"/*/"$num"-*.md; do
|
|
53
|
+
file="$cand"; break
|
|
54
|
+
done
|
|
55
|
+
shopt -u nullglob
|
|
56
|
+
else
|
|
57
|
+
# Persona-name ref → the persona's persona.md.
|
|
58
|
+
cand="$JTBD_DIR/$REF/persona.md"
|
|
59
|
+
[ -f "$cand" ] && file="$cand"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
[ -n "$file" ] && [ -f "$file" ] || {
|
|
63
|
+
echo "is-job-or-persona-unconfirmed: no persona/job file for '$REF' under $JTBD_DIR" >&2
|
|
64
|
+
exit 2
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
base="$(basename "$file")"
|
|
68
|
+
|
|
69
|
+
# Superseded artifacts are retired — a newer job/persona replaced them. The
|
|
70
|
+
# build-upon guard does not fire (mirror of detect-unoversighted.sh's skip).
|
|
71
|
+
case "$base" in *.superseded.md) exit 1 ;; esac
|
|
72
|
+
|
|
73
|
+
# Extract the frontmatter block (mirror of detect-unoversighted.sh): lines
|
|
74
|
+
# between the leading `---` and the next `---`. No leading `---` ⇒ no
|
|
75
|
+
# frontmatter ⇒ treated as unconfirmed.
|
|
76
|
+
fm="$(awk '
|
|
77
|
+
NR==1 && $0 != "---" { exit }
|
|
78
|
+
NR==1 { next }
|
|
79
|
+
/^---[[:space:]]*$/ { exit }
|
|
80
|
+
{ print }
|
|
81
|
+
' "$file")"
|
|
82
|
+
|
|
83
|
+
if printf '%s\n' "$fm" | grep -qiE '^human-oversight:[[:space:]]*confirmed[[:space:]]*$'; then
|
|
84
|
+
exit 1 # confirmed — OK to build on
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Unconfirmed — the build-upon guard SHOULD fire. Name the file for the guard.
|
|
88
|
+
echo "$file"
|
|
89
|
+
exit 0
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
# ADR-068 surface 3 / RFC-011 / P323: is-job-or-persona-unconfirmed.sh is the
|
|
4
|
+
# single-artifact predicate for the JTBD build-upon guard (the wr-jtbd:agent
|
|
5
|
+
# [Unratified Dependency] verdict). It answers "is this referenced persona or
|
|
6
|
+
# job unconfirmed?" via its EXIT CODE, where "unconfirmed" mirrors
|
|
7
|
+
# detect-unoversighted.sh EXACTLY (frontmatter lacks `human-oversight:
|
|
8
|
+
# confirmed`, and the artifact is not superseded). The JTBD twin of the
|
|
9
|
+
# architect side's is-decision-unconfirmed.sh (ADR-074).
|
|
10
|
+
#
|
|
11
|
+
# Behavioural — exercises the script against fixture trees and asserts on its
|
|
12
|
+
# exit code + stdout, not its source text (ADR-052).
|
|
13
|
+
|
|
14
|
+
setup() {
|
|
15
|
+
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
16
|
+
SCRIPT="$REPO_ROOT/packages/jtbd/scripts/is-job-or-persona-unconfirmed.sh"
|
|
17
|
+
DETECT="$REPO_ROOT/packages/jtbd/scripts/detect-unoversighted.sh"
|
|
18
|
+
DIR="$(mktemp -d)"
|
|
19
|
+
mkdir -p "$DIR/docs/jtbd"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
teardown() {
|
|
23
|
+
rm -rf "$DIR"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# mk_persona <persona-name> <confirmed?yes|no>
|
|
27
|
+
mk_persona() {
|
|
28
|
+
local name="$1"; local confirmed="$2"
|
|
29
|
+
mkdir -p "$DIR/docs/jtbd/$name"
|
|
30
|
+
{
|
|
31
|
+
echo "---"
|
|
32
|
+
echo "name: $name"
|
|
33
|
+
echo "description: test persona $name"
|
|
34
|
+
[ "$confirmed" = "yes" ] && { echo "human-oversight: confirmed"; echo "oversight-date: 2026-05-27"; }
|
|
35
|
+
echo "---"
|
|
36
|
+
echo "# $name"
|
|
37
|
+
} > "$DIR/docs/jtbd/$name/persona.md"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# mk_job <persona-name> <NNN> <slug> <confirmed?yes|no> [state]
|
|
41
|
+
mk_job() {
|
|
42
|
+
local persona="$1"; local num="$2"; local slug="$3"; local confirmed="$4"; local state="${5:-proposed}"
|
|
43
|
+
mkdir -p "$DIR/docs/jtbd/$persona"
|
|
44
|
+
{
|
|
45
|
+
echo "---"
|
|
46
|
+
echo "status: $state"
|
|
47
|
+
echo "job-id: $slug"
|
|
48
|
+
echo "persona: $persona"
|
|
49
|
+
[ "$confirmed" = "yes" ] && { echo "human-oversight: confirmed"; echo "oversight-date: 2026-05-27"; }
|
|
50
|
+
echo "---"
|
|
51
|
+
echo "# $slug"
|
|
52
|
+
} > "$DIR/docs/jtbd/$persona/JTBD-$num-$slug.md"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@test "persona without the marker is unconfirmed (exit 0, prints path)" {
|
|
56
|
+
mk_persona "solo-developer" "no"
|
|
57
|
+
run bash "$SCRIPT" "solo-developer" "$DIR/docs/jtbd"
|
|
58
|
+
[ "$status" -eq 0 ]
|
|
59
|
+
[[ "$output" == *"solo-developer/persona.md"* ]]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@test "persona carrying human-oversight: confirmed is confirmed (exit 1, no stdout)" {
|
|
63
|
+
mk_persona "tech-lead" "yes"
|
|
64
|
+
run bash "$SCRIPT" "tech-lead" "$DIR/docs/jtbd"
|
|
65
|
+
[ "$status" -eq 1 ]
|
|
66
|
+
[ -z "$output" ]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@test "job (JTBD-NNN) without the marker is unconfirmed (exit 0, prints path)" {
|
|
70
|
+
mk_job "solo-developer" "001" "enforce-governance" "no"
|
|
71
|
+
run bash "$SCRIPT" "JTBD-001" "$DIR/docs/jtbd"
|
|
72
|
+
[ "$status" -eq 0 ]
|
|
73
|
+
[[ "$output" == *"JTBD-001-enforce-governance.md"* ]]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@test "job carrying the marker is confirmed (exit 1)" {
|
|
77
|
+
mk_job "tech-lead" "201" "restore-service-fast" "yes"
|
|
78
|
+
run bash "$SCRIPT" "JTBD-201" "$DIR/docs/jtbd"
|
|
79
|
+
[ "$status" -eq 1 ]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@test "superseded job (even without marker) does NOT fire the guard (exit 1)" {
|
|
83
|
+
mkdir -p "$DIR/docs/jtbd/solo-developer"
|
|
84
|
+
{
|
|
85
|
+
echo "---"; echo "status: superseded"; echo "persona: solo-developer"; echo "---"; echo "# retired"
|
|
86
|
+
} > "$DIR/docs/jtbd/solo-developer/JTBD-009-retired.superseded.md"
|
|
87
|
+
run bash "$SCRIPT" "JTBD-009" "$DIR/docs/jtbd"
|
|
88
|
+
[ "$status" -eq 1 ]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@test "a bare numeric job ref resolves" {
|
|
92
|
+
mk_job "solo-developer" "002" "ship-with-confidence" "no"
|
|
93
|
+
run bash "$SCRIPT" "002" "$DIR/docs/jtbd"
|
|
94
|
+
[ "$status" -eq 0 ]
|
|
95
|
+
[[ "$output" == *"JTBD-002-ship-with-confidence.md"* ]]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@test "a direct path ref resolves" {
|
|
99
|
+
mk_persona "plugin-user" "no"
|
|
100
|
+
run bash "$SCRIPT" "$DIR/docs/jtbd/plugin-user/persona.md"
|
|
101
|
+
[ "$status" -eq 0 ]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@test "an unknown persona name exits 2 (not found)" {
|
|
105
|
+
run bash "$SCRIPT" "ghost-persona" "$DIR/docs/jtbd"
|
|
106
|
+
[ "$status" -eq 2 ]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@test "an unknown job ref exits 2 (not found)" {
|
|
110
|
+
run bash "$SCRIPT" "JTBD-999" "$DIR/docs/jtbd"
|
|
111
|
+
[ "$status" -eq 2 ]
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@test "agrees with detect-unoversighted on the same fixture (sync guard)" {
|
|
115
|
+
# The two scripts share the frontmatter/marker/superseded shape. This guard
|
|
116
|
+
# fails if a future edit drifts one from the other.
|
|
117
|
+
mk_persona "solo-developer" "no"
|
|
118
|
+
mk_persona "tech-lead" "yes"
|
|
119
|
+
detect_out="$(bash "$DETECT" "$DIR/docs/jtbd")"
|
|
120
|
+
# solo-developer is in the detector's unoversighted list AND the predicate exits 0.
|
|
121
|
+
[[ "$detect_out" == *"solo-developer/persona.md"* ]]
|
|
122
|
+
run bash "$SCRIPT" "solo-developer" "$DIR/docs/jtbd"; [ "$status" -eq 0 ]
|
|
123
|
+
# tech-lead is NOT in the detector's list AND the predicate exits 1.
|
|
124
|
+
[[ "$detect_out" != *"tech-lead/persona.md"* ]]
|
|
125
|
+
run bash "$SCRIPT" "tech-lead" "$DIR/docs/jtbd"; [ "$status" -eq 1 ]
|
|
126
|
+
}
|
|
@@ -80,7 +80,7 @@ description: <one-line description>
|
|
|
80
80
|
<bullet list of frustrations this product addresses>
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
Use kebab-case for the directory name (e.g., `
|
|
83
|
+
Use kebab-case for the directory name (e.g., `developer`, `tech-lead`).
|
|
84
84
|
|
|
85
85
|
### 4. Confirm personas with the user
|
|
86
86
|
|