Skip to content

Commit 5500e94

Browse files
authored
Merge pull request #112 from peacprotocol/release/v0.9.14
feat: receipt media type peac.receipt/0.9, single-header JWS
2 parents 89de929 + 458a2a8 commit 5500e94

File tree

133 files changed

+2138
-3938
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+2138
-3938
lines changed

.github/workflows/ci-lite.yml

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,15 @@ jobs:
2828
- name: Setup Node.js 20
2929
uses: actions/setup-node@v4
3030
with:
31-
node-version: 20
31+
node-version: '20.10.0'
3232
cache: 'pnpm'
3333

3434
- name: Install dependencies
3535
run: pnpm install --frozen-lockfile
3636

37+
- name: Domain guard
38+
run: bash -euxo pipefail scripts/guard.sh
39+
3740
- name: Format check
3841
run: |
3942
echo "Prettier format check..."
@@ -68,13 +71,32 @@ jobs:
6871
# Core package tests (should be stable)
6972
pnpm --filter @peac/core test || echo "::warning::Core tests had issues"
7073
71-
# Discovery tests (should be stable)
74+
# Discovery tests (should be stable)
7275
pnpm --filter @peac/disc test || echo "::warning::Discovery tests had issues"
7376
74-
- name: Leak check (crawler)
77+
- name: Build core (needed for bench)
78+
run: pnpm --filter @peac/core build
79+
80+
- name: Performance gate
81+
run: |
82+
echo "Running performance verification..."
83+
OUT=$(pnpm -w exec tsx scripts/bench-verify.ts)
84+
echo "$OUT"
85+
P95=$(echo "$OUT" | sed -n 's/^P95:[[:space:]]*\([0-9]\+\(\.[0-9]\+\)\?\).*/\1/p')
86+
if [ -z "$P95" ]; then
87+
echo "::error::No P95 metric found"; exit 1
88+
fi
89+
# Use awk for float comparison
90+
if awk -v p95="$P95" 'BEGIN{ if (p95+0 > 5.0) exit 1 }'; then
91+
echo "✅ P95=$P95 ms ≤ 5ms"
92+
else
93+
echo "::error::P95=$P95 ms exceeds 5ms budget"; exit 1
94+
fi
95+
96+
- name: Core packages validation
7597
run: |
76-
echo "Checking for open handles in crawler tests..."
77-
pnpm --filter @peac/crawler exec jest --config jest.config.ts --detectOpenHandles --runInBand || echo "::warning::Crawler has open handles - investigate async cleanup"
98+
echo "Core packages post-build validation completed"
99+
echo "Crawler archived - no longer active in v0.9.14 zero-BC release"
78100
79101
ci-lite-summary:
80102
name: CI Lite Summary

.github/workflows/leak-check.yml

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
name: Leak Check - Core & Crawler
1+
name: Leak Check - Core Only
22

33
on:
44
pull_request:
55
paths:
66
- 'packages/core/**'
7-
- 'packages/crawler/**'
87
branches: [main]
98

109
env:
@@ -34,22 +33,17 @@ jobs:
3433
- name: Install dependencies
3534
run: pnpm install --frozen-lockfile
3635

37-
- name: Build core and crawler
36+
- name: Build core
3837
run: |
3938
pnpm --filter @peac/core build
40-
pnpm --filter @peac/crawler build
4139
4240
- name: Check for open handles (core)
4341
run: |
4442
echo "Checking core package for open handles..."
4543
pnpm --filter @peac/core exec jest --detectOpenHandles --runInBand --passWithNoTests || echo "::warning::Core has open handles"
4644
47-
- name: Check for open handles (crawler)
48-
run: |
49-
echo "Checking crawler package for open handles..."
50-
pnpm --filter @peac/crawler exec jest --config jest.config.ts --detectOpenHandles --runInBand || echo "::warning::Crawler has open handles"
51-
5245
- name: Summary
5346
run: |
54-
echo "Leak check completed for core/crawler changes"
47+
echo "Leak check completed for core changes"
48+
echo "Note: Crawler archived in v0.9.14 zero-BC release"
5549
echo "Any open handles will be shown as warnings above"

.github/workflows/nightly.yml

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,19 @@ jobs:
3838
- name: Build all packages
3939
run: pnpm -w build
4040

