docs← Back to article

Markdown for LLMs

Check a property on a finite domain

The source Markdown for this article. Copy it into your assistant or download it as a text file.

Download this articlePlain text ↗
# Check a property on a finite domain

## Intention

I want to check that every element of the presented domain gets the expected conclusion.

The check runs over a finite domain; act goals use the same property form.

## Incorrect form and why it stays silent

A premise does not replace an expectation about the conclusion.

```law title="Incorrect form"
property AllRegistered {
    forall p in collect x: Person where eligible(x);
    expect eligible(p);
}
```
This checks the selection condition and stays silent on whether registered was obtained. Another incorrect form is `forall p in GeneratedPeople;`: an arbitrary generator is not declared here and does not replace a finite collect; that is exactly the mutation pinned by teaches.

## Correct form

The property reads the registered head. The collect domain is finite; there is no random generator and no seed here.

```law
language "law.core" version "0.2";
package recipes.n.r12 version "0.1.0";
namespace "urn:recipe:n-package:12";

entity Person;
relation eligible(p: Person);
relation complete(p: Person);
relation registered(p: Person);
rule Register strict {
    for p: Person;
    when eligible(p) and complete(p);
    then registered(p);
}
```

## Frozen execution scene

| Facts | Question | Answer |
|---|---|---|
| eligible(p), complete(p) | AllRegistered | PASS, domain 1 |
| eligible(p), no complete(p) | MissingRegistered | FAIL, counterexample p |
| Same incomplete input | Incorrect VacuousRegistration with expect eligible(p) | PASS |

```law
test "full input sustains property" {
    given {
        context {
            legal_time @2026-09-13;
            decision_time @2026-09-13T09:00:00+05:00;
            knowledge_time @2026-09-13T09:00:00+05:00;
            timezone "Asia/Almaty";
        }
        assert eligible(entity_ref("urn:recipe:n-package:12:p"));
        assert complete(entity_ref("urn:recipe:n-package:12:p"));
    }
    evaluate truth(registered(entity_ref("urn:recipe:n-package:12:p")));
    expect truth_status == TRUE_ONLY;
}

property AllRegistered {
    forall p in collect x: Person where eligible(x);
    expect registered(p);
}
```

```law
test "missing output counts as counterexample" {
    given {
        context {
            legal_time @2026-09-13;
            decision_time @2026-09-13T09:00:00+05:00;
            knowledge_time @2026-09-13T09:00:00+05:00;
            timezone "Asia/Almaty";
        }
        assert eligible(entity_ref("urn:recipe:n-package:12:p"));
    }
    evaluate truth(registered(entity_ref("urn:recipe:n-package:12:p")));
    expect truth_status == NEITHER;
}

property MissingRegistered {
    forall p in collect x: Person where eligible(x);
    expect registered(p);
}
```

```law
test "broken property checks only premise" {
    given {
        context {
            legal_time @2026-09-13;
            decision_time @2026-09-13T09:00:00+05:00;
            knowledge_time @2026-09-13T09:00:00+05:00;
            timezone "Asia/Almaty";
        }
        assert eligible(entity_ref("urn:recipe:n-package:12:p"));
    }
    evaluate truth(registered(entity_ref("urn:recipe:n-package:12:p")));
    expect truth_status == NEITHER;
}

property VacuousRegistration {
    forall p in collect x: Person where eligible(x);
    expect eligible(p);
}
```

## Counterfactual

The second scene leaves an element in the domain without a registered conclusion: the correct property yields FAIL. `teaches` replaces the finite collect with an undefined generator and requires a lowering rejection, not a fictitious empty run.

## Boundary

An act goal additionally carries a basis on a source fragment; across legal orders it is goals, not rules, that are checked. A seed is needed only by a generator, which this finite domain does not use. A property cannot be declared proven on an empty domain.

## Pitfall

A property once wrongly reported success on a resident without an age, because negation did not see the unknown. The fix is a separate not_known branch; the second scene checks exactly the absence of a conclusion.