@thebassclef/lite 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +1 -1
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/lite/.bassclef-source.json +2 -2
  6. package/dist/lite/.claude/hooks/_lib/wirings.sh +237 -0
  7. package/dist/lite/.claude/hooks/pre-commit-manifest-autoregen.sh +212 -0
  8. package/dist/lite/.claude/hooks/session-reflection.d/08-settings-drift.sh +66 -6
  9. package/dist/lite/.claude/hooks/session-reflection.d/20-artifact-staleness.sh +25 -5
  10. package/dist/lite/.claude/hooks/session-reflection.d/30-metrics-staleness.sh +11 -0
  11. package/dist/lite/.claude/hooks/session-reflection.d/60-deferred-actions.sh +2 -1
  12. package/dist/lite/.claude/hooks/session-reflection.d/80-hook-heartbeat-check.sh +20 -0
  13. package/dist/lite/.claude/hooks/session-reflection.d/tests/20-artifact-staleness.test.sh +89 -0
  14. package/dist/lite/.claude/hooks/session-reflection.sh +12 -1
  15. package/dist/lite/.claude/luminaries/david-farley.md +115 -0
  16. package/dist/lite/.claude/luminaries/jez-humble.md +124 -0
  17. package/dist/lite/.claude/luminaries/martin-fowler.md +18 -0
  18. package/dist/lite/.claude/skills/longrun/SKILL.md +51 -0
  19. package/dist/lite/.claude/skills/onboard-repo/SKILL.md +39 -11
  20. package/dist/lite/.claude/skills/provision-deploy-host/SKILL.md +2 -2
  21. package/dist/lite/lib/ancestor-claude-check.sh +101 -0
  22. package/dist/lite/lib/fixture-builder.sh +324 -0
  23. package/dist/lite/lib/mechanism-fidelity.sh +14 -0
  24. package/dist/lite/lib/workflow-metrics.sh +166 -0
  25. package/dist/lite/presence/install/bassclef-configs.template.jsonc +76 -0
  26. package/dist/lite/presence/install/bassclef-sync.template.sh +7 -4
  27. package/dist/lite/scripts/generate-lite-manifest.sh +151 -1
  28. package/dist/lite/scripts/workflow-metrics-query.sh +57 -0
  29. package/dist/lite/standards/lite-manifest-schema-changes.md +24 -0
  30. package/dist/lite/standards/lite-manifest.json +82 -71
  31. package/dist/lite/standards/mechanism-fidelity.md +1 -0
  32. package/dist/lite/standards/substrate-config-schema.md +2 -2
  33. package/package.json +1 -1
  34. package/dist/lite/.claude/skills/journal-export/SKILL.md +0 -293
  35. package/dist/lite/.claude/skills/release/SKILL.md +0 -311
