0 ? array_values(array_filter($all, fn($m) => (int)($m['epoch'] ?? 0) > $since)) : $all; $window = array_slice($messages, -50); $truncated = count($messages) > count($window); // The cursor is the last message the client is actually being handed. Returning the // thread's real tail after a truncation would skip everything in between for good. $lastSent = $window ? $window[count($window) - 1] : null; $lastAll = $all ? $all[count($all) - 1] : null; json_response([ 'success' => true, 'thread' => $thread, 'messages' => $window, 'truncated' => $truncated, // `awaiting` replaces `unread`: the server keeps no read state, so an unread // counter could never clear. Who spoke last is knowable. 'awaiting' => (bool)($lastAll && ($lastAll['author'] ?? '') !== 'hermes'), 'cursor' => $lastSent ? (int)($lastSent['epoch'] ?? 0) : ($lastAll ? (int)($lastAll['epoch'] ?? 0) : 0), ]);