Amber

State of the Costco iOS App

An amber health status overall. Architecture, networking security, and test coverage are strong; app stability, lifecycle/memory, and accessibility need a focused remediation quarter.

Costco iOS 26.4 / Q2 2026 · 1 app + 26 SPM packages + CocoaPods · 88 concrete findings · Reviewed 2026-05-07
68
HEALTH

Headline indicators

Overall health
68/100
Avg of 20 category scores
Critical defects
16
Likely production crashes
High-severity defects
34
Crash-prone, security, lifecycle
Total findings
88
With file:line + fix
Modernization debt
24%
108 Obj-C .m + 109 .h legacy
Accessibility score
50/100
Dynamic Type missing; AODA risk
Test files
680
+ 6 XCTestPlans w/ snapshots
SPM packages
29
+ CocoaPods hybrid

At a glance

Severity distribution

Across 88 machine-curated findings

Health by area · sorted

12 areas · color = status

Status by area

Twelve health areas, each with definition, current state, business impact, and next step. Color stripe encodes status — green / amber / red.

Green — healthy (≥75) Amber — needs attention (60–74) Red — material risk (<60)
App Stability
Amber 60/100
What this means

Likelihood of crashes on real iPhones / iPads in production.

Current state

13 critical force-try regex compilations; 18+ URL force-unwraps on Reviews API; 6 timer leaks in cart / cookies / ad views; pervasive ! force-unwrap pattern.

Why it matters

Each failed regex or URL parse takes down the feature on launch. Long sessions accumulate timer leaks → jetsam kills.

Recommended next step

Stability strike-team — 4 weeks. Fix the 13 force-try sites; sweep BazaarVoice URL force-unwraps; add SwiftLint rules force_try / force_unwrapping.

Security Posture
Amber 70/100
What this means

HTTPS, Keychain, Cert Pinning, ATS exceptions, secret handling.

Current state

Strong baseline (CostcoServerTrustManager pinning, Keychain wrappers, Passkey via NokNok, SecRandomCopyBytes used). NSAllowsArbitraryLoads = true in Notification Service Extension Info.plist (both production and QA).

Why it matters

ATS bypass weakens platform-wide HTTPS posture; auditors and Apple Privacy Reports flag this.

Recommended next step

Replace NSAllowsArbitraryLoads with NSExceptionDomains for specific hosts; document each pin and a renewal calendar.

Privacy & Compliance
Amber 70/100
What this means

App Store privacy nutrition label fidelity + iOS-specific permissions.

Current state

Permissions: camera, photo, location. Background location for geofencing. ThreatMetrix and Adobe analytics SDKs collect device + behavioral data.

Why it matters

Apple's annual privacy review can withhold review approval if disclosures are off.

Recommended next step

Generate the Privacy Manifest (PrivacyInfo.xcprivacy) per Apple's 2024+ requirement; align with App Store privacy labels.

Performance
Amber 62/100
What this means

Cold start, scrolling, memory, battery.

Current state

Heavy synchronous work in viewDidLoad; UIImage(named:) repeated in cell config; cookie polling timer running every 5s; no Instruments-based dashboard.

Why it matters

iOS users perceive jank vividly. App Store reviews and crash-free metrics suffer.

Recommended next step

Move heavy init to async Task; cache cell images; replace polling timer with event-based callback.

Accessibility
Red 50/100
What this means

VoiceOver, Dynamic Type, contrast, traits.

Current state

Some accessibilityLabel/accessibilityHint usage; Dynamic Type not enforced (hardcoded UIFont.systemFont sizes); missing traits on buttons; VoiceOver gaps in onboarding flows.

Why it matters

AODA/ADA exposure same as Android; on iOS, App Store reviewers also check accessibility.

Recommended next step

Mandate UIFont.preferredFont(forTextStyle:); SwiftLint a11y plugin; UI tests with Accessibility Inspector.

Localization Reach
Amber 70/100
What this means

Languages and regional formatting.

Current state

4 locales (en, en-CA, fr-CA, fr); ~2,000 strings per locale; pseudo-localization not enabled; some hardcoded literals.

Why it matters

Same expansion exposure as Android.

Recommended next step

Enable pseudo-locale (en-XA / ar-XB) in debug schemes; SwiftGen for compile-time string safety.

Architecture
Green 80/100
What this means

Module structure, MVVM, public-API discipline.

Current state

29 SPM packages with clear responsibilities; clean MVVM in feature ViewModels; CostcoNetworkClient + ServerTrustManager solid.

Why it matters

Strong foundation for parallel feature work.

Recommended next step

Document SPM access-control conventions; tighten public API surface where possible.

Test Coverage
Green 75/100
What this means

XCTest + Snapshot + Mockey infrastructure.

