Schema injection plus independent verification: the sample schema goes into the prompt so the model uses real columns, and the query it returns is re-checked in the browser for mutation keywords before being marked safe to run. Each clause is explained separately so the logic can be audited rather than trusted.
| customers | id PK, name, email, company, country, plan, created_at |
| subscriptions | id PK, customer_id →customers.id, plan, mrr_cents, status, started_at, canceled_at |
| invoices | id PK, customer_id →customers.id, amount_cents, status, issued_at, paid_at |
| tickets | id PK, customer_id →customers.id, subject, priority, status, opened_at, resolved_at |
| usage_events | id PK, customer_id →customers.id, feature, event_count, occurred_at |
Two things make text-to-SQL usable in production, and neither is the model. First, inject the schema — without it you get plausible queries against columns that don't exist. Second, never trust the output: the prompt forbids writes and the result is independently re-checked for mutation keywords, because a prompt is a request, not a constraint. That belt-and-braces pattern is how we ship LLM-generated queries at all.