Markdown for LLMs
Money and a rate from a snapshot
The source Markdown for this article. Copy it into your assistant or download it as a text file.
# Money and a rate from a snapshot
## Intention
I want to convert a foreign-currency amount at a rate for an explicitly supplied date.
An external indicator requires a snapshot — see [Read an external limit from a snapshot](/recipes/n-package/external-snapshot/). This scene applies the same contract to a Money rate on a date.
## Incorrect form and why it stays silent
```law title="Incorrect form"
external snapshot function Rate(on: Date) -> Money { capability "recipe.fx/1"; }
```
A function without snapshot_from does not pin a rate source. Money / Money of one currency yields a share, multiplied by the price of one USD in KZT; adding currencies directly is forbidden.
## Correct form
```law
language "law.core" version "0.2";
package recipes.l.r04 version "0.1.0";
namespace "urn:recipe:l-calc:04";
external snapshot function Rate(on: Date) -> Money {
capability "recipe.fx/1";
snapshot_from context.fx;
}
relation dollars(p: Text, amount: Money, on: Date);
relation tenge(p: Text, amount: Money);
rule Exchange strict {
for p: Text; for amount: Money; for on: Date;
when dollars(p, amount, on);
then tenge(p, (amount / 1 USD) * Rate(on));
}
```
## Frozen execution scene
| Facts and choice | Question | Answer |
|---|---|---|
| 1. 10 USD at 490 KZT | `truth(tenge("invoice", 4900 KZT))` | `TRUE_ONLY` / `COMPUTED` |
| 2. 10 USD at the next day's rate 495 KZT | `truth(tenge("invoice", 4950 KZT))` | `TRUE_ONLY` / `COMPUTED` |
| 3. snapshot not presented | `truth(tenge("invoice", 4950 KZT))` | `NEITHER` / `EXTERNAL_UNAVAILABLE` |
```law
test "ten dollars at the dated rate" {
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 dollars("invoice", 10 USD, @2026-09-12);
}
evaluate truth(tenge("invoice", 4900 KZT));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
}
```
```law
test "ten dollars at next day rate" {
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 dollars("invoice", 10 USD, @2026-09-13);
}
evaluate truth(tenge("invoice", 4950 KZT));
expect truth_status == TRUE_ONLY;
expect evaluation_status == COMPUTED;
}
```
```law
test "snapshot not presented" {
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 dollars("invoice", 10 USD, @2026-09-13);
}
evaluate truth(tenge("invoice", 4950 KZT));
expect truth_status == NEITHER;
expect evaluation_status == EXTERNAL_UNAVAILABLE;
expect issue(EXTERNAL_SNAPSHOT_MISSING);
}
```
The teaching snapshot is pinned by a semantic hash; [resource bytes](https://github.com/arxohq/law/blob/master/docs/recipes/l-calc/resources/04-fx.json):
```json
{
"schemaVersion": "law.core.external-snapshot/0.1",
"id": "urn:recipe:l-calc:04:fx",
"capability": "recipe.fx/1",
"snapshotBinding": "context.fx",
"calls": [
{
"symbol": "urn:recipe:l-calc:04#Rate",
"args": [
{
"kind": "value",
"type": {
"name": "urn:law:std#Date"
},
"value": "2026-09-12"
}
],
"result": {
"kind": "value",
"type": {
"name": "urn:law:std#Money"
},
"value": "490",
"currency": "KZT"
}
},
{
"symbol": "urn:recipe:l-calc:04#Rate",
"args": [
{
"kind": "value",
"type": {
"name": "urn:law:std#Date"
},
"value": "2026-09-13"
}
],
"result": {
"kind": "value",
"type": {
"name": "urn:law:std#Money"
},
"value": "495",
"currency": "KZT"
}
}
],
"contentHash": "sha256:61f90adf1bb21fea0eec3bd638ed536cac7b31db8916e13f890b97b728137704"
}
```
## Counterfactual
Mutation: ` snapshot_from context.fx;` → ``; expected `LDC-E1305`. Additional counterfactuals are shown as separate table rows.
## Boundary
The snapshot is instructional, not an NBK rate. The input currency tag, the date and the rate source belong to the rule. A missing rate is not a zero price; HTTP is not called at evaluation time. The snapshot envelope carries a schema version: without it the request is refused before evaluation.
## Pitfall
Without a presented snapshot there is no rate and no zero price: the question stays Not established, not refuted, with EXTERNAL_SNAPSHOT_MISSING.