# How BitChat Sync Schedule Prioritizes Different Message Types: Priority Levels Explained

> Understand BitChat sync schedule priorities. Learn how BitChat prioritizes message types from public chats to file transfers using a six-level system.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: deep-dive
- Published: 2026-07-27

---

**BitChat uses a six-level priority system encoded in a `SyncTypeFlags` bit-field to determine which message types are included in each `REQUEST_SYNC` packet, ensuring public chat content syncs first while deferring large file transfers and excluding ephemeral traffic.**

The mesh messaging protocol in `permissionlesstech/bitchat` orchestrates peer-to-peer synchronization through a carefully weighted schedule that ranks message importance by bandwidth impact and user necessity. Understanding how the BitChat sync schedule prioritizes different message types reveals why core chat packets propagate immediately while file transfers wait for dedicated rounds. This system centers on the `SyncTypeFlags` option set defined in [`SyncTypeFlags.swift`](https://github.com/permissionlesstech/bitchat/blob/main/SyncTypeFlags.swift), which maps message categories to specific bit positions within every sync request TLV.

## The Six-Level Message Priority Hierarchy

When the `GossipSyncManager` builds a `REQUEST_SYNC` packet, it constructs a compact bit-field that tells peers exactly which message categories to re-deliver. The scheduler adds flags in strict priority order until it hits the per-tick bandwidth cap.

### 1. Public Traffic (Highest Priority)

**`announce` (bit 0)** and **`message` (bit 1)** form the `SyncTypeFlags.publicMessages` baseline. These flags are always set in every sync round because they carry core chat content that every user expects to receive. The scheduler never omits these types, ensuring mesh-wide consistency for public conversations.

### 2. Fragment Re-assembly

**`fragment` (bit 5)** is appended when the local fragment buffer detects stalled broadcast reassembly. By elevating fragments to priority 2, the schedule allows peers to fetch missing pieces of large payloads before attempting to sync lower-priority data.

### 3. Board and Pre-Key Data

**`boardPost` (bit 8)** and **`prekeyBundle` (bit 9)** are added only if bandwidth permits. Board posts and X3DH pre-key bundles support onboarding and community features, but they are less time-critical than live chat. The `GossipSyncManager` probes remaining capacity after handling public traffic and fragments before setting these bits.

### 4. Group Messages

**`groupMessage` (bit 10)** follows board and pre-key traffic. Group chat payloads are synchronized after public and fragment data, respecting the same bandwidth caps that constrain priority 3 items.

### 5. File Transfers

**`fileTransfer` (bit 7)** is deliberately deferred to later sync rounds. Large payloads are excluded from early rounds to prevent saturating the mesh with heavy traffic while critical control messages are still pending.

### 6. Low-Priority and Ephemeral Types

**`courierEnvelope`**, **`ping`**, **`pong`**, **`nostrCarrier`**, and **`voiceFrame`** return `nil` when queried for their sync flag. These directed, ephemeral, or real-time media messages are **never** included in gossip syncs because replaying them later wastes airtime and offers no value to the receiving peer.

## How GossipSyncManager Orchestrates Sync Rounds

The sync workflow in [`GossipSyncManager.swift`](https://github.com/permissionlesstech/bitchat/blob/main/GossipSyncManager.swift) executes four discrete steps each time the periodic sync task fires:

1. **Collect candidates** – The manager examines pending outbound queues, fragment-assembly buffers, and forced resync requests to determine which types have outstanding data.
2. **Create `SyncTypeFlags`** – It initializes the flag set with `.publicMessages`, then iterates through priorities 2–5, adding bits until the bandwidth limit is reached.
3. **Rate-limit responses** – [`SyncResponseRateLimiter.swift`](https://github.com/permissionlesstech/bitchat/blob/main/SyncResponseRateLimiter.swift) enforces a hard cap: a peer cannot answer the same request type more than **8 times in 30 seconds**, preventing adversaries from flooding specific high-priority channels.
4. **Encode for transmission** – The `SyncTypeFlags.toData()` method serializes the bit-field (1–8 bytes, little-endian) and wraps it in a `RequestSyncPacket` (TLV type `0x04`).

Because the bit-to-type mapping lives in [`SyncTypeFlags.swift`](https://github.com/permissionlesstech/bitchat/blob/main/SyncTypeFlags.swift), the protocol maintains forward compatibility: unknown high bits are ignored by older clients, allowing the network to sync understood types without version negotiation failures.

## Implementing SyncTypeFlags in Swift

The following patterns from [`SyncTypeFlags.swift`](https://github.com/permissionlesstech/bitchat/blob/main/SyncTypeFlags.swift) and [`RequestSyncPacket.swift`](https://github.com/permissionlesstech/bitchat/blob/main/RequestSyncPacket.swift) demonstrate how to build, check, and serialize priority flags:

```swift
// Build a flag set for a normal sync round
let flags = SyncTypeFlags.publicMessages
            .union(.fragment)          // include missing fragments
            .union(.board)             // add board posts if bandwidth allows

```

```swift
// Check whether a received REQUEST_SYNC wants a given type
if receivedFlags.contains(.message) {
    // enqueue messages for retransmission
}

```

```swift
// Serialize the flag set for the TLV payload
if let payload = flags.toData() {
    let requestSync = RequestSyncPacket(payload: payload)
    // send via BLE or GCS
}

```

```swift
// Decode an incoming payload back to a flag set
if let incoming = SyncTypeFlags.decode(incomingData) {
    // use `incoming.contains(.fragment)` etc.
}

```

## Summary

- **Public traffic** (`announce`, `message`) always syncs first via `SyncTypeFlags.publicMessages`.
- **Fragments** receive priority treatment to unblock stalled reassembly, followed by **board posts**, **pre-key bundles**, and **group messages** as bandwidth allows.
- **File transfers** are explicitly deprioritized to avoid mesh saturation.
- **Ephemeral types** (`ping`, `pong`, `voiceFrame`, etc.) are excluded entirely from the gossip sync schedule.
- [`GossipSyncManager.swift`](https://github.com/permissionlesstech/bitchat/blob/main/GossipSyncManager.swift) enforces these rules while [`SyncResponseRateLimiter.swift`](https://github.com/permissionlesstech/bitchat/blob/main/SyncResponseRateLimiter.swift) caps responses at 8 per 30 seconds to prevent abuse.

## Frequently Asked Questions

### What message types does BitChat sync first?

BitChat always synchronizes `announce` and `message` types first, encoded as `SyncTypeFlags.publicMessages`. These bits are set in every `REQUEST_SYNC` packet regardless of bandwidth constraints because they carry essential public chat content.

### How does BitChat prevent sync flooding attacks?

The `SyncResponseRateLimiter` class restricts each peer to answering the same sync request type no more than **8 times within any 30-second window**. This rate limit applies per message type, preventing adversaries from exploiting high-priority flags to overwhelm the mesh.

### Can older BitChat clients handle new message types in sync requests?

Yes. The `SyncTypeFlags.decode()` method in [`SyncTypeFlags.swift`](https://github.com/permissionlesstech/bitchat/blob/main/SyncTypeFlags.swift) ignores unknown high bits, so legacy clients continue to sync the message types they recognize without failing when newer flags are present. This bit-mask approach preserves interoperability as the protocol evolves.

### Why are file transfers deprioritized in the sync schedule?

`fileTransfer` (bit 7) is assigned priority level 5 because file payloads are large and would congest the mesh if synchronized alongside critical control traffic. The `GossipSyncManager` defers these transfers until higher-priority queues are cleared, ensuring real-time chat remains responsive.