Commit graph

47 commits

Author SHA1 Message Date
bd73ca0b6d fix(tests): correct build endpoint test fixture
- Use monkeypatch.setattr to patch cloud_session._LOCAL_KIWI_DB
  instead of wrong KIWI_DB_PATH env var (module-level singleton
  computed at import time; env var had no effect)
- Assert id > 0 (real persisted DB id) instead of -1 (old
  pre-persistence sentinel value)
2026-04-14 14:57:16 -07:00
9941227fae chore: merge main into feature/meal-planner
Resolves three conflicts:
- app/api/routes.py: fixed saved_recipes-before-recipes ordering from main;
  meal_plans and community_router from feature branch
- app/db/store.py: meal plan/prep session methods (feature) + community
  pseudonym methods (main) -- both additive
- app/tiers.py: KIWI_BYOK_UNLOCKABLE includes meal_plan_llm,
  meal_plan_llm_timing (feature) and community_fork_adapt (main)
2026-04-14 14:53:52 -07:00
144d1dc6c4 chore: commit in-progress work -- tag inferrer, imitate endpoint, hall-of-chaos easter egg, migration files, Dockerfile .env defense
- app/services/recipe/tag_inferrer.py: infer tags from recipe ingredient text
- app/db/migrations/022_recipe_generic_flag.sql, 029_inferred_tags.sql: schema migrations
- app/api/endpoints/imitate.py: recipe imitation endpoint stub
- app/api/endpoints/community.py: hall-of-chaos easter egg endpoint
- scripts/pipeline/infer_recipe_tags.py, backfill_keywords.py: pipeline scripts
- scripts/pipeline/build_recipe_index.py: extended index builder
- Dockerfile: explicit .env removal as defense-in-depth
- frontend/src/components/FeedbackButton.vue: feedback UX improvements
- frontend/src/style.css: minor style tweaks
- app/cloud_session.py: cloud session improvements
- tests/api/test_community_endpoints.py: additional test coverage
2026-04-14 13:23:15 -07:00
8c4965123f feat: add GET /templates, GET /template-candidates, POST /build endpoints
Wires the three Build Your Own API routes into the recipes router,
registered before the catch-all /{recipe_id} route to avoid shadowing.
Adds 5 endpoint tests covering template list count/shape, candidate
response structure, successful recipe build, and 404 on unknown template.
2026-04-14 11:45:43 -07:00
c02e538cb2 feat: remove assembly results from suggest() -- moved to Build Your Own tab 2026-04-14 11:39:57 -07:00
da940ebaec feat: add get_role_candidates() and build_from_selection() to assembly engine
Both functions are DB-free public API additions to assembly_recipes.py.
get_role_candidates() scores pantry candidates against a wizard step using
element-profile overlap with prior picks; build_from_selection() builds a
RecipeSuggestion from explicit role overrides with required-role validation.
2026-04-14 11:06:08 -07:00
4f1570ee6f feat: add Store.get_element_profiles() for wizard role candidate lookup 2026-04-14 10:50:46 -07:00
1a5fb23dfd feat: add slug/icon/descriptor to AssemblyTemplate and get_templates_for_api()
Extends AssemblyTemplate dataclass with slug, icon, descriptor, and
role_hints fields. Updates all 13 template instantiations with
appropriate values. Adds _TEMPLATE_BY_SLUG lookup dict and
get_templates_for_api() serialiser for the templates endpoint.
2026-04-14 10:36:58 -07:00
65ef65bb4c feat: add Pydantic schemas for Build Your Own tab endpoints 2026-04-14 09:45:05 -07:00
9c64de2acf feat(community): community API endpoints — browse, publish, fork, delete, RSS, AP
Adds GET /community/posts, GET /community/posts/{slug}, GET /community/feed.rss,
GET /community/local-feed, POST /community/posts, DELETE /community/posts/{slug},
POST /community/posts/{slug}/fork, and POST /community/posts/{slug}/fork-adapt (501 stub).
Wires init_community_store into main.py lifespan. 7 new tests; 115 total passing.
2026-04-13 11:14:18 -07:00
81107ed238 feat(community): KiwiCommunityStore + pseudonym helpers in per-user store 2026-04-13 10:54:13 -07:00
b1ed369ea6 feat(community): mDNS advertisement via zeroconf — defaults OFF, opt-in per a11y audit 2026-04-13 09:59:50 -07:00
f12699349b feat(community): RSS 2.0 feed generator + ActivityPub JSON-LD scaffold 2026-04-13 09:44:51 -07:00
74c7272a50 feat(community): element snapshot — SFAH scores, allergen detection, dietary tags 2026-04-13 09:19:57 -07:00
b97cd59920 feat(community): migration 028 — community_pseudonyms table in per-user kiwi.db 2026-04-13 08:13:39 -07:00
482666907b fix(meal-planner): validate meal_type path param, enforce store whitelist safety, add week_start date validation, make PrepTask frozen
- upsert_slot: raise 422 immediately if meal_type not in VALID_MEAL_TYPES
- update_prep_task: assert whitelist safety contract after dict comprehension
- CreatePlanRequest: week_start typed as date with must_be_monday validator; str() cast at call site
- PrepTask: frozen=True; build_prep_tasks rewired to use (priority, kwargs) tuples so frozen instances are built with correct sequence_order in one pass (no post-construction mutation)
- Move deferred import json to file-level in meal_plans.py
- Fix test dates: "2026-04-14" was a Tuesday; updated request bodies to "2026-04-13" (Monday)
2026-04-12 13:51:50 -07:00
98087120ac feat(api): add /api/v1/meal-plans/ endpoints — CRUD, shopping list, prep session
refs kiwi#68 kiwi#71
2026-04-12 13:44:01 -07:00
25027762cf feat(services): add prep_scheduler — sequences batch cooking tasks by equipment priority 2026-04-12 13:14:54 -07:00
4459b1ab7e feat(services): add shopping_list service with pantry diff
refs kiwi#68
2026-04-12 13:14:08 -07:00
594fd3f3bf feat(tiers): move meal_planning to Free; add meal_plan_config/llm/llm_timing keys
refs kiwi#68
2026-04-12 13:12:11 -07:00
f3bc796f2c feat: migrate feedback endpoint to circuitforge-core router
Replace hand-rolled feedback.py with make_feedback_router() from
circuitforge_core.api.feedback. Update tests to mount the shared
router on a minimal FastAPI app and mock at the core module level.
2026-04-05 17:57:36 -07:00
6a59c8dfd1 fix: row_factory in _household_store; validate household_id from Heimdall; monkeypatch CLOUD_DATA_ROOT in accept test; add KIWI_BASE_URL to compose.cloud.yml 2026-04-04 22:59:06 -07:00
7650747651 feat: household API endpoints (create, status, invite, accept, leave, remove-member) 2026-04-04 22:45:12 -07:00
ed6813713e test: use tmp_path for _user_db_path tests; remove duplicate comment
Patch _user_db_path tests to monkeypatch CLOUD_DATA_ROOT onto a
tmp_path so they never touch /devl or any real filesystem path.
Remove duplicate X-Real-IP comment block in cloud_session.get_session.
2026-04-04 22:38:41 -07:00
9985d12156 feat: extend CloudUser with household_id + update session resolution
Add household_id and is_household_owner fields to CloudUser dataclass.
Update _user_db_path to route household members to a shared DB path.
Update _fetch_cloud_tier to return a 3-tuple and cache a dict.
Update get_session to unpack and propagate household fields.
2026-04-04 22:30:07 -07:00
6791ea22b2 feat: complete feedback button — status probe, requests dep, tests
- feedback.py: add GET /feedback/status endpoint (returns {enabled: bool})
  so frontend can probe on mount instead of optimistic-enable; remove
  unused get_db import
- FeedbackButton.vue: probe /feedback/status on mount, start hidden;
  drop redundant 503-hide path (status probe makes it redundant)
- pyproject.toml: declare requests>=2.31 (used by feedback.py Forgejo calls)
- tests/api/test_feedback.py: 7 tests — status endpoint (no-token, token,
  demo mode), POST 503/403, happy path with mocked Forgejo, 502 on error
2026-04-03 16:52:40 -07:00
b9c308ab28 fix: docuvision fast-path falls through when parse yields no items
_parse_json_from_text always returns a dict (never None), so the
previous `if parsed is not None` guard was permanently true — garbled
docuvision output would return an empty skeleton instead of falling
through to the local VLM. Replace the check with a meaningful-content
test (items or merchant present). Add two tests: one that asserts the
fallthrough behavior on an empty parse, one that confirms the fast path
is taken when parsing succeeds.
2026-04-02 13:49:38 -07:00
3016efa65b fix: address recipe/OCR quality issues from review 2026-04-02 12:41:59 -07:00
22e57118df feat: add DocuvisionClient + cf-docuvision fast-path for OCR
Introduces a thin HTTP client for the cf-docuvision service and wires it
as a fast path in VisionLanguageOCR.extract_receipt_data(). When CF_ORCH_URL
is set, the pipeline attempts docuvision allocation via CFOrchClient before
loading the heavy local VLM; falls back gracefully if unavailable.
2026-04-02 12:33:05 -07:00
33a5cdec37 feat: cloud auth bypass, VRAM leasing, barcode EXIF fix, pipeline improvements
- cloud_session.py: CLOUD_AUTH_BYPASS_IPS with CIDR support; X-Real-IP for
  Docker bridge NAT-aware client IP resolution; local-dev DB path under
  CLOUD_DATA_ROOT for bypass sessions
- compose.cloud.yml: thread CLOUD_AUTH_BYPASS_IPS from shell env; document
  Docker bridge CIDR requirement in .env.example
