GRDB performance optimization + Recently Viewed feature#244
Merged
chrisballinger merged 13 commits intomasterfrom Apr 12, 2026
Merged
GRDB performance optimization + Recently Viewed feature#244chrisballinger merged 13 commits intomasterfrom
chrisballinger merged 13 commits intomasterfrom
Conversation
Performance: Eliminate N+1 query patterns across PlayaDB - Batch getFavorites(), fetchRecentlyViewed(), fetchFavoriteEvents() (N+1 → 5 queries) - Add 5 missing indexes (hosted_by_camp, located_at_art, composite metadata, etc.) - Batch ensureMetadata() into single write transaction - Add fetchObjects(byUIDs:) for batch object resolution (40 queries → 4) - Add two batch helpers for event↔occurrence joins, applied to 10 call sites - Remove redundant .including(all:) eager loads that weren't decoded Recently Viewed: Full browsing history feature - New screen in More with type filter, search, sort by recent/distance - Swipe-to-remove individual items and Clear All with confirmation - Map view of all recently viewed items - firstViewed/lastViewed dates shown on detail screens - New ObjectMetadata.firstViewed field with schema migration - New PlayaDB methods: fetchRecentlyViewedWithDates, clearLastViewed, clearAllRecentlyViewed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8 AI workflows (For You, Surprise Me, Day Planner, Adventure Generator, Camp Crawl, Golden Hour Art, What Did I Miss, Schedule Optimizer) with per-workflow configuration knobs, transparent step progress, and whimsical playa-themed messages. Replaces free-form chat with a structured workflow browser. Adds 7 new search tools, detail levels for context budget management, and intent classification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d sort - Fix event cells in Recently Viewed to show host camp/art thumbnail via EventRecentRow instead of bare minimal layout - Enrich .event(EventObject) detail view to show full content: host image, map, schedule, host relationship, event type, and footer (previously only showed title/description/location/URL) - Fix setLastViewed for EventObjectOccurrence to track parent event UID so events viewed via occurrences appear correctly in recents - Add "First Viewed" sort option to Recently Viewed list - Show distance-only subtitles in recents cells (no last-viewed timestamps) - Add fetchOccurrences(forEventUID:) to PlayaDB for internal use - Enable XcodeBuildMCP device workflow and document in CLAUDE.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove NavigationView wrapper and NavigationLink from AIGuideView, delegate all navigation to UIKit via closures to avoid nested navigation controllers - Add onSelectWorkflow closure to AIGuideView, onNavigateToDetail closure to WorkflowDetailView - MoreViewController pushes workflow detail as separate UIHostingController onto the existing UIKit navigation stack - Fix AI summary text showing on wrong cells by adding .id(uid) to resolvedObjectRow for proper SwiftUI identity tracking - Auto-retry all workflow failures up to 3 times (was 2, limited types) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace parallel arrays in @generable structs with paired structs so UIDs/names stay correctly associated with their tips/reasons. The LLM generates two independent arrays that can drift out of alignment. - CampCrawlWorkflow: GenerableCampStop pairs uid+tip - AdventureWorkflow: GenerableSelectedStop pairs uid+reason, GenerableAdventureTip pairs stopName+tip - GoldenHourWorkflow: GenerableGoldenHourStop pairs uid+reason - DayPlanWorkflow: GenerableDayPlanNote pairs eventName+note - ScheduleOptimizerWorkflow: GenerableScheduleNote pairs eventName+note Narrative merge steps now match by name instead of array index. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add retryWithCandidateFiltering() utility that isolates problematic candidates via binary search: tries full set, then halves, then individual items to find and exclude ones that trigger guardrails - Apply to CampCrawl, Adventure, and GoldenHour workflows so the curation step recovers instead of retrying the whole workflow - DayPlan and ScheduleOptimizer narrative steps now match notes to events by name instead of array index - Show actual error descriptions in DEBUG builds (step + final error) - Clear step history between outer retries to avoid wall of repeated steps - Retry all errors up to 3 times (not just specific error types) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add @focusstate to text fields in WorkflowDetailView - Dismiss keyboard when tapping Generate button - Dismiss on background tap via .onTapGesture - Dismiss interactively while scrolling via .scrollDismissesKeyboard Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add DatePicker to WorkflowDetailView for dayPlanner config - Default to current date clamped to festival range via YearSettings.dayWithinFestival - Thread startDate through ViewModel → orchestrator → WorkflowContext - Day Planner now requires user input before auto-starting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use numeric IDs instead of full UIDs in LLM prompts — saves ~30 tokens per candidate. Map back to real UIDs after selection. - DayPlanner: numeric IDs, stripped descriptions, selectedNumbers - CampCrawl: numeric IDs in GenerableCampStop, compact formatting - Adventure: numeric IDs in GenerableSelectedStop, brief formatting - GoldenHour: numeric IDs in GenerableGoldenHourStop, compact art list - ScheduleOptimizer: trimmed conflict prompts - Serendipity/WhatDidIMiss: switched to brief detail level, shorter instructions All workflows now fit comfortably within the on-device model's 4096 token context window even with 15-20 candidates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New WorkflowUtilities.swift with four shared utilities: - resolveObject/resolveObjects/resolveDiscoveryItems: Single place for the 4-branch UID→object resolution (was copy-pasted in 4 workflows) - buildRoute: Shared route building with coordinate resolution, route optimization, and walk time calculation (was ~40 lines in 3 workflows) - buildNumberedList: Numeric ID map creation for token-efficient prompts - mergeNotesByName: LLM note→entry merging by name match Refactored all 8 workflows to use shared utilities: - Adventure, CampCrawl, GoldenHour: use buildRoute (~40 lines each → ~5) - Adventure: uses mergeNotesByName for tip merging - Serendipity, WhatDidIMiss, GeneralChat: use resolveDiscoveryItems (removed 3 identical private resolveItems methods) - DayPlan, ScheduleOptimizer: use mergeNotesByName ~200 lines of duplication eliminated. Future changes to route building, object resolution, or note merging only need to happen in one place. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add withContextWindowRetry() utility that catches LanguageModelSession.GenerationError.exceededContextWindowSize and halves the candidate count automatically until it fits - Apply to DayPlanner selection step (was failing at 7476/4096 tokens) - Replace all string-based error matching with typed pattern matching on LanguageModelSession.GenerationError cases (exceededContextWindowSize, guardrailViolation, unsupportedLanguageOrLocale, rateLimited, assetsUnavailable) - Add isContextWindowError() and isGuardrailError() typed helpers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ch/recents to EventObjectOccurrence - Correct corrupted event occurrence times from PlayaEvents API during import (negative and excessive durations fixed by preserving time-of-day on correct date) - Add UpdateInfo tracking fields (fetchStatus, fetchDate, ingestionDate, etc.) with schema migration and reactive observation via GRDB ValueObservation - DataUpdatesView now shows both YapDB and PlayaDB sections with re-import support - Migrate GlobalSearch and RecentlyViewed to use EventObjectOccurrence with EventRowView and lazy host resolution for camp/art context - Add re-import and occurrence duration validation tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nd timezone - Merge ObjectRowView + MediaObjectRowView into a single ObjectRowView with built-in RowAssetsLoader for thumbnail/color loading - Delete EventRowView — all object types now use the same row layout - Add thumbnailObjectID to DisplayableObject protocol so events automatically resolve host camp/art thumbnails at the data model layer - Add shared EventObjectOccurrence.timeDescription(now:) with proper Burning Man timezone (PDT) to fix time display inconsistency between list rows and detail page - Fix duplicate event occurrences in import: skip both EventObject AND occurrences for duplicate UIDs in API data Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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
firstViewedfield on ObjectMetadata with schema migration for existing databasesTest plan
🤖 Generated with Claude Code