Skip to content

refactor(telegram): full adapter.py god-file decomposition, 10 mixins, 10,147 to 1,390 lines - #79010

Open
andrexibiza wants to merge 19 commits into
NousResearch:mainfrom
andrexibiza:fix/tg-adapter-shard-wave2
Open

refactor(telegram): full adapter.py god-file decomposition, 10 mixins, 10,147 to 1,390 lines#79010
andrexibiza wants to merge 19 commits into
NousResearch:mainfrom
andrexibiza:fix/tg-adapter-shard-wave2

Conversation

@andrexibiza

@andrexibiza andrexibiza commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Related #54962 #75742 #78791 #78792 #78866 #78949

What

This PR is the COMPLETE adapter.py large-file decomposition (waves 1+2 consolidated):

Wave-2 of the Telegram adapter god-file conquest (tracker #78791, decomp #78792): plugins/platforms/telegram/adapter.py — originally 10,147 lines — is being sequentially sharded into cohesive mixins. Wave-1 (PR #78866) extracted 4 mixins (inbound, text-delivery, rich, polling; −6,014 lines). This PR extracts the remaining 6 clusters into mixins, following the identical proven pattern: extract → re-export into the adapter namespace → seam-identity a is b regression → aggressive failure-mode tests.

Shard Mixin Lines Cluster Methods
A1 TelegramDmTopicMixin 722 DM-topic machinery (metadata/thread helpers, create/ensure/rename topics, prune-stale-binding, retry-without-anchor, reload/get/cache trio) 23
A2 TelegramLifecycleMixin 880 connect/disconnect, post-connect housekeeping, bot-identity refresh loop, status indicator, error classifiers 10
A3 TelegramInteractiveMixin 1,467 interactive sends (update-prompt, exec-approval, slash-confirm, clarify, model/choice pickers) + inline-callback dispatch 14 + 8 attrs
A4 TelegramMediaMixin 909 media sends (voice, images, document, video, animation) + typing cooldown + size guards 15
A5 TelegramConfigMentionMixin 869 config getters, mention/identity machinery, group-observe attribution 35
A6 TelegramReactionsMixin 142 forum-command lazy registration, reactions on/off, processing hooks 6

Each mixin: methods MOVED (byte-identical bodies, AST-verified by blind review), adapter inherits it, module helpers re-exported, and the seam identity holds — getattr(TelegramAdapter, n) is getattr(<Mixin>, n) for every moved method (classmethods via __func__ unwrap). The adapter's public API is unchanged; this is pure decomposition with zero behavior drift.

Testing (aggressive + regression, per CCC doctrine)

Every shard shipped BOTH:

  • Seam-identity regression (RED-on-base proof: the test asserts a is b through the adapter, __func__-unwrapped for classmethods)
  • Aggressive failure-mode tests: edge inputs, error paths (timeouts, 4xx/5xx, network, conflict/pool exhaustion), state transitions (reconnect, cooldown, batch boundaries, media-size limits BEFORE send, reactions disabled path), message-type variants, DM-topic/forum/group thread semantics

Per-shard verification (all verified by 2 independent blind reviewers each — pass A spec/dedup/composition, pass B adversarial):

  • Base tree (un-extracted): 509 passed / 0 failed (telegram suite)
  • Head tree per shard: A1 15 passed; A2 521 passed; A3 513 passed; A4 511 passed; A5 668 passed (full-tree); A6 549 passed — 0 new failures on any shard
  • The 6 test_telegram_polling_progress_ptb.py failures are the proven pre-existing environment baseline (PTB MagicMock await) — identical on base and head, isolated to that file, verified by stash-test and base-tree reproduction; they are excluded from the pass counts above.

Reproduction (current vs expected)

Current (pre-fix): adapter.py is a 10,147-line god file — 6,075 lines after wave-1. Every Telegram fix or feature lands in a monolith where a change to one cluster risks silent breakage in another, and the file is too large for effective review.

Expected (post-fix): adapter.py drops to ~1,500 lines; each cluster is an independently-testable mixin with its own seam regression + aggressive suite; future Telegram work (the 69 campaign issues, new features like payments/gifts/games/Passport) targets a focused module instead of the monolith.

How to test

cd <checkout> && <venv-python> -m pytest tests/gateway/test_telegram*.py tests/gateway/test_dm_topics.py tests/gateway/test_telegram_lifecycle_seam.py tests/gateway/test_telegram_media_mixin_seam.py tests/gateway/test_telegram_config_mention_seam.py -q --no-header -p no:cacheprovider --basetemp=C:/tmp/pytest-tg-w2
# Per-shard battery: A1 15, A2 521, A3 513, A4 511, A5 668 (full-tree), A6 549 — 0 new failures
# (6 pre-existing PTB baseline failures only when the polling file is included)
# Seam checks per mixin: getattr(TelegramAdapter, n) is getattr(Mixin, n) — all True

Platforms tested

Windows 11, Python 3.12 — per-shard: base 509/0 → head A1 15, A2 521, A3 513, A4 511, A5 668 (full-tree), A6 549 (0 new failures each; 6 pre-existing PTB baseline excluded), seam identity 100%, compileall clean, git diff --check clean, check-windows-footguns.py clean, UTF-8 gate HEALTHY.

Why this matters to users

Before: the Telegram adapter was a single 10,147-line file where the polling, delivery, media, and auth logic all fought for space — fixes were risky, reviews were shallow, and regressions hid in plain sight. After wave-1 + this PR: the adapter is a composable set of focused mixins, each with its own regression and failure-mode tests, and the path is open for the 69 campaign features to land safely. Telegram — the final boss — is being defeated cluster by cluster, and the regression net ensures every future feature (especially new ones) ships tested.

Dedup/coordination

Fixes #78791 (epic) · #78792 (decomp)
Part of #78633
Part of #78647

Part of #54962

Part of #78689
Part of #78690
Part of #78691
Part of #78692
Part of #78693
Part of #78694
Part of #78695
Part of #78696
Part of #78697
Part of #78698
Part of #78699
Part of #78700
Part of #78701
Part of #78702
Part of #78703
Part of #78704
Part of #78705
Part of #78707
Part of #78708
Part of #78709
Part of #78710
Part of #78711
Part of #78713
Part of #78714
Part of #78715
Part of #78716
Part of #78717
Part of #78718
Part of #78719
Part of #78720
Part of #78721
Part of #78722
Part of #78723
Part of #78724
Part of #78725
Part of #78726
Part of #78727
Part of #78728
Part of #78729
Part of #78731
Part of #78732
Part of #78733
Part of #78734
Part of #78735
Part of #78736
Part of #78737
Part of #78738
Part of #78739
Part of #78740
Part of #78741
Part of #78742
Part of #78743
Part of #78744
Part of #78745
Part of #78746
Part of #78747
Part of #78748
Part of #78749
Part of #78750
Part of #78751
Part of #78752
Part of #78753
Part of #78754
Part of #78755
Part of #79564
Part of #79772

…amIngestMixin (adapter god-file slice)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
…eliveryMixin (adapter god-file slice)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>

# Conflicts:
#	plugins/platforms/telegram/adapter.py
…xin (adapter god-file slice)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>

# Conflicts:
#	plugins/platforms/telegram/adapter.py
…llingMixin (adapter god-file slice)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>

# Conflicts:
#	plugins/platforms/telegram/adapter.py
… mixin

The webhook-start block (and its GHSA-3vpc-7q5r-276h secret guard) moved
from TelegramAdapter.connect() into TelegramPollingMixin._start_webhook
during the adapter god-file slice. The source-level pin now scans both
adapter.py and telegram_polling.py so the invariant survives either
layout, and the polling-branch check anchors on the new
``if not webhook_started:`` dispatch instead of the old else-branch.

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
The inbound mixin called the media cache via its own module global; the
gateway test suite monkeypatches plugins.platforms.telegram.adapter.
cache_image_from_bytes (media-group batching), so the patch missed and the
real guard rejected the fake payloads, breaking photo-burst buffering.
Function-local lazy imports route resolution through the adapter module,
matching the landed slices' shim pattern.

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
…eactionsMixin (adapter god-file slice A6)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit 34b8bb786b6cc199d03afd0f409540b885571b38)
…ons happy path

