docs← Back to article

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.

Download this articlePlain text ↗
# 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.