Skip to content

fix(backup): preserve service action metadata in raw_data#191

Merged
GeiserX merged 2 commits into
GeiserX:mainfrom
cdelalama:fix/backup-preserve-service-action-metadata
Jun 10, 2026
Merged

fix(backup): preserve service action metadata in raw_data#191
GeiserX merged 2 commits into
GeiserX:mainfrom
cdelalama:fix/backup-preserve-service-action-metadata

Conversation

@cdelalama

@cdelalama cdelalama commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes [Bug]: Historical backfill drops service-action metadata that the live listener preserves #190: historical backfills (_process_message) now preserve message.action metadata in raw_data, restoring parity with the live listener's convention (service_type / action_type / new_title, in place since v6.0.0).
  • Forum topic history becomes auditable and reconstructible with existing columns: topic_create links via messages.id == forum_topics.id; topic_edit via reply_to_top_id. new_title goes through the existing _text_with_entities_to_string helper.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that causes existing functionality to change)
  • Documentation update
  • Infrastructure/CI change

Database Changes

  • Schema changes (Alembic migration required)
  • Data migration script added in scripts/
  • No database changes

Data Consistency Checklist

  • All chat_id values use marked format (via _get_marked_id()) — no chat_id handling changed
  • All datetime values pass through _strip_tz() before DB operations — no datetime handling changed
  • INSERT and UPDATE operations handle the same fields identically — no DB operations changed

Testing

  • Tests pass locally (python -m pytest tests/ -v) — 1847 passed on Python 3.14
  • Linting passes (ruff check .)
  • Formatting passes (ruff format --check .)
  • Manually tested in development environment — fresh backfill of a synthetic test forum recovered all 4 service actions (2x topic_create, 1x topic_edit, 1x channel_migrate_from) with titles, fully linkable, including a topic rename performed before any backup existed

Security Checklist

  • No secrets or credentials committed
  • User input properly validated/sanitized — values come from Telethon objects, titles through the existing TextWithEntities helper
  • Authentication/authorization properly checked — N/A, no auth paths touched

