[GH-ISSUE #6528] [Bug] Nonzero ADB activity refusals lose the launch report and target verdict #3921

Closed
opened 2026-10-31 00:45:15 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 23, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6528

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

Source-only finding: an ordinary nonzero am start -W refusal bypasses REA's Activity Manager verdict parser. runAmStart returns immediately when runAdb fails, so it never constructs the typed target refusal, captured output, or launch-attempt partial observation implemented below that return.

A concrete platform branch is an explicit nonexistent activity. Android emits the launch attempt and class-not-found explanation on stdout and returns status 1. REA's generic command-error branch chooses its message from stderr only. With empty stderr, the source-derived public failure is a generic unreadable_output containing adb exited with code 1 for start_adb_activity, with neither the stdout explanation nor the attempted intent retained in the public captured-output/partial-observation fields.

No runtime reproduction was performed.

Reproduction

Proposed, not run:

  1. On a connected test device, choose a component known not to exist, such as com.example/.MissingActivity.
  2. Call MCP start_adb_activity with:
{"serial":"emulator-5554","action":"android.intent.action.MAIN","component":"com.example/.MissingActivity"}
  1. Compare the REA error with the same direct adb shell am start -W -a android.intent.action.MAIN -n com.example/.MissingActivity report. Android's class-not-found branch prints a Starting: attempt and its refusal explanation to stdout, then returns 1; the REA source path skips verdict parsing for that exit.

NOT_ENOUGH_INFO: no device, command, fixture, provider stub, or public REA response was executed. The outputs above are source-derived expectations for the proposed check, not captured observations.

Expected behavior

Recognize a parsed Activity Manager refusal even when the command exits nonzero, preserve its explanation and raw report, and retain the known attempted intent. This is the behavior promised by the start tool contracts, which say failed-attempt facts and raw output are retained, and already implemented for a zero-exit refused report in runAmStart.

Transport failures and unparseable output should remain distinguishable from an explicit class-not-found verdict.

Impact and scope

Missing components and other platform launch-refusal branches that return nonzero lose useful failure evidence and receive the wrong failure classification. Callers cannot distinguish a device's explicit target refusal from unreadable output, or recover the attempted intent from the structured failure. The shared helper serves both start_adb_activity and start_adb_app; the concrete proposed input targets the former.

The scope is bounded to nonzero refusal paths; no successful launch failure is claimed. Running the same ADB command directly is a practical diagnostic bypass in principle, but was not executed here. Runtime reach, frequency, and any device-specific output differences are NOT_ENOUGH_INFO.

REA version

Audited source: main commit 49c9c9d4a14cc7d5509ec28a304dab48f85cb045. Its package metadata says 6.7.0. The same early return and generic error construction exist in tag rea-agents-6.7.0, commit 27dc42d10249f0410904a75c0997842eb03b931c; this is a tagged-source observation, not a claim that the published package was tested.

Runtime and platform

NOT_ENOUGH_INFO: no REA runtime, ADB client, emulator, or physical device was run. The concrete refusal branch is supported by Android 15 release source.

Target and artifact context

An explicit Android activity component that is absent on the selected device. No target artifact was acquired or executed.

Interface

MCP

Earliest failure stage

Transport or result projection

Relevant output or evidence

Obtained through exact-revision source inspection; no runtime output is claimed.

if (!started.ok) return started;
const verdict = parseAmStartOutput(
  started.value.stdout,
  started.value.stderr,
);

Additional context

The supplied open-issue inventory was searched for ADB activity launches, am start, nonzero refusal output, stdout/stderr loss, and captured failure reports. #6045 concerns install/uninstall verdicts, and #6046 concerns all-failed package pulls; neither describes this Activity Manager early return. Final live searches of open and closed issues found no matching report.

Triage assessment

  • Impact level: P2
  • Assessment status: provisional
  • Impact basis: Source tracing establishes that ordinary nonzero Activity Manager refusals bypass the promised evidence-retention path and collapse to a generic protocol failure. Practical impact is bounded to failed launches; no device reproduction was performed.
  • Workaround status: unverified
  • Workaround basis: A caller can in principle collect the same refusal report directly through ADB, preserving the diagnosis outside REA. That diagnostic bypass was not run on a device here.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6528 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior Source-only finding: an ordinary nonzero `am start -W` refusal bypasses REA's Activity Manager verdict parser. `runAmStart` returns immediately when `runAdb` fails, so it never constructs the typed target refusal, captured output, or launch-attempt partial observation implemented below that return. A concrete platform branch is an explicit nonexistent activity. Android emits the launch attempt and class-not-found explanation on stdout and returns status 1. REA's generic command-error branch chooses its message from stderr only. With empty stderr, the source-derived public failure is a generic `unreadable_output` containing `adb exited with code 1 for start_adb_activity`, with neither the stdout explanation nor the attempted intent retained in the public captured-output/partial-observation fields. No runtime reproduction was performed. ### Reproduction Proposed, not run: 1. On a connected test device, choose a component known not to exist, such as `com.example/.MissingActivity`. 2. Call MCP `start_adb_activity` with: ```json {"serial":"emulator-5554","action":"android.intent.action.MAIN","component":"com.example/.MissingActivity"} ``` 3. Compare the REA error with the same direct `adb shell am start -W -a android.intent.action.MAIN -n com.example/.MissingActivity` report. Android's class-not-found branch prints a `Starting:` attempt and its refusal explanation to stdout, then returns 1; the REA source path skips verdict parsing for that exit. NOT_ENOUGH_INFO: no device, command, fixture, provider stub, or public REA response was executed. The outputs above are source-derived expectations for the proposed check, not captured observations. ### Expected behavior Recognize a parsed Activity Manager refusal even when the command exits nonzero, preserve its explanation and raw report, and retain the known attempted intent. This is the behavior promised by the [start tool contracts](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/contracts/adb/adbToolContracts.ts#L325-L347), which say failed-attempt facts and raw output are retained, and already implemented for a zero-exit refused report in [runAmStart](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/adb/AdbProvider.ts#L2852-L2888). Transport failures and unparseable output should remain distinguishable from an explicit class-not-found verdict. ### Impact and scope Missing components and other platform launch-refusal branches that return nonzero lose useful failure evidence and receive the wrong failure classification. Callers cannot distinguish a device's explicit target refusal from unreadable output, or recover the attempted intent from the structured failure. The shared helper serves both `start_adb_activity` and `start_adb_app`; the concrete proposed input targets the former. The scope is bounded to nonzero refusal paths; no successful launch failure is claimed. Running the same ADB command directly is a practical diagnostic bypass in principle, but was not executed here. Runtime reach, frequency, and any device-specific output differences are NOT_ENOUGH_INFO. ### REA version Audited source: main commit `49c9c9d4a14cc7d5509ec28a304dab48f85cb045`. Its package metadata says 6.7.0. The same early return and generic error construction exist in tag `rea-agents-6.7.0`, commit `27dc42d10249f0410904a75c0997842eb03b931c`; this is a tagged-source observation, not a claim that the published package was tested. ### Runtime and platform NOT_ENOUGH_INFO: no REA runtime, ADB client, emulator, or physical device was run. The concrete refusal branch is supported by Android 15 release source. ### Target and artifact context An explicit Android activity component that is absent on the selected device. No target artifact was acquired or executed. ### Interface MCP ### Earliest failure stage Transport or result projection ### Relevant output or evidence Obtained through exact-revision source inspection; no runtime output is claimed. - Android 15 [prints the launch attempt](https://github.com/aosp-mirror/platform_frameworks_base/blob/4e43ad12e1b211f15152e9c5b16b0fe88e6b93f3/services/core/java/com/android/server/am/ActivityManagerShellCommand.java#L736-L738), [uses stdout for `-W` verdicts](https://github.com/aosp-mirror/platform_frameworks_base/blob/4e43ad12e1b211f15152e9c5b16b0fe88e6b93f3/services/core/java/com/android/server/am/ActivityManagerShellCommand.java#L794-L805), and [returns 1 for class-not-found](https://github.com/aosp-mirror/platform_frameworks_base/blob/4e43ad12e1b211f15152e9c5b16b0fe88e6b93f3/services/core/java/com/android/server/am/ActivityManagerShellCommand.java#L841-L846). - [runAmStart](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/adb/AdbProvider.ts#L2843-L2855) has the decisive gate: ```ts if (!started.ok) return started; const verdict = parseAmStartOutput( started.value.stdout, started.value.stderr, ); ``` - [The generic nonzero branch](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/adb/AdbCommand.ts#L223-L230) selects an stderr excerpt or the exit-code-only message. Its [AdbProtocolError constructor](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/adb/AdbCommand.ts#L59-L67) keeps the physical failure internally but sets only `cause`, not `capturedOutput` or `partialObservation`. - [Public error projection](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/domain/analysisErrorProjection.ts#L74-L114) emits those public fields only when explicitly retained, and [maps AnalysisProtocolError to unreadable_output](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/domain/analysisErrorProjection.ts#L249-L255). - [Tagged helper](https://github.com/morluto/rea/blob/27dc42d10249f0410904a75c0997842eb03b931c/src/adb/AdbProvider.ts#L2817-L2829) and [tagged command error](https://github.com/morluto/rea/blob/27dc42d10249f0410904a75c0997842eb03b931c/src/adb/AdbCommand.ts#L149-L156) contain the same bypass and exit-code-only fallback. ### Additional context The supplied open-issue inventory was searched for ADB activity launches, `am start`, nonzero refusal output, stdout/stderr loss, and captured failure reports. #6045 concerns install/uninstall verdicts, and #6046 concerns all-failed package pulls; neither describes this Activity Manager early return. Final live searches of open and closed issues found no matching report. ## Triage assessment - Impact level: P2 - Assessment status: provisional - Impact basis: Source tracing establishes that ordinary nonzero Activity Manager refusals bypass the promised evidence-retention path and collapse to a generic protocol failure. Practical impact is bounded to failed launches; no device reproduction was performed. - Workaround status: unverified - Workaround basis: A caller can in principle collect the same refusal report directly through ADB, preserving the diagnosis outside REA. That diagnostic bypass was not run on a device here.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3921
No description provided.