# 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.