Schema Guardian: classify migration risk before the LLM softens it
LLMs soften migration risk into chat vibes. Schema Guardian classifies locks, rewrites, money types, DROP/TRUNCATE, missing tenant scope, and replica-unsafe patterns first — then the model explains a fixed GO or NO-GO.
Ask a coding agent whether an ALTER TABLE is safe and you will get a paragraph. Soft language. “Might lock for a bit.” “Should be fine if the table isn’t huge.” “Consider running during a quiet window.”
That voice is useful for explaining. It is a terrible place to put the GO / NO-GO decision.
I spent years on a query engine team, then years watching Postgres and MySQL shops let agents draft schema changes. The failure mode is almost never “the model didn’t know DOUBLE is wrong for money.” Ask it directly and it will say DECIMAL. The failure mode is that risk arrives as narration, and narration is negotiable. Someone reads the soft paragraph, sees the green check in their head, and applies the statement.
Schema Guardian exists because we refused to let the model be the classifier.
The order that matters
DeepSQL is a self-hosted AI DBA for Postgres and MySQL — web UI, CLI, Slack, MCP, BYOK LLM. Schema Guardian sits on migrations. The analyze_migration MCP tool is how coding agents ask us about a change without getting a raw DSN and freelancing.
The architecture is deliberately boring:
- Parse and classify the statement against context — schema, workload, and rules — with deterministic checks. On Postgres,
analyze_migrationreturns a fixed verdict (SAFE/CAUTION/DANGER/FAILS/UNKNOWN), the locks taken per table (anADD FOREIGN KEYlocks the referenced table too), whether the table is rewritten, a coarse duration estimate scaled by live table size, and a safer alternative when one exists. Those rules are verified against a real PostgreSQL, not inferred from docs. MySQL returnsUNKNOWNrather than a guess — we would rather be honest than invent lock semantics we have not proven. The tool is read-only; it never executes the statement. - Surface that as a product gate — GO / NO-GO cards for what we will and will not let through Editor and MCP.
- Only then let the LLM explain what the label means in plain language.
Flip that order and you get what every chat-first “AI DBA” demo produces: a confident essay that slowly talks itself into yes.
Confirmation answers a different question than Guardian. In DBA can run confirmed DDL/DML we unbundled write authority so a DBA can apply careful changes without MANAGE_USERS. Confirmation is “did a human say yes?” Guardian is “is this change dumb against this schema?” You want both. A human yes on a soft story is still a soft story.
What we classify before anyone chats
The list is the kind of thing a senior DBA runs in their head in the first two minutes of a review. We make it a gate, not a vibe.
Lock and rewrite risk. Statements that take heavy locks, rewrite tables, or hold exclusive access longer than a “quiet window” paragraph implies. The model loves “brief.” Production cares about who else is waiting on the same relation while the migration runs.
Money and approximate types. DOUBLE / FLOAT on amounts, rates, tax fields. Classic agent habit on MySQL especially. Binary floating point is not a ledger type. We treat that as a risk class against the change, not as a style note buried in a chat reply. I wrote a longer walkthrough of this pattern when an agent proposed tax columns as DOUBLE — same class of miss, same reason a lint rule alone is not enough: you need the surrounding schema and how those columns get joined and summed.
DROP / TRUNCATE and friends. Hard-blocked in DeepSQL. Not because DBAs never need them. Because when you need them you need a change window and a restore story, not a convenient apply next to “add index.” We never auto-apply irreversible DDL. The product can draft and explain. It does not get to empty or drop on its own.
Missing tenant / entity scope. Unique keys and counters that look fine in isolation and explode once you remember the row is shared across tenants, hotels, accounts, or registrations. One serialization point. One series with gaps. One SELECT … FOR UPDATE that queues the whole platform. A model that only sees the new CREATE TABLE will bless the uniqueness. A review that sees the rest of the schema asks who else issues numbers from what already exists.
Replica-unsafe and “looks local, runs global” patterns. Changes that assume a single primary, ignore how replicas or connection pools behave, or rewrite meaning of existing columns without saying so. Overlapping amount columns. Second counters next to a live invoice series. Nullable percentages with no default and no backfill so NULL in SQL and 0 in the app both look “correct.”
None of that is exotic. Any DBA who has been burned once will recognize the shapes. The point of Guardian is that recognition happens before the model writes the soothing paragraph.
Why deterministic first
LLMs are stochastic explainers. Same statement, different temperature, different day, different “consider a quiet window.” Risk labels that decide whether a change is allowed to proceed through our gates cannot live there.
Deterministic classification means: same statement + same schema context + same rules → same risk class. The GO / NO-GO card is stable. The explanation can vary in tone. The veto cannot.
That is the same architectural instinct as treating session GUCs as ergonomics rather than security — see Session GUCs aren’t a security boundary for AI agents. Defaults that catch accidents are fine. Boundaries that the session (or the chat) can talk past are not boundaries. Policy has to sit where the softener cannot reach it.
MCP is how we keep agents on the right side of that line. Coding agents already draft migrations. Hand them a superuser DSN and they talk past every product gate you built. Point them at analyze_migration and they get our classification and our cards — same gates as the Editor, same blocks, same refusal to auto-apply irreversible DDL. Credentials are dumb. Policies are not.
Context is what makes the label real
A regex that flags DROP is not a DBA. A model prompted with “be careful about locks” is not one either.
Guardian reviews against the whole schema and the queries that actually run — the context layer: schema + workload + rules. That is how “DOUBLE for money” stops being a generic tip and becomes “this column will drag comparisons into approximate arithmetic next to the ledger joins you already have.” That is how a new counter gets compared to the numbering state that already exists instead of being reviewed as a greenfield table.
We started needing this while operating a real production data layer — Stayflexi’s — after coding agents made DDL cheap and review the bottleneck. The high time for relational databases to start thinking essay is the broader framing: agents write; something still has to reason with the live system. Guardian is the migration-shaped piece of that bet.
Honest gap, same as always: DeepSQL is not your HA runbook and not your PITR console. We classify and gate. We do not pretend a NO-GO card replaces backups, change windows, or a second pair of eyes on a true emergency drop.
What the LLM is for
After the label is fixed, narration earns its keep.
Explain why this ALTER is a rewrite on this engine. Show what would turn a NO-GO into a GO — DECIMAL instead of DOUBLE, scope the unique key, retire the old counter, define what amount means before you add two more. Translate risk classes for a developer who has never sat a lock queue at 2 a.m.
That is peer work. Softening a NO-GO into “probably fine” is not.
So the product shape is: Guardian classifies → card is GO or NO-GO → human confirms when writes are allowed → model explains. DBA and Admin share those gates on Editor and MCP. DROP / TRUNCATE stay on the floor. The chat never gets to vote first.
If you want to kick the gate yourself, the OSS build is at github.com/DeepSQLAI/deepsql / deepsql.ai. If you’ve already watched a model talk a bad migration into production, send the blunt version — what it softened, what you wish had refused it first.
Venkat Sakamuri · Founder, DeepSQL · Ex Oracle Core Query Engine · Peer DBA/eng building a self-hosted AI DBA for Postgres & MySQL · venkat@deepsql.ai