Migrate RenderedChannelParticipant.peers from [PeerId: Peer] to
[EnginePeer.Id: EnginePeer]. Closes the wave-41 ratchet — the public
struct no longer leaks raw Peer types in any field (presences stays
Postbox-typed; separate migration).
Consumer-surface: -10 bridges. Dropped 6 EnginePeer(peer) read-wraps
at participant.peers[...] extraction sites across
ChannelAdminsController, ChannelMembersSearchContainerNode,
ChannelBlacklistController. Dropped 5 .mapValues({ $0._asPeer() })
constructor-unwrap transforms in ChannelAdminsController,
ChannelMembersSearchContainerNode, ChannelMembersSearchControllerNode.
Added 2 ._asPeer() unwraps in ChatRecentActionsHistoryTransition at
the two iteration sites (line 673 via participant.peers, line 2273
via new.peers in participantSubscriptionExtended) where the iterated
value is inserted into a raw-Peer SimpleDictionary.
TelegramCore producers: 8 files build the local peers dict inside
postbox.transaction and wrap at the insertion point. ChannelMembers,
RequestStartBot, ChannelOwnershipTransfer, JoinChannel, AddPeerMember,
PeerAdmins, ChannelBlacklist, Ranks.
2-iteration build convergence. Iteration-1 surfaced new.peers at
ChatRecentActionsHistoryTransition:2272 that the plan's participant.peers
pre-flight grep missed; wider grep now confirms the two iteration sites
are the complete surface.
No unit tests in this project; full Telegram/Telegram build verified
under configuration=debug_sim_arm64.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Applies the wave-11/12/15 collapse pattern to ItemListAvatarAndNameInfoItem.
ItemContext.other payload changes from (accountPeerId:, postbox: Postbox,
network: Network) to (accountPeerId:, stateManager: AccountStateManager).
Internal AvatarNode.setPeer forward rewires through stateManager.postbox /
.network. Module drops import Postbox (source) and //submodules/Postbox:Postbox
(BUILD). Sole external caller — DeviceContactInfoController.swift:413 at the
Share-Extension boundary — migrated atomically.
Handle choice is stateManager: (not engine:) because the sole caller fires
specifically when the context is not a ShareControllerAppAccountContext;
ShareControllerAccountContext protocol exposes stateManager: AccountStateManager
but not engine: TelegramEngine, and no full TelegramEngine is constructible in
the Share Extension (no Account). Per feedback_postbox_refactor_handle.md and
the wave-15 precedent.
Pre-flight public-Postbox-type inventory grep (per CLAUDE.md's Wave-selection
guidance) returned only Postbox itself — no hidden leaks like wave 16's
EngineMessageHistoryThread / PeerStoryStats surprises.
Module fully Postbox-free after this wave. Running tally updated in CLAUDE.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First build-verified unused-import sweep: speculatively dropped
import Postbox from 782 consumer files (plain ^import Postbox$ lines,
excluding TelegramCore/Postbox/TelegramApi paths), iterated 18 full
project builds with --continueOnError, restored the import on every
file that failed to compile. 183 drops survived; 189 consumer modules
newly Postbox-free.
Bundled: spec + plan + C1 atomic batch drop + C2 CLAUDE.md outcome and
permanent methodology guidance under Wave-selection. The methodology
subsection captures the reusable playbook (--continueOnError is
essential, dependency graphs are deep so expect many iterations,
pattern-based preemptive restores accelerate convergence, and
CLAUDE.md's engine typealias cheat sheet arrows are migration targets
rather than typealiases in TelegramCore).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>