41-
- name: Run complete test suite (excluding crawler)
41+
- name: Run complete test suite
4242
env:
4343
NODE_ENV: test
4444
PAYMENT_PROVIDER: mock
4545
PEAC_WEBHOOK_SECRET: test_secret
4646
run: |
47-
echo "Running complete test suite with coverage (excluding crawler)..."
47+
echo "Running complete test suite with coverage..."
4848
pnpm run ci:test:unit
4949
50-
- name: Crawler system tests with coverage
50+
- name: Core packages validation
5151
run: |
52-
echo "Running crawler tests with coverage..."
53-
pnpm run ci:test:crawler
52+
echo "Core packages test coverage completed"
53+
echo "Crawler archived in v0.9.14 zero-BC release"
5454
5555
- name: Upload coverage reports
5656
uses: codecov/codecov-action@v3
@@ -78,29 +78,41 @@ jobs:
7878
echo "Running integration tests..."
7979
8080
# MCP server integration (TS entrypoint → run via tsx)
81-
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"peac-receipts","version":"0.9.12.1"}}}' | \
82-
timeout 5s pnpm -w exec tsx packages/adapters/mcp/server.ts || echo "MCP test completed"
81+
if [ -f "packages/adapters/mcp/server.ts" ]; then
82+
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"peac-receipts","version":"0.9.12.1"}}}' | \
83+
timeout 5s pnpm -w exec tsx packages/adapters/mcp/server.ts || echo "MCP test completed"
84+
else
85+
echo "MCP adapter archived in v0.9.14 - skipping MCP integration test"
86+
fi
8387
8488
# OpenAI functions file exists & has tools
85-
node -e "
86-
const funcs = require('./packages/adapters/openai/functions.json');
87-
if (!funcs.functions || funcs.functions.length < 4) throw new Error('Missing OpenAI functions');
88-
console.log('OpenAI functions validated:', funcs.functions.length);
89-
"
89+
if [ -f "packages/adapters/openai/functions.json" ]; then
90+
node -e "
91+
const funcs = require('./packages/adapters/openai/functions.json');
92+
if (!funcs.functions || funcs.functions.length < 4) throw new Error('Missing OpenAI functions');
93+
console.log('OpenAI functions validated:', funcs.functions.length);
94+
"
95+
else
96+
echo "OpenAI adapter archived in v0.9.14 - skipping OpenAI functions validation"
97+
fi
9098
9199
# Enhanced schema spot-checks (match actual property names)
92-
node -e "
93-
const receipt = require('./schemas/receipt.v1.1.json');
94-
const discovery = require('./schemas/discovery.v1.1.json');
95-
const purge = require('./schemas/purge.v1.0.json');
96-
97-
const has = (o,p) => p.split('.').reduce((x,k)=>x && k in x ? x[k] : undefined, o) !== undefined;
98-
99-
if (!has(receipt, 'properties.verification')) throw new Error('Missing verification in receipt schema');
100-
if (!has(receipt, 'properties.audit_chain')) throw new Error('Missing audit_chain in receipt schema');
101-
if (!has(discovery, 'properties.crawler_verification'))throw new Error('Missing crawler_verification in discovery schema');
102-
console.log('All enhanced schemas validated');
103-
"
100+
if [ -f "schemas/receipt.v1.1.json" ] && [ -f "schemas/discovery.v1.1.json" ] && [ -f "schemas/purge.v1.0.json" ]; then
101+
node -e "
102+
const receipt = require('./schemas/receipt.v1.1.json');
103+
const discovery = require('./schemas/discovery.v1.1.json');
104+
const purge = require('./schemas/purge.v1.0.json');
105+
106+
const has = (o,p) => p.split('.').reduce((x,k)=>x && k in x ? x[k] : undefined, o) !== undefined;
107+
108+
if (!has(receipt, 'properties.verification')) throw new Error('Missing verification in receipt schema');
109+
if (!has(receipt, 'properties.audit_chain')) throw new Error('Missing audit_chain in receipt schema');
110+
// Note: crawler_verification check removed - crawler archived in v0.9.14
111+
console.log('All enhanced schemas validated');
112+
"
113+
else
114+
echo "Legacy schemas archived in v0.9.14 - skipping schema validation (using core types in packages/receipts/src/types.ts)"
115+
fi
104116
105117
cross-runtime-matrix:
106118
name: Cross-Runtime Tests (${{ matrix.runtime }})

