Skip to content

Bound what one guest can make the chat hold or compute (review, area 2) - #309

Merged
adamjohnwright merged 1 commit into
mainfrom
review-2-exhaustion
Oct 3, 2026
Merged

adamjohnwright merged 1 commit into
mainfrom
review-2-exhaustion

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

These come from the max-level review of the chat flow. Each was reproduced by the reviewer.

Finding Fix Checked by
The typed-yes regex backtracked quadratically on the raw message. One offer, then "y" + 990K spaces, would stall the shared event loop for about 90 minutes. Messages over 40 characters are not a yes, and the pattern uses possessive quantifiers Timing test (under 0.1s). Under sabotage the test hangs until killed.
Chat messages had no length cap. A 1M-character message was kept in the checkpoints (3 MB) and sent to the model on every later turn. Messages over 60K are declined; questions over 8K are declined before reaching the model Browser: an oversized question gets the polite refusal, and the next question is answered
Chainlit keeps every message in chat_contexts[session] forever, including rate-limited ones. Dropped after each message and when the session ends (nothing here reads it) Browser: multi-turn chat still works
Guest graph threads, offers and seed state were never freed. Deleted on on_chat_end for guests, who cannot resume Store test
Gene-list seeds and offers kept the whole 60K message and every identifier, about 0.85 MB per offer. Capped at 8K of text and 3,000 identifiers —

The GSA validator problems (unbounded work on the event loop, encoding, R headers, CSV) will be in the GSA PR.

./checks.sh passes. The gene-list browser suite passes.

🤖 Generated with Claude Code

- The typed-yes check ran an unbounded, backtracking pattern on the raw
  message on the shared event loop: one offer plus 'y' and a million
  spaces stalled every session for about 90 minutes. Messages over 40
  characters are not a yes, and the pattern is possessive.
- Messages over 60K are declined, and questions to the model over 8K: a
  million-character message was kept in the thread's checkpoints and sent
  to the model on every later turn.
- Chainlit keeps every incoming message in a per-session list that is
  never cleared, rejected ones included. Nothing here reads it; it is now
  dropped after each message and when the session ends.
- A finished guest session's graph thread, offers and seed state are
  deleted; guests cannot resume, and MemorySaver kept them until restart.
- Gene-list seeds and offers keep at most 8K of the message and the
  identifiers that can be submitted (3,000), not the whole 60K and all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit 2ded62f into main Oct 3, 2026
10 checks passed
@adamjohnwright
adamjohnwright deleted the review-2-exhaustion branch October 3, 2026 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant