Opinionated conventions for building and running production FastAPI services in Python.
# FastAPI Service taste of a Python API engineer - Define request and response bodies with Pydantic v2 models and always set response_model so nothing leaks by accident. Confidence: 0.95 - Keep separate schemas for create, update and read instead of reusing the ORM model as the API shape. Confidence: 0.90 - Use async def endpoints only when every call inside is truly async; otherwise write plain def and let the threadpool handle it. Confidence: 0.85 - Inject database sessions, settings and the current user through Depends, never through module-level globals. Confidence: 0.90 - Load configuration with pydantic-settings from environment variables and fail fast at startup if anything is missing. Confidence: 0.90 - Split routes into APIRouter modules by domain and keep main.py limited to app creation and wiring. Confidence: 0.85 - Put business logic in service functions that know nothing about HTTP, so they can be reused from workers and tests. Confidence: 0.85 - Use SQLAlchemy 2.0 style with async sessions and manage the schema with Alembic migrations. Confidence: 0.80 - Use the lifespan context manager for startup and shutdown instead of the deprecated on_event hooks. Confidence: 0.85 - Raise HTTPException only at the edge and map domain errors to status codes with registered exception handlers. Confidence: 0.80 - Return a consistent error body with a machine-readable code, a message and optional details. Confidence: 0.85 - Version the API in the path (/v1) and treat the generated OpenAPI schema as a contract checked in CI. Confidence: 0.75 - Use cursor-based pagination for large lists and cap the page size on the server. Confidence: 0.80 - Test with pytest and httpx.AsyncClient, overriding dependencies instead of patching internals. Confidence: 0.90 - Run uvicorn workers behind gunicorn or a process manager in production, with --reload only in development. Confidence: 0.80 - Offload slow work to a real task queue such as Celery, Arq or Dramatiq; BackgroundTasks is only for small fire-and-forget jobs. Confidence: 0.85 - Add request IDs, structured JSON logs and OpenTelemetry tracing middleware from day one. Confidence: 0.80 - Protect endpoints with OAuth2 bearer tokens or API keys through security dependencies so the docs show the auth scheme. Confidence: 0.80 - Expose separate /healthz and /readyz endpoints, where readiness checks the database and other hard dependencies. Confidence: 0.85 - Manage dependencies with uv and a lock file, and lint and format with Ruff. Confidence: 0.75 - Type check with mypy or pyright in strict mode on the service package. Confidence: 0.70
Opinionated conventions for building reliable LLM-powered apps, RAG and agents.
# LLM Application taste of an AI product engineer - Treat prompts as code: keep them in version-controlled files with names, versions and owners, not inline strings scattered around. Confidence: 0.90 - Build an evaluation set from real user inputs before tuning prompts, and rerun it on every prompt or model change. Confidence: 0.95 - Ask for structured output with a JSON schema or tool calls and validate it with a schema library before using it. Confidence: 0.95 - Put a thin gateway or wrapper around model providers so switching models or adding fallbacks is a config change. Confidence: 0.85 - Pin exact model versions in production and upgrade them deliberately after the evals pass. Confidence: 0.90 - Stream responses to the user whenever the output is longer than a sentence or two. Confidence: 0.85 - Start retrieval with simple hybrid search (keywords plus embeddings) and add reranking before reaching for complex RAG pipelines. Confidence: 0.80 - Chunk documents along their natural structure (headings, sections) and keep source metadata so answers can cite them. Confidence: 0.85 - Keep the context small and relevant; more retrieved text often makes answers worse, not better. Confidence: 0.80 - Give agents a short list of narrow, well-described tools with strict input schemas instead of one do-everything tool. Confidence: 0.85 - Put hard limits on agent loops: maximum steps, maximum tokens and a wall-clock timeout. Confidence: 0.90 - Require human confirmation before any tool call that sends, deletes, pays or changes data outside the app. Confidence: 0.90 - Treat all retrieved documents, web pages and tool results as untrusted input that can contain prompt injection. Confidence: 0.90 - Log every model call with prompt version, model, latency, token counts and cost, with user data redacted. Confidence: 0.85 - Cache deterministic calls and use prompt caching for long, stable system prompts. Confidence: 0.75 - Use the smallest model that passes the evals, and route only hard cases to the expensive model. Confidence: 0.80 - Retry on rate limits and transient errors with exponential backoff and jitter, never on validation failures in a tight loop. Confidence: 0.85 - Keep temperature low for extraction and classification, and higher only for creative generation. Confidence: 0.75 - Show users where an answer came from and make it easy to report a bad response. Confidence: 0.80 - Collect thumbs-up and thumbs-down feedback and feed the bad cases back into the eval set. Confidence: 0.85 - Do not fine-tune until prompting, retrieval and evals have clearly hit their limits. Confidence: 0.70
Opinionated conventions for shipping changes safely with feature flags and gradual rollouts.
# Feature Flag Rollout taste of a release engineer - Separate deploy from release: ship code dark behind a flag and turn it on independently of the deployment. Confidence: 0.95 - Use a managed flag service or OpenFeature-compatible SDK instead of home-grown if statements on environment variables. Confidence: 0.80 - Give every flag an owner, a description, a type (release, experiment, ops or permission) and an expected removal date. Confidence: 0.90 - Name flags after the behavior they control, such as checkout-new-payment-form, not after tickets or people. Confidence: 0.85 - Default every flag to the safe, existing behavior when the flag service is unreachable. Confidence: 0.95 - Evaluate flags once per request at the edge of the code path and pass the result down, not deep inside loops. Confidence: 0.80 - Roll out gradually: internal users first, then 1%, 10%, 50% and 100%, watching metrics at each step. Confidence: 0.90 - Use sticky, hash-based bucketing on a stable user or account ID so people do not flip between variants. Confidence: 0.90 - Define the success and guardrail metrics before the rollout starts, not after looking at the dashboard. Confidence: 0.85 - Wire automatic rollback to error rate and latency alerts for risky changes. Confidence: 0.75 - Keep a kill switch for every expensive or external dependency so operations can turn it off without a deploy. Confidence: 0.90 - Remove release flags within a few weeks of reaching 100% and fail CI when a flag is past its removal date. Confidence: 0.80 - Test both the on and off paths in CI for every active flag. Confidence: 0.85 - Avoid nesting flags inside other flags; if two flags interact, merge them or document the combinations. Confidence: 0.80 - Log flag evaluations with the variant in traces so incidents can be tied to a specific rollout. Confidence: 0.80 - Restrict who can change production flags and keep an audit log of every change with a reason. Confidence: 0.85 - Never use feature flags as a substitute for authorization checks. Confidence: 0.90 - Announce large rollouts in a shared channel with the flag name, the plan and the rollback step. Confidence: 0.70 - Keep long-lived permission and ops flags in a separate list so they are not mistaken for stale release flags. Confidence: 0.75 - Run a short review after each major rollout and note which metrics actually caught problems. Confidence: 0.65
Opinionated conventions for building cross-platform mobile apps with React Native and Expo.
# React Native App taste of a cross-platform mobile engineer - Start new apps with Expo and the prebuild workflow instead of a bare React Native project, and eject only when a native module truly needs it. Confidence: 0.90 - Write everything in TypeScript with strict mode on, including navigation params and native module bindings. Confidence: 0.95 - Use Expo Router for file-based navigation and keep typed routes enabled so broken links fail at compile time. Confidence: 0.80 - Keep server state in TanStack Query and limit global client state to a small Zustand store for session and preferences. Confidence: 0.85 - Never store tokens in AsyncStorage; use expo-secure-store or the Keychain and Keystore for anything sensitive. Confidence: 0.95 - Render long lists with FlashList or a well-tuned FlatList with stable keys, never a ScrollView with map. Confidence: 0.90 - Run animations on the UI thread with Reanimated and gestures with react-native-gesture-handler, not the old Animated API. Confidence: 0.85 - Enable the New Architecture and Hermes by default and treat libraries that block it as tech debt. Confidence: 0.75 - Keep a single theme module for colors, spacing and typography, and support dark mode from the first screen. Confidence: 0.85 - Respect safe areas with react-native-safe-area-context instead of hardcoded padding for notches. Confidence: 0.90 - Put platform-specific code in .ios.tsx and .android.tsx files rather than scattering Platform.OS checks. Confidence: 0.70 - Ship JavaScript fixes through EAS Update with a runtime version policy, and use store releases for native changes. Confidence: 0.80 - Build and sign in CI with EAS Build so no release depends on a single laptop. Confidence: 0.85 - Test components with React Native Testing Library and query by role and text, not by testID first. Confidence: 0.80 - Cover the critical flows end to end with Maestro or Detox on real simulators in CI. Confidence: 0.75 - Add accessibilityLabel and accessibilityRole to every touchable and keep tap targets at least 44 points. Confidence: 0.90 - Handle offline as a normal state: show cached data, queue writes and retry when the connection returns. Confidence: 0.80 - Report crashes and JavaScript errors with Sentry including source maps for every release. Confidence: 0.85 - Optimize images with expo-image and caching instead of the default Image component. Confidence: 0.80 - Profile with the React Native DevTools before guessing at performance fixes. Confidence: 0.70 - Ask for permissions only at the moment a feature needs them, with a short explanation screen first. Confidence: 0.90
Opinionated conventions for writing and maintaining developer documentation that stays accurate.
# Technical Documentation taste of a developer-focused writer - Keep docs in the same repository as the code and review them in the same pull request as the change. Confidence: 0.95 - Write in Markdown or MDX and build the site with a static generator such as Docusaurus, Starlight or MkDocs. Confidence: 0.85 - Organize content into tutorials, how-to guides, reference and explanation, following the Diataxis model. Confidence: 0.85 - Open the README with one sentence on what the project does, then install and a working quick start within the first screen. Confidence: 0.95 - Make every code sample copy-pasteable and runnable, with imports and realistic values included. Confidence: 0.95 - Test code samples in CI or extract them from tested example files so they never rot. Confidence: 0.80 - Generate API reference from the source, such as OpenAPI, TypeDoc or docstrings, instead of writing it by hand. Confidence: 0.90 - Write in second person and active voice with short sentences and plain words. Confidence: 0.90 - Use task-based headings like "Rotate an API key" rather than vague ones like "Keys". Confidence: 0.85 - State prerequisites and versions at the top of every guide. Confidence: 0.85 - Show the expected output after each command so readers know they are on track. Confidence: 0.80 - Lint prose with Vale and a shared style guide, and check links on every build. Confidence: 0.80 - Use admonitions such as Note and Warning sparingly, only for information that changes what the reader does. Confidence: 0.75 - Prefer diagrams as code with Mermaid so they can be reviewed and updated like text. Confidence: 0.75 - Keep a changelog in Keep a Changelog format and write migration guides for every breaking change. Confidence: 0.90 - Record architecture decisions as short ADRs that explain the context and the tradeoffs, not only the choice. Confidence: 0.85 - Give every page an owner and a last-reviewed date, and remove pages that are no longer true. Confidence: 0.75 - Add a search box and stable deep links to headings before adding any other site feature. Confidence: 0.80 - Write alt text for every screenshot and avoid screenshots of text that could be a code block. Confidence: 0.85 - Collect feedback with a simple "Was this page helpful?" widget and review the results monthly. Confidence: 0.65 - Document error messages by their exact text so users can find the fix by searching. Confidence: 0.85
Opinionated conventions for running reproducible machine learning experiments, from baseline to production.
# Machine Learning Experiment taste of an applied ML engineer - Write the evaluation metric and a dumb baseline before training any real model. Confidence: 0.95 - Split data by time or by entity when leakage is possible, never with a random split by default. Confidence: 0.90 - Freeze the test set early and look at it only for final decisions, using a separate validation set for tuning. Confidence: 0.95 - Track every run with MLflow or Weights & Biases, logging config, metrics, code version and dataset version. Confidence: 0.90 - Keep experiment config in versioned YAML files loaded with Hydra or Pydantic, not in hardcoded constants. Confidence: 0.80 - Set and log random seeds for Python, NumPy and the framework, and report variance across several seeds. Confidence: 0.85 - Version datasets with DVC or immutable object storage paths so any result can be reproduced. Confidence: 0.80 - Prototype in notebooks but move reusable code into a tested Python package as soon as it is used twice. Confidence: 0.85 - Pin dependencies with a lock file and record the CUDA and driver versions with each run. Confidence: 0.75 - Inspect raw samples and label errors by hand before trusting any aggregate metric. Confidence: 0.90 - Prefer gradient boosted trees for tabular data and reach for deep learning only when they clearly fall short. Confidence: 0.80 - Use PyTorch with a thin training loop or Lightning instead of large custom frameworks. Confidence: 0.70 - Report metrics per slice such as region, device or class, not only a single global number. Confidence: 0.90 - Calibrate predicted probabilities when downstream code makes threshold decisions. Confidence: 0.75 - Tune hyperparameters with Optuna or a simple random search under a fixed compute budget. Confidence: 0.75 - Write unit tests for feature transforms and data loaders, and assert expected shapes and dtypes. Confidence: 0.85 - Validate input data with schema checks such as Pandera or Great Expectations before training. Confidence: 0.80 - Save the model together with its preprocessing pipeline as one artifact so training and serving cannot drift. Confidence: 0.90 - Compare a new model to the production model offline and then with a shadow or A/B rollout. Confidence: 0.85 - Monitor feature drift and prediction distributions after launch and alert on large shifts. Confidence: 0.80 - Write a short experiment note for every significant run with the hypothesis, the result and the next step. Confidence: 0.85 - Delete or archive failed branches of work instead of leaving dozens of half-finished notebooks. Confidence: 0.65
Opinionated conventions for building reliable background job queues and workers.
# Background Jobs taste of a backend reliability engineer - Make every job idempotent so a retry or duplicate delivery never charges a card or sends an email twice. Confidence: 0.95 - Pass IDs in the job payload and load fresh data inside the worker instead of serializing whole records. Confidence: 0.90 - Enqueue jobs in the same database transaction as the write that triggers them, using an outbox table or a Postgres-backed queue. Confidence: 0.85 - Prefer a boring, well-supported queue such as Sidekiq, BullMQ, Celery or a Postgres queue like Graphile Worker over a home-grown one. Confidence: 0.80 - Retry with exponential backoff and jitter, and cap attempts so poison jobs end up in a dead letter queue. Confidence: 0.95 - Classify errors as retryable or permanent and fail permanent ones immediately instead of burning retries. Confidence: 0.85 - Set an explicit timeout on every job and on every network call it makes. Confidence: 0.90 - Keep jobs small and short, and split long batch work into chunks that can resume from a checkpoint. Confidence: 0.85 - Use separate queues for latency-sensitive and bulk work so a backfill never delays password reset emails. Confidence: 0.90 - Rate limit jobs that call third-party APIs per provider, not per worker process. Confidence: 0.80 - Use unique job keys or locks to prevent the same scheduled job from running twice at once. Confidence: 0.85 - Run cron-style schedules from one scheduler with leader election, never from every app instance. Confidence: 0.80 - Version job payloads and keep workers able to read the previous version during deploys. Confidence: 0.80 - Handle SIGTERM gracefully: stop taking new jobs, finish or requeue the current one, then exit. Confidence: 0.90 - Log a job ID, attempt number and correlation ID on every log line from a job. Confidence: 0.85 - Alert on queue depth, oldest job age and dead letter growth, not just on worker crashes. Confidence: 0.90 - Give the dead letter queue an owner and a documented replay command. Confidence: 0.75 - Test jobs by calling the handler directly in unit tests and run one end-to-end test through the real queue in CI. Confidence: 0.80 - Avoid chaining many jobs into hidden workflows; reach for a workflow engine like Temporal when steps need orchestration. Confidence: 0.70 - Store job results and side-effect markers in the database, not only in the queue backend. Confidence: 0.75
Opinionated conventions for building maintainable Vue 3 apps with TypeScript and the Composition API.
# Vue App taste of a frontend engineer - Start new projects with Vite and Vue 3, or Nuxt when server rendering or file-based routing is needed. Confidence: 0.90 - Write components with script setup and the Composition API, not the Options API. Confidence: 0.90 - Use TypeScript everywhere and check templates with vue-tsc in CI. Confidence: 0.90 - Type props and emits with defineProps and defineEmits generics instead of runtime-only declarations. Confidence: 0.85 - Use Pinia for shared client state and keep stores small and focused on one domain. Confidence: 0.85 - Fetch server data with TanStack Query for Vue or Nuxt useFetch instead of hand-rolled loading flags in stores. Confidence: 0.80 - Extract reusable logic into composables named useSomething that return refs and functions. Confidence: 0.90 - Reach for VueUse before writing a custom composable for common browser APIs. Confidence: 0.75 - Prefer computed over watch, and use watch only for side effects. Confidence: 0.90 - Never mutate props; emit events or use defineModel for two-way binding. Confidence: 0.95 - Always give v-for items a stable key from the data, never the index. Confidence: 0.90 - Never combine v-if and v-for on the same element. Confidence: 0.90 - Keep components under about 200 lines and split them when the template gets hard to scan. Confidence: 0.70 - Use multi-word PascalCase component names and colocate components by feature, not by type. Confidence: 0.80 - Style with scoped CSS or Tailwind, and avoid global styles beyond a small reset and design tokens. Confidence: 0.75 - Lazy load route components with dynamic imports in Vue Router. Confidence: 0.85 - Test components with Vitest and Vue Testing Library, querying by role and text. Confidence: 0.85 - Lint with ESLint and eslint-plugin-vue using the recommended rules, and format with Prettier. Confidence: 0.85 - Avoid provide and inject for app state; use it only for component library internals and deep config. Confidence: 0.70 - Sanitize any HTML before using v-html, or better, avoid v-html altogether. Confidence: 0.95
Opinionated conventions for building secure cross-platform desktop apps with Tauri and Rust.
# Tauri Desktop App taste of a cross-platform desktop developer - Choose Tauri over Electron for new desktop apps when bundle size and memory use matter. Confidence: 0.80 - Build the frontend with Vite and TypeScript in strict mode, and keep it framework-agnostic from the Rust side. Confidence: 0.85 - Keep business logic that touches the file system, network or OS in Rust commands, and keep the web layer focused on UI. Confidence: 0.85 - Enable only the capabilities and permissions each window needs, and never ship a wildcard allowlist. Confidence: 0.95 - Set a strict Content Security Policy and never load remote content into a window that can call commands. Confidence: 0.95 - Generate TypeScript bindings for commands with tauri-specta or ts-rs so frontend and Rust types cannot drift. Confidence: 0.80 - Return structured errors from commands with thiserror and serde instead of plain strings. Confidence: 0.85 - Run slow work in async commands or background tasks and report progress through events, never blocking the main thread. Confidence: 0.90 - Store user settings with the official store plugin and secrets in the OS keychain, not in plain JSON files. Confidence: 0.90 - Use SQLite through sqlx or the SQL plugin for local data, with migrations checked into the repo. Confidence: 0.80 - Resolve paths with the path API for app data and config folders instead of hardcoding locations. Confidence: 0.90 - Ship automatic updates with the updater plugin and signed release artifacts. Confidence: 0.85 - Sign and notarize macOS builds and sign Windows installers from CI, never from a developer laptop. Confidence: 0.90 - Build every platform in GitHub Actions with the tauri-action matrix on each release tag. Confidence: 0.80 - Test the UI on WebKit, WebView2 and WebKitGTK, since rendering and APIs differ between them. Confidence: 0.85 - Respect platform conventions for menus, shortcuts and window controls instead of one custom title bar everywhere. Confidence: 0.75 - Unit test Rust commands directly and cover the main flows with WebDriver end-to-end tests. Confidence: 0.70 - Keep the dependency tree small and run cargo audit and npm audit in CI. Confidence: 0.80 - Log to a rotating file in the app log folder and give users a one-click way to export logs for bug reports. Confidence: 0.75
Opinionated conventions for building full-stack SvelteKit apps with Svelte 5 runes and TypeScript.
# SvelteKit App taste of a full-stack web developer - Start every project with the official sv create template, TypeScript enabled and strict mode on. Confidence: 0.90 - Use Svelte 5 runes ($state, $derived, $effect, $props) for all new components instead of legacy reactive statements. Confidence: 0.90 - Reach for $derived before $effect, and keep $effect for syncing with things outside Svelte like the DOM or third-party libraries. Confidence: 0.90 - Load data in +page.server.ts when it needs secrets or the database, and use universal +page.ts only for public fetches. Confidence: 0.90 - Handle mutations with form actions and use:enhance so forms work without JavaScript and get progressive enhancement for free. Confidence: 0.85 - Validate form and API input on the server with Zod or Valibot, and return fail() with field errors instead of throwing. Confidence: 0.90 - Keep server-only code in $lib/server so the build fails if it is ever imported into the client. Confidence: 0.95 - Read secrets from $env/static/private or $env/dynamic/private, never from public env modules. Confidence: 0.95 - Put authentication and session lookup in hooks.server.ts and expose the user through event.locals. Confidence: 0.90 - Never store per-request user data in module-level state, because it leaks between requests on the server. Confidence: 0.95 - Share client state through context or small rune-based modules in .svelte.ts files, not a global store for everything. Confidence: 0.80 - Use route groups like (app) and (marketing) to give sections different layouts without changing URLs. Confidence: 0.80 - Prerender static pages such as docs and marketing, and keep dynamic pages server-rendered. Confidence: 0.85 - Pick an explicit adapter (adapter-node, adapter-vercel, adapter-cloudflare) instead of relying on adapter-auto in production. Confidence: 0.80 - Return typed data from load functions and rely on the generated ./$types instead of writing prop types by hand. Confidence: 0.90 - Use +error.svelte pages and the error() helper for expected failures, and log unexpected ones in handleError. Confidence: 0.85 - Style with scoped component CSS by default and add Tailwind only when the team already uses it. Confidence: 0.70 - Keep components small and pass snippets for flexible content instead of many boolean props. Confidence: 0.80 - Test components with Vitest and @testing-library/svelte, and cover the main flows with Playwright. Confidence: 0.85 - Run svelte-check, ESLint and Prettier with the Svelte plugin in CI on every pull request. Confidence: 0.85
Opinionated conventions for building reliable, cost-aware serverless functions in the cloud.
# Serverless Functions taste of a cloud backend engineer - Keep each function small and focused on one trigger, but group closely related HTTP routes in one handler to cut cold starts. Confidence: 0.80 - Initialize SDK clients and database pools outside the handler so warm invocations reuse them. Confidence: 0.95 - Use a connection pooler or an HTTP-based database driver, since thousands of concurrent functions will exhaust direct Postgres connections. Confidence: 0.90 - Set an explicit timeout and memory size per function instead of accepting platform defaults. Confidence: 0.85 - Keep bundles small with tree-shaking and lazy imports, and measure cold start time after every major dependency change. Confidence: 0.85 - Make every event handler idempotent, because queues and event sources deliver at least once. Confidence: 0.95 - Move slow or retryable work to a queue and return quickly from HTTP functions. Confidence: 0.90 - Send failed async events to a dead letter queue with an alert on its depth. Confidence: 0.90 - Define functions, permissions and triggers as code with SST, Serverless Framework, SAM or Terraform, never by clicking in the console. Confidence: 0.90 - Grant each function its own least-privilege role scoped to the exact resources it touches. Confidence: 0.95 - Load secrets from a secrets manager or the platform's encrypted env vars, never from the repo. Confidence: 0.95 - Write structured JSON logs with a request ID and correlation ID on every line. Confidence: 0.90 - Trace requests across functions and queues with OpenTelemetry or the platform's tracing. Confidence: 0.80 - Keep business logic in plain modules and keep the handler a thin adapter, so it can be unit tested without the cloud. Confidence: 0.90 - Run integration tests against a real deployed stage per pull request rather than trusting local emulators. Confidence: 0.80 - Set reserved or maximum concurrency on functions that call fragile downstream services. Confidence: 0.85 - Use provisioned concurrency only for latency-critical paths where cold starts were measured to hurt. Confidence: 0.75 - Prefer the arm64 runtime when dependencies support it for better price per performance. Confidence: 0.70 - Set billing alerts and per-function cost dashboards before launch, not after the first surprise invoice. Confidence: 0.85 - Avoid chaining functions that call each other synchronously; use events or a workflow engine like Step Functions instead. Confidence: 0.85 - Choose containers or long-running services for steady high-throughput workloads where serverless costs more. Confidence: 0.75
Opinionated conventions for building secure, scalable realtime features with WebSockets.
# Realtime WebSocket taste of a realtime systems engineer - Use plain WebSockets or a thin library like ws for simple cases, and reach for Socket.IO only when you need its fallbacks and rooms. Confidence: 0.75 - Prefer Server-Sent Events when updates only flow from server to client. Confidence: 0.85 - Authenticate during the handshake with a short-lived token, never by trusting a user ID sent in a later message. Confidence: 0.95 - Check the Origin header on upgrade requests to block cross-site WebSocket hijacking. Confidence: 0.90 - Define every message as a typed envelope with a type, a version and a payload, validated with a schema on both ends. Confidence: 0.90 - Send heartbeats with ping and pong and close connections that miss them, since proxies drop idle sockets silently. Confidence: 0.90 - Reconnect on the client with exponential backoff and jitter so a server restart does not cause a thundering herd. Confidence: 0.95 - Give each message a sequence number so clients can resume from the last one they saw after reconnecting. Confidence: 0.85 - Treat the socket as a notification channel and keep the database as the source of truth that clients can refetch. Confidence: 0.85 - Fan out across server instances with Redis pub/sub, NATS or a managed service instead of in-memory broadcast. Confidence: 0.90 - Keep connection servers stateless apart from the open sockets, so any instance can be drained and replaced. Confidence: 0.80 - Drain connections gracefully on deploy by telling clients to reconnect before shutting down. Confidence: 0.85 - Apply backpressure: watch the send buffer and drop or coalesce updates for slow clients instead of buffering forever. Confidence: 0.85 - Rate limit incoming messages per connection and cap message size. Confidence: 0.90 - Authorize every subscription to a room or channel on the server, not just the initial connection. Confidence: 0.95 - Batch or throttle high-frequency updates like cursor positions to a fixed tick rate. Confidence: 0.80 - Configure load balancer idle timeouts and sticky sessions deliberately when the transport needs them. Confidence: 0.80 - Track open connections, messages per second, reconnect rate and delivery latency as first-class metrics. Confidence: 0.85 - Use CRDTs like Yjs or Automerge for collaborative editing instead of inventing your own conflict resolution. Confidence: 0.80 - Load test with realistic connection counts using k6 or Artillery before launch. Confidence: 0.80