- nginx.cloud.conf + nginx.conf: client_max_body_size 20m for barcode uploads
- barcode_scanner.py: EXIF orientation correction (PIL ImageOps.exif_transpose)
  before cv2 decode; rotation coverage extended to [90, 180, 270, 45, 135]
  to catch sideways barcodes the 270° case was missing
- llm_recipe.py: CF-core VRAM lease acquire/release wrapping LLMRouter calls
- tasks/runner.py + config.py: COORDINATOR_URL + recipe_llm VRAM budget (4GB)
- recipes.py: per-request Store creation inside asyncio.to_thread worker to
  avoid SQLite check_same_thread violations
- download_datasets.py: HF_PARQUET_FILES strategy for repos without dataset
  builders (lishuyang/recipepairs direct parquet download)
- derive_substitutions.py: use recipepairs_recipes.parquet for ingredient
  lookup; numpy array detection; JSON category parsing
- test_build_flavorgraph_index.py: rewritten for CSV-based index format
- pyproject.toml: add Pillow>=10.0 for EXIF rotation support
2026-04-01 16:06:23 -07:00
1c9221d27c Merge branch 'feature/shared-task-scheduler' 2026-03-31 14:27:51 -07:00
9371df1c95 feat: recipe engine Phase 3 — StyleAdapter, LLM levels 3-4, user settings
Task 13: StyleAdapter with 5 cuisine templates (Italian, Latin, East Asian,
Eastern European, Mediterranean). Each template includes weighted method_bias
(sums to 1.0), element-filtered aromatics/depth/structure helpers, and
seasoning/finishing-fat vectors. StyleTemplate is a fully immutable frozen
dataclass with tuple fields.

Task 14: LLMRecipeGenerator for Levels 3 and 4. Level 3 builds a structured
element-scaffold prompt; Level 4 generates a minimal wildcard prompt (<1500
chars). Allergy hard-exclusion wired through RecipeRequest.allergies into
both prompt builders and the generate() call path. Parsed LLM response
(title, ingredients, directions, notes) fully propagated to RecipeSuggestion.

Task 15: User settings key-value store. Migration 012 adds user_settings
table. Store.get_setting / set_setting with upsert. GET/PUT /settings/{key}
endpoints with Pydantic SettingBody, key allowlist, get_session dependency.
RecipeEngine reads cooking_equipment from settings when hard_day_mode=True.

55 tests passing.
2026-03-31 14:15:18 -07:00
0d65744cb6 feat: StyleAdapter — 5 cuisine templates with element dimension biasing 2026-03-31 12:54:42 -07:00
ce61b5f422 feat: recipe + staple API endpoints with tier gating 2026-03-31 12:49:38 -07:00
e8fb57f6a2 feat: RecipeEngine Level 1-2 — grocery links + affiliate deeplink builder
Add GroceryLink schema model and grocery_links field to RecipeResult.
Introduce GroceryLinkBuilder service (Amazon Fresh, Walmart, Instacart)
using env-var affiliate tags; no links emitted when tags are absent.
Wire link builder into RecipeEngine.suggest() for levels 1-2.
Add test_grocery_links_free_tier to verify structure contract.

35 tests passing.
2026-03-31 12:23:07 -07:00
37737b06de feat: RecipeEngine Level 1-2 — corpus match, substitution, grocery list, hard day mode 2026-03-31 11:50:28 -07:00
3c4f568b3e feat: store — recipe search, rate-limit check, substitution feedback logging 2026-03-31 11:29:54 -07:00
636bffda5a feat(tasks): add background task scheduler for LLM expiry fallback
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.
2026-03-31 09:25:48 -07:00
3527d61655 fix: test fixture — add protein_delta to substitution_pairs inserts 2026-03-30 23:16:15 -07:00
96850c6d2a feat: SubstitutionEngine — deterministic swap candidates with compensation hints 2026-03-30 23:13:49 -07:00
e57ae74e27 fix: staple library — consistent tofu_firm slug, load error handling, typed yield_formats, expanded test coverage 2026-03-30 23:10:51 -07:00
a03807951b fix: ElementClassifier — guard empty input, safe JSON decode, dedup heuristic elements, strengthen test assertions 2026-03-30 23:10:49 -07:00
e377bd85aa feat: ElementClassifier -- ingredient element tagging with heuristic fallback 2026-03-30 22:59:46 -07:00
bad6dd175c feat: data pipeline -- recipe corpus + substitution pair derivation 2026-03-30 22:55:41 -07:00
27ec14b40f feat: tiers -- leftover_mode rate-limited free, style_picker paid+, staple_library free 2026-03-30 22:50:35 -07:00
59b6a8265f feat: data pipeline -- FlavorGraph molecule index builder 2026-03-30 22:46:53 -07:00
97203313c1 feat: data pipeline -- USDA FDC ingredient index builder 2026-03-30 22:44:25 -07:00