# CRITICAL FIX: Gateway Timing and Listener Start

## The Problem

Messages were being queued but NEVER flushed - the Remote channel was never becoming ready:

```
17:21:23  📦 Remote channel not ready, queued message (1 in queue)
17:21:23  📤 Attempting to flush 1 queued messages
17:21:23  📦 Flushed 0 messages, 1 still queued  ← NEVER SENDS!
```

### Root Cause: Starting Listener Too Early

We were starting `listenForMessages()` in `Connect()`, but Matterbridge's architecture requires:

1. **`Connect()`** - Establish connection, set up client
2. **Router sets up gateway** - Creates the `b.Remote` channel and wires everything together
3. **`JoinChannel()`** - Called by router when gateway is READY
4. **THEN** start receiving messages

By starting the listener in `Connect()`, we were receiving messages BEFORE the gateway was ready, so `b.Remote` wasn't set up yet.

## The Solution

**Delay starting the message listener until `JoinChannel()` is called.**

### Changes Made

1. **In `graphql_ws_client.go`**:
   - Removed `go c.listenForMessages()` from `Connect()`
   - Added new method `StartListening()` that starts the listener
   - Added to `KosmiClient` interface

2. **In `kosmi.go`**:
   - Call `b.client.StartListening()` in `JoinChannel()`
   - This is when the router has finished setting up the gateway

### Code Changes

```go
// graphql_ws_client.go
func (c *GraphQLWSClient) Connect() error {
    // ... connection setup ...
    
    c.log.Info("Native WebSocket client connected (listener will start when gateway is ready)")
    
    // DON'T start listener here!
    return nil
}

func (c *GraphQLWSClient) StartListening() {
    c.log.Info("Starting message listener...")
    go c.listenForMessages()
}

// kosmi.go
func (b *Bkosmi) JoinChannel(channel config.ChannelInfo) error {
    b.Log.Infof("Channel %s is already connected via room URL", channel.Name)
    
    // NOW start listening - the gateway is ready!
    b.Log.Info("Gateway is ready, starting message listener...")
    if b.client != nil {
        b.client.StartListening()
    }
    
    return nil
}
```

## Why This Fixes Everything

### Before (Broken)
```
1. Connect() starts
2. listenForMessages() starts immediately
3. Messages start arriving
4. Try to send to b.Remote → NOT READY YET
5. Queue messages
6. Router finishes setup (b.Remote now ready)
7. Try to flush → but no new messages trigger flush
8. Messages stuck in queue forever
```

### After (Fixed)
```
1. Connect() starts
2. Connection established, but NO listener yet
3. Router finishes setup (b.Remote ready)
4. JoinChannel() called
5. StartListening() called
6. listenForMessages() starts NOW
7. Messages arrive
8. Send to b.Remote → SUCCESS!
9. No queue needed (but available as safety net)
```

## Expected Behavior

### Logs Should Show
```
17:20:43  Starting bridge: kosmi.hyperspaceout
17:20:43  Connecting to Kosmi
17:21:00  Successfully connected to Kosmi
17:21:01  Native WebSocket client connected (listener will start when gateway is ready)
17:21:01  Successfully connected to Kosmi
17:21:01  kosmi.hyperspaceout: joining main
17:21:01  Gateway is ready, starting message listener...
17:21:01  Starting message listener...
17:21:01  🎧 [KOSMI WEBSOCKET] Message listener started
17:21:23  📨 [KOSMI WEBSOCKET] Received: type=next id=subscribe-messages
17:21:23  Received message from Kosmi: [2025-11-01T17:21:23-04:00] cottongin: IKR
17:21:23  ✅ Message forwarded to Matterbridge  ← SUCCESS!
```

## Why This Matters

This is a **fundamental timing issue** in how bridges integrate with Matterbridge's gateway system. The gateway must be fully initialized before messages start flowing, otherwise the routing infrastructure isn't ready.

This pattern should be followed by ALL bridges:
- Connect and authenticate in `Connect()`
- Start receiving messages in `JoinChannel()` (or equivalent)

## Testing

```bash
go build
docker-compose build
docker-compose up -d
docker-compose logs -f matterbridge
```

Send messages immediately after bot connects. They should:
1. NOT be queued
2. Be forwarded directly to IRC/other bridges
3. Appear in all connected channels

No more "Remote channel not ready" messages!