Post-review cleanup (adapter shard A6): blind-review pass B flagged the
ProcessingOutcome import at adapter.py:272 as dangling — it was only used by
the moved on_processing_complete (0 uses remaining in adapter). Removed.
Also added the reviewer's recommended happy-path test for _clear_reactions
(set_message_reaction(None) invoked with converted ints); CANCELLED-outcome
clear and the without-bot/malformed-id failure modes were already covered.

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit 54c98816ee508c806a422420c9ad47c196527aee)
…apter god-file slice A2)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit 634b7dc31ad0f2fbbbbf750b8745611db713265a)
Blind-review pass B (adapter shard A2) found _run_post_connect_housekeeping
calls _redact_telegram_error_text(e) with no lazy import — the NameError was
swallowed by the except-Exception wrapper, silently breaking command-menu
registration error logging (the 'swallowed error plays truncated output as
complete' class). Add the lazy import (same circular-import adaptation every
other lifecycle method uses) + a behavioral regression test that drives the
raising command-menu path: RED pre-fix (NameError propagates), GREEN post-fix.

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit b4859ec80bd9b4705b4f49d1cbe3492ea4b69d7c)
…ter god-file slice A4)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit d9e87873ec0e19e3379a28e414d68eedf91cfbbe)
…xin (adapter god-file slice A1)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit a8890d9)
Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>

