feat: v1.10.0 — allergens, multi-image recipes, public sharing#326
Merged
Conversation
…314) (#319) PR 1 of 4 toward v1.10.0. Targets feature/allergens-v1.10.0. Schema: - allergens table with global Big 9 seed (family_id null) + per-family customs - member_allergens pivot (UUID-keyed, flat user↔allergen binary) - users.allergen_profile_reviewed_at nullable timestamp (drives dashboard prompt) Backend: - Allergen model with availableToFamily(string $familyId) scope (Big 9 union customs) - MemberAllergen pivot model (HasUuids) - AllergenPolicy: parents may create; only the owning family may rename/delete their own customs; Big 9 are immutable for everyone - AllergenController: list / add / rename / delete customs - UserAllergenController: read / replace member profile + mark-reviewed. Parents may edit anyone; members may edit only their own. Cross-family access 404s. PUT with empty array still counts as "reviewed". - Routes gated by `module:food` middleware (food disabled → 403 on all paths) Vue (Composition API, design-system aligned, mobile-first): - Pinia allergens store (list + per-member profiles + CRUD actions) - AllergenSelector: chip-based multi-select. Big 9 row + family customs row. Reusable; recipe form (PR 2) will consume it. - AllergyProfileEditor: wraps selector + Save / "Confirm: no allergies" - AllergyProfileReviewBanner: dashboard banner shown until current member's profile has been reviewed (food module on + profile loaded + not yet reviewed) - FamilyAllergenSettings: Big 9 read-only chips + family customs list with inline rename/delete (parents only) + add-custom form - Settings: new "Allergens" collapsible section (parents) and "My Allergies" card (members), both hidden when food module is off - Dashboard: mounted the review banner above the widget grid Tests: 19 new in AllergenTest covering Big 9 seed, CRUD permission matrix, member profile read/write/mark-reviewed, cross-family scoping, module gating. Total suite: 383 tests, 1004 assertions, green. Manually verified in preview: banner → /settings#allergens → add Cinnamon → toggle Peanuts on Adaeze → Save → banner disappears on dashboard. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…320) * feat: recipe allergen tagging (manual) — pivot, badges, form, detail (#315) PR 2 of 4+1 toward v1.10.0. Targets feature/allergens-v1.10.0. Schema: - recipe_allergens pivot: (recipe, allergen, presence, source, confidence, confirmed_by, confirmed_at), UUID-keyed via RecipeAllergen pivot model. Unique on (recipe_id, allergen_id, presence) so the same allergen can be carried at both contains and may_contain on one recipe. - AllergenPresence enum: contains | may_contain - AllergenSource enum: ai_auto | ai_suggested | human_confirmed | imported (only human_confirmed is written in this PR; AI sources land in #317) Backend: - Recipe::allergens() BelongsToMany with pivot fields - StoreRecipeRequest + UpdateRecipeRequest accept `allergens: [{allergen_id, presence}]` with enum validation - RecipeService::syncAllergens replaces a recipe's allergen list. All rows written by the form path are stamped human_confirmed + confirmed_by/at. availableToFamily() guard silently drops any allergen not visible to the recipe's family. - RecipeAllergenController for single-row edits: POST adds (idempotent on duplicate via firstOrCreate), PATCH confirms / changes presence / removes. Used by recipe detail (PR 4 wires AI-tag confirmations through it). - RecipeResource exposes allergens with full pivot shape (presence, source, confidence, confirmed_at) so the frontend can render unconfirmed badges in PR 4 without touching the API again. - show + searchRecipes eager-load allergens Vue: - AllergenBadge: single allergen chip. Contains = status-error tint; may_contain = status-warning + dashed border. Optional `unconfirmed` prop reserved for PR 4 (subtle opacity + dashed outline). - AllergenBadgeRow: wraps a recipe.allergens array into a badge row with optional `limit` + "+N more" indicator (used on cards). - RecipeForm: new Allergens section with tri-state cycle per chip (off → contains → may_contain → off). Tap once / twice / three times. Hidden when food module is off. Auto-loads allergens on mount. - RecipeCard renders AllergenBadgeRow under the card (limit 3). - RecipeDetailView renders the full badge row inline with meta info. Tests: 16 new in RecipeAllergenTaggingTest. Total suite: 399 tests, 1048 assertions, green. Pint clean, PHPStan clean. Manually verified in preview: edit Banana Bread → cycle Wheat (contains) + Tree nuts twice (may_contain) → Update → detail page shows "Wheat / gluten" + "May contain tree nuts" → recipes list also surfaces the badges on the card. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: clarify Family Allergens header as informational, not selectable The read-only Big 9 chip row in FamilyAllergenSettings was visually indistinguishable from the selectable chips in the per-member AllergyProfileEditor below, leading a tester to assume those top chips should be clickable. Replaced with a single descriptive line that names the Big 9 and points users to the per-member profiles below for actual selection. The selectable chips remain unchanged — they continue to live inside each member's AllergenSelector (still includes Big 9 + family customs). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat: allergen filtering + meal planner safety guard (#316) PR 3 of 4+1 toward v1.10.0. Targets feature/allergens-v1.10.0. Recipe list filtering: - searchRecipes() accepts safe_for_members[]=<member_id> and safe_for=all. Excludes any recipe carrying a contains|may_contain allergen on the given reviewed-profile members. Members without a reviewed profile are silently dropped — better to under-filter than to mark a recipe "safe for someone we never asked about." - RecipeController index forwards the new params. UI — Safe-for filter chip: - SafeForMemberFilter.vue: dropdown chip listing family members with reviewed profiles. Multi-select with checkboxes. Loads each member's profile lazily. - Wired into RecipesTab toolbar (food module only). Selection drives a refetch via the recipes store's new safeForMemberIds state. Meal planner safety: - AllergenAcknowledgementRequired exception renders 409 with hits[] and requires_acknowledgement=true. - MealPlanService::addEntry() checks the recipe against reviewed family profiles. Throws unless data.acknowledge_allergens === true. - StoreMealPlanEntryRequest accepts the acknowledge_allergens flag. - MealPlannerAllergenWarning.vue: modal grouping hits by member, severity-coded copy (contains = red, may_contain = yellow), explicit "I understand, plan anyway" button. - mealsStore.addEntry surfaces requiresAllergenAck + retry callback when 409 comes back. MealEntryPicker shows the modal and re-submits with the acknowledgement on confirm. Tests: 9 new in AllergenFilteringTest (safe_for_members excludes correctly, may_contain treated as unsafe, safe_for=all skips unreviewed members, empty-allergen member returns everything, unreviewed member silently skipped, planner refuses without ack, acknowledged plan succeeds, no-allergen recipe proceeds, unreviewed-profile match does not block). Total suite: 417 tests, 1098 assertions, green. Manually verified in preview: Adaeze (peanuts profile) + Chocolate Chip Cookies (peanuts) — list filter excludes the recipe; planner returns 409 with hit details; modal renders with member + allergen; "I understand" re-submits with acknowledge_allergens=true and the entry lands. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: allergen palette renders as red — was silently transparent (status-error → status-failed) The allergen UI was authored against Tailwind tokens `bg-status-error`, `text-status-error`, `border-status-error` and friends — but the design system only ships `status-failed` (Kinhold convention for red). Tailwind silently generated no CSS for the `-error` variants, so: - the "contains" chip in the recipe form rendered as the default sunken pill (Greg: "turns white which doesn't feel selected") - AllergenBadge "contains" rendered as ink text on no background - MealPlannerAllergenWarning's red iconography + per-member bullets were monochrome - inline error messages in FamilyAllergenSettings / AllergyProfileEditor rendered as default ink Renamed every `status-error` reference across the five new allergen-related components + RecipeForm to `status-failed`. Also bumped the contains chip in the recipe form to a solid fill (`bg-status-failed text-white border-status-failed`, `border-2`, `font-semibold`) so the selected state reads as unambiguous before the user even sees the label change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…322) PR 4 of 4+1 toward v1.10.0. Targets feature/allergens-v1.10.0. AI extraction on import: - Both URL_SYSTEM_PROMPT and PHOTO_PROMPT are now built dynamically per family (Big 9 + family customs) so the model returns slug-anchored allergen tags. - Prompts ask the model to emit `allergens: [{slug, presence, confidence}]` with conservative rules and explicit guidance for sneaky cases (wheat in soy sauce / beer, milk in butter / cream, eggs in mayo). - JSON-LD imports skip the LLM entirely, so we run a separate `extractAllergensFromIngredients()` pass over the parsed ingredient list so coverage is consistent across import methods. Confidence routing: - `persistAiAllergens()`: confidence ≥ 0.95 → source = ai_auto. Otherwise source = ai_suggested. Idempotent on (recipe, allergen, presence). Never overwrites a human-confirmed row. Frontend: - `RecipeForm.populateFromImportPreview()` now translates AI's `{slug, presence, confidence}` shape to the form's `{allergen_id, presence}` shape, fetching the allergens store if it hasn't loaded yet. Result: AI suggestions land pre-checked in the form, the user can adjust or accept. - `AllergenBadgeRow` gets an `editable` mode. Unconfirmed (ai_auto / ai_suggested) badges render with a small `✓` button beside them; clicking hits PATCH and flips the row to human_confirmed. - `RecipeDetailView` passes `editable={isParent}` so only parents can confirm AI tags. - `RecipeResource` now exposes `pivot_id` so the frontend can target the pivot row by ID for confirm. - `recipesStore.confirmAllergen()` patches in place and stamps the local recipe's source so the badge re-renders without a refetch. Backfill: - `php artisan recipes:backfill-allergens` command with `--family`, `--force`, and `--sync` flags. Dispatches `BackfillRecipeAllergens` job per recipe. Idempotent: skips recipes with existing rows unless `--force`. - Parent-only `POST /api/v1/recipes/allergens/backfill` endpoint queues the same jobs for the requesting family. Returns the count queued. - `BackfillRecipeAllergens` job is safe to re-run: skips already-tagged recipes, skips recipes with no ingredients, swallows extraction failures with a warning log (no retries that would chew through API budget). No-AI fallback: - The dynamic prompt builder is purely additive — when AI is disabled or fails, the existing manual tagging path from PR2 is unchanged. JSON-LD imports also still work without AI; the secondary allergen pass returns an empty array if the family has no AI configured. Tests: 11 new in AllergenAiIntegrationTest covering confidence routing, idempotency, ignoring unknown slugs, PATCH confirm → human_confirmed + confirmed_by stamping, pivot_id exposure in RecipeResource, parent-only backfill endpoint, queueing logic with/without --force, job idempotency on already-tagged recipes, job no-op on empty ingredients, mocked extraction flow end-to-end. Total suite: 419 tests, 1098 assertions, green. Manually verified in preview: parent user → recipe detail view → manually flipped a row to ai_suggested via SQL → page reload showed dashed "unconfirmed" badge + green checkmark button → click confirm → API PATCH → source becomes human_confirmed → checkmark disappears, badge becomes solid. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…) (#324) PR 5 of 6 toward v1.10.0. Targets feature/allergens-v1.10.0. Sub-PR carved out of #311 (public sharing) because cookbook-scan thumbnails make sharing pages look bad; multi-image is the prerequisite. Schema: - recipe_images table: (recipe_id, path, sort_order, is_primary, timestamps) UUID-keyed. - Data migration backfills existing recipes.image_path into a single primary recipe_images row per recipe. recipes.image_path stays as a denormalized cache of the primary's path so cards / cross-cutting readers don't break. Backend: - Recipe::images() HasMany sorted by sort_order - RecipeImage model (HasUuids, casts is_primary/sort_order) - RecipeService::syncImages(): diff against existing rows by id (preserves IDs across edits), creates new rows for new paths, deletes dropped paths. Sets is_primary based on the first image (or explicit flag). Mirrors the primary path into recipes.image_path. - StoreRecipeRequest + UpdateRecipeRequest accept `images: [{id?, path, sort_order?, is_primary?}]` - Legacy single image_path still works (gets converted into a single primary image entry by the service) - RecipeResource exposes `images: [{id, path, sort_order, is_primary}]`; show() + searchRecipes() eager-load the relation Frontend: - RecipeImageGallery: thumbnail strip with drag-to-reorder (SortableJS), tap-to-set-primary (star button), delete (trash button), and an "Add photo" tile that handles multi-file upload. Primary thumbnail wears a lavender border + Primary badge. Uploading shows a dimmed local preview until the server returns a path. - RecipeForm wires the gallery to form.images and ships the full list on Save. Replaces the single PhotoUpload. - RecipeDetailView: hero of the primary image + scrollable thumbnail row of extras below. Tap a thumbnail to swap the hero (client-side only; doesn't change the saved primary). This sets the pattern PR6 will reuse on the public sharing page. Tests: 8 new in RecipeImageGalleryTest — multi-image create, image_path sync to primary, first-image-becomes-primary default, update swaps primary + appends new, subset removes dropped, empty array clears, RecipeResource ordering, legacy image_path-only save still works. Total suite: 427 tests, 1125 assertions, green. Manually verified in preview: existing seeded recipe loaded with backfilled image as Primary chip; gallery shows the helper copy and an Add photo tile; can navigate the form without errors. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat: public recipe sharing — token URLs + beautiful Blade page (#311) PR 6 of 6 toward v1.10.0. Final sub-PR. Targets feature/allergens-v1.10.0. Schema: - recipes.share_token (string, nullable, unique) — null = not shared. - recipes.share_visible_attribution (boolean, default false) — anonymous by default. Owner opts in to surface the family name. Backend: - RecipeShareController: parent-only - POST /api/v1/recipes/{id}/share — mints a 22-char base62 token (~131 bits of entropy). Idempotent: re-calling on an already-shared recipe returns the same URL. Optional visible_attribution flag on initial publish. - PATCH /api/v1/recipes/{id}/share — toggles attribution without rotating the token. - DELETE /api/v1/recipes/{id}/share — revoke. Clears the token + the attribution flag. Re-sharing later mints a brand-new token by design (old links should die permanently on revoke). - RecipeResource exposes a `share` object on every detail payload (is_shared / url / visible_attribution) so the SPA can render the toggle in place. Public page: - Web route `/r/{token}` declared before the SPA catch-all. - PublicRecipeController renders a dedicated Blade view. No auth needed — the unguessable token is the access grant. 404 on miss (covers never-shared and revoked cases). - View design takes cues from the Crackin' events layout Greg shared: blurred hero image as full-bleed background with a gradient overlay for legibility, floating content over the bottom half, category pill ("RECIPE" or first food tag), big Plus Jakarta Sans title, 2×2 meta cards (Prep / Cook / Total / Serves) with Total highlighted in the lavender accent, prominent allergen banner with the same contains (red) / may_contain (yellow dashed) treatment used elsewhere in the app, source link to the original site if imported, optional extras gallery row, two-column ingredients (sticky on desktop) + numbered method instructions, notes panel in the sun accent if present, and an attribution footer card (anonymous "Shared via Kinhold" by default; opts up to "Shared by The Ellis Family" when the toggle is on) plus a "Try Kinhold free" CTA. All Tailwind tokens are the same ones the SPA uses, so the public page reads native to Kinhold's brand. - OG / Twitter Card meta tags wired from recipe title + description + primary image so link unfurls render the recipe card in iMessage / Slack / Discord / Twitter. - Pure SSR — no Vue hydration. Fast, SEO-friendly, low cost. Frontend (SPA): - ShareRecipeModal: parent-only sheet on the recipe detail view. Publish CTA when not shared. When shared: read-only URL field with copy-to-clipboard (✓ feedback for 2s), visible-attribution KinSwitch with helper copy explaining the trade-off, and a Revoke action with confirm. - New Share icon-button in the recipe detail header, parent-only. - recipe.share state mutated locally on modal updates so the modal reads the latest state on next open without a refetch. Tests: 15 new in PublicRecipeSharingTest — share/revoke/re-share token rotation, PATCH attribution preserves token, attribution fails-422 when not shared, child cannot publish, resource exposes share state, public route renders recipe + OG tags + allergens, attribution anonymous by default, opt-in family name visible, 404 on bad token, no auth required. Total suite: 442 tests, 1168 assertions, green. Manually verified in preview: shared Chocolate Chip Cookies → opened the /r/{token} URL → page rendered with blurred warm hero, Recipe pill, big title, full meta-card row, allergen banner (Peanuts in red), numbered method, attribution footer with Kinhold branding + free-tier CTA, and footer links. Mobile-first layout holds at 375px. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: redesign public recipe page based on dogfood feedback + Preview/Print Working through Greg's design notes on PR #325: Hero - Drop the blurred-photo + floating-card layout; the food image is now full- bleed at the top of the page, sharp and unobstructed. - Title and description overlay the bottom of the image inside a soft gradient that fades the image into the page background. Title clamped to 2 lines and description to 3 lines so long copy can't push the title out of the hero. - Drop the redundant "RECIPE" pill. - Section gets bg-surface-app so any sub-pixel anti-alias seam where the gradient meets the body bg is filled by the same color underneath, and the gradient itself extends 1px below the image to remove the visible line Greg was catching. - Use the actual Tailwind token (surface-app) — the previous CSS variable references to a non-existent surface-base were rendering as transparent, which is why the prior gradient overlay had no effect. Allergens - Move out of the hero entirely; they now sit at the bottom of the Ingredients column under a small "Contains" header. - Replace emoji glyphs with custom inline SVG line-art icons for the Big 9 (milk carton, egg, fish, shrimp, almond, two-lobed peanut, wheat stalk, bean pod with seeds, sesame seeds). Custom family allergens fall back to a neutral warning icon. Quantities - Ingredients render as fractions ("2 1/4 cups", "3/4 cup") not decimals ("2.25", "0.75"). Ported the SPA's RecipeForm decimalToFraction helper to PHP so the public page and the in-app view stay in sync. Share modal - Clipboard copy now falls back through document.execCommand('copy') when navigator.clipboard rejects (sandboxed iframes, focus issues). The "Copy failed" toast only fires when both paths fail. - Read-only URL input wears a subtle lavender focus ring instead of the browser's native warm-gold outline which read as a danger state. - New "Preview what your family will see" button opens the public URL in a new tab so the parent can sanity-check before sharing. Print - Dedicated Print button in the top bar (line-art printer icon, parent- visible). Wires straight to window.print(). - Print stylesheet hides chrome (top bar, gradient overlay, attribution CTA card, footer links, extras gallery), pulls the title out of overlay positioning so it flows under the image, constrains the hero to ~220px, forces ink-friendly black on white, swaps the lavender step circles to solid black, and uses break-inside: avoid on ingredient + method rows. Elements opted out of print carry .no-print or data-* hooks. PWA - Adds `/^\/r\//` to navigateFallbackDenylist in vite.config.js. New SW builds will pass /r/{token} requests through to the server instead of serving the cached SPA shell (which is what the 404 Greg saw was — the service worker intercepting his shared URL). Mobile - Verified at 375px: Print + Try Kinhold buttons fit in the top bar, hero image full-bleed, title large and readable in the gradient zone, meta cards reflow to a 2×2 grid, ingredients still read cleanly. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Security and architecture hardening based on the pre-merge review. - Harden mass-assignment: remove share_token, share_visible_attribution, and allergen_profile_reviewed_at from $fillable; use forceFill where the system needs to write them. Defeats the false-safe filtering invariant if a request could mass-assign reviewed_at. - Add UserAllergenPolicy and route reads/writes through it from the UserAllergenController. - Rate-limit allergen backfill: per-family per-minute job middleware and per-day per-family dispatch throttle on the route. - BackfillRecipeAllergens job now takes family_id and short-circuits on mismatch. Service centralizes queueing for both the controller and the console command. - Public recipe controller no longer eager-loads creator (unused by Blade). Search no longer eager-loads images (cards use image_path). - updateRecipe now takes the editor User so allergen sync attribution is correct. - KinholdFood MCP tool exposes 13 new actions covering allergens, allergen profiles, recipe allergen tagging, backfill, and sharing. - Docs: add DEC-013 (severe-stakes allergen system) and Module 10 reference covering allergens, multi-image, and public sharing. - Public recipe Blade: noindex/nofollow, decimal-to-fraction conversion, design polish. - Tests updated for new ctor sig, forceFill setup, and the family_id mismatch defense. 443/443 tests green. Pint, PHPStan, Prettier all clean.
Two CI-only failures from the v1.10.0 surface: - PublicRecipeSharingTest hit ViteManifestNotFoundException because the public recipe Blade view uses @Vite() and CI doesn't compile assets before phpunit. withoutVite() in setUp skips manifest resolution for these tests; the assertions are about routing/auth/render, not Vite. - RecipeImportTest::test_url_import_with_json_ld_extracts_recipe was asserting Anthropic was never called; the JSON-LD path now runs a separate allergen-extraction pass that legitimately hits Anthropic. Stub Anthropic with an empty-allergens payload and assert call count instead. Recipe assertions still prove the recipe data came from local JSON-LD parsing, not from the LLM stub.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
v1.10.0 release. Six PRs into the integration branch, two user-visible features:
/r/{token}, Blade-rendered for OG/SEO, opt-in family attribution. Carved multi-image support (#323) out so cookbook-scan thumbnails wouldn't leak into shared recipes.Architecture decision: DEC-013 — severe-stakes allergen system design (false-safe filtering invariant, confidence routing, provenance tracking, mass-assignment hardening).
Sub-PRs included
Pre-merge /review pass
/reviewflagged 3 BLOCK + 11 WARN before this PR opened. All addressed:share_token,share_visible_attribution,allergen_profile_reviewed_atremoved from$fillable— explicitforceFillonly.UserAllergenPolicygates reads (family-scoped) and writes (parent or self).family_idand short-circuits on mismatch.noindex,nofollow, decimal-to-fraction conversion.KinholdFoodcovering the full allergen + sharing surface.Closes
Closes #311
Closes #312
Closes #323
Test Plan
Checklist
Session Handoff (auto-updated by /handoff)
Updated: 2026-05-21 13:50
Branch: feature/allergens-v1.10.0
Last commit: 4553295 fix: CI test failures from v1.10.0 changes
What was done this session
/reviewpass before opening the integration PR. All 3 BLOCKs + 11 WARNs addressed: mass-assignment hardening (share_token, share_visible_attribution, allergen_profile_reviewed_at out of $fillable), new UserAllergenPolicy, per-family rate limits on backfill (30/min/family worker, 2/day/family dispatch), family_id mismatch defense in BackfillRecipeAllergens job, 13 new MCP actions on KinholdFood covering allergens + sharing.PublicRecipeSharingTestcallswithoutVite()because the public Blade view uses@vite()and CI doesn't compile assets;RecipeImportTestnow stubs Anthropic for the new JSON-LD allergen pass (recipe extraction assertions still prove JSON-LD parsing, not LLM).Quality state
What's next
/mergePR feat: v1.10.0 — allergens, multi-image recipes, public sharing #326 into main. Will squash, delete branch, tag v1.10.0 (config/version.php already bumped), and monitor Upsun deploy of the main environment./cleanupskill to prune local branches and worktrees that piled up across the six sub-PRs.Blockers / gotchas
Open questions