# 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).
