@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
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: The cold-adopter harness is a structural validator that approximates a brand-new operator cloning bassclef on a fresh laptop.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cold-adopter harness — standard
|
|
7
|
+
|
|
8
|
+
The cold-adopter harness is a structural validator that approximates a brand-new operator cloning bassclef on a fresh laptop. It catches the failure class where substrate changes silently break adoption — broken symlinks, missing tier-tagged files, invalid `settings.json`, dangling references to files that exist on the developer's machine but not in a clean clone.
|
|
9
|
+
|
|
10
|
+
This standard documents the V1 shape (shape a per `bassclef-upstream#333`): structural-only checks against a fresh fetch of public bassclef HEAD. Shape b (sync round-trip) and shape c (skill round-trip + CI integration) are deferred follow-ons named in the parent ticket.
|
|
11
|
+
|
|
12
|
+
## Invocation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Default: fetch public bassclef HEAD into a tmpdir + run checks
|
|
16
|
+
scripts/cold-adopter-harness.sh
|
|
17
|
+
|
|
18
|
+
# Run against an existing directory (used by tests + ad-hoc validation)
|
|
19
|
+
scripts/cold-adopter-harness.sh --target /path/to/tree
|
|
20
|
+
|
|
21
|
+
# Help text
|
|
22
|
+
scripts/cold-adopter-harness.sh --help
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Exit codes (Hoare postcondition)
|
|
26
|
+
|
|
27
|
+
| Code | Meaning |
|
|
28
|
+
|---|---|
|
|
29
|
+
| 0 | All 5 structural checks pass |
|
|
30
|
+
| 2 | At least one structural check fails |
|
|
31
|
+
| 3 | Setup failure (network, no public bassclef, target missing) |
|
|
32
|
+
|
|
33
|
+
## 5 structural checks
|
|
34
|
+
|
|
35
|
+
Each check is implemented as a separate function in `scripts/cold-adopter-harness.sh`.
|
|
36
|
+
|
|
37
|
+
| Function | What it asserts | When it fails |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `check_settings_json` | `.claude/settings.json` parses as valid JSON when present | hand-edit corrupted the file; merge dropped a brace |
|
|
40
|
+
| `check_hooks_executable` | All `.claude/hooks/*.sh` carry the executable bit | git fetch dropped permissions; rename lost +x |
|
|
41
|
+
| `check_tier_tags` | Every `tier:` frontmatter value is `lite`, `standard`, `ultra`, `upstream`, or `private` | typo (`tier: standar`) or new tier value not yet documented |
|
|
42
|
+
| `check_bassclef_source_schema` | `.bassclef-source.json` parses + carries `source_url` when present | adopter hand-rolled the file or copied from a different repo |
|
|
43
|
+
| `check_no_broken_symlinks` | `find -type l` finds no dangling targets in the tree | substrate rename left a symlink pointing at the old path |
|
|
44
|
+
|
|
45
|
+
Each check returns silently on absence (no `.claude/settings.json`? OK — not every adopter carries one) and reports `FAIL` on presence-with-defect.
|
|
46
|
+
|
|
47
|
+
## Override
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
SKIP_COLD_ADOPTER_HARNESS=1 scripts/cold-adopter-harness.sh
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Logged via `trace-helper.sh`. Use only when the harness itself is under maintenance OR when the cold-adopter contract is genuinely irrelevant to the current task (rare — the discipline holds in most cases).
|
|
54
|
+
|
|
55
|
+
## Why this exists
|
|
56
|
+
|
|
57
|
+
Six vendoring-gap failures surfaced on bet 25b (PR #334) the first time CI fired on bassclef-upstream — every gap was the class "file exists on public bassclef but missing on upstream." Each was diagnosed individually; the harness names the class and runs against it before bets ship. The discipline parallels `@luminary michael-feathers` Working Effectively with Legacy Code — a characterization test locks the observable contract.
|
|
58
|
+
|
|
59
|
+
## Composes with
|
|
60
|
+
|
|
61
|
+
- `.claude/rules/we-dont-break-adopters.md` — the harness IS the mechanical layer for the adopter-compat stance
|
|
62
|
+
- `.claude/rules/testing-tier-config.md` Tier 0 — harness ships test-first with `.claude/hooks/tests/cold-adopter-harness.test.sh`
|
|
63
|
+
- `.claude/rules/bootstrap-pair-discipline.md` — the harness is the runtime pair for substrate primitives that need adopter-side validation
|
|
64
|
+
- `scripts/release-to-bassclef.sh` — sister at the release boundary; harness fires before release, andon scan fires during
|
|
65
|
+
- `architecture/audits/2026-06-24-release-tree-origin.md` — the asymmetry the harness measures
|
|
66
|
+
|
|
67
|
+
## Distinct from
|
|
68
|
+
|
|
69
|
+
- `release-to-bassclef.sh` — that script publishes changes downstream; this harness validates state. Both ship together but operate on different boundaries.
|
|
70
|
+
- `scripts/secrets-status.sh` — that script reports secret lifecycle; this harness reports substrate-shape integrity.
|
|
71
|
+
- Pre-commit hooks — those fire at write time; this harness fires at validation time (operator-triggered today; CI-triggered when shape c lands).
|
|
72
|
+
|
|
73
|
+
## Shape b — sync round-trip (V2, bassclef-upstream#341)
|
|
74
|
+
|
|
75
|
+
Shape b extends shape a by composing the 5 structural checks with a sixth check that verifies post-sync surface consistency: when `settings.json` carries a statusLine reference, the script it references must exist on disk. Closes the regression class surfaced by #340 (`additive_merge_settings` cp-fallback dropping `statusLine` reference silently).
|
|
76
|
+
|
|
77
|
+
### Invocation
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Run shape b against an existing tree (composes shape a + statusLine check)
|
|
81
|
+
scripts/cold-adopter-harness-sync.sh --target /path/to/tree
|
|
82
|
+
|
|
83
|
+
# Structural-only (delegates to shape a, 5 checks)
|
|
84
|
+
scripts/cold-adopter-harness-sync.sh --mode structural --target /path/to/tree
|
|
85
|
+
|
|
86
|
+
# Live fetch: clone public bassclef HEAD into tmpdir + run
|
|
87
|
+
scripts/cold-adopter-harness-sync.sh --fetch
|
|
88
|
+
|
|
89
|
+
# Help text
|
|
90
|
+
scripts/cold-adopter-harness-sync.sh --help
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Exit codes (same shape as shape a)
|
|
94
|
+
|
|
95
|
+
| Code | Meaning |
|
|
96
|
+
|---|---|
|
|
97
|
+
| 0 | All 6 checks pass (5 structural + 1 statusLine consistency) |
|
|
98
|
+
| 2 | At least one check fails |
|
|
99
|
+
| 3 | Setup failure (shape a foundation missing, target missing, fetch error) |
|
|
100
|
+
|
|
101
|
+
### Sixth check
|
|
102
|
+
|
|
103
|
+
| Function | What it asserts | When it fails |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `check_statusline_consistency` | When `.claude/settings.json` carries a `statusLine.command` of shape `bash <path>`, the referenced script exists on disk | The cp-fallback path silently dropped the ref (per #340); or the operator hand-edited the ref to point at a now-renamed script |
|
|
106
|
+
|
|
107
|
+
When `settings.json` does NOT carry a statusLine reference, the check passes silently (not all adopters carry one). When `settings.json` fails to parse at all, the check defers to shape a's `check_settings_json` finding (avoids redundant noise).
|
|
108
|
+
|
|
109
|
+
### Seventh + Eighth checks (shape c — bassclef-upstream#341 WU-3)
|
|
110
|
+
|
|
111
|
+
Shape c extends the harness with workflow-loop smoke checks. Both run after shape a's 5 structural checks + shape b's 6th statusLine consistency check, totaling 8 checks per run.
|
|
112
|
+
|
|
113
|
+
| Function | What it asserts | When it fails |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| `check_state_spine_smoke` | `lib/state.sh` exists at the target's expected path AND sources cleanly AND defines `state_whereami_get` (the canonical read accessor) | `lib/state.sh` missing (broken symlink, never shipped); the library fails to source (syntax error after recent edit); the canonical accessor function went missing or got renamed without a rename-compat shim |
|
|
116
|
+
| `check_skills_parse_smoke` | `/sprint`, `/whereami`, `/substrate-check` SKILL.md files all exist + carry parseable YAML frontmatter | A workflow-loop skill went missing (rename without compat shim); a SKILL.md got hand-edited to drop the frontmatter block; the frontmatter close marker `---` is missing |
|
|
117
|
+
|
|
118
|
+
Why these three skills specifically: they form the workflow-loop orientation triad every adopter session uses at session-start. `/sprint` shows what's in flight; `/whereami` shows project-state; `/substrate-check` validates the substrate wiring. A regression in any of them breaks adopter onboarding silently.
|
|
119
|
+
|
|
120
|
+
Why `check_state_spine_smoke` checks function-definition (not return-data): adopter Shape (A JSON vs B markdown) varies; the accessor's return value depends on whether `docs/whereami.json` exists locally. The smoke proof is that the library SOURCES + the accessor function IS DEFINED. Data-correctness validation is per-accessor; out of scope for shape-c smoke.
|
|
121
|
+
|
|
122
|
+
### Override
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
SKIP_COLD_ADOPTER_HARNESS_SYNC=1 scripts/cold-adopter-harness-sync.sh
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Logged via `trace-helper.sh`. Same discipline as shape a.
|
|
129
|
+
|
|
130
|
+
### Live end-to-end sync invocation (deferred to shape c)
|
|
131
|
+
|
|
132
|
+
Shape b currently validates a target's post-sync state structurally — it does NOT invoke `presence/install/bassclef-sync.template.sh` end-to-end against a fake consumer + fake HOME inside the harness. That live invocation lands with shape c (workflow round-trip + CI integration) per `bassclef-upstream#341` § Shape c. The `--fetch` flag does the safest piece (clone + structural validation) without requiring fake HOME plumbing.
|
|
133
|
+
|
|
134
|
+
## V3 (shape c — deferred per `bassclef-upstream#341`)
|
|
135
|
+
|
|
136
|
+
- **Shape c** — workflow round-trip + CI integration. Composes shape b. After sync, invokes `/sprint`, `/whereami`, `/substrate-check` against the cold dir + sources `lib/state.sh` for state-spine smoke. Runs in GitHub Actions on PR — PR-blocking when shape c fails. Catches breakage in the actual workflow loop. Filed as next bet after shape b lands.
|
|
137
|
+
|
|
138
|
+
V1 (shape a) ships the foundation; V2 (shape b) adds statusLine consistency; V3 (shape c) lands the CI gate.
|
|
139
|
+
|
|
140
|
+
## Shape d — mechanism-fidelity check classes (bet 27c WU-5, bassclef-upstream#417)
|
|
141
|
+
|
|
142
|
+
Shape d adds 4 check classes that catch every future instance of the "rule names a mechanism that does not fire" failure class. Each class composes `lib/mechanism-fidelity.sh` (shipped bet 27c WU-3) — the shared deep module. The audit skill (`.claude/skills/audit-rule-mechanism-fidelity/`, WU-4) and the harness (this Shape d, WU-5) share the same impl; no duplicated logic.
|
|
143
|
+
|
|
144
|
+
### Invocation
|
|
145
|
+
|
|
146
|
+
Shape d fires as part of `--mode sync` (default). No new mode flag; the 4 checks run after Shape c's state-spine + skills-parse smokes.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
scripts/cold-adopter-harness-sync.sh --mode sync --target <dir>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
When `<target>/lib/mechanism-fidelity.sh` is absent (pre-bet-27c-WU-3 install layout), Shape d emits a SKIP finding and the harness proceeds without the 4 checks.
|
|
153
|
+
|
|
154
|
+
### V1 ADVISORY mode
|
|
155
|
+
|
|
156
|
+
Shape d ships in V1 as ADVISORY: findings record to the SYNC_FINDINGS array with `ADVISORY (Shape d V1; will BLOCK in V2):` prefix but do NOT increment SYNC_FAIL_COUNT. The harness exits 0 even with Shape d findings present.
|
|
157
|
+
|
|
158
|
+
This pattern lets the PR-CI gate ship while WU-6 audit produces the full findings doc + WU-7 sizes the cure bet (Bet C-pre-2) from those findings. After cures land, the V2 flip changes ADVISORY to BLOCK; the harness then fails CI on any Shape d finding.
|
|
159
|
+
|
|
160
|
+
### The 4 check classes
|
|
161
|
+
|
|
162
|
+
**Check 9 — `hook-wiring-presence`** — For each hook in `.claude/hooks/*.sh` (except `trace-helper.sh`), the harness calls `verify_hook_wired` from the lib. The lib greps `<target>/.claude/settings.json` and `$HOME/.claude/settings.json` for the hook name. PASS when wired in at least one; ADVISORY when wired in neither.
|
|
163
|
+
|
|
164
|
+
Catches: hooks shipped without their paired settings.json entry (the "hook-wire-on-author" failure mode named in `.claude/rules/hook-wire-on-author.md`).
|
|
165
|
+
|
|
166
|
+
**Check 10 — `hook-path-resolution-under-install-class`** — For each hook, `verify_path_resolution` checks for the Class A pattern: hook reads `SCRIPT_DIR/../../<project-resource>` but declares `# install-class: operator`. Mismatch = Class A failure (under `$HOME` wiring, `SCRIPT_DIR/../../` resolves to a nonexistent path). PASS when no risky pattern OR risky pattern + `install-class: dual`/`project`. ADVISORY when Class A or undeclared with risky pattern.
|
|
167
|
+
|
|
168
|
+
Catches: the failure mode the `turn-prose-kiss-check.sh` cure (PR #427) closed; prevents repeats.
|
|
169
|
+
|
|
170
|
+
**Check 11 — `hook-end-to-end-smoke`** — For each hook: `bash -n` syntax check + invocation with empty JSON stdin (`{}`). Assert exit code is in `{0, 2, 3}` (success or known block codes). Other codes indicate a real crash. Conservative: invokes with empty stdin to exercise the hook's graceful-skip path; does not exercise full hook behavior.
|
|
171
|
+
|
|
172
|
+
Catches: hooks that fail to parse OR crash with unexpected exit codes when invoked normally.
|
|
173
|
+
|
|
174
|
+
**Check 12 — `rule-mechanism-claim-fidelity`** — For each rule under `.claude/rules/*.md`, `scan_rule_for_mechanism_claims` extracts hook references. For each claim, the harness runs the 5-step verification cascade (`verify_hook_exists` + `verify_hook_wired` + `verify_path_resolution` + `verify_hook_test_pins_contract`) and `classify_finding` returns one of 7 labels (CLEAN / DEAD-LETTER / UNWIRED / PATH-BROKEN / TEST-MISSING / METHODOLOGY-ONLY / SILENT-PASS). PASS when all claims classify CLEAN; ADVISORY otherwise with classification per claim.
|
|
175
|
+
|
|
176
|
+
False-positive filter (V1): claims that reference `.sh` files outside `.claude/hooks/` are skipped (lib references like `state.sh`, script references like `release-to-bassclef.sh`, doc example names like `foo.sh`). The audit skill (WU-4) uses the broader scanner without this filter to classify ALL claims; the harness applies the filter to focus PR-CI signal on hook-related claims only.
|
|
177
|
+
|
|
178
|
+
### Composition with prior shapes
|
|
179
|
+
|
|
180
|
+
| Layer | Shape | Checks |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| Foundation | a | 1-5 (structural validity) |
|
|
183
|
+
| Sync round-trip | b | 6 (statusLine) |
|
|
184
|
+
| Workflow round-trip | c | 7-8 (state-spine + skills-parse) |
|
|
185
|
+
| **Mechanism fidelity** | **d** | **9-12 (wiring + path + smoke + rule-claim)** |
|
|
186
|
+
|
|
187
|
+
Shape a is mandatory. Shape b/c are mandatory under `--mode sync`. Shape d is mandatory when `lib/mechanism-fidelity.sh` is present in target.
|
|
188
|
+
|
|
189
|
+
### V2 (BLOCK flip — deferred to follow-on)
|
|
190
|
+
|
|
191
|
+
V2 flips Shape d findings from ADVISORY to BLOCK after Bet C-pre-2 cures land. The flip is a single-line code change in the harness (`shape_d_advisory()` → identical to a `FAIL:` accumulator). No methodology change; the discipline already exists in V1.
|
|
192
|
+
|
|
193
|
+
V2 ships when the audit skill's first findings table (`architecture/audits/2026-06-27-mechanism-fidelity.md`, WU-6 product) drives down to zero remaining findings under the V1 false-positive filter.
|
|
194
|
+
|
|
195
|
+
## Refs
|
|
196
|
+
|
|
197
|
+
- `bassclef-upstream#333` — this standard's filing ticket
|
|
198
|
+
- `bassclef-upstream#320` — parent epic
|
|
199
|
+
- bet `docs/iteration-bets/2026-06-25e-cold-adopter-harness.md` — ship vehicle
|
|
200
|
+
- `architecture/audits/2026-06-24-release-tree-origin.md` — WU-11 of bet 24c surfaced the asymmetry
|
|
201
|
+
- `docs/deferred-actions/completed/2026-06-25T00-31-00Z-cold-adopter-harness-decision-pending.md` — operator decision recorded
|
|
202
|
+
|
|
203
|
+
## Retirement condition
|
|
204
|
+
|
|
205
|
+
This standard retires only if bassclef stops having adopters. The harness's surface area may grow (more checks, more shapes) but the discipline of validating the adopter-observable contract before ship survives.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: Verify with data, not empty state. An empty page that renders is not verification — it proves the template works, not the feature.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Data Management Standard
|
|
7
|
+
|
|
8
|
+
## Principle
|
|
9
|
+
|
|
10
|
+
Verify with data, not empty state. An empty page that renders is not
|
|
11
|
+
verification — it proves the template works, not the feature.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Schema Migration Workflow
|
|
16
|
+
|
|
17
|
+
When a branch adds or modifies Prisma schema:
|
|
18
|
+
|
|
19
|
+
### Before migration (SHOULD)
|
|
20
|
+
|
|
21
|
+
1. **Snapshot the local dev DB** — rollback point
|
|
22
|
+
```bash
|
|
23
|
+
pg_dump -Fc $DATABASE_URL > docs/db-snapshots/YYYY-MM-DD-pre-{name}.dump
|
|
24
|
+
```
|
|
25
|
+
Store in `docs/db-snapshots/` (create if missing). Not committed to git
|
|
26
|
+
(add to `.gitignore`) — too large. Just a local safety net.
|
|
27
|
+
|
|
28
|
+
### Apply migration (MUST)
|
|
29
|
+
|
|
30
|
+
2. **Run migration**
|
|
31
|
+
```bash
|
|
32
|
+
npx prisma migrate dev --name descriptive_name
|
|
33
|
+
```
|
|
34
|
+
This creates the migration file AND applies it locally.
|
|
35
|
+
|
|
36
|
+
3. **Regenerate client** (MUST — see schema-management.md)
|
|
37
|
+
```bash
|
|
38
|
+
npx prisma generate
|
|
39
|
+
```
|
|
40
|
+
Then restart the dev server. The cached Prisma client won't pick up
|
|
41
|
+
new models without a restart.
|
|
42
|
+
|
|
43
|
+
4. **Commit the migration file** with the schema change.
|
|
44
|
+
|
|
45
|
+
### After migration — seed test data (MUST for new entities)
|
|
46
|
+
|
|
47
|
+
5. **Write a seed script for new entities**
|
|
48
|
+
- Location: `prisma/seeds/` or `scripts/seed-{entity}.ts`
|
|
49
|
+
- Use factories, not hardcoded data (per testing.md)
|
|
50
|
+
- Each new entity gets a seed file
|
|
51
|
+
- Seeds are idempotent (safe to re-run, use upsert)
|
|
52
|
+
- Seeds create realistic data:
|
|
53
|
+
- Real-looking names, emails, phone numbers
|
|
54
|
+
- Realistic distributions (not all the same value)
|
|
55
|
+
- Time-spread data (some recent, some old) for testing
|
|
56
|
+
time-based queries like "needs attention"
|
|
57
|
+
- Minimum: 5-10 records per new entity
|
|
58
|
+
- Link to existing entities where relationships exist
|
|
59
|
+
|
|
60
|
+
6. **Run the seed**
|
|
61
|
+
```bash
|
|
62
|
+
npx tsx prisma/seeds/seed-{entity}.ts
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Verify with data (MUST)
|
|
66
|
+
|
|
67
|
+
7. **Verify the feature works with seeded data**
|
|
68
|
+
- UI renders data, not just empty state
|
|
69
|
+
- API returns seeded records
|
|
70
|
+
- Queries that filter/sort/group work correctly
|
|
71
|
+
- Time-based logic (e.g., "needs attention after 7 days") has
|
|
72
|
+
both qualifying and non-qualifying records to test
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Restoring from Production (for realistic local testing)
|
|
77
|
+
|
|
78
|
+
When you need real data patterns (not just seed data):
|
|
79
|
+
|
|
80
|
+
1. **Snapshot prod** (read-only):
|
|
81
|
+
```bash
|
|
82
|
+
pg_dump -Fc $PROD_DATABASE_URL > docs/db-snapshots/YYYY-MM-DD-prod.dump
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
2. **Restore to local dev**:
|
|
86
|
+
```bash
|
|
87
|
+
pg_restore --clean --no-owner -d $DATABASE_URL docs/db-snapshots/YYYY-MM-DD-prod.dump
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
3. **Apply pending migrations** (prod may be behind local schema):
|
|
91
|
+
```bash
|
|
92
|
+
npx prisma migrate dev
|
|
93
|
+
npx prisma generate
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
4. **Seed new entities** that don't exist in prod yet:
|
|
97
|
+
```bash
|
|
98
|
+
npx tsx prisma/seeds/seed-{new-entity}.ts
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
5. **Restart dev server** and verify.
|
|
102
|
+
|
|
103
|
+
**Rules**:
|
|
104
|
+
- NEVER modify production data. Read-only access to prod.
|
|
105
|
+
- All writes are to local dev only.
|
|
106
|
+
- Prod snapshots are NOT committed to git (add to `.gitignore`).
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Verify Gate Update
|
|
111
|
+
|
|
112
|
+
The `/verify` gate for schema changes must include:
|
|
113
|
+
|
|
114
|
+
| Check | What | Why |
|
|
115
|
+
|-------|------|-----|
|
|
116
|
+
| Migration applies | `prisma migrate dev` succeeds | Schema is valid |
|
|
117
|
+
| Client regenerates | `prisma generate` succeeds | Client knows new models |
|
|
118
|
+
| Seed runs | Seed script creates data | New entities have test data |
|
|
119
|
+
| App renders with data | UI shows seeded records | Not just empty state |
|
|
120
|
+
| API returns data | Endpoints return seeded records | Queries work |
|
|
121
|
+
| Tests pass | `vitest run` passes | No regressions |
|
|
122
|
+
|
|
123
|
+
An empty-state screenshot is NOT verification for a schema change.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Seed Data Conventions
|
|
128
|
+
|
|
129
|
+
- **Factories over hardcoded data** — per testing.md
|
|
130
|
+
- **Naming**: `test_{what}_{scenario}` for test data factory functions
|
|
131
|
+
- **Realistic**: use `faker` or realistic patterns, not "test1", "test2"
|
|
132
|
+
- **Idempotent**: use `upsert` or check-before-create
|
|
133
|
+
- **Minimal**: 5-10 records per entity is enough for dev verification
|
|
134
|
+
- **Time-aware**: spread records across time for testing recency queries
|
|
135
|
+
- **Relational**: link to existing entities (deals, users) where applicable
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
tier: lite
|
|
3
|
+
description: "The operator's reference stack. Stack-specific instantiation of standards/frontend-stack.md for adopters who pick the same stack."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Frontend Stack — Next.js + Prisma + Postgres + EC2-Tailscale
|
|
7
|
+
|
|
8
|
+
The operator's reference stack. Stack-specific instantiation of `standards/frontend-stack.md` for adopters who pick the same stack.
|
|
9
|
+
|
|
10
|
+
## When this sibling fires
|
|
11
|
+
|
|
12
|
+
When adopter's `.claude/bassclef-configs.jsonc` has:
|
|
13
|
+
|
|
14
|
+
```jsonc
|
|
15
|
+
"tech_stack": {
|
|
16
|
+
"frontend": "nextjs",
|
|
17
|
+
"backend": "nodejs",
|
|
18
|
+
"orm": "prisma",
|
|
19
|
+
"pkg_manager": "npm",
|
|
20
|
+
"deploy": "ec2-tailscale"
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The loader (future ticket) reads this sibling and applies the stack-specific guidance below in addition to the universal principle in the parent standard.
|
|
25
|
+
|
|
26
|
+
## Decision
|
|
27
|
+
|
|
28
|
+
Full TypeScript stack. One language from database to UI.
|
|
29
|
+
|
|
30
|
+
See [ADR-008](../../architecture/decisions/ADR-008-full-typescript-stack.md) for rationale.
|
|
31
|
+
|
|
32
|
+
## Stack
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Next.js 14+ (App Router)
|
|
36
|
+
├── TypeScript (strict) — end-to-end type safety
|
|
37
|
+
├── Prisma + Postgres — ORM, migrations, type-safe queries
|
|
38
|
+
├── NextAuth.js — auth for operator, family, collaborators
|
|
39
|
+
├── BullMQ + Redis — async job queue, scheduling, retries
|
|
40
|
+
├── Anthropic TS SDK — LLM calls inside tools
|
|
41
|
+
├── Langfuse TS SDK — tracing, evals
|
|
42
|
+
├── Tailwind CSS — design tokens map to utilities
|
|
43
|
+
├── shadcn/ui — copy-paste components you own
|
|
44
|
+
└── Deploy: Docker on EC2 via Tailscale
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Project Structure
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
app/
|
|
51
|
+
├── (dashboard)/ — authenticated pages
|
|
52
|
+
│ ├── deals/
|
|
53
|
+
│ ├── tools/
|
|
54
|
+
│ └── admin/queues/ — Bull Board (operator-only)
|
|
55
|
+
├── api/
|
|
56
|
+
│ ├── health/ — healthcheck endpoint
|
|
57
|
+
│ ├── tools/ — tool trigger endpoints
|
|
58
|
+
│ └── auth/ — NextAuth routes
|
|
59
|
+
├── layout.tsx
|
|
60
|
+
└── page.tsx
|
|
61
|
+
src/
|
|
62
|
+
├── tools/ — tool implementations
|
|
63
|
+
│ ├── registry.ts — tool registry (name, description, params, run fn)
|
|
64
|
+
│ ├── scrappy-scrapper.ts
|
|
65
|
+
│ ├── deal-scorer.ts
|
|
66
|
+
│ └── inbox-classifier.ts
|
|
67
|
+
├── lib/
|
|
68
|
+
│ ├── queue.ts — BullMQ queue + worker setup
|
|
69
|
+
│ ├── langfuse.ts — Langfuse client
|
|
70
|
+
│ └── anthropic.ts — Anthropic client wrapper
|
|
71
|
+
└── components/
|
|
72
|
+
└── ui/ — shadcn/ui components
|
|
73
|
+
prisma/
|
|
74
|
+
├── schema.prisma — single source of truth for DB schema
|
|
75
|
+
├── migrations/ — Prisma migrations (committed to git)
|
|
76
|
+
└── seed.ts — deterministic seed data
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Conventions
|
|
80
|
+
|
|
81
|
+
- Components live in `/src/components/ui/` (shadcn/ui, modified to use design tokens).
|
|
82
|
+
- Pages use App Router conventions (`/app/page.tsx`, `/app/layout.tsx`).
|
|
83
|
+
- Design tokens from `platform-docs/design/design-tokens.css` map to Tailwind config.
|
|
84
|
+
- No external component libraries beyond shadcn/ui. You own every component.
|
|
85
|
+
- **Tailwind v4 + bassclef symlinks**: Tailwind v4's `@import "tailwindcss"`
|
|
86
|
+
auto-scans all project files. Symlinks in `.claude/skills/` that point to
|
|
87
|
+
`../bassclef/` cause Turbopack to follow paths outside the project root
|
|
88
|
+
and crash. Add this to `globals.css` after the import:
|
|
89
|
+
```css
|
|
90
|
+
@import "tailwindcss";
|
|
91
|
+
@source not "../../.claude";
|
|
92
|
+
```
|
|
93
|
+
This excludes the `.claude/` directory from Tailwind's content scanning.
|
|
94
|
+
The bassclef-sync script should check for this and warn if missing.
|
|
95
|
+
- Tools are registered in `src/tools/registry.ts`. Every tool is a typed function with metadata.
|
|
96
|
+
- Prisma schema is the single source of truth for database structure.
|
|
97
|
+
- Environment variables in `.env.local` (local) and Docker env (production). Never committed.
|
|
98
|
+
|
|
99
|
+
## Key Commands
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Local development
|
|
103
|
+
docker-compose -f docker-compose.dev.yml up -d # Postgres + Redis
|
|
104
|
+
npm run dev # Next.js hot reload
|
|
105
|
+
|
|
106
|
+
# Database
|
|
107
|
+
npx prisma migrate dev # Create/apply migration
|
|
108
|
+
npx prisma db seed # Seed data
|
|
109
|
+
npx prisma studio # Visual DB browser
|
|
110
|
+
|
|
111
|
+
# Testing
|
|
112
|
+
npx vitest # Watch mode
|
|
113
|
+
npx vitest run # CI mode
|
|
114
|
+
|
|
115
|
+
# Production deploy
|
|
116
|
+
git push origin main # Triggers full CI/CD pipeline
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Refs
|
|
120
|
+
|
|
121
|
+
- Parent standard: `standards/frontend-stack.md`
|
|
122
|
+
- ARCH-T0 #1133 — operator-stack-leakage audit + remediation
|
|
123
|
+
- bassclef#1313 — this sibling (frontend-stack Path A WU-8 of bet 2026-06-20e)
|
|
124
|
+
- ADR-008 — operator-side rationale for this stack
|
|
@@ -34,6 +34,33 @@ 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
|
+
### Goal 2026-09-17c — one tier declaration per file (v1.8.1 → v1.8.2, 2026-09-17)
|
|
38
|
+
|
|
39
|
+
- **Change type:** content-change (27 content hashes; no entries added or removed)
|
|
40
|
+
- **Fields:** none changed. 420 entries before and after. 26 files lose a stale second `# tier:` line; `script/generate-lite-manifest` changes because the uniqueness check lands in it.
|
|
41
|
+
- **Version bump:** v1.8.1 → v1.8.2 (patch; content-hash change only; no schema shape shift, no entry count change). PR #1720 landed 1.8.1 first, so this follows it directly; an earlier draft of this entry said it would skip 1.8.1.
|
|
42
|
+
- **Rationale:** bassclef-upstream#1724. `scripts/apply-lite-widen.sh` inserted a tier tag above an existing one instead of replacing it, whenever the file had a shebang. Its awk streamed, so the shebang rule fired on line 1 and set the done flag before the real tier line on line 2 was ever reached. 26 files ended up with two tier lines that disagreed — 24 read `lite` then `standard`, 2 read `lite` then `upstream`. Every reader takes the first match, so the shipped tier was correct throughout and nothing warned. Verified before cleaning: all 26 have at least one lite parent in the substrate graph, so `lite` is the value reachability derives per ADR-056 D7, and the second line was the pre-widen leftover. The awk now reads the file, decides, then emits. The generator gained a check that counts tier declarations and exits 5 on a repeat.
|
|
43
|
+
- **Downstream cure:** none. Patch bump; adopters on sync pick it up at the next `bassclef-sync`. No file changes tier.
|
|
44
|
+
- **Old shape retired:** none.
|
|
45
|
+
|
|
46
|
+
### Goal 2026-09-17b — shellcheck directive + generator version is the source of truth (v1.8.0 → v1.8.1, 2026-09-17)
|
|
47
|
+
|
|
48
|
+
- **Change type:** content-change (2 content hashes; no entries added or removed)
|
|
49
|
+
- **Fields:** none changed. 420 entries before and after. Two `content_hash` values move — `hook/10-abrupt-stop-recovery` (the #1719 fix: a fresh install is no longer read as an abrupt stop) and `script/generate-lite-manifest` (the version constant below).
|
|
50
|
+
- **Version bump:** v1.8.0 → v1.8.1 (patch; content-hash change only; no schema shape shift, no entry count change).
|
|
51
|
+
- **Rationale:** bassclef-upstream#1719 + PR #1720. Two fixes. The `SC1090` finding on the new test file now carries an in-file `# shellcheck source=/dev/null` directive rather than an allowlist row, so the suppression stays with the line it explains. Separately, `scripts/generate-lite-manifest.sh` held `MANIFEST_VERSION="1.7.0"` while the committed manifest read `1.8.0`, so every regeneration silently downgraded the version and the drift check then failed on a version nobody had changed. The constant is now `1.8.1` and the script is the one place the version lives.
|
|
52
|
+
- **Downstream cure:** none. Patch bump; adopters on sync pick it up at the next `bassclef-sync`.
|
|
53
|
+
- **Old shape retired:** none.
|
|
54
|
+
|
|
55
|
+
### Goal 2026-09-16a — catalog-closure gate + widen to reachability (v1.6.1 → v1.8.0, 2026-09-17)
|
|
56
|
+
|
|
57
|
+
- **Change type:** content-add (125 new entries) + policy-change (generator now gates on reachability)
|
|
58
|
+
- **Fields:** none changed. 292 → 420 entries. Added by type: 47 hook (26 `session-reflection.d/` fragments + 21 retagged), 32 skill, 17 standard, 14 rule, 8 luminary, 3 lib, 3 template, 1 root-doc (`.claude/bassclef-orientation.md`). Zero entries removed (fixture guard at `.claude/hooks/tests/fixtures/2026-09-16-lite-catalog-closure/`).
|
|
59
|
+
- **Version bump:** v1.6.1 → v1.8.0 (minor; additive content; existing type values only; no schema shape shift). Corrected 2026-09-17: this entry originally read v1.7.0 / 417 entries. No v1.7.0 manifest was ever committed — `93192ea0` took the manifest straight from v1.6.1 (292 entries) to v1.8.0 (420), because the first-run bundle rode in the same PR as the catalog widen.
|
|
60
|
+
- **Rationale:** cli#90 + bassclef-upstream#1690. Lite entries referenced 96 files tagged `standard` (skills a lite skill dispatches, rules a lite rule composes, hooks the lite wiring fires, standards a lite rule cites) that never shipped. Same class as the hooks + libs gap cured for cli#82; ADR-056 D1 covered `source` closure only. `scripts/generate-lite-manifest.sh` now runs a manifest-seeded reachability walk (`scripts/walk-substrate-graph.py --closure-vs-manifest`) after the tag scan and exits 3 naming every reachable-but-untagged file. Tags stay the source of what ships; the walk validates them. `scripts/apply-lite-widen.sh --apply` retags to fixed point. `adrs` excluded (bassclef governance, cited as footnotes); two conditional citations sit in `standards/lite-closure-allowlist.txt` with reasons. Fragments and the orientation doc now ship via the manifest, so cli 1.1.1+ can retire its recursive hook-tree copy.
|
|
61
|
+
- **Downstream cure:** none for cli 1.1.0+ (reads `manifest_version` major only; 1.8.x picks up automatically). Adopters on sync get the 128 files at next `bassclef-sync`. Consumers that pin an exact entry count must update (292 → 420). A consumer that pinned v1.7.0 on the strength of the original entry will not find it; pin v1.8.0.
|
|
62
|
+
- **Old shape retired:** none — additive. The closure gate is on by default; `--no-closure-check` / `SKIP_LITE_CLOSURE_CHECK=1` bypass, logged.
|
|
63
|
+
|
|
37
64
|
### Goal 14c Step 6 — Zeller luminary added at lite tier (v1.6.0 → v1.6.1, 2026-09-15)
|
|
38
65
|
|
|
39
66
|
- **Change type:** content-add (1 new luminary entry at lite tier)
|