Populates question.pack_id (build_db.py). The column was plumbed end to end
(question.pack_id -> QuestionEntity.packId -> Question.packId) but was NULL for
all 3811 rows, so content had no pack identity. Bundled packs now carry one —
the logical id a pack declares in metadata (daily ships as category
daily_fun_mc but is logically daily_single_choice_weekly_v1), else its category
id. This is the hook a purchased/imported pack needs: it becomes just another
pack_id in the same table rather than a special case. No schema or behaviour
change; identity hash unchanged.
Fixes two regressions the rebuilt db exposed, both latent for the same reason:
every category previously carried the placeholder icon_name "question", which
masked them. Packs now declare real Material icon names (shield, forum, paid).
1. Category glyphs. categoryGlyphStyle keyed on `iconName ?: categoryId`, so
icon_name won. Material names are a different vocabulary from this file's
keys, so 22 of 23 categories fell through to the default star. The curated
per-category glyph now wins, with icon_name as the fallback — which is also
what gives an imported pack a real glyph, since its category_id will not be
listed here but its declared icon_name resolves. Added the Material aliases
and the two unmapped categories (quality_time, daily_fun_mc).
2. Pack library chips. metadataLabels() rendered the raw icon_name as a
user-facing tag, producing chips like "Chat Bubble Outline". It was only ever
invisible because the list filtered the single value "Question". icon_name is
a rendering detail, not a topic, so the chip is gone; access remains.
Verified live on both fixtures (dark 5554 / light 5556): distinct correct glyphs
(Boundaries warning, Communication chat, Rebuilding Trust shield, Sex & Desire
heart-outline), no leaked chips, and the new Quality Time pack browsable with
150 questions and a calendar glyph. Unit tests green, 0 FATAL.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>