BUILDING Parts of this page describe what is not built yet, and each says so.
The gates
A change set that carries SQL passes four gates before it can be submitted or approved: Dialect, Catalog, Dry run and Differential. A gate reads the statement and says what it found. The verdict is the control plane's, never the browser's, and the rules are the same for every author.
What the gates are
A change set gets gates when one of its items carries SQL: a pipeline asset's SQL, a view's SQL or a semantic model's expressions. A change set with no SQL has no gates, and its page says so rather than showing four passes.
The four run in this order, and each waits for the one before it. When a gate fails, the ones behind it read not run and name the gate they wait on.
A statement the gates could not read is named, and is never passed over: a SQL file the branch does not hold, a path that leaves the pipeline's folder, an overlay of another environment. The Dialect gate reads not run and says which.
What each gate checks
| Gate | It asks | The evidence it shows |
|---|---|---|
| Dialect | Does every statement parse in the restricted authoring dialect? A construct outside it is refused, never silently rewritten. | For each refusal: the file, the line and the column, the construct, the rule, and what to write instead. |
| Catalog | Does every table the statement reads resolve to a declared table of the environment, as its author may see it? Does every column it reads exist in that table's declared schema? Do the output columns match the target table's by name and, where a type can be stated, by a compatible type? | The tables that resolved and, where the plane reports one, the snapshot they resolved against. For what did not: the file, the line, the column and the name. A table its author may not see reads exactly like a table that does not exist. |
| Dry run | Does the statement run, on a bounded sample of its inputs, on the plane? | Counts only: the rows read from each input and the snapshot, the rows out of each model, the nulls in each output column, the error class if it failed, the engine and its version, and how long it took. No row and no value leaves your plane. |
| Differential | Do the engines the router may send this asset to on this plane agree on the result? | For each model on each engine: the rows out and a digest of the result, and whether they matched. |
Column types are compared by family, never by precision, scale or length, and only where both are stated. A widening conversion, an integer into a long for instance, is compatible; a narrowing one, a long into an integer column, is a mismatch and fails the gate. A type the parser cannot state is not compared, so a mismatch that is not proven never fails it.
Which gates run on your plane depends on its release. A gate your plane's release cannot run reads not run with the reason, and never reads as passed.
What a gate can say
- passed: it ran, and the statement is what it asks for.
- failed: it ran, and the statement is not. It names what, with the evidence above.
- could not run: it started and could not finish, for instance because the parser or the catalog could not be reached. That says nothing about your SQL. It is a fault and never a pass, it stops a submit and an approval, and trying again can clear it.
- running: it has not answered. Trying again can clear it.
- not run: it did not run, and says why: it waits on a gate before it, or your plane's release does not run it, or the statement could not be read.
At submit and approve
The control plane refuses a submit and an approval while any gate is running, has failed or could not run. The refusal names the gate in fixed wording that holds no table, statement or file.
Submit stays available beside a refusal: pressing it asks the control plane again, so a failure you fixed elsewhere does not hold Submit off. Approve is off while the control plane's verdict says a gate blocks it, and the sentence beside the button is that verdict. The console never works a verdict out from the checklist; it shows the one the control plane gave.
No role, step-up or setting waives a gate that ran and failed or could not run. A gate that did not run is shown with its reason, never as a pass, and whether it stops a submit is the control plane's rule, said in the sentence it gives.
Why an agent gets no shortcut
An agent's proposal is a change set, so it goes through the same two doors as anyone's. Submit and Approve are refused on the same verdicts with the same sentences, and no gate is looser for an agent's SQL than for a person's. A person decides: nothing is submitted, approved or applied on an agent's behalf.
The Catalog gate reads the catalog as the change set's author may see it. A table the author cannot see reads as one that does not exist, so a statement cannot learn from a gate what its author could not already see.
What “not compared” means
The Differential compares the result of an asset across the engines the router may send it to on your plane. The number of engines is whatever your plane runs. With two or more, the sample is run on each and the results are compared. On a plane that runs one engine there is nothing to compare, and the gate says so:
Not compared: one engine is deployed, so there is nothing to compare against.
That is a gate that did not run, not a pass. The Gates tab draws it as not run,
rl gates does not count it against the change set, and it never stops a submit or
an approval; nothing waits on it either. The same gate can also read not run because
the dry run it waits on did not run, which is a different reason and is said in its own words.
From the command line
rl gates prints each gate of a change set, its state and the control plane's
sentence, with the evidence beneath it. -o json prints the control plane's
answer as it came. It checks nothing itself: the verdict is the control plane's, and a script
reads it from the exit code.
# Exit 0: every gate passed. A Differential that reads "not run" on a plane with one engine does not stop that.
# Exit 1: a gate failed or could not run.
# Exit 2: nothing was decided, and that is not a pass: a gate did not run, no gate was reported, or the call could not be made.
rl gates cs_01J7K4Q3X9M2T8V5R1P6WN
A 2 is never a pass. A change set whose dry run and differential did not run exits 2, because nothing was decided for it, and so does one for which no gate was reported.
SQL pushed outside a change set
The repository is yours, and a push straight to its branch does not pass through a submit, so these gates cannot stop it. After the next sync, the same gates judge the SQL of a pipeline or view whose commit no change set wrote, and the result is kept beside the resource and shown on its page. It warns and blocks nothing. To prevent a direct push, protect the branch in your repository host: that is the only control that can.