eleven / ocho Public

Clone
git clone https://amadan.net/eleven/ocho

Plain git — no account needed to clone.

Download

Download this file

1# πŸ€– Reproducing the iOS threading issues (#580)
2
3Working notes for validating the fixes on this branch. The user-visible hang is
4intermittent because it needs a main-thread stall to coincide with a tap β€” so
5instead of chasing the rare hang, reproduce the **mechanism signals** (console
6warnings), which fire far more reliably, and treat "signal gone" as the pass
7condition.
8
9## The signals to watch (device console β€” Xcode debug console or Console.app)
10
11| Signal | What it means |
12|---|---|
13| `onChange(of: CGRect) action tried to update multiple times per frame` | The `globalFrame` layout feedback loop in image/link/YouTube bubbles (`MessageBubble.swift`, `YouTubeCard.swift`, `ChatView.swift`). Main-thread layout churn. |
14| `System gesture gate timed out` | The system back/edge gesture waited on the feed's gesture stack (per-row swipe-to-reply + long-press + iOS-26 content-pop) and gave up. |
15| `Got a keyboard will change frame / will hide notification, but keyboard was not even present` | Spurious keyboard notifications β€” tied to the slow-to-focus symptom. |
16
17Filter Console.app on the app process with text `multiple times per frame` or
18`gesture gate`.
19
20## Setup that maximizes the odds
21
22- A space with **many chats** (warming starts 5 live feed-model sockets).
23- Open a chat that has **images and/or a link-preview or YouTube card** on
24 screen (those bubbles carry the `globalFrame` tracker that fuels the loop).
25- A **second device / the web client** generating churn into the space: flap
26 presence (foreground/background), type, send messages.
27- Use the **slowest device** available β€” main-thread stalls are amplified there.
28
29## Per-symptom recipe
30
311. **Layout loop** β€” open the media chat; raise/dismiss the keyboard and scroll,
32 repeatedly. Expect the `onChange(of: CGRect)` warning to spam (near
33 deterministic).
342. **Back delay** β€” with churn active, open the media chat and immediately tap
35 back; repeat ~20Γ—. Watch for the visible delay + `System gesture gate`.
363. **Phantom second copy** (the clearest one) β€” tap a chat row; if nothing
37 commits, tap it again a few times; when it finally opens, hit back. On the
38 buggy build "back" lands on a duplicate copy of the same chat.
394. **Blank feed** β€” from the list, tap the media chat β†’ immediately back β†’
40 immediately tap it again, ~10Γ— fast. Feed opens empty; a tiny scroll redraws.
415. **Slow focus** β€” open the media chat, immediately tap the composer. Delay
42 before the caret/keyboard; correlate with the CGRect warning.
43
44## Fixes on this branch
45
46- **Phantom second copy (#580, symptom 6):** navigation push is now idempotent β€”
47 `ChatNavGuard.shouldPush` skips a push when that chat is already on top, so
48 queued taps can't stack duplicate `.thread(id)` entries
49 (`ThreadListView.onSelect`). Deterministic regression test:
50 `ChatNavGuardTests`. This makes navigation robust *to* a stall; it does not
51 remove the stall.
52
53- **`onChange(of: CGRect)` layout churn (likely a root-cause contributor):** the
54 image / video / YouTube cards tracked their `.global` frame with a
55 `GeometryReader` + `onChange`. That's a *continuous observation of a value
56 that changes on every layout pass* β€” and a chat open runs several layout
57 passes per displayed frame (scroll-settle pin, avatar spring, composer inset,
58 keyboard), so the frame changes several times per frame and SwiftUI flags
59 `onChange(of: CGRect) action tried to update multiple times per frame`.
60 (Not a self-invalidation loop β€” moving the write off `@State` did NOT silence
61 it, confirmed by breakpoint at `MessageBubble` image bubble: the trigger is
62 observing a high-frequency value at all.) The frame is read **only at tap
63 time** and **only on macOS** (the lightbox zooms out from it; iOS ignores it β€”
64 every `onImageTap` consumer takes `_`), so the tracker is compiled out on iOS
65 via `trackingFrame(into:)` and kept on macOS. **Validate via the console
66 signal** β€” the warning should no longer appear while scrolling / animating the
67 keyboard in a media chat on iOS (runtime behaviour the test suite can't cover).
68
69_Still to land (tracked, not yet on this branch): apply `EdgeOnlyBackGesture`
70to `NativeChatScreen` on iOS 26; coalesce presence frames / skip no-op row
71reconfigures; make the feed reveal robust to a missed opening pin (blank
72feed)._
73