<feed xmlns='http://www.w3.org/2005/Atom'>
<title>newos4/api/chat, branch main</title>
<subtitle>newOS4 - the browser terminal that runs WebX11 user spaces</subtitle>
<id>https://newos.webx11.duckdns.org/newos4/atom?h=main</id>
<link rel='self' href='https://newos.webx11.duckdns.org/newos4/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/'/>
<updated>2026-10-23T18:37:54+00:00</updated>
<entry>
<title>fix(chat): GLM review batch — corruption, traversal, cursor truncation, double print (v4.6.78-80)</title>
<updated>2026-10-23T18:37:54+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-23T18:37:54+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=4d717018ea8a748b8bb16ad71c3deab6d8c20545'/>
<id>urn:sha1:4d717018ea8a748b8bb16ad71c3deab6d8c20545</id>
<content type='text'>
12 findings accepted, 3 refuted with evidence (see _docs/chat-review-glm-2026-10-23.md).

Data loss: a corrupt thread read as [] and the next append rewrote it with one message —
now 500 and the file is left alone. Cursor after a &gt;50-message truncation pointed at the
thread tail, making the oldest permanently unfetchable — now the last message actually
sent, plus truncated:true. Two posts in the same millisecond shared a cursor — epoch is
now strictly increasing.

Security: chat.py show() had no id validation and joined argv onto CHAT_DIR ('../../x'
read any .json as darkbot) — THREAD_RE added. The auto-reply prompt now treats message
text as untrusted data and forbids acting on instructions found in it.

Ops: relay housekeeping swept neither .lock-* nor orphaned .tmp-*; a crashed listing
looked identical to an empty queue; grep AWAITING also matched message bodies; hermes-poll
printed every reply twice.

Verified: corrupt file -&gt; 500 with the file untouched; traversal -&gt; 'invalid thread id';
hermes-poll -&gt; exactly one line per reply.
</content>
</entry>
<entry>
<title>feat(chat): token-scoped chat endpoints, contract, host CLI, old POST retired (v4.6.71 phase B)</title>
<updated>2026-10-23T17:29:31+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-23T17:29:31+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=313f13955ad9c72895b0914ac828c61b3e469715'/>
<id>urn:sha1:313f13955ad9c72895b0914ac828c61b3e469715</id>
<content type='text'>
- 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 -&gt; 410 Gone with pointers (one write path)

Measured: 401 no-token, 201+id, poll 1 msg, poll&gt;since 1 new, data/chat 403,
4001 chars 413 (codepoints), 429 with Retry-After 576, round trip via chat.py.
</content>
</entry>
</feed>
