# Three-axis drift: catching code↔schema, env, and dependency mismatches before they ship The bug isn't in the code you're reading — it's in the gap between the code and the schema, the env, or the manifest. SecondOS surfaces all three, read-only. Some of the nastiest bugs aren't *in* a file — they're in the **gap** between two things that were supposed to agree. The code writes a column the schema doesn't have. The code reads an env var nobody documented. You import a package that isn't in `package.json`. Everything looks fine in review, and breaks in production. SecondOS surfaces three of these gaps, read-only, with both locations: ## 1. Code vs DB schema It reads your Drizzle schema into a model and checks the columns your code actually writes against it. Write `lastSeenAt` in `routes/ping.ts` when the `users` table has no such column, and `schema_drift` flags it — with the code location *and* the schema location. Dynamic/spread writes are skipped and counted, so it never cries wolf. ## 2. Env vars vs .env.example The `process.env` values your code reads, checked against what `.env.example` documents: the ones you read but never declared (a deploy waiting to fail), and the ones declared but never used. ## 3. Imports vs package.json The packages you import, checked against your manifest: an import with no dependency entry, and declared-but-unused packages. ## Read-only, and honest Drift is an **alert**, not an auto-fix — it never changes your code. And it reports only what it can prove; ambiguous cases are counted, not guessed. Run it from the CLI (`secondos drift`) or read it over MCP (`schema_drift`, `cross_repo_drift`) so your AI tool catches the mismatch too. The map that powers this is the same one every AI tool reads. [See the product](/product).