@thebassclef/lite 0.1.2 → 1.0.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 (293) hide show
  1. package/dist/cli.cjs +238 -127
  2. package/dist/cli.js +240 -129
  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/.bassclef-source.json +10 -0
  7. package/dist/lite/.claude/settings.json +212 -0
  8. package/dist/lite/CLAUDE.md +41 -0
  9. package/dist/lite/gitignore +58 -0
  10. package/dist/lite/standards/bassclef-wiring-manifest.json +497 -0
  11. package/dist/lite/whereami.md +24 -0
  12. package/package.json +8 -2
  13. package/substrate/.bassclef/lite-manifest.json +0 -2701
  14. package/substrate/.claude/agents/architect.md +0 -70
  15. package/substrate/.claude/agents/builder.md +0 -114
  16. package/substrate/.claude/agents/designer.md +0 -156
  17. package/substrate/.claude/agents/reviewer.md +0 -88
  18. package/substrate/.claude/hooks/artifact-ingestion-gate.sh +0 -357
  19. package/substrate/.claude/hooks/assert-verify-steering.sh +0 -77
  20. package/substrate/.claude/hooks/bassclef-source-config-validate.sh +0 -215
  21. package/substrate/.claude/hooks/bassclef-sync.sh +0 -634
  22. package/substrate/.claude/hooks/compound-noun-scrub.sh +0 -292
  23. package/substrate/.claude/hooks/kiss-expansion-inject.sh +0 -69
  24. package/substrate/.claude/hooks/longrun-prep-compounding-axis-check.sh +0 -492
  25. package/substrate/.claude/hooks/longrun-prep-compounding-sequence-check.sh +0 -492
  26. package/substrate/.claude/hooks/plain-english-steering.sh +0 -156
  27. package/substrate/.claude/hooks/post-skill-friction-check.sh +0 -177
  28. package/substrate/.claude/hooks/post-skill-telemetry.sh +0 -62
  29. package/substrate/.claude/hooks/pre-build-gate.sh +0 -511
  30. package/substrate/.claude/hooks/pre-commit-gate.sh +0 -451
  31. package/substrate/.claude/hooks/session-end.sh +0 -433
  32. package/substrate/.claude/hooks/session-reflection.sh +0 -303
  33. package/substrate/.claude/hooks/skill-body-grade-gate.sh +0 -219
  34. package/substrate/.claude/hooks/skill-body-intent-drift.sh +0 -107
  35. package/substrate/.claude/hooks/skill-step-list-check.sh +0 -171
  36. package/substrate/.claude/hooks/state-validate.sh +0 -271
  37. package/substrate/.claude/hooks/substrate-clarity-gate.sh +0 -1110
  38. package/substrate/.claude/hooks/temperance-gate.sh +0 -147
  39. package/substrate/.claude/hooks/testing-tier-enforce.sh +0 -233
  40. package/substrate/.claude/hooks/turn-prose-grade-measure.sh +0 -219
  41. package/substrate/.claude/hooks/turn-prose-kiss-check.sh +0 -463
  42. package/substrate/.claude/hooks/vocabulary-migration-check.sh +0 -171
  43. package/substrate/.claude/hooks/whereami-utc-gate.sh +0 -142
  44. package/substrate/.claude/luminaries/alan-cooper.md +0 -170
  45. package/substrate/.claude/luminaries/alistair-cockburn.md +0 -140
  46. package/substrate/.claude/luminaries/amazon-pr-faq.md +0 -34
  47. package/substrate/.claude/luminaries/ash-maurya.md +0 -121
  48. package/substrate/.claude/luminaries/bill-buxton.md +0 -210
  49. package/substrate/.claude/luminaries/charles-sanders-peirce.md +0 -150
  50. package/substrate/.claude/luminaries/david-ogilvy.md +0 -192
  51. package/substrate/.claude/luminaries/don-norman.md +0 -173
  52. package/substrate/.claude/luminaries/edward-tufte.md +0 -179
  53. package/substrate/.claude/luminaries/eric-evans.md +0 -160
  54. package/substrate/.claude/luminaries/frederick-brooks.md +0 -50
  55. package/substrate/.claude/luminaries/gang-of-four.md +0 -157
  56. package/substrate/.claude/luminaries/glenford-myers.md +0 -230
  57. package/substrate/.claude/luminaries/hunt-thomas.md +0 -115
  58. package/substrate/.claude/luminaries/hyrum-wright.md +0 -94
  59. package/substrate/.claude/luminaries/jason-fried-dhh.md +0 -46
  60. package/substrate/.claude/luminaries/jesse-james-garrett.md +0 -154
  61. package/substrate/.claude/luminaries/john-ousterhout.md +0 -94
  62. package/substrate/.claude/luminaries/karl-popper.md +0 -132
  63. package/substrate/.claude/luminaries/kent-beck.md +0 -168
  64. package/substrate/.claude/luminaries/linus-torvalds.md +0 -218
  65. package/substrate/.claude/luminaries/martin-fowler.md +0 -164
  66. package/substrate/.claude/luminaries/michael-feathers.md +0 -125
  67. package/substrate/.claude/luminaries/michael-nygard.md +0 -118
  68. package/substrate/.claude/luminaries/robert-c-martin.md +0 -164
  69. package/substrate/.claude/luminaries/saltzer-schroeder.md +0 -194
  70. package/substrate/.claude/luminaries/sophia-prater.md +0 -193
  71. package/substrate/.claude/luminaries/stephen-toulmin.md +0 -131
  72. package/substrate/.claude/luminaries/tony-hoare.md +0 -170
  73. package/substrate/.claude/luminaries/vaughn-vernon.md +0 -50
  74. package/substrate/.claude/luminaries/w-edwards-deming.md +0 -158
  75. package/substrate/.claude/rules/accessor-library-discipline.md +0 -138
  76. package/substrate/.claude/rules/adr-discipline.md +0 -120
  77. package/substrate/.claude/rules/api-conventions.md +0 -125
  78. package/substrate/.claude/rules/artifact-ingestion.md +0 -179
  79. package/substrate/.claude/rules/assert-only-after-verify.md +0 -137
  80. package/substrate/.claude/rules/blocked-items.md +0 -146
  81. package/substrate/.claude/rules/bootstrap-pair-discipline.md +0 -141
  82. package/substrate/.claude/rules/branching.md +0 -28
  83. package/substrate/.claude/rules/cold-adopter-harness-discipline.md +0 -129
  84. package/substrate/.claude/rules/commit-conventions.md +0 -22
  85. package/substrate/.claude/rules/compounding-axis-fresh-analysis.md +0 -188
  86. package/substrate/.claude/rules/compounding-sequence-fresh-analysis.md +0 -188
  87. package/substrate/.claude/rules/context-engineering.md +0 -202
  88. package/substrate/.claude/rules/context-management.md +0 -85
  89. package/substrate/.claude/rules/defensive-bash.md +0 -68
  90. package/substrate/.claude/rules/deferred-actions.md +0 -233
  91. package/substrate/.claude/rules/destructive-operations.md +0 -69
  92. package/substrate/.claude/rules/diagnosis.md +0 -38
  93. package/substrate/.claude/rules/github-issue-flash-tweet.md +0 -156
  94. package/substrate/.claude/rules/guardrails.md +0 -73
  95. package/substrate/.claude/rules/hook-wire-on-author.md +0 -103
  96. package/substrate/.claude/rules/identifier-leak-prevention.md +0 -104
  97. package/substrate/.claude/rules/iteration-bet-brief-completeness.md +0 -54
  98. package/substrate/.claude/rules/lite-manifest-schema-change-discipline.md +0 -98
  99. package/substrate/.claude/rules/longrun-prep-plan-doc-compression.md +0 -89
  100. package/substrate/.claude/rules/loop-discipline.md +0 -81
  101. package/substrate/.claude/rules/manual-prod-approval.md +0 -100
  102. package/substrate/.claude/rules/marker-enrichment-discipline.md +0 -99
  103. package/substrate/.claude/rules/mobile-ephemeral-session.md +0 -109
  104. package/substrate/.claude/rules/new-dependency-check.md +0 -51
  105. package/substrate/.claude/rules/oo-ad-entry-point.md +0 -117
  106. package/substrate/.claude/rules/operator-facing-prose.md +0 -196
  107. package/substrate/.claude/rules/option-label-discipline.md +0 -108
  108. package/substrate/.claude/rules/pattern-annotation.md +0 -100
  109. package/substrate/.claude/rules/plain-english-discipline.md +0 -156
  110. package/substrate/.claude/rules/plan-enumeration-needs-value-props.md +0 -211
  111. package/substrate/.claude/rules/pr-body-shape.md +0 -317
  112. package/substrate/.claude/rules/pr-strategy.md +0 -167
  113. package/substrate/.claude/rules/pr-title-shape.md +0 -161
  114. package/substrate/.claude/rules/prototype-workflow.md +0 -65
  115. package/substrate/.claude/rules/reserved-skill-names.md +0 -123
  116. package/substrate/.claude/rules/schema-management.md +0 -49
  117. package/substrate/.claude/rules/sdlc-gates.md +0 -149
  118. package/substrate/.claude/rules/security.md +0 -37
  119. package/substrate/.claude/rules/session-artifacts.md +0 -236
  120. package/substrate/.claude/rules/skill-composition-declarations.md +0 -124
  121. package/substrate/.claude/rules/skill-description-clarity.md +0 -247
  122. package/substrate/.claude/rules/skill-procedure-step-list.md +0 -137
  123. package/substrate/.claude/rules/state-schema-validation.md +0 -162
  124. package/substrate/.claude/rules/stuck-signal-diagnostic.md +0 -140
  125. package/substrate/.claude/rules/substrate-config-schema.md +0 -98
  126. package/substrate/.claude/rules/test-list-discipline.md +0 -175
  127. package/substrate/.claude/rules/test-sufficiency.md +0 -210
  128. package/substrate/.claude/rules/testing-tier-config.md +0 -145
  129. package/substrate/.claude/rules/testing.md +0 -38
  130. package/substrate/.claude/rules/turn-estimate-grounding.md +0 -134
  131. package/substrate/.claude/rules/visual-hierarchy.md +0 -437
  132. package/substrate/.claude/rules/we-dont-break-adopters.md +0 -126
  133. package/substrate/.claude/rules/whereami-load-bearing.md +0 -202
  134. package/substrate/.claude/rules/writing-craft-discipline.md +0 -92
  135. package/substrate/.claude/rules/wu-sequencing-compounds.md +0 -145
  136. package/substrate/.claude/skills/build/SKILL.md +0 -640
  137. package/substrate/.claude/skills/chronicle/SKILL.md +0 -55
  138. package/substrate/.claude/skills/clean-artifacts/SKILL.md +0 -249
  139. package/substrate/.claude/skills/decompose/SKILL.md +0 -280
  140. package/substrate/.claude/skills/diagnose/SKILL.md +0 -297
  141. package/substrate/.claude/skills/feynman/SKILL.md +0 -90
  142. package/substrate/.claude/skills/howdoi/SKILL.md +0 -105
  143. package/substrate/.claude/skills/ia-model/SKILL.md +0 -108
  144. package/substrate/.claude/skills/interaction-design/SKILL.md +0 -112
  145. package/substrate/.claude/skills/interpret-input/SKILL.md +0 -180
  146. package/substrate/.claude/skills/journal/SKILL.md +0 -209
  147. package/substrate/.claude/skills/kiss/SKILL.md +0 -449
  148. package/substrate/.claude/skills/launch/SKILL.md +0 -915
  149. package/substrate/.claude/skills/lean-canvas/SKILL.md +0 -332
  150. package/substrate/.claude/skills/longrun/SKILL.md +0 -463
  151. package/substrate/.claude/skills/luminary/SKILL.md +0 -481
  152. package/substrate/.claude/skills/ogilvy-writing-audit/SKILL.md +0 -177
  153. package/substrate/.claude/skills/onboard-repo/SKILL.md +0 -1624
  154. package/substrate/.claude/skills/pattern-review/SKILL.md +0 -99
  155. package/substrate/.claude/skills/personas/SKILL.md +0 -207
  156. package/substrate/.claude/skills/promote/SKILL.md +0 -283
  157. package/substrate/.claude/skills/requirement/SKILL.md +0 -98
  158. package/substrate/.claude/skills/retro/SKILL.md +0 -117
  159. package/substrate/.claude/skills/riff/SKILL.md +0 -114
  160. package/substrate/.claude/skills/roadmap-reconcile/SKILL.md +0 -163
  161. package/substrate/.claude/skills/session-end/SKILL.md +0 -309
  162. package/substrate/.claude/skills/session-log/SKILL.md +0 -299
  163. package/substrate/.claude/skills/skills/SKILL.md +0 -228
  164. package/substrate/.claude/skills/spec/SKILL.md +0 -105
  165. package/substrate/.claude/skills/sprint/SKILL.md +0 -392
  166. package/substrate/.claude/skills/stage/SKILL.md +0 -384
  167. package/substrate/.claude/skills/state-a-problem/SKILL.md +0 -185
  168. package/substrate/.claude/skills/temperance/SKILL.md +0 -108
  169. package/substrate/.claude/skills/use-case/SKILL.md +0 -417
  170. package/substrate/.claude/skills/user-stories/SKILL.md +0 -268
  171. package/substrate/.claude/skills/value-prop/SKILL.md +0 -251
  172. package/substrate/.claude/skills/verify/SKILL.md +0 -160
  173. package/substrate/.claude/skills/visual-review/SKILL.md +0 -503
  174. package/substrate/.claude/skills/whats-the-plan/SKILL.md +0 -202
  175. package/substrate/.claude/skills/whereami/SKILL.md +0 -307
  176. package/substrate/AGENTS.md +0 -79
  177. package/substrate/CLAUDE-lite.md +0 -85
  178. package/substrate/CODE_OF_CONDUCT.md +0 -28
  179. package/substrate/CONTRIBUTING.md +0 -177
  180. package/substrate/README.md +0 -173
  181. package/substrate/SECURITY.md +0 -19
  182. package/substrate/architecture/decisions/ADR-029-release-pipeline.md +0 -79
  183. package/substrate/architecture/decisions/ADR-031-non-breaking-changes-adopter-discipline.md +0 -139
  184. package/substrate/architecture/decisions/ADR-032-adopter-sync-dispatcher-architecture.md +0 -192
  185. package/substrate/architecture/decisions/ADR-039-release-tagging-scheme.md +0 -145
  186. package/substrate/architecture/decisions/ADR-040-planning-skill-vocabulary-and-lite-profile.md +0 -155
  187. package/substrate/architecture/decisions/ADR-044-unified-skill-body-template.md +0 -162
  188. package/substrate/lib/clean-artifacts-sweep.sh +0 -112
  189. package/substrate/lib/code-comment-discipline.sh +0 -144
  190. package/substrate/lib/composer-preflight.sh +0 -459
  191. package/substrate/lib/hook-inject.sh +0 -255
  192. package/substrate/lib/luminary-pick.sh +0 -96
  193. package/substrate/lib/output-discipline.sh +0 -143
  194. package/substrate/lib/prose-scan-boundary.sh +0 -171
  195. package/substrate/lib/rewrite-check.sh +0 -214
  196. package/substrate/lib/state.sh +0 -1372
  197. package/substrate/lib/telemetry.sh +0 -205
  198. package/substrate/lib/tier-check.sh +0 -187
  199. package/substrate/lib/tier-dependency-audit.sh +0 -1088
  200. package/substrate/presence/install/bassclef-hook-connect.sh +0 -178
  201. package/substrate/presence/install/bassclef-sync.dispatcher.template.sh +0 -841
  202. package/substrate/presence/install/bassclef-sync.template.sh +0 -2076
  203. package/substrate/presence/install/schedule-auto-save.cron.sh +0 -88
  204. package/substrate/presence/install/schedule-auto-save.taskscheduler.md +0 -122
  205. package/substrate/scripts/aggregate-telemetry.sh +0 -217
  206. package/substrate/scripts/analyze-tier-dependencies.sh +0 -239
  207. package/substrate/scripts/generate-lite-manifest.sh +0 -505
  208. package/substrate/scripts/generate-tier-manifest.sh +0 -28
  209. package/substrate/scripts/intent-drift-check.sh +0 -456
  210. package/substrate/scripts/lite-manifest-drift-check.sh +0 -146
  211. package/substrate/scripts/render-lite-manifest-doc.sh +0 -150
  212. package/substrate/standards/adr-template.md +0 -86
  213. package/substrate/standards/api-conventions/nextjs.md +0 -84
  214. package/substrate/standards/artifact-composition.md +0 -209
  215. package/substrate/standards/bash-hook-safety.md +0 -246
  216. package/substrate/standards/bassclef-configs-schema.md +0 -232
  217. package/substrate/standards/bassclef-evolution.md +0 -143
  218. package/substrate/standards/bassclef-internal-jargon.md +0 -244
  219. package/substrate/standards/bassclef-managed-sentinel.md +0 -96
  220. package/substrate/standards/bassclef-source-config.md +0 -228
  221. package/substrate/standards/branch-stacking.md +0 -408
  222. package/substrate/standards/code-safety-principles.md +0 -176
  223. package/substrate/standards/composer-prerequisites.md +0 -155
  224. package/substrate/standards/deferred-actions-schema.md +0 -204
  225. package/substrate/standards/dependency-discipline/cargo.md +0 -39
  226. package/substrate/standards/dependency-discipline/gem.md +0 -43
  227. package/substrate/standards/dependency-discipline/go-mod.md +0 -41
  228. package/substrate/standards/dependency-discipline/npm.md +0 -42
  229. package/substrate/standards/dependency-discipline/pip.md +0 -42
  230. package/substrate/standards/deployment-topology/ec2-tailscale.md +0 -225
  231. package/substrate/standards/deployment-topology.md +0 -69
  232. package/substrate/standards/docs-sync-allowlist.md +0 -76
  233. package/substrate/standards/domain-and-dns.md +0 -145
  234. package/substrate/standards/frontend-stack.md +0 -67
  235. package/substrate/standards/frontmatter-schema.md +0 -154
  236. package/substrate/standards/graceful-exit.md +0 -227
  237. package/substrate/standards/hook-idempotency.md +0 -102
  238. package/substrate/standards/hook-injection-discipline.md +0 -202
  239. package/substrate/standards/hook-install-class.md +0 -215
  240. package/substrate/standards/input-handler-interface.md +0 -152
  241. package/substrate/standards/lite-manifest-schema-changes.md +0 -135
  242. package/substrate/standards/luminary-matching.md +0 -105
  243. package/substrate/standards/luminary-problem-patterns.md +0 -481
  244. package/substrate/standards/migration-discipline/active-record.md +0 -50
  245. package/substrate/standards/migration-discipline/alembic.md +0 -43
  246. package/substrate/standards/migration-discipline/gorm.md +0 -50
  247. package/substrate/standards/migration-discipline/prisma.md +0 -53
  248. package/substrate/standards/migration-discipline/sqlalchemy.md +0 -51
  249. package/substrate/standards/mobile-ephemeral-session.md +0 -167
  250. package/substrate/standards/model-routing-discipline.md +0 -160
  251. package/substrate/standards/ogilvy-writing-rules.md +0 -225
  252. package/substrate/standards/opener-discipline.md +0 -96
  253. package/substrate/standards/operator-facing-prose-discipline.md +0 -201
  254. package/substrate/standards/persona-schema.md +0 -229
  255. package/substrate/standards/pluggable-luminaries.md +0 -323
  256. package/substrate/standards/pr-body-discipline.md +0 -115
  257. package/substrate/standards/preview-state-schema.md +0 -189
  258. package/substrate/standards/project-directory-layout.md +0 -276
  259. package/substrate/standards/release-tagging.md +0 -137
  260. package/substrate/standards/reserved-skill-names.md +0 -120
  261. package/substrate/standards/scannable-multi-option-output.md +0 -261
  262. package/substrate/standards/sdlc-compliance.md +0 -286
  263. package/substrate/standards/sdlc-gates/typescript.md +0 -57
  264. package/substrate/standards/secrets-lifecycle.md +0 -210
  265. package/substrate/standards/security-scanner-adapter.md +0 -145
  266. package/substrate/standards/session-board.md +0 -256
  267. package/substrate/standards/skill-output-discipline.md +0 -90
  268. package/substrate/standards/state-spine-contract.md +0 -255
  269. package/substrate/standards/state-spine.md +0 -511
  270. package/substrate/standards/steering-hints/kiss-words.md +0 -11
  271. package/substrate/standards/substrate-config-schema.md +0 -267
  272. package/substrate/standards/tech-stack-config.md +0 -109
  273. package/substrate/standards/tier-dependency-analysis.md +0 -167
  274. package/substrate/standards/tier-runtime-deps/lite.md +0 -57
  275. package/substrate/standards/tier-tag-schema.md +0 -155
  276. package/substrate/standards/two-layer-config.md +0 -99
  277. package/substrate/standards/use-case-format.md +0 -292
  278. package/substrate/standards/user-story-invest.md +0 -268
  279. package/substrate/standards/velocity-and-appetite.md +0 -229
  280. package/substrate/standards/voice-input-pattern.md +0 -119
  281. package/substrate/standards/whereami-schema.md +0 -301
  282. package/substrate/standards/worktree-management.md +0 -211
  283. package/substrate/standards/writing-guide.md +0 -213
  284. package/substrate/templates/chronicle-template.md +0 -75
  285. package/substrate/templates/deferred-action-template.md +0 -45
  286. package/substrate/templates/memory-proposal-template.md +0 -77
  287. package/substrate/templates/persona-template.md +0 -200
  288. package/substrate/templates/pr-faq.md +0 -45
  289. package/substrate/templates/secret-rotation-template.md +0 -162
  290. package/substrate/templates/spec-template.md +0 -131
  291. package/substrate/templates/use-case-template.md +0 -194
  292. package/substrate/templates/user-story-template.md +0 -107
  293. package/substrate/templates/whereami-template.md +0 -101
