# Belnap four-valued logic as an API: knowledge join, truth join, negation and conflation per call

## Belnap four-valued logic as an API: knowledge join, truth join, negation and conflation per call

Belnap's four-valued logic (Belnap 1977) has two lattice orders over four values, and an agent combining evidence from several sources needs both of them. The market at market.561.group sells eight small operations over that algebra, each at $0.001 or $0.002 per call over x402: rename a point between naming families, join or meet in the knowledge order, join or meet in the truth order, negate, conflate, and count. All of them refuse unknown names before payment. This article gives the full tables, the live endpoint contracts and the reason one would want a paid logic service at all.

### What are the four values, in the market's names?

A point is a pair (told-for, told-against). The extremal family, which the examples below use, names the four points `held` (told for, not against), `denied` (against, not for), `contested` (both) and `unknown` (neither). Belnap's classical names are true, false, both and neither. The same four points have names in three other families, and the conversion offer renames between them without changing the point:

| Family | Names |
| --- | --- |
| extremal | `held`, `denied`, `contested`, `unknown` (for-only, against-only, both, neither) |
| truth | `true`, `false`, `both`, `neither` (same order) |
| told | `told true`, `told false`, `told both`, `told none` (same order) |
| knowledge | `absurd`, `potential`, `active`, `stable` (four more names; use the conversion offer to map them) |

Operations that take two points require both to be from the same family, so that an agent cannot silently mix `true` with `held`; it has to call the conversion offer, which says what it does: "Rename one Belnap FOUR point among knowledge, told, truth and extremal families, preserving its told-for/told-against sides. For example held becomes told true."

### Why are there two orders?

Information and truth are different axes. In the **knowledge order**, `unknown` is the bottom (nothing known), `contested` is the top (everything told), and `held` and `denied` are incomparable in between. Joining in this order *accumulates evidence*: if one source tells you a claim is held and another tells you it is denied, the accumulated state is `contested`. Meeting in this order keeps only what both sources say.

In the **truth order**, `denied` is the bottom and `held` is the top, and `contested` and `unknown` sit between. Joining in this order is a disjunction: a claim is held if either operand holds it. Meeting is a conjunction. Negation swaps `held` and `denied`.

A system that checks "is the claim established" by joining in the truth order, and "do my sources conflict" by joining in the knowledge order, will not confuse the two. That separation is why the market sells both rather than one.

### What does each operation compute?

With a point written as (for, against):

| Offer | Route | Rule | Example from the catalog |
| --- | --- | --- | --- |
| Knowledge join | `/v1/four/reading-knowledge-join` | (for OR for, against OR against) | held + denied = **contested** |
| Knowledge meet | `/v1/four/reading-knowledge-meet` | (for AND for, against AND against) | held and denied = **unknown** |
| Truth join | `/v1/four/reading-truth-join` | (for OR for, against AND against) | held and denied = **held** |
| Truth conjunction | `/v1/four/reading-truth-meet` | (for AND for, against OR against); empty input is the unit |  |
| Negation | `/v1/four/reading-negate` | swap for and against | held becomes **denied**; unknown and contested are fixed |
| Conflation | `/v1/four/reading-conflate` | exchange unknown and contested; fix held and denied |  |
| Name conversion | `/v1/four/reading-convert` | rename between families | `{family: told, name: held}` gives **told true** |
| Point census | `/v1/four/reading-census` | count up to 14,627 named points by knowledge-family name |  |

The first two rows' examples are the catalog's own; the other tables below we derived from the rules in the descriptions and checked against those examples.

The knowledge join, as a table over the extremal names:

| ⊕ | held | denied | contested | unknown |
| --- | --- | --- | --- | --- |
| **held** | held | contested | contested | held |
| **denied** | contested | denied | contested | denied |
| **contested** | contested | contested | contested | contested |
| **unknown** | held | denied | contested | unknown |

and the truth join:

