Markdown for LLMs
Distinguish an enum member from a data variant
The source Markdown for this article. Copy it into your assistant or download it as a text file.
# Distinguish an enum member from a data variant
## Intent
I want to keep enum identity and a variant’s payload.
## Wrong form and why it stays silent
```law title="Incorrect form"
enum Kind { Local = "Local"; Foreign; }
```
An enum member is its own qualified identity, not a string. A variant with fields is a different data device; cross-package qualification of members is checked by a separate witness below.
## Correct form
```law
language "law.core" version "0.2";
package recipes.g.r10 version "0.1.0";
namespace "urn:recipe:g-concepts:10";
entity Person;
enum Kind { Local; Foreign; }
type Identifier = NationalId { value: Text; } | ForeignId { scheme: Text; value: Text; };
relation category(p: Person, k: Kind);
relation identification(p: Person, id: Identifier);
relation eligible(p: Person);
rule LocalOnly strict { for p: Person; when category(p, Local); then eligible(p); }
```
## Frozen execution scene
| Facts on 13.09.2026 | Question | Answer |
|---|---|---|
| local category | `truth(eligible(entity_ref("urn:recipe:g-concepts:10:p")))` | `truth_status == TRUE_ONLY;` / `COMPUTED` |
| other category | `truth(eligible(entity_ref("urn:recipe:g-concepts:10:p")))` | `truth_status == NEITHER;` / `COMPUTED` |
| variant with payload | `truth(identification(entity_ref("urn:recipe:g-concepts:10:p"), NationalId { value: "123" }))` | `truth_status == TRUE_ONLY;` / `COMPUTED` |
```law
test "local category qualifies" {
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 category(entity_ref("urn:recipe:g-concepts:10:p"), Local);
}
evaluate truth(eligible(entity_ref("urn:recipe:g-concepts:10:p")));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
}
```
```law
test "foreign category stays unknown" {
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 category(entity_ref("urn:recipe:g-concepts:10:p"), Foreign);
}
evaluate truth(eligible(entity_ref("urn:recipe:g-concepts:10:p")));
expect truth_status == NEITHER;
expect evaluation_status == COMPUTED;
}
```
```law
test "loaded variant identifies" {
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 identification(entity_ref("urn:recipe:g-concepts:10:p"), NationalId { value: "123" });
}
evaluate truth(identification(entity_ref("urn:recipe:g-concepts:10:p"), NationalId { value: "123" }));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
}
```
Two synthetic packages: the dependency is pinned by a generated law.lock. In the correct consumer the type and the member are qualified. For the second test only `kind == recipes.g.owner10::first` is replaced with `kind == first`: lowering succeeds without an error, but this is a LocalKind member, and the comparison yields TYPE_ERROR.
```law
language "law.core" version "0.2";
package recipes.g.owner10 version "0.1.0";
namespace "urn:recipe:g-concepts:10:owner";
pub enum ForeignKind { first; second; }
```
```law
language "law.core" version "0.2";
package recipes.g.consumer10 version "0.1.0";
namespace "urn:recipe:g-concepts:10:consumer";
import recipes.g.owner10 version "0.1.0";
entity Person;
enum LocalKind { first; other; }
relation chosen(p: Person, kind: recipes.g.owner10::ForeignKind);
relation eligible(p: Person);
rule Choose strict { for p: Person; for kind: recipes.g.owner10::ForeignKind;
when chosen(p, kind) and kind == recipes.g.owner10::first;
then eligible(p);
}
```
```law
language "law.core" version "0.2";
package recipes.g.consumer10 version "0.1.0";
namespace "urn:recipe:g-concepts:10:consumer";
test "imported member qualifies" {
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 chosen(entity_ref("urn:recipe:g-concepts:10:p"), recipes.g.owner10::first); }
evaluate truth(eligible(entity_ref("urn:recipe:g-concepts:10:p")));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
}
```
```law
language "law.core" version "0.2";
package recipes.g.consumer10 version "0.1.0";
namespace "urn:recipe:g-concepts:10:consumer";
test "bare member fails comparison" {
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 chosen(entity_ref("urn:recipe:g-concepts:10:p"), recipes.g.owner10::first); }
evaluate truth(eligible(entity_ref("urn:recipe:g-concepts:10:p")));
expect truth_status == NEITHER;
expect issue(TYPE_ERROR);
expect evaluation_status == TYPE_ERROR;
}
```
```python
>>> import runpy
>>> check = runpy.run_path("docs/recipes/g-concepts/resources/check.py")
>>> check["check_import"]()
'Г10: квалифицированный член TRUE_ONLY; голый член TYPE_ERROR; lawc = lawref'
```
## Counterfactual
Mutation `enum Kind { Local; Foreign; }` → `enum Kind { Local = "Local"; Foreign; }`: LDC-E0206.
## Boundary
A bare member name is resolved in the current package. In an importing package pkg::Member is required; qualifying the type does not qualify each value for the author.