Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
186 commits
Select commit Hold shift + click to select a range
c97852a
Add canonical base-class-keys def for cross-namespace reuse
codeGlaze Jun 10, 2026
39a054b
Carry plugin-source through option-cfg as a distinct slot
codeGlaze Jun 10, 2026
6680994
Add show-class-source-suffix user preference to the db spec
codeGlaze Jun 10, 2026
36482fe
Add show-class-source-suffix subscription
codeGlaze Jun 10, 2026
9a709c0
Stop folding plugin source into class :name; keep it as :plugin-source
codeGlaze Jun 10, 2026
fe54963
Derive spell-selection keys from class-key, not the display name
codeGlaze Jun 10, 2026
a3e2615
Reconcile orphaned spell-selection keys on a character at load
codeGlaze Jun 10, 2026
4289871
Run spell-selection reconciler on set-character; add source-suffix to…
codeGlaze Jun 10, 2026
8f94a94
Show homebrew source on class names when the preference is enabled
codeGlaze Jun 10, 2026
aabcc82
Add tests for spell-selection key reconciliation
codeGlaze Jun 10, 2026
0637931
Run content-reconciliation tests in the test runner
codeGlaze Jun 10, 2026
f445615
docs: capture content extensibility analysis, plan, and decisions
claude Jun 13, 2026
60e4a49
docs(kb): content extensibility analysis + decisions, structured for …
claude Jun 13, 2026
0b5867b
docs: add session handoff summary and decision audit
claude Jun 13, 2026
793062d
docs(kb): add backward-compatibility audit for content extensibility
claude Jun 13, 2026
3f0e84b
docs(kb): propagate compatibility findings into design + decisions
claude Jun 13, 2026
3d47135
docs(kb): add phased implementation playbook for content extensibility
claude Jun 13, 2026
87015cc
test(extensibility): Phase 0 golden safety net for compat invariants
claude Jun 13, 2026
c67006e
feat(extensibility): Phase 1 — generic option injector, applied to su…
claude Jun 13, 2026
725182d
feat(extensibility): Phase 2 — route subclasses through the catalog seam
claude Jun 13, 2026
bab2403
docs(branch): turn status into a live roadmap/TODO checklist
claude Jun 13, 2026
8f19c5d
feat(extensibility): Phase 3b — catalog read primitive (plugin-options)
claude Jun 13, 2026
cc1d3fe
test(extensibility): Phase 3a — lock boon/invocation option + selecti…
claude Jun 13, 2026
da2f63d
feat(extensibility): Phase 4a — content-types registry (single source…
claude Jun 13, 2026
8c528f1
docs: record name-to-kw footgun + catalog-layering rules across KB/br…
claude Jun 13, 2026
ec26955
Merge feature/name-keyword-fix into content-extensibility work
claude Jun 13, 2026
ade4e8b
docs(e2e): add live verification checklist + record merge in BRANCH.md
claude Jun 13, 2026
f977ba9
test(extensibility): add e2e fixture with subrace/subclass/boon/invoc…
claude Jun 14, 2026
e769f35
docs(branch): record live E2E verification result (PR #28, all PASS/c…
claude Jun 14, 2026
ad61a08
docs(kb): consolidate verified test-suite findings + working agreements
claude Jun 14, 2026
42ceaaa
fix(save): gate make-summary behind the ability check (prevents null …
claude Jun 14, 2026
9fc1c1a
docs(kb): preserve character-validation intent before retiring the br…
claude Jun 14, 2026
2f1a484
docs: make the built-character representation findable + record defer…
claude Jun 14, 2026
114e02b
feat(extensibility): Phase 4b — generate builder-item subs from the r…
claude Jun 14, 2026
d0990fb
docs(kb): capture verification-discipline lessons + re-anchor branch …
claude Jun 14, 2026
86eb5cc
fix(import): dedup homebrew-selection options + count-non-ascii cljs …
claude Jun 14, 2026
adf9394
docs(branch): mark import-validation triage fixed + verified
claude Jun 14, 2026
c369e75
docs(kb): persist deflated direction + cljs harness recipe before com…
claude Jun 14, 2026
96d5775
docs: fix stale summary header to point at the deflated direction first
claude Jun 14, 2026
d3bde51
docs: add 'superseded — see direction doc' banners to the now-histori…
claude Jun 14, 2026
9546776
docs(decisions): record late design decisions D12-D16 (the deflation)
claude Jun 14, 2026
9777ce8
refactor(extensibility): revert thin option_catalog wrappers (readabi…
claude Jun 14, 2026
d32a301
docs: record step 1 (option_catalog revert) done across BRANCH.md + d…
claude Jun 14, 2026
3980ea1
refactor(extensibility): wire boon through register-homebrew-content!
claude Jun 14, 2026
b4ad215
docs: record step 2 (register-homebrew-content! + boon swap) done acr…
claude Jun 14, 2026
d2950bb
docs: re-center on the pool+grant composition spine (stability AND fl…
claude Jun 14, 2026
f30b11e
docs: lock the maintainability GATE (D21) + pin mechanical-effects-fo…
claude Jun 14, 2026
acaa131
feat(extensibility): first pool+grant slice — open draconic ancestry …
claude Jun 14, 2026
25d7c31
docs: record the draconic ancestry pool+grant slice (acaa131d) as done
claude Jun 14, 2026
026f870
feat(extensibility): richer ancestries carry extra mechanics via :pro…
claude Jun 14, 2026
a7094d3
docs: record FTD validation — draconic ancestry expands along 3 axes,…
claude Jun 14, 2026
109b5dd
refactor(builders): collapse per-type builder forms into simple-conte…
claude Jun 14, 2026
b771cdd
docs: record that builder forms are data (simple-content-builder), co…
claude Jun 14, 2026
34be994
test(extensibility): prove a homebrew draconic ancestry choice round-…
claude Jun 14, 2026
0aca611
feat(extensibility): add the Draconic Ancestry homebrew builder end-t…
claude Jun 14, 2026
7503006
docs: record the Draconic Ancestry builder done + the measured add-a-…
claude Jun 14, 2026
d2e002b
refactor(extensibility): generate homebrew event wiring from the cont…
claude Jun 14, 2026
af68061
refactor(extensibility): generate homebrew db default-value slots fro…
claude Jun 14, 2026
64fa470
docs: record foundation progress (events+db generative) + the routes …
claude Jun 14, 2026
cfde081
docs: add representative BEFORE/AFTER for adding a homebrew content type
claude Jun 14, 2026
2d5ea5e
docs: add canonical content-extensibility FRAMEWORK reference (human …
claude Jun 14, 2026
506c32b
refactor(routes): break the content_types -> route_map dependency cycle
claude Jun 14, 2026
c5e9aea
refactor(routes): generate the bidi tree builder segments from the re…
claude Jun 14, 2026
58c4de4
refactor(routes): generate my-content route-set + SPA allowlist from …
claude Jun 14, 2026
da0c500
docs: mark the routes layer generative across framework/direction/BRA…
claude Jun 14, 2026
f32790b
feat(framework): declarative builder field-schema; fixes the breath-w…
claude Jun 15, 2026
de0cf37
feat(framework): generate the save spec from the field schema (option…
claude Jun 15, 2026
ae57173
feat(framework): wire :required? into the form (markers + inline vali…
claude Jun 15, 2026
d53b661
feat(framework): sync import/export verification with the field schema
claude Jun 15, 2026
e461451
feat(import): strict-mode toggle — report missing fields instead of a…
claude Jun 15, 2026
4bd5ab3
docs: D17 — audit what each framework piece REPLACES before building it
claude Jun 15, 2026
2344a39
docs: add homebrew-content-merge KB — kill the recurring feat-options…
claude Jun 15, 2026
4718ac3
docs: decision-vocabulary map, cycle 1 — the compile paths
claude Jun 15, 2026
d98d466
docs: decision-vocabulary cycle 2 — corrects cycle 1, maps cross-silo…
claude Jun 15, 2026
20d44a0
docs: decision-vocabulary correction — subclasses CAN grant spells; t…
claude Jun 15, 2026
7f1373f
docs: decision-vocabulary methodology correction (4th) — races are ri…
claude Jun 15, 2026
71e96b0
docs(kb): rebuild cross-silo capability table from backward builder t…
claude Jun 15, 2026
f05d55a
docs(kb): trace Class silo (builder -> level-option), correct plugin?…
claude Jun 15, 2026
ded3464
docs(kb): complete backward trace for Subrace + Background; finalize …
claude Jun 15, 2026
e7a342a
docs(kb): confirm simple types are descriptive (simple-content-builder)
claude Jun 15, 2026
cddb068
docs: cross-link decision-vocabulary KB at the key assembly fns + index
claude Jun 15, 2026
20ec0ab
docs(kb): correct subclass-spellcasting overclaim (maintainer caught it)
claude Jun 15, 2026
15f0fb5
docs(kb): close the open edge — subclass spellcasting gate is in the …
claude Jun 15, 2026
a474d77
docs(kb): confirm subclass-spellcasting gate with real Divine Soul .o…
claude Jun 15, 2026
fcad36c
docs(kb): fix dead README link + label decision-vocabulary as wiring …
claude Jun 16, 2026
559cbd6
test(e2e): prove custom-class spell-list behaviorally + record open l…
claude Jun 16, 2026
09aaf01
test(e2e): correct the overclaiming spellcaster assertion
claude Jun 16, 2026
3cbe86a
test(e2e): resolve the 'caster that can't cast' — it was MY entity bu…
claude Jun 16, 2026
8dd5168
test(e2e): first built-character test of the cross-bucket grant (and …
claude Jun 16, 2026
8c8c0b1
feat(bridge-prototype): feat-granted fighting style — pool+grant gene…
claude Jun 16, 2026
a4c34f3
test(bridge): prove feat-granted homebrew fighting style end-to-end o…
claude Jun 16, 2026
467c5e3
docs(kb): document the runtime-toggle / conditional-modifier mechanism
claude Jun 16, 2026
68f42e7
docs(kb): document AC computation model + custom-AC friction
claude Jun 16, 2026
7b7f3b3
test(ac): AC characterization visualization + settle single-class Monk
claude Jun 16, 2026
1edaa81
test(ac): rename characterization test to .clj (JVM-only; format unav…
claude Jun 16, 2026
c1f5496
feat(bridge): generalize per-bucket :fighting-style hook into a gener…
claude Jun 17, 2026
03faa9a
docs(kb): trace spell-granting across silos — same primitives, diverg…
claude Jun 17, 2026
ef1b6ea
docs(kb): declarative grant/select vocabulary — design + analysis
claude Jun 17, 2026
c9fb749
docs(kb): correct the feat-spell-template overstatement (maintainer c…
claude Jun 17, 2026
8b0e6f2
docs(kb): magic-item spells + usage-limits are text-only; compound gr…
claude Jun 17, 2026
e89fa82
docs(kb): consolidation pass on decision-vocabulary (de-bloat + de-du…
claude Jun 17, 2026
3fb58b9
docs(kb): class-features + mechanization + rolling layer (corrects 'n…
claude Jun 17, 2026
4a43e53
docs(kb): class features = a handful of distinct features + mostly sc…
claude Jun 17, 2026
a8c27a5
docs(kb): two custom-class entry points (template-from-base + filtera…
claude Jun 17, 2026
e4df9e3
docs(kb): editable references = key + overrides over structured/param…
claude Jun 17, 2026
b6b2b19
docs(kb): add roadmap.md — dependency-ordered layers + critical path
claude Jun 17, 2026
cc7cd17
test(foundation): class-feature characterization net — fighter baseline
claude Jun 17, 2026
a482708
test(foundation): class-feature regression net — all 10 classes basel…
claude Jun 17, 2026
09af807
test(foundation): strengthen the net with feature detail (summary + u…
claude Jun 17, 2026
0618ab8
feat(foundation): compile-feature proof — data schedule reproduces fi…
claude Jun 17, 2026
8c65f42
feat(foundation): structured effect + fill template — Sneak Attack di…
claude Jun 18, 2026
b8920f4
docs(kb): per-class feature catalogue (roadmap C1) — all 10 classes i…
claude Jun 18, 2026
b258639
fix(foundation): add druid + warlock — net + catalogue now cover all …
claude Jun 18, 2026
355f8ce
docs(kb): capture spell-slot progression — the :level-factor overload…
claude Jun 18, 2026
2fd8f40
docs: reconcile the two plans into one source (roadmap.md) + flag the…
claude Jun 18, 2026
8763c62
docs(decisions): backfill the D-log with this session's decisions (D2…
claude Jun 18, 2026
910dc3c
docs: capture grant/vocabulary analysis (D30–D31) + the prototype/zea…
claude Jun 19, 2026
8250d08
docs(kb): capture the verified class-builder capability trace (Artifi…
claude Jun 19, 2026
9ce6025
docs: correct the vocabulary A/B finding — B IS level-gated (traced u…
claude Jun 19, 2026
ab1df3a
docs: persist the standing verification rule + the old-vs-new compari…
claude Jun 19, 2026
41281b2
test(foundation): characterize spell-slot computation — pins baseline…
claude Jun 19, 2026
aec2931
test(foundation): characterize grant vocabulary A + record the cljc/c…
claude Jun 19, 2026
f6ed8bb
test(cljs): characterize grant vocabulary B in the headless harness —…
claude Jun 19, 2026
ade4fa0
test(ac): deepen AC characterization (armored/shield/tie-break/natura…
claude Jun 19, 2026
c68169d
test(foundation): .orcbrew round-trip characterization + the round-tr…
claude Jun 19, 2026
7781119
docs: incorporate agents/develop import insights — round-trip is loss…
claude Jun 19, 2026
47bf507
feat(grant): 4-mode grant compiler + feat-silo matrix proof (toward t…
claude Jun 19, 2026
5ec287d
test(grant): prove many custom styles are reachable by all/filter/spe…
claude Jun 20, 2026
655ba2a
docs: organize the KB README index (all 25 docs, sectioned) + drop by…
claude Jun 21, 2026
3988143
docs+test: map duplicate-key behavior across the content stack (verif…
claude Jun 21, 2026
2642f37
docs(key-collision): mark import-conflict edge cases out of scope for…
claude Jun 21, 2026
2fffbe1
docs(roadmap): add A4 — user-choice floating ASI (any silo), with fix…
claude Jun 22, 2026
b89aa00
feat(asi): layer 1 — compile-ability-increases (fixed+floating), prov…
claude Jun 22, 2026
4c75338
feat(asi): layer 2 — wire compile-ability-increases into race/subrace…
claude Jun 22, 2026
a9f08e9
feat(asi): layer 3 — race-builder authoring form for floating ASI (en…
claude Jun 22, 2026
5831a96
docs(harness): full-app headless E2E recipe — render/drive the real a…
claude Jun 22, 2026
050dbb9
Fix race-builder ASI widget string coercion; add full-app E2E
claude Jun 22, 2026
64db244
Template dropdown value coercion via :typed?; document the footgun
claude Jun 23, 2026
fa82c0b
Correct dropdown-coercion provenance: git-verified, not presumed
claude Jun 23, 2026
d2b2059
Decision log: fix duplicate D17, stub reversed D13, add status index
claude Jun 23, 2026
c63276c
Floating ASI layer 5: round-trip proven (orcbrew + character save/load)
claude Jun 23, 2026
a7c3392
Layer 5: prove export->import->use through the real UI (E2E)
claude Jun 23, 2026
8e33156
Fix: homebrew floating ASI choice now renders in the character builder
claude Jun 23, 2026
a52ffe7
Clarify: the :asi limit is floating-only; fixed + floating renders fully
claude Jun 23, 2026
8f56b36
Correct the floating-ASI limitation: it blocks standard Tasha's "+2/+1"
claude Jun 23, 2026
dfa111b
Record: filter-broadening is insufficient — :different? is per-selection
claude Jun 23, 2026
f5ec6d6
Exact-spread ASI backend: :amounts bag compiles to (stat,amount) options
claude Jun 24, 2026
cee3775
Exact-spread ASI widget: assign-from-bag picker (rendered-UI proven)
claude Jun 24, 2026
48b4b9c
Roadmap A4: exact-spread ASI RESOLVED via the :amounts bag
claude Jun 24, 2026
fac6ca9
Fix: bag widget restricts the floating pool to the creator's :from set
claude Jun 24, 2026
b99a7b9
Converge :ability-increases on the terse [amount pool] spread form
claude Jun 24, 2026
633ffd0
Docs: ability-increase-spreads KB + D33 (terse export data principle)
claude Jun 24, 2026
fea3886
Backward-compat guard for :ability-increases (overloaded field name)
claude Jun 24, 2026
a992279
Make :ability-increases handling a migration SHIM, not a silent drop
claude Jun 24, 2026
420ab3b
Drop the migration shim — there's nothing released to migrate
claude Jun 24, 2026
d7ddc99
Remove the dump-asi diagnostic test (no assertions, dev leftover)
claude Jun 24, 2026
29f30de
Comment the ability-increases-component spread branch
claude Jun 24, 2026
736027d
Roadmap A4: mark DONE + collapse the iteration narrative
claude Jun 24, 2026
a7359e8
Resolve D29: no duplicated functionality — one mechanism per job
claude Jun 25, 2026
10fe032
Record D34 (deprecation policy) + backfill ledger
claude Jun 25, 2026
f00394a
Backgrounds ASI: wire the spread through the background assembly
claude Jun 26, 2026
a9c3ce9
Backgrounds ASI: authoring UI + rendered-UI E2E
claude Jun 26, 2026
abc4df5
Docs: backgrounds ASI wired (spec + roadmap A4)
claude Jun 26, 2026
287219f
Opt-in toggle + subclass ASI
claude Jun 26, 2026
24175b0
Docs: subclass ASI + opt-in toggle (spec + roadmap A4)
claude Jun 26, 2026
19e842f
Prove multi-silo ASI containment with an E2E
claude Jun 28, 2026
8cf5f50
Prove multi-silo ASI export/import round-trip on a cleared browser
claude Jun 29, 2026
4694b76
Make the multi-silo round-trip an unbroken authored E2E
claude Jun 29, 2026
ac284b0
Add undated branch changelog for merge into CHANGELOG.md
claude Jun 29, 2026
91fcf2a
Feat-path ASI reconciliation: dual-format reader
claude Jun 29, 2026
e9fef6a
Save-proficiency grants: :save rider + standalone :save-proficiencies
claude Jun 29, 2026
ba79bc5
Authoring UI + rendered E2E for the save tools
claude Jun 29, 2026
8d66369
Docs: bring roadmap/README/changelog current with saves + feat reader
claude Jun 30, 2026
a2edfbe
Builder warn-and-explain for redundant/overlapping save coverage
claude Jun 30, 2026
e31ad96
Harden the non-save-rider test (was green but not protective)
claude Jun 30, 2026
d87d3f1
Extract builder-notes: one render for builder item-feedback (rule-of-…
claude Jun 30, 2026
91004c4
Nil-immune :boolean field type for the generated builder UI
claude Jun 30, 2026
63abd52
Drop the parallel toggle helper; defer :boolean to common/toggle-in
claude Jul 1, 2026
bfec387
Make the '+ save prof' rider toggle tested + self-healing
claude Jul 1, 2026
3217b59
Harden compile against messy paks + capture the toggle-primitive synt…
claude Jul 1, 2026
0420c1e
Codify data-safety layers (prevent/harden/heal/surface) + track pool-…
claude Jul 1, 2026
854e01b
Fix: fixed ASIs from non-racial silos were mis-attributed as racial
claude Jul 3, 2026
594c04c
Fix: floating ASI picks attributed to nothing; single-source attribution
claude Jul 3, 2026
e3d8c1a
Verify deselect + multiple-feat floating ASI edge cases
claude Jul 3, 2026
3eae0e9
Rendered multi-feat floating E2E via the (live) Homebrew mug
claude Jul 3, 2026
1ab16c0
Surface malformed ASI/save entries in the authoring form (harden → su…
claude Jul 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions .claude/summaries/2026-06-13-content-extensibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Session Summary: Content Extensibility Analysis

**Date**: 2026-06-13
**Branch**: claude/zen-wright-04xhdz

> ⚠️ **READ `docs/kb/content-extensibility-direction.md` FIRST.** The plan was deliberately
> **deflated** late in the session. Sections below (esp. "What we concluded", "How to
> resume", the two-layer / catalog-grant framing) are **history** — the direction doc is the
> real plan. Status: lots of code IS committed (Phases 0–4b, import-validation fixes,
> `save-character` fix, merged `feature/name-keyword-fix`); `by-parent` is slated for revert.

## The question

Why does adding a minor content type / builder to the 5e app touch ~8 files
(`routes.clj`, `route_map.cljc`, `db.cljs`, `events.cljs`, `spell_subs.cljs`,
`views.cljs`, `core.cljs`, plus a spec home)? Is there a less error-prone way that
keeps the standardization the codebase has?

## What we concluded

The cost is two separate problems, not one:

1. **Registration** — scattered, parallel boilerplate keyed by the same entity
(route, db default, localStorage, events, subs, page-map). Mechanical.
2. **Injection** — wiring new options into a *parent* entity (e.g. boons into the
warlock) via positional function arguments. This is the fragile, bug-prone half.

Proposed direction — two composable layers:

- **Layer 1: content-type registry.** One descriptor list feeding loops that call the
*existing* `reg-*-homebrew` factories. Kills the registration boilerplate.
- **Layer 2: type-addressed catalogs + grants.** Generalize the subrace
"bucket-by-key" pattern from `:race` to option *type*. Producers declare a type;
consumers `grant-choice` from a catalog with an optional filter. Keep `mod5e/*` for
fixed grants. Kills the positional injection and makes cross-aspect grants
(feat→spell, background→feat, feat→boon) uniform — homebrew flows in for free.

## Why it matters

Verified from code: subraces and subclasses already use the clean bucket-by-key
pattern; boons and invocations use fragile positional threading; draconic ancestries
are a static list with no plugin path. The proposal is to make the rest work like
subraces already do. It also answers a cluster of open issues in
`docs/issues/homebrew-builders.md` (#58, #57/#209, #172/#170, #210/#107, #280, #173,
#128).

## Files created (this branch)

| File | Purpose |
|------|---------|
| `docs/kb/content-extensibility.md` | Problem, verified cross-link map, proposed two-layer direction |
| `docs/kb/content-extensibility-decisions.md` | Decision audit (how the thinking evolved) + crisp decisions D1–D8 |
| `docs/kb/content-extensibility-compatibility.md` | Backward-compat audit: persisted formats, invariants, proposal assessment |
| `docs/kb/content-extensibility-plan.md` | Phased implementation playbook for low-context agents (gates, stop conditions) |
| `BRANCH.md` | Branch purpose + handoff + split-commit notes |
| `.claude/summaries/2026-06-13-content-extensibility.md` | This summary |

## How to resume

1. Read `docs/kb/content-extensibility.md` (design) and `-decisions.md` (the why).
2. To implement, follow `content-extensibility-plan.md` literally: Phase 0 builds a
golden test, then Phase 1 migrates **subraces** onto a generic injector
(behavior-preserving), then subclasses, boons/invocations, the registry, and finally
lineages. Each phase is gated and has stop conditions.
3. When split-committing these docs to `agents/develop`, add index rows for the two
KB docs to `docs/kb/README.md` there (this branch's index differs).

## Caveats for the next agent

- KB rule is verified-only content. The cross-link map is verified from code; the
design is labeled a proposal. Keep that boundary.
- File:line references were read on the monolithic frontend layout of this branch; on
`agents/develop` views are split (`views-builders-split.md`), so resolve view
references by symbol, not line.
- Backward compatibility is a hard constraint, audited in
`content-extensibility-compatibility.md`. The target is zero-migration: derive
catalogs over the existing plugin storage and preserve selection/option keys, then
prove it with an orcbrew + saved-character fixture before/after each migration.
- **Coordinate with `feature/name-keyword-fix`** (same base `d42e05d`): identity keys
derive from stable ids, not display names; `option-cfg` has a `::plugin-source` slot;
a reconciler heals orphaned keys. Two standing rules for the catalog/grant phases
(decisions D10/D11): pass each item's stored `:key` to `option-cfg` (never re-derive
from a display `:name`), and make catalogs layered/memoized `reg-sub`s referenced by
grants (never recompute a catalog in a hot sub). Guard both with comments.

## Implementation progress (code, this branch)
Phases 0, 1, 2 (subraces/subclasses via `option_catalog/by-parent`), 3a (key-lock
guard), 3b (`option_catalog/plugin-options`; boons/invocations), and 4a (the
`content_types.cljc` registry + audit test) are committed and gated green
(223 tests / 1106 assertions with the e2e fixture). Merged `feature/name-keyword-fix`
(`ec26955`); live-verified via PR #28 (all items PASS/covered, no regressions).
Remaining: 3c (positional-threading removal — risky, deferred), 4b–4f (wire the registry
into subs/db/events/routes/core — cljs, lint+review only here), Phase 5 (new builders).
See BRANCH.md for the live checklist.

## Test-suite debt found this session (separate from the extensibility work)
See `docs/kb/test-suite-state.md` (verified). Headline: **CI runs only the JVM gate
(`lein lint`/`lein test`); the cljs suite is never run and has rotted** — 10 failures /
3 errors pre-existing on `develop`, all real or removed-subject tests (not theater).
Notable: `character_test.cljc` references the `::character` spec Larry removed in the 2016
entity refactor (and duplicates the `.clj` test's namespace); the computed/built character
has no validation spec (the `save-character` null crash is a symptom). Working agreements
adopted: tests must be falsifiable (no theater); fix bugs on sight unless deep enough for
their own branch. Fixed the `save-character` null crash on sight (`42ceaaa8`).

**Load-bearing gotcha captured** (`docs/kb/built-character-representation.md`, anchored in
code): the built/computed character is a map whose derived values are deferred `:entity-fn?`
functions read via `entity-val` — NOT a flat map; don't `spec/keys` it. This is why the
computed character has no spec and why Larry's flat `::character` died.

**Deferred follow-ups — HIGHLIGHT AT BRANCH CLOSE** (also in BRANCH.md): (1) the
character-validation contract (own branch; charter in `character-validation.md`), and
(2) getting the cljs tests into CI (own branch; the cljs suite is unrun/rotted). Surface
both in the final PR/handoff so they aren't lost.

## Verification discipline + re-anchor (late session)
Several confident claims this session were wrong until verified (spec history, sub-vs-spec, which import tests failed). Lessons captured in `docs/kb/verification-discipline.md`: verify against real callers/intent/runtime before asserting; a red test means test+code DISAGREE, not that code is broken.

RE-ANCHOR: the branch's founding purpose is **content extensibility** (Phases 0–4b done; next core step = 4c, gated by the new headless cljs harness). The test-suite / import-validation triage is a semi-related tangent that produced the harness — which enables safely finishing 4c–4f. Don't let the tangent become the branch.

## DIRECTION DEFLATED (late session — read the direction doc)
After a readability review the grand registry / catalog-grant DSL was **deliberately
scaled back**. Authoritative plan now: `docs/kb/content-extensibility-direction.md`.
Principle: an abstraction earns its keep only if it's thicker than what it hides and
reveals intent (`by-parent` failed this → revert to `group-by`). Agreed shape: a
descriptor + `register-homebrew-content!` HOF composing the existing factories, scoped
to mechanical boilerplate; keep readable data (`default-value`) explicit; magic-item
stays its own server-backed registrar; do NOT build a catalog/grant DSL.
Audit: 12 types share the shape (6 basic, 6 +`:builder-features`), 3 deviate.
cljs verification recipe: `docs/kb/cljs-headless-harness.md` (ephemeral; rebuild).
Next: revert by-parent; swap boon through the HOF + commit; create a NEW builder to
measure effort. Goal: stabilize while adding features.
Loading