- CurlCffi/Noble raw_request translate backend-native network errors (curl_cffi
RequestException, noble_tls TLSClientException) into aiohttp.ClientError so the bare
request() path gives the same typed-failure contract as the aiohttp backend (L6)
- Noble.setup uses download_if_necessary (the current noble_tls API), with
update_if_necessary only as a fallback; docstring/CLAUDE.md no longer claim the dead
'refreshes an existing one' path (L7)
- pyproject description says composition (one injectable TLSSession), not the old
'ExtendedSession subclasses' (L8).
Signed-off-by: disqualifier <dev@disqualifier.me>
per-call impersonate= is honored only via the low-level request()/_raw_request path
(which forwards **kwargs to the backend), NOT request_with_retries — its inherited
aioweb signature is fixed with no **kwargs and raises TypeError on an extra kwarg.
docs-only across README + backend docstring + CLAUDE.md; for the retrying path, set
the profile on the CurlCffi/Noble instance. no code change.
Signed-off-by: disqualifier <dev@disqualifier.me>
Noble.setup guarded the one-time Go shared-library fetch with a bare 'if self._updated' flag — a TOCTOU race where concurrent first requests both passed the check before either set the flag, running the download multiple times. now guarded by a per-instance asyncio.Lock with a check-lock-recheck. verified under load: 2/10/100/500 concurrent setups run the fetch exactly once each (a no-lock control runs it N times).
Signed-off-by: disqualifier <dev@disqualifier.me>