# Appointment Screenshot Date Handling

The date in appointment screenshots sits in the top middle (e.g., "Wednesday Jun 10, 2026").
All appointments in one screenshot are for the same day.

## Current approach: User-selected date (no OCR date extraction)

The user picks the date via a date picker before scanning. The date is injected into the LLM
system prompt so the AI never tries to extract it from garbled OCR text. This eliminates an
entire Tesseract OCR pass (~30s savings) and frees tokens for better appointment extraction.

### Date picker UI element

```html
<div class="mb-4">
    <label for="scan-appointment-date" class="...">Appointment Date</label>
    <input type="date" id="scan-appointment-date" class="...">
    <p class="text-xs text-purple-500 mt-1">All appointments in this screenshot are for this date.</p>
</div>
```

Located between the model selector and upload area in `#scan-screenshot-modal`.

### Default to today

When the modal opens, the date picker defaults to today if not already set:

```js
const dateInput = document.getElementById('scan-appointment-date');
if (dateInput && !dateInput.value) dateInput.value = new Date().toISOString().split('T')[0];
```

### Reading in handleFile

```js
const selectedDate = document.getElementById('scan-appointment-date')?.value
    || new Date().toISOString().split('T')[0];
```

### System prompt injection

The LLM prompt includes the date explicitly so it never wastes tokens deciphering the header:

```
### ALL APPOINTMENTS ARE FOR: 2026-06-14
```

And rule #1 changed from "Find the date in the header..." to:

```
1. appointmentDate: Use "2026-06-14" for EVERY appointment. Do not read dates from the text.
```

The prompt is built with string concatenation: `'...### ALL APPOINTMENTS ARE FOR: ' + selectedDate + '\n\n### COLUMN LAYOUT...'`

### Fallback in mapping

The final appointment mapping uses `selectedDate` as fallback:

```js
appointmentDate: /^\d{4}-\d{2}-\d{2}$/.test(a.appointmentDate) ? a.appointmentDate : selectedDate,
```

## Removed: Two-pass OCR date extraction

The previous approach (removed June 2026) used a second Tesseract pass with PSM 7 on a
cropped top-20% image. This was fragile — OCR artifacts, wrong PSM, and table-row false
positives made it unreliable. The user-picker approach is faster, more reliable, and simpler.

## One remaining detail

The `preprocessed` object still creates a `header` blob during preprocessing (top 20% crop)
but it is no longer used. It can be cleaned up in a future refactor.
