fix(artifacts): keep case-distinct archive names in inventory (#1480)

ZIP member names are case-sensitive. Inventory was folding them with a
filesystem case rule, so shrunk APKs never became evidence for the Android
application graph. Logical registration now keeps both spellings and records
an English Unicode case-folding limitation. Extraction fails only when the
destination directory already holds the other spelling.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
morlutoandCursor Agent authored and GitHub committed 2026-10-10 15:21:16 +08:00
1 parent 7296f2b5bf
commit 1f0775684b
11 files changed
+425 -95

No files matched your search

+9 -28
View File
@@ -125,6 +125,8 @@ export const projectAndroidApplication = (
"Manifest, resource, signing, and bytecode semantics require a dedicated Android provider; this projection reports exact inventory paths and hashes only.",
"Runtime families are inferred from inventory formats and paths; filename suffixes do not establish valid DEX or JVM class bytes.",
"Bridge candidates are path-based hypotheses, not decoded JNI declarations or observed runtime calls.",
"A bridge basis is inferred from the native path and is repeated for every managed component.",
"ZIP inventory cannot see the APK Signing Block, so an empty signing array does not mean the APK is unsigned.",
...(bridgeProjection.coverage.status === "partial"
? [
`Bridge candidate pairs exceeded the projection safety budget; ${bridgeProjection.coverage.omitted_candidates} hypotheses are omitted. Component arrays still include every component from the supplied inventory pages.`,
@@ -157,23 +159,12 @@ export const projectAndroidApplication = (
};
const classify = (all: readonly Component[]) => ({
manifests: all.filter(
({ path, format }) =>
format === "android-manifest" ||
/(?:^|\/)AndroidManifest\.xml$/u.test(path),
),
resources: all.filter(
({ path, format }) =>
format === "android-resources" || /(?:^|\/)resources\.arsc$/u.test(path),
),
dex: all.filter(
({ path, format }) =>
format === "dex" || /(?:^|\/)[^/]+\.dex$/iu.test(path),
),
jvm_classes: all.filter(
({ path, format }) =>
format === "jvm-class" || /(?:^|\/)[^/]+\.class$/iu.test(path),
manifests: all.filter(({ path }) =>
/(?:^|\/)AndroidManifest\.xml$/u.test(path),
),
resources: all.filter(({ path }) => /(?:^|\/)resources\.arsc$/u.test(path)),
dex: all.filter(({ path }) => /(?:^|\/)[^/]+\.dex$/iu.test(path)),
jvm_classes: all.filter(({ path }) => /(?:^|\/)[^/]+\.class$/iu.test(path)),
native_libraries: all.filter(
({ path, format }) =>
format === "elf" || /(?:^|\/)lib\/[^/]+\/[^/]+\.so$/iu.test(path),
@@ -189,19 +180,9 @@ const runtimeFamilies = (all: readonly Component[]) => {
const families = new Set<
AndroidApplicationProjectionResult["runtime_families"][number]
>();
if (
all.some(
({ path, format }) =>
format === "dex" || path.toLowerCase().endsWith(".dex"),
)
)
if (all.some(({ path }) => path.toLowerCase().endsWith(".dex")))
families.add("dalvik-art");
if (
all.some(
({ path, format }) =>
format === "jvm-class" || path.toLowerCase().endsWith(".class"),
)
)
if (all.some(({ path }) => path.toLowerCase().endsWith(".class")))
families.add("java-kotlin");
if (all.some(({ format }) => format === "elf")) families.add("native");
if (all.some(({ format }) => format === "javascript-bundle"))