.github/workflows/publish.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# .github/workflows/publish.yml
2+
name: Publish (manual)
3+
4+
on:
5+
workflow_dispatch:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
publish:
12+
runs-on: ubuntu-latest
13+
env:
14+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- uses: actions/setup-node@v4
19+
with:
20+
node-version: '22'
21+
registry-url: 'https://registry.npmjs.org'
22+
23+
- uses: pnpm/action-setup@v4
24+
with:
25+
version: 9
26+
27+
- name: Install deps
28+
run: pnpm -w install --frozen-lockfile
29+
30+
- name: Build & test
31+
run: pnpm -w build && pnpm -w test
32+
33+
- name: Configure npm auth
34+
run: |
35+
echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > ~/.npmrc
36+
pnpm config set publish-branch "main|master|release/.*"
37+
38+
- name: Publish selected packages
39+
run: |
40+
pnpm -r \
41+
--filter @peac/core \
42+
--filter @peac/receipts \
43+
--filter @peac/pref \
44+
--filter @peac/disc \
45+
--filter @peac/pay402 \
46+
--filter @peac/sdk \
47+
publish --access public --no-git-checks
48+
49+
- name: Verify versions
50+
run: |
51+
pnpm view @peac/core version
52+
pnpm view @peac/sdk version

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
20
1+
20.10.0

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ All notable changes to PEAC Protocol will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.9.14] - 2025-09-27
9+
10+
### Changed
11+
12+
- **Wire format v0.9.14**: Simplified JWS header with `typ: "peac.receipt/0.9"`
13+
- **Single header**: Only `PEAC-Receipt` header (removed `peac-version` header)
14+
- **Receipt fields**: Use `iat` (Unix seconds) instead of `issued_at`, `payment.scheme` instead of `payment.rail`
15+
- **Core exports**: New `signReceipt()`, `verifyReceipt()` functions with v0.9.14 format
16+
- **Performance**: Sub-1ms p95 verification target with benchmark script
17+
18+
### Added
19+
20+
- `packages/core/src/b64.ts`: Base64url utilities
21+
- `scripts/bench-verify.ts`: Performance benchmark with p95 metrics
22+
- `tests/golden/generate-vectors.ts`: 120+ test vectors generator
23+
- `scripts/assert-core-exports.mjs`: Build output validation
24+
- `scripts/guard.sh`: Safety checks for dist imports and field regressions
25+
26+
### Deprecated
27+
28+
- `verify()`: Use `verifyReceipt()` instead
29+
- `verifyBulk()`: Use `verifyReceipt()` in a loop
30+
831
## [0.9.13.2] - 2025-09-17
932

1033
Intent: Zero-friction local enforcement/verification via a loopback sidecar.

README.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# PEAC Protocol
22

