# Validation gates

> This section covers the handoff gate that closes every node.

Page: PAG · Validation
Canonical: https://banes-lab.com/pag/validation#validation-gates

This section is stop 50 of 102 in the learning route. Previous: [35 - Coverage is derived](https://banes-lab.com/disciplined-methodology/verify/coverage-is-derived.md). Next: [02 - Limits](https://banes-lab.com/pag/validation/limitations.md). It builds on [04 - Node design](https://banes-lab.com/pag/guide/node-design.md), [29 - Unknown is not pass](https://banes-lab.com/disciplined-methodology/verify/unknown-is-not-pass.md).

This section covers the handoff gate that closes every node. A gate holds three to five checks, each compared against the node's output and each carrying the evidence that decided it and the set it was measured over, as shown in [A1·a a gate](https://banes-lab.com/pag/validation#validation-gates-panel-a) and [A1·d at the boundary](https://banes-lab.com/pag/validation#validation-gates-panel-d). Its result line has three arms, which send a pass to the next node, a failure to the node that owns the repair, and an unknown to blocked, as shown in [A1·b verdict and domain](https://banes-lab.com/pag/validation#validation-gates-panel-b). A judgement is rewritten as a comparison in [A1·c judgement or check](https://banes-lab.com/pag/validation#validation-gates-panel-c), and [A1·e who decides](https://banes-lab.com/pag/validation#validation-gates-panel-e) shows the difference between the two. The gate is the verify stage of [the loop](https://banes-lab.com/disciplined-methodology/start/the-loop.md), and its third arm is the rule described in [unknown is not pass](https://banes-lab.com/disciplined-methodology/verify/unknown-is-not-pass.md).

### Checkable, with evidence

A vague check passes whatever the reader is inclined to pass, and a check with no domain passes over nothing. A gate reads that the data looks good, the model reports the gate passed because the data looked good to it, and the next node consumes records that never matched the schema. A condition that compares an artifact to a value gives the model, the developer and a script the same answer, while a condition that asks whether something looks right can give each of them a different one, and a verdict with no domain cannot say what it was true of.

For this reason a check is a comparison against the node's output, with its evidence, its population and its repair owner beside it, and unknown is a verdict of its own. The evidence is written beside each check, together with the set and the count measured over it wherever a check ranges over a set, rather than the verdict standing alone, so a green reads as coverage and not as silence. In practice, every node closes on a gate of three to five checks, each written as a comparison against the node's output. A hard assertion and a prerequisite are marked as such, and where the node writes, the condition under which it refuses is named before the write. The result line carries all three arms, so a failed check names what was found and routes to the earliest node that can supply the missing evidence, and an unmeasured claim routes to blocked rather than reading as pass. The next node's contract reads exactly the output the gate confirmed.

To check this, rewrite each check as a comparison and name the artifact on each side and the set it ranged over. A check with no artifact on one side is a judgement and a check with no set is a verdict about nothing, so in either case the gate's green does not say whether the node closed. A gate checks outcomes, never confidence. How sure the model is, or whether it understood, is not observable from outside, so a check about either belongs under [limits](https://banes-lab.com/pag/validation/limitations.md) rather than in a gate.

The count is bounded on both sides. With fewer than three checks the gate shows that something ran rather than that a unit closed, and with more than five the node holds several decisions and is several nodes. A gate that passes and a gate that was never evaluated produce the same silence, and the evidence beside each check tells them apart. A gate that passed over an empty set produces the same silence with a number attached, and the population beside the verdict exposes it. The result line applies [fail fast](https://banes-lab.com/records/arch/fail-fast.md) at the node boundary, as described for a whole system in [fail at the boundary](https://banes-lab.com/disciplined-methodology/build/fail-at-the-boundary.md), and its owner is the earliest node that can supply what the check lacked, so a repair invalidates forward from there and nothing earlier is redone.

The refusal line stops the node before an irreversible write, because that is the only moment a refusal costs nothing. The standing line names the surfaces that moved beneath the verdict, and a non-empty moved set withdraws the verdict's standing to be quoted without touching the verdict itself, as derived in [a report, not a checkbox](https://banes-lab.com/disciplined-methodology/verify/a-report-not-a-checkbox.md). The markers form a closed set with one meaning each, marking a check, a hard assertion, or a prerequisite that a prior node must have yielded. Severity is not a marker, because severity orders repairs among failures and never softens a verdict, and there is no tier between fail and pass.

A1·a a gate

```pag
HANDOFF GATE (evidence-bearing):
rule_id: "<NODE NAME>"   yields: <shape>
[check] <file> exists at <path>                    (evidence: the listing that shows it)
[check] <settings> conforms to <schema>            (evidence: the validator's report) over: <settings files> measured: <conforming> / <files>
[check] every <dependency> in <settings> resolves  (evidence: the resolution log)
ASSERT <count> above 0
REQUIRE <prior-node>.<output>
refuse: <destination> changed since it was read before PERSIST_ARTIFACT
standing: moved-set <the surfaces re-read since the node began>
result: pass → NODE <n+1> | <which check failed, what was found> → REPAIR (owner: <the earliest node that can supply the evidence>) | unknown → BLOCKED
```

A1·b verdict and domain

```pag
# a verdict with no domain · passed over what?
[check] every settings file conforms                (evidence: the validator's report)

# a verdict beside its domain · zero of zero is not evidence
[check] every settings file conforms                (evidence: the validator's report) over: <settings files> measured: 12 / 12
[check] every settings file conforms                (evidence: the validator's report) over: <settings files> measured: 0 / 0    # empty · the gate fails

# the three verdicts · unknown is routed, never absorbed into pass
result: pass → NODE 4 | schema mismatch → REPAIR (owner: NODE 2) | unknown → BLOCKED
```

A1·c judgement or check

```pag
# a judgement · its truth depends on the reader
[check] the email looks valid
[check] the data is good
[check] everything worked

# a condition · true or false against the artifact, with what settles it and what it ranged over
[check] <record>.<email> matches <pattern>          (evidence: the match returned true)
[check] <records> is non-empty                       (evidence: a count above zero)
[check] every required field present in <record>    (evidence: no missing field named) over: <records> measured: <complete> / <records>
[check] <output>.<count> equals <input>.<count>      (evidence: the two numbers)
```

A1·d at the boundary

```mermaid
flowchart TB
node["A node yields its output"]
conditions["Three to five checks · each against the output"]
evidence["Each carries the evidence that decided it and the set it ranged over"]
refuse["A write is refused before it lands when its condition holds"]
verdict{"pass · fail · unknown"}
next["The next node's contract reads exactly that output"]
action["The result line · which check, what was found, which node owns the repair"]
blocked["BLOCKED · the answer is owed from outside the run"]
node --> conditions --> evidence --> refuse --> verdict
verdict -- pass --> next
verdict -- fail --> action
verdict -- unknown --> blocked
```

A1·e who decides

```mermaid
flowchart LR
judgement["looks valid · a judgement"]
who["Its truth depends on the reader"]
condition["matches the pattern · a condition"]
what["True or false against the artifact"]
domain["Over a declared set · n of N"]
judgement --> who
condition --> what --> domain
```

## Links to

- [The loop](https://banes-lab.com/disciplined-methodology/start/the-loop.md)
- [Unknown is not pass](https://banes-lab.com/disciplined-methodology/verify/unknown-is-not-pass.md)
- [Limits](https://banes-lab.com/pag/validation/limitations.md)
- [Fail Fast](https://banes-lab.com/records/arch/fail-fast.md)
- [Fail at the boundary](https://banes-lab.com/disciplined-methodology/build/fail-at-the-boundary.md)
- [A report, not a checkbox](https://banes-lab.com/disciplined-methodology/verify/a-report-not-a-checkbox.md)

## Linked from

- [Template families](https://banes-lab.com/pag/templates/templates-families.md)
- [A report, not a checkbox](https://banes-lab.com/disciplined-methodology/verify/a-report-not-a-checkbox.md)
