Metadata-Version: 2.4
Name: belief-check
Version: 0.3.4
Summary: A machine's way to know when it's wrong — detect semantic drift in a counterparty's API.
Author: Veronica Dawkins
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: api,contract,drift,integration,reliability,semantic-versioning
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: System :: Networking :: Monitoring
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# belief-check

**A machine's way to know when it's wrong.**

Two services agree on a contract. Months later one of them changes what a
field *means* — `amount_cents` starts carrying `49.99` instead of `4999` —
and every type checker, schema validator, and integration test stays green.
The field kept its name. The wrongness flows.

belief-check is the smallest thing that catches that: a document stating what
you believe about a counterparty, a way to check whether it still holds, and a
tripwire that stops the call when it doesn't.

Zero dependencies. Python 3.9+, standard library only. No registry, no
coordination, no permission, no cryptographic identity.

```bash
python example.py
```

That runs the whole proof against a live local server — drift, containment,
recovery — in four acts.

## The three layers

**Layer 1 — the belief.** A plain JSON document: the schema fingerprint you
built against, a semantic version, and probes that test *meaning* (values,
units, types), not just shape.

**Layer 2 — the check.** `POST /.well-known/belief-check`. The counterparty
answers `confirmed` or `diff`. On silence — non-200, timeout, endpoint absent
— the consumer runs its probes itself and decides unilaterally. The first
adopter gets fail-fast against counterparties that never cooperate.

**Layer 3 — the tripwire.** Detection is the primitive; blocking is policy,
and the two are never fused. `FAIL_CLOSED` (default) blocks the call with a
typed, machine-readable `BeliefBroken`. `HALF_OPEN` blocks but re-checks and
resumes automatically. `OBSERVE` never blocks and hands every break to your
own handler.

## Consumer

```python
from beliefcheck import Belief, Probe, Tripwire, Policy, schema_hash

belief = Belief(
    counterparty="https://api.example.com",
    schema_hash=schema_hash(openapi_dict),   # the artifact you built against
    semantic_version="orders-v2",
    probes=[
        Probe(
            name="amount-is-integer-cents",
            request={"method": "POST", "path": "/orders/echo",
                     "body": {"sku": "A1", "qty": 1}},
            expect={"status": 200, "body_subset": {"amount_cents": 4999}},
        )
    ],
)

wire = Tripwire(belief, policy=Policy.FAIL_CLOSED, interval=300)
wire.connect()                       # check on connect
order = wire.guard(client.place_order, "A1")   # blocks if belief broke
```

`guard` also probes on anomaly: if the wrapped call raises, the wire checks
whether drift — rather than ordinary failure — is the real cause, and tells
you which.

## Producer

One route makes you a cooperating counterparty:

```python
from beliefcheck import answer, WELL_KNOWN, schema_hash

@app.post(WELL_KNOWN)
def belief_check(doc: dict):
    return answer(doc, schema_hash(CURRENT_SCHEMA), "orders-v2")
```

A handshake `confirmed` is your claim about your *declared state*, not
verified behavior. The producer never executes a stranger's probes against
itself — that is a security hole, not a courtesy. Probes verify behavior;
handshakes verify declaration.

## Read this before trusting it

Probes are examples, not invariants. The two outcomes are not symmetric:

> **A fired check is proof of drift. A passing check is evidence of health,
> never proof.**

Drift outside your probes' coverage is invisible to this protocol. Widen
coverage; accept that it never closes. Probes are also perishable — the most
dangerous deployment is a confidently `FAIL_CLOSED` wire whose probes went
stale. Treat a long-silent tripwire with suspicion, not comfort.

Anything claiming a silent tripwire means a healthy integration is lying to
you.

## When not to use this

- **You own both sides and deploy them together.** Types, review, and shared
  libraries already enforce the contract; a belief document is a second source
  of truth that can rot.
- **The producer is simple and stable.** If probe maintenance costs more than
  the expected breakage, the ROI is negative.
- **The drift you fear is syntactic.** Strict parsers and compiled protos
  already scream at shape changes. This protocol exists for the residue:
  meaning changes that survive the type system.
- **You need audit or compliance guarantees.** This is a safety mechanism, not
  an evidence trail. Proving to a third party that you checked is attestation,
  a different layer.

It earns its keep where drift is silent, dangerous, and outside your control.

## Non-goals

Signatures, gossip, history, anchoring, repair, and dashboards are other
layers answering other questions. [SPEC.md](SPEC.md) is one page and is
complete as written.

## License

Apache-2.0. No CLA.
