Protocol versioning
Every signed object carries its schema version inside the signed bytes — the version marker is itself cryptographically committed, not a label on the envelope. This page states, for each object: what the marker is, what bumps it, and which changes are additive-safe.
Summary
| Surface | Marker | Signed? | Additive-safe today? |
|---|---|---|---|
| Decision | schema_version = pg.decision.v1 | Yes | Yes — new optional fields are free |
| Policy | policy_version | Stamped on every decision | Versioned by design (append-only history) |
| License | v = pg.license.v2 | Yes | Within v2, yes; a meaning change needs a v3 branch |
| Receipt | v = pg.receipt.v2 | Yes | No — body changes ship live on merge |
| Identity assertion | audience = prampta:identity:v1 | Yes | No — a new required field breaks old signatures, by design |
| Entitlement | audience (same mechanism) | Yes | No — same reason |
| Evidence bundle | pg.evidence.v1 | Yes — minted fresh at read time | — |
| Assertion (§11 bridge) | pg.assertion.v1 | Yes — built and signed fresh | — |
| Identity assertion (response wrapper) | pg.identity.v1 | Response-only | — |
| Audit event | pg.audit-event.v1 | Response-only | — |
Decision vs policy versioning
The schema (schema_version) is the shape of the envelope;
the policy (policy_version) is the rule set that filled it
in. They are stamped independently. A decision can be read against exactly the rules in
force when it was signed, even after the rules change — both versions are on the object.
Policy history is append-only: every entry names the date and the change, and every
PG_* refusal code is registered and classified there (see
Refusal codes).
Why some objects are deliberately not additive-safe
The license body’s v marker was added as a hard cut: the point was
a real, load-bearing version marker inside the signed bytes, not another optional field a
legacy row can silently ignore. The identity assertion’s audience string is
part of what gets signed — changing it is exactly how a v2 assertion refuses to replay
against a v1 verifier. Where a break is possible, it is a break on purpose, so a
signature from one format era cannot silently pass as another.
Receipts: the known gap
There is currently no deprecation window or dual-accept mechanism for receipt format changes — an addition to the receipt body ships live the moment it merges. The receipt’s version marker closed the “no marker at all” gap; the evolution-window gap is known and tracked, not hidden. Providers holding cached receipts should verify them against the operator key set and store the evidence bundle for long-term audit.
