@thebassclef/lite 1.1.0 → 1.2.0-alpha.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.
Files changed (135) hide show
  1. package/dist/cli.cjs +258 -63
  2. package/dist/cli.js +258 -63
  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 +12 -5
  135. /package/dist/lite/{whereami.md → docs/whereami.md} +0 -0
@@ -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