Current state

680 test files; SnapshotTesting + iOSSnapshotTestCase; 6 XCTestPlans (Snapshot-Tests-EN_CA / EN_US / FR_CA + others). Coverage threshold not surfaced in CI.

Why it matters

Snapshot suite is a real strength.

Recommended next step

Publish line + branch coverage to Codecov; fail PRs that drop coverage on changed files.

Build Modernity
Green 78/100
What this means

Xcode, Swift, Pods, SPM.

Current state

Xcode 15.x · Swift 5 · iOS 16 deployment · 29 SPM packages · CocoaPods + SwiftLint.

Why it matters

Modern toolchain; gradual migration to all-SPM is plausible.

Recommended next step

Plan CocoaPods → SPM migration as legacy Pods become SPM-available.

Tech Debt
Amber 60/100
What this means

Legacy Obj-C, hardcoded literals, duplicate stacks.

Current state

108 .m + 109 .h files in main app; hardcoded hex colors despite design system; RZVinyl custom networking fork; mixed UIKit/SwiftUI.

Why it matters

Each new feature pays a small Obj-C/UIKit interop tax.

Recommended next step

Quarterly Obj-C → Swift LoC target; ban hex literals; assess RZVinyl replacement.

Engineering Velocity
Amber 72/100
What this means

PR reviews, conventions, build times.

Current state

29 SPM packages buildable in parallel; Azure Pipelines CI with NowSecure; SwiftLint integrated; no CODEOWNERS evident.

Why it matters

Reviews unrouted; new engineer onboarding friction.

Recommended next step

Add CODEOWNERS; enforce SwiftLint baseline on PRs; document SPM workflow.

Operational Telemetry
Amber 68/100
What this means

OSLog, Crashlytics, signposts, dashboards.

Current state

print() usage in widget + test utils; no os.Logger adoption seen; Crashlytics integration unclear in scan.

Why it matters

Without structured logging, post-launch incident debug is harder.

Recommended next step

Adopt os.Logger with signpost categories; ship structured-log dashboards.

Top risks (business framing)

Each risk maps to suggested owner team and rough effort.

1

Force-try regex / URL crashes

13 try! NSRegularExpression + 18 URL(string:)! force-unwraps on production code paths
A single regex syntax change or malformed URL crashes the affected module on launch. The Reviews/Ratings module is concentrated risk — every BazaarVoice URL is force-unwrapped.
StabilityRevenueReputationOwner: Mobile platform teamEffort: M
Severity
CRITICAL
2

Memory leaks: timers, observers, retain cycles

6 timer-not-invalidated, 21 NotificationCenter observers without removal
Long iPhone sessions accumulate retained ViewModels and timers. Jetsam kills + degraded scrolling. Cookie polling timer drains battery.
StabilityBatteryUXOwner: Mobile platform teamEffort: M
Severity
HIGH
3

ATS exceptions in Notification Service Extension

NSAllowsArbitraryLoads = true in production + QA Info.plist
Apple App Review and security audits flag broad ATS exemptions; secondary attack surface for push payload manipulation.
SecurityApple ReviewPrivacyOwner: Security + MobileEffort: S
Severity
HIGH
4

Accessibility: Dynamic Type missing

Hardcoded UIFont.systemFont(ofSize: ...) across onboarding + filters
Users with Larger Text settings see clipped/overlapping content. AODA/ADA risk + Apple a11y review concerns.
ComplianceBrandApple ReviewOwner: Design system + featuresEffort: M
Severity
HIGH
5

Hardcoded hex colors despite design system

Pallet tokens defined; feature code uses Color(hex: "#…") inline
Dark-mode work blocked; brand consistency drifts; repeated bugs.
UXVelocityOwner: Design system teamEffort: S
Severity
MEDIUM
6

print() / NSLog in production paths

30+ print() statements in widget + test utils + production code
PII leakage into logs; no structured signposts for post-launch debugging.
PrivacyOperationalOwner: Mobile platform teamEffort: S
Severity
MEDIUM
7

Stale documentation

README outdated; minimal DocC coverage; no ADRs
Onboarding 2-3× slower for new engineers; SPM module choices undocumented.
HiringVelocityOwner: Tech leadsEffort: M
Severity
MEDIUM

Quick reference

If you have 2 minutes

Look at the headline indicators. Critical defects (16) and accessibility (50/100) are where leadership attention is most useful.

If you have 10 minutes

Skim the Top Risks. Each maps to a recommended owner and effort estimate.

If you want to dig in

Tech Overview has charts and Excel export. Class-by-class gives engineers their working list.

For the board

Print-friendly: Cmd-P hides sidebar and toolbars.

Costco iOS · Code Review Report · Generated 2026-05-07 · 88 machine-curated findings