Skip to content

Commit ef409e4

Browse files
authored
docs: reconcile documentation to current code state (#6)
1 parent 0430ce7 commit ef409e4

3 files changed

Lines changed: 94 additions & 94 deletions

File tree

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Free iOS app (iPhone-only): match a photo to a geolocated historical photograph
1515
## Build / Test / Run
1616
See IMPLEMENTATION-ROADMAP.md for full phase details and verification checklist.
1717

18-
Current phase: **Phase 1: Core App — Camera → Match → Slider**
18+
Current phase: **Phase 3: Confidence UI + Polish** (Phases 0–2 complete)
1919

2020
## Conventions
2121
- Use `guard let` or `try?` with explicit fallback — force-unwraps (`!`) only inside `fatalError`/`precondition`
@@ -53,7 +53,7 @@ Afterimage is a free iOS app (iPhone-only) that matches a photo you take — or
5353

5454
## Current State
5555

56-
**Phase 1: Core App — Camera → Match → Slider**
56+
**Phase 3: Confidence UI + Polish** (Phases 0–2 complete)
5757
See IMPLEMENTATION-ROADMAP.md for full phase details and verification checklist.
5858

5959
## Stack

DOC-RECONCILIATION.md

Lines changed: 91 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,150 @@
11
# DOC-RECONCILIATION.md
22

3-
This file was generated by the `/doc-truth-up` documentation-reconciliation pass, which treats the
4-
code as read-only ground truth and edits only documentation so it reflects the repo's actual current
5-
state. No code was changed and no builds or tests were run. It exists so the operator can audit
6-
every finding in one place.
3+
This file was generated by the `/doc-truth-up` documentation-reconciliation pass. It treats the
4+
code as read-only ground truth and edits only documentation (`README.md`, `CLAUDE.md`,
5+
`DOC-RECONCILIATION.md`) so they reflect the repo's actual current state. No code was changed and
6+
no builds or tests were run. It exists so the operator can audit every finding in one place.
7+
8+
A prior reconciliation pass ran on 2026-05-30 (HEAD `db25f8b`). That pass corrected README feature
9+
overclaims and CLAUDE.md stack version numbers. Those fixes are in the tree; this pass picks up
10+
remaining drift at HEAD `0430ce7`.
711

812
---
913

1014
## Per-Claim Findings
1115

12-
### 1. What it is
16+
### 1. What It Is
17+
18+
**Status: `consistent`**
19+
**Evidence: verified-by-reading-code**
1320

14-
**Status:** `consistent`
15-
**Evidence:** `Afterimage/App/AfterimageApp.swift``@main struct AfterimageApp`, `RootView`
16-
navigation confirms the core identity: camera → matching → slider reveal.
17-
`Afterimage/App/AppState.swift` — navigation state machine (`.camera`, `.matching`, `.comparison`)
18-
matches the overview in README and CLAUDE.md. `Afterimage/Data/Database/DatabaseManager.swift`
19-
opens `photos.db` read-only via `DatabasePool`, confirming the "no backend, bundled SQLite" claim.
21+
README.md and CLAUDE.md accurately describe Afterimage: a free iPhone-only iOS app that matches a
22+
user photo to a geolocated historical photograph using a bundled SQLite index, with a draggable
23+
slider as the core UX. Verified against `Afterimage/App/AfterimageApp.swift` (navigation state
24+
machine), `Afterimage/Features/Comparison/SliderOverlayView.swift` (drag gesture + overlay),
25+
`Afterimage/Data/Database/DatabaseManager.swift` (read-only `DatabasePool`).
2026

21-
No changes made.
27+
One feature was **missing** from README.md — city browse mode — which is fully implemented in
28+
`Afterimage/Features/Gallery/CitySelectorView.swift` and wired into the navigation state machine
29+
in `Afterimage/App/AppState.swift:84–91`. Fixed in claim 2 below.
2230

2331
---
2432

25-
### 2. Current state
33+
### 2. Current State (Phase / Completeness)
2634

27-
**Status:** `drifted` (three README features not implemented)
35+
**Status: `drifted` → fixed**
36+
**Evidence: verified-by-reading-code**
2837

29-
The README Features list claimed three capabilities that do not exist in the source tree:
38+
Both occurrences of the "Current phase" label in `CLAUDE.md` read **Phase 1: Core App — Camera →
39+
Match → Slider**. Reading the source tree shows Phases 0, 1, and 2 are entirely complete:
3040

31-
| Claimed feature | Verdict | Evidence |
32-
|---|---|---|
33-
| "Three comparison modes — draggable slider (hero), side-by-side, and animated crossfade" | **drifted** | Only `SliderOverlayView.swift` exists in `Afterimage/Features/Comparison/`. No `SideBySideView.swift` or `FadeView.swift` anywhere in the project. `ComparisonView.swift` has no mode-switching UI. |
34-
| "Multi-match browsing — up to 5 candidates in a horizontal thumbnail strip" | **drifted** | `AppState.swift:124–128` takes only `candidates.first` and passes one `MatchCandidate` to `ComparisonView`. `ComparisonView.swift` accepts a single `match: MatchCandidate`. No thumbnail strip UI exists. |
35-
| "Share sheet — exports a 1200×800 composite JPEG of then-and-now" | **drifted** | No `ShareCompositor.swift` or `ShareSheetView.swift` in the project. No share button in `ComparisonView.swift`. |
41+
| Phase | Status | Evidence |
42+
|-------|--------|----------|
43+
| Phase 0 — Data Pipeline | **complete** | `DataPipeline/ingest_oldnyc.py`, `ingest_wikimedia.py`, `ingest_flickr.py` (contingency), `build_index.py`, `audit_coverage.py`, `config.py` all present; `DataPipeline/output/photos.db` and staging CSVs exist |
44+
| Phase 1 — Core App | **complete** | All named source files present and fully implemented: `CameraView`, `CameraViewModel`, `CameraCoordinator`, `LocationService`, `SpatialQuery`, `HeadingFilter`, `ThumbnailFetcher`, `VisionRanker`, `MatchingService`, `SliderOverlayView`, `ComparisonView`; unit tests for all five core components |
45+
| Phase 2 — Gallery + Expanded Cities | **complete** | `GalleryPickerView.swift`, `LocationPickerView.swift` (GPS-less location picker), `CitySelectorView.swift` (city browse mode), and all 6 city centers hardcoded in `AppState.swift:28–35` |
46+
| Phase 3 — Confidence UI + Polish | **not started** | `ConfidenceLabel` enum exists in the model (`HistoricalPhoto.swift:66–70`) and is computed in `VisionRanker.swift`, but no badge overlay in `SliderOverlayView.swift` or `ComparisonView.swift`; no multi-match thumbnail strip; no onboarding modal anywhere in the source tree |
47+
| Phase 4 — Share Sheet | **not started** | No `ShareCompositor.swift` or `ShareSheetView.swift` present; no share button in `ComparisonView.swift` |
3648

37-
Implemented and correctly described features (consistent):
38-
- Live camera matching — `MatchingService.swift` orchestrates the four-stage pipeline
39-
- Four-stage pipeline — `SpatialQuery.swift`, `HeadingFilter.swift`, `ThumbnailFetcher.swift`, `VisionRanker.swift` all exist and are wired in `MatchingService.swift`
40-
- Composite scoring (70%/30%) — `VisionRanker.swift` implements this exactly
41-
- Camera roll matching — `GalleryPickerView.swift` + `LocationPickerView.swift` handle GPS-present and GPS-absent cases
49+
**Changes made to `CLAUDE.md` (two occurrences):**
50+
- `## Build / Test / Run` section:
51+
`Current phase: **Phase 1: Core App — Camera → Match → Slider**`
52+
`Current phase: **Phase 3: Confidence UI + Polish** (Phases 0–2 complete)`
53+
- `## Current State` block (portfolio-context region): same string, same fix.
4254

43-
**Changes made to `README.md`:**
44-
- Removed: `"Three comparison modes — draggable slider (hero), side-by-side, and animated crossfade"`
45-
→ replaced with: `"Draggable slider — reveals the historical image beneath the present-day photo"`
46-
- Removed: `"Multi-match browsing — up to 5 candidates in a horizontal thumbnail strip"` (entire bullet)
47-
- Removed: `"Share sheet — exports a 1200×800 composite JPEG of then-and-now"` (entire bullet)
48-
- Updated camera roll bullet to mention the manual location picker (implemented in `LocationPickerView.swift`)
55+
**Change made to `README.md`:**
56+
Added missing bullet to Features list:
57+
`- **City browse mode** — explore historical photos for any of 6 covered US cities (NYC, SF, Chicago, DC, New Orleans, Boston) without taking a photo`
4958

5059
---
5160

5261
### 3. Stack
5362

54-
**Status:** `drifted` in CLAUDE.md; `consistent` in README.md
63+
**Status: `consistent`**
64+
**Evidence: verified-by-reading-code**
5565

5666
`Afterimage.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved` pins:
57-
- GRDB.swift → **7.10.0**
58-
- Kingfisher → **8.8.0**
59-
60-
README.md already said "GRDB.swift 7.x" and "Kingfisher 8.x" — consistent.
67+
- GRDB.swift → **7.10.0** — README says "GRDB.swift 7.x", CLAUDE.md says "GRDB.swift 7.x" ✓
68+
- Kingfisher → **8.8.0** — README says "Kingfisher 8.x", CLAUDE.md says "Kingfisher 8.x" ✓
6169

62-
CLAUDE.md (Tech Stack section and Portfolio Context > Stack section) said "GRDB.swift 6.x" and
63-
"Kingfisher 7.x" in both occurrences — one major version behind in each.
64-
65-
**Changes made to `CLAUDE.md`:**
66-
- `GRDB.swift 6.x``GRDB.swift 7.x` (Tech Stack section, line ~9)
67-
- `Kingfisher 7.x``Kingfisher 8.x` (Tech Stack section, line ~10)
68-
- `GRDB.swift 6.x``GRDB.swift 7.x` (Portfolio Context > Stack section, line ~67)
69-
- `Kingfisher 7.x``Kingfisher 8.x` (Portfolio Context > Stack section, line ~68)
70+
(These version numbers were corrected by the 2026-05-30 pass and remain accurate.)
7071

7172
---
7273

73-
### 4. How to run
74+
### 4. How to Run
7475

75-
**Status:** `consistent`
76-
**Evidence:** `Afterimage.xcodeproj/` directory confirmed present (Package.resolved lives inside it).
77-
README Quick Start shows `open Afterimage.xcodeproj` and "Build and run on a physical iPhone."
78-
No build scripts to verify; build command is Xcode UI only, which is the conventional approach for
79-
iOS projects without a Makefile or CI script at the root.
76+
**Status: `consistent`**
77+
**Evidence: verified-by-reading-code**
8078

81-
No changes made.
79+
README Quick Start documents `git clone … && open Afterimage.xcodeproj`. The Xcode project
80+
directory is confirmed present (`Afterimage.xcodeproj/project.xcworkspace/…/Package.resolved`
81+
exists). No Makefile, CI script, or other build surface exists — Xcode-only is correct for this
82+
project type. Prerequisites (Xcode 16+, iOS 17, physical iPhone) are unverifiable from source
83+
alone but are not contradicted by any file.
8284

8385
---
8486

85-
### 5. Known risks
87+
### 5. Known Risks
8688

87-
**Status:** `consistent` (where verifiable)
88-
**Evidence:** `DatabaseManager.swift:13``config.readonly = true` confirms the "never write to
89-
photos.db" rule. `AppState.swift` — no network transmissions of user data. Camera/location
90-
permission requests are deferred to user action, not app launch (verified in `CameraView.swift` and
91-
`AppState.onPhotoCaptured`). These match the Do NOT constraints in CLAUDE.md exactly.
89+
**Status: `consistent`** (where verifiable)
90+
**Evidence: verified-by-reading-code**
9291

93-
Performance and coverage claims (e.g., "<5s matching", "≥25% grid coverage") are runtime
94-
assertions not checkable by reading source — marked `unverifiable-because-requires-device-or-data`.
92+
CLAUDE.md's risk list (read-only `photos.db`, no off-device data, deferred permission requests,
93+
grayscale Vision pre-processing, no Combine, Phase 0 scope gate) all match code constraints:
94+
- Read-only database: `DatabaseManager.swift` opens a `DatabasePool` with `readonly = true`
95+
- Deferred permissions: camera/location requests live in `CameraView` and `AppState.onPhotoCaptured`, not in `AfterimageApp.init()`
96+
- Grayscale requirement: enforced in `VisionRanker.swift`
9597

