Add Prep for Doctor Appointment tab; merge Health + Documents - #40
Conversation
Adds a "Prep" primary tab that turns this visit's symptoms/notes plus the user's existing health record into an organized report (timeline, questions for the doctor, relevant info), ported from the medical-appt-prep tool and enhanced to auto-pull meds, labs, conditions, and relevant documents into the LLM context. Reports are saved, editable, and exportable (share/print/copy). - Model + encrypted persistence (DB migration v7 -> v8, appointment_preps table) - Prompts ported verbatim; output cleaning/validation ported from processor.py - AppointmentPrepManager runs the 3-call workflow via the existing AI provider interface with progressive section updates - Prep tab UI: list, editor with live generation, detail with export - Merge Health Data + Documents into one "Health" tab with a themed segmented scope switch in the navigation title (child views gain embedInNavigation) - Unit tests for the ported processor logic - Docs updated (CLAUDE.md DB version + components) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4ba2bea796
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } else if !selectedTypes.isEmpty { | ||
| categoriesToFilter = [] | ||
| } else { | ||
| categoriesToFilter = nil |
There was a problem hiding this comment.
Respect an empty appointment context selection
When the user turns off every “Include From My Record” toggle, selectedTypes is empty and this branch passes nil to fetchDocumentsForAIContext, which that API treats as “fetch all AI-context documents”; HealthContextJSON then includes those medical_documents even though selected_types is empty. In that opt-out scenario, generating a prep report can still send all included documents/PHI to the AI provider, so this should use an explicit empty filter or skip document fetching when no types are selected.
Useful? React with 👍 / 👎.
Persist partial appointment prep output when generation fails after producing sections. Include appointment prep records in the encrypted Health Data iCloud backup payload and restore them when present. Co-authored-by: OpenAI Codex <codex@openai.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fff8174338
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if !lastLine.isEmpty && firstMatch(lastLine, pattern: "[.!?*_)]\\s*$") == nil { | ||
| lines.removeLast() |
There was a problem hiding this comment.
Preserve complete bullets that omit punctuation
When a model returns a multi-line section whose final bullet is complete but does not end with punctuation, this cleanup drops that last item before the report is shown or saved. That is common for concise timeline/relevant-info bullets such as - Track whether symptoms worsen after meals, so users can lose one of the generated doctor-prep points even though the response was otherwise valid.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9904210115
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| errorMessage = nil | ||
| generationStage = .idle | ||
|
|
||
| var prep = input |
There was a problem hiding this comment.
Clear stale report sections before regenerating
When an existing report is regenerated after the user edits symptoms or notes, var prep = input keeps the previous timeline, questions, and relevantInfo. If any provider call fails before all sections are overwritten, the catch path sees hasGeneratedContent from those stale sections and saves a “complete” prep with old doctor-prep content attached to the new inputs; clear the generated fields at the start of a run or distinguish content produced by this run.
Useful? React with 👍 / 👎.
Summary
Adds a Prep for Doctor Appointment primary tab and merges the Health Data + Documents tabs into one Health tab.
The Prep feature is ported from the Python
medical-appt-preptool and enhanced to pull the user's existing health record into the LLM context. The user enters this visit's symptoms/notes; the app auto-fills medications and feeds labs, conditions, and relevant documents to the model, then runs a three-call workflow producing a Timeline, Questions for the doctor, and Relevant Info. Reports are saved, editable, and exportable (share / print / copy).What's included
AppointmentPrepstored as an encrypted blob; DB migration v7 → v8 adds theappointment_prepstable (create paths + migration case + index).AppointmentPrepPrompts); validation + output cleaning ported fromprocessor.py(AppointmentPrepProcessor).AppointmentPrepManagerruns the 3 calls through the existingAIProviderInterface(Bedrock / OpenAI-compatible / on-device MLX) with progressive section updates, medication prefill, and JSON health-context assembly (same builder AI Chat uses).AppointmentPrepView(saved list),AppointmentPrepEditorView(inputs + live generation),AppointmentPrepDetailView(view/edit + export).HealthTabViewhosts Records/Documents behind a themed segmented scope switch in the navigation title;HealthDataView/DocumentsViewgained anembedInNavigationflag (defaulttrue, so standalone behavior is unchanged).CLAUDE.mdupdated (DB version 8 + components).Notes
DocumentsView's split code is preserved behind the default flag..segmentedstyle renders the selected label unreadably against the dark theme.Testing
xcodebuild ... -destination 'generic/platform=iOS Simulator' build→ BUILD SUCCEEDED (no warnings from new code, including Swift 6 concurrency).AppointmentPrepProcessorTests.🤖 Generated with Claude Code