33
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
4-
[![Status](https://img.shields.io/badge/status-0.9.13--stable-green.svg)](https://github.com/peacprotocol/peac/releases)
4+
[![Status](https://img.shields.io/badge/status-0.9.14--stable-green.svg)](https://github.com/peacprotocol/peac/releases)
55
[![CI-Lite](https://github.com/peacprotocol/peac/actions/workflows/ci-lite.yml/badge.svg)](https://github.com/peacprotocol/peac/actions/workflows/ci-lite.yml)
66
[![CodeQL](https://github.com/peacprotocol/peac/actions/workflows/codeql.yml/badge.svg)](https://github.com/peacprotocol/peac/actions/workflows/codeql.yml)
77

@@ -38,10 +38,10 @@ Autonomous clients need predictable, auditable policy and trust rails. With well
3838
## At a glance
3939

4040
- **Discovery:** `/.well-known/peac.txt` (fallback `/peac.txt`)
41-
- **Wire version:** `0.9.13` (set header `peac-version: 0.9.13`)
42-
- **Headers:** `PEAC-Receipt`, `peac-version`; parsers MUST treat header names case-insensitively
41+
- **Wire version:** `0.9.14` (JWS header `typ: "peac.receipt/0.9"`)
42+
- **Headers:** Single `PEAC-Receipt` header; parsers MUST treat header names case-insensitively
4343
- **Media:** `application/peac+json` (content), `application/problem+json` (errors), `application/jwk-set+json` (JWKS)
44-
- **Receipts:** detached JWS (`typ: application/peac-receipt+jws`) using JCS
44+
- **Receipts:** JWS with `typ: "peac.receipt/0.9"`, `iat` field (Unix seconds), `payment.scheme`
4545
- **Trust:** UDA (JWT with `typ: "JWT"`), DPoP proofs bound to `cnf.jkt`, optional agent attestation header
4646
- **Conformance:** Levels L0-L4; see [docs/conformance.md](docs/conformance.md)
4747

@@ -87,15 +87,15 @@ npx peac validate peac.txt # Expected: Valid PEAC 0.9.13 policy
8787
curl -I https://your-domain/.well-known/peac.txt # check ETag + Cache-Control
8888
```
8989

90-
Tips: emit `PEAC-Receipt`, `peac-version`; be case-insensitive on read. Start in simulation via `PEAC_MODE=simulation`.
90+
Tips: emit `PEAC-Receipt` header; be case-insensitive on read. Start in simulation via `PEAC_MODE=simulation`.
9191
Common pitfalls: invalid schema returns HTTP Problem Details (RFC 7807) 400.
9292

9393
---
9494

9595
## Core surfaces
9696

9797
- **Discovery**: `/.well-known/peac.txt` (fallback `/peac.txt`)
98-
- **Headers**: `peac-version`, `PEAC-Receipt`, `peac-agent-attestation`, etc.
98+
- **Headers**: `PEAC-Receipt`, `peac-agent-attestation`, etc.
9999
- **Errors**: HTTP Problem Details (RFC 7807) with stable catalog
100100
- **Caching**: strong `ETag`, sensible `Cache-Control` for `peac.txt` and well-known endpoints
101101

@@ -111,10 +111,10 @@ Common pitfalls: invalid schema returns HTTP Problem Details (RFC 7807) 400.
111111
| Attribution and provenance | Required attribution formats and verify-only provenance chains via adapters. |
112112
| Negotiation and settlement | Programmatic terms, adapters for payment rails (**x402**, **L402**, Stripe), and DPoP-bound receipts. |
113113
| Agent trust rails | UDA (OAuth Device Flow), DPoP proof-of-possession, agent attestation verification for autonomous coordination. |
114-
| Receipts v2 | Detached JWS with `typ: "application/peac-receipt+jws"`; JCS canonicalization for verifiable settlements. |
114+
| Receipts v2 | JWS with `typ: "peac.receipt/0.9"`; JCS canonicalization for verifiable settlements. |
115115
| JWKS management | 30-day key rotation, 7-day grace periods, `application/jwk-set+json` with ETag caching. |
116116
| Adapters and interop | Bridges for MCP, A2A, payment rails such as **x402**, **L402**, and Stripe, Chainlink, peaq, and any payment provider via adapter. Extend via PEIPs. |
117-
| HTTP semantics | `PEAC-Receipt`, `peac-version` headers, RFC9457 Problem Details, and idempotency guidance. |
117+
| HTTP semantics | `PEAC-Receipt` header, RFC9457 Problem Details, and idempotency guidance. |
118118
| Conformance and tooling | L0-L4 levels, CLI validation and fixtures, and ACID-style tests. |
119119

120120
---
@@ -163,7 +163,7 @@ More examples: [docs/examples.md](docs/examples.md)
163163

164164
## Receipts (detached JWS)
165165

166-
- Media type `typ: "application/peac-receipt+jws"`
166+
- Media type `typ: "peac.receipt/0.9"`
167167
- JCS canonicalization of payload before signing
168168
- Verification via detached JWS (no payload bloat in transit)
169169

@@ -227,8 +227,7 @@ if (access.granted) {
227227
**Example API request with curl:**
228228

229229
```bash
230-
curl -X POST https://demo.peac.dev/peac/agreements \
231-
-H "peac-version: 0.9.13" \
230+
curl -X POST https://peacprotocol.org/agreements \
232231
-H "content-type: application/json" \
233232
-H "x-api-key: your-key" \
234233
-d '{
@@ -241,10 +240,9 @@ curl -X POST https://demo.peac.dev/peac/agreements \
241240
**JavaScript example:**
242241

243242
```javascript
244-
const response = await fetch('https://demo.peac.dev/peac/agreements', {
243+
const response = await fetch('https://peacprotocol.org/agreements', {
245244
method: 'POST',
246245
headers: {
247-
'peac-version': '0.9.13',
248246
'content-type': 'application/json',
249247
'x-api-key': apiKey,
250248
},
@@ -279,7 +277,7 @@ const response = await fetch('https://demo.peac.dev/peac/agreements', {
279277
"amount": "5.00",
280278
"currency": "USD",
281279
"method": "x402",
282-
"issued_at": "2025-08-16T00:00:00Z",
280+
"iat": 1723766400,
283281
"expires_at": "2025-08-17T00:00:00Z"
284282
}
285283
```
@@ -370,7 +368,7 @@ More templates are in `docs/templates.md`.
370368

371369
- 400 HTTP Problem Details (RFC 7807). Validate `peac.txt` or the negotiation body.
372370
- Missing receipt. Ensure the adapter completed settlement. On success the server can return `PEAC-Receipt` and a receipt body.
373-
- Header mismatch. Emit `PEAC-Receipt`, `peac-version`. Intermediaries may alter casing.
371+
- Header mismatch. Emit `PEAC-Receipt`. Intermediaries may alter casing.
374372
- Negotiation fails. Enable flags like `PEAC_FEATURE_NEGOTIATION=1` and start with a simulation adapter.
375373

376374
---

RELEASE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ npm audit @peac/core --audit-level=high
4343

4444
```bash
4545
# Install and verify core functionality
46-
npm install @peac/core
46+
pnpm add @peac/core
4747
node -e "
4848
import { sign, verify } from '@peac/core';
4949
console.log('✅ @peac/core imports successfully');

0 commit comments

Comments
 (0)