Skip to content

refactor(android): allow providers to install prepared app artifacts - #4194

Merged
thymikee merged 1 commit into
callstack:mainfrom
muvaf:codex/android-deployment-installer
Nov 3, 2026
Merged

thymikee merged 1 commit into
callstack:mainfrom
muvaf:codex/android-deployment-installer

Conversation

@muvaf

@muvaf muvaf commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Allow hosted Android artifact installers through shared deployment operations; preserve installer results and materialized package identity. Four files; extraction requested in #4174. Local ADB remains the default; no production provider switches here.

Related work

Independent siblings: lease lifecycle #4195, recordings #4196. Apple hooks follow this; native Limrun XCTest follows all layers to replace AX.

Validation

Tested 4d65affa7cddbb7ad0a3340a4dc36c12b9c13aea, base a2c169fa502a53f1f2a1da25b1cd16b9c731af39. pnpm check:affected --run --base <base> --head <head> passed (exactCommit:true, 17,144 unit tests; one skipped). Identity regressions fail without fixes.

Live device: emulator-5588, Android 16 Google Play ARM64, SDK 36.1. Built SDK calls routed through the daemon:

import {createAgentDeviceClient} from './dist/src/index.js';
const root = '/private/tmp/agent-device-review2/android-live';
const client = createAgentDeviceClient({session: 'android-installer-review4194', stateDir: `${root}/state`, debug: true});
const target = {platform: 'android', serial: 'emulator-5588'};
const app = 'com.agentdevice.installerreview';
await client.apps.install({...target, appPath: `${root}/fixtures/v1/installer-review.apk`});
await client.apps.open({...target, app});
await client.apps.reinstall({...target, app, appPath: `${root}/fixtures/v2/installer-review.apk`});
await client.apps.open({...target, app});
await client.apps.installFromSource({...target, source: {kind: 'path', path: `${root}/fixtures/source-v3.zip`}});
await client.apps.open({...target, app});

Observed outputs:

Operation Result
Path appId=package=com.agentdevice.installerreview; versionCode=1; MainActivity resumed.
Reinstall versionCode=2; adb -s emulator-5588 shell run-as com.agentdevice.installerreview ls files/pre-reinstall-marker changed from present to No such file or directory.
ZIP appId=packageName=launchTarget=com.agentdevice.installerreview; versionCode=3; extracted directory removed; source ZIP/data preserved.

Each snapshot -i --json showed its version title and androidSnapshot={backend:"android-helper",helperVersion:"0.21.37-dev"}, matching package.json. Session/daemon/emulator cleanup passed. Complete commands/outputs, reproduction.

Independent review passed. GitHub owns remaining device/coverage/provider checks; Vercel requires maintainer authorization.


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

View guided diff

@vercel

vercel Bot commented Nov 3, 2026

Copy link
Copy Markdown

@muvaf is attempting to deploy a commit to the Callstack Team on Vercel.

A member of the Team first needs to authorize it.

@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.

2 issues found across 4 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/platform-android/src/deployment/runtime.ts">

<violation number="1" location="packages/platform-android/src/deployment/runtime.ts:143">
P2: Same gap on the source-install path: when the injected installer returns no `packageName`, the owner returns `{}` and drops the identity it already has from `artifact.packageName`. Fall back to the artifact identity here too.</violation>

<violation number="2" location="packages/platform-android/src/deployment/runtime.ts:173">
P2: This branch discards the materialized artifact identity and the provider's other result fields by reading only `packageName`. A provider result without `packageName` therefore throws despite `input.artifact.packageName` being available, while `appName` and `launchTarget` are lost; preserve the full installer result and fall back to the artifact identity in both install paths.</violation>
</file>

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

View guided diff | Re-trigger cubic

signal,
);
const packageName = install
? (await install(artifact, signal)).packageName

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.

P2: Same gap on the source-install path: when the injected installer returns no packageName, the owner returns {} and drops the identity it already has from artifact.packageName. Fall back to the artifact identity here too.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/platform-android/src/deployment/runtime.ts, line 143:

