_get_copilot_access_token had a check-then-act race: concurrent chat() calls after token expiry both fetched new tokens and clobbered each other. Add asyncio.Lock with double-checked locking so only one fetch happens per expiry window. Closes #4677