Add AI event summary highlights on detail pages#247
Merged
Conversation
Remove hidesBottomBarWhenPushed from detail screens, tracks, AI guide, recently viewed, and feature flags views for a consistent Liquid Glass tab bar experience. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show a concise AI-generated pro-tip summarizing hosted events on camp, art, and event detail pages, plus the hosted events list view. Uses the existing workflow pipeline (retryWithCandidateFiltering + withContextWindowRetry) so summaries work even when individual events trigger guardrails or exceed the context window. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of regenerating the AI summary, pass it through from the detail page. Also move the summary into the scrollable list content so it scrolls away with the rest of the rows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split AI summary into Swift-generated schedule tips (factual, from real occurrence data) and LLM-generated overview (no timing info allowed). This prevents the on-device model from fabricating event times. - Schedule tips: group by event name (fixes duplicates), sorted by day-of-week, strikethrough for expired (only during festival), tappable to navigate to event detail, themed highlight color - RAM cache (actor-based EventSummaryCache) keyed by host UID - Model pre-warming at AgentOrchestrator init - LLM overview: 1-2 sentences, can mention event names, no times/days - Host camp description passed to LLM for richer context - Tips show instantly, LLM overview arrives async Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pass 1 generates the overview with tightened instructions ("only
reference provided data"). Pass 2 validates against the exact source
data (camp description + event names/descriptions) using a separate
LLM session that flags unsupported claims. Swift strips flagged
phrases. If validation fails or strips too much, the overview is
discarded entirely — no unverified text shown.
Each step handles its own retries via withContextWindowRetry /
retryWithCandidateFiltering, matching the pattern used by other
AI workflows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-load event host (camp or art) via batch query so list cells can show "[Host Name] ... [Address]" without N+1 async resolution. Adds PlaceDataObject protocol with address fallback chains, populates EventObjectOccurrence.host on fetch, and removes the old async resolveHosts() machinery from 5 view models. DetailViewModel reuses the pre-loaded host instead of refetching. Tests cover address fallback, host delegation, EventOccurrenceJoinedRow precedence, and end-to-end batch resolution through fetchEvents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move hour grouping into PlayaDB via observeEventsByHour and a new EventHourSection model so the SwiftUI Events list consumes pre-shaped sections, matching the legacy YapDB-grouped UIKit path. Build a tappable + drag-scrubbable EventHourIndexView strip on the trailing edge with bare hour digits, and split the view model into browse vs. search modes so search runs as its own observation. Search now hits event_objects_fts (Porter stemming/unicode folding) by pre-resolving matching event UIDs and constraining the occurrence request, replacing the in-memory .lowercased().contains() fallback that was masking FTS for both UI and AI-tool callers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a tap+drag scrubber bubble to the hour quick-scroll strip with light haptic feedback, fading in over the row content above the user's finger so the active hour stays visible during a drag. Collapse the strip's padding and material when idle so digits sit flush at the trailing edge, expanding only on scrub-active; widen the gesture's hit area with an invisible leading-side extension so the collapsed strip is comfortably tappable without expanding its visible footprint or reflowing the table. Pin the row trailing inset to the strip's active width so layout stays stable across both states. Move the favorite heart from a trailing Button to a leading Image with its own onTapGesture, restoring the legacy UIKit cell shape and unblocking row-level taps that the nested Button-in-Button was swallowing. Drop the fixed 100pt description height so cells with short descriptions don't pad out unnecessarily. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace SwiftUI List with ScrollView+LazyVStack so day swaps no longer process ~1500 row identities. Collapse the per-tap GRDB fetch into a single long-lived observation with a single JOIN, sliced by day in the view model. Cache Calendar boundaries in the bucket so ~16k Calendar calls become ~30. Skip the bulk metadata-ensure write on the new observation to avoid a startup feedback loop. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Collapse the 8-workflow AI Guide catalog, the separate chat surface, and the orphaned assistant path into one immediacy-first screen: free-text + suggestion chips, a time-of-day picker, and a map-area picker. It returns "what's near you happening now" plus "what to do next." - New: RightNowWorkflow + RightNowView/RightNowViewModel, TimeOfDay, Vibe, AreaPickerView, AIResolvedObject, WorkflowProgressTypes. - Delete Adventure/CampCrawl/GoldenHour/DayPlan/ScheduleOptimizer/Serendipity/ WhatDidIMiss/GeneralChat workflows, the chat UI, the catalog, and the dead AIAssistantService path (21 files). - Preserve semantic search (AISearchService.search) and the detail-page event summaries (WorkflowUtilities + the two kept Generables). - Add tests: TimeOfDay windows, Vibe/chip mapping, area-region conversion, candidate gathering. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The time-of-day picker now pairs with a day selector covering the full festival (Sunday through Sunday). - TimeOfDay.dateWindow(on:) anchors the window to any festival day (`.now` stays "next 2h" for today, else the whole selected day); dateWindow(now:) kept as a convenience. - RightNowViewModel tracks selectedDay, defaulting to today's festival day. - RightNowView adds a Day menu (from YearSettings.festivalDays) beside Time and Place, in a horizontally scrollable filter bar. - Tests: day-anchored windows, consecutive-day ordering, week-length coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two fixes from on-device testing:
- Event-first results: lead with events ("now" = happening now, "next" =
upcoming in the window) and only fall back to camps/art when no events match.
If the vibe's event types return nothing, relax to any event type so we still
surface events instead of a pile of camps. Steer the curation prompt to honor
each candidate's type (don't call a camp an "event").
- Bound LLM curation with a 22s timeout + graceful fallback: if the on-device
model stalls (cold first-use / asset load) or is filtered, show the gathered
candidates without AI pitches instead of hanging forever on "Picking the best."
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Region filtering on events was a client-side Swift post-filter (fetch all time-matching occurrences, then drop out-of-region ones). Index it instead, and route art/camp region filtering through the existing point R*Tree too. - New event_occurrence_rtree (lat/lon + start/end epoch), self-maintained by insert/delete triggers on event_occurrences (lat/lon from the parent event's denormalized GPS; time via strftime), plus a full rebuild on import and a one-time backfill in setupDatabase for installs whose DB predates the index. - eventObjectOccurrences[/Joined](filter:) now push region into SQL via an occurrence-id prefilter from the rtree (spatial); time/type stay exact in SQL. - Art/camp inRegion() now query spatial_index instead of a 4-clause bbox WHERE; added FilterRegion.bounds. - Added event_occurrence_rtree to event observations' tracked regions. - Tests: EventOccurrenceRTreeTests (region/window/type/in-region-camp/nil-GPS/ rebuild + art/camp inRegion parity). Full PlayaDB suite: 145 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The occurrence R*Tree's minT/maxT time columns were never queried (region filtering via occurrenceIDsInRegion is spatial-only), yet they violated the rtree (minT<=maxT) constraint on the real bundled dataset — for occurrences whose stored TEXT dates don't parse via SQLite strftime, or whose end precedes start, one bound resolved to a large epoch and the other to 0. That failed the seed import outright (DependencyContainer init), so the app ran on an empty DB. In-memory test fixtures were clean, so it never tripped in tests. Convert event_occurrence_rtree to spatial-only (id, minLat, maxLat, minLon, maxLon). A PRAGMA table_info migration drops the prior 7-column table + its triggers and recreates the index, which self-heals the broken install on next launch (the never-completed seed re-runs). The insert trigger and rebuildOccurrenceRTree now index lat/lon only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A compact, swipeable SwiftUI card pinned near the bottom of the main map that surfaces art/camps/events within ~100m of the user. Events come first (happening now / starting soon, by start time), then art + camps by distance. - NearbyCardViewModel: observes Art/Camp/Event data providers over a tight region + the location stream; emits a flat, ordered, de-duped [NearbyItem] (ordering extracted into a pure, unit-tested static function). Selection is tracked by item id so location updates don't yank the user mid-swipe. - NearbyCardView: paged card (image, 1-line title/description, event timing, favorite heart, audio-tour play button for art), a minimize button, and a badged FAB. iOS 26 Liquid Glass morph between card and FAB (GlassEffectContainer + shared glassEffectID), gated behind canImport(FoundationModels) + #available with a .ultraThinMaterial + matchedGeometry fallback for the iOS 16.6 deployment target. - NearbyCardHostingController: hosts the view as a proper child VC of the map (addChild/didMove, intrinsic-content sizing so it doesn't block the map), pushes detail via DetailViewControllerFactory on tap. - DependencyContainer.makeNearbyCardViewModel(); MainMapViewController wires it in via setupNearbyCard(). - Tests: NearbyCardViewModelTests covers events-first, distance sort, radius exclusion, ended-event exclusion, dedup, cap, and no-GPS drop. Note: final build/test runs in this environment failed at SPM package resolution (network), so a green build+test was not reconfirmed here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add nearby card overlay to the main map
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
retryWithCandidateFiltering+withContextWindowRetry) for graceful handling of guardrail violations and context overflowTest plan
🤖 Generated with Claude Code