Skip to content

refactor(db): dedupe cross-bundle wrappers into shared mixins (#1135) - #1283

Merged
axisrow merged 1 commit into
mainfrom
ao/tg_content_factory_5863f66be3-63/dedup-bundles
Jul 27, 2026
Merged

refactor(db): dedupe cross-bundle wrappers into shared mixins (#1135)#1283
axisrow merged 1 commit into
mainfrom
ao/tg_content_factory_5863f66be3-63/dedup-bundles

Conversation

@axisrow

@axisrow axisrow commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Part of #1135 (axis 5 of #1130). Stays off the parity surface — only genuine within-repo duplication is touched.

What

src/database/bundles.py duplicated identical repository pass-through methods across bundles:

  • channel read/state ops — ChannelBundle + CollectionBundle
  • task create / task read — both bundles
  • get_setting/set_settingfour bundles (Collection, Notification, Search, Scheduler)
  • account reads (list_accounts, list_account_summaries) — three bundles
  • message search_messages/insert_messages_batch — Collection + Search
  • get_recent_searches — Search + Scheduler

jscpd flagged 5 clone pairs inside the file — the top cluster of #1135.

How

Each duplicated wrapper group moves into a repo-scoped plain-class mixin (_ChannelOps, _CollectionTaskCreateOps, _CollectionTaskReadOps, _SettingsOps, _NotificationQueriesOps, _MessageOps, _AccountReadOps, _SearchLogReadOps). A bundle mixes in only the groups whose repository field it already carries.

Mixins are deliberately NOT dataclasses: their attribute annotations (channels: ChannelsRepository, …) do not become dataclass fields, so every bundle's positional constructor order is unchanged.

Verification

  • Public API byte-identical — verified by an inspect.signature diff of all 10 bundle classes before/after. The only diffs are PipelineBundle.list_accounts/list_account_summaries, which gain the return-type annotations the duplicates already carried.
  • Bundle method count 138 → 111; the test_db_access_conventions ratchet baseline is lowered accordingly (it is a downward-only cap by design).
  • tests/test_bundles.py (42) + bundle consumers (scheduler, search_queries, notifier, photo_loader, pipeline_service, regression-services: 178) green.

jscpd

  • Before (this file): 5 internal clones (~80 dup lines)
  • After: 0 internal clones; the two remaining cross-file hits (bundles.py:19facade.py:18 import block; bundles.py:734photo_loader.py:456 repo pass-through) are import-boilerplate / single thin wrappers, not worth a helper.

Part of #1135 / #1130. Not for merge — review requested.

🤖 Generated with Claude Code

@axisrow
axisrow force-pushed the ao/tg_content_factory_5863f66be3-63/dedup-bundles branch from 004defe to 02decd1 Compare July 27, 2026 14:38
@axisrow

axisrow commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review — cycle 1/3 (clean)

Reviewed locally via built-in /review + Codex companion (sol/xhigh), no GitHub bots pinged. Reviewed head 02decd1f against base 53001148.

This is a MOVE refactor (byte-identical relocation of pass-through wrappers into repo-scoped plain-class mixins). Both reviewers confirmed semantic equivalence:

Reviewer Verdict Findings
Codex (sol/xhigh) approve 0 — "Dataclass constructor signatures unchanged, mixin annotations do not become fields, MROs contain no conflicting wrapper names."
/review (Claude) clean 0 — equivalent MOVE; public API identical (verified by inspect.signature diff of all 10 bundle classes); ratchet baseline 138→111 lowered correctly.

No FIX, no UNVERIFIED, no SKIP — nothing to apply in cleanup. Round bound to 02decd1f; PR snapshot intact (author + head + base unchanged since round start).

Tests: test_bundles.py (42) + 6 consumer files (178) green after rebase. ruff clean.

Totals: 0 FIX, 0 SKIP, 0 UNVERIFIED. Review cycle complete — merge is yours to trigger (local mode does not auto-merge).

bundles.py duplicated identical repository pass-through methods across
bundles (ChannelBundle/CollectionBundle channel+task ops, get_setting/
set_setting in four bundles, account reads in three, message search/batch
insert in two, scheduler task reads). jscpd flagged the top clone cluster
of issue #1135.

Consolidate each duplicated wrapper group into a repo-scoped plain-class
mixin (_ChannelOps, _CollectionTaskCreateOps, _CollectionTaskReadOps,
_SettingsOps, _NotificationQueriesOps, _MessageOps, _AccountReadOps,
_SearchLogReadOps). Mixins are deliberately NOT dataclasses: their
attribute annotations do not become dataclass fields, so every bundle's
positional constructor order is unchanged.

Rebased onto a main where #1287 (vulture #1136) already dropped three
dead bundle methods (list_live_usable_accounts, update_premium,
get_message_stats) — those were unique to their bundles, so the dedup
groups are unaffected; the rebase just no longer carries them. The
set_active name collision is handled by resolution: ChannelBundle/
CollectionBundle get _ChannelOps.set_active(pk), while AccountBundle
(account_id), SearchQueryBundle (sq_id), PipelineBundle (pipeline_id)
keep their own class-body definitions.

Public API verified equivalent by inspect.signature over MRO: identical
method set per bundle, identical fields, set_active resolves to the
correct definition per bundle. Bundle method count 135 -> 108; the
test_db_access_conventions ratchet baseline is lowered accordingly.

Part of #1135 (axis 5 of #1130).

Co-Authored-By: Claude <noreply@anthropic.com>
@axisrow
axisrow force-pushed the ao/tg_content_factory_5863f66be3-63/dedup-bundles branch from 02decd1 to 50ef5b8 Compare July 27, 2026 16:17
@axisrow

axisrow commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review — cycle 1/3 (clean, post-rebase)

Rebased onto a main where #1287 (vulture #1136) already dropped three dead bundle methods, then reviewed locally via built-in /review + Codex companion (sol/medium), no GitHub bots pinged. Reviewed head 50ef5b80.

This is a MOVE refactor (identical pass-through wrappers relocated into 8 repo-scoped plain-class mixins). Both reviewers confirmed semantic equivalence after rebase:

Reviewer Verdict Findings
Codex (sol/medium) approve 0 — "Effective bundle method sets and wrapper behavior match origin/main; dataclass field order is unchanged; set_active resolves to the correct repository for all five bundles; and the three #1287 removals remain absent."
/review (Claude) clean 0 — verified by runtime inspect over MRO: method-set equivalent, dataclass fields unchanged (mixins are NOT dataclasses), set_active resolves correctly per bundle, #1287's 3 dead methods stay absent.

The subtle point both cleared: the set_active name is overloaded — ChannelBundle/CollectionBundle get _ChannelOps.set_active(pk) via the mixin, while AccountBundle(account_id), SearchQueryBundle(sq_id), PipelineBundle(pipeline_id) keep their own class-body definitions (no misresolution). Also: #1287 already removed list_live_usable_accounts/update_premium/get_message_stats, so this rebased PR carries 135→108 bundle methods (not the original 138→111); the ratchet baseline is lowered to 108 with a trace comment.

No FIX, no UNVERIFIED, no SKIP — nothing to apply in cleanup. Round bound to 50ef5b80; PR head + author intact.

Tests: test_bundles.py + ratchet + 6 consumer files (220) green after rebase. ruff clean. (Codex could not run pytest itself — its sandbox has no writable tmp dir — but the suite is covered locally.)

Totals: 0 FIX, 0 SKIP, 0 UNVERIFIED. Review cycle complete — merge is yours to trigger (local mode does not auto-merge).

@axisrow
axisrow merged commit 2c8cc3b into main Jul 27, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant