@thebassclef/lite 1.1.1 → 1.2.0

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.
Files changed (135) hide show
  1. package/dist/cli.cjs +23 -6
  2. package/dist/cli.js +23 -6
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/lite/.claude/bassclef-configs.jsonc +56 -0
  7. package/dist/lite/.claude/bassclef-orientation.md +120 -0
  8. package/dist/lite/.claude/hooks/adr-discipline-check.sh +132 -0
  9. package/dist/lite/.claude/hooks/atomic-pr-check.sh +169 -0
  10. package/dist/lite/.claude/hooks/auto-save-idle.sh +51 -0
  11. package/dist/lite/.claude/hooks/bassclef-sync.sh +51 -13
  12. package/dist/lite/.claude/hooks/bet-doc-gate.sh +283 -0
  13. package/dist/lite/.claude/hooks/bug-diagnosis.sh +64 -0
  14. package/dist/lite/.claude/hooks/destructive-command-guard.sh +136 -0
  15. package/dist/lite/.claude/hooks/file-rename-discipline-check.sh +147 -0
  16. package/dist/lite/.claude/hooks/hook-classifier-canary.sh +158 -0
  17. package/dist/lite/.claude/hooks/kiss-default-check.sh +129 -0
  18. package/dist/lite/.claude/hooks/multi-tenancy-check.sh +83 -0
  19. package/dist/lite/.claude/hooks/oo-ad-entry-point-check.sh +216 -0
  20. package/dist/lite/.claude/hooks/operator-private-path-check.sh +203 -0
  21. package/dist/lite/.claude/hooks/pattern-annotation-validate.sh +142 -0
  22. package/dist/lite/.claude/hooks/plain-english-steering.sh +15 -1
  23. package/dist/lite/.claude/hooks/post-write-trace.sh +66 -0
  24. package/dist/lite/.claude/hooks/pr-body-scrub-check.sh +446 -0
  25. package/dist/lite/.claude/hooks/pre-commit-identifier-leak-scrub.sh +137 -0
  26. package/dist/lite/.claude/hooks/pre-gh-pr-body-scrub.sh +192 -0
  27. package/dist/lite/.claude/hooks/pre-gh-pr-title-scrub.sh +172 -0
  28. package/dist/lite/.claude/hooks/role-entry-gate.sh +115 -0
  29. package/dist/lite/.claude/hooks/save-state.sh +268 -0
  30. package/dist/lite/.claude/hooks/session-reflection.d/08-settings-drift.sh +8 -1
  31. package/dist/lite/.claude/hooks/session-reflection.d/10-abrupt-stop-recovery.sh +52 -0
  32. package/dist/lite/.claude/hooks/session-reflection.d/55-orientation-gate.sh +40 -4
  33. package/dist/lite/.claude/hooks/session-reflection.d/80-hook-heartbeat-check.sh +12 -5
  34. package/dist/lite/.claude/hooks/session-reflection.d/81-hook-manifest-staleness.sh +18 -2
  35. package/dist/lite/.claude/hooks/session-reflection.d/91-npm-version-drift.sh +54 -0
  36. package/dist/lite/.claude/hooks/session-reflection.d/tests/10-abrupt-stop-recovery.test.sh +95 -0
  37. package/dist/lite/.claude/hooks/session-reflection.sh +62 -15
  38. package/dist/lite/.claude/hooks/tool-failure-diagnosis.sh +50 -0
  39. package/dist/lite/.claude/luminaries/andrej-karpathy.md +165 -0
  40. package/dist/lite/.claude/luminaries/dave-gray.md +155 -0
  41. package/dist/lite/.claude/luminaries/gary-klein.md +166 -0
  42. package/dist/lite/.claude/luminaries/kaoru-ishikawa.md +162 -0
  43. package/dist/lite/.claude/luminaries/lean-product-canvas.md +33 -0
  44. package/dist/lite/.claude/luminaries/luke-wroblewski.md +224 -0
  45. package/dist/lite/.claude/luminaries/ryan-singer.md +113 -0
  46. package/dist/lite/.claude/luminaries/steve-krug.md +168 -0
  47. package/dist/lite/.claude/luminaries/tony-ulwick.md +134 -0
  48. package/dist/lite/.claude/rules/arc-level-orientation-before-leaf.md +60 -0
  49. package/dist/lite/.claude/rules/architect-review-discipline.md +71 -0
  50. package/dist/lite/.claude/rules/auto-fix-criteria.md +126 -0
  51. package/dist/lite/.claude/rules/bassclef-hook-drift-blocker.md +144 -0
  52. package/dist/lite/.claude/rules/bassclef-models-discovery.md +107 -0
  53. package/dist/lite/.claude/rules/bassclef-workflow-parity.md +104 -0
  54. package/dist/lite/.claude/rules/cost-governance.md +154 -0
  55. package/dist/lite/.claude/rules/file-rename-discipline.md +95 -0
  56. package/dist/lite/.claude/rules/mechanism-fidelity.md +88 -0
  57. package/dist/lite/.claude/rules/prototype-production-coupling.md +125 -0
  58. package/dist/lite/.claude/rules/quick-fix-criteria.md +90 -0
  59. package/dist/lite/.claude/rules/session-artifacts.md +30 -0
  60. package/dist/lite/.claude/rules/sibling-smoke-after-substrate-change.md +107 -0
  61. package/dist/lite/.claude/rules/substrate-as-system.md +67 -0
  62. package/dist/lite/.claude/rules/usability.md +22 -0
  63. package/dist/lite/.claude/settings.json +20 -0
  64. package/dist/lite/.claude/skills/agent-research-spawn/SKILL.md +100 -0
  65. package/dist/lite/.claude/skills/architect-review/SKILL.md +201 -0
  66. package/dist/lite/.claude/skills/auto-fix/SKILL.md +297 -0
  67. package/dist/lite/.claude/skills/autonomous/SKILL.md +300 -0
  68. package/dist/lite/.claude/skills/bind-subdomain/SKILL.md +232 -0
  69. package/dist/lite/.claude/skills/canvas/SKILL.md +41 -0
  70. package/dist/lite/.claude/skills/deploy-prod/SKILL.md +106 -0
  71. package/dist/lite/.claude/skills/docs-sync/SKILL.md +188 -0
  72. package/dist/lite/.claude/skills/eisenhower/SKILL.md +273 -0
  73. package/dist/lite/.claude/skills/empathy-map/SKILL.md +168 -0
  74. package/dist/lite/.claude/skills/frontend-design/SKILL.md +53 -0
  75. package/dist/lite/.claude/skills/interview-me/SKILL.md +171 -0
  76. package/dist/lite/.claude/skills/journal-export/SKILL.md +293 -0
  77. package/dist/lite/.claude/skills/jtbd-tasks/SKILL.md +203 -0
  78. package/dist/lite/.claude/skills/objectory-decompose/SKILL.md +256 -0
  79. package/dist/lite/.claude/skills/pick-luminaries/SKILL.md +100 -0
  80. package/dist/lite/.claude/skills/pre-mortem/SKILL.md +180 -0
  81. package/dist/lite/.claude/skills/prototype-gallery/SKILL.md +264 -0
  82. package/dist/lite/.claude/skills/provision-deploy-host/SKILL.md +257 -0
  83. package/dist/lite/.claude/skills/quick-fix/SKILL.md +273 -0
  84. package/dist/lite/.claude/skills/release/SKILL.md +311 -0
  85. package/dist/lite/.claude/skills/release-notes/SKILL.md +202 -0
  86. package/dist/lite/.claude/skills/rfc/SKILL.md +222 -0
  87. package/dist/lite/.claude/skills/riff-prototypes/SKILL.md +637 -0
  88. package/dist/lite/.claude/skills/secrets-bootstrap/SKILL.md +209 -0
  89. package/dist/lite/.claude/skills/skill/SKILL.md +304 -0
  90. package/dist/lite/.claude/skills/smoke-test/SKILL.md +100 -0
  91. package/dist/lite/.claude/skills/state/SKILL.md +204 -0
  92. package/dist/lite/.claude/skills/substrate-check/SKILL.md +218 -0
  93. package/dist/lite/.claude/skills/synthetic-user/SKILL.md +381 -0
  94. package/dist/lite/.claude/skills/task-scenarios/SKILL.md +105 -0
  95. package/dist/lite/.claude/skills/tier-dependency-audit/SKILL.md +139 -0
  96. package/dist/lite/.claude/skills/ux-migration/SKILL.md +424 -0
  97. package/dist/lite/.claude/skills/value-prop-canvas/SKILL.md +297 -0
  98. package/dist/lite/README.md +5 -1
  99. package/dist/lite/gitignore +6 -0
  100. package/dist/lite/lib/bassclef-dir-resolver.sh +85 -0
  101. package/dist/lite/lib/clone-failure-classifier.sh +59 -0
  102. package/dist/lite/lib/fixture-builder.sh +190 -0
  103. package/dist/lite/lib/fresh-install-check.sh +49 -0
  104. package/dist/lite/lib/hook-heartbeat.sh +0 -1
  105. package/dist/lite/lib/mechanism-fidelity.sh +569 -0
  106. package/dist/lite/lib/npm-version-check.sh +112 -0
  107. package/dist/lite/lib/preview-state.sh +229 -0
  108. package/dist/lite/lib/session-rescue.sh +0 -1
  109. package/dist/lite/scripts/generate-lite-manifest.sh +145 -4
  110. package/dist/lite/scripts/lite-manifest-drift-check.sh +5 -1
  111. package/dist/lite/standards/architect-review-discipline.md +222 -0
  112. package/dist/lite/standards/bassclef-platform.md +249 -0
  113. package/dist/lite/standards/bassclef-test-repos.md +97 -0
  114. package/dist/lite/standards/bassclef-wiring-manifest.json +25 -1
  115. package/dist/lite/standards/cold-adopter-harness.md +205 -0
  116. package/dist/lite/standards/data-management.md +135 -0
  117. package/dist/lite/standards/frontend-stack/nextjs-prisma.md +124 -0
  118. package/dist/lite/standards/lite-manifest-schema-changes.md +27 -0
  119. package/dist/lite/standards/lite-manifest.json +1456 -14
  120. package/dist/lite/standards/mechanism-fidelity.md +205 -0
  121. package/dist/lite/standards/operator-private-discipline.md +200 -0
  122. package/dist/lite/standards/operator-to-public-flow.md +195 -0
  123. package/dist/lite/standards/prototype-gallery.md +251 -0
  124. package/dist/lite/standards/pseudonym-key-schema.md +109 -0
  125. package/dist/lite/standards/sibling-validation-checklist.md +181 -0
  126. package/dist/lite/standards/slack-notifications.md +161 -0
  127. package/dist/lite/standards/synthetic-user-testing.md +173 -0
  128. package/dist/lite/standards/vendor-bindings.md +165 -0
  129. package/dist/lite/standards/vendor-plugins/frontend-design.md +66 -0
  130. package/dist/lite/standards/vpc-fit-validation.md +167 -0
  131. package/dist/lite/templates/gallery-yml.md +113 -0
  132. package/dist/lite/templates/product-canvas.md +169 -0
  133. package/dist/lite/templates/value-prop-canvas.md +180 -0
  134. package/package.json +3 -3
  135. /package/dist/lite/{whereami.md → docs/whereami.md} +0 -0
