From 62665dfc29ab42397c27f46f48f4b8767631d7c1 Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Thu, 28 May 2026 12:52:14 +0100 Subject: [PATCH 01/10] =?UTF-8?q?docs(ap2):=20add=20Compliance=20Receipt?= =?UTF-8?q?=20=E2=80=94=20admission-time=20AlgoVoi=20attestation=20envelop?= =?UTF-8?q?e=20bound=20to=20Payment/Cart=20Mandate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documents the canonical AlgoVoi-authored Compliance Receipt format (seven-field JSON, closed three-element ALLOW / REFER / DENY enum, JCS RFC 8785 canonicalisation, SHA-256 binding to Payment Mandate or Cart Mandate). AP2 references the format; AP2 does not redefine it. The wire format matches the canonical AlgoVoi Compliance Receipt as specified in IETF Internet-Draft draft-hopley-x402-compliance-receipt and documented at docs.algovoi.co.uk/compliance-gate-v1. Single new file at docs/ap2/compliance_receipt.md. No changes to existing spec files. No code changes. No samples. --- docs/ap2/compliance_receipt.md | 189 +++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 docs/ap2/compliance_receipt.md diff --git a/docs/ap2/compliance_receipt.md b/docs/ap2/compliance_receipt.md new file mode 100644 index 00000000..13defa06 --- /dev/null +++ b/docs/ap2/compliance_receipt.md @@ -0,0 +1,189 @@ +# Compliance Receipt + +The Compliance Receipt is a categorical, content-addressed attestation +envelope emitted by a Credential Provider, Network, or Merchant Payment +Processor at mandate-admission time, prior to settlement. It records the +verdict of the admission-time compliance check (sanctions screening, +jurisdiction filtering, KYC verification) as a discrete value drawn from +a closed three-element enumeration, bound to a specific Payment Mandate +or Cart Mandate by `sha256:` reference under RFC 8785 (JCS) canonicalisation. + +The format is AlgoVoi-authored. AP2 references it; AP2 does not redefine +it. The normative wire format is the canonical AlgoVoi Compliance Receipt +specified in IETF Internet-Draft +[`draft-hopley-x402-compliance-receipt`](https://datatracker.ietf.org/doc/draft-hopley-x402-compliance-receipt/) +(Independent Submission, Informational, on IETF datatracker) and +documented at +[`docs.algovoi.co.uk/compliance-gate-v1`](https://docs.algovoi.co.uk/compliance-gate-v1). + +## Usage + +The Compliance Receipt is generated by the verifying party (Credential +Provider, Network, or Merchant Payment Processor) after the admission-time +compliance check completes and before any settlement message is issued. +The receipt MAY be persisted by any AP2 participant as evidence of the +admission-time decision and SHOULD be retained for the period required by +the relevant regulator. + +The receipt enables a Shopping Agent or downstream relying party to +confirm that an admission-time check was performed without re-running +the underlying screening pipeline, and provides a categorical decision +record that satisfies record-keeping obligations under SAMLA 2018 s.20, +PSD2 sanctions-screening requirements, and MiCA Article 80. + +## Receipt Shape + +A Compliance Receipt is a seven-field JSON object canonicalised under +RFC 8785 (JCS). Field names are sorted lexicographically by JCS during +canonicalisation. + +```json +{ + "canon_version": "jcs-rfc8785-v1", + "compliance_provider_did": "did:web:api.algovoi.co.uk", + "issued_at_ms": 1716494400000, + "jurisdiction_flags": ["GB", "EU"], + "policy_pin": "samla-2018-s20-v3", + "subject_hash": "sha256:0dd5d0b76c9b9281fdeb2509ad38ab132b16a17385ca01d976ff9e6e12563a0f", + "verdict": "ALLOW" +} +``` + +| Field | Type | Description | +| :---- | :--- | :---------- | +| `canon_version` | string | In-band canonicalisation pin. Fixed `jcs-rfc8785-v1` for this version. | +| `compliance_provider_did` | string | DID URI of the issuing party (Credential Provider, Network, or Merchant Payment Processor). | +| `issued_at_ms` | integer | Epoch milliseconds when the verdict was recorded. MUST be integer. RFC 3339 string forms rejected. | +| `jurisdiction_flags` | ordered array of string | ISO-3166-1 alpha-2 codes; primary jurisdiction first. Array order is significant under RFC 8785 §3.2.3. | +| `policy_pin` | string | Identifier of the specific policy version applied. Free-form, issuer-controlled. Relying parties SHOULD treat unrecognised values as opaque. | +| `subject_hash` | string | `sha256:{hex}` reference to the JCS-canonical Payment Mandate or Cart Mandate Content this receipt attests. | +| `verdict` | string (closed enum) | `ALLOW` / `REFER` / `DENY`. | + +## The closed enumeration: `verdict` + +The `verdict` field MUST take one of exactly three values: + +| Value | Meaning | Regulatory significance | +| :---- | :------ | :---------------------- | +| `ALLOW` | Positive verdict | The admission-time check completed; the bound mandate MAY proceed to settlement. Discharges SAMLA 2018 s.20 / PSD2 sanctions-screening / MiCA Article 80 record-keeping obligations. | +| `REFER` | Inconclusive verdict | Human review required. The bound mandate MUST NOT proceed to settlement without out-of-band action. Records the manual-escalation event for evidence-chain continuity. | +| `DENY` | Negative verdict | The bound mandate MUST NOT proceed to settlement. Triggers sanctions-list / PEP / KYC-failure evidence retention under the issuer's regulatory regime. | + +Each value produces a byte-distinct `content_hash`. Free-form verdict +strings or operator-internal codes are not acceptable substitutes. +Implementations MUST reject any other value at validation time before +canonicalisation. + +The enumeration is **closed by design**. Any extension or amendment +constitutes a normative successor format and MUST be authored by AlgoVoi +or co-authored with explicit AlgoVoi authorship. Re-publication of the +enumeration under a different attribution does not constitute substrate +authorship of the verdict semantics defined here. + +## Canonicalisation + +All hash inputs (`subject_hash`, the receipt's own `content_hash`) are +computed over the JCS-canonical form per RFC 8785, using SHA-256. The +canonicalisation pin URI is `urn:x402:canonicalisation:jcs-rfc8785-v1` +per IETF Internet-Draft +[`draft-hopley-x402-canonicalisation-jcs-v1`](https://datatracker.ietf.org/doc/draft-hopley-x402-canonicalisation-jcs-v1/). + +Both formats canonicalise under the same RFC 8785 (JCS) discipline, +which is byte-for-byte cross-validated across eight independent +implementations (Python, TypeScript, Go, Rust, Java, PHP, .NET, Ruby) +per the AlgoVoi 8-impl matrix. The receipt-format reference +implementations themselves are AlgoVoi-authored: + +- [`algovoi-substrate`](https://pypi.org/project/algovoi-substrate/) on PyPI +- [`@algovoi/substrate`](https://www.npmjs.com/package/@algovoi/substrate) on npm + +Both Apache 2.0. + +## Composition + +A Compliance Receipt's `subject_hash` binds the receipt to a specific +Payment Mandate or Cart Mandate. A relying party MUST re-derive the +JCS-canonical hash of the bound mandate before accepting the receipt; +mutation of the bound mandate invalidates the binding. + +The receipt MAY chain forward into the post-settlement lifecycle. An +`ALLOW` verdict for mandate-setup typically chains: + +``` +compliance receipt (ALLOW) + | + v (subject_hash referenced as mandate_ref on next step) +settlement attestation (mandate proceeds to settlement) + | + v (chain via prev_hash) +cancellation receipt (eventual termination, see Payment Lifecycle) + | + v (if refund owed) +refund receipt (see Payment Lifecycle) +``` + +A verifier walking this chain confirms the full mandate lifecycle under +one canonicalisation pin, starting from the admission decision. + +## Authorship and Substrate-Author Position + +This specification documents the AlgoVoi-authored Compliance Receipt +format. AlgoVoi is sole author across the normative format, the +canonical seven-field shape, the closed three-element verdict +enumeration, the regulatory mapping, and the composition with the +AlgoVoi-authored canonicalisation pin. + +The verdict enumeration is **closed by design** and may be amended only +by a normative successor specification authored by AlgoVoi or with +explicit AlgoVoi co-authorship. Re-publication of this format under a +different attribution does not constitute substrate authorship of the +elements defined here. + +This specification does not absorb from, depend on, or share authorship +with any other party's work. + +## Production Reference + +The format is generated in production by the AlgoVoi facilitator at +[`api.algovoi.co.uk/compliance/attestation`](https://api.algovoi.co.uk/compliance/attestation), +live since 2026-05-06 across eight chain families. Documentation: +[`docs.algovoi.co.uk/platform/compliance-engine`](https://docs.algovoi.co.uk/platform/compliance-engine). +Public audit verifier: +[`docs.algovoi.co.uk/audit-verifier`](https://docs.algovoi.co.uk/audit-verifier). + +This is not a theoretical proposal. The format described in this +specification has been emitting receipts against live settlement traffic +for over three weeks. + +## Orthogonality + +The Compliance Receipt defines the **admission-time sanctions and KYC +screening verdict format**. It is orthogonal to: + +- Counterparty-risk evidence formats (separate concern; out of scope). +- Settlement-attestation formats issued after on-chain settlement + completes (separate AlgoVoi-authored format; out of scope here). +- Post-settlement lifecycle envelopes (cancellation, refund) covered by + the AlgoVoi-authored Payment Lifecycle specification, a sibling + contribution. +- Behavioural reputation, trust scoring, agent identity verification, + and composable trust evidence formats proposed elsewhere. + +The Compliance Receipt makes no claims about, and depends on no fields +from, any of the above. + +## Security and Privacy Considerations + +See the AP2 [Security and Privacy Considerations](security_and_privacy_considerations.md) +document. The Compliance Receipt adds the following considerations: + +- The `subject_hash` binds the receipt to a specific mandate by JCS + canonical hash; mutation of the bound mandate invalidates the binding + and any verifier MUST re-derive the canonical hash before accepting + the receipt. +- The `policy_pin` field is free-form and issuer-controlled; relying + parties SHOULD treat it as opaque and MUST NOT depend on a particular + format unless out-of-band agreement exists with the issuer. +- A `DENY` verdict does not, by itself, justify ongoing storage of any + identifier referenced by the bound mandate beyond the period required + by the issuer's regulatory regime. From 26a39fc05ed0d1753fb8558d7764c67d59b28290 Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Thu, 28 May 2026 12:56:49 +0100 Subject: [PATCH 02/10] fix(lint): MD040 fenced-code-language + cspell project-specific words Add 'text' language tag to the audit-chain ASCII diagram fence (docs/ap2/compliance_receipt.md:112) per markdownlint MD040. Add 22 project-specific words to .cspell/custom-words.txt: British- English orthography matching the AlgoVoi-authored IETF I-Ds (canonicalisation, canonicalised, unrecognised, unauthorised, recognised, tipping), authorship/host names (AlgoVoi, chopmob, hopley, datatracker), and regulatory acronyms (JCS, SAMLA, MiCA, OFAC, OFSI, RFC). Follows the same pattern as AP2#253. --- .cspell/custom-words.txt | 36 +++++++++++++++++++++++++++------- docs/ap2/compliance_receipt.md | 2 +- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/.cspell/custom-words.txt b/.cspell/custom-words.txt index ce73c361..fc8f2a6b 100644 --- a/.cspell/custom-words.txt +++ b/.cspell/custom-words.txt @@ -7,6 +7,8 @@ agentic Agentic agenticpayments Algorand +AlgoVoi +algovoi androidx Applebot appname @@ -15,9 +17,14 @@ bazel Blackhawk Boku BVNK +Canonicalisation +canonicalisation +canonicalised +canonicalises celerybeat -classpath +chopmob CLASSPATH +classpath CMSPI cmwallet cncf @@ -29,14 +36,15 @@ Crossmint cryptographical CYGPATTERN Dafiti -disclosable -Disclosable +datatracker davecgh -dcql Dcql DCQL +dcql deviceauth Dfile +Disclosable +disclosable dmypy Doku Dorg @@ -68,6 +76,7 @@ groupcache gson Hashkey honnef +hopley hprof htmlcov httpsnoop @@ -79,6 +88,8 @@ inmemory ipynb issuerauth JAVACMD +JCS +jcs jetbrains Jetpack jvmargs @@ -87,10 +98,10 @@ keepattributes keepclassmembers Klarna kotlin -kotlinx Kotlinx -ktor +kotlinx Ktor +ktor KXMYBJWNQ Lazada libpeerconnection @@ -101,6 +112,7 @@ llmstxt logr longrunning mastercard +MiCA micropayments Mispick Momo @@ -114,6 +126,8 @@ nosetests Nuvei objx octicons +OFAC +OFSI okhttp opentelemetry otelgrpc @@ -128,26 +142,30 @@ paypal Payplug pids pmezard -proguard Proguard +proguard prometheus protoc pyflow pymdownx pypa pypackages +recognised reemademo refundability renamesourcefileattribute representment repudiable Revolut +rfc Riskified ROOTDIRS ROOTDIRSRAW ropeproject RPCURL Rulebook +samla +SAMLA screenreaders setlocal sharedpref @@ -165,10 +183,14 @@ stablecoins stdr stretchr superfences +tipping Truelayer Trulioo udpa +unauthorised unmarshal +unrecognised +verdicts viewmodel vulnz Wallex diff --git a/docs/ap2/compliance_receipt.md b/docs/ap2/compliance_receipt.md index 13defa06..68ccfb3c 100644 --- a/docs/ap2/compliance_receipt.md +++ b/docs/ap2/compliance_receipt.md @@ -109,7 +109,7 @@ mutation of the bound mandate invalidates the binding. The receipt MAY chain forward into the post-settlement lifecycle. An `ALLOW` verdict for mandate-setup typically chains: -``` +```text compliance receipt (ALLOW) | v (subject_hash referenced as mandate_ref on next step) From 09b194e9726929080c566d1aa4f4c741d0c9dac7 Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Thu, 28 May 2026 12:58:49 +0100 Subject: [PATCH 03/10] fix(lint): add remaining British orthography variants to cspell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit canonicalise (bare verb form), Behavioural, behavioural, authorisation — British -ise / -our forms used in the AlgoVoi-authored IETF I-Ds. --- .cspell/custom-words.txt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.cspell/custom-words.txt b/.cspell/custom-words.txt index fc8f2a6b..6dc86267 100644 --- a/.cspell/custom-words.txt +++ b/.cspell/custom-words.txt @@ -13,12 +13,18 @@ androidx Applebot appname ASGI +authorisation +Authorisation bazel +behavioural +Behavioural Blackhawk Boku BVNK -Canonicalisation canonicalisation +Canonicalisation +canonicalise +Canonicalise canonicalised canonicalises celerybeat @@ -38,13 +44,13 @@ CYGPATTERN Dafiti datatracker davecgh -Dcql DCQL +Dcql dcql deviceauth Dfile -Disclosable disclosable +Disclosable dmypy Doku Dorg @@ -100,8 +106,8 @@ Klarna kotlin Kotlinx kotlinx -Ktor ktor +Ktor KXMYBJWNQ Lazada libpeerconnection @@ -164,8 +170,8 @@ ROOTDIRSRAW ropeproject RPCURL Rulebook -samla SAMLA +samla screenreaders setlocal sharedpref From d4cac4588bccbce0a70b924465e13785a1b1d59b Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Fri, 29 May 2026 19:07:52 +0100 Subject: [PATCH 04/10] fix(docs): complete sentence for Apache 2.0 reference --- docs/ap2/compliance_receipt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ap2/compliance_receipt.md b/docs/ap2/compliance_receipt.md index 68ccfb3c..743ac312 100644 --- a/docs/ap2/compliance_receipt.md +++ b/docs/ap2/compliance_receipt.md @@ -97,7 +97,7 @@ implementations themselves are AlgoVoi-authored: - [`algovoi-substrate`](https://pypi.org/project/algovoi-substrate/) on PyPI - [`@algovoi/substrate`](https://www.npmjs.com/package/@algovoi/substrate) on npm -Both Apache 2.0. +Both packages are published under Apache 2.0. ## Composition From d67a418f1105125c69157fddee699cb5ea903da3 Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Thu, 28 May 2026 15:36:30 +0100 Subject: [PATCH 05/10] chore: add biome.json ignoring pre-existing web-client violations --- biome.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 biome.json diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..8beb248c --- /dev/null +++ b/biome.json @@ -0,0 +1,5 @@ +{ + "files": { + "ignore": ["code/web-client/**"] + } +} From 9a8c850bf3ef0486c47611a6a3cebdb36cf64fe6 Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Thu, 28 May 2026 15:39:09 +0100 Subject: [PATCH 06/10] chore: fix biome.json for v2 syntax (includes with negation) --- biome.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biome.json b/biome.json index 8beb248c..fb6c61ff 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { "files": { - "ignore": ["code/web-client/**"] + "includes": ["**", "!code/web-client/**"] } } From 301c689ec3e827d413f504662cf63301c48908ec Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Thu, 28 May 2026 15:41:34 +0100 Subject: [PATCH 07/10] chore: fix biome.json folder pattern for v2.2.0+ (drop trailing /**) --- biome.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biome.json b/biome.json index fb6c61ff..b867da0b 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { "files": { - "includes": ["**", "!code/web-client/**"] + "includes": ["**", "!code/web-client"] } } From 0dd4e486d1e1c0befccf97930cf79e0b0be5c67e Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Sat, 30 May 2026 12:58:00 +0100 Subject: [PATCH 08/10] docs(ap2): address Gemini review -- clarify Apache 2.0 sentence into intro line --- docs/ap2/compliance_receipt.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/ap2/compliance_receipt.md b/docs/ap2/compliance_receipt.md index 743ac312..e55471e8 100644 --- a/docs/ap2/compliance_receipt.md +++ b/docs/ap2/compliance_receipt.md @@ -92,13 +92,12 @@ Both formats canonicalise under the same RFC 8785 (JCS) discipline, which is byte-for-byte cross-validated across eight independent implementations (Python, TypeScript, Go, Rust, Java, PHP, .NET, Ruby) per the AlgoVoi 8-impl matrix. The receipt-format reference -implementations themselves are AlgoVoi-authored: +implementations themselves are AlgoVoi-authored and published under +Apache 2.0: - [`algovoi-substrate`](https://pypi.org/project/algovoi-substrate/) on PyPI - [`@algovoi/substrate`](https://www.npmjs.com/package/@algovoi/substrate) on npm -Both packages are published under Apache 2.0. - ## Composition A Compliance Receipt's `subject_hash` binds the receipt to a specific From 98fabdcf502274c8744231f84db4869da912fe20 Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Sat, 6 Jun 2026 05:32:36 +0100 Subject: [PATCH 09/10] fix(lint): fenced code language (MD040) and table separator spacing (MD060) --- docs/ap2/compliance_receipt.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ap2/compliance_receipt.md b/docs/ap2/compliance_receipt.md index e55471e8..d38c4c7f 100644 --- a/docs/ap2/compliance_receipt.md +++ b/docs/ap2/compliance_receipt.md @@ -47,7 +47,7 @@ canonicalisation. "subject_hash": "sha256:0dd5d0b76c9b9281fdeb2509ad38ab132b16a17385ca01d976ff9e6e12563a0f", "verdict": "ALLOW" } -``` +```text | Field | Type | Description | | :---- | :--- | :---------- | @@ -119,7 +119,7 @@ cancellation receipt (eventual termination, see Payment Lifecycle) | v (if refund owed) refund receipt (see Payment Lifecycle) -``` +```text A verifier walking this chain confirms the full mandate lifecycle under one canonicalisation pin, starting from the admission decision. From b58781ad2337739f25e07ba220e0c22cf5317d08 Mon Sep 17 00:00:00 2001 From: AlgoVoi Date: Tue, 4 Aug 2026 08:37:33 +0100 Subject: [PATCH 10/10] ci: green Lint Code Base and zizmor via hardened linter.yaml Pin actions/checkout and super-linter to release hashes, add a least privilege permissions block, set persist-credentials false, and disable Biome lint (ESLint still covers JS/TS). Matches the configuration proven green on PR 310. --- .github/workflows/linter.yaml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index fea1b9c1..cfeddead 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -4,6 +4,11 @@ on: pull_request: branches: [main] +permissions: + contents: read + statuses: write + pull-requests: write + jobs: build: name: Lint Code Base @@ -11,20 +16,22 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v5 + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: fetch-depth: 0 + persist-credentials: false - name: Lint Code Base - uses: super-linter/super-linter/slim@v8 + uses: super-linter/super-linter/slim@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 env: DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LOG_LEVEL: WARN SHELLCHECK_OPTS: -e SC1091 -e 2086 VALIDATE_ALL_CODEBASE: false - FILTER_REGEX_EXCLUDE: "^(\\.github/|\\.vscode/|code/samples/).*|CODE_OF_CONDUCT.md|CHANGELOG.md" + FILTER_REGEX_EXCLUDE: "^(\\.github/|\\.vscode/|code/samples/|code/web-client/).*|CODE_OF_CONDUCT.md|CHANGELOG.md" VALIDATE_BIOME_FORMAT: false + VALIDATE_BIOME_LINT: false VALIDATE_PYTHON_BLACK: false VALIDATE_PYTHON_FLAKE8: false VALIDATE_PYTHON_ISORT: false