| Screenshot does not match source | Preserve repro, then replace/install and launch the known artifact | Reset or uninstall only after preserving evidence and isolating the suspected layer |
| Tool cannot read a simulator screenshot temp path | Re-capture from the current simulator | Temp screenshot files expire or move. Do not treat a missing temp path as invalidating the user's visible report |
| Install says app is missing executable | Inspect built .app bundle | Verify Info.plist and executable path before touching Swift |
| Simulator behaves inconsistently | Prove destination, boot, install, launch state | Do not debate UI until runtime truth exists |
| Auth appears to succeed but next screen is unauthenticated | Inspect token persistence and auth propagation after fresh launch | Do not redesign UI first |
| Push works on Xcode build but fails on TestFlight | Inspect archived entitlements and newest backend device row | Wrong APNs environment is more likely than feature-code regression |
APNs returns BadDeviceToken for older installs | Check device-row environment and staleness first | Often stale tokens or env mismatch, not a current-device blocker |
Push tap opens to black screen, freeze, or _performBlockAfterCATransactionCommitSynchronizes | Start at references/swift-concurrency-crash-triage.md; web-search the exact symbol before any code review | Root-cause candidates include a nonisolated delegate or completion callback mutating main-actor UI state, nested actor hops, or SceneKit updates. Task { } inherits the actor context where its closure is formed; inspect that creation context rather than assuming every task is detached. Separate transport proof from push-open proof |
| UITest env var is present but the wrong screen is captured | Verify branch execution and a screen-specific accessibility marker | Process env alone is not runtime proof |
| Route state changes but the destination never appears | Prefer a direct presentation hook for isolated proof | NavigationStack state is not the same as a visible screen |
| "cannot find X in scope" after adding new files | XcodeGen project not regenerated | Regenerate: scripts/generate-xcodeproj.sh or xcodegen generate |
"cannot find X in scope" in a .pbxproj project after adding files | New file not added to target membership | Add the file to the target before touching Swift feature code |
| CoreSimulatorService "Connection refused" | Simulator service crashed | Use generic/platform=iOS destination instead of simulator; or restart Simulator.app |
| DerivedData write failure / sandbox error | Check the denied path and active toolchain | Use a writable project-specific DerivedData path; if platform services need wider access, use the runtime's scoped approval mechanism or Xcode.app |
| Swift "failed to produce diagnostic" | Type inference overload in complex ViewBuilder | Simplify: inline optional views, remove AnyView, split large computed properties |
| "Copy Bundle Resources contains entitlements" warning | Check whether the entitlements file was added as a bundled resource | Keep entitlements in signing configuration only; exclude them from copied app resources |
Background xcodebuild … | tail -N output file stays 0 bytes until exit | Looks like a stall; not one | tail emits only when its input stream closes. In background execution, the output file appears empty for the entire build run, which looks stuck but is actually normal. Alternatives: 2>&1 | tee output.log for live progress, or drop tail entirely and accept the full output. The tail -N recipe trades live visibility for clean final output — pick based on whether you need progress signals during the run |
Ld failed / missing file after project generation | Check generated paths and target membership, then try an isolated clean build | Cache drift is a hypothesis; a missing source or resource remains missing after a cache reset |
App terminates with 0x8badf00d / WATCHDOG reason | Not a code crash — a callback (scene-create, background task) failed to return in time | Read the reason string for which subsystem timed out; treat as a hang that ran out the clock. See references/runtime-performance-triage.md |
| Process still alive but input goes unanswered | Hang, not crash — no crash log will exist | Capture a main-thread backtrace via the Hangs instrument or lldb bt all; do not search for a nonexistent crash report |
| Scrolling or animation stutters but the app stays responsive | Jank — a missed frame budget, not a hang | Profile with Hitches/SwiftUI instrument, not the Hangs template. 60 Hz = 16.67 ms/frame, ProMotion 120 Hz = 8.33 ms/frame (adaptive; measure the target device's active refresh rate) |
| App disappears with no crash log after memory growth | Suspect a Jetsam kill | Confirm via a jetsam event report or the memory diagnostic available in the target SDK; do not assume a normal crash was swallowed. Apple publishes no official per-device memory-limit table — treat any specific MB figure as empirical |
| "Main thread blocked" in a trace, but the code path looks fine | Possible priority inversion, not main-thread overwork | Check the QoS of every thread in the backtrace before moving work off main; a low-priority thread holding a lock the main thread needs looks identical to a slow main-thread task |
| Launch-time regression only shows up in some samples | Prewarming skew | The OS may prewarm the process before the user taps the icon — loads linked libraries, then suspends before any app code runs. No documented API detects it. Treat a single launch sample as unverified — use MetricKit's launch-type-bucketed metrics or a large field sample |
| MetricKit payload never arrives during local testing | Distinguish field delivery from simulated payloads | On a physical device, Xcode's Debug > Simulate MetricKit Payloads tests report handling with sample data; it does not measure the app's performance |