@@ -0,0 +1,76 @@
1
+ { "tier": "lite",
2
+ // Adopter-facing default for `.claude/bassclef-configs.jsonc`.
3
+ // Ships via lite manifest per bassclef-cli#104. `bassclef init` copies this
4
+ // file to `.claude/bassclef-configs.jsonc` on first-run. Adopters edit it
5
+ // to tune per-repo behavior.
6
+ //
7
+ // Full field catalog + validation: standards/state-spine/schemas/bassclef-configs.schema.json
8
+ // Field reference doc: standards/bassclef-configs-schema.md
9
+ //
10
+ // Every field below is optional. Absent fields fall back to substrate defaults.
11
+ // ----- tech stack -----
12
+ // Declares your primary framework so per-stack skills (SDLC gates,
13
+ // dependency check, migration discipline) load the right sibling docs.
14
+ // Common values: "nextjs", "vite-react", "remix", "fastapi", "rails",
15
+ // "express", "go-http", or omit for framework-agnostic.
16
+ //
17
+ // "tech_stack": {
18
+ // "frontend": "nextjs",
19
+ // "pkg_manager": "pnpm",
20
+ // "orm": "prisma",
21
+ // "lang": "typescript"
22
+ // },
23
+
24
+ // ----- prose discipline -----
25
+ // Controls the /kiss words Stop hook. Values:
26
+ // true — advisory (default; findings to stderr, session continues)
27
+ // "strict" — blocks the stop on jargon findings, forces a rewrite turn
28
+ // false — disabled
29
+ //
30
+ // "prose_discipline": {
31
+ // "kiss_words_turn_prose": true
32
+ // },
33
+
34
+ // ----- testing tier per path -----
35
+ // Extends .claude/rules/testing-tier-config.md with per-repo path matchers.
36
+ // Tier 0 = strict TDD (test mtime <= source mtime, BLOCK at pre-commit)
37
+ // Tier 1 = test-with (WARN at pre-commit if new source has no matching test)
38
+ // Tier 2 = smoke (advisory)
39
+ // Tier 3 = manual verify (silent)
40
+ //
41
+ // "testing": {
42
+ // "global_floor": 1,
43
+ // "path_matchers": [
44
+ // { "match": "src/middleware.ts", "tier": 0 },
45
+ // { "match": "src/lib/auth/**", "tier": 0 },
46
+ // { "match": "src/app/**", "tier": 2 }
47
+ // ]
48
+ // },
49
+
50
+ // ----- /promote target -----
51
+ // Where /promote sends substrate proposals. Two shapes:
52
+ // "<owner>/<repo>" — gh issue create --repo <value>
53
+ // "email:<address>" — mailto: URL printed for you to send
54
+ // Absent — /promote falls back to current-repo filing.
55
+ //
56
+ // "promote_target": "your-org/your-substrate-fork",
57
+
58
+ // ----- longrun orchestrator merge mode -----
59
+ // Controls how /longrun handles PR merges within its bet scope.
60
+ // "operator-gated" — every PR pauses for your review (default)
61
+ // "agent-merges-within-scope" — orchestrator merges autonomously within
62
+ // bet scope; hard_ceilings stay blocking
63
+ //
64
+ // "longrun": {
65
+ // "orchestrator_merge": {
66
+ // "mode": "operator-gated",
67
+ // "hard_ceilings": ["auth", "schema", "security", "prod-deploy", "blast-radius-floor"]
68
+ // }
69
+ // },
70
+
71
+ // ----- adopter defaults -----
72
+ // Per-adopter tunings. See standards/bassclef-configs-schema.md
73
+ // for the full field list.
74
+ //
75
+ // "adopter_defaults": {}
76
+ }
@@ -2178,10 +2178,13 @@ echo ""
2178
2178
  # === 6. Boot check — only report what's missing ===
2179
2179
  MISSING=""
2180
2180
 
2181
- # Google service account (needed for LinkedIn → Google Docs)
2182
- SA_KEY="$HOME/.config/gcloud/sunjay-google-ops.json"
2183
- if [ ! -f "$SA_KEY" ]; then
2184
- MISSING="${MISSING}\n- Google Docs service account key missing at $SA_KEY (needed for /journal Google Doc push)"
2181
+ # Google service account (needed for journal → Google Docs)
2182
+ # Ship 1 (#1816): env var lookup; unset = feature disabled.
2183
+ # Operator sets BASSCLEF_GCLOUD_KEY in their shell profile pointing at their
2184
+ # service-account JSON. Adopters without a Google Docs pipeline leave it unset.
2185
+ SA_KEY="${BASSCLEF_GCLOUD_KEY:-}"
2186
+ if [ -n "$SA_KEY" ] && [ ! -f "$SA_KEY" ]; then
2187
+ MISSING="${MISSING}\n- Google Docs service account key missing at \$BASSCLEF_GCLOUD_KEY (needed for /journal → Google Doc push)"
2185
2188
  fi
2186
2189
 
2187
2190
  # gh CLI auth (needed for /promote, issue creation)
@@ -30,7 +30,11 @@
30
30
 
31
31
  set -euo pipefail
32
32
 
33
- MANIFEST_VERSION="1.8.2"
33
+ # Bug 2 fix (#1829): MANIFEST_VERSION was hardcoded here; dry-run always
34
+ # emitted the compile-time value regardless of on-disk manifest state,
35
+ # so the pre-commit auto-regen hook saw phantom version drift on every
36
+ # commit and bumped needlessly. Now resolved dynamically from the on-disk
37
+ # manifest AFTER OUTPUT_PATH is set (see below).
34
38
 
35
39
  # --- arg parse ---
36
40
  DRY_RUN=0
@@ -94,6 +98,16 @@ if [[ -z "$OUTPUT_PATH" ]]; then
94
98
  OUTPUT_PATH="${REPO_ROOT}/${TARGET_TIER}-manifest.json"
95
99
  fi
96
100
 
