0290b003c7
Review round on the K3 kit, four moves: _client.py/_client.ts -> client.py/client.ts across every backend, both languages (the underscore said plumbing; the kit made the client a named layer). The sweep covers dotted module paths, module-object imports (postgres), monkeypatch string targets (including the multiline commands.builtin.postgres.tail one), vi.mock specifiers, namespace-import aliases, the mypy override list, and dify's test__client mirror; attribute spellings like self._client and the s3 _client_kwargs symbol are deliberately untouched. API bases, versions and thresholds move out of the four migrated clients into per-backend constants.py/constants.ts (discord, notion, google, dropbox), following slack's existing convention; the remaining backends move with their own K3 migrations. ErrorOf and PageFetch move to mirage.types / core/src/types.ts as the shared contracts. The python alias is quoted behind TYPE_CHECKING so importing mirage.types still never loads aiohttp at runtime. The python engine's retry loop is now tenacity (already a dependency, and dify's client is the in-repo idiom): the attempt raises a _RetryableStatus carrying the body text it already read, the wait callback derives the delay from it synchronously, and exhaustion maps through the same error_of hook as a plain error status. TypeScript keeps the hand-rolled loop - there is no tenacity twin and core takes no new dependency for a 15-line loop. Verified again end to end: layout parity 290=baseline, spec trees regen zero-diff, knip/eslint/tsc clean, core 8824 / node 2255 / browser 184, py suite green (known local deepagents drift excepted), integ both hosts 7423 passed / 0 failed across the same eight targets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>