> ## Documentation Index
> Fetch the complete documentation index at: https://docs.algovoi.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy Binding

> Additive policy snapshot binding over a frozen subject reference: proves which ruleset version was in force when a record was sealed. Apache 2.0.

[![Keystone Enabled](https://img.shields.io/badge/Keystone-enabled-5cb9f8)](/keystone)

A receipt or audit chain tells an auditor *what* was decided. It does not, on its own, tell them *under which ruleset* that decision was made — and if the issuer quietly rotates its policy, an old record gives no signal that the rules changed underneath it.

**Policy Binding** closes that gap. It binds a content hash of the policy snapshot to an existing, frozen reference (a settlement-action `binding_ref`, or a `retention_chain_ref`) so the bound record becomes **version-provable** (you can prove exactly which policy was in force) and **rotation-detectable** (a record sealed under policy `P` fails recomputation under a rotated policy `P'`).

It is **strictly additive over the frozen Layer 1**. It introduces no new cryptographic primitive and changes nothing in the canonicalisation substrate — it composes the same RFC 8785 JCS + SHA-256 already in use.

<Info>
  **Apache-2.0 open source.** Install via `pip install algovoi-policy-binding`. Python and TypeScript are byte-for-byte identical on the same input. Adopters who pin and verify against the canonical vectors qualify for a free v0 licence key for the mandate auditor — see [Adopters](#adopters) below.
</Info>

## How it works

Two references, both computed with RFC 8785 JCS canonicalisation and SHA-256:

```
policy_ref       = "sha256:" + SHA-256(JCS(policy_document))
policy_bound_ref = "sha256:" + SHA-256(JCS({ policy_ref, subject_ref }))
```

* **`policy_ref`** is the content hash of the policy/ruleset/mandate snapshot itself. Because the policy is JCS-canonicalised first, key order in the policy document does not affect the result.
* **`policy_bound_ref`** binds that policy hash to a `subject_ref` — the frozen reference of the thing the policy governed. The construction is **version-agnostic**: the `subject_ref` is imported by hash, so the same construction binds a policy to a settlement-action `binding_ref` (v1) or to a `retention_chain_ref` (v0 or v1) without any change.

Because `subject_ref` is imported by hash, Policy Binding does not need to know — and is not coupled to — the internal shape of whatever it binds. The subject can evolve independently; the binding stays valid as long as the subject hash is unchanged.

## What an auditor can verify

| Auditor holds                                 | What they can check                                                            |
| --------------------------------------------- | ------------------------------------------------------------------------------ |
| A bound record + the policy document          | That the record was sealed under exactly this policy (`policy_ref` recomputes) |
| A bound record + a different (rotated) policy | Rotation is detected — `policy_bound_ref` fails to recompute under `P'`        |
| A bound record + the subject                  | That the policy is bound to this specific subject and no other                 |

No issuer call. No registry lookup. No AlgoVoi service. RFC 8785 JCS, SHA-256, and a JSON parser are the entire dependency.

## Invariants

The construction holds five invariants, each backed by a conformance check:

| Invariant                | Meaning                                                                                                        |
| ------------------------ | -------------------------------------------------------------------------------------------------------------- |
| **Stability**            | The same `(policy, subject)` always yields the same `policy_bound_ref` across implementations and time         |
| **Snapshot-binding**     | The `policy_bound_ref` is bound to the exact policy bytes; any change to the policy changes the ref            |
| **Rotation-detection**   | A record sealed under `P` does not recompute under a rotated `P'` (negative case)                              |
| **Subject-binding**      | The same policy bound to different subjects yields different refs; substituting the subject changes the result |
| **Key-order-invariance** | JCS absorbs policy key order — `policy_ref(P)` equals `policy_ref(P)` with its keys shuffled                   |

## Conformance vectors

`policy_binding_v1` — **14 checks** across three subject types and both rotation directions. Cross-validated Python + TypeScript, byte-for-byte.

**Subjects** (the published canonical references from the conformance corpus):

| Subject                        | Canonical ref                                                             |
| ------------------------------ | ------------------------------------------------------------------------- |
| `retention_chain_v0`           | `sha256:f15a1dcd03cc039204dff24619ff4815ad041ad8796b94f59d52252043d0d08f` |
| `retention_chain_v1`           | `sha256:60081d57e585e6a7ee0b79e1204aae2be3739a539c6524074003408b3de1951e` |
| `settlement_action_binding_v1` | `sha256:7dc4a2bf62b3c5eabd10fc875ff7fc10f188666f15838c4a51464cc72e80f6ca` |

**Policy references:**

| Policy                   | `policy_ref`                                                                                                  |
| ------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `P` (`aml.transfer` v1)  | `sha256:acc943b05fa8e8096e5b313288bc4f919cc2661f167c833770509a53049afa1c`                                     |
| `P'` (`aml.transfer` v2) | `sha256:858fd6694716f503448ea89da802c0c2942e2619938f126d0088cb4ba9af5d35`                                     |
| `P` key-shuffled         | `sha256:acc943b05fa8e8096e5b313288bc4f919cc2661f167c833770509a53049afa1c` (identical — JCS absorbs key order) |

**Bound references** (`policy_bound_ref`), six positives — every subject under both `P` and `P'`:

| Subject                        | under `P`                                                                 | under `P'`                                                                |
| ------------------------------ | ------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `retention_chain_v0`           | `sha256:65390e374d9a3ec4ffe08a078c66c088da3c8a2c993a21885531e7e371a7e8b0` | `sha256:7329a61c9b61e8d64cb8b141e15f7b1743c51d73a52c26404e18666ee241ea55` |
| `retention_chain_v1`           | `sha256:7a2d7b0464edadcee38151524e2d458f4396df4b3daeede329fb5a16006c12e2` | `sha256:bf6bac1ce44f1dc8b0cfec04c1be3994ac70e6abad49634cb666019cf5218b90` |
| `settlement_action_binding_v1` | `sha256:aaee2091799f376ee8cac802ea4920feaa4eca52950488a3e047ff82e6959a21` | `sha256:e6629ede721146e62ce148fc25c52b79a58103a7476784397b328809e0f027e2` |

Plus three negative rotation cases (one per subject: sealed under `P`, must reject under `P'`) and two invariant assertions (key-order-invariance, subject-binding).

## Adopters

If you build on `algovoi-policy-binding` and verify against the canonical vectors, you qualify for a free **v0 licence key** for `algovoi-mandate-auditor` — AlgoVoi's production-grade MiCA/DORA compliance audit service for payment mandate charge chains.

**Qualification criteria** (enforced by `scripts/check_v0_adoption.py`):

1. `algovoi-policy-binding` declared as a dependency, pinned to a specific version (`==0.1.0`) — a bare version range is rejected
2. At least one canonical vector hash from `policy_binding_v1` in your conformance tests
3. A `NOTICE` file preserving the Apache-2.0 attribution

**To apply:** email [chopmob@gmail.com](mailto:chopmob@gmail.com) with your dependency file, a snippet showing the canonical hash in your test suite, and a copy of your `NOTICE` file. If all criteria are met, a v0 key is issued within one business day.

## Relationship to the open substrate

Policy Binding sits directly on top of the open [JCS Canonicalisation Substrate](/canonicalisation-substrate) and composes with the [Retention Chain](/retention-chain-substrate) and settlement-action binding. It uses the same RFC 8785 JCS and SHA-256 primitives — no additional cryptographic dependencies.

```
Policy Binding                 Apache-2.0 open source (this page)
        |
        v
Retention Chain / binding_ref  the frozen subject_ref (imported by hash)
        |
        v
JCS + SHA-256 primitives       open substrate (Apache-2.0)
        |
        v
RFC 8785 (JCS)                 IETF standard
```

It **enables** the security; it is **realized** only when a verifier or gate rejects on a `policy_bound_ref` mismatch — that is a runtime posture decision, not a property of the substrate itself.

Also available natively in the commercial [Substrate 2](/substrate-2) (`substrate2.policy_binding`), carried to adopters through the existing pin-and-licence channel.

## Specification

The normative specification is IETF Internet-Draft [`draft-hopley-x402-retention-chain-05`](https://datatracker.ietf.org/doc/draft-hopley-x402-retention-chain/) (AlgoVoi, sole authorship, 19 June 2026), which adds:

* **Section 7.7 — Policy Binding:** the `policy_ref` / `policy_bound_ref` construction and its invariants (Stability, Snapshot-binding, Rotation-detection, Subject-binding, Key-order-invariance)
* **Section 8.10 — Policy Binding Vectors:** the exact preimage inputs, JCS canonical forms, and expected byte sequences for `policy_binding_v1`
