Repository navigation
fix: prepare reinstall artifacts before removing apps - #4533
Conversation
A replacement that cannot be prepared no longer removes the installed app or its data. A failure during install after the uninstall can still leave the app removed. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A replacement that cannot be materialized no longer removes the installed app. Cancellation after preparation also stops before the uninstall. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
|
Evidence for head Exact-head receipt facts and commands{
"status": "passed",
"exitCode": 0,
"refs": {
"base": "origin/main",
"head": "88bfc20263d77baedc88db4c4cdb9349bc7fe740",
"resolvedBase": "ddbfc855661fa9d29b8c836057b7f5b099bcad44",
"resolvedHead": "88bfc20263d77baedc88db4c4cdb9349bc7fe740",
"mergeBase": "ddbfc855661fa9d29b8c836057b7f5b099bcad44"
},
"exactCommit": true,
"checkoutChanged": false,
"receiptSha256": "c4709de6a6f94863ad0a7373cad28c503a1c48ce9800bf7d279851a97693035c",
"results": [
{
"id": "format",
"status": "passed",
"command": [
"pnpm",
"run",
"format:check"
],
"exitCode": 0,
"durationMs": 1279
},
{
"id": "lint",
"status": "passed",
"command": [
"pnpm",
"run",
"lint"
],
"exitCode": 0,
"durationMs": 2433
},
{
"id": "typecheck",
"status": "passed",
"command": [
"pnpm",
"run",
"typecheck"
],
"exitCode": 0,
"durationMs": 1256
},
{
"id": "layering",
"status": "passed",
"command": [
"pnpm",
"run",
"check:layering"
],
"exitCode": 0,
"durationMs": 31513
},
{
"id": "fallow",
"status": "passed",
"command": [
"pnpm",
"run",
"check:fallow",
"--base",
"ddbfc855661fa9d29b8c836057b7f5b099bcad44"
],
"exitCode": 0,
"durationMs": 9417
},
{
"id": "build",
"status": "passed",
"command": [
"pnpm",
"run",
"build"
],
"exitCode": 0,
"durationMs": 5768
},
{
"id": "vitest-related",
"status": "passed",
"command": [
"pnpm",
"exec",
"vitest",
"related",
"--run",
"--passWithNoTests",
"--project=!unit-core",
"--project=!apple-runner",
"--project=!fuzz-worker",
"packages/command-surface/src/management/install.ts",
"packages/platform-android/src/deployment/runtime.test.ts",
"packages/platform-android/src/deployment/runtime.ts",
"packages/platform-apple/src/deployment/runtime.test.ts",
"packages/platform-apple/src/deployment/runtime.ts",
"src/core/interactors/limrun-ios-runner-parity.test.ts",
"test/integration/provider-scenarios/android-reinstall.test.ts",
"test/integration/provider-scenarios/ios-lifecycle.test.ts",
"test/integration/provider-scenarios/limrun-deployment-cancellation.test.ts",
"website/docs/docs/commands.md"
],
"exitCode": 0,
"durationMs": 44184
},
{
"id": "unit",
"status": "passed",
"command": [
"pnpm",
"run",
"check:unit"
],
"exitCode": 0,
"durationMs": 233840
},
{
"id": "coverage",
"status": "skipped",
"reason": "GitHub-authoritative (jobs: Coverage)"
},
{
"id": "provider-integration",
"status": "deduplicated",
"reason": "covered by related tests"
},
{
"id": "web-smoke",
"status": "skipped",
"reason": "GitHub-authoritative (jobs: Apple / Smoke Tests (${{ matrix.platform }}), Integration Tests, Lint, Typecheck & Package, Perf Nightly / Android Command Perf, Perf Nightly / iOS Command Perf)"
},
{
"id": "command-docs",
"status": "passed",
"command": [
"pnpm",
"run",
"check:command-docs"
],
"exitCode": 0,
"durationMs": 1479
},
{
"id": "docs-links",
"status": "passed",
"command": [
"pnpm",
"run",
"check:doc-links"
],
"exitCode": 0,
"durationMs": 7886
},
{
"id": "docs-prose",
"status": "passed",
"command": [
"pnpm",
"run",
"check:doc-prose"
],
"exitCode": 0,
"durationMs": 1172
},
{
"id": "replay-ios",
"status": "skipped",
"reason": "parked, workflow_dispatch only (Replay Manual / iOS Replay Suite)"
},
{
"id": "replay-ios-device",
"status": "skipped",
"reason": "parked, workflow_dispatch only (Replay Manual / iOS Replay Suite)"
},
{
"id": "replay-macos",
"status": "skipped",
"reason": "GitHub-authoritative (jobs: Apple / Smoke Tests (${{ matrix.platform }}))"
},
{
"id": "replay-linux",
"status": "skipped",
"reason": "GitHub-authoritative (jobs: Linux / Smoke Tests)"
},
{
"id": "linux-command-evidence",
"status": "skipped",
"reason": "GitHub-authoritative (jobs: Linux / Smoke Tests)"
},
{
"id": "replay-android",
"status": "skipped",
"reason": "parked, workflow_dispatch only (Replay Manual / Android Full Emulator Suite)"
}
]
}The full-unit production fallback was retained. Skips are not passes. No separate provider run is claimed by this receipt. Native marker retention and fresh-reinstall controlsCombined #4516 (Apple) + #4517 (Android) reinstall: native evidenceCandidate: the reviewed checkout, HEAD 88bfc20, base ddbfc85. Runtime binding
Android: ReactNative_API_35B (emulator-5556, Android 15 / API 35), fixture com.callstack.audit4517fixtureFixture: Java Activity with SharedPreferences. Source, manifest, build notes and hashes are in android-fixture/ (apk sha256 4caf5036...). Bad archive: zip with only README.
Apple: iPhone 17 Pro BC54AC11 (iOS 27.0), fixture com.callstack.audit4516fixtureFixture: UIKit app with UserDefaults, source in ios-fixture/ (ipa sha256 486531ed...). bad.ipa is a text file, not a zip.
Proven vs missingProven on both platforms (API 35 emulator, iOS 27.0 simulator), with the candidate daemon: a corrupt or unmaterializable archive fails reinstall at preparation, before any uninstall or install, and the app data survives. A valid reinstall still clears data.
Cleanup
Last status: 4516+4517, exact SHA 88bfc20, native state proven (both platforms, per above), unpublished. The initial iOS fixture crash attempt is excluded, as the native report states. Only the rebuilt fixture's complete empty → saved → failed-reinstall/saved → successful-reinstall/empty sequence is evidence. Apple runner binary provenance was not independently checked; the changed deployment ordering runs in the verified candidate daemon, and this PR changes no runner source. Native cancellation was not tested. The native marker expectations were checked again against the saved raw JSON before publication. The absence of an uninstall log line is not treated as a dispatch trace: retained marker data and the successful-clearing control are the live behavioral evidence. |
Size Report
Startup median (7 runs, lower is better):
|
There was a problem hiding this comment.
All reported issues were addressed across 10 files
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
Apex Sentinel · ✅ ApproveSince the last review: 0 new · 0 still open · 1 no longer raised No open findings. 1 finding below 💬 Talking to SentinelIn a finding's thread, reply with:
On this conversation, comment Earlier reviewsReview of
|
| Where | Finding |
|---|---|
test/integration/provider-scenarios/ios-lifecycle.test.ts:415 |
iOS corrupt-archive test asserts yauzl's error text, not a typed reason |
1 finding below minor hidden (user_settings.min_severity).
Reviewed with this repository's own Sentinel configuration (ddbfc855661f).
There was a problem hiding this comment.
Apex Sentinel: 1 new finding on 88bfc20. The verdict and the full list are in the summary comment.
|
The code at 88bfc20 looks right, but two open review threads still need the test fixes described below before merge. The 23 checks are green, and they exercise the Apple and Android deployment routes this diff touches. There are no conflicts. I ran no tests and drove no device, so the native Android API 35 and iOS 27 retention evidence rests on your comment at this head. Not blocking, and you can take or leave these: the harness in packages/platform-apple/src/deployment/runtime.test.ts#L190 casts the These two open threads still apply and should be fixed before merge: #4533 (comment) (post-prepare cancellation test) and #4533 (comment) (typed no-app-bundle fixture). Please push your local fixes for both (24a20eb, not part of this review) and re-run validation at the new head. |
|
Both requested test fixes are now pushed in The exact-head local gate passed:11checks passed,8named owner skips,1provider deduplication,no failures or unrun checks. Full unit passed19,771 with10skipped;related tests passed390. The revised provider case detects the original uninstall-before-prepare order (control1pass,original runtime1fail at the no-uninstall assertion,restored control1pass). The cancellation case detects skipped cleanup,with identical source/test blobs permitting its recorded proof to carry over. CI for this pushed head is still awaited. I am keeping the watch and will not merge. Final-head local validation reportPR #4533 final feedback validationPR #4533. Reviewed head 9d79933, base ddbfc85. 1. Typed no-app provider fixture detects the original order (dirty patched evidence)BASE tree t3-95bb651d-99fe5e13e5d1cdf6 was clean at ddbfc85 before edits. Patch = git diff --binary base..9d79933 (old-order/base-to-candidate.patch, SHA256 3188a313e00fb2914f701394ee02c711e18a37a8e0d3adab096d969477b6e420). git apply --check OK, then applied. Frozen install and build ran once (setup/base-*), exit 0.
Mutant diagnostic (old-order/mutant.stderr): 2. Reused cancellation proof (not rerun)Source: 4533-cancellation-feedback/validation/logs, attributed to 24a20eb. control1 exit 0 (1 passed, 36 skipped). mutant (skips cleanup when signal.aborted) exit 1: 3. Final-head gate (single run)Reviewed tree clean at 9d79933 before install/build, after build, and after the gate. Frozen install and build exit 0 (setup/reviewed-*). Passed (exit 0): format, lint, typecheck, layering, fallow (--base ddbfc85), build, vitest-related, unit, command-docs, docs-links, docs-prose.
Limits
|
|
I found no problems in 9d79933. Both findings from the earlier review (#4533 (comment)) are now fixed, and nothing from it remains. The post-prepare cancellation case now expects prepare then cleanup and rejects with the cancellation, and the iOS lifecycle integration test now asserts the typed INVALID_ARGS code with HTTP 400 instead of matching message text. The production code is identical to 88bfc20, so this delta is two test files only. Both earlier inline threads (#4533 (comment) and #4533 (comment)) are fixed at this head, so the author can resolve them. No lower-priority threads still apply. All 22 checks pass. No conflicts. Nothing else must happen before merge. I read the code path for the two new tests but did not run them locally or run mutants against them. I also did not re-check the native device runs, which were at 88bfc20 and still cover the same production code. The integration fixtures use the host zip binary, as the Android scenario already does, and CI is green with it. |
* origin/main: fix(android): carry an empty text on a node labelled by its content description (#4531) fix(ios): restore the back swipe's pre-swipe still span (#4515) fix(daemon-client): type the remote daemon refusal with its dispatch fact (#4532) fix: prepare reinstall artifacts before removing apps (#4533) fix(ios): classify the keyboard dismiss refusal by what it dispatched (#4536) fix(ios): press the navigation bar back button and speed up the back swipe (#4508) refactor(gestures): one owner for the densified gesture path; drop the unproven sendevent transport (#4239) fix(host-kit): keep Linux process identity stable across clock steps (#4438) fix(ios): bound the idle wait of keyboard dismiss and keyboard enter (#4454) fix(device-selection): fail an ambiguous device request with only the tied devices (#4506)
Summary
Prepare Apple and Android replacement artifacts before uninstalling the existing app. An archive that cannot be unpacked now fails while the app and its data remain installed. Successful reinstall still creates fresh app state.
The 10-file change preserves cache invalidation, cancellation, hosted installers and cleanup. Invalid app bundles, corrupt APKs or later installation failures can still leave the app removed. No validator or rollback is added.
Closes #4516. Closes #4517. Refs #4368.
Validation
Tested
9d7993318de5d202ecb7c653ff099baca1f43e8fagainstddbfc855661fa9d29b8c836057b7f5b099bcad44:pnpm check:affected --run --head <sha> --jsonpassed: 11 checks passed, 8 named skips, 1 provider deduplication. Full unit: 19,771 passed/10 skipped; related: 390 passed.88bfc202retained saved markers after bad-archive failures and cleared them after valid reinstall. Owned resources were cleaned up.CI is green at this head (21 successful checks, 1 skipped); no review threads are open. Historical provider timeout causes remain unproven. Native cancellation and arbitrary invalid APK/app-bundle protection are not claimed.
Validation evidence.