Safe by design
A language model is good at reading a question and bad at being a guarantee. Fidara uses the model to understand and uses code for everything that must be exactly right. Each entry gives the decision, the reason, what code does in place of the model, and what it rules out.
In short
- The model reads the question and writes a plan; code checks it, applies scope and builds the SQL.
- Your app keeps authentication, credentials and row-scope rules; the model never types a number into a file.
- When a name or row is unclear, Fidara asks; writes are held for approval and read back.
The model plans, code executes
The model writes an IR, not SQL
- Decision
- The model writes the question as a structured JSON query plan, the intermediate representation (IR). It never sees or writes SQL. Fidara validates the plan, critiques it and emits parameterized SQL with code.
- Why
- If the model writes the SQL, row isolation is whatever it emitted that time, and "usually correct" is not a security property. SQL is also not one language: engines disagree, often by returning a wrong number instead of an error. With an IR, each rule is fixed once per engine. Validation runs before anything executes, and the plan is a readable audit trail.
- Code does
- Checks that every table and column exists, that joins connect and match the foreign keys the catalogue declares, that output names are unique, and that a join does not multiply a sum (the fan-out check). Then the emitter builds a parameterized
SELECT. Values are bound parameters.
- Rules out
- Model-written SQL reaching your app. Prompts that teach the model each engine's quirks. Writing from the query path:
INSERT, UPDATE, DELETE and DROP cannot come out of the emitter, whatever the model produces, and SQL injection through the question is structurally ruled out.
LimitsOne exception, inside Deep Research only: to combine results it has already fetched, the research model may write a read-only DuckDB SELECT over those rows. The rows were fetched through the path above, in the user's scope, and that query never reaches your app's database.
One rule per database engine, written once
- Decision
- Each engine's rules live in an engine profile, written once and tested on the real engine.
- Why
- Many engine differences give a different number with no error. Fixing each once means every question inherits the fix.
- Code does
- Applies the profile in the emitter. For example, a bare standard deviation is the population formula on MariaDB and the sample formula on PostgreSQL, and the emitter always asks for the sample formula.
- Rules out
- A model that has to know the exact engine and version on every question and never slip.
The plan cache replays code, not model output
- Decision
- On a cache hit the model is skipped. The stored IR goes straight to the emitter.
- Why
- The same question then costs no model call, and cannot leak one user's scope to another.
- Code does
- Stores only plans that were built without retries. The scope is never stored with a plan and is injected again on every run. A plan is never replayed against a different catalogue or semantics overlay: a fingerprint of both must match.
- Rules out
- Replaying a stored scope. Replaying a plan against a changed catalogue.
The local engine: the same exact calculation, wherever the data lives
- Decision
- The model plays no part in how a calculation runs. Each plan is split in two stages.
- Why
- Scope is applied only in stage one, so stage two can never see more than the user could fetch. A result over the row cap is never presented as complete: the answer says the question needs too many rows and offers to narrow it.
- Code does
- Stage one runs on your app's database: the scoped fetch, always, and every aggregate that database can do. Stage two runs in DuckDB inside the Fidara process, over the rows stage one returned: percentiles, correlation, window functions and similar, where the database cannot. Money travels as exact decimals. DuckDB runs with file, network and extension access turned off.
- Rules out
- A calculation that runs on more rows than the user may fetch. An incomplete result presented as complete.
LimitsThe local engine and its differential tests (SQLite, PostgreSQL, MariaDB) are built. A general guarantee that every supported database gives the same answer is still being proven; today the databases agree where the engine profiles are tested. The shared library of business functions such as growth rates and fiscal periods is not built. The row-cap answer is unit-tested but has not been checked live.