From 0a20ddccc869c753af3fd86477a07ec3e4118afd Mon Sep 17 00:00:00 2001 From: Greg Soucy Date: Thu, 19 Mar 2026 02:42:31 -0400 Subject: [PATCH] Tighten validation and provenance surfaces --- .github/workflows/validate.yml | 21 +++- COMPLIANCE.md | 15 +++ GOVERNANCE.md | 32 +++-- README.md | 53 +++++--- RESOLUTION.md | 29 ++++- SECURITY_PROVENANCE.md | 63 +++++++++- .../v1.0.0/commercial/authorizeagent.eth.json | 39 +++--- .../v1.0.0/commercial/checkoutagent.eth.json | 39 +++--- .../v1.0.0/commercial/purchaseagent.eth.json | 38 +++--- agents/v1.0.0/commercial/shipagent.eth.json | 39 +++--- agents/v1.0.0/commercial/verifyagent.eth.json | 18 +-- checksums.txt | 10 +- package.json | 7 +- scripts/validate-cards.mjs | 113 +++++++++++++----- 14 files changed, 357 insertions(+), 159 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 1f3fcfa..5f76fe7 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -7,7 +7,8 @@ on: branches: ["main"] jobs: - validate: + validate-current-release: + name: Validate current release flow (v1.1.0) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -19,5 +20,21 @@ jobs: - name: Install dependencies run: npm install - - name: Validate (cards + checksums + typecheck) + - name: Validate current release flow run: npm run validate + + validate-legacy-compatibility: + name: Validate legacy compatibility line (v1.0.0) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install dependencies + run: npm install + + - name: Validate legacy compatibility cards + run: npm run validate:legacy diff --git a/COMPLIANCE.md b/COMPLIANCE.md index 84b885d..8994618 100644 --- a/COMPLIANCE.md +++ b/COMPLIANCE.md @@ -1,5 +1,7 @@ # Compliance — Agent Cards +## Current release line (`v1.1.0`) + Agent Cards v1.1.0 is compliant when: - current cards validate under `schemas/v1.1.0/agent.card.schema.json` @@ -7,3 +9,16 @@ Agent Cards v1.1.0 is compliant when: - current cards use no `_shared` references - Commons and Commercial bindings are flat and direct - checksums cover release artifacts including `dist-pin/agent-cards/v1.1.0/` +- the current release flow passes via `npm run validate` + +## Legacy compatibility line (`v1.0.0`) + +`v1.0.0` is retained as an archival and compatibility line, not as the normative compliance surface. + +Known preservation limits: + +- the line is still structured around `schemas/v1.0.0/_shared/` +- the legacy card schema permits looser metadata and URL conventions than the current line +- `meta.pgp_fingerprint` may appear in legacy cards as historical metadata, but it is not part of the v1.1.0 compliance contract +- legacy commercial cards intentionally omit `schemas_mirror` where the repository never recorded a canonical historical mirror URL; placeholder values were removed rather than normalized into fake history +- maintainers may run `npm run validate:legacy` to ensure the archive remains internally consistent, but passing that command does not make `v1.0.0` the release authority diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 348d560..8f398e3 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -2,15 +2,31 @@ ## Stewardship -Founding steward: `commandlayer.eth` +- Repository steward: `commandlayer.eth` +- Repository surface: `https://github.com/commandlayer/agent-cards` +- Public documentation surface: `https://commandlayer.org/agent-cards` -## Current release stance +## Release authority -- Agent Cards current line: `v1.1.0` -- Commons current line: `v1.1.0` -- Commercial current line: `v1.1.0` -- Agent Cards v1.1.0 is flat and direct by policy +The canonical Agent Cards release line is `v1.1.0`. -## Approval rule +That authority is exercised through the current repository state and its release artifacts, not through the preserved legacy line. In practice, the authoritative release surface is the combination of: -A canonical release change is acceptable only when cards, schemas, manifest, discovery, checksums, and dist-pin are updated together and validation passes. +- current cards under `agents/v1.1.0/` +- current discovery descriptors under `.well-known/` +- current schemas under `schemas/v1.1.0/` +- `meta/manifest.json` as the release index +- `checksums.txt` as the deterministic digest ledger for published artifacts +- `dist-pin/agent-cards/v1.1.0/` as the repinnable release bundle + +## Decision process + +A release-affecting change is expected to update the repository as a coherent set. That means cards, discovery, metadata, checksums, and any repinning bundle must stay aligned. + +`npm run validate` is the default gate for the current release line. `npm run validate:legacy` exists to keep archival material internally coherent, but it is not the primary release gate. + +## Legacy policy + +`v1.0.0` remains in the repository for compatibility and historical inspection. + +It is preserved with known structural limitations. Governance does not treat that line as the normative model for new releases, new schema conventions, or current provenance expectations. diff --git a/README.md b/README.md index 4423456..f21bae0 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,26 @@ Agent Cards v1.1.0 is intentionally flat: - current cards bind **directly** to `commandlayer.org` mirror URLs - current v1.1.0 uses **no `_shared`** +## Validation and release trust + +The default reviewer path is the current canonical line. + +```bash +npm install +npm run validate +``` + +Validation commands are intentionally split by authority surface: + +- `npm run validate` — release-facing validation for the current canonical line; runs current discovery validation, current v1.1.0 card validation, checksum verification, and typecheck +- `npm run validate:current` — current discovery + current v1.1.0 cards only +- `npm run validate:legacy` — archival/compatibility validation for `agents/v1.0.0/` +- `npm run validate:checksums` — verifies `checksums.txt` against tracked release artifacts +- `npm run validate:release` — explicit alias for the full current release flow used by CI +- `npm run validate:cards` — runs both current and legacy card schema/path validation when a maintainer wants a full repository sweep + +`npm run validate` is the command reviewers should trust most because it centers the current release line instead of the compatibility archive. + ## How card bindings work For `v1.1.0`: @@ -45,6 +65,20 @@ For `v1.1.0`: `https://commandlayer.org/schemas/v1.1.0/commercial//.request.schema.json` +## Legacy preservation scope (`v1.0.0`) + +`v1.0.0` remains in the repository for compatibility and archival inspection. It is not the normative line. + +Known limitations of the legacy line are preserved explicitly: + +- `v1.0.0` uses the older `_shared` schema layout +- the legacy schema is materially looser than `v1.1.0` +- legacy cards may carry provenance-adjacent metadata such as `meta.pgp_fingerprint` that is no longer part of the current card schema +- legacy commercial cards no longer claim mirror URLs where no canonical historical mirror binding was recorded; those placeholder URLs were removed instead of replaced with invented values +- legacy validation exists to keep the archive coherent, not to define the current release story + +See `COMPLIANCE.md` and `SECURITY_PROVENANCE.md` for the compliance and provenance implications of that split. + ## Repository layout ```text @@ -109,27 +143,10 @@ agent-cards/ } ``` -## Validation - -```bash -npm install -npm run validate -``` - -Validation checks: - -- descriptor schema conformance -- exact authoritative v1.1.0 card presence -- version / path / `$schema` / `$id` alignment -- direct Commons and Commercial source URL patterns -- direct `commandlayer.org` mirror URL patterns -- entry URI correctness -- checksum determinism across cards, schemas, meta, discovery, and dist-pin - ## Release artifacts - `meta/manifest.json` — authoritative release index - `.well-known/agent.json` — current discovery descriptor - `.well-known/agent-cards-v1.1.0.json` — versioned descriptor - `dist-pin/agent-cards/v1.1.0/` — publish bundle for repinning -- `checksums.txt` — deterministic artifact digests +- `checksums.txt` — deterministic artifact digests for cards, schemas, discovery, metadata, and pin bundle contents diff --git a/RESOLUTION.md b/RESOLUTION.md index e142d24..4a4c74e 100644 --- a/RESOLUTION.md +++ b/RESOLUTION.md @@ -1,5 +1,28 @@ # Resolution Log — Agent Cards -| Date | Agent Name(s) | Action | Reason | Resolution | Approver(s) | -|---|---|---|---|---|---| -| 2026-03-19 | `analyzeagent.eth`, `classifyagent.eth`, `cleanagent.eth`, `convertagent.eth`, `describeagent.eth`, `explainagent.eth`, `fetchagent.eth`, `formatagent.eth`, `parseagent.eth`, `summarizeagent.eth`, `authorizeagent.eth`, `checkoutagent.eth`, `purchaseagent.eth`, `shipagent.eth`, `verifyagent.eth` | Updated | Post-publish alignment migration for Agent Cards v1.1.0. | Removed current-line `_shared` usage, switched v1.1.0 cards to direct flat Commons and Commercial schema URL bindings, regenerated manifest/discovery/checksums, and refreshed the v1.1.0 pin bundle. | `commandlayer.eth` | +## Purpose + +This log records formal release-affecting decisions for the Agent Cards repository. It is meant to explain why a release-line change was made, what artifacts it touched, and how to interpret the repository state after the change. + +## Logging scope + +- Formal decision logging began on **2026-03-19**. +- Earlier repository changes may exist without entries here. +- Absence of an older entry should be read as "not logged in this file," not as evidence that no earlier decision occurred. + +## How to read entries + +Each entry captures: + +- the decision date +- the release-affecting action that was taken +- the rationale for taking it +- the artifacts directly affected + +## Entries + +### 2026-03-19 — Current-line release validation and provenance clarification + +- **Decision:** Make the default validation path release-facing for `v1.1.0`, contain legacy validation behind an explicit compatibility command, remove placeholder mirror URLs from legacy commercial cards, and expand governance/provenance documentation to match the actual release model. +- **Rationale:** The repository's current authority line is `v1.1.0`. The default validation path and supporting documentation needed to reflect that reality directly. Legacy artifacts are still preserved, but their limitations needed to be explicit so they do not distort reviewer perception. +- **Affected artifacts:** `package.json`, `scripts/validate-cards.mjs`, `.github/workflows/validate.yml`, `agents/v1.0.0/commercial/*.json`, `README.md`, `COMPLIANCE.md`, `GOVERNANCE.md`, `SECURITY_PROVENANCE.md`, and `checksums.txt`. diff --git a/SECURITY_PROVENANCE.md b/SECURITY_PROVENANCE.md index 9f78bac..e702061 100644 --- a/SECURITY_PROVENANCE.md +++ b/SECURITY_PROVENANCE.md @@ -1,10 +1,61 @@ # Security & Provenance — Agent Cards -Agent Cards prove identity and routing intent. They do not prove execution success. +Agent Cards express identity, routing, and release bindings. They do not prove execution success, payment settlement, or runtime behavior by themselves. -For v1.1.0, provenance expectations are: +## Current provenance model (`v1.1.0`) -- direct upstream schema source URLs -- direct commandlayer.org mirror URLs -- deterministic repo checksums -- mirrored publish bundle under `dist-pin/agent-cards/v1.1.0/` +For the current line, provenance is repository- and release-artifact-based. + +The trust anchors are: + +- the Git repository state for `commandlayer/agent-cards` +- the canonical current card set under `agents/v1.1.0/` +- the current discovery descriptors under `.well-known/` +- `meta/manifest.json` as the release index that names the current line and its bindings +- semver-pinned upstream schema URLs in each current card +- `checksums.txt`, which deterministically covers cards, schemas, metadata, discovery, and `dist-pin/agent-cards/v1.1.0/` +- the mirrored release bundle under `dist-pin/agent-cards/v1.1.0/` + +In other words: current provenance is a combination of repository state, manifest/discovery metadata, semver-pinned schema bindings, and release checksums. + +## Direct answer on the PGP question + +### Was `pgp_fingerprint` intentionally removed? + +Yes. `pgp_fingerprint` is present in legacy `v1.0.0` cards as historical metadata, but it is intentionally not part of the `v1.1.0` card schema. + +### What replaced it as the provenance anchor? + +No single in-card field replaced it one-for-one. + +For `v1.1.0`, provenance is anchored primarily by the repository release surface: + +- the card file path and `$id` +- the versioned schema contract +- the manifest and discovery descriptors +- the semver-pinned schema source and mirror URLs +- the deterministic checksum ledger +- the repinnable dist bundle + +### Why is it no longer part of the current card model? + +The current line treats provenance as a release-level property rather than as a per-card PGP assertion. That keeps the current card schema focused on routing and schema bindings, while the repository, manifest, and checksum set carry the integrity story. + +### Tradeoff + +This is a different model, not a stronger in-card cryptographic claim. + +Compared with a field-level `pgp_fingerprint`, the current line is clearer about what the repository actually publishes and verifies, but it does not provide a standalone per-card PGP attestation inside card metadata. Reviewers should therefore read current provenance as release-bundle provenance, not as embedded card-signature provenance. + +## Legacy line (`v1.0.0`) + +The legacy line mixes routing metadata with provenance-adjacent metadata more loosely. + +Important limitations: + +- it uses the older `_shared` layout +- the legacy schema allows more permissive metadata fields +- some provenance-adjacent fields, including `meta.pgp_fingerprint`, are historical artifacts of that model +- legacy commercial cards no longer advertise placeholder mirror URLs where no canonical historical value was recorded + +That legacy material is retained for compatibility and inspection. It should not be interpreted as the current normative provenance design. diff --git a/agents/v1.0.0/commercial/authorizeagent.eth.json b/agents/v1.0.0/commercial/authorizeagent.eth.json index f213261..c9fdeac 100644 --- a/agents/v1.0.0/commercial/authorizeagent.eth.json +++ b/agents/v1.0.0/commercial/authorizeagent.eth.json @@ -1,51 +1,54 @@ { "$schema": "https://commandlayer.org/agent-cards/schemas/v1.0.0/_shared/agent.card.base.schema.json", "$id": "https://commandlayer.org/agent-cards/agents/v1.0.0/commercial/authorizeagent.eth.json", - "id": "authorizeagent.eth", "slug": "authorizeagent", "display_name": "Authorize Agent", "description": "Commercial reference agent for the authorize verb. Creates and manages payment authorizations or mandates without immediate capture.", - "owner": "commandlayer.eth", "ens": "authorizeagent.eth", "version": "1.0.0", "status": "protocol_reference", "class": "commercial", - - "implements": ["authorize"], - + "implements": [ + "authorize" + ], "schemas": { "request": "https://commandlayer.org/schemas/v1.0.0/commercial/authorize/requests/authorize.request.schema.json", "receipt": "https://commandlayer.org/schemas/v1.0.0/commercial/authorize/receipts/authorize.receipt.schema.json" }, - "schemas_mirror": { - "request": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/authorize/requests/authorize.request.schema.json", - "receipt": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/authorize/receipts/authorize.receipt.schema.json" - }, - "entry": "x402://authorizeagent.eth/authorize/v1.0.0", - "capabilities": { "operations": [ "create_authorization", "refresh_authorization", "cancel_authorization" ], - "input_types": ["application/json"], - "output_types": ["application/json"] + "input_types": [ + "application/json" + ], + "output_types": [ + "application/json" + ] }, - "meta": { "publisher": "CommandLayer", "contact": "dev@commandlayer.org", "pgp_fingerprint": "5016 D496 9F38 22B2 C5A2 FA40 99A2 6950 197D AB0A", - "tags": ["authorize", "commercial", "payments", "mandates"] + "tags": [ + "authorize", + "commercial", + "payments", + "mandates" + ], + "notes": [ + "Legacy commercial v1.0.0 cards are preserved without mirror URLs because no canonical IPFS mirror binding was recorded for this line." + ] }, - - "networks": ["eip155:1"], + "networks": [ + "eip155:1" + ], "license": "Apache-2.0", - "created_at": "2025-11-22T00:00:00Z", "updated_at": "2025-11-22T00:00:00Z" } diff --git a/agents/v1.0.0/commercial/checkoutagent.eth.json b/agents/v1.0.0/commercial/checkoutagent.eth.json index a8ba9de..8eea468 100644 --- a/agents/v1.0.0/commercial/checkoutagent.eth.json +++ b/agents/v1.0.0/commercial/checkoutagent.eth.json @@ -1,31 +1,23 @@ { "$schema": "https://commandlayer.org/agent-cards/schemas/v1.0.0/_shared/agent.card.base.schema.json", "$id": "https://commandlayer.org/agent-cards/agents/v1.0.0/commercial/checkoutagent.eth.json", - "id": "checkoutagent.eth", "slug": "checkoutagent", "display_name": "Checkout Agent", "description": "Commercial reference agent for the checkout verb. Turns carts into canonical orders and payment intents using checkout.request and checkout.receipt schemas.", - "owner": "commandlayer.eth", "ens": "checkoutagent.eth", "version": "1.0.0", "status": "protocol_reference", "class": "commercial", - - "implements": ["checkout"], - + "implements": [ + "checkout" + ], "schemas": { "request": "https://commandlayer.org/schemas/v1.0.0/commercial/checkout/requests/checkout.request.schema.json", "receipt": "https://commandlayer.org/schemas/v1.0.0/commercial/checkout/receipts/checkout.receipt.schema.json" }, - "schemas_mirror": { - "request": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/checkout/requests/checkout.request.schema.json", - "receipt": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/checkout/receipts/checkout.receipt.schema.json" - }, - "entry": "x402://checkoutagent.eth/checkout/v1.0.0", - "capabilities": { "operations": [ "create_order", @@ -33,20 +25,31 @@ "resolve_shipping", "initiate_payment_intent" ], - "input_types": ["application/json"], - "output_types": ["application/json"] + "input_types": [ + "application/json" + ], + "output_types": [ + "application/json" + ] }, - "meta": { "publisher": "CommandLayer", "contact": "dev@commandlayer.org", "pgp_fingerprint": "5016 D496 9F38 22B2 C5A2 FA40 99A2 6950 197D AB0A", - "tags": ["checkout", "commercial", "orders", "payments"] + "tags": [ + "checkout", + "commercial", + "orders", + "payments" + ], + "notes": [ + "Legacy commercial v1.0.0 cards are preserved without mirror URLs because no canonical IPFS mirror binding was recorded for this line." + ] }, - - "networks": ["eip155:1"], + "networks": [ + "eip155:1" + ], "license": "Apache-2.0", - "created_at": "2025-11-22T00:00:00Z", "updated_at": "2025-11-22T00:00:00Z" } diff --git a/agents/v1.0.0/commercial/purchaseagent.eth.json b/agents/v1.0.0/commercial/purchaseagent.eth.json index 6433368..e7f1412 100644 --- a/agents/v1.0.0/commercial/purchaseagent.eth.json +++ b/agents/v1.0.0/commercial/purchaseagent.eth.json @@ -1,51 +1,53 @@ { "$schema": "https://commandlayer.org/agent-cards/schemas/v1.0.0/_shared/agent.card.base.schema.json", "$id": "https://commandlayer.org/agent-cards/agents/v1.0.0/commercial/purchaseagent.eth.json", - "id": "purchaseagent.eth", "slug": "purchaseagent", "display_name": "Purchase Agent", "description": "Commercial reference agent for the purchase verb. Executes direct purchases without complex cart semantics, using purchase.request and purchase.receipt.", - "owner": "commandlayer.eth", "ens": "purchaseagent.eth", "version": "1.0.0", "status": "protocol_reference", "class": "commercial", - - "implements": ["purchase"], - + "implements": [ + "purchase" + ], "schemas": { "request": "https://commandlayer.org/schemas/v1.0.0/commercial/purchase/requests/purchase.request.schema.json", "receipt": "https://commandlayer.org/schemas/v1.0.0/commercial/purchase/receipts/purchase.receipt.schema.json" }, - "schemas_mirror": { - "request": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/purchase/requests/purchase.request.schema.json", - "receipt": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/purchase/receipts/purchase.receipt.schema.json" - }, - "entry": "x402://purchaseagent.eth/purchase/v1.0.0", - "capabilities": { "operations": [ "execute_purchase", "apply_pricing", "record_order" ], - "input_types": ["application/json"], - "output_types": ["application/json"] + "input_types": [ + "application/json" + ], + "output_types": [ + "application/json" + ] }, - "meta": { "publisher": "CommandLayer", "contact": "dev@commandlayer.org", "pgp_fingerprint": "5016 D496 9F38 22B2 C5A2 FA40 99A2 6950 197D AB0A", - "tags": ["purchase", "commercial", "payments"] + "tags": [ + "purchase", + "commercial", + "payments" + ], + "notes": [ + "Legacy commercial v1.0.0 cards are preserved without mirror URLs because no canonical IPFS mirror binding was recorded for this line." + ] }, - - "networks": ["eip155:1"], + "networks": [ + "eip155:1" + ], "license": "Apache-2.0", - "created_at": "2025-11-22T00:00:00Z", "updated_at": "2025-11-22T00:00:00Z" } diff --git a/agents/v1.0.0/commercial/shipagent.eth.json b/agents/v1.0.0/commercial/shipagent.eth.json index 8b55a25..ae52776 100644 --- a/agents/v1.0.0/commercial/shipagent.eth.json +++ b/agents/v1.0.0/commercial/shipagent.eth.json @@ -1,31 +1,23 @@ { "$schema": "https://commandlayer.org/agent-cards/schemas/v1.0.0/_shared/agent.card.base.schema.json", "$id": "https://commandlayer.org/agent-cards/agents/v1.0.0/commercial/shipagent.eth.json", - "id": "shipagent.eth", "slug": "shipagent", "display_name": "Ship Agent", "description": "Commercial reference agent for the ship verb. Orchestrates label creation, tracking, and shipment status for orders.", - "owner": "commandlayer.eth", "ens": "shipagent.eth", "version": "1.0.0", "status": "protocol_reference", "class": "commercial", - - "implements": ["ship"], - + "implements": [ + "ship" + ], "schemas": { "request": "https://commandlayer.org/schemas/v1.0.0/commercial/ship/requests/ship.request.schema.json", "receipt": "https://commandlayer.org/schemas/v1.0.0/commercial/ship/receipts/ship.receipt.schema.json" }, - "schemas_mirror": { - "request": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/ship/requests/ship.request.schema.json", - "receipt": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/ship/receipts/ship.receipt.schema.json" - }, - "entry": "x402://shipagent.eth/ship/v1.0.0", - "capabilities": { "operations": [ "create_label", @@ -33,20 +25,31 @@ "update_tracking", "mark_delivered" ], - "input_types": ["application/json"], - "output_types": ["application/json"] + "input_types": [ + "application/json" + ], + "output_types": [ + "application/json" + ] }, - "meta": { "publisher": "CommandLayer", "contact": "dev@commandlayer.org", "pgp_fingerprint": "5016 D496 9F38 22B2 C5A2 FA40 99A2 6950 197D AB0A", - "tags": ["ship", "logistics", "fulfillment", "commercial"] + "tags": [ + "ship", + "logistics", + "fulfillment", + "commercial" + ], + "notes": [ + "Legacy commercial v1.0.0 cards are preserved without mirror URLs because no canonical IPFS mirror binding was recorded for this line." + ] }, - - "networks": ["eip155:1"], + "networks": [ + "eip155:1" + ], "license": "Apache-2.0", - "created_at": "2025-11-22T00:00:00Z", "updated_at": "2025-11-22T00:00:00Z" } diff --git a/agents/v1.0.0/commercial/verifyagent.eth.json b/agents/v1.0.0/commercial/verifyagent.eth.json index 4ce737d..ee557bb 100644 --- a/agents/v1.0.0/commercial/verifyagent.eth.json +++ b/agents/v1.0.0/commercial/verifyagent.eth.json @@ -1,33 +1,23 @@ { "$schema": "https://commandlayer.org/agent-cards/schemas/v1.0.0/_shared/agent.card.base.schema.json", "$id": "https://commandlayer.org/agent-cards/agents/v1.0.0/commercial/verifyagent.eth.json", - "id": "verifyagent.eth", "slug": "verifyagent", "display_name": "Verify Agent", - "description": "Commercial reference agent for the verify verb. Confirms payments, invoices, and settlements against a provider’s canonical ledger using commercial verify.request and verify.receipt schemas.", - + "description": "Commercial reference agent for the verify verb. Confirms payments, invoices, and settlements against a provider\u2019s canonical ledger using commercial verify.request and verify.receipt schemas.", "owner": "commandlayer.eth", "ens": "verifyagent.eth", "version": "1.0.0", "status": "protocol_reference", "class": "commercial", - "implements": [ "verify" ], - "schemas": { "request": "https://commandlayer.org/schemas/v1.0.0/commercial/verify/requests/verify.request.schema.json", "receipt": "https://commandlayer.org/schemas/v1.0.0/commercial/verify/receipts/verify.receipt.schema.json" }, - "schemas_mirror": { - "request": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/verify/requests/verify.request.schema.json", - "receipt": "https://ipfs.io/ipfs/COMMERCIAL_SCHEMAS_CID/commercial/verify/receipts/verify.receipt.schema.json" - }, - "entry": "x402://verifyagent.eth/verify/v1.0.0", - "capabilities": { "operations": [ "verify_payment", @@ -42,7 +32,6 @@ "application/json" ] }, - "meta": { "publisher": "CommandLayer", "contact": "dev@commandlayer.org", @@ -53,14 +42,15 @@ "payments", "settlement", "protocol-reference" + ], + "notes": [ + "Legacy commercial v1.0.0 cards are preserved without mirror URLs because no canonical IPFS mirror binding was recorded for this line." ] }, - "networks": [ "eip155:1" ], "license": "Apache-2.0", - "created_at": "2025-11-22T00:00:00Z", "updated_at": "2025-11-22T00:00:00Z" } diff --git a/checksums.txt b/checksums.txt index 28c0fe2..308761c 100644 --- a/checksums.txt +++ b/checksums.txt @@ -1,10 +1,10 @@ cfb2adbfe8de109f249e9019596b38cb38816375e50752c2188e480d140479d7 .well-known/agent-cards-v1.1.0.json 9ed62edd51168143b431317454e4133ce3924fbb437fdbb1868be5a8d47b2670 .well-known/agent.json -8cbbb8edf6b3ec2e65dc54ce5bdd467a63aaaad1d90bbd251a729b238ef56507 agents/v1.0.0/commercial/authorizeagent.eth.json -bfad808d0e3b107df59887c9684303b87b4867d9887c9b1a035ca8b33b115cca agents/v1.0.0/commercial/checkoutagent.eth.json -0bbd1601794b3d18f63fc331b55888cb083e0f1a37d14c3c79679c237ec0414b agents/v1.0.0/commercial/purchaseagent.eth.json -15062e72b528e2f66e58a3d83ea617a4d9e699cb1eb25a0576cbf09f3808425d agents/v1.0.0/commercial/shipagent.eth.json -4079b22e3821dbfc141b1c9baaaf1cefb20b4c68af58725aacf8428e05d2e91a agents/v1.0.0/commercial/verifyagent.eth.json +938d748b85f5dc1e20e361caef618d18406d952868dcb87d81a9ecee34961bd3 agents/v1.0.0/commercial/authorizeagent.eth.json +e49cb41f3808fc431450ff9a494b697d7d3fc1e757e9bf622a456cf958c27a58 agents/v1.0.0/commercial/checkoutagent.eth.json +a5a0e3bbb0290023be7a4004fcaf27461e8d21e0f4d98fea3ccc19add0175634 agents/v1.0.0/commercial/purchaseagent.eth.json +cc38e1e76a51c429a896247b003d874a4c29bc3564b2fcb435fa7edb999b17dd agents/v1.0.0/commercial/shipagent.eth.json +76ad9fcff2f85321bbf81cb86c2ea2bdf3c50b22dde9c990cbff2328e9c62a13 agents/v1.0.0/commercial/verifyagent.eth.json 2b14d78ad82435da6846e119bc9bf82f5b7661ccef53f4b7c25aaa50411d8812 agents/v1.0.0/commons/analyzeagent.eth.json acb40f650362582daedda35fd1dbd78b7d1b6866e26cb3ee8ca090e0d18331e1 agents/v1.0.0/commons/classifyagent.eth.json 88943a385de72550bbd7454ddc8aabc6b4bc101449b571a1966e9e8c8266040e agents/v1.0.0/commons/cleanagent.eth.json diff --git a/package.json b/package.json index c719cad..e13d41e 100644 --- a/package.json +++ b/package.json @@ -40,11 +40,14 @@ "README.md" ], "scripts": { - "validate:cards": "node scripts/validate-cards.mjs", + "validate:cards": "node scripts/validate-cards.mjs --mode=all", "generate:checksums": "node scripts/generate-checksums.mjs", "validate:checksums": "node scripts/generate-checksums.mjs --verify", "typecheck": "tsc --noEmit", - "validate": "npm run validate:cards && npm run validate:checksums && npm run typecheck" + "validate": "npm run validate:release", + "validate:current": "node scripts/validate-cards.mjs --mode=current", + "validate:legacy": "node scripts/validate-cards.mjs --mode=legacy", + "validate:release": "npm run validate:current && npm run validate:checksums && npm run typecheck" }, "devDependencies": { "@types/node": "^22.0.0", diff --git a/scripts/validate-cards.mjs b/scripts/validate-cards.mjs index 8b20899..909c9f4 100644 --- a/scripts/validate-cards.mjs +++ b/scripts/validate-cards.mjs @@ -14,9 +14,26 @@ const expectedV11 = { commercial: commercialVerbs.map((verb) => `${verb}agent.eth.json`) }; +const VALIDATION_MODES = new Set(["current", "legacy", "all"]); +const CURRENT_DESCRIPTOR_PATHS = [ + ".well-known/agent.json", + ".well-known/agent-cards-v1.1.0.json" +]; + const ajv = new Ajv2020({ strict: true, allErrors: true }); addFormats(ajv); +function getMode() { + const arg = process.argv.find((value) => value.startsWith("--mode=")); + if (!arg) return "current"; + const mode = arg.slice("--mode=".length); + if (!VALIDATION_MODES.has(mode)) { + console.error(`❌ Unknown validation mode: ${mode}. Expected one of: ${[...VALIDATION_MODES].join(", ")}`); + process.exit(1); + } + return mode; +} + function loadJson(relativePath) { return JSON.parse(fs.readFileSync(path.join(ROOT, relativePath), "utf8")); } @@ -69,60 +86,98 @@ function validateExpectedV11Set() { } } -function validateCard(fullPath) { +function validateCurrentCard(fullPath) { const relativePath = path.relative(ROOT, fullPath).replace(/\\/g, "/"); const [, folderVersion, tier, fileName] = relativePath.split("/"); const card = readJson(fullPath); - const validate = folderVersion === "v1.1.0" ? v11Validate : v10Validate; - if (!validate(card)) { - fail(`Agent Card failed schema validation: ${relativePath}`, validate.errors); + + if (!v11Validate(card)) { + fail(`Agent Card failed schema validation: ${relativePath}`, v11Validate.errors); return; } const primaryVerb = card.implements[0]; const expectedId = `https://commandlayer.org/agent-cards/${relativePath}`; const expectedEntry = `x402://${card.ens}/${primaryVerb}/v${card.version}`; - const semverFolder = folderVersion.replace(/^v/, ""); + const expectedSchema = "https://commandlayer.org/agent-cards/schemas/v1.1.0/agent.card.schema.json"; + const rawCommons = /^https:\/\/raw\.githubusercontent\.com\/commandlayer\/protocol-commons\/refs\/tags\/v1\.1\.0\/schemas\/v1\.1\.0\/commons\/([^/]+)\/\1\.(request|receipt)\.schema\.json$/; + const rawCommercial = /^https:\/\/raw\.githubusercontent\.com\/commandlayer\/protocol-commercial\/refs\/tags\/v1\.1\.0\/schemas\/v1\.1\.0\/commercial\/([^/]+)\/\1\.(request|receipt)\.schema\.json$/; + const mirrorCommons = /^https:\/\/commandlayer\.org\/schemas\/v1\.1\.0\/commons\/([^/]+)\/\1\.(request|receipt)\.schema\.json$/; + const mirrorCommercial = /^https:\/\/commandlayer\.org\/schemas\/v1\.1\.0\/commercial\/([^/]+)\/\1\.(request|receipt)\.schema\.json$/; - if (card.version !== semverFolder) fail(`${relativePath}: version mismatch.`); + if (card.version !== folderVersion.replace(/^v/, "")) fail(`${relativePath}: version mismatch.`); if (card.$id !== expectedId) fail(`${relativePath}: $id mismatch.`); + if (card.$schema !== expectedSchema) fail(`${relativePath}: stale or invalid $schema.`); if (card.entry !== expectedEntry) fail(`${relativePath}: entry mismatch.`); if (card.id !== card.ens) fail(`${relativePath}: id must equal ens.`); if (card.class !== tier) fail(`${relativePath}: class mismatch.`); if (fileName !== `${card.ens}.json`) fail(`${relativePath}: filename mismatch.`); if (new Date(card.updated_at).getTime() < new Date(card.created_at).getTime()) fail(`${relativePath}: updated_at must be >= created_at.`); + if (JSON.stringify(card).includes("_shared")) fail(`${relativePath}: current v1.1.0 card must not reference _shared.`); - if (folderVersion === "v1.1.0") { - const expectedSchema = "https://commandlayer.org/agent-cards/schemas/v1.1.0/agent.card.schema.json"; - if (card.$schema !== expectedSchema) fail(`${relativePath}: stale or invalid $schema.`); - if (JSON.stringify(card).includes("_shared")) fail(`${relativePath}: current v1.1.0 card must not reference _shared.`); + if (tier === "commons") { + if (!rawCommons.test(card.schemas.request) || !rawCommons.test(card.schemas.receipt)) fail(`${relativePath}: stale Commons source schema paths.`); + if (!mirrorCommons.test(card.schemas_mirror.request) || !mirrorCommons.test(card.schemas_mirror.receipt)) fail(`${relativePath}: stale Commons mirror schema paths.`); + } + if (tier === "commercial") { + if (!rawCommercial.test(card.schemas.request) || !rawCommercial.test(card.schemas.receipt)) fail(`${relativePath}: stale Commercial source schema paths.`); + if (!mirrorCommercial.test(card.schemas_mirror.request) || !mirrorCommercial.test(card.schemas_mirror.receipt)) fail(`${relativePath}: stale Commercial mirror schema paths.`); + } + if (!card.schemas.request.includes(`/${primaryVerb}/`) || !card.schemas.receipt.includes(`/${primaryVerb}/`)) fail(`${relativePath}: schema URLs must match implements[0].`); - const rawCommons = /^https:\/\/raw\.githubusercontent\.com\/commandlayer\/protocol-commons\/refs\/tags\/v1\.1\.0\/schemas\/v1\.1\.0\/commons\/([^/]+)\/\1\.(request|receipt)\.schema\.json$/; - const rawCommercial = /^https:\/\/raw\.githubusercontent\.com\/commandlayer\/protocol-commercial\/refs\/tags\/v1\.1\.0\/schemas\/v1\.1\.0\/commercial\/([^/]+)\/\1\.(request|receipt)\.schema\.json$/; - const mirrorCommons = /^https:\/\/commandlayer\.org\/schemas\/v1\.1\.0\/commons\/([^/]+)\/\1\.(request|receipt)\.schema\.json$/; - const mirrorCommercial = /^https:\/\/commandlayer\.org\/schemas\/v1\.1\.0\/commercial\/([^/]+)\/\1\.(request|receipt)\.schema\.json$/; + console.log(`✅ Current Agent Card valid: ${relativePath}`); +} - if (tier === "commons") { - if (!rawCommons.test(card.schemas.request) || !rawCommons.test(card.schemas.receipt)) fail(`${relativePath}: stale Commons source schema paths.`); - if (!mirrorCommons.test(card.schemas_mirror.request) || !mirrorCommons.test(card.schemas_mirror.receipt)) fail(`${relativePath}: stale Commons mirror schema paths.`); - } - if (tier === "commercial") { - if (!rawCommercial.test(card.schemas.request) || !rawCommercial.test(card.schemas.receipt)) fail(`${relativePath}: stale Commercial source schema paths.`); - if (!mirrorCommercial.test(card.schemas_mirror.request) || !mirrorCommercial.test(card.schemas_mirror.receipt)) fail(`${relativePath}: stale Commercial mirror schema paths.`); - } - if (!card.schemas.request.includes(`/${primaryVerb}/`) || !card.schemas.receipt.includes(`/${primaryVerb}/`)) fail(`${relativePath}: schema URLs must match implements[0].`); +function validateLegacyCard(fullPath) { + const relativePath = path.relative(ROOT, fullPath).replace(/\\/g, "/"); + const [, folderVersion, tier, fileName] = relativePath.split("/"); + const card = readJson(fullPath); + + if (!v10Validate(card)) { + fail(`Legacy Agent Card failed schema validation: ${relativePath}`, v10Validate.errors); + return; } - console.log(`✅ Agent Card valid: ${relativePath}`); + const primaryVerb = card.implements[0]; + const expectedId = `https://commandlayer.org/agent-cards/${relativePath}`; + const expectedEntry = `x402://${card.ens}/${primaryVerb}/v${card.version}`; + const semverFolder = folderVersion.replace(/^v/, ""); + const serialized = JSON.stringify(card); + + if (card.version !== semverFolder) fail(`${relativePath}: version mismatch.`); + if (card.$id !== expectedId) fail(`${relativePath}: $id mismatch.`); + if (card.entry !== expectedEntry) fail(`${relativePath}: entry mismatch.`); + if (card.id !== card.ens) fail(`${relativePath}: id must equal ens.`); + if (card.class !== tier) fail(`${relativePath}: class mismatch.`); + if (fileName !== `${card.ens}.json`) fail(`${relativePath}: filename mismatch.`); + if (new Date(card.updated_at).getTime() < new Date(card.created_at).getTime()) fail(`${relativePath}: updated_at must be >= created_at.`); + if (/COMMERCIAL_SCHEMAS_CID|example\.com|placeholder|your-domain|REPLACE_ME|TODO|TBD/i.test(serialized)) fail(`${relativePath}: contains placeholder or template content.`); + + console.log(`✅ Legacy Agent Card valid: ${relativePath}`); } -function main() { - validateDescriptor(".well-known/agent.json"); - validateDescriptor(".well-known/agent-cards-v1.1.0.json"); +function runCurrentValidation() { + console.log("▶ Validating current canonical line (v1.1.0 + discovery)..."); + for (const descriptorPath of CURRENT_DESCRIPTOR_PATHS) validateDescriptor(descriptorPath); validateExpectedV11Set(); - for (const file of collectJsonFiles("agents")) validateCard(file); + for (const file of collectJsonFiles("agents/v1.1.0")) validateCurrentCard(file); +} + +function runLegacyValidation() { + console.log("▶ Validating legacy compatibility line (v1.0.0)..."); + for (const file of collectJsonFiles("agents/v1.0.0")) validateLegacyCard(file); +} + +function main() { + const mode = getMode(); + + if (mode === "current" || mode === "all") runCurrentValidation(); + if (mode === "legacy" || mode === "all") runLegacyValidation(); + if (process.exitCode) process.exit(process.exitCode); - console.log("✅ All Agent Card validations completed successfully."); + if (mode === "current") console.log("✅ Current canonical validation completed successfully."); + else if (mode === "legacy") console.log("✅ Legacy compatibility validation completed successfully."); + else console.log("✅ All current and legacy card validations completed successfully."); } main();