@@ -1,357 +0,0 @@
1
- #!/bin/bash
2
- # tier: lite
3
- # Artifact Ingestion Gate — fires on Write/Edit to generative artifact paths.
4
- # Enforces .claude/rules/artifact-ingestion.md: every substantive generative
5
- # output must include a "## Sources read" block (or a stated-from-scratch
6
- # rationale) so agents can't substitute training priors for staged artifacts.
7
- #
8
- # Exit codes:
9
- # 0 — allow (path doesn't match, or Sources-read block present, or override)
10
- # 2 — block (matcher hit, no Sources-read, no override)
11
- #
12
- # Override: set SKIP_ARTIFACT_INGESTION=1 to bypass (logged to trace).
13
- #
14
- # Rule: .claude/rules/artifact-ingestion.md
15
- # Issue: bassclef#116
16
-
17
- set +e # never crash the tool call; fall through to allow on any unexpected error
18
-
19
- # === Hook liveness heartbeat (WU-3 of bet 2026-07-31d; closes #1002) ===
20
- # Silent-fail — a missing lib never crashes the hook.
21
- {
22
- _hb_sd="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
- for _hb_c in "${_hb_sd}/../../lib/hook-heartbeat.sh" "${HOME:-/}/lib/hook-heartbeat.sh"; do
24
- [ -f "$_hb_c" ] && source "$_hb_c" && heartbeat_mark "artifact-ingestion-gate" && break
25
- done
26
- unset _hb_sd _hb_c
27
- } 2>/dev/null || true
28
-
29
- INPUT=$(cat)
30
- TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null)
31
- FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null)
32
-
33
- # Only fire on Write / Edit
34
- if [ "$TOOL_NAME" != "Write" ] && [ "$TOOL_NAME" != "Edit" ]; then
35
- exit 0
36
- fi
37
-
38
- # No file path → allow (defensive)
39
- if [ -z "$FILE_PATH" ]; then
40
- exit 0
41
- fi
42
-
43
- # Matcher paths — generative artifacts requiring Sources-read block.
44
- # Narrow by design; expand carefully. Skip paths (.claude/, memory, configs,
45
- # release-notes, journals) are NOT matched here and pass through.
46
- MATCH=0
47
- case "$FILE_PATH" in
48
- */strategy/canvases/*.md) MATCH=1 ;;
49
- */docs/specs/*.md) MATCH=1 ;;
50
- */docs/iteration-bets/*.md) MATCH=1 ;;
51
- */architecture/decisions/ADR-*.md) MATCH=1 ;;
52
- */docs/prototypes/*/index.html) MATCH=1 ;;
53
- */docs/prototypes/*/*.html) MATCH=1 ;;
54
- */docs/decompositions/*.md) MATCH=1 ;;
55
- esac
56
-
57
- if [ "$MATCH" -eq 0 ]; then
58
- exit 0
59
- fi
60
-
61
- # Override hatch — log and allow
62
- if [ "${SKIP_ARTIFACT_INGESTION:-0}" = "1" ]; then
63
- SCRIPT_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd)"
64
- if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/trace-helper.sh" ]; then
65
- source "$SCRIPT_DIR/trace-helper.sh" 2>/dev/null || true
66
- trace_log "artifact-ingestion-gate" "OVERRIDE $TOOL_NAME $FILE_PATH" 2>/dev/null || true
67
- fi
68
- exit 0
69
- fi
70
-
71
- # Assemble the content that WILL exist after this operation.
72
- # Write: tool_input.content is authoritative.
73
- # Edit: check existing file on disk (if any) + new_string together.
74
- FUTURE_CONTENT=""
75
- if [ "$TOOL_NAME" = "Write" ]; then
76
- FUTURE_CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // ""' 2>/dev/null)
77
- elif [ "$TOOL_NAME" = "Edit" ]; then
78
- NEW_STRING=$(echo "$INPUT" | jq -r '.tool_input.new_string // ""' 2>/dev/null)
79
- EXISTING=""
80
- if [ -f "$FILE_PATH" ]; then
81
- EXISTING=$(cat "$FILE_PATH" 2>/dev/null)
82
- fi
83
- FUTURE_CONTENT="${EXISTING}
84
- ${NEW_STRING}"
85
- fi
86
-
87
- # Check for Sources-read block (case-insensitive, tolerant of heading depth).
88
- # Accepted forms:
89
- # ## Sources read
90
- # ### Sources read
91
- # ## Sources Read
92
- # ## SOURCES READ
93
- # Also accepts an explicit from-scratch rationale:
94
- # "No prior artifacts" (per rule)
95
- HAS_SOURCES_READ=0
96
- if echo "$FUTURE_CONTENT" | grep -qiE '^#{1,6}[[:space:]]+sources[[:space:]]+read'; then
97
- HAS_SOURCES_READ=1
98
- fi
99
- if echo "$FUTURE_CONTENT" | grep -qi 'no prior artifacts'; then
100
- HAS_SOURCES_READ=1
101
- fi
102
-
103
- # Block if no Sources-read block at all.
104
- if [ "$HAS_SOURCES_READ" -eq 0 ]; then
105
- EMIT_BLOCK=1
106
- fi
107
-
108
- # === Parent citation check (bassclef#334 — Layer A determinism gate) ===
109
- #
110
- # When the artifact's frontmatter declares parent_roadmap, parent_bet, or
111
- # parent_canvas, the "Sources read" block MUST cite those paths/ids. This
112
- # catches the case where an agent declares lineage in frontmatter but
113
- # doesn't actually read the parent (a determinism failure mode caught by
114
- # the operator 2026-04-27d when an agent missed parent_roadmap framing).
115
- #
116
- # Only fires when HAS_SOURCES_READ=1; if the Sources-read block is missing
117
- # entirely, the prior check covers it.
118
- PARENT_CITATION_BLOCK=""
119
- if [ "$HAS_SOURCES_READ" -eq 1 ]; then
120
- # Extract YAML frontmatter (between leading --- ... ---)
121
- FRONTMATTER=$(echo "$FUTURE_CONTENT" | awk '/^---$/{c++; if(c==2) exit; next} c==1')
122
-
123
- # Extract Sources-read section content (everything from "## Sources read"
124
- # heading to the next ## heading or end-of-file)
125
- SOURCES_SECTION=$(echo "$FUTURE_CONTENT" | awk '
126
- /^#{1,6}[[:space:]]+[Ss][Oo][Uu][Rr][Cc][Ee][Ss][[:space:]]+[Rr][Ee][Aa][Dd]/ { in_section=1; next }
127
- in_section && /^#{1,6}[[:space:]]/ { exit }
128
- in_section { print }
129
- ')
130
-
131
- # For each parent_* field set in frontmatter, verify it (or its slug/id)
132
- # is referenced in the Sources-read section. Bash regex via grep -F for
133
- # literal-string match (paths contain dots).
134
- MISSING_CITATIONS=""
135
- for parent_key in parent_roadmap parent_bet parent_canvas parent_decomposition; do
136
- PARENT_VALUE=$(echo "$FRONTMATTER" | awk -v key="$parent_key" '
137
- $0 ~ "^"key":" {
138
- sub("^"key":[[:space:]]*", "")
139
- # Strip leading/trailing whitespace and surrounding quotes
140
- gsub(/^[[:space:]]+|[[:space:]]+$/, "")
141
- gsub(/^"|"$|^'\''|'\''$/, "")
142
- print
143
- exit
144
- }
145
- ')
146
- if [ -z "$PARENT_VALUE" ]; then
147
- continue
148
- fi
149
-
150
- # Check if the parent path (or its basename without extension) appears
151
- # in the Sources-read section. Accepts either:
152
- # - Full path (docs/roadmaps/foo.md)
153
- # - Slug/id (foo, no path/extension)
154
- PARENT_BASENAME=$(basename "$PARENT_VALUE" .md)
155
-
156
- if echo "$SOURCES_SECTION" | grep -qF "$PARENT_VALUE"; then
157
- continue
158
- fi
159
- if echo "$SOURCES_SECTION" | grep -qF "$PARENT_BASENAME"; then
160
- continue
161
- fi
162
-
163
- MISSING_CITATIONS="${MISSING_CITATIONS} - ${parent_key}: ${PARENT_VALUE}\n"
164
- done
165
-
166
- if [ -n "$MISSING_CITATIONS" ]; then
167
- PARENT_CITATION_BLOCK="$MISSING_CITATIONS"
168
- EMIT_BLOCK=1
169
- fi
170
-
171
- # === Layer A composition (bassclef#337 WU-5) ===
172
- #
173
- # When parent_roadmap is cited, verify the citation includes the
174
- # current last_event.ts OR last_event.event. This proves the agent
175
- # read CURRENT roadmap state, not a stale snapshot. Closes the
176
- # determinism loop: parent declared, parent path cited, current
177
- # event referenced.
178
- #
179
- # Skips silently if no parent_roadmap was set (covered by prior loop).
180
- STALE_EVENT_BLOCK=""
181
- PARENT_ROADMAP=$(echo "$FRONTMATTER" | awk '
182
- $0 ~ /^parent_roadmap:/ {
183
- sub(/^parent_roadmap:[[:space:]]*/, "")
184
- gsub(/^[[:space:]]+|[[:space:]]+$/, "")
185
- gsub(/^"|"$|^'\''|'\''$/, "")
186
- print
187
- exit
188
- }
189
- ')
190
- if [ -n "$PARENT_ROADMAP" ] && [ -f "$PARENT_ROADMAP" ]; then
191
- # Extract current last_event from roadmap frontmatter via Python
192
- LAST_EVENT_TS=$(python3 -c "
193
- import sys, yaml
194
- try:
195
- with open('$PARENT_ROADMAP', 'r') as f:
196
- content = f.read()
197
- parts = content.split('---', 2)
198
- if len(parts) < 3:
199
- sys.exit(0)
200
- fm = yaml.safe_load(parts[1]) or {}
201
- le = fm.get('last_event', {}) or {}
202
- ts = le.get('ts', '')
203
- print(str(ts))
204
- except Exception:
205
- pass
206
- " 2>/dev/null)
207
- LAST_EVENT_NAME=$(python3 -c "
208
- import sys, yaml
209
- try:
210
- with open('$PARENT_ROADMAP', 'r') as f:
211
- content = f.read()
212
- parts = content.split('---', 2)
213
- if len(parts) < 3:
214
- sys.exit(0)
215
- fm = yaml.safe_load(parts[1]) or {}
216
- le = fm.get('last_event', {}) or {}
217
- ev = le.get('event', '')
218
- print(str(ev))
219
- except Exception:
220
- pass
221
- " 2>/dev/null)
222
-
223
- # If roadmap has a last_event, verify Sources cites ts or event name
224
- if [ -n "$LAST_EVENT_TS" ] || [ -n "$LAST_EVENT_NAME" ]; then
225
- EVENT_CITED=0
226
- if [ -n "$LAST_EVENT_TS" ] && echo "$SOURCES_SECTION" | grep -qF "$LAST_EVENT_TS"; then
227
- EVENT_CITED=1
228
- fi
229
- if [ -n "$LAST_EVENT_NAME" ] && echo "$SOURCES_SECTION" | grep -qF "$LAST_EVENT_NAME"; then
230
- EVENT_CITED=1
231
- fi
232
- if [ "$EVENT_CITED" -eq 0 ]; then
233
- STALE_EVENT_BLOCK="parent_roadmap=$PARENT_ROADMAP\n current last_event.ts=$LAST_EVENT_TS\n current last_event.event=$LAST_EVENT_NAME\n"
234
- EMIT_BLOCK=1
235
- fi
236
- fi
237
- fi
238
- fi
239
-
240
- # All checks passed → allow.
241
- if [ "${EMIT_BLOCK:-0}" -eq 0 ]; then
242
- exit 0
243
- fi
244
-
245
- # Block — emit banner to stderr (Claude Code surfaces stderr on exit 2)
246
- if [ "$HAS_SOURCES_READ" -eq 0 ]; then
247
- cat >&2 <<EOF
248
-
249
- ============================================
250
- 🛑 ARTIFACT-INGESTION GATE — BLOCKED 🛑
251
- ============================================
252
-
253
- File: $FILE_PATH
254
- Tool: $TOOL_NAME
255
-
256
- Generative artifacts require a "## Sources read" block citing the
257
- artifacts you read before producing this output. This is per
258
- .claude/rules/artifact-ingestion.md — no Sources-read = no write.
259
-
260
- Required block (add near top of file):
261
-
262
- ## Sources read
263
-
264
- - [path]:[line range] — [what you took]
265
- - ...
266
-
267
- ## What I'm NOT reading (with reason)
268
-
269
- - [path] — [deliberate exclusion reason]
270
-
271
- If producing genuinely from scratch, state:
272
-
273
- "No prior artifacts; producing from scratch because [reason]."
274
-
275
- Override (logged): SKIP_ARTIFACT_INGESTION=1 <command>
276
-
277
- Rule: .claude/rules/artifact-ingestion.md
278
- Issue: bassclef#116
279
- ============================================
280
-
281
- EOF
282
- elif [ -n "$STALE_EVENT_BLOCK" ]; then
283
- cat >&2 <<EOF
284
-
285
- ============================================
286
- 🛑 STALE-EVENT GATE — BLOCKED 🛑
287
- ============================================
288
-
289
- File: $FILE_PATH
290
- Tool: $TOOL_NAME
291
-
292
- This artifact cites parent_roadmap but the "Sources read" block
293
- doesn't reference the roadmap's CURRENT last_event. Citing the
294
- parent path proves you read the file; citing the current event
295
- proves you read the current state, not a stale snapshot.
296
-
297
- Roadmap state:
298
-
299
- $(printf "$STALE_EVENT_BLOCK")
300
-
301
- Add the current ts OR event name to your Sources-read entry. Example:
302
-
303
- ## Sources read
304
-
305
- - $PARENT_ROADMAP — current last_event ($LAST_EVENT_NAME at $LAST_EVENT_TS)
306
- - ...
307
-
308
- Override (logged): SKIP_ARTIFACT_INGESTION=1 <command>
309
-
310
- Rule: .claude/rules/artifact-ingestion.md
311
- Issue: bassclef#337 WU-5 (Layer A composition)
312
- ============================================
313
-
314
- EOF
315
- elif [ -n "$PARENT_CITATION_BLOCK" ]; then
316
- cat >&2 <<EOF
317
-
318
- ============================================
319
- 🛑 PARENT-CITATION GATE — BLOCKED 🛑
320
- ============================================
321
-
322
- File: $FILE_PATH
323
- Tool: $TOOL_NAME
324
-
325
- This artifact declares parent lineage in frontmatter but the
326
- "Sources read" block doesn't cite the parent path(s). Declaring a
327
- parent without reading it is a determinism failure — agent infers
328
- context instead of reading current state.
329
-
330
- Missing citations (parent declared in frontmatter, not cited in Sources read):
331
-
332
- $(printf "$PARENT_CITATION_BLOCK")
333
-
334
- Add each parent path to the "## Sources read" block. Example:
335
-
336
- ## Sources read
337
-
338
- - docs/roadmaps/<YYYY-MM-DD>-<slug>.md — parent_roadmap; current task list + last_event
339
- - ...
340
-
341
- Override (logged): SKIP_ARTIFACT_INGESTION=1 <command>
342
-
343
- Rule: .claude/rules/artifact-ingestion.md
344
- Issue: bassclef#334 (Layer A determinism gate)
345
- ============================================
346
-
347
- EOF
348
- fi
349
-
350
- # Trace the block (best-effort, don't let trace failure change the block signal)
351
- SCRIPT_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd)"
352
- if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/trace-helper.sh" ]; then
353
- source "$SCRIPT_DIR/trace-helper.sh" 2>/dev/null || true
354
- trace_log "artifact-ingestion-gate" "BLOCK $TOOL_NAME $FILE_PATH" 2>/dev/null || true
355
- fi
356
-
357
- exit 2
@@ -1,77 +0,0 @@
1
- #!/bin/bash
2
- # tier: lite
3
- # install-class: dual
4
- # assert-verify-steering.sh — UserPromptSubmit hook that injects
5
- # additionalContext steering the agent toward Toulmin's argument model
6
- # (claim + data + warrant) before any operator-facing assertion.
7
- #
8
- # Per bassclef-upstream#582 (parent ticket) + bassclef-upstream#559 (R8
9
- # mechanization umbrella) + bet 2026-07-01b WU-1.
10
- #
11
- # Adds argument-shape steering to the reasoning-boundary defense layer,
12
- # alongside .claude/hooks/plain-english-steering.sh (bassclef#443).
13
- #
14
- # The rule this hook pairs with: .claude/rules/assert-only-after-verify.md
15
- # The three luminaries anchoring the shape:
16
- # - Stephen Toulmin (argument model — claim/data/warrant/qualifier/rebuttal)
17
- # - Karl Popper (falsifiability — rebuttal cell)
18
- # - Charles Sanders Peirce (abductive reasoning — alternative-consideration)
19
- #
20
- # Sibling pattern: .claude/hooks/plain-english-steering.sh
21
- # Envelope helper: lib/hook-inject.sh emit_additional_context
22
- #
23
- # Override per-call: SKIP_ASSERT_VERIFY_STEERING=1
24
- #
25
- # Tier 0 strict TDD: .claude/hooks/tests/assert-verify-steering.test.sh
26
-
27
- set +e
28
-
29
- # === Source install-class-aware lib (per standards/hook-install-class.md) ===
30
- # Hook is `dual` — runs under both project install (<repo>/.claude/hooks/)
31
- # and operator install ($HOME/.claude/hooks/). Uses layered resolution
32
- # per lib/hook-inject.sh convention.
33
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
34
- for _candidate in \
35
- "${SCRIPT_DIR}/../../lib/hook-inject.sh" \
36
- "${HOME_OVERRIDE:-${HOME:-/}}/lib/hook-inject.sh"; do
37
- if [ -f "$_candidate" ]; then
38
- # shellcheck disable=SC1090
39
- source "$_candidate"
40
- break
41
- fi
42
- done
43
-
44
- # Defensive: if lib not loaded, exit silent (fail-soft per Nygard)
45
- if ! declare -f emit_additional_context >/dev/null 2>&1; then
46
- exit 0
47
- fi
48
-
49
- # Override per-call
50
- if [ "${SKIP_ASSERT_VERIFY_STEERING:-0}" = "1" ]; then
51
- exit 0
52
- fi
53
-
54
- # === Steering content ===
55
- STEERING_CONTENT="**Plain check:** Before I make a claim in this turn, I read the source first and cite it. If I cannot cite the source, I do not ship the claim.
56
-
57
- **Check my claims before I write them:**
58
-
59
- For any claim to the operator — a finding, a rating, a fix I recommend, why I think X caused Y, how many turns something will take, or a strong-word claim (wrong, broken, should, must, always) — I fill three parts:
60
-
61
- 1. **My claim** — the assertion in one sentence.
62
- 2. **Evidence** — the source I read, cited inline (file path, ticket number, git SHA, chronicle filename, standard section).
63
- 3. **Why the evidence supports the claim** — one sentence tying the source to the claim.
64
-
65
- Add more when it helps:
66
-
67
- 4. **Confidence plus how many observations back it** — from Toulmin, *The Uses of Argument* (1958).
68
- 5. **What would falsify the claim** — from Popper, *The Logic of Scientific Discovery* (1959). A claim that cannot be falsified is a guess.
69
- 6. **Two or three alternative explanations that fit the same data** — from Peirce, *Deduction, Induction, and Hypothesis* (1878). Name each option before you pick one.
70
-
71
- If I cannot fill all three, I do not ship the claim. I read the source first.
72
-
73
- Per bassclef#559 and .claude/rules/assert-only-after-verify.md."
74
-
75
- # === Emit envelope ===
76
- emit_additional_context "UserPromptSubmit" "$STEERING_CONTENT"
77
- exit 0
@@ -1,215 +0,0 @@
1
- #!/usr/bin/env bash
2
- # tier: lite
3
- # bassclef-source-config-validate.sh — PreToolUse hook validating
4
- # .bassclef-source.json writes against the bassclef schema.
5
- #
6
- # Wires per .claude/settings.json under hooks.PreToolUse with matcher
7
- # "Edit|Write|MultiEdit". Reads the tool's event JSON from stdin, detects
8
- # whether the target file is a `.bassclef-source.json`, validates against
9
- # the schema, and BLOCKs (exit non-zero) on failure.
10
- #
11
- # Per ADR-015: JSON Schema draft-2020-12 with format support via ajv-formats.
12
- # Pairs with: standards/bassclef-source-config.md
13
- #
14
- # Override: SKIP_BASSCLEF_SOURCE_VALIDATE=1 (logged to stderr).
15
- #
16
- # F77 fix (bassclef#743): probe ajv-cli before validation; distinguish
17
- # offline / install failure from schema validation failure so the operator
18
- # sees the real cause rather than a fake "validation failed" exit.
19
- #
20
- # F78 fix (bassclef#743): Edit/MultiEdit are PreToolUse — the file on disk
21
- # is still pre-edit content. Synthesize post-edit content by replaying the
22
- # event's edit operations against the on-disk content, then validate that.
23
- # Write is unchanged — tool_input.content is the post-content.
24
-
25
- set -u
26
-
27
- # === Override path ===
28
-
29
- if [ "${SKIP_BASSCLEF_SOURCE_VALIDATE:-}" = "1" ]; then
30
- echo "[bassclef-source-config-validate.sh] SKIP_BASSCLEF_SOURCE_VALIDATE=1 — bypassing validation" >&2
31
- exit 0
32
- fi
33
-
34
- # === Read PreToolUse event ===
35
-
36
- EVENT_JSON="$(cat)"
37
- TOOL_NAME="$(printf '%s' "$EVENT_JSON" | jq -r '.tool_name // empty')"
38
- TARGET_PATH="$(printf '%s' "$EVENT_JSON" | jq -r '.tool_input.file_path // empty')"
39
-
40
- # Tool filter: only Edit/Write/MultiEdit trigger validation
41
- case "$TOOL_NAME" in
42
- Edit|Write|MultiEdit) ;;
43
- *) exit 0 ;;
44
- esac
45
-
46
- # Empty path → pass-through
47
- if [ -z "$TARGET_PATH" ]; then
48
- exit 0
49
- fi
50
-
51
- # Path filter: only .bassclef-source.json files trigger validation
52
- case "$TARGET_PATH" in
53
- */.bassclef-source.json|.bassclef-source.json) ;;
54
- *) exit 0 ;;
55
- esac
56
-
57
- # === Resolve project dir + schema path ===
58
-
59
- PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
60
- SCHEMA="${PROJECT_DIR}/standards/bassclef-source/schemas/bassclef-source.schema.json"
61
-
62
- # If schema not present locally (consumer repo without bassclef-side
63
- # files), pass-through — the hook is a defensive gate for bassclef-side
64
- # edits, not for consumer-side edits where the schema isn't available.
65
- if [ ! -f "$SCHEMA" ]; then
66
- exit 0
67
- fi
68
-
69
- # === Temp-file cleanup trap ===
70
-
71
- TMP_JSON=""
72
- cleanup() {
73
- [ -n "$TMP_JSON" ] && rm -f "$TMP_JSON" 2>/dev/null
74
- }
75
- trap cleanup EXIT
76
-
77
- # === F77 — Probe ajv-cli availability before validating ===
78
- #
79
- # Distinguish offline / install-failure from schema-validation failure.
80
- # Without this probe, the error filter at the end strips npm/npx warnings
81
- # and the operator sees what looks like a schema-validation failure even
82
- # when the real cause is network or install. Pass-through on probe failure
83
- # with a loud stderr explanation; do NOT block on infrastructure.
84
-
85
- # Probe uses `ajv help` because `ajv --version` exits non-zero in
86
- # ajv-cli@5's CLI parser (unrecognized option). help is the cheapest
87
- # parse-and-print that exits 0 when the binary is installed.
88
- AJV_PROBE_OUTPUT="$(npx -y -p ajv-cli@5 ajv help 2>&1)"
89
- AJV_PROBE_EXIT=$?
90
- if [ "$AJV_PROBE_EXIT" -ne 0 ]; then
91
- echo >&2
92
- echo "[bassclef-source-config-validate.sh] ajv-cli unavailable — validation skipped" >&2
93
- echo "[bassclef-source-config-validate.sh] Likely cause: offline, npm registry unreachable, or first-run install failed." >&2
94
- echo "[bassclef-source-config-validate.sh] Target: $TARGET_PATH" >&2
95
- echo "[bassclef-source-config-validate.sh] Probe output (last 5 lines):" >&2
96
- echo "$AJV_PROBE_OUTPUT" | tail -5 | sed 's/^/ /' >&2
97
- echo "[bassclef-source-config-validate.sh] To pre-cache: run \`npx -y -p ajv-cli@5 -p ajv-formats@2 ajv --version\` while online." >&2
98
- echo "[bassclef-source-config-validate.sh] To bypass deliberately: \`SKIP_BASSCLEF_SOURCE_VALIDATE=1 <command>\`" >&2
99
- echo >&2
100
- exit 0 # Pass-through; don't block on infrastructure
101
- fi
102
-
103
- # === F78 — Synthesize post-edit content per tool ===
104
- #
105
- # Write: tool_input.content IS the post-content (current shape OK).
106
- # Edit: apply tool_input.{old_string, new_string, replace_all} to on-disk
107
- # content; validate the result.
108
- # MultiEdit: apply each entry of tool_input.edits[] in order; validate the
109
- # final result.
110
-
111
- case "$TOOL_NAME" in
112
- Write)
113
- # ajv-cli detects format from file extension; macOS mktemp -t
114
- # appends random suffix AFTER the template, so .json must be
115
- # explicitly added via mv to ensure it's the trailing extension.
116
- TMP_JSON_RAW="$(mktemp -t bassclef-source-validate-XXXXXX)"
117
- TMP_JSON="${TMP_JSON_RAW}.json"
118
- mv "$TMP_JSON_RAW" "$TMP_JSON"
119
- printf '%s' "$EVENT_JSON" | jq -r '.tool_input.content // empty' > "$TMP_JSON"
120
- VALIDATE_TARGET="$TMP_JSON"
121
- ;;
122
- Edit|MultiEdit)
123
- # Edit on non-existent file — the Edit tool will fail with its own
124
- # error; pass-through quietly.
125
- if [ ! -f "$TARGET_PATH" ]; then
126
- exit 0
127
- fi
128
- # ajv-cli detects format from file extension; macOS mktemp -t
129
- # appends random suffix AFTER the template, so .json must be
130
- # explicitly added via mv to ensure it's the trailing extension.
131
- TMP_JSON_RAW="$(mktemp -t bassclef-source-validate-XXXXXX)"
132
- TMP_JSON="${TMP_JSON_RAW}.json"
133
- mv "$TMP_JSON_RAW" "$TMP_JSON"
134
-
135
- # Replay edits via python3. Pipes EVENT_JSON to python's stdin;
136
- # passes target path + tool name as argv. python writes post-edit
137
- # content to stdout, which bash captures into TMP_JSON.
138
- #
139
- # Exit code from python:
140
- # 0 — replay succeeded; TMP_JSON has post-edit content
141
- # 2 — old_string not in content; the Edit tool will fail with the
142
- # same error so pass-through quietly
143
- # other — unexpected; pass-through (don't block on hook bugs)
144
- REPLAY_EXIT=0
145
- printf '%s' "$EVENT_JSON" | python3 -c '
146
- import json, sys
147
- event = json.load(sys.stdin)
148
- target = sys.argv[1]
149
- tool_name = sys.argv[2]
150
- with open(target) as f:
151
- content = f.read()
152
- if tool_name == "Edit":
153
- edits = [event["tool_input"]]
154
- else: # MultiEdit
155
- edits = event["tool_input"].get("edits", [])
156
- for e in edits:
157
- old = e.get("old_string", "")
158
- new = e.get("new_string", "")
159
- if old not in content:
160
- sys.exit(2)
161
- replace_all = e.get("replace_all", False)
162
- content = content.replace(old, new) if replace_all else content.replace(old, new, 1)
163
- sys.stdout.write(content)
164
- ' "$TARGET_PATH" "$TOOL_NAME" > "$TMP_JSON" 2>/dev/null || REPLAY_EXIT=$?
165
-
166
- if [ "$REPLAY_EXIT" -ne 0 ]; then
167
- # Replay failed — the underlying tool will fail too. Pass-through.
168
- exit 0
169
- fi
170
- VALIDATE_TARGET="$TMP_JSON"
171
- ;;
172
- esac
173
-
174
- # === Validate via ajv-cli ===
175
-
176
- VALIDATION_OUTPUT="$(npx -y -p ajv-cli@5 -p ajv-formats@2 ajv validate \
177
- -s "$SCHEMA" \
178
- -d "$VALIDATE_TARGET" \
179
- --spec=draft2020 \
180
- -c ajv-formats 2>&1)"
181
- EXIT_CODE=$?
182
-
183
- if [ "$EXIT_CODE" -eq 0 ]; then
184
- exit 0
185
- fi
186
-
187
- # === BLOCK on validation failure ===
188
-
189
- # Strip noisy npm warnings; surface only ajv's actual error lines.
190
- # (Network failures already short-circuited above via the F77 probe.)
191
- ERR=$(echo "$VALIDATION_OUTPUT" | grep -vE '^npm |^npx |^$' | head -10)
192
-
193
- cat >&2 <<EOF
194
-
195
- 🛑 BLOCKED — .bassclef-source.json validation failed
196
-
197
- Path: $TARGET_PATH
198
- Schema: standards/bassclef-source/schemas/bassclef-source.schema.json
199
- Standard: standards/bassclef-source-config.md
200
-
201
- ajv-cli error:
202
- $ERR
203
-
204
- Resolution paths:
205
- 1. Fix the data to match the schema (preferred)
206
- — see standards/bassclef-source-config.md § Schema for field reference
207
- — see scripts/tests/fixtures/bassclef-source/*.json for working examples
208
- 2. If the schema is genuinely wrong, open a PR amending it (rare)
209
- 3. Override with SKIP_BASSCLEF_SOURCE_VALIDATE=1 (logged; rare; not for normal work)
210
-
211
- Per .claude/rules/blocked-items.md: silence is not deferral.
212
-
213
- EOF
214
-
215
- exit 3