[GH-ISSUE #1813] [Design] Android split APK sets: set identity and relationship evidence before a bundletool lane #612

Open
opened 2026-10-15 18:26:37 +00:00 by bsakaguchi · 4 comments
Owner

Originally created by @cevieiras on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1813

Decision needed

Should REA give an Android split APK set its own identity and relationship evidence, starting with a check that needs no new external tool, before adding a bundletool lane for AAB/APKS?

Concretely: is a caller-selected set of APKs (base.apk plus split_config.* / feature splits, as pull_adb_package already acquires them) a first-class analysis input whose members, roles and consistency are reported with explicit evidence and unknowns, rather than being analyzed as unrelated files?

This is the "AAB/APKS/base/split relationships" follow-up in #717. It narrows that item to the part that can be decided now.

Context and evidence

Observed on main at e4407dbed:

Area Current behavior Source
ADB acquisition pull_adb_package pulls the complete set reported by pm path and digests each file. adb-device-analysis.md
Member role base / split / unknown, derived only from the file name; reported as role_basis: file_name. parsePmPathOutput
Relationships None. Nothing records which split configures which ABI, density, language or feature module, nor whether the files belong together. —
JADX lane One APK is snapshotted to target.apk; identity is that one file's SHA-256. snapshotAndroidTarget
Apktool lane Decodes one APK; smali is skipped. apktool-resource-analysis.md
Documented gap "These operations do not … provide split APK/AAB handling"; an .aab is a ZIP, not an APK. android-analysis.md

Consequence: analyzing base.apk alone omits resources, native libraries and (for dynamic feature modules) DEX that live in other members, and the Evidence does not say so.

Prototype (derived, author-run)

I built a local prototype to test whether the first step is tractable before proposing it. It is not published; I can push it to a fork branch if that helps review. It is organized as four small stacked changes with no new tool surface:

  1. a pure check over caller-selected manifest facts (package and effective version-code agreement, duplicate split names, missing parents, coverage);
  2. a bounded reader for the top-level attributes of a compiled AndroidManifest.xml (package, versionCode/versionCodeMajor, split, configForSplit, isFeatureSplit, isolatedSplits, targetSandboxVersion, uses-sdk, isSplitRequired);
  3. source-built fixtures compiled with a caller-supplied aapt2 (base, ABI/language/density config splits, a feature split and its config split, version-mismatch and missing-parent variants);
  4. a thin adapter that reads the manifest and lib/<abi>/ paths from an APK through ZipArtifactReader.

What it established:

  • aapt2 link accepts split, configForSplit and isFeatureSplit; the framework resource ids match aapt2 dump xmltree output.
  • isSplitRequired is declared on <application>, not on <manifest>. versionCodeMajor (API 28+) must be read, otherwise two different effective versions can look equal.
  • A reader that decodes the whole string pool eagerly can be made to exhaust memory with a small input (many offsets to one large UTF-16 string); lazy decoding with per-string and aggregate budgets removes that.
  • Attribute ranges must be validated against the element's own chunk, and the element tree must be balanced, or a forged attributeStart can read facts from a following chunk.
  • ZipArtifactReader.entries() can surface bare Error instances from zip.js (for example "File format is not recognized") next to its typed ArtifactReaderFailure.

Verification so far: 42 unit tests, tsc, lint, module boundaries and test discovery pass on top of main; two guards were mutation-checked. Not verified: real-world manifests from large applications, the numeric limits (they are starting points, not measurements), and any provider other than aapt2-built fixtures.

Boundary and invariants

  • Layering. Manifest facts and the set check are pure (src/domain/android/); the binary-XML reader and the ZIP adapter are artifact readers (src/artifacts/android/). No provider process is needed for an installed split set.
  • Evidence classes stay distinct. Manifest values and ZIP paths are observed; agreement and duplicates are derived; a role that relies on the platform default of an undeclared isFeatureSplit is marked as derived, not observed; lib/<abi>/ names are path-level evidence, not confirmed from ELF headers.
  • Absence is not proof. Coverage describes the caller's selection. It cannot show that every installed or published APK was selected; an empty or all-silent selection reports unknown, never "consistent".
  • No execution, no signature claim. Nothing runs the APK; signature verification stays not_performed and belongs to a separate bring-your-own apksigner lane.
  • Bring-your-own tools. bundletool, if added, is caller-supplied and never installed, following the Apktool/JADX pattern.
  • Hostile input. Document size, string count, per-string and aggregate decoded bytes, and chunk count are bounded before work is done; failures are typed rather than thrown.

Options and tradeoffs

Option What it gives Cost / risk
A. Keep per-APK analysis only No change. The set stays invisible; analyses silently omit members.
B. Manifest-based set check, no bundletool (proposed first step) Relationships and consistency for installed splits from data REA can already read; no new external dependency. Needs a small, bounded binary-XML reader; AAB/APKS remain unsupported.
C. Merge a split set into one APK for JADX/Apktool One artifact for existing lanes. Creates a derived artifact with its own identity and signature implications; should follow, not precede, B.
D. bundletool for everything Handles AAB/APKS. Does not apply to installed splits (plain APKs); heavy dependency for the common case.

B and D are complementary: B covers what ADB acquisition already delivers; a read-only bundletool lane (inspect-style, AAB/APKS only) can follow for the formats B cannot read. build-apks / extract-apks / install-apks produce artifacts or touch a device and would need their own design with explicit module and device-spec selection.

Success criteria and open questions

The decision is settled when maintainers agree on (a) whether set identity belongs in REA, (b) where its public surface lives, and (c) the order B → bundletool.

Open questions that could change the choice:

  1. Surface. A new inspect_android_split_set, or extend inspect_android_package to accept a set? Extending changes the retained-session target identity of the JADX lane.
  2. Manifest reading. Is a small pure reader under src/artifacts/android/ acceptable, or should manifest facts come from an existing provider (JADX/Apktool) per member? The reader is cheap and bounded; a provider reuses decoded semantics but is heavy per member.
  3. Roles. Should pull_adb_package's file-name role stay as an inference superseded by the manifest-based role in the new result, or be enriched in place?
  4. Overlap with #717's slices. The ABI-inventory and signing-block slices proposed in the #717 thread overlap with path-level ABI evidence and signature facts. Should those land first, or should this reuse them?
  5. Granularity. Four stacked PRs (set check; manifest reader; fixtures; APK adapter), or a different split? None adds a tool surface until question 1 is answered.
  6. bundletool selection (later). A JAR path (like REA_JADX_MCP_JAR) plus the existing JDK resolution, or an Apktool-style launcher variable?

I am happy to implement this in small, independently verifiable pull requests once the surface question is settled, and to coordinate with whoever picks up the ABI and signing slices.

References

Originally created by @cevieiras on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1813 ## Decision needed Should REA give an Android **split APK set** its own identity and relationship evidence, starting with a check that needs no new external tool, before adding a bundletool lane for AAB/APKS? Concretely: is a caller-selected set of APKs (`base.apk` plus `split_config.*` / feature splits, as `pull_adb_package` already acquires them) a first-class analysis input whose members, roles and consistency are reported with explicit evidence and unknowns, rather than being analyzed as unrelated files? This is the "AAB/APKS/base/split relationships" follow-up in #717. It narrows that item to the part that can be decided now. ## Context and evidence Observed on `main` at `e4407dbed`: | Area | Current behavior | Source | | --- | --- | --- | | ADB acquisition | `pull_adb_package` pulls the complete set reported by `pm path` and digests each file. | [`adb-device-analysis.md`](https://github.com/morluto/rea/blob/e4407dbed/docs/adb-device-analysis.md#L112) | | Member role | `base` / `split` / `unknown`, derived **only from the file name**; reported as `role_basis: file_name`. | [`parsePmPathOutput`](https://github.com/morluto/rea/blob/e4407dbed/src/adb/AdbDeviceOutput.ts#L218) | | Relationships | None. Nothing records which split configures which ABI, density, language or feature module, nor whether the files belong together. | — | | JADX lane | One APK is snapshotted to `target.apk`; identity is that one file's SHA-256. | [`snapshotAndroidTarget`](https://github.com/morluto/rea/blob/e4407dbed/src/android/AndroidTargetSnapshot.ts#L18) | | Apktool lane | Decodes one APK; smali is skipped. | [`apktool-resource-analysis.md`](https://github.com/morluto/rea/blob/e4407dbed/docs/apktool-resource-analysis.md#L63) | | Documented gap | "These operations do not … provide split APK/AAB handling"; an `.aab` is a ZIP, not an APK. | [`android-analysis.md`](https://github.com/morluto/rea/blob/e4407dbed/docs/android-analysis.md#L127) | Consequence: analyzing `base.apk` alone omits resources, native libraries and (for dynamic feature modules) DEX that live in other members, and the Evidence does not say so. ### Prototype (derived, author-run) I built a local prototype to test whether the first step is tractable before proposing it. It is **not published**; I can push it to a fork branch if that helps review. It is organized as four small stacked changes with no new tool surface: 1. a pure check over caller-selected manifest facts (package and effective version-code agreement, duplicate split names, missing parents, coverage); 2. a bounded reader for the top-level attributes of a compiled `AndroidManifest.xml` (`package`, `versionCode`/`versionCodeMajor`, `split`, `configForSplit`, `isFeatureSplit`, `isolatedSplits`, `targetSandboxVersion`, `uses-sdk`, `isSplitRequired`); 3. source-built fixtures compiled with a caller-supplied `aapt2` (base, ABI/language/density config splits, a feature split and its config split, version-mismatch and missing-parent variants); 4. a thin adapter that reads the manifest and `lib/<abi>/` paths from an APK through `ZipArtifactReader`. What it established: - `aapt2 link` accepts `split`, `configForSplit` and `isFeatureSplit`; the framework resource ids match `aapt2 dump xmltree` output. - `isSplitRequired` is declared on `<application>`, not on `<manifest>`. `versionCodeMajor` (API 28+) must be read, otherwise two different effective versions can look equal. - A reader that decodes the whole string pool eagerly can be made to exhaust memory with a small input (many offsets to one large UTF-16 string); lazy decoding with per-string and aggregate budgets removes that. - Attribute ranges must be validated against the element's own chunk, and the element tree must be balanced, or a forged `attributeStart` can read facts from a following chunk. - `ZipArtifactReader.entries()` can surface bare `Error` instances from zip.js (for example "File format is not recognized") next to its typed `ArtifactReaderFailure`. Verification so far: 42 unit tests, `tsc`, lint, module boundaries and test discovery pass on top of `main`; two guards were mutation-checked. **Not verified:** real-world manifests from large applications, the numeric limits (they are starting points, not measurements), and any provider other than `aapt2`-built fixtures. ## Boundary and invariants - **Layering.** Manifest facts and the set check are pure (`src/domain/android/`); the binary-XML reader and the ZIP adapter are artifact readers (`src/artifacts/android/`). No provider process is needed for an installed split set. - **Evidence classes stay distinct.** Manifest values and ZIP paths are observed; agreement and duplicates are derived; a role that relies on the platform default of an undeclared `isFeatureSplit` is marked as derived, not observed; `lib/<abi>/` names are path-level evidence, not confirmed from ELF headers. - **Absence is not proof.** Coverage describes the caller's selection. It cannot show that every installed or published APK was selected; an empty or all-silent selection reports `unknown`, never "consistent". - **No execution, no signature claim.** Nothing runs the APK; signature verification stays `not_performed` and belongs to a separate bring-your-own `apksigner` lane. - **Bring-your-own tools.** bundletool, if added, is caller-supplied and never installed, following the Apktool/JADX pattern. - **Hostile input.** Document size, string count, per-string and aggregate decoded bytes, and chunk count are bounded before work is done; failures are typed rather than thrown. ## Options and tradeoffs | Option | What it gives | Cost / risk | | --- | --- | --- | | A. Keep per-APK analysis only | No change. | The set stays invisible; analyses silently omit members. | | **B. Manifest-based set check, no bundletool (proposed first step)** | Relationships and consistency for installed splits from data REA can already read; no new external dependency. | Needs a small, bounded binary-XML reader; AAB/APKS remain unsupported. | | C. Merge a split set into one APK for JADX/Apktool | One artifact for existing lanes. | Creates a derived artifact with its own identity and signature implications; should follow, not precede, B. | | D. bundletool for everything | Handles AAB/APKS. | Does not apply to installed splits (plain APKs); heavy dependency for the common case. | B and D are complementary: B covers what ADB acquisition already delivers; a read-only bundletool lane (`inspect`-style, AAB/APKS only) can follow for the formats B cannot read. `build-apks` / `extract-apks` / `install-apks` produce artifacts or touch a device and would need their own design with explicit module and device-spec selection. ## Success criteria and open questions The decision is settled when maintainers agree on (a) whether set identity belongs in REA, (b) where its public surface lives, and (c) the order B → bundletool. Open questions that could change the choice: 1. **Surface.** A new `inspect_android_split_set`, or extend `inspect_android_package` to accept a set? Extending changes the retained-session target identity of the JADX lane. 2. **Manifest reading.** Is a small pure reader under `src/artifacts/android/` acceptable, or should manifest facts come from an existing provider (JADX/Apktool) per member? The reader is cheap and bounded; a provider reuses decoded semantics but is heavy per member. 3. **Roles.** Should `pull_adb_package`'s file-name `role` stay as an inference superseded by the manifest-based role in the new result, or be enriched in place? 4. **Overlap with #717's slices.** The ABI-inventory and signing-block slices proposed in the #717 thread overlap with path-level ABI evidence and signature facts. Should those land first, or should this reuse them? 5. **Granularity.** Four stacked PRs (set check; manifest reader; fixtures; APK adapter), or a different split? None adds a tool surface until question 1 is answered. 6. **bundletool selection** (later). A JAR path (like `REA_JADX_MCP_JAR`) plus the existing JDK resolution, or an Apktool-style launcher variable? I am happy to implement this in small, independently verifiable pull requests once the surface question is settled, and to coordinate with whoever picks up the ABI and signing slices. ## References - #717 (Android analysis roadmap); #738 (JADX), #1552 (ADB), #1556 (Apktool resource decoding) - [`docs/android-analysis.md`](https://github.com/morluto/rea/blob/e4407dbed/docs/android-analysis.md), [`docs/adb-device-analysis.md`](https://github.com/morluto/rea/blob/e4407dbed/docs/adb-device-analysis.md), [`docs/apktool-resource-analysis.md`](https://github.com/morluto/rea/blob/e4407dbed/docs/apktool-resource-analysis.md) - [`src/artifacts/ZipArtifactReader.ts`](https://github.com/morluto/rea/blob/e4407dbed/src/artifacts/ZipArtifactReader.ts) - Android documentation: [`aapt2`](https://developer.android.com/tools/aapt2), [bundletool](https://developer.android.com/tools/bundletool)
Author
Owner

@tackyou0-dev commented on GitHub (Oct 12, 2026):

REA #1813 - split APK set-20261012T062206Z-1-001.zip

<!-- gh-comment-id:6118930520 --> @tackyou0-dev commented on GitHub (Oct 12, 2026): [REA #1813 - split APK set-20261012T062206Z-1-001.zip](https://github.com/user-attachments/files/33323924/REA.1813.-.split.APK.set-20261012T062206Z-1-001.zip)
Author
Owner

@cevieiras commented on GitHub (Oct 14, 2026):

The stack is now rebased on current main and passes npm run check at each branch tip: set check, manifest reader, fixtures and tests, APK adapter. None adds a tool surface.

I have opened the first two PRs (set check: #3495, manifest reader: #3496) as independent, no-surface changes so they can be reviewed in parallel. #3496 is a draft stacked on #3495 and will be rebased once that lands. The fixtures and APK adapter stay on hold until questions 1 and 4 are settled.

<!-- gh-comment-id:6169146939 --> @cevieiras commented on GitHub (Oct 14, 2026): The stack is now rebased on current `main` and passes `npm run check` at each branch tip: set check, manifest reader, fixtures and tests, APK adapter. None adds a tool surface. I have opened the first two PRs (set check: #3495, manifest reader: #3496) as independent, no-surface changes so they can be reviewed in parallel. #3496 is a draft stacked on #3495 and will be rebased once that lands. The fixtures and APK adapter stay on hold until questions 1 and 4 are settled.
Author
Owner

@Rinkia commented on GitHub (Oct 14, 2026):

A real-world data point for the "not verified: real-world manifests from large applications" gap, plus one input-format observation. rea-agents@6.5.0, Linux x64 Docker.

Target: tinyCam Monitor 19.0.3 (com.alexvas.dvr, versionCode 70120), a Google Play build downloaded as an APKMirror .apkm bundle (sha256 15b59a9e302a2976069a6e5fe3a321cf9474dade790cada825a8131f2ceeb9aa). Proprietary app, so only manifest metadata is quoted here. 21 member APKs: base.apk (10.9 MB, 12,463 classes), 2 ABI splits (82.5 MB arm64, 48 MB armv7), 2 density splits and 16 language splits.

Manifest facts across all 21 members

Read per member with the existing JADX lane (inspect-android-package on each extracted APK): 21/21 succeeded, 79 s in total (about 3–8 s per member).

Members split android:splitTypes versionCode configForSplit / isFeatureSplit / isSplitRequired / versionCodeMajor Play derived.apk.id
base none "" 70120 all absent 2
16 language config.de, config.es, … "" 70120 all absent 2
2 ABI config.arm64_v8a, config.armeabi_v7a base__abi 70120 all absent 2
2 density config.xxhdpi, config.xxxhdpi base__density 70120 all absent 2

What differs from the prototype's attribute list:

  • The base declares the requirement differently from isSplitRequired. It has android:requiredSplitTypes="base__abi,base__density" on <manifest> (Android 14 split types), and <application> has no isSplitRequired. Play also adds meta-data: com.android.vending.splits.required=true, com.android.vending.splits → @xml/splits0 (a resource listing the expected splits), and com.android.vending.derived.apk.id=2.
  • Config splits carry split="config.*" plus splitTypes, but no configForSplit. Their role (ABI, density or language) is declared through splitTypes, except language splits, which use "", the same as the base.
  • Config splits declare <application android:hasCode="false">.

For the proposed set check, requiredSplitTypes versus the union of member splitTypes could be an observed coverage fact. Here the base requires base__abi and base__density, and the set provides both, while language coverage isn't expressible through split types. derived.apk.id agreement across members may also be a useful consistency signal, though I don't know Play's guarantees for it.

Input-format observation: third-party bundle containers

The set arrived as an APKMirror .apkm: a ZIP containing the 21 APKs plus info.json (apkm_version: 5, pname, versioncode, variant, languages, capabilities), icon.png, APKM_installer.url, and a META-INF/APKMIRRO.SF/.RSA signature over the container, not over the APKs. Current behavior:

  • inspect-android-package on the .apkm: a clear refusal, "Target … is zip; provide one standalone APK".
  • inspect-artifact on the .apkm: one root-manifest observation, with empty hypotheses, unexplored_branches and next_probes, so nothing indicates that it holds a split set.

.apkm, .xapk and .apks are how many people obtain split sets without ADB. Even if the set check only accepts caller-selected member APKs (option B), it might help if inspect_artifact recognised these containers and pointed to the member APKs as the selection, while recording the container's metadata as unverified provenance rather than as evidence of set membership.

On open question 2 (manifest source): the JADX lane already gives every member's decoded manifest text at a moderate cost (79 s for 21 members here, dominated by JVM startup and APK load). A pure reader would avoid that cost, but the per-member provider route works today, if a comparison point is useful.

<!-- gh-comment-id:6172805385 --> @Rinkia commented on GitHub (Oct 14, 2026): A real-world data point for the "not verified: real-world manifests from large applications" gap, plus one input-format observation. `rea-agents@6.5.0`, Linux x64 Docker. **Target:** tinyCam Monitor 19.0.3 (`com.alexvas.dvr`, versionCode 70120), a Google Play build downloaded as an APKMirror `.apkm` bundle (sha256 `15b59a9e302a2976069a6e5fe3a321cf9474dade790cada825a8131f2ceeb9aa`). Proprietary app, so only manifest metadata is quoted here. 21 member APKs: `base.apk` (10.9 MB, 12,463 classes), 2 ABI splits (82.5 MB arm64, 48 MB armv7), 2 density splits and 16 language splits. ### Manifest facts across all 21 members Read per member with the existing JADX lane (`inspect-android-package` on each extracted APK): 21/21 succeeded, 79 s in total (about 3–8 s per member). | Members | `split` | `android:splitTypes` | `versionCode` | `configForSplit` / `isFeatureSplit` / `isSplitRequired` / `versionCodeMajor` | Play `derived.apk.id` | |---|---|---|---|---|---| | base | none | `""` | 70120 | all absent | 2 | | 16 language | `config.de`, `config.es`, … | `""` | 70120 | all absent | 2 | | 2 ABI | `config.arm64_v8a`, `config.armeabi_v7a` | `base__abi` | 70120 | all absent | 2 | | 2 density | `config.xxhdpi`, `config.xxxhdpi` | `base__density` | 70120 | all absent | 2 | What differs from the prototype's attribute list: - **The base declares the requirement differently from `isSplitRequired`.** It has `android:requiredSplitTypes="base__abi,base__density"` on `<manifest>` (Android 14 split types), and `<application>` has no `isSplitRequired`. Play also adds meta-data: `com.android.vending.splits.required=true`, `com.android.vending.splits` → `@xml/splits0` (a resource listing the expected splits), and `com.android.vending.derived.apk.id=2`. - **Config splits carry `split="config.*"` plus `splitTypes`, but no `configForSplit`.** Their role (ABI, density or language) is declared through `splitTypes`, except language splits, which use `""`, the same as the base. - Config splits declare `<application android:hasCode="false">`. For the proposed set check, `requiredSplitTypes` versus the union of member `splitTypes` could be an observed coverage fact. Here the base requires `base__abi` and `base__density`, and the set provides both, while language coverage isn't expressible through split types. `derived.apk.id` agreement across members may also be a useful consistency signal, though I don't know Play's guarantees for it. ### Input-format observation: third-party bundle containers The set arrived as an APKMirror `.apkm`: a ZIP containing the 21 APKs plus `info.json` (`apkm_version: 5`, `pname`, `versioncode`, `variant`, `languages`, `capabilities`), `icon.png`, `APKM_installer.url`, and a `META-INF/APKMIRRO.SF`/`.RSA` signature over the container, not over the APKs. Current behavior: - `inspect-android-package` on the `.apkm`: a clear refusal, "Target … is zip; provide one standalone APK". - `inspect-artifact` on the `.apkm`: one `root-manifest` observation, with empty `hypotheses`, `unexplored_branches` and `next_probes`, so nothing indicates that it holds a split set. `.apkm`, `.xapk` and `.apks` are how many people obtain split sets without ADB. Even if the set check only accepts caller-selected member APKs (option B), it might help if `inspect_artifact` recognised these containers and pointed to the member APKs as the selection, while recording the container's metadata as unverified provenance rather than as evidence of set membership. On open question 2 (manifest source): the JADX lane already gives every member's decoded manifest text at a moderate cost (79 s for 21 members here, dominated by JVM startup and APK load). A pure reader would avoid that cost, but the per-member provider route works today, if a comparison point is useful.
Author
Owner

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

Thank you for the real-world data point, this is exactly the gap the issue listed as not verified.

A few things I take from it:

  • Roles. A config split that declares split but neither configForSplit nor isFeatureSplit is what the set check already models: it is read as a config split for the base, with the role marked as derived from the platform default rather than observed. Your table fits that case, so the roles should come out as expected for the 21 members.
  • requiredSplitTypes / splitTypes. The manifest reader in #3496 does not read these yet, and I agree they look like observed coverage facts: the base's required types compared with the union of the members' declared types, reported as unknown when a member's attribute is unresolved. I would keep it as a follow-up to #3495/#3496 so those two stay small, and I would not claim anything about language coverage, since splitTypes cannot express it.
  • Store-specific meta-data (derived.apk.id and the listed splits resource) is a vendor convention. I would record it as an observed value at most, not as evidence of set membership, until its guarantees are known.
  • Bundle containers (.apkm, .xapk, .apks). I agree that recognising them in inspect_artifact and pointing at the member APKs would help. I would treat anything in the container's own metadata as unverified provenance, and keep it separate from the set check. That depends on the surface question (question 1), so I will leave it for the maintainers to place.

On question 2: thanks for the timing. The per-member provider route clearly works today; the pure reader trades the JVM and APK-load cost for a small bounded parser, and I will keep both options visible in the discussion rather than assume one.

If you can share the manifest facts for the base and one config split in raw form (attribute names and values only, no identifiers you do not want public), I can turn them into a synthetic fixture for the reader tests.

<!-- gh-comment-id:6188612926 --> @cevieiras commented on GitHub (Oct 15, 2026): Thank you for the real-world data point, this is exactly the gap the issue listed as not verified. A few things I take from it: - **Roles.** A config split that declares `split` but neither `configForSplit` nor `isFeatureSplit` is what the set check already models: it is read as a config split for the base, with the role marked as derived from the platform default rather than observed. Your table fits that case, so the roles should come out as expected for the 21 members. - **`requiredSplitTypes` / `splitTypes`.** The manifest reader in #3496 does not read these yet, and I agree they look like observed coverage facts: the base's required types compared with the union of the members' declared types, reported as `unknown` when a member's attribute is unresolved. I would keep it as a follow-up to #3495/#3496 so those two stay small, and I would not claim anything about language coverage, since `splitTypes` cannot express it. - **Store-specific meta-data** (`derived.apk.id` and the listed splits resource) is a vendor convention. I would record it as an observed value at most, not as evidence of set membership, until its guarantees are known. - **Bundle containers** (`.apkm`, `.xapk`, `.apks`). I agree that recognising them in `inspect_artifact` and pointing at the member APKs would help. I would treat anything in the container's own metadata as unverified provenance, and keep it separate from the set check. That depends on the surface question (question 1), so I will leave it for the maintainers to place. On question 2: thanks for the timing. The per-member provider route clearly works today; the pure reader trades the JVM and APK-load cost for a small bounded parser, and I will keep both options visible in the discussion rather than assume one. If you can share the manifest facts for the `base` and one config split in raw form (attribute names and values only, no identifiers you do not want public), I can turn them into a synthetic fixture for the reader tests.
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#612
No description provided.