Migration 015 did a one-time rebuild of recipes_fts at creation time but
omitted triggers, so rows inserted after that point were invisible to MATCH
queries. Adds AFTER INSERT/UPDATE/DELETE triggers to 015 (fresh DBs / tests)
and migration 016 to backfill them on existing databases.
Fixes 3 failing tests: test_search_recipes_by_ingredient_names,
test_level1_returns_ranked_suggestions, test_level2_returns_swap_candidates.
- build_recipe_index.py: add _parse_r_vector() for food.com R format, add
_parse_allrecipes_text() for corbt/all-recipes text format, _row_to_fields()
dispatcher handles both columnar (food.com) and single-text (all-recipes)
- build_flavorgraph_index.py: switch from graph.json to nodes/edges CSVs
matching actual FlavorGraph repo structure
- download_datasets.py: switch recipe source to corbt/all-recipes (2.1M
recipes, 807MB) replacing near-empty AkashPS11/recipes_data_food.com
- 007_recipe_corpus.sql: add UNIQUE constraint on external_id to prevent
duplicate inserts on pipeline reruns
Uses circuitforge_core.tasks.scheduler. VRAM detection via cf-orch when
available, falling back to unlimited. Adds expiry_llm_fallback task type
to background-predict expiry dates for items the LUT doesn't cover.