diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 18c6e36..9f53761 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -21,4 +21,4 @@ jobs: - run: npm run validate - run: npm run generate:checksums - run: git diff --exit-code -- checksums.txt - - run: npm pack --dry-run + - run: npm run validate:pack diff --git a/ONBOARDING.md b/ONBOARDING.md index e2a1908..ebbe977 100644 --- a/ONBOARDING.md +++ b/ONBOARDING.md @@ -4,17 +4,17 @@ This document is an orientation guide for the active v1.1.0 release line. Contri ## Document scope -Use this document to understand the repository shape, release line, and published package boundary before editing. +Use this document to understand the repository shape, release line, and shipped package boundary before editing. For the authoritative version policy, checksum boundary, and validation requirements, see `POLICY.md` and `SPEC.md`. ## External consumer workflow -1. Use `manifest.json` to confirm that `v1.1.0` is the current line. +1. Use `manifest.json` to confirm that `v1.1.0` is the current line in repository-validated, pre-publication state. 2. Treat the shipped package surface as limited to `schemas/v1.1.0/`, `examples/v1.1.0/`, `manifest.json`, `checksums.txt`, `LICENSE`, `README.md`, and `index.js`. 3. Use `index.js` or `schemas/v1.1.0/index.json` as the package entrypoint to the current schema map. 4. Choose flat schemas under `schemas/v1.1.0/commercial//` for validator configuration. -5. Run the maintained verification commands listed in `README.md#validation-commands` before mirroring or vendoring. +5. Run the maintained verification commands listed in `README.md#validation-commands` before mirroring, vendoring, or performing a release step. 6. Treat `examples/v1.1.0/commercial//valid/` and `invalid/` as conformance fixtures. 7. Treat `v1.0.0` as repository-only historical material unless a separate compatibility workflow explicitly vendors it from source. @@ -27,7 +27,7 @@ High-level maintainer sequence: 1. Install dependencies with `npm install`. 2. Edit schemas, examples, metadata, scripts, and docs coherently. 3. Run the canonical validation commands referenced from `README.md#validation-commands`. -4. Regenerate `checksums.txt` when any checksum-covered published payload file changes. +4. Regenerate `checksums.txt` when any checksum-covered shipped-boundary file changes. 5. Keep current-line teaching focused on `v1.1.0` and keep `v1.0.0` out of the shipped package boundary. ## Adding a new commercial verb @@ -48,17 +48,17 @@ High-level maintainer sequence: 2. Create a new `schemas/vX.Y.Z/` and `examples/vX.Y.Z/` tree. 3. Update `package.json`, `manifest.json`, README, SPEC, policy docs, and workflow assumptions. 4. Draft release notes and changelog updates for the new line before publication. -5. Regenerate checksums for the new line's checksum-covered published payload. +5. Regenerate checksums for the new line's checksum-covered shipped payload. 6. Move superseded lines out of the shipped package boundary unless they are explicitly revalidated and intentionally kept. For the canonical path model and namespace rules, see `SPEC.md`. ## Manual publication follow-up -The repository does not automate publication, GitHub Release publication, IPFS pinning, CID capture, or mirror updates. If your release process uses those steps, perform them manually after the new version line has passed validation: +The repository does not automate publication, GitHub Release publication, signed provenance publication, IPFS pinning, CID capture, or mirror updates. If your release process uses those steps, perform them manually after the new version line has passed validation: 1. Publish the GitHub Release using `releases/v1.1.0.md` or the corresponding new-version draft. -2. Pin the checksum-covered published payload to IPFS, if that distribution channel is being used for the release. +2. Pin the checksum-covered shipped payload to IPFS, if that distribution channel is being used for the release. 3. Capture resulting CIDs in the external release record if your publication process requires them. 4. Update commandlayer.org mirrors to match the release paths exactly. 5. Update any Agent Card schema bindings that reference the superseded version. diff --git a/POLICY.md b/POLICY.md index 4e144f4..edd1366 100644 --- a/POLICY.md +++ b/POLICY.md @@ -1,10 +1,10 @@ # POLICY — Protocol-Commercial -This policy governs the active release line and the canonical published package boundary. Repo-wide governance and security reporting are defined separately. +This policy governs the active release line and the canonical shipped package boundary. Repo-wide governance and security reporting are defined separately. ## Current line -`v1.1.0` is the current Protocol-Commercial line and the only canonical published package line. +`v1.1.0` is the current Protocol-Commercial line and the only canonical shipped line. `v1.0.0` may remain in the repository as historical source material for audit or migration reference, but it is outside the shipped npm package surface and outside the active canonical release boundary. @@ -17,7 +17,7 @@ This policy governs the active release line and the canonical published package ## Canonical published boundary -The canonical published package surface for `v1.1.0` is limited to: +The canonical shipped boundary for `v1.1.0` is limited to: - `schemas/v1.1.0/` - `examples/v1.1.0/` @@ -31,7 +31,7 @@ Legacy `v1.0.0` schemas, examples, and any historical TypeScript fixtures are re ## Integrity boundary -`checksums.txt` is the generated ledger for the canonical published package payload, excluding `checksums.txt` itself. +`checksums.txt` is the generated ledger for the canonical shipped boundary, excluding `checksums.txt` itself. The checksum-covered payload consists of: @@ -56,3 +56,5 @@ Release-defining prose docs outside that list are repository guidance only and m - `fulfillment_ref` denotes the merchant or provider controlled fulfillment artifact, not a generic external pointer. - Shipment receipts must remain commercially scoped and tied to an upstream checkout or purchase. - `requester` is the governed field for the initiator of a `verify.request`; `verifier` is reserved for the authority that issues or attests the verification receipt. + +Tarball validation may additionally allow npm-emitted `package.json` metadata, but that packaging artifact does not expand the canonical shipped boundary. diff --git a/README.md b/README.md index 21745d9..bbde183 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,14 @@ Protocol-Commercial is intentionally limited to protocol truth: ## Document scope -This README is a repo-wide orientation document for the active release line and its canonical published package boundary. +This README is a repo-wide orientation document for the active release line and its canonical shipped boundary. ## Release truth - **Current canonical line:** `v1.1.0` - **Current canonical schema root:** `https://commandlayer.org/schemas/v1.1.0/` - **Current package entrypoint:** `index.js` → `schemas/v1.1.0/index.json` -- **Canonical published package surface:** `schemas/v1.1.0/`, `examples/v1.1.0/`, `manifest.json`, `checksums.txt`, `LICENSE`, `README.md`, `index.js` +- **Canonical shipped boundary:** `schemas/v1.1.0/`, `examples/v1.1.0/`, `manifest.json`, `checksums.txt`, `LICENSE`, `README.md`, `index.js` - **Historical repository-only line:** `v1.0.0`, retained under `schemas/v1.0.0/` and `examples/v1.0.0/` - **Changelog:** `CHANGELOG.md` - **Release note draft for a future GitHub Release publication:** `releases/v1.1.0.md` @@ -50,7 +50,7 @@ This repository is the source of truth for those schema files and release metada ## Schema identity and trust - `https://commandlayer.org/...` is the canonical schema namespace and the normative `$id` base for this release line. -- This Git repository and its canonical published package contents are the source of truth for those artifacts. +- This Git repository and its canonical shipped package contents are the source of truth for those artifacts. - External resolution of `$id` URLs is a convenience, not a trust requirement; consumers should vendor, mirror, or package-pin the repository artifacts they validate against. ## Relationship to the stack @@ -73,7 +73,7 @@ The stack story is singular: For consumers who need the shortest safe path: -1. Install the package and use the package-root export or explicit current-line schema export. +1. If and when `@commandlayer/commercial` is published, install that package and use the package-root export or explicit current-line schema export. Until then, treat the repository checkout as the authoritative source of the current line. ```bash npm install @commandlayer/commercial ``` @@ -87,9 +87,9 @@ For consumers who need the shortest safe path: 3. Prefer `schemas/v1.1.0/commercial//.request.schema.json` and `...receipt.schema.json` directly for validator configuration. 4. Verify the shipped current-line payload before mirroring or vendoring using the canonical command surface in [Validation commands](#validation-commands). 5. Ignore `v1.0.0` unless you are consulting repository-local historical material for migration work. It is not part of the canonical shipped package surface. -6. Treat schemas, examples, `manifest.json`, `README.md`, `LICENSE`, and `index.js` as the shipped release payload. Treat `checksums.txt` as the ledger for that payload. +6. Treat `schemas/v1.1.0/`, `examples/v1.1.0/`, `manifest.json`, `checksums.txt`, `README.md`, `LICENSE`, and `index.js` as the canonical shipped boundary for the current line. Treat the checksum-covered subset as that same boundary minus `checksums.txt` itself. -Package-install instructions are intentionally minimal here because npm publication state for `@commandlayer/commercial` could not be verified from this repository alone. +The install command above is a future-publication consumer path, not a claim that npm publication has already happened. In the current repository state, the checked-in artifacts are the authoritative release candidate surface. ## Commercial execution model @@ -175,6 +175,8 @@ protocol-commercial/ └── scripts/ ``` +When npm produces a tarball, it also emits `package.json` as required package metadata. That generated tarball addition does not widen the canonical shipped boundary described above. + Protocol-Commercial v1.1.0 does **not** use a current-line `_shared/` tree. Every v1.1.0 request and receipt schema is self-contained, flat, and mirror-safe. ### Browsing large self-contained schemas @@ -266,9 +268,10 @@ sha256sum -c checksums.txt - `npm test` runs the full current-line validation aggregate (`npm run validate`). - `npm run validate:schemas` checks current-line metadata, package boundary, schema identity, layout, and manifest/index alignment expectations. -- `npm run validate:examples` validates every current-line JSON valid and invalid example against the canonical schemas. +- `npm run validate:examples` validates every shipped v1.1.0 JSON valid and invalid example fixture against the canonical schemas. - `npm run validate:integrity` verifies the canonical shipped payload scope and hash coverage for the current release line. -- `checksums.txt` intentionally covers the shipped payload excluding the ledger itself: `manifest.json`, `schemas/v1.1.0/`, `examples/v1.1.0/`, `LICENSE`, `README.md`, and `index.js`. +- `checksums.txt` intentionally covers the shipped boundary excluding the ledger itself: `manifest.json`, `schemas/v1.1.0/`, `examples/v1.1.0/`, `LICENSE`, `README.md`, and `index.js`. +- `npm run validate:pack` checks that `npm pack --dry-run` contains only the canonical shipped boundary plus npm-emitted `package.json`. ## Agent Cards and Commons alignment @@ -287,7 +290,7 @@ Protocol-Commons and Protocol-Commercial therefore tell one coherent story: The checksum boundary is defined normatively in `SPEC.md` and governed by `POLICY.md`. -`checksums.txt` is the generated hash ledger for the shipped payload; it describes that surface but is not itself part of the hashed payload, so checksum verification confirms covered files only relative to the checked-in `checksums.txt` ledger and does not independently authenticate that ledger. Repository docs outside the published package surface remain authoritative guidance inside the repo, but they are not shipped or checksum-covered unless package metadata is expanded deliberately in a later release. +`checksums.txt` is the generated hash ledger for the shipped payload; it describes that surface but is not itself part of the hashed payload, so checksum verification confirms covered files only relative to the checked-in `checksums.txt` ledger and does not independently authenticate that ledger. Repository docs outside the shipped package surface remain authoritative guidance inside the repo, but they are not shipped or checksum-covered unless package metadata is expanded deliberately in a later release. For external verification, the minimal path is: diff --git a/SECURITY_PROVENANCE.md b/SECURITY_PROVENANCE.md index f77526e..6c9a6df 100644 --- a/SECURITY_PROVENANCE.md +++ b/SECURITY_PROVENANCE.md @@ -2,7 +2,7 @@ ## Release posture -Current release line: `v1.1.0` +Current release line: `v1.1.0` (repository-validated, not yet asserted as publicly published) Canonical shipped npm package surface: @@ -14,7 +14,7 @@ Canonical shipped npm package surface: - `README.md` - `index.js` -Checksum-covered published payload: +Checksum-covered shipped payload: - `schemas/v1.1.0/` - `examples/v1.1.0/` @@ -23,14 +23,16 @@ Checksum-covered published payload: - `README.md` - `index.js` -`checksums.txt` is the generated SHA-256 ledger for that checksum-covered payload. Because the ledger describes the payload, it is not itself part of the hashed payload. Checksum verification therefore confirms the published payload relative to the checked-in `checksums.txt` ledger and does not independently authenticate that ledger. +`checksums.txt` is the generated SHA-256 ledger for that checksum-covered payload. Because the ledger describes the payload, it is not itself part of the hashed payload. Checksum verification therefore confirms the shipped payload relative to the checked-in `checksums.txt` ledger and does not independently authenticate that ledger. Release integrity state for this repository: -- `manifest.json` marks `v1.1.0` as the current release line. +- `manifest.json` marks `v1.1.0` as the current draft line and avoids asserting a completed external publication date. - `checksums.txt` records repository-local SHA-256 digests for the canonical shipped payload excluding the ledger file itself. - `index.js` resolves the package root export to `schemas/v1.1.0/index.json`. - Canonical schema `$id` values resolve to the commandlayer.org release paths for `v1.1.0`. - Retained `v1.0.0` material is repository-only historical source and is not part of the shipped package boundary. This file makes only repository-backed claims. It does not assert external pin, CID, or public mirror state unless those values are recorded in this repository. + +The repository does not currently claim signed provenance attestations, external transparency-log inclusion, or registry publication beyond what can be verified from checked-in files. diff --git a/SPEC.md b/SPEC.md index 5cd3575..6642730 100644 --- a/SPEC.md +++ b/SPEC.md @@ -1,6 +1,6 @@ # SPEC — Protocol-Commercial v1.1.0 -This document is normative for the active v1.1.0 commercial release line. +This document is normative for the active v1.1.0 commercial release line in its repository-validated, pre-publication state. ## 1. Scope @@ -14,15 +14,15 @@ This specification governs: - deterministic versioning rules - x402-first commercial binding expectations - validation and integrity requirements -- canonical published package boundary requirements +- canonical shipped package boundary requirements This specification does not govern runtime transport implementation, provider policy, or legal adjudication. ## 2. Canonical release boundary -The canonical published package line is `v1.1.0` only. +The canonical shipped line is `v1.1.0` only. -Canonical published package contents: +Canonical shipped package contents: - `schemas/v1.1.0/` - `examples/v1.1.0/` @@ -32,7 +32,7 @@ Canonical published package contents: - `README.md` - `index.js` -Checksum-covered published payload: +Checksum-covered shipped payload: - `schemas/v1.1.0/` - `examples/v1.1.0/` @@ -48,7 +48,7 @@ Historical repository-only material that is outside the canonical shipped packag - `schemas/v1.0.0/` - `examples/v1.0.0/` -Additional prose docs may remain authoritative for interpretation or process inside the repository, but they are outside the published package surface unless package metadata is changed deliberately in a later release. +Additional prose docs may remain authoritative for interpretation or process inside the repository, but they are outside the shipped package surface unless package metadata is changed deliberately in a later release. ## 3. Version and identity rules @@ -58,8 +58,8 @@ Additional prose docs may remain authoritative for interpretation or process ins 4. A schema file path and its `$id` MUST agree exactly. 5. A v1.1.0 schema MUST NOT be mutated in place after release publication. 6. Breaking or meaning-changing edits require a new version directory. -7. `manifest.json` MUST identify the current release line and any retained repository-only legacy lines. -8. `checksums.txt` MUST enumerate the checksum-covered published payload exactly and MUST NOT be described as protecting files it does not hash. +7. `manifest.json` MUST identify the current release line, publication posture, and any retained repository-only legacy lines. +8. `checksums.txt` MUST enumerate the checksum-covered shipped payload exactly and MUST NOT be described as protecting files it does not hash. 9. The npm `files` surface and package exports MUST exclude non-canonical legacy lines unless those lines are revalidated and intentionally reintroduced. ## 4. Current path model @@ -167,12 +167,17 @@ A conformant release MUST satisfy all of the following: - every declared verb has valid and invalid examples for both request and receipt artifacts - every current schema path matches its `$id` - `manifest.json` and `schemas/v1.1.0/index.json` agree on the current verb set and path inventory -- the package `files` field matches the canonical published package boundary exactly +- the package `files` field matches the canonical shipped package boundary exactly - `npm test` passes as the current-line validation aggregate - `npm run validate:schemas` passes - `npm run validate:examples` passes - `npm run validate:integrity` passes -- `sha256sum -c checksums.txt` passes for the checksum-covered published payload -- repository metadata does not drift from the active current line +- `sha256sum -c checksums.txt` passes for the checksum-covered shipped boundary +- repository metadata does not drift from the active current line or overclaim publication state The canonical command list lives in `README.md#validation-commands`. + + +## 10. Publication posture + +Until a public release is actually performed, repository metadata MUST describe `v1.1.0` as the current line without claiming that npm publication, GitHub Release publication, or signed provenance publication has already happened. `release_date` MAY remain null before publication, and any publication-state field MUST describe repository-local readiness only. diff --git a/checksums.txt b/checksums.txt index 8b78ab7..df2bfd7 100644 --- a/checksums.txt +++ b/checksums.txt @@ -1,5 +1,5 @@ c43ff17a819f42e67cc2ee01a6356ea1c6d3917d498b2fc1930a42e80075e48c LICENSE -ef319b2e98654582ad6a09a87482deb6c5ef722385357890e835242e2081093b README.md +a451582f4d6e088606126f6504ce97c0404b5a7f9eaf2a1b1e253185afc9491e README.md 930cbbb3992d01385c1e5a64a4a04de5bac7c68a8b59a25a6c0e5507a1cea33f examples/v1.1.0/commercial/authorize/invalid/001-authorize.request.invalid.json ef1e7e77e6c53ef918053918a1b9243505fef02a61b4899868cad36feebe42f3 examples/v1.1.0/commercial/authorize/invalid/900-authorize.receipt.invalid.json afbcee85906d0249ed0c60eecf40657832549ca8032a99154dd0e643b6d82884 examples/v1.1.0/commercial/authorize/valid/001-authorize.request.valid.json @@ -31,7 +31,7 @@ a2a5e61fa04e12786a848e03bbabbc3f9d066ca55a6f48cb1ae1140f6373bf94 examples/v1.1. 50874f3eea69a51ac132873b05e39318e4c2241078ca5e258e466934935ec945 examples/v1.1.0/commercial/verify/valid/900-verify.receipt.valid.json 455d19ad1b7ef98e436d8f1c675fee7f2716eb17d301da8d2cc4e2e2c51e624a examples/v1.1.0/commercial/verify/valid/901-verify.receipt.valid.json 6b0461ac0138c9ba356cbe99ccfaa8c904296c41b6fe26808aef5bac44b29478 index.js -2a906522b85debe988ec618f7d097e491976193d3b132df408b64cde1bbd06e7 manifest.json +da3ad7f894942068b7848038cad9da3a84fe6d88cfe988fc9404c3f59161eb64 manifest.json 4d1178e63f6c5a9e1e4d9cc4d386fbad023dd5a85c000ff193285b1fed9af243 schemas/v1.1.0/commercial/authorize/authorize.receipt.schema.json ef5da55ba5acdd43e8d2715204938762a63819dd370ebc8dfedad014617259c3 schemas/v1.1.0/commercial/authorize/authorize.request.schema.json 66e39d85a503ec2fa096d789b5b3136a451387186fa33424c4bcb07ce9aea49b schemas/v1.1.0/commercial/checkout/checkout.receipt.schema.json diff --git a/manifest.json b/manifest.json index 89b94ff..55ceafd 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "name": "@commandlayer/commercial", "class": "commercial", "version": "1.1.0", - "status": "current", + "status": "current-draft", "description": "Canonical x402-first commercial schemas, examples, and release metadata for CommandLayer.", "repository": "https://github.com/commandlayer/protocol-commercial", "homepage": "https://commandlayer.org", @@ -13,7 +13,7 @@ "examples_root": "examples/v1.1.0", "current_index": "schemas/v1.1.0/index.json", "checksums_file": "checksums.txt", - "release_date": "2026-03-19T00:00:00Z", + "release_date": null, "supersedes": [ "1.0.0" ], @@ -72,5 +72,6 @@ "receipt_schema": "schemas/v1.1.0/commercial/verify/verify.receipt.schema.json", "examples": "examples/v1.1.0/commercial/verify" } - ] + ], + "publication_state": "repository-validated-not-yet-published" } diff --git a/package.json b/package.json index 1186754..de58546 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,8 @@ "validate:schemas": "node scripts/validate-all.mjs", "validate:examples": "node scripts/validate-examples.mjs", "validate:integrity": "node scripts/validate-integrity.mjs", - "validate:all": "npm run validate:schemas && npm run validate:examples && npm run validate:integrity", + "validate:pack": "node scripts/check-packed-surface.mjs", + "validate:all": "npm run validate:schemas && npm run validate:examples && npm run validate:integrity && npm run validate:pack", "validate": "npm run validate:all", "generate:checksums": "node scripts/generate-checksums.mjs", "test": "npm run validate" diff --git a/releases/v1.1.0.md b/releases/v1.1.0.md index 33f0c50..83a7ffc 100644 --- a/releases/v1.1.0.md +++ b/releases/v1.1.0.md @@ -2,14 +2,16 @@ ## Release summary -Protocol-Commercial v1.1.0 is the current canonical commercial release line for CommandLayer. +This file is a repository-local draft. It does not by itself assert that npm publication, a GitHub Release, or signed provenance publication has already occurred. + +Protocol-Commercial v1.1.0 is the current canonical commercial line for CommandLayer and is described here as a checked-in release-note draft for a future publication step. Scope of this release: - flat self-contained schemas under `schemas/v1.1.0/` - current-line examples under `examples/v1.1.0/` - package-root entrypoint `index.js` resolving to `schemas/v1.1.0/index.json` -- published package metadata limited to `manifest.json`, `checksums.txt`, `LICENSE`, and `README.md` +- release metadata limited to `manifest.json`, `checksums.txt`, `LICENSE`, and `README.md` - explicit actor grammar: `payer`, `payee`, `merchant`, `provider`, `carrier`, `verifier` - explicit x402 payment grammar: `payment_requirement`, `payment_session`, `payment_proof` - retained `v1.0.0` as repository-only historical material for audit or migration reference @@ -30,7 +32,7 @@ Scope of this release: - normalized actor and payment grammar across authorize, checkout, purchase, ship, and verify - published current-line valid and invalid conformance examples per verb - narrowed the npm package surface to the active `v1.1.0` line only -- aligned checksum and integrity tooling to the shipped `v1.1.0` package payload +- aligned checksum and integrity tooling to the shipped `v1.1.0` boundary ## Validation commands @@ -40,12 +42,13 @@ npm run validate npm run validate:schemas npm run validate:examples npm run validate:integrity +npm run validate:pack sha256sum -c checksums.txt ``` ## Published package surface -The canonical published package surface for v1.1.0 is: +The canonical shipped boundary for v1.1.0 is: - `schemas/v1.1.0/` - `examples/v1.1.0/` @@ -57,7 +60,7 @@ The canonical published package surface for v1.1.0 is: ## Checksum scope -The checksum-covered published payload for v1.1.0 is: +The checksum-covered shipped boundary for v1.1.0 is: - `schemas/v1.1.0/` - `examples/v1.1.0/` @@ -71,10 +74,15 @@ The checksum-covered published payload for v1.1.0 is: ## Provenance summary - canonical schema `$id` values resolve to `https://commandlayer.org/schemas/v1.1.0/...` -- `manifest.json` marks `v1.1.0` as current and `v1.0.0` as retained historical repository material +- `manifest.json` marks `v1.1.0` as the current draft line and `v1.0.0` as retained historical repository material - `schemas/v1.1.0/index.json` and `manifest.json` agree on verb inventory and schema paths -- integrity tooling verifies the shipped package payload before publication +- integrity tooling verifies the shipped boundary before publication ## Migration note Use `v1.1.0` for all new integrations. Keep `v1.0.0` only as repository-local historical source material unless you are performing a deliberate legacy migration outside the shipped package surface. + + +## Packaging note + +`npm pack --dry-run` may additionally show npm-emitted `package.json` metadata in the tarball. CI treats that as packaging metadata only, not as an expansion of the canonical shipped boundary. diff --git a/scripts/check-packed-surface.mjs b/scripts/check-packed-surface.mjs new file mode 100644 index 0000000..e791a28 --- /dev/null +++ b/scripts/check-packed-surface.mjs @@ -0,0 +1,28 @@ +#!/usr/bin/env node +import { execFile } from "child_process"; +import { promisify } from "util"; +import { TARBALL_ALLOWED_SURFACE } from "./release-boundary.mjs"; + +const execFileAsync = promisify(execFile); + +function assert(condition, message) { + if (!condition) throw new Error(message); +} + +async function main() { + const { stdout } = await execFileAsync("npm", ["pack", "--json", "--dry-run"], { maxBuffer: 1024 * 1024 * 10 }); + const pack = JSON.parse(stdout); + assert(Array.isArray(pack) && pack.length === 1, "npm pack --json --dry-run returned an unexpected payload"); + + const packedFiles = pack[0].files.map((file) => file.path).sort(); + const expected = [...new Set(TARBALL_ALLOWED_SURFACE.flatMap((entry) => entry.endsWith("/") ? packedFiles.filter((file) => file.startsWith(entry)) : [entry]))].sort(); + + assert(JSON.stringify(packedFiles) === JSON.stringify(expected), `packed tarball surface drift\nexpected: ${expected.join(", ")}\nactual: ${packedFiles.join(", ")}`); + console.log("✅ Packed tarball surface matches the canonical v1.1.0 package boundary plus npm-emitted package.json."); +} + +main().catch((error) => { + console.error("❌ Packed tarball surface validation failed."); + console.error(error); + process.exit(1); +}); diff --git a/scripts/generate-checksums.mjs b/scripts/generate-checksums.mjs index e9e4e94..544918b 100644 --- a/scripts/generate-checksums.mjs +++ b/scripts/generate-checksums.mjs @@ -2,18 +2,11 @@ import { promises as fs } from "fs"; import path from "path"; import crypto from "crypto"; +import { CHECKSUM_COVERED_SURFACE } from "./release-boundary.mjs"; const ROOT_DIR = process.cwd(); const OUTPUT_PATH = path.join(ROOT_DIR, "checksums.txt"); -const CURRENT_VERSION = "1.1.0"; -const TARGETS = [ - "manifest.json", - "LICENSE", - "README.md", - "index.js", - `schemas/v${CURRENT_VERSION}`, - `examples/v${CURRENT_VERSION}` -]; +const TARGETS = CHECKSUM_COVERED_SURFACE.map((entry) => entry.replace(/\/$/, "")); async function walk(targetPath) { const absolute = path.join(ROOT_DIR, targetPath); @@ -30,14 +23,9 @@ async function walk(targetPath) { } function isCoveredReleaseArtifact(relPath) { - return [ - "manifest.json", - "LICENSE", - "README.md", - "index.js" - ].includes(relPath) - || relPath.startsWith(`schemas/v${CURRENT_VERSION}/`) - || relPath.startsWith(`examples/v${CURRENT_VERSION}/`); + return CHECKSUM_COVERED_SURFACE.some((entry) => + entry.endsWith("/") ? relPath.startsWith(entry) : relPath === entry + ); } async function hashFile(filePath) { @@ -60,7 +48,7 @@ async function main() { if (!isCoveredReleaseArtifact(rel)) throw new Error(`unexpected checksum target: ${rel}`); } await fs.writeFile(OUTPUT_PATH, rows.map(({ hash, rel }) => `${hash} ${rel}`).join("\n") + "\n"); - console.log(`✅ Wrote ${rows.length} canonical package-payload checksums to ${OUTPUT_PATH}`); + console.log(`✅ Wrote ${rows.length} checksums for the canonical v1.1.0 checksum-covered surface to ${OUTPUT_PATH}`); } main().catch((error) => { diff --git a/scripts/release-boundary.mjs b/scripts/release-boundary.mjs new file mode 100644 index 0000000..c93c0dc --- /dev/null +++ b/scripts/release-boundary.mjs @@ -0,0 +1,20 @@ +export const CURRENT_VERSION = "1.1.0"; + +export const CANONICAL_PACKAGE_SURFACE = [ + `schemas/v${CURRENT_VERSION}/`, + `examples/v${CURRENT_VERSION}/`, + "manifest.json", + "checksums.txt", + "LICENSE", + "README.md", + "index.js" +]; + +export const CHECKSUM_COVERED_SURFACE = CANONICAL_PACKAGE_SURFACE.filter((entry) => entry !== "checksums.txt"); + +export const TARBALL_ALLOWED_SURFACE = [ + ...CANONICAL_PACKAGE_SURFACE, + "package.json" +]; + +export const EXPECTED_VERBS = ["authorize", "checkout", "purchase", "ship", "verify"]; diff --git a/scripts/validate-all.mjs b/scripts/validate-all.mjs index a31d807..e956c75 100644 --- a/scripts/validate-all.mjs +++ b/scripts/validate-all.mjs @@ -5,21 +5,11 @@ import Ajv2020 from "ajv/dist/2020.js"; import addFormats from "ajv-formats"; import ajvErrors from "ajv-errors"; import { loadJsonStrict } from "./load-json-strict.mjs"; +import { CANONICAL_PACKAGE_SURFACE, CHECKSUM_COVERED_SURFACE, CURRENT_VERSION, EXPECTED_VERBS } from "./release-boundary.mjs"; const ROOT_DIR = process.cwd(); -const CURRENT_VERSION = "1.1.0"; const SCHEMAS_ROOT = path.join(ROOT_DIR, "schemas", `v${CURRENT_VERSION}`); const EXAMPLES_ROOT = path.join(ROOT_DIR, "examples", `v${CURRENT_VERSION}`, "commercial"); -const EXPECTED_VERBS = ["authorize", "checkout", "purchase", "ship", "verify"]; -const EXPECTED_PACKAGE_FILES = [ - "schemas/v1.1.0/", - "examples/v1.1.0/", - "manifest.json", - "checksums.txt", - "LICENSE", - "README.md", - "index.js" -]; const CANONICAL_DEF_NAMES = [ "actor_identity", "payer_actor", @@ -103,13 +93,15 @@ async function validateManifest() { const manifest = await loadJsonStrict(path.join(ROOT_DIR, "manifest.json")); assert(!("$schema" in manifest), "manifest.json must not carry a decorative $schema field"); assert(manifest.version === CURRENT_VERSION, `manifest version must be ${CURRENT_VERSION}`); - assert(manifest.status === "current", "manifest status must be current"); + assert(manifest.status === "current-draft", "manifest status must be current-draft until publication is completed"); assert(manifest.path_base === ".", "manifest path_base must anchor repo-relative paths"); assert(manifest.paths_are_repo_relative === true, "manifest must declare repo-relative path semantics"); assert(manifest.schemas_root === `schemas/v${CURRENT_VERSION}`, "manifest schemas_root drift"); assert(manifest.examples_root === `examples/v${CURRENT_VERSION}`, "manifest examples_root drift"); assert(manifest.current_index === `schemas/v${CURRENT_VERSION}/index.json`, "manifest current_index drift"); assert(manifest.checksums_file === "checksums.txt", "manifest checksums_file drift"); + assert(manifest.release_date === null, "manifest release_date must remain null until publication is completed"); + assert(manifest.publication_state === "repository-validated-not-yet-published", "manifest publication_state drift"); assert("declared_alignment" in manifest, "manifest must expose declarative alignment metadata"); assert(manifest.alignment_verification === "declarative-only", "manifest alignment verification mode drift"); assert(!("aligns_with" in manifest), "manifest aligns_with field must not imply verified enforcement"); @@ -125,7 +117,7 @@ async function validatePackage() { assert(pkg.main === "index.js", "package main must resolve through index.js"); assert(pkg.exports["."] === "./index.js", "package root export must resolve through index.js"); assert(pkg.publishConfig?.access === "public", "package publishConfig.access drift"); - assert(JSON.stringify(pkg.files) === JSON.stringify(EXPECTED_PACKAGE_FILES), "package files surface drift"); + assert(JSON.stringify(pkg.files) === JSON.stringify(CANONICAL_PACKAGE_SURFACE), "package files surface drift"); assert(!(pkg.files.includes("schemas/") || pkg.files.includes("examples/")), "package files must not expose repo-wide schema/example roots"); assert(!(pkg.files.includes("INTEGRATOR.md") || pkg.files.includes("SPEC.md") || pkg.files.includes("POLICY.md")), "package files must exclude non-canonical prose docs"); assert(!("./schemas/*" in pkg.exports) && !("./examples/*" in pkg.exports), "package exports must not expose wildcard legacy roots"); @@ -221,7 +213,8 @@ async function main() { const currentSchemas = await validateSchemaTree(); await validateSchemaConsistency(currentSchemas); await validateIndex(); - console.log("✅ Current release metadata, package boundary, paths, schemas, and canonical $defs validated."); + const checksumCovered = CHECKSUM_COVERED_SURFACE.join(", "); + console.log(`✅ Current release metadata, canonical v1.1.0 package boundary, checksum scope (${checksumCovered}), paths, schemas, and canonical $defs validated.`); } main().catch((error) => { diff --git a/scripts/validate-examples.mjs b/scripts/validate-examples.mjs index c4115da..6905dd7 100644 --- a/scripts/validate-examples.mjs +++ b/scripts/validate-examples.mjs @@ -5,12 +5,12 @@ import addFormats from "ajv-formats"; import ajvErrors from "ajv-errors"; import { loadJsonStrict } from "./load-json-strict.mjs"; import { readdir } from "fs/promises"; +import { CURRENT_VERSION, EXPECTED_VERBS } from "./release-boundary.mjs"; const ROOT_DIR = process.cwd(); -const CURRENT_VERSION = "1.1.0"; const EXAMPLES_ROOT = path.join(ROOT_DIR, "examples", `v${CURRENT_VERSION}`, "commercial"); const SCHEMAS_ROOT = path.join(ROOT_DIR, "schemas", `v${CURRENT_VERSION}`, "commercial"); -const VERBS = ["authorize", "checkout", "purchase", "ship", "verify"]; +const VERBS = EXPECTED_VERBS; const ajv = new Ajv2020({ strict: true, allErrors: true, allowUnionTypes: false }); addFormats(ajv); @@ -42,4 +42,4 @@ async function validateVerb(verb) { } for (const verb of VERBS) await validateVerb(verb); -console.log("✅ All current-line examples validated."); +console.log("✅ All shipped v1.1.0 example fixtures validated."); diff --git a/scripts/validate-integrity.mjs b/scripts/validate-integrity.mjs index 457e8d0..2022047 100644 --- a/scripts/validate-integrity.mjs +++ b/scripts/validate-integrity.mjs @@ -2,18 +2,11 @@ import { promises as fs } from "fs"; import path from "path"; import crypto from "crypto"; +import { CHECKSUM_COVERED_SURFACE } from "./release-boundary.mjs"; const ROOT_DIR = process.cwd(); -const CURRENT_VERSION = "1.1.0"; const CHECKSUMS_PATH = path.join(ROOT_DIR, "checksums.txt"); -const TARGETS = [ - "manifest.json", - "LICENSE", - "README.md", - "index.js", - `schemas/v${CURRENT_VERSION}`, - `examples/v${CURRENT_VERSION}` -]; +const TARGETS = CHECKSUM_COVERED_SURFACE.map((entry) => entry.replace(/\/$/, "")); function assert(condition, message) { if (!condition) throw new Error(message); @@ -67,7 +60,7 @@ async function main() { assert(actualMap.get(rel) === computed, `checksum mismatch for ${rel}`); } - console.log("✅ Canonical package payload checksum scope and hashes validated."); + console.log("✅ Canonical v1.1.0 checksum-covered surface and hashes validated."); } main().catch((error) => {