96-
No changes made.
98+
Performance claims ("< 5s matching", "≥ 25% grid coverage") and physical-device behaviour are
99+
`unverifiable-because-requires-device-or-data` — left unchanged.
97100

98101
---
99102

100-
### 6. Next move
101-
102-
**Status:** `consistent` (roadmap accurately reflects what is and isn't built)
103-
**Evidence:** Cross-referencing source files against IMPLEMENTATION-ROADMAP.md phases:
104-
- Phase 0 (data pipeline): Python scripts not in the repo root — `DataPipeline/` directory not
105-
present in the source tree. Marked `unverifiable` — pipeline may have been run externally.
106-
- Phase 1 (core app): All named Swift files exist and are wired correctly.
107-
- Phase 2 (gallery + expanded cities): `GalleryPickerView.swift`, `LocationPickerView.swift`,
108-
`CitySelectorView.swift` all exist; `GalleryMatchViewModel.swift` does not (replaced by
109-
`LocationPickerView.swift` + `AppState` logic — functionally equivalent).
110-
- Phase 3 (confidence UI, multi-match, onboarding, haptics): **Not implemented.** Confidence
111-
labels exist in the data model (`MatchCandidate.confidenceLabel`) but no badge UI in
112-
`ComparisonView`. Multi-match UI, onboarding modal, and haptics absent from source.
113-
- Phase 4 (share sheet, App Store submission): **Not implemented.** No share code present.
103+
### 6. Next Move
114104

115-
CLAUDE.md says "Current Phase: Phase 1" which is the most honest current description given that
116-
Phase 1's core flows are built but Phase 3/4 polish items remain. This is `consistent`.
105+
**Status: `drifted` → addressed by phase-label fix above**
106+
**Evidence: verified-by-reading-code**
117107

118-
No changes made.
108+
The corrected phase label in claim 2 is the "next move" signal. Concretely absent from the source
109+
tree (Phase 3 and 4 work):
110+
- `Afterimage/Features/Comparison/SideBySideView.swift` — not present
111+
- `Afterimage/Features/Comparison/FadeView.swift` — not present
112+
- `Afterimage/Features/Share/ShareCompositor.swift` — not present
113+
- `Afterimage/Features/Share/ShareSheetView.swift` — not present
114+
- Confidence badge overlay in `SliderOverlayView` / `ComparisonView` — not present
115+
- Multi-match thumbnail strip — not present
116+
- First-launch onboarding modal — not present
119117

120118
---
121119

122120
## Contradictions for Manual Review
123121

124-
These are drifts found in files this pass is not permitted to edit. A human should apply the fixes.
122+
These drifts are in files outside the editable set (`IMPLEMENTATION-ROADMAP.md`,
123+
`APPSTORE-METADATA.md`). A human should apply the fixes.
125124

126125
### IMPLEMENTATION-ROADMAP.md
127126

128127
| Location | What is wrong | One-line fix |
129-
|---|---|---|
130-
| Line 234 (`from: "6.0.0"` for GRDB.swift) | GRDB.swift is pinned at 7.10.0 in Package.resolved | Change `from: "6.0.0"` to `from: "7.0.0"` |
131-
| Line 238 (`from: "7.0.0"` for Kingfisher) | Kingfisher is pinned at 8.8.0 in Package.resolved | Change `from: "7.0.0"` to `from: "8.0.0"` |
132-
| Lines 173–186 (Swift type definitions) | `thumbnailURL: URL` and `fullResURL: URL?` — actual code (`HistoricalPhoto.swift:29,31`) uses `String` for both | Change `URL``String` and `URL?``String?` in the type definition block |
133-
| Lines 128–137 (SQL schema) | Schema does not include the `city TEXT` column | Add `city TEXT,` after the `lon REAL NOT NULL,` line |
134-
| Lines 112–114 (AfterimageTests listing) | Lists 3 test files; actual suite has 6: also `MatchingServiceTests.swift`, `DatabaseManagerTests.swift`, `TestHelpers.swift` | Add the three missing files to the listing |
135-
| Lines 82–92 (file structure — Comparison/) | Lists `SideBySideView.swift` and `FadeView.swift` as existing files | Remove or mark as `[planned]` — these files do not exist |
136-
| Lines 88–90 (file structure — Gallery/) | Lists `GalleryMatchViewModel.swift` | Remove or rename to `LocationPickerView.swift` — that is the actual file |
137-
| Lines 90–92 (file structure — Share/) | Lists `ShareCompositor.swift` and `ShareSheetView.swift` | Remove or mark as `[planned]` — these files do not exist |
128+
|----------|---------------|--------------|
129+
| Line ~234 — GRDB dependency | Shows `from: "6.0.0"` | Change to `from: "7.0.0"` — Package.resolved pins 7.10.0 |
130+
| Line ~238 — Kingfisher dependency | Shows `from: "7.0.0"` | Change to `from: "8.0.0"` — Package.resolved pins 8.8.0 |
131+
| Line ~63 — file structure | Source dir shown as `afterimage/` (lowercase) | Change to `Afterimage/` — actual Xcode target directory is PascalCase |
132+
| Lines ~105–109 — file structure | Lists `ingest_loc.py` and `ingest_nypl.py` as DataPipeline scripts | Remove both — neither file exists on disk; both sources were dropped (noted in the API Contracts section of the same document) |
133+
| Line ~242 — pip install command | Says `pip install aiohttp requests Pillow tqdm geojson` | Remove `Pillow` and `geojson``DataPipeline/requirements.txt` contains only `aiohttp`, `requests`, `tqdm` |
134+
| Lines ~173–180 — Swift type definitions | `thumbnailURL: URL` and `fullResURL: URL?` | Change both to `String` and `String?``Afterimage/Data/Models/HistoricalPhoto.swift:32–33` uses `String` |
135+
| Lines ~172 — Swift type definitions | `HistoricalPhoto` struct is missing `city: String?` | Add `let city: String?` between `lon` and `heading` — present in `HistoricalPhoto.swift:30` and in `DataPipeline/config.py:52` staging columns |
138136

139137
### APPSTORE-METADATA.md
140138

141139
| Location | What is wrong | One-line fix |
142-
|---|---|---|
143-
| Lines 116–120 (App Review Notes) | "Tap 'Gallery' and browse the bundled historical photos" / "pick a historical photo and navigate to its exact location" misdescribes the Gallery button, which opens the user's camera roll (not a browsable historical archive) | Rewrite to: "Tap the photo icon to pick from your camera roll; if the photo has GPS data it matches immediately, otherwise a map picker appears to pin a location." |
140+
|----------|---------------|--------------|
141+
| Lines ~116–120 — App Review Notes | "Tap 'Gallery' and browse the bundled historical photos" / "Tap any photo to see its metadata and navigate to its location" — describes the Gallery button as opening a historical photo browser | Rewrite: Gallery opens the user's camera roll via `PHPickerViewController`; selecting a GPS-tagged photo triggers matching immediately; selecting a GPS-less photo shows a map pin picker |
142+
| Line ~68 — Support URL | `https://github.com/d/Afterimage` is a placeholder | Update to the real repo URL (`https://github.com/saagpatel/Afterimage` per README.md) |
144143

145144
---
146145

147146
## Footer
148147

149-
- **Run date/time:** 2026-05-30 19:12:52 PDT
150-
- **Branch:** docs/truth-up-2026-05-30
151-
- **HEAD sha reconciled against:** db25f8b46d2ade91d7012dcfb0210b73672a10fb
148+
**Generated:** 2026-06-02 19:29:42 PDT
149+
**Branch:** docs/truth-up-2026-06-02
150+
**HEAD reconciled against:** 0430ce753d8ed96029dd527ac961a8ac6a983b5b

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Afterimage matches your photo to a geolocated historical photograph from the sam
1313
- **Draggable slider** — reveals the historical image beneath the present-day photo
1414
- **Composite scoring** — 70% GPS/heading + 30% Vision similarity; labeled Strong Match, Good Match, or Nearby
1515
- **Camera roll matching** — any photo with GPS EXIF metadata works; manual location picker for GPS-less images
16+
- **City browse mode** — explore historical photos for any of 6 covered US cities (NYC, SF, Chicago, DC, New Orleans, Boston) without taking a photo
1617

1718
## Quick Start
1819

0 commit comments

Comments
 (0)