Markdown for LLMs
Exercise 19. A digital receipt
The source Markdown for this article. Copy it into your assistant or download it as a text file.
# Exercise 19. A digital receipt
An exercise for the [evidence](/tutorials/evidence/) page. The page's
policy admits the issue desk's paper receipt. The archive launched
a portal, and returns are now confirmed also by the portal's digital
receipt, verified by the same registry.
**Setup.** Extend the policy: a "digital receipt" document issued by the
portal and verified by the registry is admitted as return support. The
same digital receipt issued by the issue desk is not admitted: each
document kind has its own publisher.
**Hint.** A document's soundness and a support's admission are two
different rules, with the publisher in both conditions. A new document
kind means a new soundness rule and a new admission rule, not editing
the old ones.
Below is the solution. Try it yourself first.
## Solution
The header and norm from the page, transport relations unchanged:
```law
language "law.core" version "0.2";
package tutorial.archive version "0.11.1";
namespace "urn:law:tutorial:archive";
entity Person;
entity ReturnReceipt;
relation document_lent(p: Person) kind empirical;
relation document_returned(p: Person) kind empirical;
relation loan_closed(p: Person) kind institutional;
rule LoanClosed strict {
for p: Person;
when document_lent(p) and document_returned(p);
then loan_closed(p);
}
relation ev_edge(edge: Text, document: Text, link: Text) kind empirical;
relation ev_issuer(document: Text, issuer: Text) kind empirical;
relation ev_available(document: Text) kind empirical;
relation ev_authentic(document: Text, verifier: Text, outcome: Text) kind empirical;
relation doc_kind(document: Text, kind: Text) kind empirical;
relation doc_reader(document: Text, reader: Person) kind empirical;
relation edge_reader(edge: Text, reader: Person) kind empirical;
relation edge_is_return(edge: Text) kind empirical;
relation sound_receipt(document: Text) kind institutional;
relation sound_portal_receipt(document: Text) kind institutional;
relation accepted_support(edge: Text) kind institutional;
const ARCHIVE_DESK: Text = "urn:tutorial:archive:reading-desk";
const ARCHIVE_PORTAL: Text = "urn:tutorial:archive:portal";
const ARCHIVE_REGISTRY: Text = "urn:tutorial:archive:registry";
```
The page's rules plus a portal pair:
```law
rule SoundReceipt strict {
for d: Text;
when ev_available(d)
and ev_issuer(d, ARCHIVE_DESK)
and ev_authentic(d, ARCHIVE_REGISTRY, "verified");
then sound_receipt(d);
}
rule AcceptReturnReceipt strict {
for edge: Text;
for d: Text;
for p: Person;
when ev_edge(edge, d, "supports")
and edge_is_return(edge)
and edge_reader(edge, p)
and sound_receipt(d)
and doc_kind(d, "return_receipt")
and doc_reader(d, p);
then accepted_support(edge);
}
rule SoundPortalReceipt strict {
for d: Text;
when ev_available(d)
and ev_issuer(d, ARCHIVE_PORTAL)
and ev_authentic(d, ARCHIVE_REGISTRY, "verified");
then sound_portal_receipt(d);
}
rule AcceptDigitalReceipt strict {
for edge: Text;
for d: Text;
for p: Person;
when ev_edge(edge, d, "supports")
and edge_is_return(edge)
and edge_reader(edge, p)
and sound_portal_receipt(d)
and doc_kind(d, "digital_receipt")
and doc_reader(d, p);
then accepted_support(edge);
}
```
The policy lists all four rules:
```law
evidence policy ArchiveReturnEvidence {
profile "law.core.evidence-policy/0.1";
accepts accepted_support;
protects document_returned;
input edge ev_edge;
input issuer ev_issuer;
input available ev_available;
input authentic ev_authentic;
field kind doc_kind;
field reader doc_reader;
arg 0 edge_reader;
target document_returned edge_is_return;
rule SoundReceipt, AcceptReturnReceipt, SoundPortalReceipt, AcceptDigitalReceipt;
}
```
The first test is the portal's digital receipt:
```law
test "электронная квитанция портала проверена реестром — возврат установлен" {
given {
context {
decision_time @2026-04-10T09:00:00+05:00;
knowledge_time @2026-04-10T09:00:00+05:00;
legal_time @2026-04-10;
timezone "Asia/Almaty";
evidence_policy ArchiveReturnEvidence;
}
assert document_lent(entity_ref("urn:tutorial:ivanova")) {
id "assert-lent";
origin case_input;
}
evidence ERECEIPT: ReturnReceipt {
id "doc-ereceipt";
status verified;
issuer "urn:tutorial:archive:portal";
observed_at @2026-04-02T15:00:00+05:00;
recorded_at @2026-04-02T15:00:05+05:00;
valid [@2026-04-02, infinity);
content_hash "sha256:2222222222222222222222222222222222222222222222222222222222222222";
kind "digital_receipt";
reader entity_ref("urn:tutorial:ivanova");
}
verification VERECEIPT {
evidence ERECEIPT;
document_hash "sha256:2222222222222222222222222222222222222222222222222222222222222222";
verifier "urn:tutorial:archive:registry";
outcome verified;
recorded @2026-04-03T10:00:00+05:00;
}
support ERECEIPT supports document_returned(entity_ref("urn:tutorial:ivanova"));
}
evaluate truth(document_returned(entity_ref("urn:tutorial:ivanova")));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
}
```
The test name reads: "The portal's digital receipt is registry-verified — return is established."
## Check
Two tests in `tests/49-exercise-evidence.lawtest`: the portal receipt
admitted; the same receipt with the "issue desk" publisher not admitted,
return not established. The second test is the task's point: a document
kind and its publisher are linked by the soundness rule, and a
right-kind document from a wrong publisher is declined silently, without
error.
What the exercise teaches. An evidence policy does not "trust the
publisher" at large: it lists rules, each binding a document kind to who
may issue and who may verify it. Extending a policy means adding rules
and entering them in the list, not loosening the old ones' conditions.