# Conflicts:
#	plugins/platforms/telegram/adapter.py
…InteractiveMixin (adapter god-file slice A3)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit bfc1ee6db747e8a48cfcd58141ebaee7d49e4fbd)
Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>

# Conflicts:
#	plugins/platforms/telegram/adapter.py
…igMentionMixin (adapter god-file slice A5)

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit b3b81201b4007fef0cc9d41ded39574ef50a4b08)
Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>

# Conflicts:
#	plugins/platforms/telegram/adapter.py
The A3 conflict resolution (checkout --theirs) dropped the Media/Lifecycle/
Reactions/DmTopic mixin imports accumulated by earlier cherry-picks. Restore
them so the composed TelegramAdapter MRO carries all 10 mixins (6 wave-2 +
4 wave-1).

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
…ition

The A3 conflict resolution restored pre-extraction module-level helper copies
on the adapter; the media seam requires the adapter namespace to resolve
_coerce_duration_seconds/_probe_voice_duration_seconds/_MEDIA_SEND_READ_TIMEOUT
to the mixin's objects. Replace own copies with the mixin import (the approved
A4 branch's pattern).

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
@alt-glitch alt-glitch added type/refactor Code restructuring, no behavior change comp/plugins Plugin system and bundled plugins platform/telegram Telegram bot adapter P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Aug 5, 2026
@andrexibiza andrexibiza changed the title refactor(telegram): shard adapter.py wave 2 — dm-topics, lifecycle, interactive, media, config/mention, reactions mixins (−4,724 lines) refactor(telegram): full adapter.py god-file decomposition, 10 mixins, 10,147 to 1,390 lines Aug 5, 2026
…tures

Three bare open() calls in test_dm_topics.py violate the blocking
windows-footguns gate (platform-default encoding on Windows is cp1252).
Explicit encoding="utf-8" on both write and read sides of the same
round-trip — zero behavior change for the fixtures, closes the live
gate violations in a file this PR already touches.

Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit 472523e)
Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit 7279039)
Signed-off-by: andrexibiza <84248988+andrexibiza@users.noreply.github.com>
(cherry picked from commit 8207af5)
@andrexibiza

Copy link
Copy Markdown
Contributor Author

🔒 This shard is part of the telegram/adapter.py KILL LOCK — the permanent record of the 10,147-line whole, the mess it caused (#78791 feature-parity meta, #78792 decomp plan, #75741 buried auth, reply-anchor drift, media timeouts, caption escaping, retry-after loss, unacknowledged callbacks), every mixin in the kill (10 mixins, −8,757 lines), and every open fixer PR still fighting the surface (#67306 #78093 #63635 #69153 #74107 #78874 #74769 #77403 #75742 #65526 #72957 #69984 #77827 #64473 #51397 #68909 #50562 #76454 #61169 #68823 #61022 #73416 #57090 #72937 #54274 #68757 #73701 #54262).

Lock: posted on #78633 · Indexed by the Kill All Gods meta-issue #78647.

This was referenced Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/telegram Telegram bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/refactor Code restructuring, no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Telegram Feature Parity & Alignment Campaign (Bot API 10.2) — meta-issue

2 participants