Skip to content

fix(apple): refuse clear-app-state for apps with no data container - #3332

Merged
thymikee merged 2 commits into
mainfrom
fix/clear-app-state-null-container-3305
Oct 9, 2026
Merged

thymikee merged 2 commits into
mainfrom
fix/clear-app-state-null-container-3305

Conversation

@thymikee

@thymikee thymikee commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Summary

settings clear-app-state on an iOS simulator system app (e.g. com.apple.Preferences) crashed with ENOENT … scandir '(null)': simctl get_app_container … data exits 0 and prints the literal (null) for an app with no data container, and the old guard rejected only empty stdout before handing the sentinel to readHostDirectory. Every get_app_container stdout now goes through one classifier, readSimctlContainerPath (simctl.ts), which treats (null) and empty output as the tool's no-container answer. clear-app-state refuses it with UNSUPPORTED_OPERATION keyed on typed details.reason: app-no-data-container (names the app; hint/details survive normalizeError). The runner-screenshot container loop — the sibling reading the same data domain — shares the fix through the same classifier and no longer probes a (null) path. The app-domain readers (launch-diagnostics, perf-target, logs/start) were probed live and are unaffected: system apps answer the app domain with a real runtime-root path, missing apps exit non-zero. CLI, Node client, and MCP surfaces verified live; docs and --help detail updated. The refusal's recovery guidance points at what a caller can actually do (erase/recreate the simulator; uninstall an app they installed), since runtime-shipped apps cannot be uninstalled. 8 files.

Closes #3305

Validation

Tested commits 701977ff3 + faba0da3e (guidance-text fix).

  • pnpm check:affected --run exit 0 on faba0da3e, including command-docs (commands.md asserted against the CLI in both directions). Earlier run on 701977ff3: 3 unrelated load flakes (runner-cache-retention, provider ios/android-lifecycle, snapshot-source/preparation ENOTEMPTY) — each passed in isolation and on rerun of the same head.
  • Focused: app-settings/screenshot/simctl suites pass; regression tests observed failing without the fix (old code reaches readHostDirectory('(null)')).
  • Live (iPhone 17 Pro BC54AC11…, iOS 27.0): node bin/agent-device.mjs settings clear-app-state clear --app com.apple.Preferences --platform ios --udid <udid> → Error (UNSUPPORTED_OPERATION): com.apple.Preferences has no data container to clear… exit 1, hint offering simulator-erase/self-installed-app recovery; --json carries details.reason: app-no-data-container + hint + diagnosticId + logPath. com.example.miniapp clear still succeeds (exit 0, fresh-install layout). Node client and MCP stdio tools/call surface the typed refusal un-degraded.

Unresolved risks: none beyond CI arbitration of provider-integration/coverage jobs.

simctl get_app_container answers an installed app that owns no data
container (system apps shipped in the simulator runtime, such as
com.apple.Preferences) by exiting 0 and printing the literal (null).
clearIosSimulatorAppState only rejected an empty stdout, so the
sentinel reached readHostDirectory and the command failed with
ENOENT: no such file or directory, scandir '(null)' instead of a
refusal.

Route every get_app_container stdout through one classifier,
readSimctlContainerPath, which treats the (null) sentinel and empty
output as the tool's no-container answer. clear-app-state now refuses
it with UNSUPPORTED_OPERATION keyed on the typed reason
app-no-data-container, naming the app; the runner-screenshot container
loop already skips that answer instead of probing a (null) path.

Closes #3305
@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 8, 2026
@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-09 06:54 UTC

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.13 MB 5.13 MB +718 B
Package (unpacked) 5.13 MB 5.13 MB +718 B
Package (download) 1.54 MB 1.54 MB +305 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 21.9 ms 22.1 ms +0.2 ms
CLI --help 63.4 ms 64.4 ms +1.0 ms

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 8 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/platform-apple/src/core/app-settings.ts Outdated
Comment thread website/docs/docs/commands.md Outdated
The hint and the command doc told the caller to uninstall and
reinstall the refused app, but the motivating class ships inside the
simulator runtime and cannot be uninstalled, so the advertised
recovery was unavailable for precisely the app that triggers the
refusal. Point at what a caller can actually do: erase or recreate
the simulator device, or uninstall an app they installed themselves.
Typed reason and details are unchanged.
@thymikee

thymikee commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

Fixed the unavailable-recovery claim at the owning string in faba0da: the hint constant in app-settings.ts (whose docstring carried the same claim), the commands.md bullet, and re-checked the cliDetail versioned-help string — it never carried an uninstall/reinstall recovery claim (only the reason name), so it needed no change. The hint now reads: 'Clear the app under test instead. A runtime-shipped app keeps no data container, so this command has no app state to remove; to reset it, erase or recreate the simulator device, or uninstall and reinstall the app if you installed it yourself.' Typed reason/details unchanged; the /Clear the app under test instead/ and /com.apple.Preferences has no data container to clear/ assertions both still stand (verified live on the rebuilt CLI). pnpm check:affected --run exit 0 on faba0da incl. command-docs.

@thymikee

thymikee commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

The PR is ready for human review at faba0da, and I found no problems in the code. All 21 checks pass, and none are failing. There are no conflicts.

Not blocking: in clearIosSimulatorAppState, closeIosApp runs before the container is read, so a refused clear on a system app such as com.apple.Preferences still terminates the running app. The test double accepts the terminate call, so the order is only implied by the tests. Reading and classifying the container first would make the refusal free of side effects, and the terminate should stay before the delete. The reason string app-no-data-container is kebab-case, while session_app_required is snake_case (line 204). The neighbouring platform-apple reasons are also kebab-case, so this is fine today. You can take or leave both.

The two review threads on the hint wording (app-settings.ts) and the docs text (commands.md) are fixed at this commit, so they no longer apply and can be resolved.

On evidence, I did not run the tests locally. The claim that the new tests fail without the fix rests on my reading of the old code path. The live iOS 27.0 simulator run and the Node client and MCP checks are the author's reports, and I did not rerun them. I also could not confirm that the app domain returns a real path for system apps, since that needs a simulator.

@thymikee
thymikee merged commit d87cf26 into main Oct 9, 2026
21 checks passed
@thymikee
thymikee deleted the fix/clear-app-state-null-container-3305 branch October 9, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

settings clear-app-state fails with ENOENT … scandir '(null)' for iOS system apps such as Settings

1 participant