From 658f3ba86b5e5f00997388ffe437f0982cbef207 Mon Sep 17 00:00:00 2001 From: Greg Soucy Date: Sat, 13 Jun 2026 18:47:01 -0400 Subject: [PATCH] Publish execution receipt schemas --- public/docs/scoped-execution-settlement.html | 2 +- .../execution/execution.receipt.schema.json | 96 +++++++++++++++++++ public/schemas/execution/manifest.json | 14 +++ public/schemas/index.json | 24 ++++- scripts/sync-clas-schemas.sh | 35 ++++--- tests/execution-schema-publication.test.js | 25 +++++ 6 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 public/schemas/execution/execution.receipt.schema.json create mode 100644 public/schemas/execution/manifest.json create mode 100644 tests/execution-schema-publication.test.js diff --git a/public/docs/scoped-execution-settlement.html b/public/docs/scoped-execution-settlement.html index 98e746d..d5bc709 100644 --- a/public/docs/scoped-execution-settlement.html +++ b/public/docs/scoped-execution-settlement.html @@ -47,7 +47,7 @@ }

Selective disclosure

The public receipt contains opaque references and commitments. A verifier that is authorized to see private payment details receives a disclosure package with the original payee data, private settlement metadata, and nonce/salt. VerifyAgent or another verifier hashes the disclosed data and compares it to the public sha256: commitment while checking the settlement attestation signature.

VerifyAgent display

VerifyAgent displays separate proof cards: Execution proof for the agent/runtime signature and Settlement proof for the rail/payer/settlement authority signature. A receipt can be execution-only, execution plus settlement, or invalid when a signer tries to cover fields outside its scope.

Open demo Verify paste flow

Privacy warning

  • Do not publish settlement.stealth_address.
  • Do not publish a raw 0x... payment transaction hash as payment_ref.
  • Use an opaque settlement reference.
  • Use a sha256: payee commitment.
  • Private payment linkage is verified through selective disclosure, not by exposing payment addresses or raw transaction hashes in public receipts.
-

Schema publication

The runtime schema name is clas.execution.receipt.v1. Public schema sync for /schemas/execution/execution.receipt.schema.json is not wired in this site yet, so schema publication needs a follow-up sync. Until then, treat this page and the demo as public documentation for the receipt model.

