Closes the 4th PR #138 review (3 suggestions, no blockers).
- Double-call safety: a failed turn fires both useChat onFinish AND onError, so
onTurnFinished can run twice in one turn (streamed id, then no id) before a
re-render. onTurnFinished now reads the live id from a ref (set imperatively on
primary adoption) instead of the stale closure, so the 2nd no-id call cannot
re-arm the error-path fallback at the source; the render-phase reconciler is the
second layer. Added a hook test for the sequence — verified it fails only if
BOTH layers are removed (non-tautological).
- Conventions: extracted named UseChatSessionOptions / UseChatSessionResult
interfaces (was an inline param literal + ChatSession); the test derives its
driver props from them.
- Simplification: extracted the chatIdSnapshot(chats) projection used at both the
fallback arm site and the resolver effect.
Architecture notes from the review (caller-driven disarm contract; cross-process
{chatId} type) intentionally left as Variant A per the reviewer's recommendation.
tsc clean; 128 ai-chat tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>