@@ -0,0 +1,216 @@
1
+ #!/bin/bash
2
+ # tier: lite
3
+ # oo-ad-entry-point-check.sh — PreToolUse Edit/Write hook mechanizing .claude/rules/oo-ad-entry-point.md.
4
+ #
5
+ # Fires on Write to a new file matching the rule's globs. Requires:
6
+ # 1. A decomposition marker at state/markers/decompose/<branch>.marker
7
+ # OR any file under docs/decompositions/
8
+ # 2. A use-case artifact under docs/use-cases/ matching the code class
9
+ #
10
+ # Per bassclef-upstream#1169 + canvas docs/canvases/2026-08-25-ooad-chain-as-substrate-offering.md.
11
+ # Composes with .claude/hooks/adr-discipline-check.sh (sister hook on architectural boundaries).
12
+ # Override: SKIP_OO_AD_ENTRY_POINT=1 (logged via trace-helper).
13
+
14
+ set -euo pipefail
15
+
16
+ # ============================================================================
17
+ # Read stdin JSON from Claude Code harness
18
+ # ============================================================================
19
+ PAYLOAD=$(cat 2>/dev/null || echo '{}')
20
+
21
+ TOOL_NAME=$(echo "$PAYLOAD" | jq -r '.tool_name // empty' 2>/dev/null)
22
+ FILE_PATH=$(echo "$PAYLOAD" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
23
+
24
+ # ============================================================================
25
+ # Filter: only fire on Write / Edit / MultiEdit
26
+ # ============================================================================
27
+ case "$TOOL_NAME" in
28
+ Write|Edit|MultiEdit) ;;
29
+ *) exit 0 ;;
30
+ esac
31
+
32
+ # Defensive precondition — empty file_path
33
+ if [ -z "$FILE_PATH" ]; then
34
+ exit 0
35
+ fi
36
+
37
+ # ============================================================================
38
+ # Override check
39
+ # ============================================================================
40
+ if [ "${SKIP_OO_AD_ENTRY_POINT:-0}" = "1" ]; then
41
+ TRACE_HELPER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/trace-helper.sh"
42
+ if [ -f "$TRACE_HELPER" ]; then
43
+ bash "$TRACE_HELPER" override "oo-ad-entry-point-check" "SKIP_OO_AD_ENTRY_POINT=1 on $FILE_PATH" 2>/dev/null || true
44
+ fi
45
+ exit 0
46
+ fi
47
+
48
+ # ============================================================================
49
+ # Path matcher — classify code class per rule oo-ad-entry-point.md L18-25
50
+ # Bash case globs do NOT expand ** — use per-level cases + src/ recursive fallback.
51
+ # ============================================================================
52
+ CODE_CLASS=""
53
+ case "$FILE_PATH" in
54
+ */.claude/hooks/*.sh|.claude/hooks/*.sh)
55
+ CODE_CLASS="substrate-hook"
56
+ ;;
57
+ */lib/*.sh|lib/*.sh)
58
+ CODE_CLASS="substrate-lib"
59
+ ;;
60
+ */scripts/*.sh|scripts/*.sh)
61
+ CODE_CLASS="adopter-script"
62
+ ;;
63
+ esac
64
+
65
+ # src/ handled via recursive path check — any depth under src/ with .ts/.tsx/.js/.py extension
66
+ if [ -z "$CODE_CLASS" ]; then
67
+ case "$FILE_PATH" in
68
+ src/*|*/src/*)
69
+ case "$FILE_PATH" in
70
+ *.ts|*.tsx|*.js|*.py) CODE_CLASS="adopter-app" ;;
71
+ esac
72
+ ;;
73
+ esac
74
+ fi
75
+
76
+ # Not a matched path → pass through
77
+ if [ -z "$CODE_CLASS" ]; then
78
+ exit 0
79
+ fi
80
+
81
+ # ============================================================================
82
+ # Cockburn casual tier — existing file Edit passes through
83
+ # ============================================================================
84
+ # Edit / MultiEdit on existing files needs no new artifacts per rule L24.
85
+ # Only new files (Write, OR Edit of missing file) require ceremony.
86
+ REPO_ROOT="${HOOK_TEST_REPO_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
87
+
88
+ # Resolve absolute path — file_path may be relative
89
+ if [ "${FILE_PATH:0:1}" = "/" ]; then
90
+ ABS_PATH="$FILE_PATH"
91
+ else
92
+ ABS_PATH="$REPO_ROOT/$FILE_PATH"
93
+ fi
94
+
95
+ if [ -f "$ABS_PATH" ]; then
96
+ exit 0
97
+ fi
98
+
99
+ # ============================================================================
100
+ # Decomposition check
101
+ # ============================================================================
102
+ BRANCH="${HOOK_TEST_BRANCH:-}"
103
+ if [ -z "$BRANCH" ]; then
104
+ BRANCH=$(cd "$REPO_ROOT" && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
105
+ fi
106
+
107
+ MARKER_PATH="$REPO_ROOT/state/markers/decompose/${BRANCH}.marker"
108
+ DECOMP_DIR="$REPO_ROOT/docs/decompositions"
109
+
110
+ DECOMP_OK=0
111
+ if [ -f "$MARKER_PATH" ]; then
112
+ DECOMP_OK=1
113
+ elif [ -d "$DECOMP_DIR" ] && find "$DECOMP_DIR" -maxdepth 1 -name '*.md' -type f 2>/dev/null | grep -q .; then
114
+ DECOMP_OK=1
115
+ fi
116
+
117
+ # ============================================================================
118
+ # Use case check per code class
119
+ # ============================================================================
120
+ UC_DIR="$REPO_ROOT/docs/use-cases"
121
+ UC_OK=0
122
+
123
+ if [ -d "$UC_DIR" ]; then
124
+ case "$CODE_CLASS" in
125
+ adopter-app)
126
+ # UC-*.md that does NOT start with UC-hook-, UC-lib-, or UC-script-
127
+ if find "$UC_DIR" -maxdepth 1 -name 'UC-*.md' -type f \
128
+ -not -name 'UC-hook-*' -not -name 'UC-lib-*' -not -name 'UC-script-*' \
129
+ 2>/dev/null | grep -q .; then
130
+ UC_OK=1
131
+ fi
132
+ ;;
133
+ substrate-hook)
134
+ if find "$UC_DIR" -maxdepth 1 -name 'UC-hook-*.md' -type f 2>/dev/null | grep -q .; then
135
+ UC_OK=1
136
+ fi
137
+ ;;
138
+ substrate-lib)
139
+ if find "$UC_DIR" -maxdepth 1 -name 'UC-lib-*.md' -type f 2>/dev/null | grep -q .; then
140
+ UC_OK=1
141
+ fi
142
+ ;;
143
+ adopter-script)
144
+ if find "$UC_DIR" -maxdepth 1 -name 'UC-script-*.md' -type f 2>/dev/null | grep -q .; then
145
+ UC_OK=1
146
+ fi
147
+ ;;
148
+ esac
149
+ fi
150
+
151
+ # ============================================================================
152
+ # Pass or block
153
+ # ============================================================================
154
+ if [ "$DECOMP_OK" -eq 1 ] && [ "$UC_OK" -eq 1 ]; then
155
+ exit 0
156
+ fi
157
+
158
+ # ============================================================================
159
+ # Block message
160
+ # ============================================================================
161
+ case "$CODE_CLASS" in
162
+ adopter-app)
163
+ CEREMONY="Fully-dressed use case + /decompose + /spec"
164
+ UC_PATTERN="docs/use-cases/UC-<slug>.md"
165
+ ;;
166
+ substrate-hook)
167
+ CEREMONY="Brief use case + /decompose"
168
+ UC_PATTERN="docs/use-cases/UC-hook-<slug>.md"
169
+ ;;
170
+ substrate-lib)
171
+ CEREMONY="Brief use case + /decompose"
172
+ UC_PATTERN="docs/use-cases/UC-lib-<slug>.md"
173
+ ;;
174
+ adopter-script)
175
+ CEREMONY="Brief use case + Tier 0 tests"
176
+ UC_PATTERN="docs/use-cases/UC-script-<slug>.md"
177
+ ;;
178
+ esac
179
+
180
+ cat >&2 <<EOF
181
+ 🛑 oo-ad-entry-point-check — BLOCK (bassclef-upstream#1169)
182
+
183
+ You are creating a new file in the ${CODE_CLASS} class.
184
+
185
+ Path: ${FILE_PATH}
186
+ Branch: ${BRANCH}
187
+
188
+ The rule .claude/rules/oo-ad-entry-point.md requires design artifacts
189
+ before this file lands. Ceremony for this class:
190
+ ${CEREMONY}
191
+
192
+ Missing artifacts:
193
+ $([ "$DECOMP_OK" -eq 0 ] && echo " - Decomposition: marker at ${MARKER_PATH} OR any file under docs/decompositions/")
194
+ $([ "$UC_OK" -eq 0 ] && echo " - Use case: ${UC_PATTERN}")
195
+
196
+ Three resolution paths:
197
+
198
+ 1. Run /decompose to produce the decomposition, then write a use case.
199
+ Touch the marker after:
200
+ mkdir -p $(dirname "$MARKER_PATH")
201
+ touch $MARKER_PATH
202
+
203
+ 2. Write the artifacts by hand per the rule table (L18-25) and touch
204
+ the marker.
205
+
206
+ 3. Override for genuine trivial work:
207
+ SKIP_OO_AD_ENTRY_POINT=1 <command>
208
+
209
+ Then retry the original write.
210
+
211
+ Per .claude/rules/oo-ad-entry-point.md
212
+ Composes with .claude/hooks/adr-discipline-check.sh
213
+ Cockburn ceremony tiering — Writing Effective Use Cases (2000)
214
+ EOF
215
+
216
+ exit 2
@@ -0,0 +1,203 @@
1
+ #!/bin/bash
2
+ # tier: lite
3
+ # Operator-private path enforcement — Rule 3 of bassclef#739
4
+ # Per bassclef#769 (canvas-path discipline) + bassclef#803 (persona-review extension).
5
+ #
6
+ # Checks: persona-review-shaped + canvas-shaped artifacts must live under
7
+ # docs/operator-private/<artifact-type>/. Public-tree placement is explicit
8
+ # operator request via PR label `bassclef-internal-prose-ok` (shared with
9
+ # Rule 1 + Rule 4) OR commit footer `SKIP_OPERATOR_PRIVATE_PATH=1`.
10
+ #
11
+ # Shape patterns flagged outside docs/operator-private/:
12
+ #
13
+ # 1. Persona-review-shaped (any of):
14
+ # - Path matches docs/persona-reviews/**
15
+ # - Filename matches *-review*.md OR *-persona-review*.md
16
+ # AND located outside docs/operator-private/persona-reviews/
17
+ #
18
+ # 2. Canvas-shaped (any of):
19
+ # - Path matches docs/strategy/canvases/** AND filename contains canvas-related
20
+ # keywords (lean-canvas, value-prop-canvas, chain-of-beliefs)
21
+ # - Filename matches *-canvas.md OR *-chain-of-beliefs.md
22
+ # AND located outside docs/operator-private/canvases/
23
+ # AND not under templates/ or presence/install/ (scaffolds + adopter assets are public)
24
+ #
25
+ # Usage:
26
+ # bash operator-private-path-check.sh <changed-files-list>
27
+ #
28
+ # <changed-files-list> is a newline-separated file of changed paths
29
+ # (from `git diff --name-only`).
30
+ #
31
+ # Optional env:
32
+ # PR_LABELS=label1,label2,... — labels on the PR
33
+ # STRICT_MODE=1 — force blocking even with override label
34
+ #
35
+ # Exit codes:
36
+ # 0 — pass (no violations, OR violations + override label present)
37
+ # 1 — block (violations + no override)
38
+ # 2 — usage error
39
+
40
+ set +e
41
+
42
+ CHANGED_FILES="${1:-}"
43
+ if [ -z "$CHANGED_FILES" ] || [ ! -f "$CHANGED_FILES" ]; then
44
+ echo "usage: $0 <changed-files-list>" >&2
45
+ exit 2
46
+ fi
47
+
48
+ PR_LABELS="${PR_LABELS:-}"
49
+ STRICT_MODE="${STRICT_MODE:-0}"
50
+
51
+ LABELS_NORMALIZED=$(echo "$PR_LABELS" | tr ',' '\n' | sed 's/^ *//;s/ *$//' | grep -v '^$' || true)
52
+
53
+ HAS_OVERRIDE=0
54
+ if [ "$STRICT_MODE" != "1" ]; then
55
+ if echo "$LABELS_NORMALIZED" | grep -qx "bassclef-internal-prose-ok"; then
56
+ HAS_OVERRIDE=1
57
+ fi
58
+ fi
59
+
60
+ PERSONA_REVIEW_VIOLATIONS=""
61
+ CANVAS_VIOLATIONS=""
62
+ PR_COUNT=0
63
+ CV_COUNT=0
64
+
65
+ while IFS= read -r path; do
66
+ [ -z "$path" ] && continue
67
+
68
+ # Skip files inside the bassclef operator-private tree
69
+ case "$path" in
70
+ docs/operator-private/*) continue ;;
71
+ esac
72
+
73
+ # Skip templates + distribution assets (public; used as scaffolding sources)
74
+ # Per bassclef-upstream#317 reorg: templates/ + presence/install/ replaced
75
+ # strategy/templates/ as public-scaffold homes.
76
+ case "$path" in
77
+ templates/*) continue ;;
78
+ presence/install/*) continue ;;
79
+ esac
80
+
81
+ # Skip itself + the hook test fixtures
82
+ case "$path" in
83
+ .claude/hooks/operator-private-path-check.sh) continue ;;
84
+ .claude/hooks/tests/operator-private-path-check.test.sh) continue ;;
85
+ esac
86
+
87
+ # Skip Feathers rollback snapshots of rule bodies under docs/rule-history/
88
+ # These are byte-identical copies of rule files; filenames match source
89
+ # rule names (e.g., architect-review-discipline.md) which false-positive
90
+ # on the persona-review regex. Landed via bassclef-upstream PR #1649.
91
+ case "$path" in
92
+ docs/rule-history/*) continue ;;
93
+ esac
94
+
95
+ # Skip substrate definition directories (#1700 sister). A persona review or
96
+ # a canvas never lives in one of these — they hold rules, luminaries, skills,
97
+ # agents, hooks, standards, libs and scripts, each with its own naming and
98
+ # tier gates. Before this narrowing the check flagged
99
+ # `.claude/rules/architect-review-discipline.md` (matched `-review-[a-z]+`)
100
+ # and `.claude/luminaries/lean-product-canvas.md` (matched `-canvas.md`),
101
+ # neither of which is an operator-private artifact. Named as a deferred
102
+ # follow-on in .claude/rules/bootstrap-pair-discipline.md.
103
+ #
104
+ # The narrowing does not weaken the rule: docs/ and strategy/ paths, where
105
+ # these artifacts actually live, still fire. Pinned by the negative test in
106
+ # .claude/hooks/tests/operator-private-path-check.test.sh.
107
+ case "$path" in
108
+ .claude/rules/*|.claude/luminaries/*|.claude/skills/*|.claude/agents/*|.claude/hooks/*) continue ;;
109
+ standards/*|lib/*|scripts/*) continue ;;
110
+ esac
111
+
112
+ filename=$(basename "$path")
113
+
114
+ # === Rule 3 Shape 1 — persona-review-shaped ===
115
+ case "$path" in
116
+ docs/persona-reviews/*)
117
+ PERSONA_REVIEW_VIOLATIONS="${PERSONA_REVIEW_VIOLATIONS}- \`${path}\` — under \`docs/persona-reviews/\` (legacy path; relocate to \`docs/operator-private/persona-reviews/\`)"$'\n'
118
+ PR_COUNT=$((PR_COUNT + 1))
119
+ continue
120
+ ;;
121
+ esac
122
+
123
+ # Filename pattern check for persona-review (case-insensitive)
124
+ if echo "$filename" | grep -qiE '(^|[-_])(persona-review|persona_review)|.*-review-[a-z]+\.md$|persona-review.*\.md$'; then
125
+ PERSONA_REVIEW_VIOLATIONS="${PERSONA_REVIEW_VIOLATIONS}- \`${path}\` — filename pattern matches persona-review (relocate to \`docs/operator-private/persona-reviews/\`)"$'\n'
126
+ PR_COUNT=$((PR_COUNT + 1))
127
+ continue
128
+ fi
129
+
130
+ # === Rule 3 Shape 2 — canvas-shaped ===
131
+ # Filename pattern check for canvas
132
+ if echo "$filename" | grep -qiE '\-lean\-canvas\.md$|\-value\-prop\-canvas\.md$|\-chain\-of\-beliefs\.md$|\-canvas\.md$'; then
133
+ CANVAS_VIOLATIONS="${CANVAS_VIOLATIONS}- \`${path}\` — filename pattern matches canvas-shaped (relocate to \`docs/operator-private/canvases/\`)"$'\n'
134
+ CV_COUNT=$((CV_COUNT + 1))
135
+ continue
136
+ fi
137
+
138
+ # Path-based: under strategy/canvases/ but not template/example
139
+ case "$path" in
140
+ strategy/canvases/*.md)
141
+ # Allow strategy/canvases/* only if it's the public-tree exception
142
+ # (verified by operator request via override label). Without override,
143
+ # this is a violation.
144
+ CANVAS_VIOLATIONS="${CANVAS_VIOLATIONS}- \`${path}\` — under \`strategy/canvases/\` (relocate to \`docs/operator-private/canvases/\` unless explicit public-tree placement)"$'\n'
145
+ CV_COUNT=$((CV_COUNT + 1))
146
+ ;;
147
+ esac
148
+
149
+ done < "$CHANGED_FILES"
150
+
151
+ TOTAL=$((PR_COUNT + CV_COUNT))
152
+
153
+ if [ "$TOTAL" -eq 0 ]; then
154
+ echo "PASS — no operator-private path violations"
155
+ exit 0
156
+ fi
157
+
158
+ echo "==============================================="
159
+ echo "Operator-private path violations (bassclef#739 Rule 3)"
160
+ echo "==============================================="
161
+ echo ""
162
+
163
+ if [ -n "$PERSONA_REVIEW_VIOLATIONS" ]; then
164
+ echo "## Persona-review-shaped artifacts outside operator-private (${PR_COUNT})"
165
+ echo ""
166
+ echo "$PERSONA_REVIEW_VIOLATIONS"
167
+ echo ""
168
+ fi
169
+
170
+ if [ -n "$CANVAS_VIOLATIONS" ]; then
171
+ echo "## Canvas-shaped artifacts outside operator-private (${CV_COUNT})"
172
+ echo ""
173
+ echo "$CANVAS_VIOLATIONS"
174
+ echo ""
175
+ fi
176
+
177
+ echo "==============================================="
178
+ echo "Why this rule fires:"
179
+ echo ""
180
+ echo "Persona-review-shaped + canvas-shaped artifacts default to"
181
+ echo " docs/operator-private/<artifact-type>/"
182
+ echo "Public-tree placement is explicit operator request, not default."
183
+ echo ""
184
+ echo "Per bassclef#769 (canvas-path discipline) + bassclef#803 (persona-review extension):"
185
+ echo "- Canvases live at: docs/operator-private/canvases/"
186
+ echo "- Persona reviews live at: docs/operator-private/persona-reviews/"
187
+ echo ""
188
+ echo "Resolution paths:"
189
+ echo ""
190
+ echo "1. Relocate the file to docs/operator-private/<artifact-type>/"
191
+ echo " (use git mv to preserve history)"
192
+ echo ""
193
+ echo "2. Add label \`bassclef-internal-prose-ok\` to the PR if public-tree"
194
+ echo " placement is intentional (e.g., template, example, public-facing reference)."
195
+ echo "==============================================="
196
+
197
+ if [ "$HAS_OVERRIDE" -eq 1 ]; then
198
+ echo ""
199
+ echo "ADVISORY — \`bassclef-internal-prose-ok\` label present; downgraded from blocking."
200
+ exit 0
201
+ fi
202
+
203
+ exit 1
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env bash
2
+ # tier: lite
3
+ # pattern-annotation-validate.sh — Layer 3 of bassclef#478 traceability.
4
+ #
5
+ # Fires on PreToolUse for Edit/Write/MultiEdit. When the file being written
6
+ # is source code (src/**, scripts/**, lib/**, .claude/**) and contains
7
+ # @pattern annotations, validate that each annotation points to an existing
8
+ # catalog entry under patterns/<shelf>/<source>/<slug>.md. BLOCK on missing
9
+ # catalog paths.
10
+ #
11
+ # Also auto-populates state/pattern-implementations/*.json manifest entries
12
+ # via state_pattern_implementation_set accessor (post-validation).
13
+ #
14
+ # Override: SKIP_PATTERN_ANNOTATION=1 <command> — logged.
15
+
16
+ set -euo pipefail
17
+
18
+ # Read tool input from stdin (Claude Code hook protocol).
19
+ INPUT="${1:-$(cat)}"
20
+
21
+ # Skip when override is set.
22
+ if [ "${SKIP_PATTERN_ANNOTATION:-0}" = "1" ]; then
23
+ echo "[pattern-annotation-validate: SKIP_PATTERN_ANNOTATION=1; bypassing]" >&2
24
+ exit 0
25
+ fi
26
+
27
+ # Extract tool name + file path from JSON input.
28
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null || echo "")
29
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || echo "")
30
+ NEW_CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null || echo "")
31
+
32
+ # Only fire on Edit/Write/MultiEdit.
33
+ case "$TOOL_NAME" in
34
+ Edit|Write|MultiEdit) ;;
35
+ *) exit 0 ;;
36
+ esac
37
+
38
+ # Only fire on source-code paths.
39
+ case "$FILE_PATH" in
40
+ */src/*|*/scripts/*|*/lib/*|*/.claude/skills/*|*/.claude/hooks/*) ;;
41
+ *) exit 0 ;;
42
+ esac
43
+
44
+ # Skip if file doesn't currently exist (Write of new file) AND new content
45
+ # has no @pattern annotation — no validation needed.
46
+ EXISTING_CONTENT=""
47
+ if [ -f "$FILE_PATH" ]; then
48
+ EXISTING_CONTENT=$(cat "$FILE_PATH")
49
+ fi
50
+
51
+ # Combine existing + new content for annotation extraction (covers both
52
+ # Write of new files and Edit of existing).
53
+ COMBINED="${EXISTING_CONTENT}
54
+ ${NEW_CONTENT}"
55
+
56
+ # Extract @pattern annotations: match `@pattern\s+(patterns/...)`.
57
+ ANNOTATIONS=$(echo "$COMBINED" | grep -oE '@pattern[[:space:]]+patterns/[a-z0-9_-]+/[a-z0-9_-]+/[a-z0-9_-]+\.md' || true)
58
+
59
+ if [ -z "$ANNOTATIONS" ]; then
60
+ exit 0 # No annotations; nothing to validate.
61
+ fi
62
+
63
+ # Get repo root.
64
+ REPO_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
65
+
66
+ # For each annotation, check the catalog path exists.
67
+ INVALID=""
68
+ while IFS= read -r line; do
69
+ # Extract the catalog path from `@pattern patterns/...`
70
+ pattern_path=$(echo "$line" | sed -E 's/.*@pattern[[:space:]]+(patterns\/[a-z0-9_-]+\/[a-z0-9_-]+\/[a-z0-9_-]+\.md).*/\1/')
71
+ if [ ! -f "$REPO_ROOT/$pattern_path" ]; then
72
+ INVALID="${INVALID}${pattern_path}\n"
73
+ fi
74
+ done <<< "$ANNOTATIONS"
75
+
76
+ if [ -n "$INVALID" ]; then
77
+ cat >&2 <<EOF
78
+ ============================================
79
+ 🛑 PATTERN-ANNOTATION GATE — BLOCKED 🛑
80
+ ============================================
81
+
82
+ File: $FILE_PATH
83
+ Tool: $TOOL_NAME
84
+
85
+ Violation: @pattern annotation references catalog path that doesn't exist.
86
+
87
+ Missing catalog entries:
88
+ $(echo -e "$INVALID")
89
+
90
+ Resolution paths:
91
+ 1. Fix the annotation to point at an existing catalog entry (preferred).
92
+ 2. Run /agent-research-spawn to add the missing entry, then write.
93
+ 3. Override (logged): SKIP_PATTERN_ANNOTATION=1 <command>
94
+
95
+ Per rule: .claude/rules/pattern-annotation.md
96
+ Per ticket: bassclef#478 Layer 3
97
+ ============================================
98
+ EOF
99
+ exit 3 # Hook BLOCK exit code.
100
+ fi
101
+
102
+ # Validation passed; auto-populate manifest entries.
103
+ # (Best-effort; failures here are non-blocking.)
104
+ #
105
+ # Filter ephemeral paths before writing to manifest. The auto-populate path
106
+ # uses ${FILE_PATH#$REPO_ROOT/} to compute a relative path; if FILE_PATH is
107
+ # outside REPO_ROOT (e.g., test fixtures under /tmp or /var/folders), the
108
+ # substitution doesn't strip and the absolute path becomes the manifest key.
109
+ # That leaks ephemeral paths into git-tracked state. Skip these.
110
+ # Override: SKIP_PATTERN_ANNOTATION=1 (already handled above).
111
+ case "$FILE_PATH" in
112
+ /tmp/*|/var/folders/*)
113
+ # Test fixture path; skip manifest write.
114
+ exit 0
115
+ ;;
116
+ esac
117
+ case "$FILE_PATH" in
118
+ "$REPO_ROOT"/*) ;; # Inside repo — proceed.
119
+ *)
120
+ # File is outside REPO_ROOT (no leading match). Skip manifest write.
121
+ exit 0
122
+ ;;
123
+ esac
124
+
125
+ if command -v jq >/dev/null 2>&1; then
126
+ cd "$REPO_ROOT"
127
+ if [ -f "lib/state.sh" ]; then
128
+ # shellcheck disable=SC1091
129
+ source lib/state.sh 2>/dev/null || exit 0
130
+
131
+ # Re-extract annotations with line numbers from the COMBINED content.
132
+ while IFS= read -r line; do
133
+ pattern_path=$(echo "$line" | sed -E 's/.*@pattern[[:space:]]+(patterns\/[a-z0-9_-]+\/[a-z0-9_-]+\/[a-z0-9_-]+\.md).*/\1/')
134
+ # Find line number in the file (best-effort).
135
+ line_num=$(grep -nF "@pattern $pattern_path" "$FILE_PATH" 2>/dev/null | head -1 | cut -d: -f1 || echo "1")
136
+ relative_path="${FILE_PATH#$REPO_ROOT/}"
137
+ state_pattern_implementation_set "$relative_path" "$pattern_path" "$line_num" 2>/dev/null || true
138
+ done <<< "$ANNOTATIONS"
139
+ fi
140
+ fi
141
+
142
+ exit 0
@@ -83,10 +83,24 @@ ${OFFENDERS_BULLETS}"
83
83
  GRADE_LINE="
84
84
 
85
85
  **From your LAST turn (not this one): grade ${LAST_GRADE} (${LAST_WORDS} words). Target: grade 8 for 80%+ of prose. Ceiling: 10 for simple technical sentences. ${GRADE_STATUS}. THIS turn is not measured yet — self-check each sentence before I ship it.** (Per #1044 Option B: post-turn measurement + pre-turn injection means the number I see is one turn old by design.)${OFFENDERS_LINE}"
86
+ # cli#107 cure — fire the textstat-missing warning at most once per session.
87
+ # Prior version emitted this on every UserPromptSubmit fire, training the
88
+ # reader to skim the steering block it sits in. Marker under
89
+ # $HOME/.claude/state/sessions/<session-id>/ scopes the check to one
90
+ # session; fresh sessions get the warning once. Marker write failure is
91
+ # silent (never crashes the hook) per bassclef defensive-bash pattern.
86
92
  if [ "$SOURCE" = "FALLBACK" ]; then
87
- FALLBACK_WARNING="
93
+ __ts_session_id="${CLAUDE_SESSION_ID:-${PPID:-$$}}"
94
+ __ts_marker_dir="${CLAUDE_SESSION_STATE_DIR:-$HOME/.claude/state/sessions}/${__ts_session_id}"
95
+ __ts_marker="${__ts_marker_dir}/textstat-warned"
96
+ if [ ! -f "$__ts_marker" ]; then
97
+ FALLBACK_WARNING="
88
98
 
89
99
  **textstat not installed; grade uses the hand-rolled fallback. Numbers are approximate. Run \`pip install textstat\` for the sharper score.**"
100
+ mkdir -p "$__ts_marker_dir" 2>/dev/null || true
101
+ touch "$__ts_marker" 2>/dev/null || true
102
+ fi
103
+ unset __ts_session_id __ts_marker_dir __ts_marker
90
104
  fi
91
105
  fi
92
106
  fi
@@ -0,0 +1,66 @@
1
+ #!/bin/bash
2
+ # tier: lite
3
+ set -e
4
+
5
+ # Post-Write Traceability — fires on PostToolUse for Write/Edit.
6
+ # Checks that artifacts maintain traceability to their source.
7
+
8
+ INPUT=$(cat)
9
+ # Fail-soft on malformed JSON — match bassclef#1101 pre-commit-gate.sh
10
+ # pattern. Without the 2>/dev/null fallback, jq exit 5 + set -e crashes
11
+ # the hook on malformed harness payloads. Caught WU-5 of bet 2026-06-17c.
12
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null || echo "")
13
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null || echo "")
14
+
15
+ # Only check Write and Edit operations
16
+ if [ "$TOOL_NAME" != "Write" ] && [ "$TOOL_NAME" != "Edit" ]; then
17
+ exit 0
18
+ fi
19
+
20
+ # Skip non-markdown files (traceability is for documentation artifacts)
21
+ if ! echo "$FILE_PATH" | grep -qE '\.md$'; then
22
+ exit 0
23
+ fi
24
+
25
+ # Skip memory, config, and template files
26
+ if echo "$FILE_PATH" | grep -qE 'memory/|MEMORY\.md|CLAUDE\.md|AGENTS\.md|template|settings'; then
27
+ exit 0
28
+ fi
29
+
30
+ # === Spec traceability ===
31
+ if echo "$FILE_PATH" | grep -qiE 'specs?/'; then
32
+ echo ""
33
+ echo "TRACE CHECK: Spec written to $FILE_PATH"
34
+ echo " → Does this spec reference its source canvas or issue?"
35
+ echo " → Format: 'Source: [canvas path or issue #NNN]'"
36
+ echo ""
37
+ fi
38
+
39
+ # === Chronicle traceability ===
40
+ if echo "$FILE_PATH" | grep -qiE 'chronicle/'; then
41
+ echo ""
42
+ echo "TRACE CHECK: Chronicle written to $FILE_PATH"
43
+ echo " → Does it include commit refs in 'Work done' section?"
44
+ echo " → Does it have 'Open threads' for next session?"
45
+ echo ""
46
+ fi
47
+
48
+ # === ADR traceability ===
49
+ if echo "$FILE_PATH" | grep -qiE 'decisions/|adrs?/'; then
50
+ echo ""
51
+ echo "TRACE CHECK: ADR written to $FILE_PATH"
52
+ echo " → Does it reference the risk or issue that prompted it?"
53
+ echo " → Status set? (proposed/accepted/deprecated/superseded)"
54
+ echo ""
55
+ fi
56
+
57
+ # === Iteration bet traceability ===
58
+ if echo "$FILE_PATH" | grep -qiE 'iteration-bets?/'; then
59
+ echo ""
60
+ echo "TRACE CHECK: Iteration bet written to $FILE_PATH"
61
+ echo " → Does it reference specific issue numbers in scope?"
62
+ echo " → Does it declare the risk being retired?"
63
+ echo ""
64
+ fi
65
+
66
+ exit 0