+
diff --git a/public/schemas/execution/execution.receipt.schema.json b/public/schemas/execution/execution.receipt.schema.json new file mode 100644 index 0000000..a9113d9 --- /dev/null +++ b/public/schemas/execution/execution.receipt.schema.json @@ -0,0 +1,96 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://commandlayer.org/schemas/execution/execution.receipt.schema.json", + "title": "CLAS Execution Receipt v1", + "description": "Scoped execution and private settlement receipt for clas.execution.receipt.v1.", + "type": "object", + "additionalProperties": false, + "required": ["schema", "receipt_id", "verb", "agent", "action", "proofs"], + "properties": { + "schema": { "const": "clas.execution.receipt.v1" }, + "receipt_id": { "type": "string", "minLength": 1 }, + "parent_receipt_id": { "type": ["string", "null"], "minLength": 1 }, + "root_receipt_id": { "type": ["string", "null"], "minLength": 1 }, + "chain_id": { "type": ["string", "null"], "minLength": 1 }, + "verb": { "type": "string", "minLength": 1 }, + "agent": { "type": "string", "minLength": 1 }, + "action": { "type": "string", "minLength": 1 }, + "input": true, + "output": true, + "execution": { + "type": "object", + "additionalProperties": true, + "properties": { + "status": { "type": "string", "minLength": 1 }, + "duration_ms": { "type": "integer", "minimum": 0 } + } + }, + "settlement": { + "type": "object", + "additionalProperties": true, + "required": ["payment_ref", "payee_commitment"], + "properties": { + "payment_ref": { "type": "string", "minLength": 1 }, + "payee_commitment": { "type": "string", "pattern": "^sha256:[A-Za-z0-9+/=_:-]+$" }, + "amount": { "type": ["string", "number"] }, + "currency": { "type": "string", "minLength": 1 }, + "rail": { "type": "string", "minLength": 1 } + } + }, + "metadata": { + "type": "object", + "additionalProperties": true + }, + "proofs": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/proof" } + } + }, + "$defs": { + "proof": { + "type": "object", + "additionalProperties": false, + "required": ["type", "covers", "signer_id", "signature"], + "properties": { + "type": { "enum": ["execution", "settlement"] }, + "covers": { + "type": "array", + "minItems": 1, + "items": { "type": "string", "minLength": 1 } + }, + "canonicalization": { "type": "string", "default": "json.sorted_keys.v1" }, + "hash": { + "type": "object", + "additionalProperties": false, + "required": ["alg", "value"], + "properties": { + "alg": { "type": "string", "minLength": 1 }, + "value": { "type": "string", "minLength": 1 } + } + }, + "signer_id": { "type": "string", "minLength": 1 }, + "signature": { + "type": "object", + "additionalProperties": false, + "required": ["alg", "value"], + "properties": { + "alg": { "type": "string", "minLength": 1 }, + "kid": { "type": "string", "minLength": 1 }, + "value": { "type": "string", "minLength": 1 } + } + } + }, + "allOf": [ + { + "if": { "properties": { "type": { "const": "execution" } }, "required": ["type"] }, + "then": { "properties": { "covers": { "not": { "contains": { "const": "settlement" } } } } } + }, + { + "if": { "properties": { "type": { "const": "settlement" } }, "required": ["type"] }, + "then": { "properties": { "covers": { "contains": { "const": "settlement" } } } } + } + ] + } + } +} diff --git a/public/schemas/execution/manifest.json b/public/schemas/execution/manifest.json new file mode 100644 index 0000000..b9ec299 --- /dev/null +++ b/public/schemas/execution/manifest.json @@ -0,0 +1,14 @@ +{ + "family_id": "execution", + "family_name": "Execution Receipts", + "family_status": "live", + "version": "v1", + "schemas": [ + { + "schema": "clas.execution.receipt.v1", + "kind": "receipt", + "path": "/schemas/execution/execution.receipt.schema.json", + "description": "Scoped execution receipt with optional private settlement attestation." + } + ] +} diff --git a/public/schemas/index.json b/public/schemas/index.json index f5456c7..1ff96fb 100644 --- a/public/schemas/index.json +++ b/public/schemas/index.json @@ -6,11 +6,33 @@ "family_id": "trust-verification", "family_name": "Trust Verification v1", "family_status": "live", - "verbs": ["verify","sign","attest","authorize","approve","reject","permit","grant","authenticate","endorse"], + "verbs": [ + "verify", + "sign", + "attest", + "authorize", + "approve", + "reject", + "permit", + "grant", + "authenticate", + "endorse" + ], "request_schema_path_prefix": "/schemas/trust/", "receipt_schema_path_prefix": "/schemas/trust/", "manifest_path": "/capabilities/trust-verification/manifest.json", "source_repo_url": "https://github.com/commandlayer/commandlayer-clas" + }, + { + "family_id": "execution", + "family_name": "Execution Receipts v1", + "family_status": "live", + "receipt_schema_path_prefix": "/schemas/execution/", + "manifest_path": "/schemas/execution/manifest.json", + "schemas": [ + "clas.execution.receipt.v1" + ], + "source_repo_url": "https://github.com/commandlayer/commandlayer-clas" } ] } diff --git a/scripts/sync-clas-schemas.sh b/scripts/sync-clas-schemas.sh index 3eb3693..327528f 100755 --- a/scripts/sync-clas-schemas.sh +++ b/scripts/sync-clas-schemas.sh @@ -1,21 +1,32 @@ #!/usr/bin/env bash set -euo pipefail -SRC_ROOT="${1:-../clas/schemas/trust-verification}" -DEST_ROOT="${2:-public/schemas/trust-verification}" +SRC_BASE="${1:-../clas/schemas}" +DEST_BASE="${2:-public/schemas}" +FAMILIES=("trust-verification" "execution") -if [[ ! -d "$SRC_ROOT" ]]; then - echo "Source directory not found: $SRC_ROOT" >&2 +if [[ ! -d "$SRC_BASE" ]]; then + echo "Source directory not found: $SRC_BASE" >&2 exit 1 fi -mkdir -p "$(dirname "$DEST_ROOT")" -rm -rf "$DEST_ROOT" -mkdir -p "$DEST_ROOT" +mkdir -p "$DEST_BASE" -cp -a "$SRC_ROOT"/. "$DEST_ROOT"/ +for family in "${FAMILIES[@]}"; do + src="$SRC_BASE/$family" + dest="$DEST_BASE/$family" -echo "Synced CLAS trust-verification schemas" -echo "Source: $SRC_ROOT" -echo "Destination: $DEST_ROOT" -find "$DEST_ROOT" -type f | sort + if [[ ! -d "$src" ]]; then + echo "Source family directory not found: $src" >&2 + exit 1 + fi + + rm -rf "$dest" + mkdir -p "$dest" + cp -a "$src"/. "$dest"/ + + echo "Synced CLAS $family schemas" + echo "Source: $src" + echo "Destination: $dest" + find "$dest" -type f | sort +done diff --git a/tests/execution-schema-publication.test.js b/tests/execution-schema-publication.test.js new file mode 100644 index 0000000..1a34f99 --- /dev/null +++ b/tests/execution-schema-publication.test.js @@ -0,0 +1,25 @@ +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const test = require('node:test'); + +const schemaPath = path.join(process.cwd(), 'public', 'schemas', 'execution', 'execution.receipt.schema.json'); +const manifestPath = path.join(process.cwd(), 'public', 'schemas', 'execution', 'manifest.json'); +const indexPath = path.join(process.cwd(), 'public', 'schemas', 'index.json'); + +test('execution receipt schema is published under public schemas', () => { + const schema = JSON.parse(fs.readFileSync(schemaPath, 'utf8')); + + assert.equal(schema.properties.schema.const, 'clas.execution.receipt.v1'); + assert.equal(schema.$id, 'https://commandlayer.org/schemas/execution/execution.receipt.schema.json'); + assert.ok(schema.required.includes('proofs')); +}); + +test('execution manifest and schema index expose the execution family', () => { + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + const index = JSON.parse(fs.readFileSync(indexPath, 'utf8')); + + assert.equal(manifest.family_id, 'execution'); + assert.equal(manifest.schemas[0].path, '/schemas/execution/execution.receipt.schema.json'); + assert.ok(index.families.some((family) => family.family_id === 'execution' && family.manifest_path === '/schemas/execution/manifest.json')); +});