101
+ # --- resolve MANIFEST_VERSION dynamically (Bug 2 fix per #1829) ---
102
+ # Read from on-disk manifest so dry-run + write emit the SAME version.
103
+ # Callers that need to bump the version (pre-commit auto-regen hook)
104
+ # apply the bump AFTER regen via jq. Default 0.0.0 when no manifest exists.
105
+ if [[ -f "$OUTPUT_PATH" ]]; then
106
+ MANIFEST_VERSION=$(jq -r '.manifest_version // "0.0.0"' "$OUTPUT_PATH" 2>/dev/null || echo "0.0.0")
107
+ else
108
+ MANIFEST_VERSION="0.0.0"
109
+ fi
110
+
97
111
  # --- generation metadata ---
98
112
  GENERATED_AT="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
99
113
  UPSTREAM_COMMIT="$(cd "$REPO_ROOT" && git rev-parse HEAD 2>/dev/null || echo '0000000000000000000000000000000000000000')"
@@ -140,6 +154,49 @@ count_hook_tier_declarations() {
140
154
  || true
141
155
  }
142
156
 
157
+ # Extract install-class from bash hook file # install-class: header.
158
+ # Ship 1 (#1825): the install-class boundary Gate B reads this per hook
159
+ # to filter operator-scope files from adopter bundles. Values per
160
+ # standards/hook-install-class.md — operator | project | dual.
161
+ # Missing header — grace-window default is "dual" per docs/risk-ledgers/
162
+ # 2026-09-20-ship-1-install-class-boundary.md pre-mortem N2.
163
+ extract_hook_install_class() {
164
+ local val
165
+ val=$(grep -m1 -E '^#[[:space:]]*install-class:[[:space:]]' "$1" 2>/dev/null \
166
+ | sed -E 's/^#[[:space:]]*install-class:[[:space:]]*//' \
167
+ | sed -E 's/[[:space:]]*$//' \
168
+ || true)
169
+ # Grace-window default per pre-mortem N2 fold — missing header treated as dual.
170
+ echo "${val:-dual}"
171
+ }
172
+
173
+ # Gate B — install-class admission check.
174
+ # Returns 0 (admit) when the file belongs in the current TARGET_TIER's bundle
175
+ # based on install-class alone. Returns 1 (reject) when operator-scope in an
176
+ # adopter target. Ship 1 (#1825, #1827, #1828) closes the boundary here.
177
+ check_install_class_admission() {
178
+ local install_class="$1"
179
+ local surface_type="$2"
180
+ # Only enforce on hook + script + presence-template + lib surfaces —
181
+ # skill + rule + luminary + agent + standard + adr do not carry
182
+ # install-class semantics (they are content, not wiring).
183
+ case "$surface_type" in
184
+ hook|script|lib|presence-template) ;;
185
+ *) return 0 ;;
186
+ esac
187
+ # Operator-class always excluded from adopter bundles.
188
+ # Ship 1 grace window (through 2026-10-31 per ADR-031) — allow override
189
+ # for legacy files during rollout via SKIP_INSTALL_CLASS_FILTER.
190
+ if [ "${SKIP_INSTALL_CLASS_FILTER:-0}" = "1" ]; then
191
+ return 0
192
+ fi
193
+ case "$install_class" in
194
+ operator) return 1 ;;
195
+ project|dual) return 0 ;;
196
+ *) return 0 ;;
197
+ esac
198
+ }
199
+
143
200
  # Normalize `—` YAML escape to literal em-dash character. Closes
144
201
  # bassclef-upstream#1548 — YAML frontmatter with double-quoted strings can
145
202
  # carry `—` as a 6-char literal; jq preserves it as `\\u2014` in JSON
@@ -313,6 +370,21 @@ emit_entries() {
313
370
  *) continue ;;
314
371
  esac
315
372
 
373
+ # Ship 1 (#1825) Gate B — install-class filter.
374
+ # Excludes operator-scope files from adopter bundles.
375
+ # Only fires on wiring-carrying surface types (hook, script, lib,
376
+ # presence-template). Content surfaces (skill, rule, luminary, agent,
377
+ # standard, adr) pass through.
378
+ case "$surface_type" in
379
+ hook|script|lib|presence-template)
380
+ local install_class
381
+ install_class=$(extract_hook_install_class "$f" || echo "dual")
382
+ if ! check_install_class_admission "$install_class" "$surface_type"; then
383
+ continue
384
+ fi
385
+ ;;
386
+ esac
387
+
316
388
  case "$slug_from" in
317
389
  dirname)
318
390
  slug=$(basename "$(dirname "$f")")
@@ -441,6 +513,13 @@ while IFS= read -r f; do
441
513
  PRESENCE_TEMPLATE_MD_FILES+=("$f")