<comment>Same gap on the source-install path: when the injected installer returns no `packageName`, the owner returns `{}` and drops the identity it already has from `artifact.packageName`. Fall back to the artifact identity here too.</comment>

<file context>
@@ -133,13 +139,15 @@ async function deployAndroidApp(
-      signal,
-    );
+    const packageName = install
+      ? (await install(artifact, signal)).packageName
+      : await installAndroidArtifact(
+          host,
</file context>
Suggested change
? (await install(artifact, signal)).packageName
? ((await install(artifact, signal)).packageName ?? artifact.packageName)

signal,
);
const packageName = install
? (await install(input.artifact, signal)).packageName

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.

P2: This branch discards the materialized artifact identity and the provider's other result fields by reading only packageName. A provider result without packageName therefore throws despite input.artifact.packageName being available, while appName and launchTarget are lost; preserve the full installer result and fall back to the artifact identity in both install paths.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/platform-android/src/deployment/runtime.ts, line 173:

<comment>This branch discards the materialized artifact identity and the provider's other result fields by reading only `packageName`. A provider result without `packageName` therefore throws despite `input.artifact.packageName` being available, while `appName` and `launchTarget` are lost; preserve the full installer result and fall back to the artifact identity in both install paths.</comment>

<file context>
@@ -159,14 +167,17 @@ async function deployPreparedAndroidApp(
-    signal,
-  );
+  const packageName = install
+    ? (await install(input.artifact, signal)).packageName
+    : await installAndroidArtifact(
+        host,
</file context>

@thymikee

thymikee commented Nov 3, 2026

Copy link
Copy Markdown
Member

The installation dispatch at fa67e69 needs live Android validation before merge. The PR says no Android device was attached, so unit doubles do not establish native transfer or the installed identity. Please record the head SHA, device, commands, and observable results for daemon-routed Android path install, reinstall, and materialized/source install, including installed identity and launch, replacement and data removal, and cleanup. Include snapshot -i --json showing android-helper with a matching helperVersion. A production provider binding the callback will also need live callback evidence. Installation dispatch

The two open threads on install identity and source install identity still apply.

Only Vercel fails, and the bot requests authorization for the external contributor; the changed Android files do not overlap website or Vercel configuration, so this failure appears unrelated. There are no known conflicts. Address the two identity threads and provide the live Android evidence before merge; Vercel authorization remains separate.

This review did not run tests or a live device, and the external validation gist was not available for review.

@muvaf
muvaf force-pushed the codex/android-deployment-installer branch from fa67e69 to 4d65aff Compare November 3, 2026 18:00
@thymikee

thymikee commented Nov 3, 2026

Copy link
Copy Markdown
Member

At 4d65aff the install-identity fallback now covers path and materialized installs, so both earlier identity threads are fixed. The live Android run is the remaining gap.

Could you provide accessible exact-head receipts for daemon-routed Android path install and launch, reinstall with data-removal proof, and source/ZIP materialization install and launch with identity and artifact cleanup proof? Please include the device, commands and observable outputs. The linked evidence repository was unavailable for inspection, so the run summary could not be verified. Install dispatch

The path identity and materialized identity threads no longer apply and can be resolved.

The only failing check is the Vercel deploy, which needs team authorization for this fork and does not build this change. There are no conflicts. Before merge, please make the Android receipts accessible.

@thymikee

thymikee commented Nov 3, 2026

Copy link
Copy Markdown
Member

Thanks, the live run settles the remaining point at 4d65aff. The recorded result is attributed to this exact commit and covers path install and launch, reinstall with the data marker removed, and ZIP materialization with the right identity and cleanup, with android-helper at the package version. The code looks good and there are no conflicts; the only failing check is the Vercel deploy, which needs team authorization for this fork.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Nov 3, 2026
@thymikee
thymikee merged commit 035c2b6 into callstack:main Nov 3, 2026
11 of 12 checks passed
@muvaf
muvaf deleted the codex/android-deployment-installer branch November 4, 2026 01:17
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.

2 participants