From a9ec8e98bbf0c703a2cd14bcc11f2f760f21f902 Mon Sep 17 00:00:00 2001 From: Paul Hitt Date: Tue, 25 Aug 2026 15:55:19 -0400 Subject: [PATCH] One sign-up helper, because five copies had the same bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seven of 52 UI tests failed in one run with "sign-up did not complete". The app was right and the tests were wrong, and the failure dump said so: signup.password value: • ← one character signup.confirm value: ••••••••••••••••• ← all seventeen signup.submit Disabled iOS puts "Use Strong Password?" over the first `.newPassword` field, and from the first keystroke on it swallows what follows. Every sign-up helper in this target called `dismissPasswordSuggestionIfPresent()` — at the end, after both passwords had been typed, by which point there is nothing left to save. The app then correctly refused a form whose two passwords disagreed, and the report blamed sign-up for it. It is non-deterministic, which is why it reads as flake: a fifth suite running identical keystrokes passed in the same run. It is not flake and it is not machine load. There were five hand-rolled copies of that helper — four here, plus one I wrote for the new two-simulator suite, which reproduced the bug immediately and is what makes the point. Now there is one, `XCUIApplication.completeSignUp`, and it dismisses the panel when the field takes focus, reads both fields back, repairs a short one, and fails naming the cause instead of the app. Two new suites: TwoSimulatorUITests — two simulators, two accounts, one relay. Both sides run the same test with the handles swapped, so neither has to start first; the peer lookup retries, which is the rendezvous. A direct message crosses in both directions and a group created on one device arrives on the other. This is weaker evidence than CrossPlatformUITests and says so in its own header: both halves are the same binary and will agree when both are wrong. What it proves that nothing else does is that a message crosses two devices, two Keychains and two ratchets and lands in the app's own UI. AppSurfaceUITests — the screens nothing was opening. Reactions, unsend, in-chat search, mute, the voice-note recorder, the stories strip, the groups section, the safety number and five of the seven settings screens had no test at all. Deliberately shallow and it says so: this catches a screen that crashes or fails to push, not one that is wrong. Also here, each found while running the above: - DEVELOPMENT_TEAM was "2W7DA3A8W2", the free personal team on the build Mac, while the App Store provisioning profile that already exists for net.flamenet.messenger belongs to M5923Y84P5 — the team that ships hittfitness and shepherdgiving, valid to 2027-06-04. A personal team cannot produce a distribution build, so every archive for TestFlight would have failed naming the certificate rather than the team ID that put it out of reach. - Scripts/generate.sh, because .gitignore excludes the whole .xcodeproj and SwiftPM keeps Package.resolved inside it. Since the WebRTC dependency landed a fresh checkout had no pins at all: resolve against the network and get a different build tomorrow, or disable resolution and fail outright. Both unacceptable for something going to testers. The pins live in Scripts/ now. - rounds.sh ran an iOS *build* and called it a round. The 45 XCUITest cases never ran. It runs them now — and refuses to score a run that executed zero tests as a pass, which xcodebuild will happily report after a runner crashes and relaunches: Test Suite 'TwoSimulatorUITests' passed Executed 0 tests, with 0 failures Co-Authored-By: Claude Opus 5 --- PARITY.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/PARITY.md b/PARITY.md index 6c49ca8..4b2d3a5 100644 --- a/PARITY.md +++ b/PARITY.md @@ -17,7 +17,7 @@ screen renders. | Protocol engine | `Sources/E2E`, 15 files | `engine`, 10 files | | App layer | ~9,700 lines, 45 files | accounts, contacts, chat, photos | | Tests | XCUITest + JS interop | 114 unit + 37 cross-engine + 15 on-device + live round trips | -| Ships to | nobody (no signing team) | a debug APK that installs and runs | +| Ships to | TestFlight, once a distribution cert is minted (see below) | a debug APK that installs and runs; the release keystore is configured | Android's engine is **verified against the web engine in both directions** (`engine/test/interop-kotlin.mjs`), which is a stronger claim than the iOS app @@ -334,3 +334,26 @@ for the app to settle before deciding anything. first takes the message and the other reports zero, which reads as "nothing was sent". Run a single `autoreply` at a time. +## Signing, on both sides (2026-08-25) + +**iOS was pinned to the wrong Apple team, and that — not a missing membership — +is what made TestFlight unreachable.** `project.yml` carried +`DEVELOPMENT_TEAM: "2W7DA3A8W2"`, the free personal team attached to the iCloud +address on the build Mac. Meanwhile an **App Store provisioning profile for +`net.flamenet.messenger` already exists**, issued to team `M5923Y84P5` — the +team that ships hittfitness and shepherdgiving — and valid until 2027-06-04. A +personal team cannot produce a distribution build at all, so every archive would +have failed at signing while naming the certificate rather than the team ID that +put it out of reach. The team is now `M5923Y84P5`. + +⚠️ **Still outstanding: no distribution certificate in the build Mac's +keychain.** `security find-identity -v -p codesigning` returns exactly one +identity, the personal-team *development* one. Signing in to Xcode with the App +Store Connect account mints the distribution certificate and the matching +profile; nothing in this repository can do it, and nothing here should try. + +**Android needs none of that.** The release `signingConfig` reads +`~/.flamenet-android-signing.properties` — present on the build Mac since +2026-08-23 — so `:app:assembleRelease` produces a signed APK that can go +straight to a tester. That asymmetry is why Android reaches testers first, and +it has nothing to do with which app is more finished.