Assistant trigger CAS (P1):
- hook-triggered route: added expectedOwner param for compare-and-swap —
rejects if current owner doesn't match, closing the race where two tabs
both clear then both claim the lock
- useAssistantTrigger: clear sends expectedOwner (stale session), set sends
expectedOwner: null; non-2xx responses now bail instead of falling through
- Server-side completion (chat/route.ts): only clears lock if owner matches
current sessionId, preventing completed sessions from wiping active locks
- Compensation branch: clear now passes expectedOwner to avoid bypassing CAS
Image-gen LIKE escape (P2):
- db.ts: escape backslashes before % and _ since ESCAPE '\' makes \ the
escape char — prevents Windows paths / escaped JSON from corrupting the
LIKE pattern and silently falling back to prompt-prefix matching
Provider options fetch race (P2):
- page.tsx + ChatView.tsx: provider options fetch now uses AbortController
with cleanup on dependency change — prevents stale slow responses from
overwriting the current provider's thinking/context_1m state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>