# Concurrency Contract for State Ownership in BitChat: Three-Domain Architecture Explained

> Understand BitChat's three-domain concurrency contract for state ownership. Learn how serial queues and unidirectional synchronization ensure deadlock freedom. Explore the permissionlesstech/bitchat repository.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: architecture
- Published: 2026-08-23

---

**BitChat enforces a strict three-domain concurrency contract that isolates mutable state to specific serial queues—engine-confined, BLE queue-confined, and lock-backed stores—guaranteeing deadlock freedom through a unidirectional synchronization edge order.**

This guide examines the thread-safety architecture in the [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat) repository, a Bluetooth Low Energy (BLE) mesh messaging framework written in Swift. The **concurrency contract for state ownership in BitChat** organizes all mutable state into distinct isolation domains, preventing data races while maintaining high throughput across the mesh network stack.

## The Three Concurrency Domains

BitChat's BLE transport layer divides mutable state into **three distinct concurrency domains**, each governed by specific ownership rules that eliminate contention.

### Engine-Confined State

The **engine-confined** domain restricts mutable access to the serial *engine* queue (`mesh.message`). All cross-thread mutations must use the `onEngine` helper to hop onto this queue. This domain protects core mesh engine state including the codec, fragmentation logic, deduplication tables, relay policies, peer registry, topology management, and Noise protocol orchestration.

### BLE Queue-Confined State

The **bleQueue-confined** domain houses state adjacent to CoreBluetooth objects, including the link store, write buffers, notification buffers, and link-authentication maps. Access is strictly limited to the *BLE queue*, ensuring that peripheral write operations and link-layer authentication data remain consistent with CoreBluetooth threading requirements.

### Lock-Backed Global Stores

The **lock-backed store** domain allows read access from any thread through a **read-write lock**, though writes remain confined to a single domain (either engine or BLE queue). This pattern protects global stores—such as `BLEPeerRegistryStore`, local identity/capabilities, and traffic monitors—that require visibility across multiple domains while guaranteeing readers never observe torn data.

## Synchronization Edge Order and Deadlock Prevention

BitChat enforces a **unidirectional synchronization edge order** that guarantees deadlock freedom. The hierarchy flows as:

```

main / test threads ──sync──▶ engine ──sync──▶ bleQueue
                                   └──sync──▶ noise / identity queues (leaves)

```

Critical enforcement occurs in the `onEngine` helper: **no code may synchronously wait in the reverse direction**. The BLE queue and cryptographic queues may only **async-dispatch** to the engine, and the engine never synchronously dispatches back to the main thread. This construction eliminates circular wait conditions entirely.

## Contract Enforcement in BLEService.swift

The concurrency contract is implemented and debug-checked in [`bitchat/Services/BLE/BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEService.swift). The `onEngine` method (around line 396) contains assertions verifying that only the engine queue may call into the BLE queue and vice-versa. According to the BLE Architecture V3 design document ([`docs/BLE-ARCHITECTURE-V3.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/BLE-ARCHITECTURE-V3.md), lines 54-66), these runtime checks validate the sync-edge order during development, while the test suite in [`bitchatTests/Services/BLEQueueContractTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/Services/BLEQueueContractTests.swift) greps for illegal synchronous dispatches to prevent regressions.

## Practical Implementation Examples

The following patterns demonstrate safe cross-domain state access in BitChat.

Safely mutating engine-confined state:

```swift
// Closure executes exclusively on the serial engine queue
BLEService.shared.onEngine {
    meshEngine.enqueue(event: .incomingMessage(payload))
    // Safe to mutate: codec, fragmentation, deduplication, relay policy
}

```

Reading from lock-backed stores:

```swift
// Read from any thread via read-write lock
let peerCount = BLEPeerRegistryStore.shared.withReadLock { 
    $0.allPeers.count 
}

```

Dispatching to the BLE queue from the engine:

```swift
BLEService.shared.onEngine {
    // Engine-scheduled work requiring BLE layer access
    let pending = BLEPendingWrite(data: encryptedPayload)
    bleQueue.enqueue(pending)  // Safe: maintains queue confinement
}

```

## Summary

- **Three-domain isolation** separates state into engine-confined, BLE queue-confined, and lock-backed stores, each with explicit ownership rules.
- **Unidirectional sync edges** flow from main/test threads to engine to BLE queue (and engine to crypto queues), with strict prohibition on reverse synchronous waits.
- **Runtime enforcement** via `onEngine` assertions in [`BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEService.swift) and automated contract testing prevents deadlock and data races.
- **Lock-backed patterns** enable safe cross-domain visibility for global stores like `BLEPeerRegistryStore` without compromising the serial queue model.

## Frequently Asked Questions

### What happens if code attempts to synchronously dispatch against the grain of the sync-edge order?

The `onEngine` helper contains debug assertions that trap illegal synchronous dispatches. In production builds, violating the unidirectional flow (such as having the BLE queue block-wait for the engine) would create a deadlock risk, which is why the architecture mandates strict async callbacks for reverse-direction communication.

### Why does BitChat use a read-write lock for the peer registry instead of queue confinement?

The peer registry requires visibility from both the engine domain and the BLE domain while supporting high-concurrency reads. The **read-write lock** pattern allows any thread to read consistent state without queue hopping overhead, while write operations remain serialized through either the engine or BLE queue owner, ensuring writers cannot interfere with each other.

### How does the `onEngine` helper prevent accidental thread migration?

In [`BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEService.swift), the `onEngine` implementation checks the current execution context and asserts that callers from the BLE queue or crypto queues do not attempt synchronous dispatches back to the engine. This validation ensures that state access respects the domain boundaries defined in the BLE Architecture V3 specification.

### Where is the concurrency contract documented and tested?

The formal contract resides in [`docs/BLE-ARCHITECTURE-V3.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/BLE-ARCHITECTURE-V3.md) (lines 54-66), while enforcement logic lives in [`bitchat/Services/BLE/BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEService.swift). The test suite [`bitchatTests/Services/BLEQueueContractTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/Services/BLEQueueContractTests.swift) provides automated validation by scanning for prohibited synchronous dispatch patterns across the codebase.