[GH-ISSUE #3943] [Bug] Package inspection returns absent installer as the string null #1549

Closed
opened 2026-10-16 21:07:01 +00:00 by bsakaguchi · 3 comments
Owner

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

Before submitting

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

Area

Process capture or runtime observation

Observed behavior

The sentinel reproduction exited 0 with empty stderr and this result fragment:

{
  "package_name": "com.example",
  "version_name": "1.2.3",
  "installer_package_name": "null",
  "coverage": "complete"
}

The named-installer control returned "com.android.vending". Both the missing-line and empty-value controls returned JSON null. All four CLI calls exited 0. The observed failure is in the normalized installer value; no downstream device action or physical-device behavior was tested.

Reproduction

From the baseline checkout with its built CLI available, run this isolated fake-provider reproduction:

probe=$(mktemp -d)
mkdir "$probe/home"
cat > "$probe/package.txt" <<'EOF'
Packages:
  Package [com.example] (abcdef):
    versionName=1.2.3
    installerPackageName=null
EOF
cat > "$probe/adb" <<'EOF'
#!/bin/sh
if [ "$1" = version ]; then
  printf 'Android Debug Bridge version 1.0.41\nVersion 34.0.5-stub\nInstalled as %s\n' "$0"
  exit 0
fi
if [ "$1" = '-s' ] && [ "$2" = emulator-5554 ] && [ "$3" = shell ] && [ "$4" = dumpsys ] && [ "$5" = package ]; then
  cat "$ADB_FIXTURE"
  exit 0
fi
exit 1
EOF
chmod +x "$probe/adb"
HOME="$probe/home" REA_ADB_PATH="$probe/adb" ADB_FIXTURE="$probe/package.txt" \
  node scripts/rea.mjs inspect-adb-package emulator-5554 com.example \
  --format json --full-output
rm -r "$probe"

Read data.normalized_result.installer_package_name in the JSON response. As controls, replace the installer value with com.android.vending, omit the installer line, or leave its value empty. These three controls were executed independently against the same CLI.

Expected behavior

The package inspection contract reports the package's installer through a nullable normalized result. The repository also requires interpretations to preserve omission and explicit unknowns across boundaries. A package dump that declares no installer with installerPackageName=null should return JSON null for installer_package_name, while retaining a reported installer such as com.android.vending.

This expectation concerns the meaning of the installer observation. The plain nullable-string output schema accepts the faulty string and does not by itself define sentinel conversion.

Impact and scope

The normalized package inspection result gives an incorrect present identity for an absent installer. This changes machine-readable behavior for the sentinel input, but other package facts remain usable. Physical-device frequency and downstream effects were not measured.

Workaround: A caller can map exactly the installer field's string "null" to JSON null. Applying that conversion to all four observed results preserved the named installer and correctly represented the three absence cases without changing other fields.

REA version

rea 6.5.0 at source commit 4692bb3330; current-main source checked at 22ec8bdb2f

Runtime and platform

Node 24.18.0; macOS arm64

Target and artifact context

Simulated adb dumpsys package output for com.example with installerPackageName=null. No Android device was used.

Interface

CLI

Earliest failure stage

Capture or observation

Relevant output or evidence

src/contracts/adb/adbToolContracts.ts:93-106 and docs/adb-device-analysis.md:93 document installer inspection; src/domain/adb/adbDeviceAnalysis.ts:525-544 defines its nullable result. AGENTS.md:19-29 requires preservation of omission and explicit unknowns. src/adb/AdbShellOutput.ts:262-266 normalizes only empty installer text, and src/adb/AdbProvider.ts:914-947 forwards the string. All four CLI cases exited 0.

Typed outcome or recovery expected

Return JSON null for installerPackageName=null, missing and empty installer declarations; retain com.android.vending unchanged.

Analysis or suspected cause

Source-derived: the package parser treats only an empty installer value as absent, so the literal absence sentinel passes through as a present string. The nullable string schema accepts that string; the mismatch concerns meaning, not schema rejection. MCP shares the operation but was not executed.

Additional context

This report is confined to installer absence. Window-focus parsing has a separate branch and closure signal; versionName and flags sentinel semantics were not tested.

Freshness check: the failing source is unchanged on current upstream main at 22ec8bdb2f. The only change among the cited files is unrelated CLI output-flag normalization. Runtime observations above are from the stated baseline; current-main persistence is source-derived.

Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3943 ### 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 Process capture or runtime observation ### Observed behavior The sentinel reproduction exited 0 with empty stderr and this result fragment: ```json { "package_name": "com.example", "version_name": "1.2.3", "installer_package_name": "null", "coverage": "complete" } ``` The named-installer control returned `"com.android.vending"`. Both the missing-line and empty-value controls returned JSON `null`. All four CLI calls exited 0. The observed failure is in the normalized installer value; no downstream device action or physical-device behavior was tested. ### Reproduction From the baseline checkout with its built CLI available, run this isolated fake-provider reproduction: ```sh probe=$(mktemp -d) mkdir "$probe/home" cat > "$probe/package.txt" <<'EOF' Packages: Package [com.example] (abcdef): versionName=1.2.3 installerPackageName=null EOF cat > "$probe/adb" <<'EOF' #!/bin/sh if [ "$1" = version ]; then printf 'Android Debug Bridge version 1.0.41\nVersion 34.0.5-stub\nInstalled as %s\n' "$0" exit 0 fi if [ "$1" = '-s' ] && [ "$2" = emulator-5554 ] && [ "$3" = shell ] && [ "$4" = dumpsys ] && [ "$5" = package ]; then cat "$ADB_FIXTURE" exit 0 fi exit 1 EOF chmod +x "$probe/adb" HOME="$probe/home" REA_ADB_PATH="$probe/adb" ADB_FIXTURE="$probe/package.txt" \ node scripts/rea.mjs inspect-adb-package emulator-5554 com.example \ --format json --full-output rm -r "$probe" ``` Read `data.normalized_result.installer_package_name` in the JSON response. As controls, replace the installer value with `com.android.vending`, omit the installer line, or leave its value empty. These three controls were executed independently against the same CLI. ### Expected behavior The package inspection contract reports the package's installer through a nullable normalized result. The repository also requires interpretations to preserve omission and explicit unknowns across boundaries. A package dump that declares no installer with `installerPackageName=null` should return JSON `null` for `installer_package_name`, while retaining a reported installer such as `com.android.vending`. This expectation concerns the meaning of the installer observation. The plain nullable-string output schema accepts the faulty string and does not by itself define sentinel conversion. ### Impact and scope The normalized package inspection result gives an incorrect present identity for an absent installer. This changes machine-readable behavior for the sentinel input, but other package facts remain usable. Physical-device frequency and downstream effects were not measured. Workaround: A caller can map exactly the installer field's string `"null"` to JSON null. Applying that conversion to all four observed results preserved the named installer and correctly represented the three absence cases without changing other fields. ### REA version rea 6.5.0 at source commit 4692bb33300c7cb77b095b6cc0c33da861c1b860; current-main source checked at 22ec8bdb2f7d4626587f23b1eed4a207df600386 ### Runtime and platform Node 24.18.0; macOS arm64 ### Target and artifact context Simulated adb dumpsys package output for com.example with installerPackageName=null. No Android device was used. ### Interface CLI ### Earliest failure stage Capture or observation ### Relevant output or evidence `src/contracts/adb/adbToolContracts.ts:93-106` and `docs/adb-device-analysis.md:93` document installer inspection; `src/domain/adb/adbDeviceAnalysis.ts:525-544` defines its nullable result. `AGENTS.md:19-29` requires preservation of omission and explicit unknowns. `src/adb/AdbShellOutput.ts:262-266` normalizes only empty installer text, and `src/adb/AdbProvider.ts:914-947` forwards the string. All four CLI cases exited 0. ### Typed outcome or recovery expected Return JSON null for installerPackageName=null, missing and empty installer declarations; retain com.android.vending unchanged. ### Analysis or suspected cause Source-derived: the package parser treats only an empty installer value as absent, so the literal absence sentinel passes through as a present string. The nullable string schema accepts that string; the mismatch concerns meaning, not schema rejection. MCP shares the operation but was not executed. ### Additional context This report is confined to installer absence. Window-focus parsing has a separate branch and closure signal; versionName and flags sentinel semantics were not tested. Freshness check: the failing source is unchanged on current upstream main at 22ec8bdb2f7d4626587f23b1eed4a207df600386. The only change among the cited files is unrelated CLI output-flag normalization. Runtime observations above are from the stated baseline; current-main persistence is source-derived.
Author
Owner

@XinwangTao commented on GitHub (Oct 15, 2026):

Confirmed: emitting the literal string "null" for an absent installer breaks the nullable normalized-result contract — downstream consumers cannot distinguish "no installer recorded" from a package literally named "null". The missing-line and empty-value controls returning JSON null show the intent, so the fix is to treat installerPackageName=null as an explicit unknown rather than stringifying it.

<!-- gh-comment-id:6185999623 --> @XinwangTao commented on GitHub (Oct 15, 2026): Confirmed: emitting the literal string "null" for an absent installer breaks the nullable normalized-result contract — downstream consumers cannot distinguish "no installer recorded" from a package literally named "null". The missing-line and empty-value controls returning JSON null show the intent, so the fix is to treat installerPackageName=null as an explicit unknown rather than stringifying it.
Author
Owner

@yankikucuk commented on GitHub (Oct 15, 2026):

Working on this. Reproduced with the stub-adb CLI controls above: installerPackageName=null returned the string "null" while the empty and missing forms returned JSON null. The fix normalizes Package Manager's literal null sentinel at the parser boundary for installerPackageName and for versionName, which is printed the same way; a reported installer such as com.android.vending is unchanged. Draft PR follows shortly.

<!-- gh-comment-id:6189441600 --> @yankikucuk commented on GitHub (Oct 15, 2026): Working on this. Reproduced with the stub-adb CLI controls above: `installerPackageName=null` returned the string `"null"` while the empty and missing forms returned JSON null. The fix normalizes Package Manager's literal `null` sentinel at the parser boundary for `installerPackageName` and for `versionName`, which is printed the same way; a reported installer such as `com.android.vending` is unchanged. Draft PR follows shortly.
Author
Owner

@XinwangTao commented on GitHub (Oct 22, 2026):

Fix looks correct — normalizing the literal null sentinel at the parser boundary for both installerPackageName and versionName keeps the nullable normalized-result contract intact, while a real installer like com.android.vending still passes through unchanged. The missing-line and empty-value controls already produced JSON null, so this closes the inconsistency cleanly.

<!-- gh-comment-id:6330188063 --> @XinwangTao commented on GitHub (Oct 22, 2026): Fix looks correct — normalizing the literal null sentinel at the parser boundary for both installerPackageName and versionName keeps the nullable normalized-result contract intact, while a real installer like com.android.vending still passes through unchanged. The missing-line and empty-value controls already produced JSON null, so this closes the inconsistency cleanly.
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#1549
No description provided.