test(pins): widen whitelist for the episode-collections JSON shapes (item 2 series)

TestContractPin_CollectionsJSON tripped on the additive keys the
episode-collections work introduced — the tripwire worked exactly as
designed (additive keys must be whitelisted here AND in
docs/contract_pins.md first).

- Collections envelope gains rule_match_mode (item 2.4): the
  smart-collection match semantics on GET /api/collections/:id.
- BookInfo gains four STABLE keys (item 2.3): is_episode,
  feed_title, download_state, hidden — dropped omitempty so every
  card surface emits the same key set (the viewer_percentage
  precedent; adapters that predate episode awareness emit zero
  values).

docs/contract_pins.md changelog entry written. Nothing removed,
nothing renamed.
This commit is contained in:
John O'Keefe committed 2026-10-30 17:25:22 -04:00
1 parent 962f9089e0
commit bc91ce68d4
3 files changed
+24 -5

No files matched your search

+8 -5
View File
@@ -50,11 +50,14 @@ type BookInfo struct {
// LEFT JOIN missed under RLS (unsubscribed episode, or a
// family-lens hidden book) — the row renders as an "unavailable"
// hint instead of silently vanishing. Adapters that don't load
// visibility leave Hidden false (cards stay fully rendered).
IsEpisode bool `json:"is_episode,omitempty"`
FeedTitle string `json:"feed_title,omitempty"`
DownloadState string `json:"download_state,omitempty"`
Hidden bool `json:"hidden,omitempty"`
// visibility leave Hidden false (cards stay fully rendered). The
// four keys are NOT omitempty: every BookInfo surface emits the
// same stable key set (the viewer_percentage precedent —
// contract-pin widening, docs/contract_pins.md 2026-10-30).
IsEpisode bool `json:"is_episode"`
FeedTitle string `json:"feed_title"`
DownloadState string `json:"download_state"`
Hidden bool `json:"hidden"`
}
// LibraryTypeMap builds libraryID→library-type-name for badge resolution