docs← Back to article

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.

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