@thebassclef/lite 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +23 -6
- package/dist/cli.js +23 -6
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lite/.claude/bassclef-configs.jsonc +56 -0
- package/dist/lite/.claude/bassclef-orientation.md +120 -0
- package/dist/lite/.claude/hooks/adr-discipline-check.sh +132 -0
- package/dist/lite/.claude/hooks/atomic-pr-check.sh +169 -0
- package/dist/lite/.claude/hooks/auto-save-idle.sh +51 -0
- package/dist/lite/.claude/hooks/bassclef-sync.sh +51 -13
- package/dist/lite/.claude/hooks/bet-doc-gate.sh +283 -0
- package/dist/lite/.claude/hooks/bug-diagnosis.sh +64 -0
- package/dist/lite/.claude/hooks/destructive-command-guard.sh +136 -0
- package/dist/lite/.claude/hooks/file-rename-discipline-check.sh +147 -0
- package/dist/lite/.claude/hooks/hook-classifier-canary.sh +158 -0
- package/dist/lite/.claude/hooks/kiss-default-check.sh +129 -0
- package/dist/lite/.claude/hooks/multi-tenancy-check.sh +83 -0
- package/dist/lite/.claude/hooks/oo-ad-entry-point-check.sh +216 -0
- package/dist/lite/.claude/hooks/operator-private-path-check.sh +203 -0
- package/dist/lite/.claude/hooks/pattern-annotation-validate.sh +142 -0
- package/dist/lite/.claude/hooks/plain-english-steering.sh +15 -1
- package/dist/lite/.claude/hooks/post-write-trace.sh +66 -0
- package/dist/lite/.claude/hooks/pr-body-scrub-check.sh +446 -0
- package/dist/lite/.claude/hooks/pre-commit-identifier-leak-scrub.sh +137 -0
- package/dist/lite/.claude/hooks/pre-gh-pr-body-scrub.sh +192 -0
- package/dist/lite/.claude/hooks/pre-gh-pr-title-scrub.sh +172 -0
- package/dist/lite/.claude/hooks/role-entry-gate.sh +115 -0
- package/dist/lite/.claude/hooks/save-state.sh +268 -0
- package/dist/lite/.claude/hooks/session-reflection.d/08-settings-drift.sh +8 -1
- package/dist/lite/.claude/hooks/session-reflection.d/10-abrupt-stop-recovery.sh +52 -0
- package/dist/lite/.claude/hooks/session-reflection.d/55-orientation-gate.sh +40 -4
- package/dist/lite/.claude/hooks/session-reflection.d/80-hook-heartbeat-check.sh +12 -5
- package/dist/lite/.claude/hooks/session-reflection.d/81-hook-manifest-staleness.sh +18 -2
- package/dist/lite/.claude/hooks/session-reflection.d/91-npm-version-drift.sh +54 -0
- package/dist/lite/.claude/hooks/session-reflection.d/tests/10-abrupt-stop-recovery.test.sh +95 -0
- package/dist/lite/.claude/hooks/session-reflection.sh +62 -15
- package/dist/lite/.claude/hooks/tool-failure-diagnosis.sh +50 -0
- package/dist/lite/.claude/luminaries/andrej-karpathy.md +165 -0
- package/dist/lite/.claude/luminaries/dave-gray.md +155 -0
- package/dist/lite/.claude/luminaries/gary-klein.md +166 -0
- package/dist/lite/.claude/luminaries/kaoru-ishikawa.md +162 -0
- package/dist/lite/.claude/luminaries/lean-product-canvas.md +33 -0
- package/dist/lite/.claude/luminaries/luke-wroblewski.md +224 -0
- package/dist/lite/.claude/luminaries/ryan-singer.md +113 -0
- package/dist/lite/.claude/luminaries/steve-krug.md +168 -0
- package/dist/lite/.claude/luminaries/tony-ulwick.md +134 -0
- package/dist/lite/.claude/rules/arc-level-orientation-before-leaf.md +60 -0
- package/dist/lite/.claude/rules/architect-review-discipline.md +71 -0
- package/dist/lite/.claude/rules/auto-fix-criteria.md +126 -0
- package/dist/lite/.claude/rules/bassclef-hook-drift-blocker.md +144 -0
- package/dist/lite/.claude/rules/bassclef-models-discovery.md +107 -0
- package/dist/lite/.claude/rules/bassclef-workflow-parity.md +104 -0
- package/dist/lite/.claude/rules/cost-governance.md +154 -0
- package/dist/lite/.claude/rules/file-rename-discipline.md +95 -0
- package/dist/lite/.claude/rules/mechanism-fidelity.md +88 -0
- package/dist/lite/.claude/rules/prototype-production-coupling.md +125 -0
- package/dist/lite/.claude/rules/quick-fix-criteria.md +90 -0
- package/dist/lite/.claude/rules/session-artifacts.md +30 -0
- package/dist/lite/.claude/rules/sibling-smoke-after-substrate-change.md +107 -0
- package/dist/lite/.claude/rules/substrate-as-system.md +67 -0
- package/dist/lite/.claude/rules/usability.md +22 -0
- package/dist/lite/.claude/settings.json +20 -0
- package/dist/lite/.claude/skills/agent-research-spawn/SKILL.md +100 -0
- package/dist/lite/.claude/skills/architect-review/SKILL.md +201 -0
- package/dist/lite/.claude/skills/auto-fix/SKILL.md +297 -0
- package/dist/lite/.claude/skills/autonomous/SKILL.md +300 -0
- package/dist/lite/.claude/skills/bind-subdomain/SKILL.md +232 -0
- package/dist/lite/.claude/skills/canvas/SKILL.md +41 -0
- package/dist/lite/.claude/skills/deploy-prod/SKILL.md +106 -0
- package/dist/lite/.claude/skills/docs-sync/SKILL.md +188 -0
- package/dist/lite/.claude/skills/eisenhower/SKILL.md +273 -0
- package/dist/lite/.claude/skills/empathy-map/SKILL.md +168 -0
- package/dist/lite/.claude/skills/frontend-design/SKILL.md +53 -0
- package/dist/lite/.claude/skills/interview-me/SKILL.md +171 -0
- package/dist/lite/.claude/skills/journal-export/SKILL.md +293 -0
- package/dist/lite/.claude/skills/jtbd-tasks/SKILL.md +203 -0
- package/dist/lite/.claude/skills/objectory-decompose/SKILL.md +256 -0
- package/dist/lite/.claude/skills/pick-luminaries/SKILL.md +100 -0
- package/dist/lite/.claude/skills/pre-mortem/SKILL.md +180 -0
- package/dist/lite/.claude/skills/prototype-gallery/SKILL.md +264 -0
- package/dist/lite/.claude/skills/provision-deploy-host/SKILL.md +257 -0
- package/dist/lite/.claude/skills/quick-fix/SKILL.md +273 -0
- package/dist/lite/.claude/skills/release/SKILL.md +311 -0
- package/dist/lite/.claude/skills/release-notes/SKILL.md +202 -0
- package/dist/lite/.claude/skills/rfc/SKILL.md +222 -0
- package/dist/lite/.claude/skills/riff-prototypes/SKILL.md +637 -0
- package/dist/lite/.claude/skills/secrets-bootstrap/SKILL.md +209 -0
- package/dist/lite/.claude/skills/skill/SKILL.md +304 -0
- package/dist/lite/.claude/skills/smoke-test/SKILL.md +100 -0
- package/dist/lite/.claude/skills/state/SKILL.md +204 -0
- package/dist/lite/.claude/skills/substrate-check/SKILL.md +218 -0
- package/dist/lite/.claude/skills/synthetic-user/SKILL.md +381 -0
- package/dist/lite/.claude/skills/task-scenarios/SKILL.md +105 -0
- package/dist/lite/.claude/skills/tier-dependency-audit/SKILL.md +139 -0
- package/dist/lite/.claude/skills/ux-migration/SKILL.md +424 -0
- package/dist/lite/.claude/skills/value-prop-canvas/SKILL.md +297 -0
- package/dist/lite/README.md +5 -1
- package/dist/lite/gitignore +6 -0
- package/dist/lite/lib/bassclef-dir-resolver.sh +85 -0
- package/dist/lite/lib/clone-failure-classifier.sh +59 -0
- package/dist/lite/lib/fixture-builder.sh +190 -0
- package/dist/lite/lib/fresh-install-check.sh +49 -0
- package/dist/lite/lib/hook-heartbeat.sh +0 -1
- package/dist/lite/lib/mechanism-fidelity.sh +569 -0
- package/dist/lite/lib/npm-version-check.sh +112 -0
- package/dist/lite/lib/preview-state.sh +229 -0
- package/dist/lite/lib/session-rescue.sh +0 -1
- package/dist/lite/scripts/generate-lite-manifest.sh +145 -4
- package/dist/lite/scripts/lite-manifest-drift-check.sh +5 -1
- package/dist/lite/standards/architect-review-discipline.md +222 -0
- package/dist/lite/standards/bassclef-platform.md +249 -0
- package/dist/lite/standards/bassclef-test-repos.md +97 -0
- package/dist/lite/standards/bassclef-wiring-manifest.json +25 -1
- package/dist/lite/standards/cold-adopter-harness.md +205 -0
- package/dist/lite/standards/data-management.md +135 -0
- package/dist/lite/standards/frontend-stack/nextjs-prisma.md +124 -0
- package/dist/lite/standards/lite-manifest-schema-changes.md +27 -0
- package/dist/lite/standards/lite-manifest.json +1456 -14
- package/dist/lite/standards/mechanism-fidelity.md +205 -0
- package/dist/lite/standards/operator-private-discipline.md +200 -0
- package/dist/lite/standards/operator-to-public-flow.md +195 -0
- package/dist/lite/standards/prototype-gallery.md +251 -0
- package/dist/lite/standards/pseudonym-key-schema.md +109 -0
- package/dist/lite/standards/sibling-validation-checklist.md +181 -0
- package/dist/lite/standards/slack-notifications.md +161 -0
- package/dist/lite/standards/synthetic-user-testing.md +173 -0
- package/dist/lite/standards/vendor-bindings.md +165 -0
- package/dist/lite/standards/vendor-plugins/frontend-design.md +66 -0
- package/dist/lite/standards/vpc-fit-validation.md +167 -0
- package/dist/lite/templates/gallery-yml.md +113 -0
- package/dist/lite/templates/product-canvas.md +169 -0
- package/dist/lite/templates/value-prop-canvas.md +180 -0
- package/package.json +3 -3
- /package/dist/lite/{whereami.md → docs/whereami.md} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -318,6 +318,12 @@ const GENERATED_BY = "@thebassclef/lite";
|
|
|
318
318
|
function manifestTemplate(input) {
|
|
319
319
|
const value = {
|
|
320
320
|
schema_version: MANIFEST_SHAPE_VERSION,
|
|
321
|
+
// Top-level `version` — read by the v0.45.0 npm-version-drift hook
|
|
322
|
+
// (fragment 91 under session-reflection) via lib/npm-version-check.sh
|
|
323
|
+
// `jq -r '.version // ""' "$manifest"`. Duplicates
|
|
324
|
+
// $bassclef.generated_by_version on purpose — the hook does not walk
|
|
325
|
+
// into $bassclef. Per bassclef-upstream#1749.
|
|
326
|
+
version: input.pkgVersion,
|
|
321
327
|
$bassclef: {
|
|
322
328
|
template: "init.manifest.json",
|
|
323
329
|
manifest_schema_version: MANIFEST_SCHEMA_VERSION,
|
|
@@ -1076,13 +1082,13 @@ function dispatchSubstrateCopy(targetDir, force, verbose, dryRun, allowRoot, say
|
|
|
1076
1082
|
);
|
|
1077
1083
|
const copiedCount = copiedHookEntries.length;
|
|
1078
1084
|
const declaredCount = result.hookCount;
|
|
1079
|
-
const
|
|
1085
|
+
const erroredCount = result.errored.length;
|
|
1080
1086
|
const userScope = copiedHookEntries.filter((e) => e.scope === "user").length;
|
|
1081
1087
|
const projectScope = copiedHookEntries.filter((e) => e.scope === "project").length;
|
|
1082
1088
|
const scopeSuffix = userScope + projectScope > 0 ? ` ${projectScope} in <repo>/${HOOKS_SUBPATH.replace(/\/$/, "")}, ${userScope} in ~/${HOOKS_SUBPATH.replace(/\/$/, "")}.` : "";
|
|
1083
|
-
if (
|
|
1089
|
+
if (erroredCount > 0) {
|
|
1084
1090
|
say(
|
|
1085
|
-
`bassclef init: Installed ${copiedCount} of ${declaredCount} hooks (${RESOLVED_TIER} tier).${scopeSuffix} ${
|
|
1091
|
+
`bassclef init: Installed ${copiedCount} of ${declaredCount} hooks (${RESOLVED_TIER} tier).${scopeSuffix} ${erroredCount} failed — see errors above. Rerun bassclef init to retry.
|
|
1086
1092
|
`
|
|
1087
1093
|
);
|
|
1088
1094
|
} else {
|
|
@@ -1151,10 +1157,12 @@ function dispatchSubstrateCopy(targetDir, force, verbose, dryRun, allowRoot, say
|
|
|
1151
1157
|
`
|
|
1152
1158
|
);
|
|
1153
1159
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1160
|
+
if (result.refused.length > 0) {
|
|
1161
|
+
say(
|
|
1162
|
+
`bassclef init: ${result.refused.length} files refused (path collision). Use --force to overwrite existing files.
|
|
1156
1163
|
`
|
|
1157
|
-
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1158
1166
|
if (verbose && result.erroredMessages) {
|
|
1159
1167
|
for (const msg of result.erroredMessages) {
|
|
1160
1168
|
process.stderr.write(` substrate: ${msg}
|
|
@@ -2011,6 +2019,12 @@ Proceed?`,
|
|
|
2011
2019
|
const errored = copyResult.errored;
|
|
2012
2020
|
const newManifest = {
|
|
2013
2021
|
schema_version: MANIFEST_SHAPE_VERSION,
|
|
2022
|
+
// Top-level `.version` — read by the v0.45.0 npm-version-drift hook
|
|
2023
|
+
// (fragment 91 under session-reflection) via lib/npm-version-check.sh
|
|
2024
|
+
// `jq -r '.version // ""' "$manifest"`. Duplicates
|
|
2025
|
+
// $bassclef.generated_by_version on purpose — the hook does not walk
|
|
2026
|
+
// into $bassclef. Per bassclef-upstream#1749; bassclef-cli#129.
|
|
2027
|
+
version: index.version,
|
|
2014
2028
|
$bassclef: {
|
|
2015
2029
|
template: "init.manifest.json",
|
|
2016
2030
|
manifest_schema_version: "0.1.0",
|
|
@@ -2178,6 +2192,9 @@ Run \`bassclef migrate --help\` for migrate options + the upgrade paths.
|
|
|
2178
2192
|
Version: ${index.version}
|
|
2179
2193
|
Docs: https://github.com/sunj-labs/bassclef-cli
|
|
2180
2194
|
`;
|
|
2195
|
+
for (const stream of [process.stdout, process.stderr]) {
|
|
2196
|
+
stream._handle?.setBlocking?.(true);
|
|
2197
|
+
}
|
|
2181
2198
|
async function main(argv) {
|
|
2182
2199
|
const first = argv[0];
|
|
2183
2200
|
if (first === void 0 || first === "--help" || first === "-h" || first === "help") {
|
package/dist/cli.js
CHANGED
|
@@ -295,6 +295,12 @@ const GENERATED_BY = "@thebassclef/lite";
|
|
|
295
295
|
function manifestTemplate(input) {
|
|
296
296
|
const value = {
|
|
297
297
|
schema_version: MANIFEST_SHAPE_VERSION,
|
|
298
|
+
// Top-level `version` — read by the v0.45.0 npm-version-drift hook
|
|
299
|
+
// (fragment 91 under session-reflection) via lib/npm-version-check.sh
|
|
300
|
+
// `jq -r '.version // ""' "$manifest"`. Duplicates
|
|
301
|
+
// $bassclef.generated_by_version on purpose — the hook does not walk
|
|
302
|
+
// into $bassclef. Per bassclef-upstream#1749.
|
|
303
|
+
version: input.pkgVersion,
|
|
298
304
|
$bassclef: {
|
|
299
305
|
template: "init.manifest.json",
|
|
300
306
|
manifest_schema_version: MANIFEST_SCHEMA_VERSION,
|
|
@@ -1053,13 +1059,13 @@ function dispatchSubstrateCopy(targetDir, force, verbose, dryRun, allowRoot, say
|
|
|
1053
1059
|
);
|
|
1054
1060
|
const copiedCount = copiedHookEntries.length;
|
|
1055
1061
|
const declaredCount = result.hookCount;
|
|
1056
|
-
const
|
|
1062
|
+
const erroredCount = result.errored.length;
|
|
1057
1063
|
const userScope = copiedHookEntries.filter((e) => e.scope === "user").length;
|
|
1058
1064
|
const projectScope = copiedHookEntries.filter((e) => e.scope === "project").length;
|
|
1059
1065
|
const scopeSuffix = userScope + projectScope > 0 ? ` ${projectScope} in <repo>/${HOOKS_SUBPATH.replace(/\/$/, "")}, ${userScope} in ~/${HOOKS_SUBPATH.replace(/\/$/, "")}.` : "";
|
|
1060
|
-
if (
|
|
1066
|
+
if (erroredCount > 0) {
|
|
1061
1067
|
say(
|
|
1062
|
-
`bassclef init: Installed ${copiedCount} of ${declaredCount} hooks (${RESOLVED_TIER} tier).${scopeSuffix} ${
|
|
1068
|
+
`bassclef init: Installed ${copiedCount} of ${declaredCount} hooks (${RESOLVED_TIER} tier).${scopeSuffix} ${erroredCount} failed — see errors above. Rerun bassclef init to retry.
|
|
1063
1069
|
`
|
|
1064
1070
|
);
|
|
1065
1071
|
} else {
|
|
@@ -1128,10 +1134,12 @@ function dispatchSubstrateCopy(targetDir, force, verbose, dryRun, allowRoot, say
|
|
|
1128
1134
|
`
|
|
1129
1135
|
);
|
|
1130
1136
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1137
|
+
if (result.refused.length > 0) {
|
|
1138
|
+
say(
|
|
1139
|
+
`bassclef init: ${result.refused.length} files refused (path collision). Use --force to overwrite existing files.
|
|
1133
1140
|
`
|
|
1134
|
-
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1135
1143
|
if (verbose && result.erroredMessages) {
|
|
1136
1144
|
for (const msg of result.erroredMessages) {
|
|
1137
1145
|
process.stderr.write(` substrate: ${msg}
|
|
@@ -1988,6 +1996,12 @@ Proceed?`,
|
|
|
1988
1996
|
const errored = copyResult.errored;
|
|
1989
1997
|
const newManifest = {
|
|
1990
1998
|
schema_version: MANIFEST_SHAPE_VERSION,
|
|
1999
|
+
// Top-level `.version` — read by the v0.45.0 npm-version-drift hook
|
|
2000
|
+
// (fragment 91 under session-reflection) via lib/npm-version-check.sh
|
|
2001
|
+
// `jq -r '.version // ""' "$manifest"`. Duplicates
|
|
2002
|
+
// $bassclef.generated_by_version on purpose — the hook does not walk
|
|
2003
|
+
// into $bassclef. Per bassclef-upstream#1749; bassclef-cli#129.
|
|
2004
|
+
version,
|
|
1991
2005
|
$bassclef: {
|
|
1992
2006
|
template: "init.manifest.json",
|
|
1993
2007
|
manifest_schema_version: "0.1.0",
|
|
@@ -2155,6 +2169,9 @@ Run \`bassclef migrate --help\` for migrate options + the upgrade paths.
|
|
|
2155
2169
|
Version: ${version}
|
|
2156
2170
|
Docs: https://github.com/sunj-labs/bassclef-cli
|
|
2157
2171
|
`;
|
|
2172
|
+
for (const stream of [process.stdout, process.stderr]) {
|
|
2173
|
+
stream._handle?.setBlocking?.(true);
|
|
2174
|
+
}
|
|
2158
2175
|
async function main(argv) {
|
|
2159
2176
|
const first = argv[0];
|
|
2160
2177
|
if (first === void 0 || first === "--help" || first === "-h" || first === "help") {
|
package/dist/index.cjs
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version: "1.
|
|
1
|
+
export declare const version: "1.2.0";
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// tier: lite
|
|
2
|
+
// bassclef adopter config — tune substrate rules from one file.
|
|
3
|
+
// Reference schema: standards/bassclef-configs-schema.md
|
|
4
|
+
// Every block below matches what a substrate rule reads. Values shown
|
|
5
|
+
// are the defaults; delete a block and the default kicks in.
|
|
6
|
+
{
|
|
7
|
+
// What your project runs. Frontend framework the /shadcn-first and
|
|
8
|
+
// /new-dependency-check rules key off. Common values: "vite-react",
|
|
9
|
+
// "nextjs", "remix", "vue", "svelte", "none".
|
|
10
|
+
"tech_stack": {
|
|
11
|
+
"frontend": "none"
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
// Prose discipline. The kiss-check Stop hook watches your writing
|
|
15
|
+
// for jargon. Value "true" = advisory (findings to stderr, no block).
|
|
16
|
+
// Value "strict" = BLOCK the stop, forcing a rewrite turn.
|
|
17
|
+
// Value false = disabled.
|
|
18
|
+
"prose_discipline": {
|
|
19
|
+
"kiss_words_turn_prose": true
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
// Where /promote sends proposals. Two shapes:
|
|
23
|
+
// "<owner>/<repo>" — gh issue create --repo <value>
|
|
24
|
+
// "email:<address>" — mailto: URL printed for adopter to send
|
|
25
|
+
// Absent → /promote files in the current repo (backward-compat).
|
|
26
|
+
// "promote_target": "your-org/your-repo",
|
|
27
|
+
|
|
28
|
+
// Testing tiers per .claude/rules/testing-tier-config.md. Global
|
|
29
|
+
// floor sets the baseline for every path that no matcher covers.
|
|
30
|
+
// Tier 0 = strict TDD (test-first, BLOCK on missing). Tier 1 =
|
|
31
|
+
// test-with (WARN on missing). Tier 2 = smoke test only. Tier 3 =
|
|
32
|
+
// manual verify (no test discipline).
|
|
33
|
+
"testing": {
|
|
34
|
+
"global_floor": 1,
|
|
35
|
+
"path_matchers": [
|
|
36
|
+
{ "match": ".claude/rules/*.md", "tier": 3 },
|
|
37
|
+
{ "match": "state/markers/*/*", "tier": 3 },
|
|
38
|
+
{ "match": "chronicle/*.md", "tier": 3 },
|
|
39
|
+
{ "match": "docs/iteration-bets/*.md", "tier": 3 },
|
|
40
|
+
{ "match": "docs/decompositions/*.md", "tier": 3 }
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
// /longrun preset picker per .claude/skills/longrun/SKILL.md. Values:
|
|
45
|
+
// "converged" — plan doc drives; lean prep output
|
|
46
|
+
// "exploratory" — scan-table with no cards until asked
|
|
47
|
+
// "reversible-small" — three-chunk compact for small scope
|
|
48
|
+
// "auto" — picker decides per session signals (default)
|
|
49
|
+
"longrun": {
|
|
50
|
+
"preset": "auto"
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// Adopter defaults surface. Reserved for future rules. Absent =
|
|
54
|
+
// downstream rules keep their own defaults.
|
|
55
|
+
"adopter_defaults": {}
|
|
56
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
purpose: adopter orientation — auto-imported into adopter CLAUDE.md via @.claude/bassclef-orientation.md per ADR-032 + Anthropic @import convention
|
|
4
|
+
last_updated: 2026-06-22
|
|
5
|
+
bet: 2026-06-22b-dispatcher-hardening-rename-orientation (WU-5)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Bassclef orientation
|
|
9
|
+
|
|
10
|
+
You've inherited the bassclef substrate. This file loads into every session via `@import` from your CLAUDE.md.
|
|
11
|
+
|
|
12
|
+
The substrate is a stable set of skills, rules, hooks, luminaries, agents, and standards that pin discipline at decision boundaries. It evolves upstream in `sunj-labs/bassclef-upstream`; you receive releases from public `sunj-labs/bassclef` via `bassclef-sync` at every session start.
|
|
13
|
+
|
|
14
|
+
## What you have
|
|
15
|
+
|
|
16
|
+
| Layer | Where | Discover |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Skills (invocable workflows) | `.claude/skills/<name>/SKILL.md` | `/skills` |
|
|
19
|
+
| Rules (auto-loaded context) | `.claude/rules/*.md` | All loaded every session via `additionalDirectories` |
|
|
20
|
+
| Luminaries (design + authoring lenses) | `.claude/luminaries/*.md` | `/luminary` |
|
|
21
|
+
| Agents (specialist roles) | `.claude/agents/*.md` | Used by `/autonomous`, `/build`, `/longrun` |
|
|
22
|
+
| Hooks (mechanical enforcement) | `.claude/hooks/*.sh` | Fire automatically; see `/hooks` |
|
|
23
|
+
| Standards (reference docs) | `standards/*.md` | Cited by rules + skills |
|
|
24
|
+
| ADRs (architectural decisions) | `architecture/decisions/ADR-*.md` | Read before changing what they govern |
|
|
25
|
+
|
|
26
|
+
## Cross-cutting gates — fire across every phase
|
|
27
|
+
|
|
28
|
+
| Gate | When to run |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `/temperance` | Before first edit on a branch + at scope-decision boundaries |
|
|
31
|
+
| `/diagnose` | Before writing any fix code |
|
|
32
|
+
| `/quick-fix` | Localized, obvious, ≤10 lines, no blast radius |
|
|
33
|
+
| `/auto-fix` | Narrow non-trivial bugs within Builder's safe zone |
|
|
34
|
+
| `/verify` | After each task before committing |
|
|
35
|
+
| `/whats-the-plan` | Before any ≥3-skill chain |
|
|
36
|
+
| `/kiss` | When scope bloats or prose drifts toward jargon |
|
|
37
|
+
| `/luminary` | Before ADR authoring + at any design-decision boundary |
|
|
38
|
+
|
|
39
|
+
## SDLC flow
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Canvas → Spec → Design → Issue → Branch → PR → CI → Deploy → Observe
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For UI work, run the UX translation chain during Design:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
JTBD → HTA → Entity Model → State Diagrams → Sequence Diagrams → /decompose
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Conventions
|
|
52
|
+
|
|
53
|
+
- **Commits**: `type: description` per `.claude/rules/commit-conventions.md`
|
|
54
|
+
- **PR titles**: ≤72 chars per `.claude/rules/pr-title-shape.md`
|
|
55
|
+
- **PR bodies**: open with `**Problem (≤500 chars):**` per `.claude/rules/pr-body-shape.md`
|
|
56
|
+
- **Specs** reference their source canvas or issue
|
|
57
|
+
- **New standards** go in `standards/`, not inline in other docs
|
|
58
|
+
|
|
59
|
+
## What NOT to do
|
|
60
|
+
|
|
61
|
+
- **Don't break adopters** (ADR-031). Every change to a downstream-observable surface ships with a compat shim, migration manifest, and changelog entry.
|
|
62
|
+
- **Don't make architectural or design decisions without consulting luminaries.** Design without a named lens drifts toward generic; the lens is what gives you a position to defend in review.
|
|
63
|
+
- **Don't release without checking prior open PRs first.** Cumulative stacks create cascade failures.
|
|
64
|
+
- **Don't write source before tests** on Tier 0 paths (per `.claude/rules/testing-tier-config.md`).
|
|
65
|
+
- **Don't auto-apply discipline changes without `/temperance`** at scope boundaries.
|
|
66
|
+
- **Don't conflate "propose" with "execute".** When operator says "propose," "options," "path forward" — wait for explicit go signal.
|
|
67
|
+
- **Don't use bassclef-internal jargon** in operator-facing prose. Plain English at grade-10 reading level.
|
|
68
|
+
- **Don't push to main without PR review** even on solo workflows.
|
|
69
|
+
|
|
70
|
+
## Luminaries at design boundaries
|
|
71
|
+
|
|
72
|
+
The substrate ships ~38 luminaries (Linus, Beck, Brooks, Norman, Cooper, Tufte, Nygard, Vernon, Ousterhout, Hyrum, Myers, Hoare, Saltzer-Schroeder, Parnas, Fowler, and more). They pin specific disciplines — they aren't decoration.
|
|
73
|
+
|
|
74
|
+
When to consult:
|
|
75
|
+
|
|
76
|
+
- **Architectural decisions (ADRs)** — pin 1-3 luminaries; the ADR cites their lens
|
|
77
|
+
- **Iteration bets** — declare a luminary map (primary pair + extended pairs per surface in scope) per `.claude/rules/iteration-bet-brief-completeness.md`
|
|
78
|
+
- **UI surfaces** — Norman / Cooper / Tufte / Morville per the surface's job
|
|
79
|
+
- **Cross-cutting design choices** — Bulkhead (Nygard) + Anticorruption Layer (Vernon) + Deep Modules (Ousterhout) converge often
|
|
80
|
+
|
|
81
|
+
`/luminary <slug>` previews one; `/luminary` browses by discipline. Skills with UI / architecture surfaces pin their luminary map in frontmatter — read the skill before invoking.
|
|
82
|
+
|
|
83
|
+
## Luminaries at the keyboard — not just the whiteboard
|
|
84
|
+
|
|
85
|
+
Beyond ADRs and iteration bets, luminaries inform code authoring directly. **Pick ONE dominant lens per scope** (bet / WU / surface) and check your work against it. Background discipline fires automatically — don't manually verify against each.
|
|
86
|
+
|
|
87
|
+
| Scope | Default dominant authoring luminary |
|
|
88
|
+
|---|---|
|
|
89
|
+
| Most code | @luminary kent-beck (TDD rhythm + test list + simple design) |
|
|
90
|
+
| Bash hooks + scripts | @luminary saltzer-schroeder (7 defensive disciplines) |
|
|
91
|
+
| State-spine writes | @luminary tony-hoare (pre/postconditions; contracts) |
|
|
92
|
+
| UI components | Whichever pair the prototype pinned |
|
|
93
|
+
| Architecture refactoring | @luminary john-ousterhout (deep modules) + @luminary martin-fowler (refactoring patterns) |
|
|
94
|
+
|
|
95
|
+
**Background discipline** (fires automatically — don't manually verify):
|
|
96
|
+
|
|
97
|
+
- **Rules cite anchor luminaries** explaining why each rule exists. Read the rule; the anchor tells you when the rule generalizes vs when an edge case applies
|
|
98
|
+
- **Hooks enforce specific luminary-anchored disciplines mechanically** — `testing-tier-enforce.sh` (Beck), `state-validate.sh` (Hoare), `substrate-clarity-gate.sh` (context engineering)
|
|
99
|
+
- **`@pattern <catalog-path>` annotation** in source code when you CONSCIOUSLY instantiate a named pattern (GoF, Fowler, Vernon DDD). Not every class — only the ones that EMBODY a pattern as a design choice. Per `.claude/rules/pattern-annotation.md`
|
|
100
|
+
|
|
101
|
+
## Luminary matching — tier ladder
|
|
102
|
+
|
|
103
|
+
`/pick-luminaries` picks luminary fits for an intent paragraph. Adopter capability scales with what keys you provide:
|
|
104
|
+
|
|
105
|
+
- **lite** — stub / deterministic mode; no keys required; for cold-start adopters + CI + tests
|
|
106
|
+
- **standard** — single LLM call picks from the full catalog; semantic matching; needs `ANTHROPIC_API_KEY` (default in bassclef-core)
|
|
107
|
+
- **ultra** — embedding shortlist (Voyage `voyage-3-lite`) + LLM judge re-rank; faster + per-candidate confidence; needs `ANTHROPIC + VOYAGE` keys; load `bassclef-upstream` via `additionalDirectories` to activate
|
|
108
|
+
|
|
109
|
+
Pre-computed catalog embeddings (~230KB) ship with bassclef-upstream so ultra-tier Voyage cost is per-query intent embedding only.
|
|
110
|
+
|
|
111
|
+
Pick the tier that matches your trust + budget. Upgrade path is additive — no migration required to move lite → standard → ultra. See bassclef-upstream#262 for ultra-tier downstream-readiness status; bassclef-upstream#263 for the future "plus" tier (local embedding model, no Voyage key).
|
|
112
|
+
|
|
113
|
+
## Discovery commands
|
|
114
|
+
|
|
115
|
+
- `/sprint` — what's in flight + what's next
|
|
116
|
+
- `/whereami` — current project state
|
|
117
|
+
- `/substrate-check` — validate substrate wiring
|
|
118
|
+
- `/skills` — phase-grouped skill catalog
|
|
119
|
+
- `/luminary` — design-lens catalog
|
|
120
|
+
- `/hooks` — mechanical-enforcement layer
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# adr-discipline-check.sh — PreToolUse hook on architectural decision boundaries
|
|
4
|
+
#
|
|
5
|
+
# Detects "load-bearing" architectural decisions via path-shape heuristics and
|
|
6
|
+
# refuses unless an ADR marker at state/markers/adr/<decision-slug>.md exists
|
|
7
|
+
# linking to a real ADR file under docs/adrs/ or architecture/decisions/.
|
|
8
|
+
#
|
|
9
|
+
# Per bassclef#1149 + WU-11 of bet 2026-06-20e.
|
|
10
|
+
# Override: SKIP_ADR_CHECK=1 (logged via trace-helper).
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
# ============================================================================
|
|
15
|
+
# Read stdin JSON from Claude Code harness
|
|
16
|
+
# ============================================================================
|
|
17
|
+
PAYLOAD=$(cat 2>/dev/null || echo '{}')
|
|
18
|
+
|
|
19
|
+
TOOL_NAME=$(echo "$PAYLOAD" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
20
|
+
FILE_PATH=$(echo "$PAYLOAD" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
21
|
+
|
|
22
|
+
# ============================================================================
|
|
23
|
+
# Filters: only fire on Write/Edit/MultiEdit
|
|
24
|
+
# ============================================================================
|
|
25
|
+
case "$TOOL_NAME" in
|
|
26
|
+
Write|Edit|MultiEdit) ;;
|
|
27
|
+
*) exit 0 ;;
|
|
28
|
+
esac
|
|
29
|
+
|
|
30
|
+
if [ -z "$FILE_PATH" ]; then
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# ============================================================================
|
|
35
|
+
# Override check
|
|
36
|
+
# ============================================================================
|
|
37
|
+
if [ "${SKIP_ADR_CHECK:-0}" = "1" ]; then
|
|
38
|
+
TRACE_HELPER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/trace-helper.sh"
|
|
39
|
+
if [ -f "$TRACE_HELPER" ]; then
|
|
40
|
+
bash "$TRACE_HELPER" override "adr-discipline-check" "SKIP_ADR_CHECK=1 on $FILE_PATH" 2>/dev/null || true
|
|
41
|
+
fi
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# ============================================================================
|
|
46
|
+
# Architectural-decision detection via path-shape heuristics
|
|
47
|
+
# ============================================================================
|
|
48
|
+
IS_ARCHITECTURAL=0
|
|
49
|
+
DECISION_SLUG=""
|
|
50
|
+
|
|
51
|
+
case "$FILE_PATH" in
|
|
52
|
+
*/prisma/schema.prisma|prisma/schema.prisma)
|
|
53
|
+
IS_ARCHITECTURAL=1
|
|
54
|
+
DECISION_SLUG="schema-change"
|
|
55
|
+
;;
|
|
56
|
+
*/docker-compose*.yml|docker-compose*.yml|*/docker-compose*.yaml|docker-compose*.yaml)
|
|
57
|
+
IS_ARCHITECTURAL=1
|
|
58
|
+
DECISION_SLUG="deployment-topology-change"
|
|
59
|
+
;;
|
|
60
|
+
*/middleware.ts|src/middleware.ts|*/middleware.py|*/middleware.rb)
|
|
61
|
+
IS_ARCHITECTURAL=1
|
|
62
|
+
DECISION_SLUG="middleware-change"
|
|
63
|
+
;;
|
|
64
|
+
*/alembic/versions/*.py|*/db/migrate/*.rb|*/migrations/*.go)
|
|
65
|
+
IS_ARCHITECTURAL=1
|
|
66
|
+
DECISION_SLUG="schema-migration"
|
|
67
|
+
;;
|
|
68
|
+
esac
|
|
69
|
+
|
|
70
|
+
# package.json / pyproject.toml / Gemfile / go.mod / Cargo.toml — only fire on Write (new file or rewrite)
|
|
71
|
+
# Detecting "dependency-add" inside Edit would require diff parsing; deferred to V2
|
|
72
|
+
if [ "$TOOL_NAME" = "Write" ]; then
|
|
73
|
+
case "$FILE_PATH" in
|
|
74
|
+
*/package.json|package.json|*/pyproject.toml|pyproject.toml|*/Gemfile|Gemfile|*/go.mod|go.mod|*/Cargo.toml|Cargo.toml)
|
|
75
|
+
IS_ARCHITECTURAL=1
|
|
76
|
+
DECISION_SLUG="dependency-manifest-change"
|
|
77
|
+
;;
|
|
78
|
+
esac
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [ "$IS_ARCHITECTURAL" -eq 0 ]; then
|
|
82
|
+
exit 0
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# ============================================================================
|
|
86
|
+
# Marker check: state/markers/adr/<decision-slug>.md must exist
|
|
87
|
+
# ============================================================================
|
|
88
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
89
|
+
MARKER_DIR="$REPO_ROOT/state/markers/adr"
|
|
90
|
+
|
|
91
|
+
# Explicit marker required — generic "recent ADR in dir" is too permissive
|
|
92
|
+
# (other ADRs unrelated to this decision class would silently satisfy)
|
|
93
|
+
if find "$MARKER_DIR" -maxdepth 1 -name "${DECISION_SLUG}*.md" 2>/dev/null | grep -q .; then
|
|
94
|
+
exit 0
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# ============================================================================
|
|
98
|
+
# Block: no marker + no recent ADR
|
|
99
|
+
# ============================================================================
|
|
100
|
+
cat >&2 <<EOF
|
|
101
|
+
🛑 adr-discipline-check — BLOCK (bassclef#1149)
|
|
102
|
+
|
|
103
|
+
You're about to make a load-bearing architectural decision: ${DECISION_SLUG}
|
|
104
|
+
|
|
105
|
+
Path: ${FILE_PATH}
|
|
106
|
+
|
|
107
|
+
Architectural decisions require an ADR (Architecture Decision Record)
|
|
108
|
+
per Michael Nygard's lifecycle: proposed → accepted → deprecated → superseded.
|
|
109
|
+
|
|
110
|
+
Write one before proceeding:
|
|
111
|
+
|
|
112
|
+
1. Copy the template:
|
|
113
|
+
cp standards/adr-template.md docs/adrs/ADR-NNN-<slug>.md
|
|
114
|
+
(or architecture/decisions/ADR-NNN-<slug>.md per your project layout)
|
|
115
|
+
|
|
116
|
+
2. Fill Context + Decision + Status + Consequences sections.
|
|
117
|
+
|
|
118
|
+
3. Touch the marker:
|
|
119
|
+
mkdir -p ${MARKER_DIR}
|
|
120
|
+
touch ${MARKER_DIR}/${DECISION_SLUG}-<your-slug>.md
|
|
121
|
+
|
|
122
|
+
4. Retry the original change.
|
|
123
|
+
|
|
124
|
+
Override (logged): SKIP_ADR_CHECK=1 <command>
|
|
125
|
+
|
|
126
|
+
When to use override:
|
|
127
|
+
- Trivial revert of a previously-decided architectural change
|
|
128
|
+
- Emergency rescue when the hook itself misclassifies
|
|
129
|
+
- One-shot migration script that touches many architectural files
|
|
130
|
+
EOF
|
|
131
|
+
|
|
132
|
+
exit 2
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# tier: lite
|
|
3
|
+
# Atomic-PR Check — fires on Bash tool calls matching "git push" patterns.
|
|
4
|
+
# Counts distinct WU-N tags in commit messages on the branch. BLOCKs the
|
|
5
|
+
# push if multiple step tags exist unless an iteration goal declares
|
|
6
|
+
# `bundle: true` in frontmatter.
|
|
7
|
+
#
|
|
8
|
+
# Phase II of 8-phase staircase: Trim the Fat (bassclef#382).
|
|
9
|
+
# The methodology rule at .claude/rules/pr-strategy.md is the reasoning;
|
|
10
|
+
# this hook is the mechanical enforcement.
|
|
11
|
+
#
|
|
12
|
+
# Exit codes:
|
|
13
|
+
# 0 — allow (no WU tags, single WU tag, bundle:true in matching bet,
|
|
14
|
+
# or override)
|
|
15
|
+
# 2 — block (multi-step branch without bundle:true)
|
|
16
|
+
#
|
|
17
|
+
# Override: SKIP_ATOMIC_PR_CHECK=1 to bypass (logged via trace-helper)
|
|
18
|
+
#
|
|
19
|
+
# Rule: .claude/rules/pr-strategy.md
|
|
20
|
+
# Issue: bassclef#382
|
|
21
|
+
|
|
22
|
+
set +e # never crash the tool call; fall through to allow on any unexpected error
|
|
23
|
+
|
|
24
|
+
INPUT=$(cat)
|
|
25
|
+
TOOL_NAME=$(jq <<< "$INPUT" -r '.tool_name // ""' 2>/dev/null)
|
|
26
|
+
COMMAND=$(jq <<< "$INPUT" -r '.tool_input.command // ""' 2>/dev/null)
|
|
27
|
+
|
|
28
|
+
# Only fire on Bash with a git push command
|
|
29
|
+
if [ "$TOOL_NAME" != "Bash" ]; then
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Match git push patterns (allow flags like -u, --force, etc.)
|
|
34
|
+
case "$COMMAND" in
|
|
35
|
+
*"git push"*)
|
|
36
|
+
: # match — continue
|
|
37
|
+
;;
|
|
38
|
+
*)
|
|
39
|
+
exit 0
|
|
40
|
+
;;
|
|
41
|
+
esac
|
|
42
|
+
|
|
43
|
+
# Override hatch — log and allow
|
|
44
|
+
if [ "${SKIP_ATOMIC_PR_CHECK:-0}" = "1" ]; then
|
|
45
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd)"
|
|
46
|
+
if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/trace-helper.sh" ]; then
|
|
47
|
+
source "$SCRIPT_DIR/trace-helper.sh" 2>/dev/null || true
|
|
48
|
+
trace_log "atomic-pr-check" "OVERRIDE git push" 2>/dev/null || true
|
|
49
|
+
fi
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Find the repo root
|
|
54
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
55
|
+
if [ -z "$REPO_ROOT" ]; then
|
|
56
|
+
exit 0 # not in a git repo — allow
|
|
57
|
+
fi
|
|
58
|
+
cd "$REPO_ROOT" || exit 0
|
|
59
|
+
|
|
60
|
+
# Get current branch name
|
|
61
|
+
BRANCH=$(git branch --show-current 2>/dev/null)
|
|
62
|
+
if [ -z "$BRANCH" ]; then
|
|
63
|
+
exit 0 # detached HEAD or no branch — allow
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Skip the check on main branch and bare branch names
|
|
67
|
+
case "$BRANCH" in
|
|
68
|
+
main|master|HEAD)
|
|
69
|
+
exit 0
|
|
70
|
+
;;
|
|
71
|
+
esac
|
|
72
|
+
|
|
73
|
+
# Find commits on this branch not yet on main
|
|
74
|
+
# If main is not available locally, fall back to origin/main, then to all commits
|
|
75
|
+
BASE_REF=""
|
|
76
|
+
if git rev-parse --verify main >/dev/null 2>&1; then
|
|
77
|
+
BASE_REF="main"
|
|
78
|
+
elif git rev-parse --verify origin/main >/dev/null 2>&1; then
|
|
79
|
+
BASE_REF="origin/main"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [ -n "$BASE_REF" ]; then
|
|
83
|
+
COMMITS=$(git log --format="%s%n%b" "${BASE_REF}..HEAD" 2>/dev/null)
|
|
84
|
+
else
|
|
85
|
+
# No base ref available — check the last 10 commits as a heuristic
|
|
86
|
+
COMMITS=$(git log -10 --format="%s%n%b" HEAD 2>/dev/null)
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Extract distinct WU-N tags from commit messages
|
|
90
|
+
# Match patterns: "WU-1", "WU-2a", "WU-3", etc. (case-sensitive; expects WU-)
|
|
91
|
+
WU_TAGS=$(echo "$COMMITS" | grep -oE '\bWU-[0-9]+[a-z]?\b' | sort -u)
|
|
92
|
+
|
|
93
|
+
# Count distinct WU tags. If WU_TAGS is empty, count is 0.
|
|
94
|
+
if [ -z "$WU_TAGS" ]; then
|
|
95
|
+
WU_COUNT=0
|
|
96
|
+
else
|
|
97
|
+
WU_COUNT=$(echo "$WU_TAGS" | wc -l | tr -d ' ')
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# 0 or 1 WU tags — allow
|
|
101
|
+
if [ "$WU_COUNT" -le 1 ]; then
|
|
102
|
+
exit 0
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# Multi-WU branch — check for bundle:true in any matching goal doc
|
|
106
|
+
ALLOWED=0
|
|
107
|
+
ITERATION_BETS_DIR="docs/iteration-bets"
|
|
108
|
+
if [ -d "$ITERATION_BETS_DIR" ]; then
|
|
109
|
+
# Look for goal docs that mention any of the step tags AND have bundle: true
|
|
110
|
+
for bet in "$ITERATION_BETS_DIR"/*.md; do
|
|
111
|
+
[ -f "$bet" ] || continue
|
|
112
|
+
# Check if bet has bundle: true in frontmatter
|
|
113
|
+
if awk '/^---$/{c++; next} c==1 && /^bundle:[[:space:]]*true/{print "yes"; exit}' "$bet" | grep -q "yes"; then
|
|
114
|
+
# Verify this goal covers at least one of the step tags
|
|
115
|
+
for wu in $WU_TAGS; do
|
|
116
|
+
if grep -qE "\\b${wu}\\b" "$bet"; then
|
|
117
|
+
ALLOWED=1
|
|
118
|
+
break 2
|
|
119
|
+
fi
|
|
120
|
+
done
|
|
121
|
+
fi
|
|
122
|
+
done
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
if [ "$ALLOWED" = "1" ]; then
|
|
126
|
+
exit 0
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
# BLOCK — multi-step branch without bundle:true
|
|
130
|
+
WU_LIST=$(echo "$WU_TAGS" | tr '\n' ' ' | sed 's/ $//')
|
|
131
|
+
|
|
132
|
+
cat >&2 <<EOF
|
|
133
|
+
|
|
134
|
+
============================================
|
|
135
|
+
🛑 ATOMIC-PR GATE — BLOCKED 🛑
|
|
136
|
+
============================================
|
|
137
|
+
|
|
138
|
+
Branch: $BRANCH
|
|
139
|
+
Commits found tagged with multiple steps: $WU_LIST
|
|
140
|
+
|
|
141
|
+
Per .claude/rules/pr-strategy.md, the default is one step per branch
|
|
142
|
+
per PR (atomic). Multiple WUs in one branch defeats the rollback
|
|
143
|
+
discipline — reverting one step also reverts the others.
|
|
144
|
+
|
|
145
|
+
Three resolution paths:
|
|
146
|
+
|
|
147
|
+
1. Split — create a separate branch per step and a PR for each.
|
|
148
|
+
Operator merges in dependency order.
|
|
149
|
+
|
|
150
|
+
2. Bundle — if these WUs genuinely belong together (single concern,
|
|
151
|
+
tight coupling, emergency hotfix), declare it explicitly:
|
|
152
|
+
add 'bundle: true' to the iteration goal's frontmatter, then push.
|
|
153
|
+
|
|
154
|
+
3. Override (rare) — SKIP_ATOMIC_PR_CHECK=1 git push ...
|
|
155
|
+
Logged to trace. Use only for genuine bypass cases.
|
|
156
|
+
|
|
157
|
+
Per pr-strategy.md the bundle option requires one of:
|
|
158
|
+
- Single logical concern across files (changes don't compile if split)
|
|
159
|
+
- Tight coupling that breaks atomic /verify
|
|
160
|
+
- Emergency hotfix
|
|
161
|
+
- Explicit operator request
|
|
162
|
+
|
|
163
|
+
Rule: .claude/rules/pr-strategy.md
|
|
164
|
+
Issue: bassclef#382
|
|
165
|
+
============================================
|
|
166
|
+
|
|
167
|
+
EOF
|
|
168
|
+
|
|
169
|
+
exit 2
|