[GH-ISSUE #1486] fix(apple): use one case policy for bundle anatomy #501

Closed
opened 2026-10-15 18:25:37 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @cursor[bot] on GitHub (Oct 10, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1486

TL;DR: Apple bundle discovery folds .app and .framework, then requires the exact spellings Contents, MacOS, Info.plist, and _CodeSignature. A bundle whose ZIP stored contents or info.plist is dropped or reported as a shallow iOS app with no plist.

Logical archive identity is case-sensitive, which is what #1470 established. This projection then mixes that rule with a case-folded rule in the same decision.

Area

Evidence, artifacts, or reconstruction

Observed behavior

In applicationRoots (src/domain/apple/appleBundleAnatomy.ts):

  • A directory subject whose name ends in .app matches case-insensitively (/\.app$/iu).
  • An iOS root must be spelled Payload/<name>.app. payload/ does not match. The .app suffix on that regex is case-sensitive.
  • A macOS root matches .app case-insensitively, then requires the next segment to be exactly Contents.

bundleLayout looks up the exact children Contents and Versions. infoPlistPath looks up Info.plist and Resources/Info.plist. Executable candidates look up MacOS. Signing paths look up _CodeSignature/CodeResources, embedded.provisionprofile, and embedded.mobileprovision.

bundleRole lower-cases the leaf name before testing .framework, .appex, .xpc, and the other suffixes. BUNDLE_EXTENSION is case-insensitive. So Foo.FRAMEWORK is a framework role, while Foo.app/contents/Info.plist never becomes a macOS root and never contributes that plist.

ZIP and IPA archives keep the spelling the packer wrote. A case-sensitive archive, or a packer that lower-cased directory names, inventories successfully and then disappears from project-apple-application-graph roots, platforms, signing paths, and CFBundle follow-ups.

Expected behavior

Anatomy lookups should use one stated case policy. If the projection preserves archive spelling, the limitation should name which exact spellings were required and which entries were ignored because of case. If macOS bundle anatomy is matched case-insensitively, that fold belongs only to this convention check, and both spellings should remain distinct in the inventory.

Where

  • src/domain/apple/appleBundleAnatomy.ts — applicationRoots, bundleLayout, bundleRole, infoPlistPath, executableCandidates, signingPaths, BUNDLE_EXTENSION
  • src/domain/apple/appleApplication.ts — classifyComponents (Info.plist, Contents/Library/..., _CodeSignature/CodeResources)
Originally created by @cursor[bot] on GitHub (Oct 10, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1486 **TL;DR:** Apple bundle discovery folds `.app` and `.framework`, then requires the exact spellings `Contents`, `MacOS`, `Info.plist`, and `_CodeSignature`. A bundle whose ZIP stored `contents` or `info.plist` is dropped or reported as a shallow iOS app with no plist. Logical archive identity is case-sensitive, which is what #1470 established. This projection then mixes that rule with a case-folded rule in the same decision. ### Area Evidence, artifacts, or reconstruction ### Observed behavior In `applicationRoots` (`src/domain/apple/appleBundleAnatomy.ts`): - A directory subject whose name ends in `.app` matches case-insensitively (`/\.app$/iu`). - An iOS root must be spelled `Payload/<name>.app`. `payload/` does not match. The `.app` suffix on that regex is case-sensitive. - A macOS root matches `.app` case-insensitively, then requires the next segment to be exactly `Contents`. `bundleLayout` looks up the exact children `Contents` and `Versions`. `infoPlistPath` looks up `Info.plist` and `Resources/Info.plist`. Executable candidates look up `MacOS`. Signing paths look up `_CodeSignature/CodeResources`, `embedded.provisionprofile`, and `embedded.mobileprovision`. `bundleRole` lower-cases the leaf name before testing `.framework`, `.appex`, `.xpc`, and the other suffixes. `BUNDLE_EXTENSION` is case-insensitive. So `Foo.FRAMEWORK` is a framework role, while `Foo.app/contents/Info.plist` never becomes a macOS root and never contributes that plist. ZIP and IPA archives keep the spelling the packer wrote. A case-sensitive archive, or a packer that lower-cased directory names, inventories successfully and then disappears from `project-apple-application-graph` roots, platforms, signing paths, and `CFBundle` follow-ups. ### Expected behavior Anatomy lookups should use one stated case policy. If the projection preserves archive spelling, the limitation should name which exact spellings were required and which entries were ignored because of case. If macOS bundle anatomy is matched case-insensitively, that fold belongs only to this convention check, and both spellings should remain distinct in the inventory. ### Where - `src/domain/apple/appleBundleAnatomy.ts` — `applicationRoots`, `bundleLayout`, `bundleRole`, `infoPlistPath`, `executableCandidates`, `signingPaths`, `BUNDLE_EXTENSION` - `src/domain/apple/appleApplication.ts` — `classifyComponents` (`Info.plist`, `Contents/Library/...`, `_CodeSignature/CodeResources`)
bsakaguchi 2026-10-15 18:25:37 +00:00
Author
Owner

@morluto commented on GitHub (Oct 10, 2026):

Thanks for reporting this. Closing as resolved on main. Apple anatomy now has an explicit en-US convention-name comparison shared across bundle layout and component classification, while returned paths retain inventory spelling.

Merged fix. I checked the current source against this report; no tests or real-provider workflows were run for this closure pass.

<!-- gh-comment-id:6099806505 --> @morluto commented on GitHub (Oct 10, 2026): Thanks for reporting this. Closing as resolved on main. Apple anatomy now has an explicit en-US convention-name comparison shared across bundle layout and component classification, while returned paths retain inventory spelling. [Merged fix](https://github.com/morluto/rea/commit/b4db35f092d7166aebdf4387b48f7652b1d1c3b6). I checked the current source against this report; no tests or real-provider workflows were run for this closure pass.
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#501
No description provided.