The five stages
-
Connect, and let the database prove the role is read-only
Paste a connection string. Before reading anything, LEDAR asks PostgreSQL what the role is permitted to do and shows you the answer. A role the database reports as a superuser is refused outright, with no override, because a promise made by an application about its own behaviour is not evidence.
-
Answer five questions, or skip them
Login, database, payments, file storage, scheduled jobs. Every question offers "I do not know", which is the default, and every step has a "skip all of this, just go and find out" button. For someone who inherited a system, that button is the one most often pressed, and that is expected rather than a failure.
-
The scan starts immediately, without waiting for your answers
Tables, columns, constraints, relationships, row counts and sizes. What you said and what the scan found are then compared, and the differences are brought back to you: "you said you use Stripe — I can see a stripe_customer_id column on public.users. Is that the one?"
-
A map is built, and the guesses are marked as guesses
Foreign keys the database declares are one tier. Links inferred from column names are a second, lower tier. A guessed link that is then checked by counting real values is promoted to a third tier and carries the count. The tiers are visible beside every hop, so a route built on an assumption never looks like a route built on a constraint.
-
Ask a question in your own words
Type what a customer told you: "I paid but no order appeared." LEDAR walks the map from the subject to the related records and answers with a timeline — what happened, when, where the trail breaks, and how many other cases show the same break today.
Why a map, and not a fresh scan every time
Rescanning a real database for every question is slow enough that people stop asking. The map is built once during the scan and costs no extra queries — the foreign keys and column names were already read for another purpose.
It also makes the answer explainable. A timeline that came from walking customer → payment → rental can show you those three hops and the tier of each one. An answer assembled from a fresh scan each time has nothing to show you.
| Tier | What it means | Where it comes from |
|---|---|---|
| declared | The database enforces this link | A foreign key constraint in the catalogue |
| measured | Values were counted and they line up | Reading real values and recording the match rate |
| guessed | The names suggest a link; nothing checked it | Column naming conventions only |
What the answer looks like
Not a list of findings. A sequence, ordered by the clock rather than by the route that was walked — which matters, because the route order and the time order often disagree, and a timeline printed in route order looks plausible and is wrong.
Payment recorded 28 January. Rental never reached. One other subject shows the same break.
The shape of an answer, from a real run against the Pagila sample
- A step that did not happen is reported as "did not arrive", not as zero. Those are different facts and the product refuses to blur them.
- A route the budget could not afford to walk is named as unwalked, not silently dropped.
- The count of other subjects showing the same break is there so you can tell one incident from a pattern.
What this costs to run
Scanning is free — it is your database and your machine. Asking a question costs whatever your model provider charges for the tokens. Three questions against a real schema, measured on the wire, came to under a cent in total across 3 turns.
The schema menu sent for a large database was the binding constraint rather than the price: an early version tried to send a 2 MB menu for a 368-table schema, which does not fit in a context window at any price. Splitting it into two rounds brought that to about a fortieth of the size.