| ∨ | held | denied | contested | unknown |
| --- | --- | --- | --- | --- |
| **held** | held | held | held | held |
| **denied** | held | denied | contested | unknown |
| **contested** | held | contested | contested | held |
| **unknown** | held | unknown | held | unknown |

Note that `unknown` is the identity of knowledge join and `denied` is the identity of truth join. Both operations are commutative, associative and idempotent, so the order in which evidence arrives never changes the result. That property is what makes them safe for distributed collection: two nodes that have seen the same evidence in different orders agree. The paraconsistent inbox in [Paraconsistent federation](https://engineering.561.group/activitypub-paraconsistent-inbox/) relies on exactly this.

### How do I call one?

Each operation is a `POST` of a small JSON body. Without payment you get the 402 challenge, which shows the quote:

```bash
curl -s -i -X POST https://market.561.group/v1/four/reading-knowledge-join \
  -H 'content-type: application/json' \
  -d '{"left":"held","right":"denied"}' | grep -i '^HTTP\|^payment-required' | cut -c1-80
```

A paid call to this route returns `contested`, per the catalog's example. A body naming something outside the four families is refused with `400` before any challenge:

```bash
curl -s -X POST https://market.561.group/v1/four/reading-negate \
  -H 'content-type: application/json' -d '{"name":"maybe"}'
# {"type":"urn:561-group:web-server:problem:request-validation","title":"Invalid body", ... "keyword":"enum" ...}
```

The input schema's `name` is an enum of all sixteen accepted names. The offer descriptions require both operands of a binary operation to share a family. In our unpaid probe a mixed body (`held` with `true`) still received a `402`, so that family check is not part of the schema-level refusal we could observe; we did not pay to see the paid result. The catalog gives each offer's body schema and an example under [`/v1/catalog`](https://market.561.group/v1/catalog); an agent can find them through the [MCP face](https://engineering.561.group/x402-one-catalog-machine-interfaces/) with `search_apis` and the query `belnap`.

### Why would anyone pay for a few lines of logic?

Honest answer: you probably shouldn't, if you run the algebra locally. The operations are pure and tiny. We list them for three reasons that have nothing to do with computational difficulty.

1. **A reference implementation agents can call.** When two services disagree about what "conflation" means, a shared call settles it. The offers are the specification made executable, and the descriptions state precisely what they do not do: "No witness creation or assertion of truth", "Names are not verified observations or independent witnesses", "This acts on abstract points, not on source witness sets".
2. **The pay-per-call plumbing at the cheapest price point.** At $0.001 an offer exercises the whole x402 path (challenge, validation, signing, settlement) with almost nothing at stake, which makes it a convenient first purchase for an agent that is learning to pay.
3. **Integration with the higher offers.** Other offers return FOUR-valued results directly. The reference check endpoint, `POST /v1/reference-check`, checks up to 25 citation strings against CrossRef, OpenAlex and Open Library, and returns for each item a house FOUR reading: `true` means supported, `false` means the identifier resolves to another work, `both` means sources disagree, and `neither` means nothing found. The book-record offer returns `true` when found and `neither` on refusal. A client can fold many such readings with the knowledge join.

### What do the offers deliberately not do?

The catalog's wording is careful, and we repeat it. These operations act on abstract points. They do not create witnesses, assert real-world truth, or collapse to Boolean. A `contested` result means the inputs said both things, not that reality did. Meets and joins over named points are not verified observations, so the algebra gives you a defensible way to *combine what you were told* and no way to know whether you were told the truth. The same restraint appears in how the Group's front page reads [HTTP in four values](https://engineering.561.group/http-status-four-valued-belnap/): the reading reports what was observed and keeps the contradictions.

### Where does this fit?

The implementation lives in the Group's data layer (the `readingAs` export and its siblings), the lowest layer in the dependency order data, code, networking, systems. The market offers are a thin payment shell over it. For how a pay-per-call shell is built, see [what an x402 seller should do beyond the spec](https://engineering.561.group/x402-seller-design/).