442
514
  done < <(find "$REPO_ROOT/presence/install" -maxdepth 1 -type f -name '*.md' 2>/dev/null | sort)
443
515
 
516
+ # Presence templates (jsonc) — Ship 1 (bassclef-cli#104) — configs template
517
+ # ships so `bassclef init` can copy it to adopter's `.claude/bassclef-configs.jsonc`.
518
+ PRESENCE_TEMPLATE_JSONC_FILES=()
519
+ while IFS= read -r f; do
520
+ PRESENCE_TEMPLATE_JSONC_FILES+=("$f")
521
+ done < <(find "$REPO_ROOT/presence/install" -maxdepth 1 -type f -name '*.jsonc' 2>/dev/null | sort)
522
+
444
523
  # Templates (md) — per #1392 Shape 3; chronicle-template + iteration-goal etc adopters copy
445
524
  TEMPLATE_FILES=()
446
525
  while IFS= read -r f; do
@@ -556,6 +635,9 @@ ENTRIES_JSON=$(
556
635
  if [[ ${#PRESENCE_TEMPLATE_MD_FILES[@]} -gt 0 ]]; then
557
636
  emit_entries "presence-template" extract_yaml_tier extract_yaml_description basename "${PRESENCE_TEMPLATE_MD_FILES[@]}"
558
637
  fi
638
+ if [[ ${#PRESENCE_TEMPLATE_JSONC_FILES[@]} -gt 0 ]]; then
639
+ emit_entries "presence-template" extract_json_tier extract_json_description basename "${PRESENCE_TEMPLATE_JSONC_FILES[@]}"
640
+ fi
559
641
  if [[ ${#TEMPLATE_FILES[@]} -gt 0 ]]; then
560
642
  emit_entries "template" extract_yaml_tier extract_yaml_description basename "${TEMPLATE_FILES[@]}"
561
643
  fi
@@ -644,3 +726,71 @@ else
644
726
  echo "$MANIFEST_JSON" > "$OUTPUT_PATH"
645
727
  echo "Wrote $OUTPUT_PATH ($ENTRY_COUNT entries; commit ${UPSTREAM_COMMIT:0:7})" >&2
646
728
  fi
729
+
730
+ # =============================================================
731
+ # Ship 1 (#1827) — Gate C: wiring/file symmetry check
732
+ # =============================================================
733
+ # Post-emit — cross-reference hooks wired in the adopter settings template
734
+ # against hooks emitted in the manifest. Any wiring entry without a
735
+ # matching file entry is a "dead-wired hook" (per #1827). Emits WARNING
736
+ # in V1 (ADVISORY per ADR-031 grace window); flips to BLOCK in V2 after
737
+ # one calibration cycle.
738
+ #
739
+ # Per @luminary linus-torvalds — adopter contract at the boundary.
740
+ # Per @luminary saltzer-schroeder — complete mediation.
741
+ # Per @luminary michael-nygard — stability pattern (fail-visible not fail-silent).
742
+ #
743
+ # Only fires for TARGET_TIER=lite. Other tiers have their own settings templates
744
+ # tracked in follow-on work. Skips when settings template absent (adopter has
745
+ # not published it yet — early Ship 1 dev state).
746
+ if [ "$TARGET_TIER" = "lite" ] && [ "${SKIP_MANIFEST_SYMMETRY:-0}" != "1" ]; then
747
+ SETTINGS_TEMPLATE="$REPO_ROOT/presence/install/public-bassclef-settings.template.json"
748
+ ALLOWLIST="$REPO_ROOT/scripts/generate-lite-manifest-symmetry-allowlist.txt"
749
+ if [ -f "$SETTINGS_TEMPLATE" ] && command -v jq >/dev/null 2>&1; then
750
+ # Extract hook basenames wired in settings template.
751
+ WIRED_TMP=$(mktemp -t bassclef-wired.XXXXXX)
752
+ MANIFEST_HOOKS_TMP=$(mktemp -t bassclef-manifest-hooks.XXXXXX)
753
+ ALLOWLIST_TMP=$(mktemp -t bassclef-allowlist.XXXXXX)
754
+ trap 'rm -f "$WIRED_TMP" "$MANIFEST_HOOKS_TMP" "$ALLOWLIST_TMP"' EXIT
755
+
756
+ jq -r '.hooks | to_entries[] | .value[] | .hooks[] | .command' "$SETTINGS_TEMPLATE" 2>/dev/null \
757
+ | grep -oE '[a-zA-Z0-9_-]+\.sh' | sort -u > "$WIRED_TMP"
758
+
759
+ # Extract hook slugs from the manifest we just emitted.
760
+ if [[ "$DRY_RUN" == "1" ]]; then
761
+ echo "$MANIFEST_JSON" | jq -r '.entries[] | select(.type=="hook") | .slug + ".sh"' 2>/dev/null | sort -u > "$MANIFEST_HOOKS_TMP"
762
+ else
763
+ jq -r '.entries[] | select(.type=="hook") | .slug + ".sh"' "$OUTPUT_PATH" 2>/dev/null | sort -u > "$MANIFEST_HOOKS_TMP"
764
+ fi
765
+
766
+ # Load allowlist (empty file OK — grep -v exits 1 when all lines match; guard for set -e).
767
+ if [ -f "$ALLOWLIST" ]; then
768
+ grep -vE '^\s*#|^\s*$' "$ALLOWLIST" 2>/dev/null > "$ALLOWLIST_TMP" || : > "$ALLOWLIST_TMP"
769
+ sort -u "$ALLOWLIST_TMP" -o "$ALLOWLIST_TMP" 2>/dev/null || true
770
+ else
771
+ : > "$ALLOWLIST_TMP"
772
+ fi
773
+
774
+ # Wired minus manifest, minus allowlist.
775
+ DEAD_WIRED=$(comm -23 "$WIRED_TMP" "$MANIFEST_HOOKS_TMP" | comm -23 - "$ALLOWLIST_TMP" || true)
776
+ if [ -z "$DEAD_WIRED" ]; then
777
+ DEAD_COUNT=0
778
+ else
779
+ DEAD_COUNT=$(echo "$DEAD_WIRED" | wc -l | tr -d ' ')
780
+ fi
781
+
782
+ if [ "$DEAD_COUNT" -gt 0 ]; then
783
+ echo "" >&2
784
+ echo "generate-lite-manifest: SYMMETRY WARNING — $DEAD_COUNT hook(s) wired in settings template but absent from manifest:" >&2
785
+ echo "$DEAD_WIRED" | sed 's/^/ - /' >&2
786
+ echo "" >&2
787
+ echo "Resolution paths:" >&2
788
+ echo " 1. Retag source hook so it enters lite (tier: lite + install-class: project or dual)" >&2
789
+ echo " 2. Remove the wiring entry from $SETTINGS_TEMPLATE" >&2
790
+ echo " 3. Add the hook basename to $ALLOWLIST (grace window through 2026-10-31)" >&2
791
+ echo "" >&2
792
+ echo "Per .claude/rules/we-dont-break-adopters.md (ADR-031). SKIP_MANIFEST_SYMMETRY=1 bypasses one call." >&2
793
+ # V1 ADVISORY — exit 0 with warning. V2 flips to exit 4 (BLOCK).
794
+ fi
795
+ fi
796
+ fi
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+ # tier: lite
3
+ # CLI wrapper for lib/workflow-metrics.sh — Module B4 query helper.
4
+ #
5
+ # Used at Phase checkpoints per canvas activity diagram to sample the
6
+ # median bassclef-pr-ci run duration over the last N days.
7
+ #
8
+ # Closes sunj-labs/bassclef-upstream#1307 (parent epic #1750).
9
+ #
10
+ # Usage:
11
+ # scripts/workflow-metrics-query.sh # list all entries
12
+ # scripts/workflow-metrics-query.sh --workflow <name> # filter by workflow
13
+ # scripts/workflow-metrics-query.sh --median # emit median
14
+ # scripts/workflow-metrics-query.sh --workflow <name> --median # median for one workflow
15
+
16
+ set -e
17
+
18
+ WORKFLOW=""
19
+ MEDIAN=0
20
+ STORE_DIR=""
21
+
22
+ while [[ $# -gt 0 ]]; do
23
+ case "$1" in
24
+ --workflow) WORKFLOW="${2:-}"; shift 2 ;;
25
+ --median) MEDIAN=1; shift ;;
26
+ --store-dir) STORE_DIR="${2:-}"; shift 2 ;;
27
+ -h|--help)
28
+ grep -E '^# ' "$0" | sed 's/^# \?//'
29
+ exit 0
30
+ ;;
31
+ *)
32
+ echo "unknown arg: $1" >&2
33
+ exit 1
34
+ ;;
35
+ esac
36
+ done
37
+
38
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")
39
+ LIB="$REPO_ROOT/lib/workflow-metrics.sh"
40
+
41
+ if [ ! -f "$LIB" ]; then
42
+ echo "workflow-metrics-query: lib not found at $LIB" >&2
43
+ exit 1
44
+ fi
45
+
46
+ # shellcheck source=/dev/null
47
+ source "$LIB"
48
+
49
+ if [ -z "$STORE_DIR" ]; then
50
+ STORE_DIR=$(_workflow_metrics_default_store)
51
+ fi
52
+
53
+ if [ "$MEDIAN" = "1" ]; then
54
+ compute_median "$STORE_DIR" "$WORKFLOW"
55
+ else
56
+ query_metrics "$STORE_DIR" "$WORKFLOW"
57
+ fi
@@ -34,6 +34,30 @@ Every entry stays in this file for the life of the manifest. Never pruned. When
34
34
 
35
35
  ## Entries (newest first)
36
36
 
37
+ ### Ship 1 — install-class boundary + retag rollout (v1.8.7 → v1.9.0, 2026-09-20)
38
+
39
+ - **Change type:** entry-removal (3 entries drop) + entry-add (1 template ships) + policy-change (Gate B install-class filter + Gate C wiring/file symmetry check added to generator)
40
+ - **Fields:** none changed at manifest schema layer. Emission behavior extends.
41
+ - **Version bump:** v1.8.7 → v1.9.0 (MINOR; entries removed + new emission surface + generator behavior extended).
42
+ - **Rationale:** bassclef-upstream#1825 + #1827 + #1824 + #1816 + #1828 + #1728. Five sisters from the cli 1.2.1 smoke and one coordinator from the cli 1.1.1 smoke. Generator gains three gates — tier filter, install-class filter, wiring/file symmetry. Adopters at cli 1.2.x stop seeing PreToolUse errors on every bash tool call once cli picks up.
43
+ - **Retagged out of lite (drop from adopter bundle):**
44
+ - the `/release` skill (substrate concern; operator-only)
45
+ - the `/journal-export` skill (substrate concern; operator-only)
46
+ - the operator sync hook (`install-class: operator`; adopters use the dispatcher)
47
+ - **Added to lite (new adopter file):**
48
+ - `presence/install/bassclef-configs.template.jsonc` — `bassclef init` copies to `.claude/bassclef-configs.jsonc`
49
+ - **Wiring cleanup:** 33 dead-wired hook entries pruned from `presence/install/public-bassclef-settings.template.json`. Each named a hook whose source did not ship in the lite bundle (mostly `tier: standard` hooks). PreToolUse errors on every bash tool call resolve.
50
+ - **Path sanitization:** 27 hardcoded `~/src/sunj-labs/bassclef` occurrences in 2 skill bodies replaced with `${BASSCLEF_DIR:-$CLAUDE_PROJECT_DIR}` pattern. 3 `sunjay-google-ops` gcloud path leaks replaced with `${BASSCLEF_GCLOUD_KEY:-}` env var lookup.
51
+ - **New generator gates:**
52
+ - Gate A — tier filter (strict; upstream/archive/unknown never enter lite)
53
+ - Gate B — install-class filter (operator scope excluded from adopter bundles)
54
+ - Gate C — wiring/file symmetry (ADVISORY V1 per ADR-031 grace window; flip to BLOCK V2)
55
+ - Allowlist file `scripts/generate-lite-manifest-symmetry-allowlist.txt` grants grace exceptions during rollout
56
+ - Overrides: `SKIP_INSTALL_CLASS_FILTER=1`, `SKIP_MANIFEST_SYMMETRY=1`
57
+ - **Downstream cure:** bassclef-cli picks up on next 1.2.x publish. Fresh `bassclef init` on cli 1.2.x sees zero PreToolUse errors, gets a copy of `bassclef-configs.template.jsonc` at `.claude/bassclef-configs.jsonc`, and has `/onboard-repo` with the new top-up path.
58
+ - **Old shape retired:** dead-wired hook entries in the adopter settings template. Adopters who ran cli 1.2.1 still have those entries in their `.claude/settings.json` locally; the sync run picks up the pruned template.
59
+ - **Closes:** #1825, #1827, #1824, #1816, #1828, #1728 upstream; delivers bassclef-cli#101, #104 (new); rides delivery of cli#105, #106, #108, #102, #107 (already cured upstream). cli#103 stays cli-side per cli#96.
60
+
37
61
  ### Goal 2026-09-17c — one tier declaration per file (v1.8.1 → v1.8.2, 2026-09-17)
38
62
 
39
63
  - **Change type:** content-change (27 content hashes; no entries added or removed)