Files
zulip-xmpp/pm/relay-model.org

2.6 KiB

0.1.1 Relay Envelope and Anti-Loop Rules

envelope

from dataclasses import dataclass
from typing import Literal, Optional

Origin = Literal["zulip", "xmpp"]
Direction = Literal["zulip_to_xmpp", "xmpp_to_zulip"]

@dataclass(frozen=True)
class RelayEnvelope:
    envelope_id: str
    origin: Origin
    source_message_id: str
    sender_display_name: str
    target_mapping: str
    timestamp: str
    body_text: str
    sender_platform_id: Optional[str] = None
    raw_direction: Optional[Direction] = None
    receipt_time: Optional[str] = None

Required for v0:

field purpose
origin source platform
source_message_id duplicate detection
sender_display_name relay attribution
target_mapping fixed bridge route
timestamp event ordering / logs

relay output

direction plain-text shape
Zulip -> XMPP [zulip] <sender>: <body>
XMPP -> Zulip [xmpp] <sender>: <body>

Optional machine stamp:

  • bridge_id
  • relayed_from
  • relayed_source_id

loop guards

  1. self-authored

    • Zulip sender == bridge account
    • XMPP sender == bridge nick/jid
  2. stamped bridge message

    • inbound carries this bridge instance stamp
  3. recent-seen duplicate

    • key = (origin, source_message_id)

Order:

  1. scope check
  2. self/stamp check
  3. duplicate check
  4. normalize + relay once
  5. record seen key after success

failure policy

case action
empty body after normalization drop + log
unknown origin drop + log
unmapped target drop + log
no usable id synthesize fallback id, log it
non-chat event drop + log
duplicate upstream event drop, info/debug log

reconnect policy

  • no history backfill
  • only newly delivered events
  • in-memory TTL cache suppresses short replay bursts
  • restart may re-emit old events; acceptable for v0

non-goals

  • edits / deletes / reactions
  • attachment mirroring
  • presence / roster sync
  • multi-room routing
  • Hermes / Retcon integration

exit condition

  • envelope shape is frozen
  • loop guards are explicit
  • duplicate / malformed / reconnect behavior is explicit