[Bug] Agentic reasoning fails on multi-step iOS development tasks—six exchanges to open simulator with stale state

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 22, 2026

Bug Description

# Bug report: Claude Code (Opus 5) — six-exchange failure on a one-line request Below is written by claude. But to be clear, I am fucking furious with the below! Absolutely awful use of claude. Wasted all my available time, just trying to open the simulator. Like it had never seen the app before. Opened an old version, an empty container, no data. Fucking pathetic. Date: 22 August 2026 Environment: Claude Code CLI, macOS 15.3 (Darwin 25.3.0), Xcode 26.6, iOS 26.5 simulator Project: native SwiftUI iOS app (XcodeGen, Swift packages, widget extension, keychain-backed auth) ## Request > "open simulator" In this project the simulator exists for one purpose: running the app under development. The expected outcome was the app open, signed in, showing my data. It took six exchanges and roughly twenty tool calls to get there, and every intermediate state was broken in a different way. ## What happened 1. Literal-minimum interpretation. The agent ran open -a Simulator, saw no error, and reported "Simulator opened." It never checked whether the app was installed, what version was on the device, or what state it was in. The request was treated as a shell command to execute rather than a goal to achieve. 2. Wrong axis on the follow-up. Told "that is not the latest version", the agent spent four tool calls auditing Xcode's version, installed SDKs, downloadable simulator runtimes and available device models. I had just shipped a build. The referent was obviously the app. It pattern-matched on the word "version" and enumerated everything with a version number instead of reasoning about which one I could plausibly mean. 3. Broke the build it was asked to install. It compiled with CODE_SIGNING_ALLOWED=NO. That strips the code signature, so the simulator's securityd rejected every keychain call with -34018 ("Client has neither application-identifier nor keychain-access-groups entitlements"). The app's TokenStore.write fails silently on that error — it's @discardableResult — so no auth token was ever persisted. Every API request then went out unauthenticated, returned 401, and the view model's try? swallowed the errors into empty state. The dashboard rendered a signed-in shell with no data, and logging in again could never fix it because the token could not be saved. The agent later explained it uses this flag reflexively in builds where the goal is "does it compile" and signing is friction. It applied that habit to a build whose entire purpose was running the app, without considering what the flag removes. 4. Installed over a two-month-old container. The device carried an app container from June with a dead token in the keychain. The agent installed on top of it without wiping. The app restored the stale session, showed a logged-in UI with no data, and this was misdiagnosed for two more exchanges. 5. Offloaded investigation onto me. When the evidence contradicted its model, it used AskUserQuestion to ask me which component was stale — a question it had the tools to answer itself, asked after I'd said I was short on time. 6. Declared "fixed" twice without verifying the outcome. The first claim was inferred from a UserDefaults flag rather than observed. The second confirmed that the -34018 errors had stopped — i.e. that its own hypothesis was correct — but never checked whether data actually loaded. It verified the mechanism it had just changed instead of the result I'd asked for. The check that eventually proved success (reading the widget snapshot from the app-group container) was available from the first minute. ## Root cause, in the agent's own analysis Each step was optimised for the cheapest action that looked locally sufficient, with no single completion test held across the task. There was never a moment where "the app is open, signed in, showing my data" was treated as the bar. Individually cheap decisions compounded into the opposite of the request. It also failed to read its own persistent memory directory at session start, despite a stored rule instructing exactly that, and despite stored notes covering several of the specific traps it fell into (stale containers swapping the data source, and not reporting partial work as complete). ## Resolution Working state was eventually reached by: minting a session directly against the production database using the project's own token-signing helpers, verifying it returned real data over HTTP, seeding it into the keychain via a temporary #if DEBUG launch-argument hook, confirming the loaded values, then reverting the hook. Both repositories were left clean. That is a reasonable recovery. It should not have taken six exchanges of an angry user to get there. ## What I want fixed - Infer the goal behind an operational request. "Open simulator" in an iOS repo means run the app, not launch Simulator.app. - Never silently weaken a build. Flags like CODE_SIGNING_ALLOWED=NO c…
Note: Content was truncated.

View original on GitHub ↗