Postbox -> TelegramEngine wave 15: SelectablePeerNode stateManager collapse

Applies the wave-11/12 AccountStateManager collapse pattern to
SelectablePeerNode. Module is now fully Postbox-free (source + BUILD).

- SelectablePeerNode.setup(... postbox: Postbox, network: Network, ...)
  -> setup(... stateManager: AccountStateManager, ...). Same for
  setupStoryRepost. AvatarNode.setPeer and EmojiStatusComponent are
  forwarded as stateManager.postbox / .network without naming Postbox.
- Three Namespaces.Peer.SecretChat == checks rewritten to use the
  existing PeerId.isSecretChat extension (as in wave 13).
- ShareControllerPeerGridItem.setup / setupStoryRepost and
  HorizontalPeerItem.setup call sites collapse to stateManager:.
  JoinLinkPreviewPeerContentNode uses the convenience
  setup(context: AccountContext) and is unchanged.
- Drop import Postbox in SelectablePeerNode.swift and the
  //submodules/Postbox:Postbox dep in SelectablePeerNode/BUILD.

The stateManager fallback (over the normally-preferred engine:
TelegramEngine) is used because SelectablePeerNode crosses the Share
Extension boundary: ShareControllerAccountContextExtension has no
Account, so TelegramEngine(account:) is physically unreachable there.
This matches the "rare but genuine fallback" clause of
feedback_postbox_refactor_handle.md.

Build verified green (debug_sim_arm64, 193 actions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
isaac 2026-04-20 20:37:41 +02:00
parent b20cd3502b
commit 46566e7155
5 changed files with 38 additions and 17 deletions

View file

@ -358,6 +358,31 @@ Net (wave 14 alone): 98 files changed, 0 insertions / 98 deletions.
Plan / record: (no plan doc this wave — mechanical sweep).
### Wave 15 outcome (2026-04-20)
Applies the wave-11/12 `stateManager: AccountStateManager` collapse pattern to `SelectablePeerNode` — another wave-1-era candidate listed in the post-wave-14 shortlist. Module becomes fully Postbox-free (source + BUILD).
**`SelectablePeerNode` fully Postbox-free.** Two public setup methods migrated:
- `setup(accountPeerId: EnginePeer.Id, postbox: Postbox, network: Network, …)``setup(accountPeerId:, stateManager: AccountStateManager, …)`.
- `setupStoryRepost(accountPeerId: EnginePeer.Id, postbox: Postbox, network: Network, …)``setupStoryRepost(accountPeerId:, stateManager: AccountStateManager, …)`.
Internal forwards rewired: `AvatarNode.setPeer(…, postbox: stateManager.postbox, network: stateManager.network, …)` and `EmojiStatusComponent(postbox: stateManager.postbox, …)`. Neither site names `Postbox` in the consumer — Swift infers through transitive module visibility.
**Namespaces.Peer.SecretChat fixup (×3).** Replaced `peer.peerId.namespace == Namespaces.Peer.SecretChat` checks with `peer.peerId.isSecretChat` at three sites, matching the wave-13 pattern (`PeerId.isSecretChat` at `TelegramCore/Sources/Utils/PeerUtils.swift:611`). The third site (`updateSelection` in the not-selected branch) additionally needed an `?? false` fallback — previous expression was `self.peer?.peerId.namespace == Namespaces.Peer.SecretChat` (optional-equals-non-optional produces `Bool`), new expression is `(self.peer?.peerId.isSecretChat ?? false)`.
**Share-Extension boundary — `stateManager:` over `engine:`.** `SelectablePeerNode` is used by `ShareControllerPeerGridItem`, whose context is `ShareControllerAccountContext`. That protocol exposes `stateManager: AccountStateManager` and `engineData: TelegramEngine.EngineData`, but **no `engine: TelegramEngine`** — and the Share Extension's `ShareControllerAccountContextExtension` concrete impl has no `Account`, so constructing a full `TelegramEngine` (`init(account: Account)`) is physically unreachable there. This is the documented "rare but genuine" fallback to `stateManager:` from the user-preference memory (`feedback_postbox_refactor_handle.md`) — prefer `engine:` except when crossing the Share-Extension boundary.
**Three external call sites migrated:**
- `HorizontalPeerItem/Sources/HorizontalPeerItem.swift:227` (wave 12's `stateManager:` field now forwards directly): `postbox: item.stateManager.postbox, network: item.stateManager.network``stateManager: item.stateManager`.
- `ShareController/Sources/ShareControllerPeerGridItem.swift:237` (setup): `postbox: context.stateManager.postbox, network: context.stateManager.network``stateManager: context.stateManager`.
- `ShareController/Sources/ShareControllerPeerGridItem.swift:273` (setupStoryRepost): same.
**Convenience init unchanged.** `setup(context: AccountContext, …)` now delegates with `stateManager: context.account.stateManager`; signature unchanged — `JoinLinkPreviewPeerContentNode.swift:147` (the one caller using the convenience init) needed no edit.
Net: 4 files changed, +12 / -17 lines. Build verified green (193 actions, 131s — Telegram.ipa target built successfully).
Plan / record: (no plan doc this wave — pattern-application, low-complexity).
### Modules currently free of `import Postbox` (running tally)
Consumer modules that no longer import Postbox, across all waves and standalone commits:
@ -376,6 +401,7 @@ Consumer modules that no longer import Postbox, across all waves and standalone
- `StorageUsageScreen` (waves 810)
- `ActionSheetPeerItem` (wave 11; revisits wave-1 abandonment)
- `HorizontalPeerItem` (wave 12; applies wave-11 pattern)
- `SelectablePeerNode` (wave 15; applies wave-11 pattern; ShareExtension-boundary stateManager fallback)
- `AttachmentTextInputPanelNode` BUILD cleanup (wave 13; source was already clean from wave 6)
- **Wave 14 BUILD-dep sweep: 98 modules' BUILDs cleaned** — same modules as the wave-6 batch; this sweep fixed their leftover `//submodules/Postbox:Postbox` BUILD deps. Candidate list in `/tmp/postbox-dep-candidates.txt` at commit time; derivable by the script in "Wave 14 outcome".