<feed xmlns='http://www.w3.org/2005/Atom'>
<title>newos4/scripts/chat.py, 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=577c9241a4ac1c55c5ed0031b76a8a1f83798752'/>
<id>urn:sha1:577c9241a4ac1c55c5ed0031b76a8a1f83798752</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>fix(chat): three concurrency holes found reviewing my own patch (v4.6.77)</title>
<updated>2026-10-23T18:30:20+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-23T18:30:20+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=dfef70b61b98382a1f78fc6d970fb24ac86c4e36'/>
<id>urn:sha1:dfef70b61b98382a1f78fc6d970fb24ac86c4e36</id>
<content type='text'>
1. chat.py renamed the temp file AFTER releasing the flock, so two writers could each
   read the pre-replace snapshot and the later rename silently dropped the earlier
   message. os.replace now happens inside the lock.
2. The agent cursor was global. After hermes-reset it pointed past the end of the new
   empty thread, so every read returned nothing — the agent would think it had been
   ignored. Key is now per thread and reset clears every chat cursor.
3. chat-relay.sh had no overlap guard: a slow agent run (up to 5 min) could collide with
   the next tick and answer the same thread twice. flock -n on /tmp/chat-relay.lock.

Verified: stale cursor 'webx11_chat_agent_cursor_oldthread00000' set to 9999999999999,
hermes-reset -&gt; zero cursor keys remain, read returns {messages:[], note:'no new messages...'}.
</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=0d2365ab202ba5c9b1d0604467af0594dc7360de'/>
<id>urn:sha1:0d2365ab202ba5c9b1d0604467af0594dc7360de</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>
