---
title: The Fact Block dialect
desc: Eight fields in a fixed order inside ordinary markdown. Not a new syntax, a rigid shape, so a model copies it instead of interpreting it.
order: 3
---

# Fact Block 0.1

**A Fact Block is eight named fields, always the same, always in the same order, under
a markdown heading. It invents no syntax. That is the entire idea.**

```
## Learn Salsa In Paradise, San Juan
answer: from 30 USD, rated 5 out of 5 from 156 reviews, 60 min
where: San Juan, Puerto Rico, United States
price: from 30 USD
duration: 60 min
rating: 5/5 from 156 reviews
booking: instant confirmation, free cancellation
source: https://www.viator.com/tours/San-Juan/...d903-288497P1
checked: 2026-09-04
```

## Do not invent a language

The obvious move, once you decide to write for machines, is to design a compact
notation of your own. It is the wrong move and it is worth saying why, because the
reasoning is not obvious.

A language model is fast at what it saw a trillion times during training. A notation
you invented last week is out of distribution: the model has to spend reasoning on
decoding it before it can use it, and it will not tell you when it decodes it wrong.
Tokenisers are trained on real text, so invented sigils and clever abbreviations often
cost **more** tokens than the plain English they replace. You would be paying a tax and
calling it a saving.

So the language is the one the model already knows. What you get to design is the
**shape**. A Fact Block is fast to read because it never varies, not because it is
novel.

## The eight fields

| field | holds | required |
|---|---|---|
| `answer` | one sentence, quotable on its own, carrying the numbers | yes |
| `where` | city, region, country | yes |
| `price` | `from <n> <currency>` | yes |
| `duration` | minutes under 90, hours above | yes |
| `rating` | `<n>/5 from <n> reviews` | yes |
| `booking` | instant or on request, and the cancellation terms | yes |
| `source` | the URL the values came from | yes |
| `checked` | ISO date the source was read | yes |

All eight, in that order, or it is not a Fact Block. Omitting a field you do not have
is not allowed, because a reader cannot tell an absent field from a forgotten one. The
value becomes `not stated` and stays visible.

A gap is allowed in a field and **not** allowed in `answer`. A line that reads
*"from not stated USD"* is not quotable, so the gate refuses the whole block rather
than publish a hollow summary.

## The answer line is computed, never written

`answer` is assembled from the fields below it by string formatting. **No language
model writes it.** A model asked to summarise a record with a gap in it will fill the
gap, confidently, and nothing downstream will notice. Composing the line arithmetically
removes the opportunity rather than checking for it afterwards.

## The gate

A block that cannot be trusted does not get published. The reference implementation
refuses to emit one when:

- `source` is missing or is not a URL
- `checked` is missing, malformed, in the future, or **more than 180 days old**
- fields are out of order, or any field is absent
- `answer` carries fewer than two numbers, which means it is a sentence and not an
  answer
- `answer` contains a gap, so it is not quotable alone
- `answer` cites a number that **appears in no value field below it**

That last rule is the one that earns its place, and it took two attempts to write.
The first version compared the answer against every other line, `source` and `checked`
included. A Viator URL ends in `d903-288497P1` and a date contains `2026`, so an
answer reading *"from 903 USD, rated 2026 out of 5 from 288,497 reviews"* passed,
with all three numbers invented and all three corroborated by digits in a URL slug.
The rule now compares against value fields only.

It is worth saying plainly what that means: **the check that a summary matches its
data was, for a few hours, satisfiable with noise.** It was found by a review, not by
its own tests.

## Why a fixed shape helps a machine

- The model copies rather than interprets, and a model that copies cites.
- It is extractable with one regular expression, so a consumer needs no parser.
- It is auditable. A shape you can check is a shape you can refuse.

**It is not mainly a compression win, and an earlier draft of this page said it was.**
The example block above is 361 bytes. The same nine facts written as natural prose,
carrying the same URL, are 490 bytes. That is 1.36 times, not the three times this
page claimed before the number was measured. Strip the URL from both and it is 1.46.
Real, small, and not the reason to do this. The reason is the fixed shape.

## Why it helps a person too

The block is readable out loud. Nobody needs a legend, because the field names are the
legend. This matters more than it sounds: a format only a program can read gets no
proofreading, and unproofread data goes stale silently.

## Reference implementation

[factblock.py](/tools/factblock.py), 231 lines, no dependencies, CC0. The file
asserts its own length, because this sentence would otherwise rot on the next edit. It generates blocks from the
Viator Partner API and gates them.

```
python3 factblock.py --site path/to/config.json   # generate
python3 factblock.py --check                      # self-test the gate
```

The generator is written against one source because that is the one we could test
against real records. The gate is source agnostic and is the part worth reusing.

## What this does not solve

A Fact Block makes a record cheap to read and hard to falsify by accident. Three
limits, all of them real:

- **The gate checks shape, not truth.** It cannot tell whether 30 USD was ever the
  price. It only checks that the same 30 appears in every place that claims it.
- **180 days is a guess.** It is far too long for a price and probably fine for a
  duration, and the format has one window for both.
- **A well shaped block full of stale prices is worse than prose**, because it looks
  checked.

## Relationship to the spec

[The spec](/spec) says how a document is served. This says what one can look like
inside. R1 to R4 stand on their own and a site can meet all four without ever writing
a Fact Block. This is a profile, not a fifth requirement.
