From 313f13955ad9c72895b0914ac828c61b3e469715 Mon Sep 17 00:00:00 2001 From: Agando Date: Fri, 23 Oct 2026 19:29:31 +0200 Subject: feat(chat): token-scoped chat endpoints, contract, host CLI, old POST retired (v4.6.71 phase B) - api/chat/{lib,post,poll}.php: thread = sha256(token)[0:16]; flock read-modify-write; tmp+rename; ms epoch cursor; per-thread + per-IP windows with retry_after_ms; 401/413/507/405 carry a machine code, only rate_limited is retryable - _docs/chat-contract.md: frozen shapes, incl. why the cursor is ms and not ts - scripts/chat.py: list/show/reply, UTC, locked, atomic replace - api/debug/agent-replies.php POST -> 410 Gone with pointers (one write path) Measured: 401 no-token, 201+id, poll 1 msg, poll>since 1 new, data/chat 403, 4001 chars 413 (codepoints), 429 with Retry-After 576, round trip via chat.py. --- api/chat/poll.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 api/chat/poll.php (limited to 'api/chat/poll.php') diff --git a/api/chat/poll.php b/api/chat/poll.php new file mode 100644 index 0000000..601beca --- /dev/null +++ b/api/chat/poll.php @@ -0,0 +1,27 @@ + 0 + ? array_values(array_filter($all, fn($m) => (int)($m['epoch'] ?? 0) > $since)) + : $all; +$lastAll = $all ? end($all) : null; + +json_response([ + 'success' => true, + 'thread' => $thread, + 'messages' => array_slice($messages, -50), + // `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' => $lastAll ? (int)($lastAll['epoch'] ?? 0) : 0, +]); -- cgit v1.2.3