docs← Back to article

Markdown for LLMs

Compose facts from two cases

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

Download this articlePlain text ↗
# Compose facts from two cases

## Intention

I want to join selected facts from two cases while keeping their origin.

Composing facts is separate from importing norms.

## Incorrect form and why it stays silent

You cannot overlay a different payload with the same id on top of an HR record.

```text title="Incorrect form"
assert not eligible(entity_ref("urn:recipe:n-package:07:p")) {
    id "assert-eligible-record"; origin case_input;
}
```
When a positive record with the same full StableId is attached, composition fails with LDC-E1360.

## Correct form

The composition stand in `resources/07-compose/` contains a manifest, a lock, and two exported snapshots. They are generated by `resources/generate.py`; no outside bytes are borrowed. Program, snapshot declarations, and case:

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

entity Person;
relation eligible(p: Person);
relation verified(p: Person);
relation granted(p: Person);
rule Grant strict { for p: Person; when eligible(p) and verified(p); then granted(p); }
snapshot HR "snapshots/hr.json";
snapshot Audit "snapshots/audit.json";
case Combined {
    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";
    }
    use HR { record "urn:recipe:n-package:07#assert-eligible-record"; }
    use Audit { record "urn:recipe:n-package:07#assert-verified-record"; }
}
```

## Frozen execution scene

| Facts | Question | Answer |
|---|---|---|
| eligible from HR, verified from Audit | granted(p) | TRUE_ONLY |

First both evaluators compose one case; then the test runner asks both. The table is not replaced by hand-rewritten asserts.

```law
test "composed case yields both premises" {
    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";
        }

    }
    evaluate truth(granted(entity_ref("urn:recipe:n-package:07:p")));
    expect truth_status == TRUE_ONLY;
    expect applied(Grant);
}
```

## Counterfactual

`teaches` adds a negative payload for an existing id in Combined and runs lower-case inside a copy of the pinned package. The expected result is exactly LDC-E1360, not an error about a missing snapshot.

## Boundary

Importing a program does not carry facts. A snapshot supplies only exported records; origin is preserved. Equal ids with equal payloads fold; when payloads differ there is no “last record wins” rule.

## Pitfall

Two payloads of one `StableId` are rejected with LDC-E1360. The scenario below reduces the example to two facts and one conflicting record, keeping both sides of the composition.