Vishnu — The Preserver (Clean Code & Data Fetching)
Vishnu preserves order: code that stays readable and data that arrives fast, validated, and exactly once.
Naming & structure
- Names say what, not how:
fetch_active_users, notget_data2orhelper. - Functions ≤ 30 lines, one responsibility. If you need "and" to describe it, split it.
- Max 3–4 parameters; beyond that, pass a dataclass / options object.
- Booleans read as predicates:
is_expired,has_access,should_retry. - No dead code, no commented-out blocks, no
TODOwithout an issue link. Delete it — git remembers.
Python
- Type hints on every public function signature;
mypymust pass with no# type: ignoreunless justified inline. - Raise specific exceptions; never bare
except:— catch the narrowest type and either handle or re-raise with context. - Validate all external data (API responses, request bodies, LLM output) with
pydanticmodels at the boundary; internals trust typed objects.
JS/TS
- TypeScript strict mode on (
strict: true,noUncheckedIndexedAccess: true).anyis banned; useunknown+ narrowing. - Validate at boundaries with
zod(schema.parseon API responses, form input, LLM output). - Errors: throw
Errorsubclasses with a message and cause; never throw strings. Handle rejected promises — no floating promises (@typescript-eslint/no-floating-promises).
Data fetching
- Every external call (HTTP, DB, LLM) has an explicit timeout. No unbounded waits, ever.
- Use async/await end to end:
httpx.AsyncClient/asyncpgin Python, nativefetchin TS. Never block the event loop with sync I/O. - Retries: exponential backoff with jitter, max 3 attempts, only on retryable errors (429, 5xx, timeouts). Never retry non-idempotent writes blindly.
- Batch instead of loop: one query for N ids (
WHERE id = ANY(...), DataLoader on the frontend). N+1 queries are a review blocker. - Paginate anything unbounded: cursor-based pagination for APIs,
LIMIT/cursor for DB reads. NeverSELECT *without a limit. - Cache reads with an explicit TTL; prefer stale-while-revalidate (serve cached, refresh in background) for hot paths. Key caches on all inputs that affect the result.
- Deduplicate in-flight identical requests (single-flight) so a burst hits the source once.
AI-native specifics
- LLM calls are external calls: timeout, retry with backoff on 429/5xx, and validate the parsed output with pydantic/zod before use.
- Batch embedding requests (provider batch endpoints) instead of one call per document.
- Cache LLM responses keyed on (model, prompt version, normalized input); see
garudafor semantic caching. - Fetch context concurrently: run independent retrieval calls with
asyncio.gather/Promise.all, not sequentially.
Before merging — checklist
- Types pass (
mypy/tsc --noEmit), noanyor unjustified ignores - Every external call has timeout + bounded retry
- No N+1 patterns; unbounded lists are paginated
- Boundary data validated with pydantic/zod
- No dead code or commented-out blocks in the diff