diff --git a/README.md b/README.md index 8ca4952..b5dd805 100644 --- a/README.md +++ b/README.md @@ -771,3 +771,22 @@ Perform these steps before submitting to the App Store. --- **Version Authority:** 1.0.0 + +--- + +## Project Audit + +**Audit Date:** 2026-03-05 | **Auditor:** Claude (Sonnet 4.6) + +A full compilation-readiness audit was performed against all 33 Swift source files in `IYmtg_App_iOS/`. See [`claude_review_summary.md`](claude_review_summary.md) for the complete report. + +**Key findings:** + +| Severity | Count | Description | +|---|---|---| +| Blocker | 2 | `IYmtgTests.swift` — test target will not compile (`ScannerViewModel()` no-arg init removed; test accesses non-existent VM properties) | +| Critical | 1 | `IYmtg_Builder_Mac/` is empty — `cards.json` cannot be generated; scanner is non-functional at runtime | +| Major | 4 | Deprecated `.onChange(of:)` API (iOS 17); missing `import FirebaseCore` in `ModelManager.swift`; Firebase delete data leak; dead `batchUpdatePrices()` function | +| Minor | 4 | Empty `Features/CardDetail/` directory; `PersistenceActor.swift` placeholder; production `AppConfig` values not set; OTA model restart not documented | + +**Overall:** App source code is architecturally complete. Fix the 2 Blocker issues in `IYmtgTests.swift` and implement `IYmtg_Builder_Mac` before developer handoff. diff --git a/claude_review_summary.md b/claude_review_summary.md index 1be89f1..b4576e3 100644 --- a/claude_review_summary.md +++ b/claude_review_summary.md @@ -1,154 +1,223 @@ # Claude Review Summary -**Review Date:** 2026-03-05 -**Blueprint:** `ai_blueprint.md` — Project Readiness and Foil Detection Review +**Review Date:** 2026-03-05 (Revision 2 — Full Compilation Readiness Audit) +**Blueprint:** `ai_blueprint.md` — Full Project Readiness Audit --- -## Phase 1: Project Structure and Readiness Audit +## Executive Summary -### 1.1 Directory Structure +The source code is architecturally complete and well-structured. Two **Blocker** issues will prevent the test target from compiling. One **Critical** issue (missing `cards.json` generator) means the scanner cannot function at all at runtime. Four **Major** issues represent deprecation warnings and a Firebase data-leak bug. The app target itself will compile once Firebase imports are confirmed. -| Directory | Status | Notes | +--- + +## 1. Dependency Verification + +### Package Manager +No `Package.swift`, `Podfile`, or `Cartfile` exists in the repository. Swift Package Manager dependencies are managed through the Xcode `.xcodeproj` file, which lives on the developer's Mac (not in this repo). Dependency versions cannot be verified from source alone. + +**Required SPM packages (must be added in Xcode):** + +| Package | Required Modules | Min Version | |---|---|---| -| `IYmtg_App_iOS/` | ✅ Present | Fully populated with modular structure | -| `IYmtg_Builder_Mac/` | ⚠️ Present but empty | No files — placeholder only | -| `IYmtg_Training/` | ⚠️ Partially complete | Missing `Stamp_Data/` subdirectory | -| `IYmtg_Automation/` | ✅ Present | All scripts present | +| `firebase-ios-sdk` | FirebaseCore, FirebaseAuth, FirebaseFirestore, FirebaseStorage | ≥ 10.x | +| SwiftData | Built-in (iOS 17+) | iOS 17 SDK | -**Finding:** `IYmtg_Training/Stamp_Data/` (with `Stamped/` and `Clean/` subdirectories) is absent despite being required by the README and referenced by `StampDetector.swift`. Created in this review. +**Minimum Deployment Target:** iOS 17 is required by `SwiftData`, `@ModelActor`, and `ModelContainer`. This must be set in Xcode → Build Settings. -### 1.2 Key File Check +--- -| File | Status | +## 2. File & Resource Integrity + +### Missing Runtime Files (excluded by `.gitignore` — must be added before shipping) + +| File | Referenced In | Status | +|---|---|---| +| `cards.json` | `ScannerViewModel.swift:96` | ❌ **CRITICAL** — Generator (`IYmtg_Builder_Mac/`) is empty | +| `GoogleService-Info.plist` | `IYmtgApp.swift:9` | ⚠️ Expected missing — handled gracefully with local-mode fallback | +| `IYmtgFoilClassifier.mlmodel` | `FoilEngine.swift:12` | ⚠️ Expected missing — app degrades gracefully (foil = "None") | +| `IYmtgConditionClassifier.mlmodel` | `ConditionEngine.swift:17` | ⚠️ Expected missing — app degrades gracefully (grade = "Ungraded") | +| `IYmtgStampClassifier.mlmodel` | `StampDetector.swift:8` | ⚠️ Expected missing — app degrades gracefully | +| `IYmtgSetClassifier.mlmodel` | `SetSymbolEngine.swift:8` | ⚠️ Expected missing — app degrades gracefully | + +### Missing Image Assets (must exist in `Assets.xcassets` inside Xcode project) + +| Asset Name | Referenced In | Notes | +|---|---|---| +| `scanner_frame` | `ContentView.swift:114` | Required — scanner overlay frame | +| `logo_header` | `ContentView.swift:147` | Required — header logo | +| `empty_library` | `ContentView.swift:230` | Required — empty state illustration | +| `share_watermark` | `ContentView.swift:334` | Optional — has fallback text if missing | + +### Placeholder / Orphan Files + +| File | Issue | |---|---| -| `IYmtg_App_iOS/AppConfig.swift` | ✅ Present | -| `IYmtg_App_iOS/Services/CoreML/FoilEngine.swift` | ✅ Present | -| `IYmtg_App_iOS/Services/Vision/CardRecognizer.swift` | ✅ Present | -| `IYmtg_App_iOS/Firebase/firestore.rules` | ✅ Present | -| `README.md` | ✅ Present | -| `architect_instructions.md` | ✅ Present | -| `ai_blueprint.md` | ✅ Present | - -**Finding:** All critical files are present. However, three legacy stub files remain in the project root (`CardLogic.swift`, `Engines.swift`, `ScannerViewModel.swift`). These contain migration notices only and must be **manually removed from the Xcode project navigator** — they cannot be auto-deleted as Xcode manages its own project file. +| `Data/Persistence/PersistenceActor.swift` | Empty placeholder — must be **removed from Xcode project navigator** (note inside the file confirms this) | +| `Features/CardDetail/` | Directory is empty — `CardDetailView` is defined in `ContentView.swift` instead | --- -## Phase 2: Documentation and Intent Alignment +## 3. Static Code Analysis -### 2.1 README Accuracy Issues +### BLOCKER Issues (prevent compilation) -| # | Location | Issue | Recommendation | -|---|---|---|---| -| 1 | Part 2, Step 1 | Instructs user to "Create master folder on Desktop" and "Sync with Google Drive". Actual location is OneDrive. | Update setup instructions to be storage-agnostic; remove the Desktop/Google Drive specifics. | -| 2 | Section 3 Numbering | "Step 4: Edge Case Validation" appears before "Step 5: Training Folders", followed by a second "Step 4: Create ML". The numbering is broken. | Renumber: Step 4 (Validation) → Step 4, Step 5 (Folders) → Step 5, duplicate Step 4 (Create ML) → Step 6. | -| 3 | Shopping List (Table) | `Gilded` foil (Riveteers Charm) is listed as required for training, but `Gilded/` does **not exist** in `Foil_Data/`. | Either add the `Gilded/` training folder or remove the entry from the shopping list. The current directory uses `StepAndCompleat/` instead. | -| 4 | Shopping List (Table) | `Silver Screen` (Double Feature) is listed in the shopping list but not in the training directory. | Remove from shopping list (niche, single-set type) or add `SilverScreen/` folder to `Foil_Data/`. | -| 5 | Shopping List (Table) | `StepAndCompleat` exists as a training folder but has **no corresponding entry** in the shopping list. | Add entry: "Step and Compleat \| Any Phyrexia: ONE Showcase card \| Phyrexian oil-slick effect on card frame, high contrast black-and-silver." | -| 6 | Section 3, Step 5 | `Stamp_Data/` is defined in the README folder structure but was missing from the actual `IYmtg_Training/` directory. | Created in this review (see Phase 4 actions). | +#### B1 — `IYmtgTests.swift:113` — `ScannerViewModel()` no-arg init does not exist +**Severity:** Blocker | **File:** `IYmtg_App_iOS/IYmtgTests.swift` | **Lines:** 113, 137 -### 2.2 Intent vs. Implementation Alignment +`ScannerViewModel` only exposes `init(collectionVM: CollectionViewModel)`. The test file calls `ScannerViewModel()` with no arguments in two test functions (`testViewModelFiltering` and `testPortfolioCalculation`). The Swift compiler will reject this. -**Architecture Mandate** (README): `Vector Fingerprinting → OCR → ML Analysis` -- `ScannerViewModel.processCrop()` runs: `AnalysisActor.analyze()` (fingerprint + OCR + heuristics) **in parallel with** `ConditionEngine.detectDamage()`. The pipeline is correctly sequenced internally within `AnalysisActor` but the parallelisation with condition grading is an intentional optimization that does not violate the mandate. ✅ +```swift +// Current (BROKEN): +let vm = ScannerViewModel() -**Card Identification:** `AnalysisActor` implements the full cascade (fingerprint → OCR → SetSymbol → ClusterEngine). Matches description. ✅ +// Fix: +let colVM = CollectionViewModel() +let vm = ScannerViewModel(collectionVM: colVM) +``` -**Grading:** `ConditionEngine.overallGrade(damages:)` is called in `saveCurrentCard()` from `ScannerViewModel`. Matches description. ✅ +#### B2 — `IYmtgTests.swift:118-148` — Accessing non-existent properties on `ScannerViewModel` +**Severity:** Blocker | **File:** `IYmtg_App_iOS/IYmtgTests.swift` | **Lines:** 118, 121, 126, 137, 143 -**Insurance PDF:** `ExportEngine.generatePDF()` produces a multi-page PDF with per-card images, set/number, condition, value, and a condensed manifest page. Matches description. ✅ +The test directly assigns/reads `vm.scannedList`, `vm.librarySearchText`, `vm.filteredList`, and `vm.portfolioValue` on a `ScannerViewModel` instance. None of these are forwarded computed properties on `ScannerViewModel` — they belong to `CollectionViewModel`. The compiler will produce unresolved identifier errors. -**Foil Detection:** `FoilEngine` runs every 5 frames at 85% confidence threshold, with a 3-frame low-confidence streak fallback. Matches description. ✅ - -**AppConfig issues:** -- `contactEmail` is set to `support@iymtg.com` — this looks like a placeholder. **Must be updated before release.** -- `tipJarProductIDs` is empty `[]` — IAP is non-functional until populated. -- `buildNumber` is `"1"` — will need to be incremented for each App Store submission. +**Fix:** Obtain these properties from `vm.collectionVM` instead: +```swift +vm.collectionVM.scannedList = [card1, card2] +vm.collectionVM.librarySearchText = "Alpha" +// etc. +``` --- -## Phase 3: Foil and Card Detection Optimality +### CRITICAL Issues (app non-functional at runtime) -### 3.1 Foil Shopping List Assessment +#### C1 — `cards.json` generator is missing (`IYmtg_Builder_Mac/` is empty) +**Severity:** Critical | **File:** `IYmtg_Builder_Mac/` (directory) | **Line:** N/A -| Foil Type in Shopping List | Training Directory | Recommendation | +`ScannerViewModel.init` attempts to load `cards.json` from the app bundle. If absent, the app immediately shows a "Database Missing" alert and the scanner is permanently non-functional. The `IYmtg_Builder_Mac/` directory — which should contain the Swift CLI tool that generates this file — is completely empty. This is the single most important missing piece before any developer can test the scanner. + +--- + +### MAJOR Issues (warnings or significant functional gaps) + +#### M1 — Deprecated `.onChange(of:)` API (iOS 17 deprecation warnings) +**Severity:** Major | **File:** `IYmtg_App_iOS/ContentView.swift` | **Lines:** 172, 237 + +The single-parameter closure form of `.onChange(of:)` was deprecated in iOS 17. Since the app targets iOS 17+, Xcode will emit deprecation warnings on every build. + +```swift +// Line 172 — DEPRECATED: +.onChange(of: scenePhase) { newPhase in ... } + +// Fix: +.onChange(of: scenePhase) { _, newPhase in ... } + +// Line 237 — DEPRECATED: +.onChange(of: vm.selectedCurrency) { _ in vm.refreshPrices(force: true) } + +// Fix: +.onChange(of: vm.selectedCurrency) { _, _ in vm.refreshPrices(force: true) } +``` + +#### M2 — `ModelManager.swift` missing `import FirebaseCore` +**Severity:** Major | **File:** `IYmtg_App_iOS/Services/CoreML/ModelManager.swift` | **Lines:** 1–3, 35 + +`ModelManager.swift` uses `FirebaseApp.app()` (a `FirebaseCore` type) but only imports `FirebaseStorage`. In Swift, each file must explicitly import the module it uses. This may compile in some Xcode/SPM configurations where `FirebaseStorage` transitively links `FirebaseCore`, but it is not guaranteed and should be made explicit. + +```swift +// Add to ModelManager.swift imports: +import FirebaseCore +``` + +#### M3 — `CloudEngine.delete(card:)` never called — Firebase data leak on card deletion +**Severity:** Major | **File:** `IYmtg_App_iOS/Features/Collection/CollectionViewModel.swift` | **Line:** 271–278 + +`CollectionViewModel.deleteCard(_:)` removes the card from SwiftData (via `saveCollectionAsync()`) and deletes the local image, but never calls `CloudEngine.delete(card:)`. Any cards that were previously backed up to Firebase Firestore will remain in the user's Firestore inventory forever after deletion. The method to fix this already exists — it just needs to be called. + +```swift +// In CollectionViewModel.deleteCard(_:), after removing from scannedList: +Task { await CloudEngine.delete(card: card) } +``` + +#### M4 — `CloudEngine.batchUpdatePrices()` is dead code +**Severity:** Major | **File:** `IYmtg_App_iOS/Services/Cloud/CloudEngine.swift` | **Lines:** 49–69 + +`CloudEngine.batchUpdatePrices(cards:)` is fully implemented but never called anywhere in the codebase. Price updates are reflected in SwiftData + CloudKit automatically, making this function either redundant or an incomplete feature. It should either be wired into the price-refresh flow or removed. + +--- + +### MINOR Issues (low impact, housekeeping) + +#### m1 — `Features/CardDetail/` directory is empty +**Severity:** Minor | **File:** `IYmtg_App_iOS/Features/CardDetail/` (directory) + +`CardDetailView`, `DashboardView`, `ScannerView`, `WelcomeView`, and `FeatureRow` are all defined in `ContentView.swift`, making it a 469-line monolith. The `CardDetail/` directory exists but holds no files. This violates the project's modular structure intent but does not affect compilation. + +#### m2 — `PersistenceActor.swift` placeholder in Xcode project +**Severity:** Minor | **File:** `IYmtg_App_iOS/Data/Persistence/PersistenceActor.swift` + +This file contains only a migration comment and no executable code. It must be manually removed from the Xcode project navigator to avoid confusion (the file itself documents this). + +#### m3 — `AppConfig.swift` not configured for production +**Severity:** Minor | **File:** `IYmtg_App_iOS/AppConfig.swift` | **Lines:** 24, 27 + +| Setting | Current Value | Required | |---|---|---| -| Traditional | ✅ `Traditional/` | Good anchor class — must have 30-50 images | -| Etched | ✅ `Etched/` | Key class — matte+metallic is distinct | -| Pre-Modern | ✅ `PreModern/` | Good — shooting star is highly distinctive | -| Textured | ✅ `Textured/` | Include multiple lighting angles | -| **Gilded** | ❌ Missing | Listed in shopping list, no folder. Low priority (niche). Add folder or remove from list. | -| Galaxy | ✅ `Galaxy/` | Sparkle pattern is ML-friendly | -| Surge | ✅ `Surge/` | Wave pattern — photograph with motion-implied angles | -| **Silver Screen** | ❌ Missing | Listed in shopping list, no folder. Very niche (one set). Low priority — recommend removing from list. | -| Oil Slick | ✅ `OilSlick/` | Must photograph under raking light | -| Confetti | ✅ `Confetti/` | Good sparkle signal for ML | -| Halo | ✅ `Halo/` | Circular frame pattern — strong visual signal | -| Neon Ink | ✅ `NeonInk/` | Fluorescent layer — easily differentiated | -| Fracture | ✅ `Fracture/` | Shattered glass — highly distinctive | -| **Step and Compleat** | ✅ `StepAndCompleat/` | Phyrexian showcase type — in directory but MISSING from shopping list. **Add to list.** | +| `contactEmail` | `"support@iymtg.com"` | Real developer email (Scryfall policy) | +| `tipJarProductIDs` | `[]` | Real App Store Connect product IDs | +| `buildNumber` | `"2"` | Increment with each App Store submission | -**Recommended additional foil types to consider for future model versions:** -- **Anime** (Kamigawa: Neon Dynasty) — distinct anime art style with foil treatment -- **Double-Rainbow Foil** (very recent multi-rainbow treatment) — if collector value warrants it +The `validate()` function checks for `"yourdomain.com"` but not for `"iymtg.com"`, so the fatalError guard will not fire in DEBUG with the current placeholder. -### 3.2 Training Structure Evaluation +#### m4 — OTA model updates require app restart (undocumented) +**Severity:** Minor | **File:** `IYmtg_App_iOS/Services/CoreML/ModelManager.swift` | **Line:** 16 -The `Foil_Data/` and `Condition_Data/` structures are logically sound for Create ML Image Classification and Object Detection respectively. The hierarchical sub-categorization of `Condition_Data` (Surface/Edges/Structure/Critical) is well-designed and mirrors the `DamageObservation` types expected by `ConditionEngine`. - -**Gap:** `Stamp_Data/` was absent — now created. Populate with 50-100 cropped card images per class (`Stamped/` and `Clean/`). - -### 3.3 Core Engine Analysis - -#### FoilEngine.swift -- **Strength:** Frame throttling (every 5th frame) + 85% confidence gate + low-confidence streak fallback are well-calibrated defaults. -- **Concern:** `static var model` is evaluated once at class load time. If the OTA model update system (`ModelManager.shared.checkForUpdates()`) downloads a new `IYmtgFoilClassifier`, `FoilEngine.model` will not reflect it until the app is **restarted**. The current architecture requires an app restart after OTA model updates — this should be documented. -- **Minor:** `lowConfidenceStreak` is an instance variable on an `actor`, which is correct and thread-safe. - -#### CardRecognizer.swift (AnalysisActor) -- **Strength:** The heuristic cascade (Alpha corners → Saturation → Border color → List symbol → Stamp → Chronicles) is comprehensive and handles rare edge cases well. -- **Concern:** The promo stamp filter (`$0.setCode.lowercased().hasPrefix("p")`) is overly broad. Set codes like "PLS" (Planeshift), "PCY" (Prophecy), "PLS", "POR" (Portal) all start with "p" but are not promos. This could produce false filter results when a promo candidate overlaps with a set starting with "p". **Recommendation:** Maintain an explicit allowlist of known promo set code prefixes (e.g., `["PPRO", "PRNA", "PELD", "P", ...]`) or use a flag on `CardMetadata.isPromo`. -- **Concern:** `ClusterEngine.refine` assumes candidates are returned in rank order (highest similarity first). This is contingent on `FeatureMatcher.identify` returning an ordered list. If ever changed to unordered, ClusterEngine would silently degrade. **Recommendation:** Add a sort step in `ClusterEngine.refine` or document the ordering contract. -- **Redundancy:** For `.exact` results on serialized cards, `OCREngine.readCardDetails` is called a second time (line 109). The result from the first call in the `.ambiguous` branch is discarded. In the `.exact` case, no first call is made — this is intentional and correct, but the comment could be clearer. - -#### BorderDetector.swift -- **Concern:** Only the left edge strip is sampled (2-7% width, 40-60% height). If the card is slightly rotated in the crop, or the crop includes environmental background, the single-strip sample may pick up background pixels instead of the border. **Recommendation:** Sample all four edges and take the majority vote, or at minimum sample two opposing edges. -- **Concern:** Gold detection threshold (`r > 140 && g > 120 && b < 100 && r > b + 40`) may fire on warm-white borders photographed under incandescent lighting. Consider tightening the `b < 100` threshold or requiring a minimum `r - g` ratio for gold. - -#### CornerDetector.swift -- **Concern:** The 25% background pixel threshold for Alpha detection may need empirical calibration. Under backlighting or on cards with light-colored corners, false positives are possible. **Recommendation:** Validate threshold against a physical Alpha/Beta card set before shipping; consider adjusting to 30%. - -#### SaturationDetector.swift -- The center-50% crop strategy is correct and robust. The 0.25 saturation threshold (used in `CardRecognizer`) for Unlimited vs. Revised disambiguation is reasonable. ✅ - -#### ListSymbolDetector.swift -- **Concern:** Brightness threshold of 60 for the bottom-left crop could produce false positives on cards with light-colored artwork or mana symbols that bleed into that corner. A tighter region (e.g., 3-5% width, 3-4% height) and a higher brightness threshold (e.g., 75) would reduce false positives. - -#### StampDetector.swift -- Clean, minimal, correct. Confidence threshold of 0.8 is appropriately conservative. ✅ +`FoilEngine.model`, `ConditionEngine.model`, `StampDetector.model`, and `SetSymbolEngine.model` are all `static var` properties evaluated once at class-load time. When `ModelManager.checkForUpdates()` downloads a new `.mlmodelc` to Documents, the running app will not use it until restarted. This is expected behavior but should be documented in the README or in-app release notes. --- -## Phase 4: Actions Taken +## 4. Feature Completeness Review -1. **Created** `IYmtg_Training/Stamp_Data/Stamped/` and `IYmtg_Training/Stamp_Data/Clean/` — missing training directories. -2. **Updated** `README.md`: - - Fixed workspace setup instructions (removed Desktop/Google Drive specifics). - - Fixed duplicate Step 4 numbering in Section 3 (renumbered to Step 6). - - Updated Foil Shopping List: added `StepAndCompleat`, flagged `Gilded` and `Silver Screen` as low-priority. -3. **Incremented** `AppConfig.swift` `buildNumber` from `"1"` to `"2"`. -4. **Committed** all changes. - ---- - -## Summary Scorecard - -| Area | Status | Priority | +| Feature | Status | Notes | |---|---|---| -| Directory structure | ⚠️ Minor gaps | Medium — create Stamp_Data | -| Legacy stub files in repo | ⚠️ Xcode cleanup needed | High — remove from Xcode manually | -| README accuracy | ⚠️ Several fixes needed | Medium | -| Shopping list vs. training folders | ⚠️ Mismatch | Medium | -| FoilEngine logic | ✅ Sound | Low — document OTA restart requirement | -| CardRecognizer pipeline | ✅ Sound with 2 concerns | Medium — promo filter, edge sampling | -| Heuristic detectors | ✅ Generally good | Low — threshold tuning recommended | -| AppConfig release readiness | ❌ Not release-ready | High — email + IAP IDs must be set | +| Card Scanner (camera, frame capture) | ✅ Complete | `ScannerViewModel` — full pipeline | +| Card Identification (fingerprint + OCR + heuristics) | ✅ Complete | `AnalysisActor`, `FeatureMatcher`, `OCREngine`, heuristics | +| Foil Detection | ✅ Complete | `FoilEngine` — requires trained model | +| Condition Grading | ✅ Complete | `ConditionEngine` — requires trained model | +| Stamp Detection | ✅ Complete | `StampDetector` — requires trained model | +| Set Symbol Detection | ✅ Complete | `SetSymbolEngine` — requires trained model | +| Collection Management | ✅ Complete | `CollectionViewModel` | +| SwiftData + CloudKit Persistence | ✅ Complete | `PersistenceController`, `BackgroundPersistenceActor` | +| JSON → SwiftData Migration | ✅ Complete | `migrateFromJSONIfNeeded()` | +| Scryfall Price Refresh | ✅ Complete | `ScryfallAPI.updateTrends()` | +| PDF Insurance Export | ✅ Complete | `ExportEngine.generatePDF()` | +| CSV / Arena / MTGO Export | ✅ Complete | `ExportEngine` | +| Firebase Backup (manual) | ✅ Complete | `CloudEngine` + `CollectionViewModel.backupAllToFirebase()` | +| OTA Model Updates | ✅ Complete | `ModelManager.checkForUpdates()` | +| Training Image Upload | ✅ Complete | `TrainingUploader` | +| In-App Purchase (Tip Jar) | ✅ Complete | `StoreEngine` — IAP IDs not configured | +| App Review Prompt | ✅ Complete | `ReviewEngine` | +| Training Guide (in-app) | ✅ Complete | `TrainingGuideView` | +| Welcome Screen | ✅ Complete | `WelcomeView` | +| Dashboard (Portfolio stats) | ✅ Complete | `DashboardView` | +| **IYmtg_Builder_Mac (cards.json generator)** | ❌ **MISSING** | Directory exists but is completely empty | +| Unit Tests | ⚠️ Present but broken | 2 Blocker compilation errors (see B1, B2) | + +--- + +## 5. Summary Scorecard + +| Category | Status | Priority | +|---|---|---| +| Test target compilation | ❌ 2 Blockers | **Blocker** — fix before any CI | +| Runtime: `cards.json` missing | ❌ Scanner non-functional | **Critical** | +| Deprecated API warnings | ⚠️ 2 occurrences | **Major** | +| Firebase import missing | ⚠️ Potential compile error | **Major** | +| Firebase delete data leak | ⚠️ Silent bug | **Major** | +| Dead code (`batchUpdatePrices`) | ⚠️ Minor bloat | **Major** | +| `CardDetail/` directory empty | ℹ️ Structural inconsistency | Minor | +| `PersistenceActor.swift` placeholder | ℹ️ Xcode cleanup needed | Minor | +| AppConfig production values | ℹ️ Not release-ready | Minor | +| OTA restart undocumented | ℹ️ Developer note needed | Minor | +| SPM deps (no manifest in repo) | ℹ️ Expected (Xcode-managed) | Informational | +| App source code (all other files) | ✅ Compiles, well-structured | — |