Files
bookhoard/cmd/server/tests
John O'Keefe 6b2125a45a feat(podcasts): smart collections ride the unified filter engine — filter_tree column (item 3.2)
collections gains filter_tree JSONB (idempotent in-place; same qf DSL
as saved filters — the scope key included). IsCollectionSmart is the
ONE detection (tree OR legacy rules), and EvaluateSmartMembership is
the ONE evaluator: tree-bearing collections run the composed engine
via ComposedLiveMedia (full media rows, so the collection surfaces
keep their episode-card stamping, feed positions for the replay
chain, and the family lens rides the mandatory head), while legacy
rule arrays keep per-item FieldMatches until rewritten — one call
surface, two storage epochs. All smart surfaces (detail JSON, counts,
detail page, reader chain) dispatch through it; the search service is
injected into the collection subsystem (variadic — main.go builds one
shared instance; the test harness mirrors it).

Write path: CreateCollection/UpdateCollection accept the tree,
validated against the engine grammar at the HANDLER (an invalid tree
is a 400, never a stored render-time 500) and exposed in the envelope
(pin widened in TestContractPin_CollectionsJSON + changelog). Update
semantics: an edit form that doesn't send a tree keeps the stored one.

RulesToFilterTree converts legacy rules + match mode at upgrade time:
episode rules map mechanically (feed→in-list, played/downloaded→
booleans, published_within→published_date+within_days), tree root
mode absorbs rule_match_mode, episode rules force the episodes scope,
and legacy starts_with/ends_with fall back to contains (documented).

Read-compat by design: nothing is migrated at boot — legacy arrays
evaluate exactly as before until the collection is rewritten.

Pinned by TestRulesToFilterTree (unit conversion) +
TestEpisodeCollectionsFilterTree (a tree collection evaluates through
the engine, the chain follows the tree's live membership, invalid
trees 400 at write, the tree wins when legacy rules coexist, and an
edit without a tree keeps it).
2026-10-30 19:02:49 -04:00
..