From e8d566b3f271e3dc219e48915870b01657628eba Mon Sep 17 00:00:00 2001 From: Paul Hitt Date: Tue, 25 Aug 2026 18:16:09 -0400 Subject: [PATCH] Record what was actually checked for TestFlight MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified against the built product rather than the source tree, which is what caught the one blocker: no PrivacyInfo.xcprivacy. Apple requires it for any app touching a required-reason API and this one uses UserDefaults in five files, so the upload would have come back ITMS-91053 before reaching TestFlight. The first archive silently omitted the file because it was added after the project was generated — hence the note to check the bundle, not the repo. Also green: archive for generic/platform=iOS, 38 unit tests, launch screen, usage strings, 1024 icon, ATS with no leftover dev exception, WebRTC's own manifest, and no tracking SDKs (grepped, not assumed). Two items left for a human: the collected-data declaration is a legal statement that must match the ASC privacy label, and versionCode 1 needs bumping after the first upload. And a warning that cost an archive: plutil -extract writes back in place without -o -, so using it to inspect a plist destroys it. Use plutil -p. Co-Authored-By: Claude Opus 5 --- PARITY.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/PARITY.md b/PARITY.md index 1067190..7cf89c0 100644 --- a/PARITY.md +++ b/PARITY.md @@ -507,3 +507,41 @@ peer q1.json poll; peer q2.json poll peer q1.json send

c; peer q2.json send

d # the exchange that used to die peer q1.json poll; peer q2.json poll ``` + +## iOS TestFlight readiness, checked 2026-08-25 + +Verified against the BUILT PRODUCT, not the source tree — the difference matters, +and caught one thing that would have bounced the upload. + +| | | +|---|---| +| `xcodebuild archive`, `generic/platform=iOS` | ✅ succeeded, arm64, WebRTC embedded | +| Unit tests | ✅ 38 passed, 0 failures | +| `PrivacyInfo.xcprivacy` | ✅ added, **confirmed present in the .app bundle** | +| `UILaunchScreen` | ✅ present (empty dict is the modern form) | +| Bundle / version / min OS | `net.flamenet.messenger`, 0.1.0 (1), iOS 16.0 | +| Usage strings | mic + Face ID; no camera use, so none required | +| App icon | 1024×1024 | +| ATS | fully on — no dev exception left behind | +| Third-party SDK manifest | WebRTC ships its own (no ITMS-91061) | +| Trackers | none — grepped for firebase/analytics/crashlytics/sentry/etc. | + +🔴 **The privacy manifest was a hard blocker.** Apple requires one for any app +touching a "required reason" API, and this app uses `UserDefaults` in five files +— mute and pin flags, the push toggle, the chosen relay. Without it the upload is +rejected **ITMS-91053 before it ever reaches TestFlight**. ⚠️ The first archive +silently omitted it because the file was added after the project was generated: +**check the bundle, not the repo.** + +⚠️ Two things a human must settle before submitting: +- `NSPrivacyCollectedDataTypes` is a legal declaration and must match the privacy + label in App Store Connect. Written from what the code sends; confirm it. +- `CURRENT_PROJECT_VERSION` is `1`. Fine once; every later upload needs a bump. + +⚠️ **`plutil -extract` WRITES BACK IN PLACE** unless given `-o -`. Using it to +"inspect" an archive destroyed that archive's `Info.plist` down to 3 bytes. Use +`plutil -p` to read. + +Still unproven: the feature surface end-to-end on a device — voice notes, calls, +groups, stories. Unit tests and an archive do not cover those, and testers will +be the first to exercise them.