jonnifyagile agents
jonnify / Agile Agent Workflow / A4 · Spec / A4.5 / A4.5.3 · Always true

A4.5 · Invariants · dive 3

Always true

An invariant says “always”. A check says “for this case”. No finite set of passing checks proves a rule holds for every value — there is always a next value.

An invariant is universally quantified: it claims a property of every value, including values no check has tried. A finite check set samples it. Step a stream of request values on the right and watch the master invariant hold for every one, while a single check holds for only its scenario.

Hold the rule over a value stream · step it

3
request value stream ■ invariant holds (every value stepped) ■ check holds (its one scenario)
Invariant: holds for all 3 values stepped — the web layer called only the facade for every one. Check: holds for 1 — the unknown-id scenario it names. The invariant is the universal rule; the check is one sample of it.

For all, not for one

An invariant is universally quantified. It claims a property of every value the increment can take — including values no test has ever run. “The web layer calls only the Portal facade” is true for the next request, and the one after that, and every request the Portal will ever serve, including users that do not exist yet.

A check is one point. Each Given/When/Then names a single scenario and proves it behaves. Passing checks raise confidence, and that confidence matters — but no count of them closes the universal claim, because the claim is about all values and a finite set names only some. That is why a spec carries invariants as their own named rules, held over every value as the increment runs, separately from the checks that sample them.

for all
An invariant quantifies over every value the increment can take, at all times — including values no check has tried.
a sample
Each check is one point on the rule. A finite set of passing checks raises confidence; it does not close the universal claim.
held, not asserted
An invariant is a rule held against every value as the increment runs — named once, exercised continuously — not a fact asserted from one green scenario.

This is the formal heart of A4.5: an invariant is the “for all” claim, and a check is one “for this” sample of it — the two never collapse into one.

The gap a check set leaves

Add passing checks one at a time. Each covers one more scenario, so the covered-scenario count rises. The master invariant, though, stays unproven by them: a finite set of checks samples the rule, it does not close it. There is always a next request — a value no check named — and the invariant must hold for that one too.

Drag the slider to add checks. The readout reports how many scenarios are covered, and reports that the universal claim is still not closed. The point is not that checks are weak — it is that an invariant is a different, stronger claim, and the spec names it as one so the rule is held over every value, not only the values that happen to be checked.

A check set never closes “for all” · add checks

3
the invariant's domain · every value, ∀ an open region always remains — values no check named ■ covered by a check the field is never filled by a finite set
3 checks pass — 3 scenarios covered. The master invariant still is not proven for all values: a finite check set samples the rule, it does not close it. The next request is a value no check named.

A finite set of passing checks samples a universal rule but never closes it — the next value is always one no check named.

On the Portal: the rule over every request

On the Portal — the learning platform this course builds — the master invariant holds for every request the platform ever serves. F6.1-US5's check — “an unknown user id renders the empty state, a clean 200” — tests one value. The facade is total at , so the empty state holds; but that one passing check is a sample of the universal rule, not a proof of it for all ids.

The closed error set is universal in the same way. Every error value the web layer renders is a %Portal.Error{} whose code is one of the four known kinds, extended only by an explicit no-catch-all mapping. A new error kind without that mapping would break the invariant — whatever the scenario, and whether or not any check happened to cover it.

# f6.1.md — Invariants (the rule over ALL values).
#   F6.1-INV1 (master): the web layer calls only the Portal facade …   → ∀ request

# f6.1.stories.md — one check that samples it.
#   F6.1-US5: unknown user id → renders the empty state, a clean 200.   → ∃ this case
#   Coverage maps it to deliverables D4, D7 — one sample of the rule, not the rule.

The principle

An invariant is a universal claim; a finite set of passing checks samples it but never closes it — so the spec names the invariant as its own rule, held over every value.

On the Portal

The master invariant holds for every request; F6.1-US5's “unknown id → 200” check tests one value — it exercises the rule, it does not prove it for all ids.

An invariant is held over every value as the increment runs; a check is one sample — which is why “always” is a named rule, not an inference from green scenarios.

Recap — the universal rule, sampled

An invariant says “for all”: it claims a property of every value the increment can take, including values no test has run. A finite set of passing checks samples it — the covered-scenario count rises, but the universal claim is never closed, because the next value is always one no check named. So a spec names invariants as their own rules, held over every value, distinct from the checks that exercise them. That is the discipline A4.6 turns into the closure that makes “done” correct by definition.

After A4.5, the next module — A4.6 · Traceability — correct by definition — walks the chain from deliverable to story to check and invariant, closing “done” by a rule. Return to the A4.5 module navigation to continue.

References

Primary sources for the universal rule held continuously over every value, and where it connects in the course.

Sources

Related in this course