@thebassclef/lite 1.0.4 → 1.1.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.
- package/dist/cli.cjs +65 -0
- package/dist/cli.js +65 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/agents/architect.md +70 -0
- package/dist/lite/.claude/agents/builder.md +114 -0
- package/dist/lite/.claude/agents/designer.md +156 -0
- package/dist/lite/.claude/agents/reviewer.md +88 -0
- package/dist/lite/.claude/hooks/bassclef-sync.sh +85 -27
- package/dist/lite/.claude/hooks/longrun-prep-compounding-axis-check.sh +492 -0
- package/dist/lite/.claude/hooks/longrun-prep-render-check.sh +236 -0
- package/dist/lite/.claude/hooks/persona-name-scrub-check.sh +105 -0
- package/dist/lite/.claude/hooks/skill-step-list-check.sh +171 -0
- package/dist/lite/.claude/luminaries/alan-cooper.md +170 -0
- package/dist/lite/.claude/luminaries/alistair-cockburn.md +140 -0
- package/dist/lite/.claude/luminaries/amazon-pr-faq.md +34 -0
- package/dist/lite/.claude/luminaries/andreas-zeller.md +74 -0
- package/dist/lite/.claude/luminaries/ash-maurya.md +121 -0
- package/dist/lite/.claude/luminaries/bill-buxton.md +210 -0
- package/dist/lite/.claude/luminaries/charles-sanders-peirce.md +150 -0
- package/dist/lite/.claude/luminaries/david-ogilvy.md +192 -0
- package/dist/lite/.claude/luminaries/don-norman.md +173 -0
- package/dist/lite/.claude/luminaries/edward-tufte.md +179 -0
- package/dist/lite/.claude/luminaries/eric-evans.md +160 -0
- package/dist/lite/.claude/luminaries/frederick-brooks.md +50 -0
- package/dist/lite/.claude/luminaries/gang-of-four.md +157 -0
- package/dist/lite/.claude/luminaries/glenford-myers.md +230 -0
- package/dist/lite/.claude/luminaries/hunt-thomas.md +115 -0
- package/dist/lite/.claude/luminaries/hyrum-wright.md +94 -0
- package/dist/lite/.claude/luminaries/jason-fried-dhh.md +46 -0
- package/dist/lite/.claude/luminaries/jesse-james-garrett.md +154 -0
- package/dist/lite/.claude/luminaries/john-ousterhout.md +94 -0
- package/dist/lite/.claude/luminaries/karl-popper.md +132 -0
- package/dist/lite/.claude/luminaries/kent-beck.md +168 -0
- package/dist/lite/.claude/luminaries/linus-torvalds.md +218 -0
- package/dist/lite/.claude/luminaries/martin-fowler.md +164 -0
- package/dist/lite/.claude/luminaries/michael-feathers.md +125 -0
- package/dist/lite/.claude/luminaries/michael-nygard.md +118 -0
- package/dist/lite/.claude/luminaries/robert-c-martin.md +164 -0
- package/dist/lite/.claude/luminaries/saltzer-schroeder.md +194 -0
- package/dist/lite/.claude/luminaries/sophia-prater.md +193 -0
- package/dist/lite/.claude/luminaries/stephen-toulmin.md +131 -0
- package/dist/lite/.claude/luminaries/tony-hoare.md +170 -0
- package/dist/lite/.claude/luminaries/vaughn-vernon.md +50 -0
- package/dist/lite/.claude/luminaries/w-edwards-deming.md +158 -0
- package/dist/lite/.claude/rules/accessor-library-discipline.md +110 -0
- package/dist/lite/.claude/rules/adr-discipline.md +96 -0
- package/dist/lite/.claude/rules/api-conventions.md +115 -0
- package/dist/lite/.claude/rules/artifact-ingestion.md +137 -0
- package/dist/lite/.claude/rules/assert-only-after-verify.md +111 -0
- package/dist/lite/.claude/rules/blocked-items.md +139 -0
- package/dist/lite/.claude/rules/bootstrap-pair-discipline.md +106 -0
- package/dist/lite/.claude/rules/branching.md +28 -0
- package/dist/lite/.claude/rules/cold-adopter-harness-discipline.md +93 -0
- package/dist/lite/.claude/rules/commit-conventions.md +22 -0
- package/dist/lite/.claude/rules/compounding-axis-fresh-analysis.md +173 -0
- package/dist/lite/.claude/rules/compounding-sequence-fresh-analysis.md +173 -0
- package/dist/lite/.claude/rules/context-engineering.md +155 -0
- package/dist/lite/.claude/rules/context-management.md +85 -0
- package/dist/lite/.claude/rules/defensive-bash.md +52 -0
- package/dist/lite/.claude/rules/deferred-actions.md +233 -0
- package/dist/lite/.claude/rules/destructive-operations.md +69 -0
- package/dist/lite/.claude/rules/diagnosis.md +38 -0
- package/dist/lite/.claude/rules/github-issue-flash-tweet.md +114 -0
- package/dist/lite/.claude/rules/guardrails.md +73 -0
- package/dist/lite/.claude/rules/hook-wire-on-author.md +77 -0
- package/dist/lite/.claude/rules/identifier-leak-prevention.md +73 -0
- package/dist/lite/.claude/rules/iteration-bet-brief-completeness.md +43 -0
- package/dist/lite/.claude/rules/lite-manifest-schema-change-discipline.md +79 -0
- package/dist/lite/.claude/rules/longrun-prep-plan-doc-compression.md +77 -0
- package/dist/lite/.claude/rules/loop-discipline.md +71 -0
- package/dist/lite/.claude/rules/manual-prod-approval.md +100 -0
- package/dist/lite/.claude/rules/marker-enrichment-discipline.md +72 -0
- package/dist/lite/.claude/rules/mobile-ephemeral-session.md +109 -0
- package/dist/lite/.claude/rules/new-dependency-check.md +44 -0
- package/dist/lite/.claude/rules/oo-ad-entry-point.md +95 -0
- package/dist/lite/.claude/rules/operator-facing-prose.md +177 -0
- package/dist/lite/.claude/rules/option-label-discipline.md +82 -0
- package/dist/lite/.claude/rules/pattern-annotation.md +83 -0
- package/dist/lite/.claude/rules/persona-name-leak-scrub.md +90 -0
- package/dist/lite/.claude/rules/plain-english-discipline.md +132 -0
- package/dist/lite/.claude/rules/plan-enumeration-needs-value-props.md +177 -0
- package/dist/lite/.claude/rules/pr-body-shape.md +195 -0
- package/dist/lite/.claude/rules/pr-strategy.md +142 -0
- package/dist/lite/.claude/rules/pr-title-shape.md +90 -0
- package/dist/lite/.claude/rules/prototype-workflow.md +53 -0
- package/dist/lite/.claude/rules/reserved-skill-names.md +103 -0
- package/dist/lite/.claude/rules/schema-management.md +42 -0
- package/dist/lite/.claude/rules/sdlc-gates.md +149 -0
- package/dist/lite/.claude/rules/security.md +37 -0
- package/dist/lite/.claude/rules/session-artifacts.md +236 -0
- package/dist/lite/.claude/rules/skill-composition-declarations.md +105 -0
- package/dist/lite/.claude/rules/skill-description-clarity.md +196 -0
- package/dist/lite/.claude/rules/skill-procedure-step-list.md +119 -0
- package/dist/lite/.claude/rules/sprint-prep-preset-picker.md +76 -0
- package/dist/lite/.claude/rules/state-schema-validation.md +156 -0
- package/dist/lite/.claude/rules/stuck-signal-diagnostic.md +111 -0
- package/dist/lite/.claude/rules/substrate-config-schema.md +85 -0
- package/dist/lite/.claude/rules/test-list-discipline.md +129 -0
- package/dist/lite/.claude/rules/test-sufficiency.md +186 -0
- package/dist/lite/.claude/rules/testing-tier-config.md +125 -0
- package/dist/lite/.claude/rules/testing.md +38 -0
- package/dist/lite/.claude/rules/turn-estimate-grounding.md +82 -0
- package/dist/lite/.claude/rules/visual-hierarchy.md +427 -0
- package/dist/lite/.claude/rules/we-dont-break-adopters.md +103 -0
- package/dist/lite/.claude/rules/whereami-load-bearing.md +184 -0
- package/dist/lite/.claude/rules/writing-craft-discipline.md +72 -0
- package/dist/lite/.claude/rules/wu-sequencing-compounds.md +119 -0
- package/dist/lite/.claude/skills/build/SKILL.md +640 -0
- package/dist/lite/.claude/skills/chronicle/SKILL.md +55 -0
- package/dist/lite/.claude/skills/clean-artifacts/SKILL.md +249 -0
- package/dist/lite/.claude/skills/decompose/SKILL.md +280 -0
- package/dist/lite/.claude/skills/diagnose/SKILL.md +297 -0
- package/dist/lite/.claude/skills/feynman/SKILL.md +90 -0
- package/dist/lite/.claude/skills/howdoi/SKILL.md +105 -0
- package/dist/lite/.claude/skills/ia-model/SKILL.md +108 -0
- package/dist/lite/.claude/skills/interaction-design/SKILL.md +112 -0
- package/dist/lite/.claude/skills/interpret-input/SKILL.md +180 -0
- package/dist/lite/.claude/skills/journal/SKILL.md +209 -0
- package/dist/lite/.claude/skills/kiss/SKILL.md +449 -0
- package/dist/lite/.claude/skills/launch/SKILL.md +915 -0
- package/dist/lite/.claude/skills/lean-canvas/SKILL.md +332 -0
- package/dist/lite/.claude/skills/longrun/SKILL.md +512 -0
- package/dist/lite/.claude/skills/luminary/SKILL.md +481 -0
- package/dist/lite/.claude/skills/ogilvy-writing-audit/SKILL.md +177 -0
- package/dist/lite/.claude/skills/onboard-repo/SKILL.md +1640 -0
- package/dist/lite/.claude/skills/pattern-review/SKILL.md +99 -0
- package/dist/lite/.claude/skills/personas/SKILL.md +207 -0
- package/dist/lite/.claude/skills/promote/SKILL.md +283 -0
- package/dist/lite/.claude/skills/requirement/SKILL.md +98 -0
- package/dist/lite/.claude/skills/retro/SKILL.md +117 -0
- package/dist/lite/.claude/skills/riff/SKILL.md +114 -0
- package/dist/lite/.claude/skills/roadmap-reconcile/SKILL.md +163 -0
- package/dist/lite/.claude/skills/session-end/SKILL.md +309 -0
- package/dist/lite/.claude/skills/session-log/SKILL.md +299 -0
- package/dist/lite/.claude/skills/skills/SKILL.md +228 -0
- package/dist/lite/.claude/skills/spec/SKILL.md +105 -0
- package/dist/lite/.claude/skills/sprint/SKILL.md +418 -0
- package/dist/lite/.claude/skills/stage/SKILL.md +384 -0
- package/dist/lite/.claude/skills/state-a-problem/SKILL.md +185 -0
- package/dist/lite/.claude/skills/temperance/SKILL.md +108 -0
- package/dist/lite/.claude/skills/use-case/SKILL.md +417 -0
- package/dist/lite/.claude/skills/user-stories/SKILL.md +268 -0
- package/dist/lite/.claude/skills/value-prop/SKILL.md +251 -0
- package/dist/lite/.claude/skills/verify/SKILL.md +160 -0
- package/dist/lite/.claude/skills/visual-review/SKILL.md +503 -0
- package/dist/lite/.claude/skills/whats-the-plan/SKILL.md +202 -0
- package/dist/lite/.claude/skills/whereami/SKILL.md +307 -0
- package/dist/lite/AGENTS.md +79 -0
- package/dist/lite/CLAUDE-lite.md +85 -0
- package/dist/lite/CODE_OF_CONDUCT.md +28 -0
- package/dist/lite/CONTRIBUTING.md +177 -0
- package/dist/lite/README.md +173 -0
- package/dist/lite/SECURITY.md +19 -0
- package/dist/lite/architecture/decisions/ADR-029-release-pipeline.md +79 -0
- package/dist/lite/architecture/decisions/ADR-031-non-breaking-changes-adopter-discipline.md +139 -0
- package/dist/lite/architecture/decisions/ADR-032-adopter-sync-dispatcher-architecture.md +192 -0
- package/dist/lite/architecture/decisions/ADR-039-release-tagging-scheme.md +145 -0
- package/dist/lite/architecture/decisions/ADR-040-planning-skill-vocabulary-and-lite-profile.md +155 -0
- package/dist/lite/architecture/decisions/ADR-044-unified-skill-body-template.md +162 -0
- package/dist/lite/lib/clean-artifacts-sweep.sh +112 -0
- package/dist/lite/lib/code-comment-discipline.sh +144 -0
- package/dist/lite/lib/composer-preflight.sh +459 -0
- package/dist/lite/lib/deferred-actions.sh +146 -0
- package/dist/lite/lib/hook-header-parser.sh +61 -0
- package/dist/lite/lib/hook-heartbeat.sh +152 -0
- package/dist/lite/lib/hook-inject.sh +255 -0
- package/dist/lite/lib/hook-installer.sh +195 -0
- package/dist/lite/lib/luminary-pick.sh +96 -0
- package/dist/lite/lib/output-discipline.sh +143 -0
- package/dist/lite/lib/prose-scan-boundary.sh +171 -0
- package/dist/lite/lib/rewrite-check.sh +214 -0
- package/dist/lite/lib/session-rescue.sh +151 -0
- package/dist/lite/lib/source-graph-walker.sh +277 -0
- package/dist/lite/lib/state.sh +1372 -0
- package/dist/lite/lib/telemetry.sh +205 -0
- package/dist/lite/lib/tier-check.sh +187 -0
- package/dist/lite/lib/tier-dependency-audit.sh +1088 -0
- package/dist/lite/presence/install/bassclef-hook-connect.sh +178 -0
- package/dist/lite/presence/install/bassclef-sync.dispatcher.template.sh +841 -0
- package/dist/lite/presence/install/bassclef-sync.template.sh +2278 -0
- package/dist/lite/presence/install/schedule-auto-save.cron.sh +88 -0
- package/dist/lite/presence/install/schedule-auto-save.taskscheduler.md +122 -0
- package/dist/lite/scripts/aggregate-telemetry.sh +217 -0
- package/dist/lite/scripts/analyze-tier-dependencies.sh +239 -0
- package/dist/lite/scripts/generate-lite-manifest.sh +505 -0
- package/dist/lite/scripts/generate-tier-manifest.sh +28 -0
- package/dist/lite/scripts/intent-drift-check.sh +456 -0
- package/dist/lite/scripts/lite-manifest-drift-check.sh +146 -0
- package/dist/lite/scripts/render-lite-manifest-doc.sh +150 -0
- package/dist/lite/standards/adr-template.md +86 -0
- package/dist/lite/standards/api-conventions/nextjs.md +84 -0
- package/dist/lite/standards/artifact-composition.md +209 -0
- package/dist/lite/standards/bash-hook-safety.md +246 -0
- package/dist/lite/standards/bassclef-configs-schema.md +232 -0
- package/dist/lite/standards/bassclef-evolution.md +143 -0
- package/dist/lite/standards/bassclef-internal-jargon.md +244 -0
- package/dist/lite/standards/bassclef-managed-sentinel.md +96 -0
- package/dist/lite/standards/bassclef-source-config.md +228 -0
- package/dist/lite/standards/branch-stacking.md +408 -0
- package/dist/lite/standards/code-safety-principles.md +176 -0
- package/dist/lite/standards/composer-prerequisites.md +155 -0
- package/dist/lite/standards/deferred-actions-schema.md +204 -0
- package/dist/lite/standards/dependency-discipline/cargo.md +39 -0
- package/dist/lite/standards/dependency-discipline/gem.md +43 -0
- package/dist/lite/standards/dependency-discipline/go-mod.md +41 -0
- package/dist/lite/standards/dependency-discipline/npm.md +42 -0
- package/dist/lite/standards/dependency-discipline/pip.md +42 -0
- package/dist/lite/standards/deployment-topology/ec2-tailscale.md +225 -0
- package/dist/lite/standards/deployment-topology.md +69 -0
- package/dist/lite/standards/docs-sync-allowlist.md +76 -0
- package/dist/lite/standards/domain-and-dns.md +145 -0
- package/dist/lite/standards/frontend-stack.md +67 -0
- package/dist/lite/standards/frontmatter-schema.md +154 -0
- package/dist/lite/standards/graceful-exit.md +227 -0
- package/dist/lite/standards/hook-idempotency.md +102 -0
- package/dist/lite/standards/hook-injection-discipline.md +202 -0
- package/dist/lite/standards/hook-install-class.md +215 -0
- package/dist/lite/standards/input-handler-interface.md +152 -0
- package/dist/lite/standards/lite-manifest-schema-changes.md +180 -0
- package/dist/lite/standards/lite-manifest.json +2797 -0
- package/dist/lite/standards/luminary-matching.md +105 -0
- package/dist/lite/standards/luminary-problem-patterns.md +481 -0
- package/dist/lite/standards/migration-discipline/active-record.md +50 -0
- package/dist/lite/standards/migration-discipline/alembic.md +43 -0
- package/dist/lite/standards/migration-discipline/gorm.md +50 -0
- package/dist/lite/standards/migration-discipline/prisma.md +53 -0
- package/dist/lite/standards/migration-discipline/sqlalchemy.md +51 -0
- package/dist/lite/standards/mobile-ephemeral-session.md +167 -0
- package/dist/lite/standards/model-routing-discipline.md +160 -0
- package/dist/lite/standards/ogilvy-writing-rules.md +225 -0
- package/dist/lite/standards/opener-discipline.md +96 -0
- package/dist/lite/standards/operator-facing-prose-discipline.md +201 -0
- package/dist/lite/standards/persona-schema.md +229 -0
- package/dist/lite/standards/pluggable-luminaries.md +323 -0
- package/dist/lite/standards/pr-body-discipline.md +115 -0
- package/dist/lite/standards/preview-state-schema.md +189 -0
- package/dist/lite/standards/project-directory-layout.md +276 -0
- package/dist/lite/standards/release-tagging.md +137 -0
- package/dist/lite/standards/reserved-skill-names.md +120 -0
- package/dist/lite/standards/scannable-multi-option-output.md +265 -0
- package/dist/lite/standards/sdlc-compliance.md +286 -0
- package/dist/lite/standards/sdlc-gates/typescript.md +57 -0
- package/dist/lite/standards/secrets-lifecycle.md +210 -0
- package/dist/lite/standards/security-scanner-adapter.md +145 -0
- package/dist/lite/standards/session-board.md +256 -0
- package/dist/lite/standards/skill-output-discipline.md +121 -0
- package/dist/lite/standards/state-spine-contract.md +255 -0
- package/dist/lite/standards/state-spine.md +511 -0
- package/dist/lite/standards/steering-hints/kiss-words.md +11 -0
- package/dist/lite/standards/substrate-config-schema.md +267 -0
- package/dist/lite/standards/tech-stack-config.md +109 -0
- package/dist/lite/standards/tier-dependency-analysis.md +167 -0
- package/dist/lite/standards/tier-runtime-deps/lite.md +57 -0
- package/dist/lite/standards/tier-tag-schema.md +155 -0
- package/dist/lite/standards/two-layer-config.md +99 -0
- package/dist/lite/standards/use-case-format.md +292 -0
- package/dist/lite/standards/user-story-invest.md +268 -0
- package/dist/lite/standards/velocity-and-appetite.md +229 -0
- package/dist/lite/standards/voice-input-pattern.md +119 -0
- package/dist/lite/standards/whereami-schema.md +301 -0
- package/dist/lite/standards/worktree-management.md +211 -0
- package/dist/lite/standards/writing-guide.md +213 -0
- package/dist/lite/templates/chronicle-template.md +75 -0
- package/dist/lite/templates/deferred-action-template.md +45 -0
- package/dist/lite/templates/memory-proposal-template.md +77 -0
- package/dist/lite/templates/persona-template.md +200 -0
- package/dist/lite/templates/pr-faq.md +45 -0
- package/dist/lite/templates/secret-rotation-template.md +162 -0
- package/dist/lite/templates/spec-template.md +131 -0
- package/dist/lite/templates/use-case-template.md +194 -0
- package/dist/lite/templates/user-story-template.md +107 -0
- package/dist/lite/templates/whereami-template.md +101 -0
- package/package.json +1 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: The Tier 0 hook (bassclef#1037) enforces test PRESENCE + RECENCY.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test Sufficiency Rubric
|
|
7
|
+
|
|
8
|
+
The Tier 0 hook (bassclef#1037) enforces test PRESENCE + RECENCY. The test file exists. Its mtime is at least as new as the source file's. That catches tests written after source. It catches zero things about whether the test ASSERTS ENOUGH.
|
|
9
|
+
|
|
10
|
+
This rule codifies the 12 mechanical criteria the agent applies before committing any test file. Each criterion is greppable, countable, and verifiable against the source it tests. Together they form the sufficiency contract for bassclef's Tier 0 hooks, state-spine accessors, and adopter-stack code where systematic discipline earns its keep.
|
|
11
|
+
|
|
12
|
+
INSTEAD of relying on "feels complete" — the squishy framing that surfaced this gap during /longrun prep 2026-06-17 — the agent applies the 12 criteria mechanically. The agent marks each as covered or deferred with reason in the test-list block (bassclef#1090) and ships the result.
|
|
13
|
+
|
|
14
|
+
## Anchor luminaries
|
|
15
|
+
|
|
16
|
+
- `@luminary kent-beck` — TDD rhythm anchor; test list is the planning artifact this rubric assumes
|
|
17
|
+
- `@luminary glenford-myers` — Coverage taxonomy anchor; criteria 1-4 are direct applications of Myers's 1979 categories
|
|
18
|
+
- `@luminary tony-hoare` — Contract testing anchor; criteria 5-10 are precondition / postcondition / invariant assertions in disguise
|
|
19
|
+
|
|
20
|
+
The rubric is what each luminary's lens produces when applied to a bassclef bash hook or state-spine accessor. The substrate operationalizes the discipline; the luminaries supply the why.
|
|
21
|
+
|
|
22
|
+
## The 12 criteria
|
|
23
|
+
|
|
24
|
+
### 1. Branch coverage (Myers — decision coverage)
|
|
25
|
+
|
|
26
|
+
Every branch in the source has at least one test that exercises it. Mechanically: `grep -cE '^\s*(if|elif|else|case|\|\|)' <source>` counts decision points; the test file owes that many `[x]` lines minimum.
|
|
27
|
+
|
|
28
|
+
Example for `auto-save-idle.sh` with 4 branches (no-changes / lock-present / defer-present / proceed): the test file owes 4 tests minimum to satisfy decision coverage alone.
|
|
29
|
+
|
|
30
|
+
INSTEAD of one test that covers the happy path: one test per branch. The marginal cost per test is small at write-time and compounds across every consumer adopting the hook.
|
|
31
|
+
|
|
32
|
+
### 2. Exit code matrix (Hoare — postcondition)
|
|
33
|
+
|
|
34
|
+
Every distinct `exit N` in the source has at least one test that triggers that exit and asserts the code matches. Mechanically: `grep -oE 'exit [0-9]+' <source> | sort -u` enumerates the codes; the test file owes one assertion per code.
|
|
35
|
+
|
|
36
|
+
Example: `pre-commit-gate.sh` has `exit 0` (pass), `exit 2` (BLOCK), `exit 3` (validation fail). Test file asserts each appears under the input that triggers it.
|
|
37
|
+
|
|
38
|
+
INSTEAD of asserting only success exit: one assertion per distinct exit code. Exit codes ARE the hook's postcondition contract with the harness; the test list owes one Hoare-style `{P} S {Q-exit-N}` triple per code.
|
|
39
|
+
|
|
40
|
+
### 3. Tool-name matcher (Myers — equivalence partitioning)
|
|
41
|
+
|
|
42
|
+
For hooks matching on `tool_name`, the test file has one test per matched tool AND at least one non-matched tool asserting pass-through. Each matched tool is one equivalence class; the non-matched set is another class with one representative.
|
|
43
|
+
|
|
44
|
+
Example: `pre-commit-gate.sh` matches `Edit|Write|MultiEdit`. Test file owes: Edit-fires test, Write-fires test, MultiEdit-fires test, Bash-pass-through test, NotebookEdit-pass-through test.
|
|
45
|
+
|
|
46
|
+
INSTEAD of asserting only the matched class: cover both halves of the discriminator. Pass-through tests catch matcher regressions that would silently expand the hook's surface.
|
|
47
|
+
|
|
48
|
+
### 4. Path-matcher coverage (Myers — boundary value)
|
|
49
|
+
|
|
50
|
+
For hooks matching on file paths or globs, the test file has a positive test (path matches) AND a near-miss negative test (similar path doesn't match) per glob. Boundary value applied to string-shape inputs.
|
|
51
|
+
|
|
52
|
+
Example: hook matches `state/markers/temperance/*.marker`. Positive test: `state/markers/temperance/foo.marker`. Near-miss tests: `state/markers/temperance/foo` (no extension), `state/markers/temperance-x/foo.marker` (similar dir name), `state/temperance/foo.marker` (missing markers segment).
|
|
53
|
+
|
|
54
|
+
INSTEAD of asserting only the matched path: near-miss tests catch glob bugs that would either widen or narrow the matcher unexpectedly.
|
|
55
|
+
|
|
56
|
+
### 5. Override path (Hoare — alternative precondition)
|
|
57
|
+
|
|
58
|
+
Every `SKIP_*` env var bypass in the source has one test that exercises the override AND asserts the override path fires (logged via trace-helper, hook exits with pass code, side effects suppressed).
|
|
59
|
+
|
|
60
|
+
Example: `auto-save-idle.sh` honors `SKIP_AUTO_SAVE=1`. Test file owes: with-flag-set test (asserts no-commit + trace log emission), without-flag test (asserts normal path).
|
|
61
|
+
|
|
62
|
+
INSTEAD of treating override paths as unused: they are alternative preconditions in Hoare's framing. Each override is a `{P-skip-set} S {Q-bypass}` triple the test list owes one entry for.
|
|
63
|
+
|
|
64
|
+
### 6. stdin contract (Hoare — precondition discipline)
|
|
65
|
+
|
|
66
|
+
The hook reads JSON from the harness via stdin. Each discriminated input shape (different `tool_input` fields, different content shapes) has one test that exercises it.
|
|
67
|
+
|
|
68
|
+
Example: `pre-commit-gate.sh` discriminates on `tool_input.file_path` (string) and absent (some Edit calls omit it). Test file owes: file_path-present test, file_path-absent test, malformed-JSON test (graceful error path).
|
|
69
|
+
|
|
70
|
+
INSTEAD of asserting only the well-formed input: malformed JSON is a precondition violation the hook must handle without crashing. Tests assert the hook reports the violation rather than crashing the harness.
|
|
71
|
+
|
|
72
|
+
### 7. External-binary handling (Hoare — invariant under environment variation)
|
|
73
|
+
|
|
74
|
+
For every external call (`jq`, `gh`, `git`, `flock`, `python3`, etc.), tests either mock the binary OR exercise a graceful-missing test asserting the hook handles binary-absent without crashing.
|
|
75
|
+
|
|
76
|
+
Example: hook calls `jq` to parse JSON. Test file owes: jq-present happy-path test, jq-missing test (asserts hook detects and exits with informative stderr OR falls back to bash-native parsing).
|
|
77
|
+
|
|
78
|
+
INSTEAD of assuming every adopter environment has every binary: external binaries are an environmental precondition the hook should fail soft against. Bassclef-internal hooks may assume `jq` (Tier 0). Adopter-distributed hooks should not.
|
|
79
|
+
|
|
80
|
+
### 8. Trap / cleanup (Hoare — class invariant via `trap EXIT`)
|
|
81
|
+
|
|
82
|
+
Sources that use `trap '...' EXIT` (per defensive-bash.md) need two tests: one exercises the success path (verify cleanup ran) AND one exercises a failure path (verify cleanup still ran).
|
|
83
|
+
|
|
84
|
+
Example: hook acquires `flock` and uses `trap "flock -u" EXIT`. Test file owes: success-path test (verify lock released on normal exit), failure-path test (verify lock released when hook fails mid-execution).
|
|
85
|
+
|
|
86
|
+
INSTEAD of trusting `trap` works by inspection: the trap IS the class invariant; the test verifies the invariant holds across both observable paths. Trap regressions silently leak resources.
|
|
87
|
+
|
|
88
|
+
### 9. stderr format (Hoare — postcondition contract for BLOCK exits)
|
|
89
|
+
|
|
90
|
+
For BLOCK exits (code 2 or 3), the test asserts the stderr message contains the required structured fields per `.claude/rules/blocked-items.md`: entity type, path being acted on, ajv error details (when applicable), three resolution paths.
|
|
91
|
+
|
|
92
|
+
Example: `state-validate.sh` BLOCKs on schema failure. Test file owes: BLOCK-exit test asserts stderr contains "Entity type:", "Path:", "ajv:", and the three resolution-path lines.
|
|
93
|
+
|
|
94
|
+
INSTEAD of asserting only exit code on BLOCK: the stderr message IS the contract with the agent. A BLOCK with empty stderr is a worse failure than no BLOCK at all — the agent loses the remediation path.
|
|
95
|
+
|
|
96
|
+
### 10. State-file interactions (Hoare — postcondition on side effects)
|
|
97
|
+
|
|
98
|
+
For hooks that read or write markers in `state/markers/` (or any state file), tests cover both read paths and write paths. Read-path test: state file present in expected shape → hook reads correctly. Write-path test: hook write completes → file content matches the expected shape.
|
|
99
|
+
|
|
100
|
+
Example: `pre-commit-gate.sh` reads `state/markers/temperance/<branch-slug>.marker`. Test file owes: marker-present test (verify hook reads + passes), marker-absent test (verify hook BLOCKs + writes BLOCKED stderr), marker-malformed test (verify hook fails-soft with informative error).
|
|
101
|
+
|
|
102
|
+
INSTEAD of testing only the read OR only the write: state-file interactions are bidirectional contracts. Skipping the write-path test means schema drift between writer and reader goes unnoticed until production.
|
|
103
|
+
|
|
104
|
+
### 11. Path resolution under both install classes (Hoare — invariant under install layout; added bet 27c WU-9)
|
|
105
|
+
|
|
106
|
+
For hooks that read project resources (standards files, configs, libs) AND declare `# install-class: dual` per `standards/hook-install-class.md`, tests pin behavior under both install layouts. Project class (CLAUDE_PROJECT_DIR set). Operator class (HOME_OVERRIDE pointing at fixture user-install layout). Mechanically: at least one test per resource read that fires under each layout.
|
|
107
|
+
|
|
108
|
+
Example: `turn-prose-kiss-check.sh` reads `standards/bassclef-internal-jargon.md` via `resolve_standards_path` from `lib/hook-inject.sh`. The test file owes four tests — Test 54 (CLAUDE_PROJECT_DIR layer 1), Test 55 (KISS_STANDARDS_FILE env layer 2), Test 56 (HOME_OVERRIDE layer 3), Test 57 (all layers fail; defensive fallback). PR #427 ships exactly those four tests.
|
|
109
|
+
|
|
110
|
+
INSTEAD of testing only project install: install class is an environmental precondition the hook MUST honor under both layouts. Skipping the operator install test produces the silent fail pattern that surfaced 2026-06-27 (kiss path resolution defect; chronicle Gate Evidence row 1). The cure pattern (HOME_OVERRIDE fixture + Tests 54-57 shape) is reusable across every dual-class hook.
|
|
111
|
+
|
|
112
|
+
This criterion fires when the source under test declares `install-class: dual` (most steering hooks; some adopter-distributed project hooks). Source declares `install-class: project` only → criterion does not fire. Project resources always resolve cleanly under project install.
|
|
113
|
+
|
|
114
|
+
### 12. Invocation-mode variation for coordinated fragments (Feathers + Hoare — invariant under invocation mode; added bet 2026-07-30c WU-3)
|
|
115
|
+
|
|
116
|
+
For modules invoked by a coordinator (fragments under `session-reflection.d/`, `pre-commit-hooks.d/`, or any `*.d/` directory that a parent hook sources), tests pin behavior under BOTH invocation modes:
|
|
117
|
+
|
|
118
|
+
- **Standalone**: `bash "$module"` — exit codes propagate normally; the module runs as its own process
|
|
119
|
+
- **Sourced**: coordinator sources the module under `set -e`; the module MUST use `return` (or safe dual form) not `exit`, else the coordinator dies with the module's exit code
|
|
120
|
+
|
|
121
|
+
Mechanically: at least one test per fragment that (a) sources it under a set -e wrapper and asserts a canary after the source fires, and (b) invokes it standalone via bash and asserts no "return: can only" error appears in stderr.
|
|
122
|
+
|
|
123
|
+
Example: `.claude/hooks/session-reflection.d/*.sh` fragments. Test file `.claude/hooks/tests/session-reflection-coordinator-full.test.sh` (bet 2026-07-30c WU-1) runs Class A (sourced-parent-survives) plus Class B (standalone-no-return-error) for every fragment. The wrapper injects the coordinator-side helpers (`blocked_banner`, `trace_log`, `BASSCLEF_DIR`) as stubs so the fragment's contract with the parent scope is honored during the test.
|
|
124
|
+
|
|
125
|
+
INSTEAD of trusting that `exit` in a sourced file is fine: sourced `exit` kills the parent process silently. The class shipped in PR #542 (2026-06-30 — `05-active-bet.sh`) and cost 36 days of silent session-start check skips in every adopter session until PR #992 cured 2026-07-30. Criterion 12 exists so the class cannot recur — every new fragment PR ships with sourced-parent-survives AND standalone-no-return-error assertions.
|
|
126
|
+
|
|
127
|
+
This criterion fires when the source lives under a `*.d/` directory whose parent hook sources fragments in a loop. Detection: the source directory name ends in `.d/` AND at least one sibling `.sh` file in the parent directory sources files from that directory. Adopter-authored fragments that plug into bassclef coordinators inherit this criterion at PR time.
|
|
128
|
+
|
|
129
|
+
Coordinator-side coupling note: fragments frequently call helper functions the coordinator defines (e.g., `blocked_banner`, `trace_log`) and read environment variables the coordinator exports (e.g., `BASSCLEF_DIR`). The invocation-mode test wrapper MUST inject these helpers as stubs so the test characterizes the fragment under conditions matching real coordinator invocation. Skipping the stubs produces false-red on any fragment that calls a coordinator helper.
|
|
130
|
+
|
|
131
|
+
## How to apply the rubric
|
|
132
|
+
|
|
133
|
+
1. **Before writing any test**, list applicable criteria for the source under test. Some hooks have all 10; some (pure-function libraries) have fewer (no stdin contract, no override path).
|
|
134
|
+
2. **Open the test file with the test-list block** (bassclef#1090). Use one `[ ]` line per criterion-derived assertion.
|
|
135
|
+
3. **Implement each assertion**, marking `[x]` as each ships. Add new `[ ]` lines as additional cases surface during implementation.
|
|
136
|
+
4. **Before commit**, scan the test-list for `[ ]` lines. Each is either:
|
|
137
|
+
- Implemented in this commit (mark `[x]`)
|
|
138
|
+
- Genuinely deferred (mark `[~]` with one-line reason per test-list-discipline.md)
|
|
139
|
+
- Required but missed (write the assertion now; do not commit with the line as `[ ]` when it should be `[x]`)
|
|
140
|
+
5. **Verify mechanical counts** for criteria 1, 2, 7: branch count, exit count, external-binary count. The test count must equal or exceed each source count.
|
|
141
|
+
|
|
142
|
+
INSTEAD of relying on "feels complete": each criterion has a greppable verification. If the test file has fewer `[x]` lines than the source has branches, the rubric is not satisfied. Concrete, mechanical, auditable.
|
|
143
|
+
|
|
144
|
+
## What the rubric does NOT cover
|
|
145
|
+
|
|
146
|
+
- **Test rhythm** — when to write tests (route to Beck via `testing-tier-config.md` Tier 0)
|
|
147
|
+
- **Test quality** — what makes a test well-written (route to `.claude/rules/testing.md`)
|
|
148
|
+
- **Test design** — whether the source's shape makes testing easy or hard (route to Ousterhout via `john-ousterhout.md`)
|
|
149
|
+
- **Property-based testing** — coverage of input space via QuickCheck-style generators (future addition if a stack adopts it; not in bassclef's bash substrate today)
|
|
150
|
+
- **Multi-fragment coordinator interactions** — how fragment N's side effects change fragment N+1's behavior (route to integration tests at the coordinator level, e.g., `session-reflection-coordinator.test.sh` per PR #992; criterion 12 covers per-fragment invocation-mode contract only)
|
|
151
|
+
|
|
152
|
+
INSTEAD of folding these into the rubric: each routes to a sister discipline. The rubric is sufficiency at the assertion-category layer; quality and rhythm and design are different surfaces.
|
|
153
|
+
|
|
154
|
+
## Override
|
|
155
|
+
|
|
156
|
+
`SKIP_TEST_SUFFICIENCY=1 <command>` — logged via trace-helper. Use only for one-shot migration scripts, emergency rescue, or when adding the assertion would require infrastructure not yet in place (file follow-on ticket).
|
|
157
|
+
|
|
158
|
+
INSTEAD of overriding for routine work: write the assertion. Each criterion costs minutes at write-time; each missed assertion costs hours of debugging when it ships.
|
|
159
|
+
|
|
160
|
+
## When this rule fires
|
|
161
|
+
|
|
162
|
+
Auto-loaded into every session via `additionalDirectories`. Agents self-check before committing any test file. The Tier 0 hook (`testing-tier-enforce.sh`) does not currently enforce the rubric mechanically.
|
|
163
|
+
|
|
164
|
+
INSTEAD: methodology layer with reviewer + agent self-check. V2 mechanical extension deferred to follow-on ticket. Count-based criteria (1, 2, 7) are auto-verifiable via the existing Tier 0 hook with a grep extension.
|
|
165
|
+
|
|
166
|
+
## V2 — mechanical extension (deferred)
|
|
167
|
+
|
|
168
|
+
The operator files a follow-on ticket to extend the Tier 0 hook when recurring drift shows up in manual self-check. The follow-on covers:
|
|
169
|
+
|
|
170
|
+
- Branch count: grep source for decision points; count test `[x]` lines; BLOCK when test count < branch count
|
|
171
|
+
- Exit code matrix: grep source for `exit N`; verify test asserts each
|
|
172
|
+
- External binary handling: grep source for external calls; verify test mocks or graceful-missing path exists per call
|
|
173
|
+
|
|
174
|
+
Subjective criteria (3-6, 8-10) stay methodology-only. Beck + Myers + Hoare's disciplines pair best with reviewer judgment for those; mechanical enforcement at the subjective layer produces gaming, not quality.
|
|
175
|
+
|
|
176
|
+
## Composes with
|
|
177
|
+
|
|
178
|
+
- `.claude/rules/test-list-discipline.md` (bassclef#1090) — Beck's planning artifact; the test-list IS the rubric tracking surface
|
|
179
|
+
- `.claude/rules/testing-tier-config.md` (bassclef#1037) — Tier 0 presence + recency; this rule layers sufficiency on top
|
|
180
|
+
- `.claude/rules/testing.md` — what makes a good test once you write it
|
|
181
|
+
- `.claude/rules/defensive-bash.md` — 7 bash disciplines; criteria 7-8 verify defensive-bash compliance in tests
|
|
182
|
+
- `.claude/rules/state-schema-validation.md` — state-spine accessor tests use criterion 10 (state-file interactions)
|
|
183
|
+
- `.claude/rules/blocked-items.md` — criterion 9 (stderr format) cites this rule's structured-field requirements
|
|
184
|
+
- `@luminary kent-beck` — TDD rhythm + test-list anchor
|
|
185
|
+
- `@luminary glenford-myers` — coverage taxonomy anchor (criteria 1-4)
|
|
186
|
+
- `@luminary tony-hoare` — contract testing anchor (criteria 5-10)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: "Bassclef's testing discipline is configured per path-matcher in .claude/bassclef-configs.jsonc under the testing section."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing-Tier Config
|
|
7
|
+
|
|
8
|
+
Bassclef's testing discipline is configured per path-matcher in `.claude/bassclef-configs.jsonc` under the `testing` section. Four tiers — 0 strict TDD / 1 test-with / 2 smoke / 3 manual-verify — pick by blast radius. Most-specific path-matcher wins. The mtime-checking hook (`testing-tier-enforce.sh`) enforces Tier 0 mechanically; Tier 1 WARNs; Tier 2 + Tier 3 stay silent.
|
|
9
|
+
|
|
10
|
+
This rule supersedes the honor-system framing of `.claude/rules/testing.md`. That rule remains the test-content guidance (what makes a good test); this rule governs which paths require tests and what enforcement fires.
|
|
11
|
+
|
|
12
|
+
## The four tiers
|
|
13
|
+
|
|
14
|
+
| Tier | Name | What it means | Enforcement |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| **0** | Strict TDD | Test mtime ≤ source mtime AND test file present | BLOCK at pre-commit |
|
|
17
|
+
| **1** | Test-with | New test expected when new source ships | WARN at pre-commit |
|
|
18
|
+
| **2** | Smoke | Smoke test exists somewhere for this surface | Silent (advisory only) |
|
|
19
|
+
| **3** | Manual verify | Operator eyeballs the change | Silent (no enforcement) |
|
|
20
|
+
|
|
21
|
+
**Tier 0** is for surfaces where silent bugs compound across every adopter. Bassclef hooks, state-spine schemas, lib/state.sh accessors, and the substrate's own pre-commit gates live here.
|
|
22
|
+
|
|
23
|
+
**Tier 1** is for bassclef's own glue scripts (`scripts/*.sh`) and adopter-app source files where TDD is expected but the WARN gives leeway for in-progress work.
|
|
24
|
+
|
|
25
|
+
**Tier 2** is for adopter-app routes and components where end-to-end smoke tests cover the surface without per-file unit tests. The path-matcher does not look for a sibling test file; the operator confirms a smoke test exists.
|
|
26
|
+
|
|
27
|
+
**Tier 3** is the silent default for narrative content. Chronicles, journal entries, iteration-goal docs, decompositions, and operator-private narrative all live here. INSTEAD of testing narrative: the operator reads it.
|
|
28
|
+
|
|
29
|
+
## Path-matcher precedence
|
|
30
|
+
|
|
31
|
+
Two categories of path matchers, with different ownership:
|
|
32
|
+
|
|
33
|
+
1. **Substrate-internal paths** — bassclef's own infrastructure. **Hard-coded in this rule body.** NOT adopter-configurable. Adopters read the discipline; they cannot edit it.
|
|
34
|
+
2. **Adopter-app paths** — adopter's own code paths. Configured in adopter's `bassclef-configs.jsonc` `testing.path_matchers`. Per-adopter.
|
|
35
|
+
|
|
36
|
+
The hook walks both lists. Substrate paths take precedence; adopter overrides on substrate paths are silently ignored. When no entry matches, `testing.global_floor` applies. The default global floor is Tier 1 (WARN on missing test).
|
|
37
|
+
|
|
38
|
+
### Substrate-internal path-matchers (HARD-CODED — not adopter-configurable)
|
|
39
|
+
|
|
40
|
+
| Path | Tier | Why this is Tier 0 / fixed |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `.claude/hooks/*.sh` | 0 | Silent bugs compound across every adopter using bassclef |
|
|
43
|
+
| `scripts/migrate-adopter-references.sh` | 0 | Adopter-facing migration tool; Tier 0 hooks call it at session-start (per ADR-031); a defect hits every adopter machine. (Moved from `strategy/templates/` per bassclef-upstream#317 Phase 1b.) |
|
|
44
|
+
| `scripts/bassclef-orphan-parking.sh` | 0 | Adopter-facing migration tooling — same reason as above |
|
|
45
|
+
| `scripts/bassclef-migrate-summary.sh` | 0 | Adopter-facing migration tooling — same reason as above |
|
|
46
|
+
| `presence/install/*.sh` | 0 | Adopter-facing distribution dispatcher + sync + install bootstrap; a defect hits every adopter machine. (Moved from `strategy/templates/` per bassclef-upstream#317 Phase 1a.) |
|
|
47
|
+
| `standards/state-spine/schemas/*.json` | 0 | Schema defects corrupt the state spine universally |
|
|
48
|
+
| `lib/state.sh` | 0 | Accessor library central to all state reads; one defect breaks every consumer |
|
|
49
|
+
| `lib/intent-matcher.sh` | 0 | Intent dispatch — a defect breaks every chain |
|
|
50
|
+
| `scripts/*.sh` | 1 | Other operator-class scripts not listed above; WARN if missing test |
|
|
51
|
+
| `chronicle/*.md` | 3 | Narrative content; operator-read, no test |
|
|
52
|
+
| `docs/iteration-bets/*.md` | 3 | Narrative; operator-read |
|
|
53
|
+
| `docs/decompositions/*.md` | 3 | Narrative; operator-read |
|
|
54
|
+
| `docs/operator-private/journals/*.md` | 3 | Narrative; operator-read |
|
|
55
|
+
|
|
56
|
+
These are bassclef's substrate. Per ADR-031 and Linus's rule that bassclef keeps adopters working — discipline is a contract, not a preference. INSTEAD of letting adopters lower their tier: bassclef holds the discipline for its own substrate. Adopters read this rule; they cannot lower it themselves.
|
|
57
|
+
|
|
58
|
+
Why not adopter-configurable:
|
|
59
|
+
- **Substrate integrity is a contract.** Adopters rely on bassclef's reliability guarantee; lowering bassclef's own tier would undermine the contract while still depending on it.
|
|
60
|
+
- **Hyrum's Law applied to discipline.** Configurable tier means some adopter lowers it; their substrate degrades silently; bassclef's future fixes that assumed the discipline break their setup.
|
|
61
|
+
- **Linus's kernel/userspace boundary.** Linux exposes kernel state as READ surfaces, not WRITE permission over kernel correctness machinery. bassclef's tier discipline is the same shape.
|
|
62
|
+
- **Brooks's conceptual integrity.** Discipline is bassclef's coherent vision; configurability creates per-adopter drift.
|
|
63
|
+
|
|
64
|
+
### Adopter-app path-matchers (configurable per adopter)
|
|
65
|
+
|
|
66
|
+
Adopters edit `testing.path_matchers` in their own `.claude/bassclef-configs.jsonc` for THEIR code:
|
|
67
|
+
|
|
68
|
+
```jsonc
|
|
69
|
+
"testing": {
|
|
70
|
+
"global_floor": 1,
|
|
71
|
+
"path_matchers": [
|
|
72
|
+
{ "match": "src/middleware.ts", "tier": 0 },
|
|
73
|
+
{ "match": "src/lib/auth/**", "tier": 0 },
|
|
74
|
+
{ "match": "src/app/**/route.ts", "tier": 2 },
|
|
75
|
+
{ "match": "src/components/**/*.tsx", "tier": 2 }
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The substrate entry wins when an adopter's `path_matchers` entry matches a substrate path (above). The hook ignores adopter attempts to lower substrate tiers — by design.
|
|
81
|
+
|
|
82
|
+
## Test-file sibling mapping (Tier 0 only)
|
|
83
|
+
|
|
84
|
+
For Tier 0 paths, the hook expects a sibling test file:
|
|
85
|
+
|
|
86
|
+
| Source path | Expected test path |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `.claude/hooks/<name>.sh` | `.claude/hooks/tests/<name>.test.sh` |
|
|
89
|
+
| `standards/state-spine/schemas/<name>.schema.json` | `standards/state-spine/schemas/tests/<name>.test.sh` |
|
|
90
|
+
| `lib/<name>.sh` | `lib/tests/<name>.test.sh` |
|
|
91
|
+
|
|
92
|
+
The hook BLOCKs when the source is edited and the test mtime did not advance. The BLOCK message names three things: the source path, the expected test path, and the mtime gap. INSTEAD of failing silently: the message tells the agent which test file to touch.
|
|
93
|
+
|
|
94
|
+
## Override discipline
|
|
95
|
+
|
|
96
|
+
`SKIP_TESTING_TIER_ENFORCE=1 <command>` bypasses the hook for one command. The bypass is logged via `trace-helper.sh` per bassclef's existing override idiom.
|
|
97
|
+
|
|
98
|
+
Use it sparingly. Three cases warrant the override. One-shot migration scripts that bootstrap state. Emergency rescues when the hook itself is broken. Documentation changes where the agent has clear evidence the source change carries no behavior.
|
|
99
|
+
|
|
100
|
+
INSTEAD of overriding for routine work that fails the check: write the test. The hook fires at the cheapest moment to add one. Deferred test-writing almost never happens.
|
|
101
|
+
|
|
102
|
+
## Allowlist baseline (grace window)
|
|
103
|
+
|
|
104
|
+
`.claude/hooks/testing-tier-enforce-allowlist.txt` lists existing Tier 0 sources that ship without tests as of the hook's land date. Each entry carries a dated grace window. The hook BLOCKs on listed paths in two cases. First — the grace window expires. Second — the source gets edited (new edits during grace still BLOCK). The allowlist covers pre-existing unedited state only.
|
|
105
|
+
|
|
106
|
+
The grace window is set per-adopter at `/onboard-repo` (default 60 days). Operator decides whether to backfill tests for grandfathered hooks or to remove them from the allowlist as they are next touched.
|
|
107
|
+
|
|
108
|
+
INSTEAD of forcing retroactive backfill at hook-land: the grace window covers existing untested bassclef hooks while new edits trigger enforcement. Per-hook backfill happens as those hooks are next touched.
|
|
109
|
+
|
|
110
|
+
## When this rule fires
|
|
111
|
+
|
|
112
|
+
This rule is methodology — it loads in every session via `additionalDirectories`. Agents self-check before writing source files in Tier 0 paths. The `testing-tier-enforce.sh` hook is the mechanical layer (bassclef#1037 WU-3).
|
|
113
|
+
|
|
114
|
+
Together: rule supplies the why; hook fires at the moment of failure.
|
|
115
|
+
|
|
116
|
+
## Composes with
|
|
117
|
+
|
|
118
|
+
- **@luminary kent-beck** — TDD anchor. Beck's red-green-refactor cycle is the discipline this rule does for Tier 0. A test written before source naturally satisfies "test mtime ≤ source mtime" — the test came first.
|
|
119
|
+
- **@luminary john-ousterhout** — Design-judgment anchor. The tier choice IS a design decision. Push every path to Tier 0 and you get shallow modules where tests just mirror source. Push every path to Tier 3 and you get silent regressions. The tier slider applies Ousterhout's "complexity is incremental" — pick the right tier per surface. Do not flatten the answer.
|
|
120
|
+
- `.claude/rules/testing.md` — the existing rule on test content (what makes a good test). This rule does not replace it; it adds the per-path tier decision that testing.md left implicit.
|
|
121
|
+
- `.claude/rules/state-schema-validation.md` — sister mechanical-enforcement rule at the state-spine write surface.
|
|
122
|
+
- `.claude/rules/blocked-items.md` — the BLOCK protocol the hook fires.
|
|
123
|
+
- `.claude/hooks/pre-commit-gate.sh` — the chain the new hook joins.
|
|
124
|
+
- `.claude/hooks/testing-tier-enforce.sh` — the mechanical implementation (bassclef#1037 WU-3).
|
|
125
|
+
- `.claude/bassclef-configs.jsonc` — the adopter-edit surface with inline comments.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
globs: ["**/*.ts", "**/*.tsx", "**/*.test.*", "**/*.spec.*"]
|
|
4
|
+
description: Three-layer test strategy — loads when touching source or test files
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
> **Companion rule (bassclef#1037):** `.claude/rules/testing-tier-config.md` governs WHICH paths require which level of test enforcement (Tier 0 strict TDD / 1 test-with / 2 smoke / 3 manual verify). This rule (testing.md) governs WHAT makes a good test once a tier requires one. The tier-config rule supersedes the honor-system framing implicit in "skip glue code, trivial getters" below — tier choice is now configured per path-matcher in `.claude/bassclef-configs.jsonc`, and the `testing-tier-enforce.sh` hook fires mechanically.
|
|
8
|
+
|
|
9
|
+
Three layers, all required. Skipping shifts cost to production debugging.
|
|
10
|
+
|
|
11
|
+
Layer 1 — Unit (vitest):
|
|
12
|
+
Pure function logic. New pure function = new test, no exceptions.
|
|
13
|
+
Pre-commit WARNs if new source file has no matching test.
|
|
14
|
+
CI BLOCKs on failure.
|
|
15
|
+
|
|
16
|
+
Layer 2 — Integration:
|
|
17
|
+
Pipeline wiring. Real DB + real Redis, mock only external APIs at HTTP level.
|
|
18
|
+
CI BLOCKs on failure.
|
|
19
|
+
|
|
20
|
+
Layer 3 — E2E/Smoke:
|
|
21
|
+
Post-deploy. Curl-based minimum (health, API, auth redirect).
|
|
22
|
+
Playwright for critical user paths when needed.
|
|
23
|
+
|
|
24
|
+
Coverage policy:
|
|
25
|
+
100% branch for safety rules. ≥80% line for business logic.
|
|
26
|
+
Skip glue code, trivial getters, third-party internals, LLM output content.
|
|
27
|
+
|
|
28
|
+
Naming: `test_{what}_{scenario}_{expected_outcome}`
|
|
29
|
+
Fixtures: factories not hardcoded data.
|
|
30
|
+
|
|
31
|
+
Change matrix:
|
|
32
|
+
Pure function → unit. Agent/worker → integration. API route → integration + smoke.
|
|
33
|
+
Schema migration → integration. Middleware/auth → E2E. UI component → smoke.
|
|
34
|
+
|
|
35
|
+
Order:
|
|
36
|
+
For pure functions and non-trivial logic, write the test before or
|
|
37
|
+
alongside the implementation — not after. If you wrote the test after,
|
|
38
|
+
state so in the verify summary so the reviewer can audit for tautology.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: "Plain check: Before I ship a turn estimate to an adopter, I cite a past bet's actuals + write a range + name the shape."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Turn-Estimate Grounding
|
|
7
|
+
|
|
8
|
+
**Plain check:** Before I ship a turn estimate to an adopter, I cite a past bet's actuals + write a range + name the shape. Ungrounded numbers do not ship.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Every turn estimate that lands in adopter-facing prose (goal docs, PR bodies, canvases, ticket bodies) carries three parts:
|
|
13
|
+
|
|
14
|
+
1. **Source** — cite a past bet's closeout actuals with comparable scope shape (WU count, test-heavy vs docs-heavy, defect diagnosis interludes)
|
|
15
|
+
2. **Range not point** — write a range (e.g., "40-80 turns") not a point ("60 turns")
|
|
16
|
+
3. **Plain-language framing** — name the shape driving the number in one sentence
|
|
17
|
+
|
|
18
|
+
Ungrounded turn estimates do not ship to adopter-facing prose. This rule extends the argument shape from `.claude/rules/assert-only-after-verify.md` to numeric claims. It applies at the same reasoning surface — the moment a number gets written down for an adopter to read.
|
|
19
|
+
|
|
20
|
+
## When this rule fires
|
|
21
|
+
|
|
22
|
+
Every time budget estimate, turn count, or effort range that lands in prose an adopter will read:
|
|
23
|
+
|
|
24
|
+
- `docs/iteration-bets/*.md` frontmatter `appetite:` line
|
|
25
|
+
- `docs/iteration-bets/*.md` body when narrative surfaces a number
|
|
26
|
+
- PR body `Test plan` or `Summary` sections when they cite effort
|
|
27
|
+
- `docs/canvases/*.md` sizing sections
|
|
28
|
+
- Ticket body `Estimate` fields (INVEST format uses S/M/L; this rule fires when a turn count appears instead)
|
|
29
|
+
- Chronicle time-budget actuals sections when they cite the filed number
|
|
30
|
+
- Journal drafts when they cite bet actuals for a past bet
|
|
31
|
+
|
|
32
|
+
Does NOT fire on:
|
|
33
|
+
|
|
34
|
+
- **Chronicle body actuals** for a past bet (backward-looking; the number IS the source itself)
|
|
35
|
+
- **Operator-only surfaces** — internal chronicles, private strategy docs, session-timing markers
|
|
36
|
+
- **Runtime numbers** at checkpoint or closeout time — those cite what happened, not what will happen
|
|
37
|
+
|
|
38
|
+
## What the rule requires
|
|
39
|
+
|
|
40
|
+
Before any turn estimate ships to adopter-facing prose:
|
|
41
|
+
|
|
42
|
+
1. **Cite a past bet by path** — one or two bets whose closeout actuals inform this estimate. Format: `bet 2026-07-09c (5 WUs; heavy test setup; ~110 turns actual)`. Path optional but preferred when the calibration goal is recent.
|
|
43
|
+
2. **Write a range** — the range spans enough to cover the estimate's uncertainty. A 40-80 turn range signals the shape is well-understood but has natural variance. A 200-600 turn range signals real uncertainty and prompts the operator to consider splitting the goal.
|
|
44
|
+
3. **Name the shape** — one sentence stating what drives the number. Examples: "documentation-heavy; single-file SKILL edit + rule text," "5 WUs riding a shared fixture; each cure ships end-to-end with 10-15 Tier 0 tests," "test-first Beck TDD with 4 substantive WUs sharing a fixture foundation."
|
|
45
|
+
|
|
46
|
+
## Trivial-fix exception
|
|
47
|
+
|
|
48
|
+
Fix branches and quick-fix PRs may skip the discipline when the change is under 10 lines AND no goal doc time budget line is being authored. Silence about effort is fine on trivial fixes.
|
|
49
|
+
|
|
50
|
+
## Adopter-friendly framing
|
|
51
|
+
|
|
52
|
+
Numbers can be honest AND friendly. Instead of:
|
|
53
|
+
|
|
54
|
+
> "This goal needs 500-700 turns"
|
|
55
|
+
|
|
56
|
+
Prefer:
|
|
57
|
+
|
|
58
|
+
> "This bet groups 5 substantive changes. Past bets of this shape landed around 100-350 turns. The wider top of the range covers defect diagnosis interludes that add 30-50 turns per step when they fire."
|
|
59
|
+
|
|
60
|
+
The friendly version:
|
|
61
|
+
- Cites a past shape ("bets of this shape landed around 100-350")
|
|
62
|
+
- Names the shape driver ("5 substantive changes")
|
|
63
|
+
- Explains the top-of-range variance ("defect diagnosis interludes")
|
|
64
|
+
|
|
65
|
+
## Composes with
|
|
66
|
+
|
|
67
|
+
- `.claude/rules/assert-only-after-verify.md` — parent discipline; this rule extends argument shape to numeric claims
|
|
68
|
+
- `.claude/rules/plain-english-discipline.md` — grade 8 target with grade 10 ceiling; friendly numbers pass the same reading-level test as prose
|
|
69
|
+
- `.claude/rules/pr-body-shape.md` — Test plan and Summary sections that cite effort follow this rule
|
|
70
|
+
- `.claude/rules/pr-title-shape.md` — sister at title surface
|
|
71
|
+
- `.claude/skills/longrun/SKILL.md` Step 1 pre-flight — cites this rule at time budget estimation
|
|
72
|
+
- @luminary stephen-toulmin — argument shape (claim + evidence + why the evidence supports the claim)
|
|
73
|
+
- @luminary karl-popper — falsifiability (grounded estimates check against past actuals; ungrounded ones cannot be checked)
|
|
74
|
+
- Memory `feedback_no_token_estimates.md` — sister at token-estimate surface
|
|
75
|
+
- Memory `feedback_tight_ticket_appetite.md` — calibration for infra tickets
|
|
76
|
+
- Memory `feedback_longrun_appetite_estimates_too_tight.md` — calibration for WU-heavy bets (3-4x off pattern)
|
|
77
|
+
|
|
78
|
+
## Override
|
|
79
|
+
|
|
80
|
+
`SKIP_TURN_ESTIMATE_GROUNDING=1` — logged via trace-helper. Use only when quoting an external number verbatim (e.g., citing a Shape Up appetite from Basecamp's book).
|
|
81
|
+
|
|
82
|
+
INSTEAD of overriding for routine work: cite the past bet. The cost is one sentence; the discipline compounds across every future adopter who reads a goal doc.
|