Deployment Notes

  • No image or config changes needed; existing archives are unaffected. Already-backfilled service rows gain metadata only if their history is re-fetched.
  • Naming is easy to adjust if you prefer different keys (e.g. action_title instead of new_title, or the listener's curated vocabulary for action_type).

Summary by CodeRabbit

  • New Features
    • Backups now capture and preserve service event metadata for forum topic operations (creations and renames), ensuring these events are tracked with full context in historical records.

Historical backfills store service messages but drop message.action,
losing metadata the live listener already preserves since v6.0.0
(raw_data.service_type / action_type / new_title). Capture the action
type (normalized class name) and, when present, the title via the
existing TextWithEntities helper. Forum topic creations and renames
become auditable and linkable: topic_create via messages.id,
topic_edit via reply_to_top_id. No schema change, no new logs.
@cdelalama cdelalama requested a review from GeiserX as a code owner June 10, 2026 14:01
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8f386e00-5125-4721-94b5-1bb07f3f801e

📥 Commits

Reviewing files that changed from the base of the PR and between 2e1289e and af6fb96.

📒 Files selected for processing (1)
  • tests/test_telegram_backup_extended.py
 ____________________________________________________________________________________________________________________________________________
< Organize teams around functionality. Don't separate designers from coders, testers from data modelers. Build teams the way you build code. >
 --------------------------------------------------------------------------------------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
📝 Walkthrough

Walkthrough

The PR extends message processing to capture and store Telethon service-action metadata during historical backfills, ensuring forum topic creates/edits and similar events preserve action payloads (type, title) consistently with the live listener path.

Changes

Service action metadata preservation

Layer / File(s) Summary
Service action type normalization helper
src/telegram_backup.py
Adds re import and new _service_action_type(action) helper that converts MessageAction* class names to snake_case for consistent storage identifiers.
Service action integration into message processing
src/telegram_backup.py
Updates _process_message to detect message.action, normalize the action type, and store service metadata (service_type, action_type, optional new_title) into raw_data.
Test coverage for service action handling
tests/test_telegram_backup.py
Extends imports with Telethon service action types, fixes mock message builders to explicitly set msg.action = None, and adds unit tests validating topic-create/edit service actions and regular message handling.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title directly summarizes the main change: preserving service action metadata in raw_data during backup operations, matching the core objective.
Description check ✅ Passed Description comprehensively covers all template sections with concrete details: issue fix, change type, testing results, security considerations, and deployment notes.
Linked Issues check ✅ Passed Changes fully address issue #190 objectives: service metadata (service_type, action_type, new_title) now preserved in raw_data via _service_action_type helper and _process_message updates, enabling forum topic history reconstruction.
Out of Scope Changes check ✅ Passed All changes are scoped to service action metadata preservation in _process_message and corresponding test coverage; no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 92.31% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use TruffleHog to scan for secrets in your code with verification capabilities.

Add a TruffleHog config file (e.g. trufflehog-config.yml, trufflehog.yml) to your project to customize detectors and scanning behavior. The tool runs only when a config file is present.

@GeiserX

GeiserX commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Thanks for this, @cdelalama — it's a genuinely well-crafted PR. 🙏 You opened a precise issue first, scoped the fix to the actual seam (_process_message), avoided a schema migration, anticipated the MagicMock truthiness pitfall by pinning msg.action = None in the touched factories, added four tests covering create / edit-with-title / edit-without-title / regular-message, and the commit message even pre-states the linkage invariants. CodeRabbit found nothing actionable; neither did we on correctness.

I ran a deep multi-agent review anyway (Telethon-API, logic, tests, architecture, simplicity) and verified the key claims against the installed Telethon 1.43.2 source and an empirical repro rather than from memory. Sharing the findings for transparency — none block merge; the verdict is approve, with a couple of small follow-ups you might consider.

Verified correct ✅

  • The getattr(message, "action", None) is not None guard fires only for service messages. Telethon's own docstring (tl/custom/message.py, identical in 1.41.0 and 1.43.2): "the message action object … for MessageService instances, which will be None for other types." On a regular Message, .action is a real attribute defaulting to None — confirmed by construction, no truthiness trap in production.
  • new_title only-when-.title is not None is correct. MessageActionTopicEdit types title as flags.0?string (optional); a close/hide/icon-only edit has .title is None. Verified against the TL schema (layer 224) and by constructing real objects — your test_topic_edit_without_title_has_no_new_title nails this.
  • Class names are stable across Telethon 1.41–1.43 (no renames/removals), so the name-derived action_type is robust; new action classes only add, never break.
  • Idempotent & self-healing. Backfill funnels through insert_messages_batchon_conflict_do_update(... set_=values) including raw_data, so a re-fetch overwrites old service rows with the new metadata. Your deployment note is accurate (and slightly understated — re-fetched rows are healed, not just new ones).
  • No exception risk, no key collisions. Both helpers are total over real inputs; the three keys are disjoint from the later grouped_id/forward/poll blocks; chat_id/datetime normalization is untouched (you only write into the in-memory raw_data). Full suite 1847 passed, ruff clean.

Worth a look (non-blocking)

1. (nit, test hygiene) One mock factory still omits msg.action. You correctly pinned msg.action = None in both _make_message factories in tests/test_telegram_backup.py, but tests/test_telegram_backup_extended.py:47 was missed. Six tests there call the real _process_message (lines 1631, 1651, 1661, 1688, 2219, 2241), so their bare MagicMock now silently injects junk into raw_data. Reproduced:

service_type = 'service'
action_type  = 'magic_mock'
new_title    = "<MagicMock name='mock.action.title' id=...>"

They still pass (their assertions only check reactions/poll, never these keys), and production is unaffected (a real .action is None). It's purely a test-fixture smell. One-line fix: add msg.action = None near msg.post_author = None at test_telegram_backup_extended.py:64. A direct unit test for _service_action_type would also be nice — it's currently only exercised transitively.

2. (minor) "Parity with the listener" is structural, not value-level. The raw_data keys now match the listener — but the values are a different vocabulary. The listener derives action_type from events.ChatAction (title_changed, user_added, …); your backfill derives it from the MessageAction class name (chat_edit_title, chat_add_user, …). So the same group-title change is title_changed live vs chat_edit_title on backfill. Inert today — exhaustive grep confirms nothing in the repo reads action_type/new_title (the viewer gates only on service_type === 'service' and renders {{ msg.text }}). It's a latent trap for a future consumer (e.g. the external MCP server, or a query like "all title changes"). Suggestion: just reword the comment to "structural parity (keys)" and/or add a note flagging the two vocabularies. No code change needed.

3. (minor, cosmetic) Acronym class names snake-case oddly. re.sub(r"(?<!^)(?=[A-Z])", "_", name) splits consecutive capitals letter-by-letter: MessageActionSetMessagesTTLset_messages_t_t_l. None of the topic/title actions you target are affected (those are all clean), and nothing reads the value, so it's deterministic-but-ugly only. Worth a one-line docstring note so it doesn't surprise a future reuse.

4. (FYI, out of scope) Backfilled service messages render as empty bubbles. _process_message sets text = message.text or "", and a MessageService carries its payload in .action, not .message — so the viewer's {{ msg.text }} shows an empty pill. This is pre-existing (not introduced by this PR — you only add raw_data) and explicitly outside #190's "auditability via raw_data" scope, but since this PR now tags those rows service_type='service', it's the natural next step: a follow-up could synthesize display text (mirroring the listener's service_text) or have the viewer fall back to action_type/new_title when text is empty.

