@thebassclef/lite 1.9.16 → 1.9.19
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/README.md +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/agents/builder.md +7 -4
- package/dist/lite/.claude/bassclef-orientation.md +22 -0
- package/dist/lite/.claude/hooks/artifact-ingestion-gate.sh +11 -3
- package/dist/lite/.claude/hooks/assert-verify-steering.sh +1 -19
- package/dist/lite/.claude/hooks/plain-english-steering.sh +86 -41
- package/dist/lite/.claude/hooks/pre-commit-gate.sh +10 -2
- package/dist/lite/.claude/hooks/pre-push-shellcheck.sh +196 -0
- package/dist/lite/.claude/hooks/reviewer-dispatch-check.sh +153 -0
- package/dist/lite/.claude/hooks/session-reflection.d/83-install-written-paths-rebuild.sh +15 -32
- package/dist/lite/.claude/hooks/turn-prose-density-measure.sh +109 -0
- package/dist/lite/.claude/hooks/turn-prose-kiss-check.sh +28 -0
- package/dist/lite/.claude/rules/branching.md +2 -0
- package/dist/lite/.claude/rules/identifier-leak-prevention.md +2 -1
- package/dist/lite/.claude/rules/install-written-paths-mediation.md +7 -0
- package/dist/lite/.claude/rules/lite-manifest-schema-change-discipline.md +23 -0
- package/dist/lite/.claude/rules/reviewer-dispatch.md +95 -0
- package/dist/lite/.claude/settings.json +10 -0
- package/dist/lite/.claude/skills/build/SKILL.md +81 -6
- package/dist/lite/.claude/skills/eisenhower/SKILL.md +26 -0
- package/dist/lite/.claude/skills/launch/SKILL.md +45 -2
- package/dist/lite/.claude/skills/onboard-repo/SKILL.md +208 -40
- package/dist/lite/.claude/skills/onboard-repo/claude-oauth-probe.sh +60 -0
- package/dist/lite/.claude/skills/onboard-repo/concise-prompt.sh +73 -0
- package/dist/lite/.claude/skills/onboard-repo/write-state-marker.sh +81 -0
- package/dist/lite/.claude/skills/pre-mortem/SKILL.md +56 -0
- package/dist/lite/.claude/skills/sprint/SKILL.md +24 -3
- package/dist/lite/.claude/skills/temperance/SKILL.md +15 -4
- package/dist/lite/README.md +2 -0
- package/dist/lite/bassclef-version.json +5 -5
- package/dist/lite/lib/install-written-paths.sh +250 -3
- package/dist/lite/lib/prose-marker.sh +203 -0
- package/dist/lite/lib/tier-dependency-audit.sh +52 -25
- package/dist/lite/presence/install/bassclef-sync.template.sh +86 -8
- package/dist/lite/presence/install/schedule-auto-save.cron.sh +30 -2
- package/dist/lite/scripts/generate-lite-manifest.sh +15 -0
- package/dist/lite/scripts/launch/local-serve.sh +149 -8
- package/dist/lite/standards/bassclef-wiring-manifest.json +12 -0
- package/dist/lite/standards/lite-manifest-schema-changes.md +84 -0
- package/dist/lite/standards/lite-manifest.json +100 -29
- package/dist/lite/standards/prose-marker-format.md +105 -0
- package/package.json +1 -1
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# reviewer-dispatch-check.sh — Stop hook on code-shipping sessions
|
|
4
|
+
#
|
|
5
|
+
# Refuses to let a session end if it shipped source code (>0 src/ file
|
|
6
|
+
# changes per git diff) without a reviewer marker at
|
|
7
|
+
# state/markers/reviewer/<session-id>.md or *.md naming the session.
|
|
8
|
+
#
|
|
9
|
+
# Mode-agnostic: orchestrator-gated dispatches Reviewer agent; sequential
|
|
10
|
+
# mode self-invokes Reviewer responsibilities and writes the marker.
|
|
11
|
+
#
|
|
12
|
+
# Per bassclef#1146 + WU-12 of bet 2026-06-20e.
|
|
13
|
+
# Override: SKIP_REVIEWER_CHECK=1 (logged via trace-helper).
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# ============================================================================
|
|
18
|
+
# Read stdin JSON from Claude Code harness (Stop event payload)
|
|
19
|
+
# ============================================================================
|
|
20
|
+
PAYLOAD=$(cat 2>/dev/null || echo '{}')
|
|
21
|
+
|
|
22
|
+
# ============================================================================
|
|
23
|
+
# Override check (FIRST — before any work)
|
|
24
|
+
# ============================================================================
|
|
25
|
+
if [ "${SKIP_REVIEWER_CHECK:-0}" = "1" ]; then
|
|
26
|
+
TRACE_HELPER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/trace-helper.sh"
|
|
27
|
+
if [ -f "$TRACE_HELPER" ]; then
|
|
28
|
+
bash "$TRACE_HELPER" override "reviewer-dispatch-check" "SKIP_REVIEWER_CHECK=1" 2>/dev/null || true
|
|
29
|
+
fi
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# ============================================================================
|
|
34
|
+
# Repo root + check if we're in a git repo
|
|
35
|
+
# ============================================================================
|
|
36
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
37
|
+
|
|
38
|
+
# If REVIEWER_CHECK_REPO is set, override (for tests)
|
|
39
|
+
if [ -n "${REVIEWER_CHECK_REPO:-}" ]; then
|
|
40
|
+
REPO_ROOT="$REVIEWER_CHECK_REPO"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
if ! (cd "$REPO_ROOT" && git rev-parse --git-dir >/dev/null 2>&1); then
|
|
44
|
+
# Not a git repo — skip
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# ============================================================================
|
|
49
|
+
# Detect source-file changes in this session
|
|
50
|
+
# Uses git diff against origin/main as proxy for session changes; this is a
|
|
51
|
+
# heuristic — a more precise version would track session-start ref.
|
|
52
|
+
# ============================================================================
|
|
53
|
+
cd "$REPO_ROOT"
|
|
54
|
+
|
|
55
|
+
# Define source-file path matchers — files that count as "shipped code"
|
|
56
|
+
SOURCE_MATCHERS=(
|
|
57
|
+
'src/'
|
|
58
|
+
'apps/'
|
|
59
|
+
'packages/'
|
|
60
|
+
'lib/'
|
|
61
|
+
'app/'
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Count source files changed (uncommitted + committed-since-origin)
|
|
65
|
+
SHIPPED_SOURCE_COUNT=0
|
|
66
|
+
|
|
67
|
+
# Uncommitted changes
|
|
68
|
+
for matcher in "${SOURCE_MATCHERS[@]}"; do
|
|
69
|
+
count=$(git diff --name-only -- "$matcher" 2>/dev/null | wc -l | tr -d ' ')
|
|
70
|
+
SHIPPED_SOURCE_COUNT=$((SHIPPED_SOURCE_COUNT + count))
|
|
71
|
+
done
|
|
72
|
+
|
|
73
|
+
# Committed-since-origin/main
|
|
74
|
+
if git rev-parse origin/main >/dev/null 2>&1; then
|
|
75
|
+
for matcher in "${SOURCE_MATCHERS[@]}"; do
|
|
76
|
+
count=$(git diff --name-only origin/main..HEAD -- "$matcher" 2>/dev/null | wc -l | tr -d ' ')
|
|
77
|
+
SHIPPED_SOURCE_COUNT=$((SHIPPED_SOURCE_COUNT + count))
|
|
78
|
+
done
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# No source files changed — session is non-code (docs, config, etc.); pass
|
|
82
|
+
if [ "$SHIPPED_SOURCE_COUNT" -eq 0 ]; then
|
|
83
|
+
exit 0
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# ============================================================================
|
|
87
|
+
# Marker check: state/markers/reviewer/*.md
|
|
88
|
+
# ============================================================================
|
|
89
|
+
MARKER_DIR="$REPO_ROOT/state/markers/reviewer"
|
|
90
|
+
|
|
91
|
+
if [ -d "$MARKER_DIR" ] && find "$MARKER_DIR" -maxdepth 1 -name "*.md" 2>/dev/null | grep -q .; then
|
|
92
|
+
# At least one reviewer marker exists — pass
|
|
93
|
+
exit 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# ============================================================================
|
|
97
|
+
# Block: source shipped + no reviewer marker
|
|
98
|
+
# ============================================================================
|
|
99
|
+
cat >&2 <<EOF
|
|
100
|
+
🛑 reviewer-dispatch-check — BLOCK (bassclef#1146)
|
|
101
|
+
|
|
102
|
+
This session shipped source code (${SHIPPED_SOURCE_COUNT} source files
|
|
103
|
+
changed across src/ apps/ packages/ lib/ app/) but no reviewer marker
|
|
104
|
+
exists at state/markers/reviewer/.
|
|
105
|
+
|
|
106
|
+
Reviewer responsibilities (per ~/.claude/agents/reviewer.md):
|
|
107
|
+
- Verify spec acceptance criteria met
|
|
108
|
+
- Verify tests present + green
|
|
109
|
+
- Check for TDD test-after pattern (Kent Beck)
|
|
110
|
+
- Verify ADR compliance for architectural decisions
|
|
111
|
+
- Verify Designer sign-off for UX changes
|
|
112
|
+
- Verify /architect-review invoked for Construction work
|
|
113
|
+
|
|
114
|
+
Resolve via one of:
|
|
115
|
+
|
|
116
|
+
1. Orchestrator-gated mode — dispatch Reviewer agent + capture marker:
|
|
117
|
+
/reviewer-pass
|
|
118
|
+
(or invoke via your orchestrator's handoff to Reviewer)
|
|
119
|
+
|
|
120
|
+
2. Sequential mode — self-invoke Reviewer responsibilities + write marker:
|
|
121
|
+
mkdir -p $MARKER_DIR
|
|
122
|
+
cat > $MARKER_DIR/<session-id>.md <<MARKER
|
|
123
|
+
# Reviewer pass — <session-id>
|
|
124
|
+
|
|
125
|
+
mode: sequential
|
|
126
|
+
reviewed_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
127
|
+
source_files_changed: $SHIPPED_SOURCE_COUNT
|
|
128
|
+
|
|
129
|
+
## Checks
|
|
130
|
+
- spec acceptance criteria: PASS | FAIL | N/A
|
|
131
|
+
- tests present + green: PASS | FAIL
|
|
132
|
+
- test-after pattern check: NONE FOUND | FOUND (list)
|
|
133
|
+
- ADR compliance: PASS | N/A
|
|
134
|
+
- Designer sign-off: PRESENT | N/A
|
|
135
|
+
- architect-review: INVOKED | N/A
|
|
136
|
+
|
|
137
|
+
## Findings
|
|
138
|
+
- <severity>: <description> # BLOCK / WARN / NOTE
|
|
139
|
+
|
|
140
|
+
acknowledged: true
|
|
141
|
+
MARKER
|
|
142
|
+
|
|
143
|
+
3. Defer to next session — write marker NOW with "deferred to next session"
|
|
144
|
+
note + commit; resolve at next session start per deferred-actions protocol.
|
|
145
|
+
|
|
146
|
+
Override (logged): SKIP_REVIEWER_CHECK=1 <command>
|
|
147
|
+
|
|
148
|
+
When to use override:
|
|
149
|
+
- Documentation-only session that accidentally touched a src/ comment
|
|
150
|
+
- Emergency rescue when hook itself misclassifies
|
|
151
|
+
EOF
|
|
152
|
+
|
|
153
|
+
exit 2
|
|
@@ -66,43 +66,26 @@ _iwp_fragment_main() {
|
|
|
66
66
|
return 0
|
|
67
67
|
fi
|
|
68
68
|
|
|
69
|
-
# Source lib — subshell so caller scope stays clean
|
|
69
|
+
# Source lib — subshell so caller scope stays clean.
|
|
70
|
+
# Per bassclef-upstream#2200 — bulk-rebuild verb replaces the prior
|
|
71
|
+
# 451×700ms serial register loop that timed out before completion.
|
|
72
|
+
# New verb builds one jq write + one ajv validate at the end.
|
|
70
73
|
(
|
|
71
74
|
# shellcheck source=/dev/null
|
|
72
75
|
. "$lib" 2>/dev/null || exit 0
|
|
73
76
|
|
|
74
|
-
if
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
install_written_paths_rebuild 2>/dev/null || true
|
|
82
|
-
|
|
83
|
-
local registered=0
|
|
84
|
-
local skipped=0
|
|
85
|
-
|
|
86
|
-
# Each lite-manifest entry has .path field — register when file exists on disk
|
|
87
|
-
while IFS= read -r path; do
|
|
88
|
-
[ -z "$path" ] && continue
|
|
89
|
-
local full
|
|
90
|
-
case "$path" in
|
|
91
|
-
/*) full="$path" ;;
|
|
92
|
-
*) full="$project_root/$path" ;;
|
|
93
|
-
esac
|
|
94
|
-
if [ -f "$full" ]; then
|
|
95
|
-
if install_written_paths_register "$path" "bassclef-sync-template" 2>/dev/null; then
|
|
96
|
-
registered=$((registered + 1))
|
|
97
|
-
else
|
|
98
|
-
skipped=$((skipped + 1))
|
|
99
|
-
fi
|
|
100
|
-
else
|
|
101
|
-
skipped=$((skipped + 1))
|
|
77
|
+
if declare -F install_written_paths_rebuild_from_lite_manifest >/dev/null 2>&1; then
|
|
78
|
+
# Preserve verb's stderr (ajv-fail warnings etc.) by piping to trace
|
|
79
|
+
# instead of swallowing with 2>/dev/null (architect-review F3).
|
|
80
|
+
local verb_stderr
|
|
81
|
+
verb_stderr=$(install_written_paths_rebuild_from_lite_manifest "$lite_manifest" 2>&1 >/dev/null) || true
|
|
82
|
+
if [ -n "$verb_stderr" ]; then
|
|
83
|
+
_iwp_fragment_log "bulk-rebuild stderr=$verb_stderr"
|
|
102
84
|
fi
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
85
|
+
_iwp_fragment_log "bulk-rebuild dispatched lite=$lite_manifest"
|
|
86
|
+
else
|
|
87
|
+
_iwp_fragment_log "skip reason=lib-missing-bulk-rebuild-verb"
|
|
88
|
+
fi
|
|
106
89
|
) || true
|
|
107
90
|
|
|
108
91
|
return 0
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# install-class: dual
|
|
4
|
+
# Turn-prose density measure — Stop hook that reads the last assistant message
|
|
5
|
+
# from the transcript, counts non-standard hyphenated compounds, and writes
|
|
6
|
+
# the number to a marker file at state/markers/turn-prose-density/last-turn.json
|
|
7
|
+
# via lib/prose-marker.sh per standards/prose-marker-format.md.
|
|
8
|
+
#
|
|
9
|
+
# Density = count of [a-z]{2,}-[a-z]{2,}(?:-[a-z]{2,})? matches MINUS the
|
|
10
|
+
# 25-entry standard-tech allowlist. Proxy for jargon load distinct from
|
|
11
|
+
# grade-measure's existing hyphen_words count (which includes standard tech).
|
|
12
|
+
#
|
|
13
|
+
# The pre-turn plain-english-steering.sh reads the marker on next turn
|
|
14
|
+
# (extended at Step 2d) and injects the density number into the steering
|
|
15
|
+
# block alongside grade + appositive misses.
|
|
16
|
+
#
|
|
17
|
+
# Sibling scorers:
|
|
18
|
+
# - turn-prose-grade-measure.sh — grade metric
|
|
19
|
+
# - turn-prose-kiss-check.sh — appositive miss count (Step 2c extension)
|
|
20
|
+
#
|
|
21
|
+
# Input (stdin): JSON with transcript_path + session_id
|
|
22
|
+
# Output: writes state/markers/turn-prose-density/last-turn.json
|
|
23
|
+
# Exit: 0 always (measurement only, no gate)
|
|
24
|
+
#
|
|
25
|
+
# Override: SKIP_TURN_PROSE_DENSITY=1
|
|
26
|
+
|
|
27
|
+
set +e
|
|
28
|
+
|
|
29
|
+
# === Override path ===
|
|
30
|
+
if [ "${SKIP_TURN_PROSE_DENSITY:-0}" = "1" ]; then
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# === Parse stdin JSON ===
|
|
35
|
+
STDIN_JSON=$(cat 2>/dev/null || echo '{}')
|
|
36
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
TRANSCRIPT_PATH=$(echo "$STDIN_JSON" | jq -r '.transcript_path // ""' 2>/dev/null)
|
|
40
|
+
|
|
41
|
+
[ -z "$TRANSCRIPT_PATH" ] && exit 0
|
|
42
|
+
[ ! -f "$TRANSCRIPT_PATH" ] && exit 0
|
|
43
|
+
|
|
44
|
+
# === Resolve lib path (install-class: dual) ===
|
|
45
|
+
# Project install — lib relative to this hook. Operator install — lib under $HOME.
|
|
46
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
47
|
+
LIB_PATH=""
|
|
48
|
+
for candidate in \
|
|
49
|
+
"${SCRIPT_DIR}/../../lib/prose-marker.sh" \
|
|
50
|
+
"${HOME:-/}/lib/prose-marker.sh" \
|
|
51
|
+
"${CLAUDE_PROJECT_DIR:-}/lib/prose-marker.sh"; do
|
|
52
|
+
if [ -f "$candidate" ]; then
|
|
53
|
+
LIB_PATH="$candidate"
|
|
54
|
+
break
|
|
55
|
+
fi
|
|
56
|
+
done
|
|
57
|
+
|
|
58
|
+
[ -z "$LIB_PATH" ] && exit 0
|
|
59
|
+
# shellcheck disable=SC1090
|
|
60
|
+
source "$LIB_PATH" 2>/dev/null || exit 0
|
|
61
|
+
|
|
62
|
+
# === Extract last assistant text ===
|
|
63
|
+
LAST_ASSISTANT_LINE=$(grep '"type":"assistant"' "$TRANSCRIPT_PATH" 2>/dev/null | tail -1)
|
|
64
|
+
[ -z "$LAST_ASSISTANT_LINE" ] && exit 0
|
|
65
|
+
|
|
66
|
+
MESSAGE_TEXT=$(echo "$LAST_ASSISTANT_LINE" \
|
|
67
|
+
| jq -r '.message.content[]? | select(.type == "text") | .text' 2>/dev/null)
|
|
68
|
+
[ -z "$MESSAGE_TEXT" ] && exit 0
|
|
69
|
+
|
|
70
|
+
# === Strip code blocks + inline backticks + URLs (prose only) ===
|
|
71
|
+
SCRUBBED=$(echo "$MESSAGE_TEXT" | awk '
|
|
72
|
+
BEGIN { in_code = 0 }
|
|
73
|
+
/^```/ { in_code = !in_code; next }
|
|
74
|
+
in_code { next }
|
|
75
|
+
{ print }
|
|
76
|
+
' | sed -E 's/`[^`]*`//g; s|https?://[^ )]+||g')
|
|
77
|
+
|
|
78
|
+
# Short message after strip → density=0
|
|
79
|
+
STRIPPED_LEN=${#SCRUBBED}
|
|
80
|
+
if [ "$STRIPPED_LEN" -lt 50 ]; then
|
|
81
|
+
write_prose_marker "turn-prose-density" "0" "short message under 50 chars"
|
|
82
|
+
exit 0
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# === Compute density via python ===
|
|
86
|
+
# Standard-tech allowlist excluded. Pattern per standards/prose-marker-format.md.
|
|
87
|
+
DENSITY=$(printf '%s' "$SCRUBBED" | python3 -c '
|
|
88
|
+
import sys, re
|
|
89
|
+
|
|
90
|
+
STANDARD_TECH = {
|
|
91
|
+
"pre-commit", "real-time", "data-driven", "end-to-end", "fire-and-forget",
|
|
92
|
+
"run-time", "compile-time", "read-only", "write-only", "fail-soft",
|
|
93
|
+
"fail-fast", "post-commit", "pre-push", "post-merge", "op-ed",
|
|
94
|
+
"self-test", "self-check", "re-read", "re-run", "re-fire",
|
|
95
|
+
"op-cost", "copy-paste", "cut-off", "set-up", "built-in",
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
text = sys.stdin.read().lower()
|
|
99
|
+
pattern = re.compile(r"\b[a-z]{2,}-[a-z]{2,}(?:-[a-z]{2,})?\b")
|
|
100
|
+
matches = pattern.findall(text)
|
|
101
|
+
density = sum(1 for m in matches if m not in STANDARD_TECH)
|
|
102
|
+
print(density)
|
|
103
|
+
' 2>/dev/null)
|
|
104
|
+
|
|
105
|
+
[ -z "$DENSITY" ] && DENSITY=0
|
|
106
|
+
|
|
107
|
+
# === Write density marker via lib ===
|
|
108
|
+
write_prose_marker "turn-prose-density" "$DENSITY" 2>/dev/null
|
|
109
|
+
exit 0
|
|
@@ -83,6 +83,20 @@ for _candidate in \
|
|
|
83
83
|
done
|
|
84
84
|
unset _candidate
|
|
85
85
|
|
|
86
|
+
# === Source lib/prose-marker.sh (deep module per Longrun 2 Step 2b #2197) ===
|
|
87
|
+
# Provides write_prose_marker for appositive-miss count persistence.
|
|
88
|
+
# Silent-fail — no lib = no marker write; existing stderr display path unchanged.
|
|
89
|
+
for _candidate in \
|
|
90
|
+
"${SCRIPT_DIR}/../../lib/prose-marker.sh" \
|
|
91
|
+
"${HOME_OVERRIDE:-${HOME:-/}}/lib/prose-marker.sh"; do
|
|
92
|
+
if [ -f "$_candidate" ]; then
|
|
93
|
+
# shellcheck disable=SC1090
|
|
94
|
+
source "$_candidate"
|
|
95
|
+
break
|
|
96
|
+
fi
|
|
97
|
+
done
|
|
98
|
+
unset _candidate
|
|
99
|
+
|
|
86
100
|
# === Parse stdin JSON ===
|
|
87
101
|
STDIN_JSON=$(cat 2>/dev/null || echo '{}')
|
|
88
102
|
TRANSCRIPT_PATH=$(echo "$STDIN_JSON" | jq -r '.transcript_path // ""' 2>/dev/null)
|
|
@@ -417,8 +431,15 @@ for pattern, label in patterns:
|
|
|
417
431
|
|
|
418
432
|
for f in flagged[:5]: # cap at 5 findings per turn to avoid noise
|
|
419
433
|
print(f)
|
|
434
|
+
# Emit total count on final line as sentinel — bash strips before display.
|
|
435
|
+
# Per Longrun 2 Step 2c (#2197) — scorer-stack appositive marker.
|
|
436
|
+
print(f"__APPOSITIVE_COUNT__={len(flagged)}")
|
|
420
437
|
' 2>/dev/null)
|
|
421
438
|
|
|
439
|
+
# Extract the count sentinel; strip it from the display output.
|
|
440
|
+
APPOSITIVE_COUNT=$(echo "$APPOSITIVE_FINDINGS" | grep '^__APPOSITIVE_COUNT__=' | tail -1 | sed 's/^__APPOSITIVE_COUNT__=//')
|
|
441
|
+
APPOSITIVE_FINDINGS=$(echo "$APPOSITIVE_FINDINGS" | grep -v '^__APPOSITIVE_COUNT__=')
|
|
442
|
+
|
|
422
443
|
if [ -n "$APPOSITIVE_FINDINGS" ]; then
|
|
423
444
|
cat >&2 <<EOF
|
|
424
445
|
[turn-prose-kiss-check: ADVISORY — appositive discipline (bassclef-upstream#1313)]
|
|
@@ -434,6 +455,13 @@ Override one-time: SKIP_APPOSITIVE_CHECK=1.
|
|
|
434
455
|
V1 advisory; V2 (deferred) BLOCKs after calibration.
|
|
435
456
|
EOF
|
|
436
457
|
fi
|
|
458
|
+
|
|
459
|
+
# === Write appositive-miss marker via lib/prose-marker.sh (Longrun 2 Step 2c) ===
|
|
460
|
+
# Count is total matches (not capped at 5 — that cap is display-only).
|
|
461
|
+
# Silent-fail — missing lib or write error does not affect existing path.
|
|
462
|
+
if declare -f write_prose_marker >/dev/null 2>&1 && [ -n "$APPOSITIVE_COUNT" ]; then
|
|
463
|
+
write_prose_marker "turn-prose-appositive" "$APPOSITIVE_COUNT" 2>/dev/null
|
|
464
|
+
fi
|
|
437
465
|
fi
|
|
438
466
|
|
|
439
467
|
# === Emit findings + exit per mode ===
|
|
@@ -13,6 +13,8 @@ Branch naming:
|
|
|
13
13
|
|
|
14
14
|
Every branch ties to a GitHub Issue. No branch without an issue.
|
|
15
15
|
|
|
16
|
+
**Exception — `/launch --local`.** Adopter prototype branches created by `/launch --local` are exempt from the issue-per-branch rule. Local prototype mode exists for adopters who do not yet have a GitHub repo or who iterate ahead of filing issues. Per bassclef-upstream#2175 Batch A (F2) + bassclef-cli#328 Finding 2.
|
|
17
|
+
|
|
16
18
|
Flow: issue → branch from main → work → PR → CI passes → squash merge → delete branch
|
|
17
19
|
|
|
18
20
|
Rules:
|
|
@@ -30,8 +30,9 @@ No commit lands with these patterns in message OR staged content:
|
|
|
30
30
|
|
|
31
31
|
- **Hostname shapes**: `[A-Za-z][A-Za-z0-9]*-MacBook-(Air|Pro)`, `DESKTOP-[A-Z0-9]{4,}`, `*-server-*`, `*-desktop-*`
|
|
32
32
|
- **Absolute paths**: `/Users/<name>`, `/home/<name>`
|
|
33
|
+
- **GitHub no-reply derived slug**: `operator-[0-9]+\+[a-zA-Z0-9][a-zA-Z0-9-]*` — the shape `/personas` historically derived from a GitHub no-reply email local part (`<id>+<handle>`), leaking account ID plus handle into committed persona + use-case + jobs docs. Per bassclef-upstream#2146. Scope-safe — the pattern targets the derived slug only; the raw email format `<id>+<handle>@users.noreply.github.com` stays allowed as a git author (Check 3 pins that in Test 22) because GitHub recommends no-reply as the privacy format for commit identity.
|
|
33
34
|
|
|
34
|
-
Extension mechanism — future pattern classes added to
|
|
35
|
+
Extension mechanism — future pattern classes added to `standards/identifier-leak-patterns.txt` + a corresponding Tier 0 test. The hook reads the pattern file at run time; adding a line there extends the scrub without a hook edit.
|
|
35
36
|
|
|
36
37
|
## Anti-patterns
|
|
37
38
|
|
|
@@ -13,6 +13,7 @@ The lib + manifest ship per bassclef-upstream#2036 Finding #8 (Kunal cold-adopte
|
|
|
13
13
|
Any discipline hook that currently fires on file content without discriminating install-written from author-edited. Candidate hooks:
|
|
14
14
|
|
|
15
15
|
- `.claude/hooks/pre-commit-gate.sh` — lead-lens 3-marker gate section (consumer wired per this cure's V1 PR)
|
|
16
|
+
- `.claude/hooks/pre-push-shellcheck.sh` — adopter 2; retrofitted per bassclef-upstream#2253 (cold-adopter first-push BLOCKed on 72 install-written findings)
|
|
16
17
|
- `.claude/hooks/pre-commit-identifier-leak-scrub.sh` — identifier-leak sister per Kunal #1 (future adopter per R2 risk ledger)
|
|
17
18
|
- Any new discipline hook authored under the loop discipline (`.claude/rules/loop-discipline.md`) that assumes author-edit
|
|
18
19
|
|
|
@@ -67,6 +68,12 @@ INSTEAD of overriding routinely: trust the lib. Overrides are for one-shot debug
|
|
|
67
68
|
- `presence/install/bassclef-sync.template.sh` — registers each path on sync
|
|
68
69
|
- `.claude/hooks/session-reflection.d/83-install-written-paths-rebuild.sh` — regenerates manifest when missing at session-start
|
|
69
70
|
|
|
71
|
+
## Adopter 2 — pre-push-shellcheck retrofit (bassclef-upstream#2253)
|
|
72
|
+
|
|
73
|
+
Second mediation consumer landed under v1.11.1 hotfix. Peer bassclef-cli-06 cold-adopter smoke on `giveisusfree` profile caught v1.11.0's `pre-push-shellcheck.sh` (shipped #2108) BLOCKing first push after `bassclef init` on 72 shellcheck findings in bassclef-shipped `.sh` files — Linus adopter contract break.
|
|
74
|
+
|
|
75
|
+
Cure retrofit — `pre-push-shellcheck.sh` now sources `lib/install-written-paths.sh` with fail-soft and filters `EXISTING_FILES` through `is_install_written_path` before shellcheck fires. Adopter edits to install-written files mismatch the recorded content_hash and still get scanned (lib's existing contract). The sister test `.claude/hooks/tests/pre-push-shellcheck.test.sh` added one real-lib integration test (Test 19) per Feathers characterization — the integration test caught a `set -u` leak the stub tests missed. Cure guards sourced block with `set +u` scope.
|
|
76
|
+
|
|
70
77
|
## Deferred to follow-on
|
|
71
78
|
|
|
72
79
|
- `bassclef init` npm-side registration (lands in bassclef-cli; sources the lib via package symlink)
|
|
@@ -36,6 +36,29 @@ When a PR changes the manifest schema OR output shape:
|
|
|
36
36
|
3. **Downstream cure named** — the entry names what adopters need to do. If nothing (backward-compatible add), say so explicitly. If code change (like the v0.36.0 `upstream_commit` removal), name the pattern.
|
|
37
37
|
4. **Release script pre-flight** — before every `/release`, the script reads the ledger and confirms an entry exists for the outgoing `manifest_version`. Missing entry BLOCKs the cascade.
|
|
38
38
|
|
|
39
|
+
## Ledger-edit-then-regen order (bassclef-upstream#2110)
|
|
40
|
+
|
|
41
|
+
The ledger file at `standards/lite-manifest-schema-changes.md` is ITSELF a `tier: lite` artifact. Its content_hash lives inside the manifest. So the regen must capture the FINAL ledger state. Order matters:
|
|
42
|
+
|
|
43
|
+
1. **Edit ledger first.** Write the entry explaining the schema change.
|
|
44
|
+
2. **Regen second.** Run `scripts/generate-lite-manifest.sh`.
|
|
45
|
+
|
|
46
|
+
Natural authoring instinct is "regen first (see the hashes), then explain." That order ships a stale ledger hash in the manifest. CI drift check fails. A second regen commit is then needed.
|
|
47
|
+
|
|
48
|
+
**Preferred cure — use the wrapper.** `scripts/update-lite-manifest.sh` enforces the order:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Append a pre-written entry
|
|
52
|
+
scripts/update-lite-manifest.sh --entry-file path/to/entry.md
|
|
53
|
+
|
|
54
|
+
# Open $EDITOR on the ledger
|
|
55
|
+
scripts/update-lite-manifest.sh --edit
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Both modes hash the ledger before and after. The wrapper refuses to regen when the ledger is unchanged. Then it dispatches `scripts/generate-lite-manifest.sh` + the renderer when present.
|
|
59
|
+
|
|
60
|
+
Per `.claude/rules/bootstrap-pair-discipline.md` — the wrapper ships with Tier 0 tests at `scripts/tests/update-lite-manifest.test.sh`.
|
|
61
|
+
|
|
39
62
|
## Retirements
|
|
40
63
|
|
|
41
64
|
Retirement-class changes (content-remove: a file previously shipped in the lite manifest gets deleted intentionally) ship with the same discipline shape as additions. Three paired artifacts, same PR:
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: Any session that ships source code (files under src/, apps/, packages/, lib/, app/) MUST invoke Reviewer responsibilities before the session ends.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Reviewer Dispatch
|
|
7
|
+
|
|
8
|
+
Any session that ships source code (files under `src/`, `apps/`, `packages/`, `lib/`, `app/`) MUST invoke Reviewer responsibilities before the session ends. Mode-agnostic — orchestrator-gated mode dispatches the Reviewer agent; sequential mode self-invokes Reviewer responsibilities (read against spec, check tests, validate ADR compliance, flag TDD test-after patterns per Kent Beck).
|
|
9
|
+
|
|
10
|
+
The discipline lives at the rule layer (this file) plus the mechanical layer (`.claude/hooks/reviewer-dispatch-check.sh` — Stop hook). Both required for adopter code quality.
|
|
11
|
+
|
|
12
|
+
## When this rule fires
|
|
13
|
+
|
|
14
|
+
At session end (Stop event), the hook:
|
|
15
|
+
|
|
16
|
+
1. Counts source files changed since session-start (heuristic: `git diff` against `origin/main`; uncommitted + committed changes both count)
|
|
17
|
+
2. Path matchers for "source": `src/`, `apps/`, `packages/`, `lib/`, `app/`
|
|
18
|
+
3. When source count > 0, the hook checks for any marker at `state/markers/reviewer/*.md`
|
|
19
|
+
4. When no marker exists, the hook BLOCKs with reviewer-checklist remediation
|
|
20
|
+
|
|
21
|
+
## Reviewer marker contract
|
|
22
|
+
|
|
23
|
+
The marker captures the Reviewer pass per the agent definition (`~/.claude/agents/reviewer.md`):
|
|
24
|
+
|
|
25
|
+
```markdown
|
|
26
|
+
# Reviewer pass — <session-id>
|
|
27
|
+
|
|
28
|
+
mode: sequential | orchestrator-gated
|
|
29
|
+
reviewed_at: <ISO-8601>
|
|
30
|
+
source_files_changed: <count>
|
|
31
|
+
wu_id: <e.g., bet-2026-06-25k WU-3> # bet 25k WU-5 extension
|
|
32
|
+
iteration_count: <N> # bet 25k WU-5 extension
|
|
33
|
+
lens_used: [<luminary-slug>, ...] # bet 25k WU-5 extension
|
|
34
|
+
|
|
35
|
+
## Checks
|
|
36
|
+
- spec acceptance criteria: PASS | FAIL | N/A
|
|
37
|
+
- tests present + green: PASS | FAIL
|
|
38
|
+
- test-after pattern check: NONE FOUND | FOUND (list)
|
|
39
|
+
- ADR compliance: PASS | N/A
|
|
40
|
+
- Designer sign-off: PRESENT | N/A
|
|
41
|
+
- architect-review: INVOKED | N/A
|
|
42
|
+
|
|
43
|
+
## Findings
|
|
44
|
+
- <severity>: <description> # BLOCK / WARN / NOTE
|
|
45
|
+
|
|
46
|
+
acknowledged: true
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Field extensions per bassclef-upstream#366 (bet 25k WU-5)
|
|
50
|
+
|
|
51
|
+
Three fields extend the prior contract to make the /loop discipline auditable per step:
|
|
52
|
+
|
|
53
|
+
- **`wu_id`** — goal identifier + WU number (e.g., `bet-2026-06-25k WU-3`). Lets future audits grep markers by WU. Required when the marker is written under /longrun dispatch; optional for ad-hoc reviews.
|
|
54
|
+
- **`iteration_count`** — number of /loop iterations the step ran before landing GREEN. Iteration 1 GREEN is the cleanest path; counts above 1 record rework cycles (RED → fix → GREEN). Required under /longrun dispatch.
|
|
55
|
+
- **`lens_used`** — YAML list of luminary slugs that drove the review. Mirrors the goal doc's `authoring_luminaries` for the relevant WU. Required under /longrun dispatch.
|
|
56
|
+
|
|
57
|
+
The three fields together let future operators answer questions like "which WUs in bet 25k ran more than one /loop iteration" or "which luminary lens caught the most rework" by greppable markers, not by chronicle archaeology. The mechanical layer (greppable fields) compounds across every goal; the bar (`## /temperance + /luminary + /loop discipline` section in the PR body) gives the immediate operator-visible read.
|
|
58
|
+
|
|
59
|
+
Forward-only enforcement. Markers written before WU-5 stay as-is; markers written from WU-5 onwards carry the three new fields under /longrun dispatch.
|
|
60
|
+
|
|
61
|
+
## Mode behavior
|
|
62
|
+
|
|
63
|
+
**Orchestrator-gated mode** — orchestrator dispatches Reviewer agent at code-shipping handoffs. Reviewer agent reads against spec, runs checks, writes the marker per the contract above, returns PASS/FAIL/WARN findings to orchestrator.
|
|
64
|
+
|
|
65
|
+
**Sequential mode** — agent self-invokes Reviewer responsibilities. Read the Reviewer agent definition. Apply checks against the session's source diff. Write the marker. The self-invocation is honor-system at the methodology layer; the marker is the mechanical evidence the hook reads.
|
|
66
|
+
|
|
67
|
+
## Override path
|
|
68
|
+
|
|
69
|
+
`SKIP_REVIEWER_CHECK=1 <command>` — logged via trace-helper. Use rarely:
|
|
70
|
+
|
|
71
|
+
- Documentation-only session that accidentally touched a comment in src/ (operator confirms the source touch is non-behavioral)
|
|
72
|
+
- Emergency rescue when the hook itself misclassifies (file substrate-defect)
|
|
73
|
+
- One-shot migration script that ships hundreds of source files (operator has reviewed externally)
|
|
74
|
+
- Bulk dependency-bump where the package-manager touched lockfile entries only
|
|
75
|
+
|
|
76
|
+
INSTEAD of overriding for routine work: write the marker. The Reviewer-self-invocation cost is small (~5 minutes); the audit trail compounds across every adopter session.
|
|
77
|
+
|
|
78
|
+
## What the rule does NOT cover
|
|
79
|
+
|
|
80
|
+
- Code review process content (covered in `~/.claude/agents/reviewer.md`)
|
|
81
|
+
- TDD test-list discipline (covered in `.claude/rules/test-list-discipline.md`)
|
|
82
|
+
- Sufficiency rubric for tests (covered in `.claude/rules/test-sufficiency.md`)
|
|
83
|
+
- ADR discipline (covered in `.claude/rules/adr-discipline.md`)
|
|
84
|
+
- Architect review timing (covered in `.claude/skills/architect-review/SKILL.md`)
|
|
85
|
+
|
|
86
|
+
This rule is the gate. Sister rules + skills carry the content.
|
|
87
|
+
|
|
88
|
+
## Composition with other rules
|
|
89
|
+
|
|
90
|
+
- `.claude/rules/testing-tier-config.md` — Tier 0 strict-TDD on hook + tests (this hook + its test file land Tier 0)
|
|
91
|
+
- `.claude/rules/blocked-items.md` — BLOCK protocol the hook fires
|
|
92
|
+
- `.claude/rules/test-sufficiency.md` — what Reviewer checks for under "tests present + green"
|
|
93
|
+
- `.claude/rules/test-list-discipline.md` — what Reviewer checks for under "test-after pattern check" (Beck's test-list-as-planning-artifact)
|
|
94
|
+
- `.claude/rules/adr-discipline.md` — what Reviewer checks for under "ADR compliance"
|
|
95
|
+
- `~/.claude/agents/reviewer.md` — the full Reviewer responsibilities definition
|
|
@@ -52,6 +52,11 @@
|
|
|
52
52
|
"type": "command",
|
|
53
53
|
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/git-stash-u-guard.sh",
|
|
54
54
|
"timeout": 5
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"type": "command",
|
|
58
|
+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-push-shellcheck.sh",
|
|
59
|
+
"timeout": 60
|
|
55
60
|
}
|
|
56
61
|
]
|
|
57
62
|
},
|
|
@@ -167,6 +172,11 @@
|
|
|
167
172
|
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/turn-prose-grade-measure.sh",
|
|
168
173
|
"timeout": 10
|
|
169
174
|
},
|
|
175
|
+
{
|
|
176
|
+
"type": "command",
|
|
177
|
+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/turn-prose-density-measure.sh",
|
|
178
|
+
"timeout": 10
|
|
179
|
+
},
|
|
170
180
|
{
|
|
171
181
|
"type": "command",
|
|
172
182
|
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/longrun-prep-compounding-sequence-check.sh",
|