@windyroad/jtbd 0.14.0 → 0.14.1
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/hooks/jtbd-slide-marker.sh +47 -3
- package/package.json +2 -1
- package/scripts/mark-oversight-confirmed.sh +10 -86
- package/skills/confirm-jobs-and-personas/SKILL.md +1 -1
- package/skills/update-guide/SKILL.md +6 -2
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
# JTBD - PostToolUse:Agent|Bash|Skill slide-marker hook (P111 + P213).
|
|
3
3
|
# Slides the parent session's existing jtbd-reviewed marker forward on
|
|
4
4
|
# subprocess return, treating subprocess wall-clock as continuous parent-
|
|
5
|
-
# session work for TTL purposes.
|
|
6
|
-
#
|
|
7
|
-
#
|
|
5
|
+
# session work for TTL purposes. It only TOUCHES existing JTBD-review markers.
|
|
6
|
+
# P368 also lets an exact successful oversight-helper event create its separate
|
|
7
|
+
# document-and-session evidence marker.
|
|
8
8
|
#
|
|
9
9
|
# See ADR-009 "Subprocess-boundary refresh" and P111 for context. Failed
|
|
10
10
|
# subprocesses (tool_response.is_error=true) do NOT extend the trust window
|
|
@@ -16,6 +16,50 @@ source "$SCRIPT_DIR/lib/gate-helpers.sh"
|
|
|
16
16
|
_parse_input
|
|
17
17
|
|
|
18
18
|
SESSION_ID=$(_get_session_id)
|
|
19
|
+
|
|
20
|
+
# P368: bind oversight evidence to the exact successful Bash event rather
|
|
21
|
+
# than guessing from the set of recently announced sessions.
|
|
22
|
+
OVERSIGHT_PATH=$(printf '%s' "$_HOOK_INPUT" | python3 -c '
|
|
23
|
+
import json, shlex, sys
|
|
24
|
+
try:
|
|
25
|
+
data = json.load(sys.stdin)
|
|
26
|
+
response = data.get("tool_response", {})
|
|
27
|
+
argv = shlex.split(data.get("tool_input", {}).get("command", ""))
|
|
28
|
+
if (data.get("tool_name") == "Bash"
|
|
29
|
+
and isinstance(response, dict)
|
|
30
|
+
and response.get("is_error") is not True
|
|
31
|
+
and len(argv) == 2
|
|
32
|
+
and argv[0] == "wr-jtbd-mark-oversight-confirmed"):
|
|
33
|
+
print(argv[1])
|
|
34
|
+
except Exception:
|
|
35
|
+
pass
|
|
36
|
+
' 2>/dev/null)
|
|
37
|
+
|
|
38
|
+
if [ -n "$OVERSIGHT_PATH" ]; then
|
|
39
|
+
if [ -z "$SESSION_ID" ]; then
|
|
40
|
+
echo "wr-jtbd-mark-oversight-confirmed: missing session id; no oversight marker written" >&2
|
|
41
|
+
else
|
|
42
|
+
ABS_DIR="$(cd "$(dirname "$OVERSIGHT_PATH")" 2>/dev/null && pwd)" || ABS_DIR=""
|
|
43
|
+
ABS_PATH="${ABS_DIR:+$ABS_DIR/}$(basename "$OVERSIGHT_PATH")"
|
|
44
|
+
case "$ABS_PATH" in
|
|
45
|
+
*/docs/jtbd/*.md|*/docs/jtbd/*/*.md)
|
|
46
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
47
|
+
PATH_HASH=$(printf '%s' "$ABS_PATH" | sha256sum | cut -d' ' -f1 | cut -c1-16)
|
|
48
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
49
|
+
PATH_HASH=$(printf '%s' "$ABS_PATH" | shasum -a 256 | cut -d' ' -f1 | cut -c1-16)
|
|
50
|
+
else
|
|
51
|
+
echo "wr-jtbd-mark-oversight-confirmed: no SHA-256 utility; no oversight marker written" >&2
|
|
52
|
+
PATH_HASH=""
|
|
53
|
+
fi
|
|
54
|
+
if [ -n "$PATH_HASH" ] && ! : > "${SESSION_MARKER_DIR:-/tmp}/oversight-confirmed-${PATH_HASH}-${SESSION_ID}"; then
|
|
55
|
+
echo "wr-jtbd-mark-oversight-confirmed: marker write failed" >&2
|
|
56
|
+
fi
|
|
57
|
+
;;
|
|
58
|
+
*) echo "wr-jtbd-mark-oversight-confirmed: invalid JTBD path; no oversight marker written" >&2 ;;
|
|
59
|
+
esac
|
|
60
|
+
fi
|
|
61
|
+
fi
|
|
62
|
+
|
|
19
63
|
[ -n "$SESSION_ID" ] || exit 0
|
|
20
64
|
|
|
21
65
|
slide_marker_on_subprocess_return "/tmp/jtbd-reviewed-${SESSION_ID}"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windyroad/jtbd",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Jobs-to-be-done enforcement for UI changes",
|
|
5
5
|
"bin": {
|
|
6
6
|
"windyroad-jtbd": "./bin/install.mjs"
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
".agents/",
|
|
35
35
|
".codex-plugin/",
|
|
36
36
|
"lib/",
|
|
37
|
+
"!skills/*/eval/",
|
|
37
38
|
"!agents/eval/",
|
|
38
39
|
"!agents/test/",
|
|
39
40
|
"!hooks/test/",
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
# user-substance-confirmed (P348 / ADR-110).
|
|
4
4
|
#
|
|
5
5
|
# JTBD-side sibling of packages/architect/scripts/mark-oversight-confirmed.sh.
|
|
6
|
-
# Companion to jtbd-oversight-marker-discipline.sh
|
|
7
|
-
#
|
|
8
|
-
# answer
|
|
9
|
-
#
|
|
10
|
-
# `human-oversight: confirmed` into that artefact's frontmatter.
|
|
6
|
+
# Companion to jtbd-oversight-marker-discipline.sh. SKILLs invoke this as a
|
|
7
|
+
# standalone Bash command AFTER an AskUserQuestion lands the user's substance-
|
|
8
|
+
# confirm answer. The existing PostToolUse:Bash hook binds that exact command
|
|
9
|
+
# event's path and session id into the marker.
|
|
11
10
|
#
|
|
12
11
|
# Why the marker is required:
|
|
13
12
|
# ADR-068 mirrors ADR-066's `human-oversight: confirmed` marker contract on
|
|
@@ -23,100 +22,25 @@
|
|
|
23
22
|
# ADR-110), which the drain
|
|
24
23
|
# (/wr-jtbd:confirm-jobs-and-personas) later promotes.
|
|
25
24
|
#
|
|
26
|
-
# Marker convention:
|
|
27
|
-
# /tmp/oversight-confirmed-<sha256-of-path>-<session-id>
|
|
28
|
-
# Shared marker namespace with the architect hook — both hooks consume the
|
|
29
|
-
# same marker file shape. Written under EVERY recent candidate session SID
|
|
30
|
-
# per ADR-050 Option C.
|
|
31
|
-
#
|
|
32
25
|
# Usage:
|
|
33
26
|
# wr-jtbd-mark-oversight-confirmed <artefact-path>
|
|
34
|
-
#
|
|
35
|
-
# substance-confirmed.
|
|
27
|
+
# Must be the whole Bash command, with exactly one JTBD/persona path.
|
|
36
28
|
#
|
|
37
29
|
# Exit codes:
|
|
38
|
-
# 0 —
|
|
39
|
-
#
|
|
40
|
-
# writes no marker and prints a loud stderr diagnostic (P368) explaining
|
|
41
|
-
# the downstream hook deny, then exits 0 so SKILL flows do not crash
|
|
42
|
-
# before any hook has fired in the session.
|
|
43
|
-
# 2 — bad argument (missing or empty artefact-path).
|
|
30
|
+
# 0 — command validated; PostToolUse writes the exact-session marker.
|
|
31
|
+
# 2 — bad argument count.
|
|
44
32
|
#
|
|
45
33
|
# @adr ADR-068 (JTBD/persona human-oversight marker)
|
|
46
34
|
# @adr ADR-049 (PATH shim grammar)
|
|
47
|
-
# @adr ADR-050 (multi-SID candidate enumeration)
|
|
48
35
|
# @adr ADR-013 (Rule 6 fail-safe-defer in non-interactive contexts)
|
|
49
36
|
# @problem P348 (iter subprocesses set human-oversight: confirmed without user event)
|
|
37
|
+
# @problem P368 (candidate enumeration grants unrelated sessions)
|
|
50
38
|
|
|
51
39
|
set -uo pipefail
|
|
52
40
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if [ -z "$ARTEFACT_PATH" ]; then
|
|
56
|
-
echo "wr-jtbd-mark-oversight-confirmed: missing <artefact-path>" >&2
|
|
57
|
-
exit 2
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
# Normalize to absolute path so the hash is stable regardless of CWD.
|
|
61
|
-
abs_dir="$(cd "$(dirname "$ARTEFACT_PATH")" 2>/dev/null && pwd)" || abs_dir=""
|
|
62
|
-
if [ -n "$abs_dir" ]; then
|
|
63
|
-
ABS_PATH="$abs_dir/$(basename "$ARTEFACT_PATH")"
|
|
64
|
-
else
|
|
65
|
-
ABS_PATH="$ARTEFACT_PATH"
|
|
66
|
-
fi
|
|
67
|
-
|
|
68
|
-
# Path hash — sha256, first 16 hex chars. Portable across macOS (shasum) and
|
|
69
|
-
# Linux (sha256sum / shasum).
|
|
70
|
-
if command -v sha256sum >/dev/null 2>&1; then
|
|
71
|
-
PATH_HASH=$(printf '%s' "$ABS_PATH" | sha256sum | cut -d' ' -f1 | cut -c1-16)
|
|
72
|
-
elif command -v shasum >/dev/null 2>&1; then
|
|
73
|
-
PATH_HASH=$(printf '%s' "$ABS_PATH" | shasum -a 256 | cut -d' ' -f1 | cut -c1-16)
|
|
74
|
-
else
|
|
75
|
-
echo "wr-jtbd-mark-oversight-confirmed: no sha256 tool available" >&2
|
|
41
|
+
if [ "$#" -ne 1 ] || [ -z "$1" ]; then
|
|
42
|
+
echo "wr-jtbd-mark-oversight-confirmed: expected exactly one <artefact-path>" >&2
|
|
76
43
|
exit 2
|
|
77
44
|
fi
|
|
78
45
|
|
|
79
|
-
MARKER_DIR="${SESSION_MARKER_DIR:-/tmp}"
|
|
80
|
-
WINDOW_MINS="${SESSION_CANDIDATE_WINDOW_MINS:-1440}"
|
|
81
|
-
|
|
82
|
-
# Candidate SID enumeration — recent announce markers across all systems
|
|
83
|
-
# within the mtime window. Inlined for plugin self-containment (no cross-
|
|
84
|
-
# plugin lib source — jtbd must not depend on architect-internal helpers
|
|
85
|
-
# per ADR-002 plugin packaging).
|
|
86
|
-
candidates=$(
|
|
87
|
-
{
|
|
88
|
-
if [ -n "${CLAUDE_SESSION_ID:-}" ]; then
|
|
89
|
-
echo "$CLAUDE_SESSION_ID"
|
|
90
|
-
fi
|
|
91
|
-
# `-L` follows the start-point symlink — on macOS MARKER_DIR defaults to /tmp,
|
|
92
|
-
# a symlink to /private/tmp, which `find` would otherwise refuse to descend
|
|
93
|
-
# (no-op on Linux where /tmp is a real dir). P380.
|
|
94
|
-
find -L "$MARKER_DIR" -maxdepth 1 -name '*-announced-*' -mmin "-${WINDOW_MINS}" 2>/dev/null \
|
|
95
|
-
| sed 's|.*/||; s/.*-announced-//'
|
|
96
|
-
} | awk 'NF && !seen[$0]++'
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
# No candidate SID — cold path. Emit a loud stderr diagnostic (P368) and still
|
|
100
|
-
# exit 0. Exit 0 preserves the documented contract (do not crash SKILL flows
|
|
101
|
-
# before any announce marker has fired this session); the diagnostic replaces the
|
|
102
|
-
# prior SILENT no-op, which masqueraded as success and left the caller to hit the
|
|
103
|
-
# oversight-marker-discipline hook's deny with no idea why — the confusing loop
|
|
104
|
-
# P368 documents (the deny points back at this shim, which the caller already ran).
|
|
105
|
-
if [ -z "$candidates" ]; then
|
|
106
|
-
{
|
|
107
|
-
echo "wr-jtbd-mark-oversight-confirmed: no candidate session id discoverable"
|
|
108
|
-
echo " (CLAUDE_SESSION_ID empty and no *-announced-* markers in ${MARKER_DIR} within ${WINDOW_MINS}min)."
|
|
109
|
-
echo " NO oversight marker was written for: ${ABS_PATH}"
|
|
110
|
-
echo " The oversight-marker-discipline hook will DENY the 'human-oversight: confirmed' Edit"
|
|
111
|
-
echo " until a session announce marker exists. Start a fresh session, or point SESSION_MARKER_DIR"
|
|
112
|
-
echo " at a dir containing a *-announced-<sid> file, then re-run this shim (P368)."
|
|
113
|
-
} >&2
|
|
114
|
-
exit 0
|
|
115
|
-
fi
|
|
116
|
-
|
|
117
|
-
while IFS= read -r sid; do
|
|
118
|
-
[ -n "$sid" ] || continue
|
|
119
|
-
: > "$MARKER_DIR/oversight-confirmed-${PATH_HASH}-${sid}"
|
|
120
|
-
done <<< "$candidates"
|
|
121
|
-
|
|
122
46
|
exit 0
|
|
@@ -63,7 +63,7 @@ This is a genuine human-decision surface (the point of P288/ADR-068) — `reques
|
|
|
63
63
|
|
|
64
64
|
### Step 4: Apply the outcome
|
|
65
65
|
|
|
66
|
-
- **Confirm / Amend**: write `human-oversight: confirmed` + `oversight-date: <today, YYYY-MM-DD>` into the file's frontmatter (insert after the `status:`/`date-created:` line if absent; never duplicate).
|
|
66
|
+
- **Confirm / Amend**: for Amend, apply the directed change first. Then run `wr-jtbd-mark-oversight-confirmed <job-or-persona-path>` as a standalone Bash command; do not combine it with another command, because its PostToolUse event binds the evidence to this exact session and file. Finally, write `human-oversight: confirmed` + `oversight-date: <today, YYYY-MM-DD>` into the file's frontmatter (insert after the `status:`/`date-created:` line if absent; never duplicate). Edits go through the standard JTBD / architect edit gate per ADR-014.
|
|
67
67
|
- **Reject** (ADR-068 amendment per P316, mirroring ADR-066):
|
|
68
68
|
1. Capture the supersede ticket via a follow-up `request_user_input`: "Which problem ticket tracks the rework?" — options: existing `P<NNN>` IDs surfaced from `docs/problems/`, **Capture a new ticket** (delegate to `/wr-itil:capture-problem`), or **Defer (leave un-tracked for now)**.
|
|
69
69
|
2. If a ticket ID is captured, write `human-oversight: rejected-pending-supersede` + `supersede-ticket: P<NNN>` into the file's frontmatter. The detector excludes artifacts carrying both, so the drain stops re-asking until either the rework lands (file renamed to `*.superseded.md`) or the rejection is revisited.
|
|
@@ -103,12 +103,14 @@ Use request_user_input to present the drafted personas and ask:
|
|
|
103
103
|
wr-jtbd-mark-oversight-confirmed docs/jtbd/<persona-name>/persona.md
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
Run that helper as the complete standalone Bash command. Do not combine it with another command: the PostToolUse hook binds this exact successful command event's session id and persona path into the evidence marker.
|
|
107
|
+
|
|
106
108
|
```yaml
|
|
107
109
|
human-oversight: confirmed
|
|
108
110
|
oversight-date: YYYY-MM-DD # today
|
|
109
111
|
```
|
|
110
112
|
|
|
111
|
-
The
|
|
113
|
+
The helper's PostToolUse event writes the session-scoped evidence marker (`/tmp/oversight-confirmed-<sha>-<sid>`) that the `jtbd-oversight-marker-discipline.sh` PreToolUse hook reads to authorise the subsequent Edit/Write — without the helper call, the hook will DENY the marker write. This is the load-bearing born-confirmed gate: a persona authored through update-guide enters the world human-oversighted ONLY because the helper above paired the user's substance-confirm answer to the marker write. Do NOT write the marker for a persona the user has not confirmed. AFK iter subprocesses spawned via `native Codex subagent` have no `request_user_input` access; they MUST write `human-oversight: unconfirmed` (the AFK fallback enum value codified in ADR-110), which the drain (`/wr-jtbd:confirm-jobs-and-personas`) later promotes interactively. The marker is orthogonal to status.
|
|
112
114
|
|
|
113
115
|
### 5. Draft jobs
|
|
114
116
|
|
|
@@ -162,12 +164,14 @@ Use request_user_input to present the drafted jobs and ask:
|
|
|
162
164
|
wr-jtbd-mark-oversight-confirmed docs/jtbd/<persona-name>/JTBD-NNN-<kebab-title>.proposed.md
|
|
163
165
|
```
|
|
164
166
|
|
|
167
|
+
Run that helper as the complete standalone Bash command so its PostToolUse event binds the evidence to this exact session and job path.
|
|
168
|
+
|
|
165
169
|
```yaml
|
|
166
170
|
human-oversight: confirmed
|
|
167
171
|
oversight-date: YYYY-MM-DD # today
|
|
168
172
|
```
|
|
169
173
|
|
|
170
|
-
Without the `wr-jtbd-mark-oversight-confirmed` call, the `jtbd-oversight-marker-discipline.sh` PreToolUse hook will DENY the marker write. A job authored through update-guide is born human-oversighted ONLY because the helper above paired the user's substance-confirm answer to the marker write. Do NOT write the marker for a job the user has not confirmed. AFK iter subprocesses MUST write `human-oversight: unconfirmed` instead (the AFK fallback enum value codified in ADR-110); the drain (`/wr-jtbd:confirm-jobs-and-personas`) later promotes it interactively. The marker is orthogonal to `status:`.
|
|
174
|
+
Without the standalone `wr-jtbd-mark-oversight-confirmed` call, the `jtbd-oversight-marker-discipline.sh` PreToolUse hook will DENY the marker write. A job authored through update-guide is born human-oversighted ONLY because the helper above paired the user's substance-confirm answer to the marker write. Do NOT write the marker for a job the user has not confirmed. AFK iter subprocesses MUST write `human-oversight: unconfirmed` instead (the AFK fallback enum value codified in ADR-110); the drain (`/wr-jtbd:confirm-jobs-and-personas`) later promotes it interactively. The marker is orthogonal to `status:`.
|
|
171
175
|
|
|
172
176
|
### 7. Generate README.md index
|
|
173
177
|
|