One small thing you could fold in now

_service_action_type is a pure function and a natural fit for src/message_utils.py, right next to extract_topic_id (the existing shared helper both the listener and backfill already import). Keeping new_title extraction in telegram_backup.py is fine since it needs the instance method. Totally optional.

Net: clean, correct, safe to merge as-is — the only thing I'd genuinely suggest before merge is the one-line test-fixture pin (#1). Everything else is polish or a follow-up. Really nice work, and thanks again for contributing this. 🙌

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.25%. Comparing base (25bd9a3) to head (2e1289e).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #191      +/-   ##
==========================================
+ Coverage   92.24%   92.25%   +0.01%     
==========================================
  Files          25       25              
  Lines        7130     7141      +11     
==========================================
+ Hits         6577     6588      +11     
  Misses        553      553              
Files with missing lines Coverage Δ
src/telegram_backup.py 90.96% <100.00%> (+0.08%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Same MagicMock-truthiness guard the other fixtures use: without it the
extended tests flow a truthy mock action through the new service-action
capture and store phantom metadata in raw_data.
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":401,"request":{"method":"PATCH","url":"https://api.github.com/repos/GeiserX/Telegram-Archive/issues/comments/4671056116","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/GeiserX/Telegram-Archive/pull/191?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>ℹ️ Recent review info</summary>\n\n<details>\n<summary>⚙️ Run configuration</summary>\n\n**Configuration used**: Path: .coderabbit.yaml\n\n**Review profile**: CHILL\n\n**Plan**: Pro\n\n**Run ID**: `8f386e00-5125-4721-94b5-1bb07f3f801e`\n\n</details>\n\n<details>\n<summary>📥 Commits</summary>\n\nReviewing files that changed from the base of the PR and between 2e1289edd26bccee805a42b3a90f2a0aad4c341a and af6fb96f182ba1ac42c29e2c3f3a438c4086ca40.\n\n</details>\n\n<details>\n<summary>📒 Files selected for processing (1)</summary>\n\n* `tests/test_telegram_backup_extended.py`\n\n</details>\n\n</details>\n\n---\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThe PR normalizes Telethon MessageAction class names to snake_case and stores service-action metadata (service_type, action_type, optional new_title) into message raw_data during historical backfills; tests and mock helpers were updated accordingly.\n\n## Changes\n\n**Service action metadata preservation**\n\n|Layer / File(s)|Summary|\n|---|---|\n|**Service action type normalization helper** <br> `src/telegram_backup.py`|Adds `re` import and `_service_action_type(action)` that converts `MessageAction*` class names to snake_case for storage.|\n|**Service action integration into message processing** <br> `src/telegram_backup.py`|Updates `_process_message` to detect `message.action`, normalize the action type, and store `service_type`, `action_type`, and optional `new_title` into `raw_data`.|\n|**Test updates and mock fixes** <br> `tests/test_telegram_backup.py`, `tests/test_telegram_backup_extended.py`|Imports Telethon topic action types, sets `msg.action = None` in test helpers to avoid MagicMock truthiness, and adds tests covering topic-create/edit service actions and regular-message behavior.|\n\n---\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n</details>\n\n<!-- walkthrough_end -->\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 5</summary>\n\n<details>\n<summary>✅ Passed checks (5 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                                                                                                                |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|         Title check        | ✅ Passed | The title directly describes the main change: preserving service action metadata in raw_data during backup operations, which is the core objective of the PR.                                                                                                              |\n|      Description check     | ✅ Passed | The description is comprehensive, covering all template sections: summary with issue reference, type of change, database considerations, data consistency, testing results, security checklist, and deployment notes.                                                      |\n|     Linked Issues check    | ✅ Passed | The PR fully implements the requirements from issue `#190`: adds service_type, action_type, and new_title to raw_data; enables topic history reconstruction via messages.id and reply_to_top_id; preserves the listener convention; passes 1847 tests and manual validation. |\n| Out of Scope Changes check | ✅ Passed | All changes are directly scoped to issue `#190`: the code changes in src/telegram_backup.py implement service-action metadata preservation, and test changes validate this behavior without introducing unrelated modifications.                                             |\n|     Docstring Coverage     | ✅ Passed | Docstring coverage is 92.86% which is sufficient. The required threshold is 80.00%.                                                                                                                                                                                        |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=GeiserX/Telegram-Archive&utm_content=191)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":1,"signal":{}}},"response":{"url":"https://api.github.com/repos/GeiserX/Telegram-Archive/issues/comments/4671056116","status":401,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","connection":"close","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Wed, 10 Jun 2026 15:53:48 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-media-type":"github.v3; format=json","x-github-request-id":"913C:19A388:5240302:13636E39:6A29888B","x-xss-protection":"0"},"data":{"message":"Requires authentication","documentation_url":"https://docs.github.com/rest","status":"401"}}}

@GeiserX GeiserX merged commit a5bb6e4 into GeiserX:main Jun 10, 2026
6 of 7 checks passed
GeiserX added a commit that referenced this pull request Jun 10, 2026
…rgence (#192)

Follow-up to #191 review:
- Move service_action_type to message_utils.py beside extract_topic_id
  (both paths' shared home); drop the now-unused re import in
  telegram_backup.py.
- Docstring notes the acronym snake-case edge (SetMessagesTTL ->
  set_messages_t_t_l) and that the backfill action_type vocabulary is
  intentionally distinct from the listener's curated event names —
  only the raw_data shape is shared, not the values.
- Reword the _process_message comment to say structural parity (keys),
  not value parity.
- Add direct unit tests for service_action_type (topic, multi-word,
  no-arg, acronym edge) and a non-topic MessageActionChatEditTitle /
  MessageActionPinMessage backfill test.
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.

[Bug]: Historical backfill drops service-action metadata that the live listener preserves

2 participants