Skip to content

call-baxter integration

This package is meant to live on the call-baxter side of the boundary.

  • call-baxter receives and routes Telegram events.
  • Telegram-specific source plugins emit telegram.* events.
  • call-baxter rules choose when WordPress actions fire.
  • This plugin does not fetch Telegram updates itself.

Mirror a normal Telegram message

id: mirror-telegram-message
enabled: true
match:
  source: telegram
  kind: telegram.message.new
actions:
  - kind: wordpress.mirror_telegram_message
    args:
      update: "{{ event.attrs.raw_update }}"
      required_hashtag: "#blog"

Update a post when Telegram edits the message

id: mirror-telegram-edit
enabled: true
match:
  source: telegram
  kind: telegram.message.edited
actions:
  - kind: wordpress.mirror_telegram_message
    args:
      update: "{{ event.attrs.raw_update }}"
      required_hashtag: "#blog"

Stage media-group fragments with the normal mirror rule

Configure publication staging once on the plugin:

plugins:
  - module: cb_wordpress_plugin.plugin
    config:
      state_db_path: ./state/wp-publications.db
      media_group_wait_seconds: 45
      publication_lease_seconds: 30
      publication_wait_seconds: 2
      orphan_media_cleanup_after_seconds: 86400
      orphan_media_cleanup_limit: 50

The same state database also protects normal one-message publications. Before creating a post, the plugin claims a short lease for the Telegram message or media-group key. Concurrent workers wait for the owner to complete. After a crash, the next worker searches WordPress by the deterministic idempotency slug and repairs the local mapping instead of creating another post.

Successful media uploads are recorded before post creation continues. If a create attempt is interrupted, recovery keeps the media when the deterministic post exists and deletes the tracked upload when no post exists. The age threshold prevents cleanup from racing a slow but still-active operation.

Then keep a single telegram.message.new mirror rule. The action detects media_group_id and stages grouped fragments automatically. Do not add a second broad new-message rule for media groups, because both rules would match the same update and execute the mirror action twice.

Flush due media groups from a call-baxter scheduler

id: flush-telegram-media-groups
enabled: true
match:
  source: system
  kind: system.heartbeat
actions:
  - kind: wordpress.flush_due_media_groups
    args:
      state_db_path: ./state/wp-publications.db

A dry-run flush reports due groups without deleting them. A later non-dry-run flush can still publish the staged bundle.

The flush action also performs a bounded pass over old interrupted create attempts. For an operator-controlled pass, execute wordpress.cleanup_orphan_media with dry_run: true first, then repeat without dry-run after reviewing the candidate count.

Responsibility split

The practical split is:

  • Telegram plugin responsibility
  • webhook / polling transport
  • Telegram-native event detection
  • stable telegram.* events
  • optionally aggregate native transport concepts like media_group_id

  • WordPress plugin responsibility

  • publication policy
  • title / slug / body extraction
  • hashtag routing
  • taxonomy syncing
  • WordPress media / post creation
  • temporary staging when publication needs to wait for a grouped bundle

Where should media-group reassembly live?

Long term, transport-native grouping belongs most cleanly in the Telegram plugin. That keeps the grouping reusable for non-WordPress sinks too.

But in the current architecture, the WordPress plugin still owns a valid publication-side staging layer:

  • Telegram emits one event per update.
  • call-baxter rules route each new-message event through one mirror action.
  • WordPress plugin stages by chat_id + media_group_id when it needs the whole bundle before publication.

That is a sane short-to-medium-term split because the staging is narrowly tied to publication timing rather than Telegram transport itself.

What should not live here?

Arbitrary multi-message editorial reconstruction without a stable key should not be guessed here. If a publication spans several unrelated Telegram messages with no media_group_id, that should be solved upstream:

  • explicit Telegram-side aggregation
  • authoring convention
  • or editorial tooling