Some checks failed
wai key · the real keychain / does this change touch it (push) Successful in 18s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 12s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 22s
wai key · the real keychain / the real keychain · macos (push) Successful in 39s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Failing after 57s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Failing after 2m6s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 2m17s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 4m28s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 4m30s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 4m44s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 7m36s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 7m42s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (push) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Has been cancelled
wai-app and Create / wai-app · does this change touch it (push) Has been cancelled
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Has been cancelled
wai-audit collector and player integration / does this change touch it (push) Has been cancelled
wai-audit collector and player integration / collector · linux (push) Has been cancelled
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Has been cancelled
WAI operation catalogue / does this change touch it (push) Has been cancelled
WAI operation catalogue / the catalogue and every door · linux (push) Has been cancelled
wai-fleet service / does this change touch it (push) Has been cancelled
wai-fleet service / service · linux (push) Has been cancelled
wai-fleet service / service · macos (push) Has been cancelled
wai-ledger service / does this change touch it (push) Has been cancelled
wai-ledger service / service · linux (push) Has been cancelled
wai-ledger service / service · macos (push) Has been cancelled
wai-quantum for JavaScript / does this change touch it (push) Has been cancelled
wai-quantum for JavaScript / javascript · linux (push) Has been cancelled
wai-quantum studio and desktop / does this change touch it (push) Has been cancelled
wai-quantum studio and desktop / studio · browser (push) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (push) Has been cancelled
wai-quantum studio and desktop / desktop app · linux (push) Has been cancelled
wai-quantum studio and desktop / desktop app · windows (push) Has been cancelled
wai-sink-android native sink library / does this change touch it (push) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Has been cancelled
wai-sink-swift native sink package / does this change touch it (push) Has been cancelled
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Has been cancelled
WAI Studio / does this change touch it (push) Has been cancelled
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
wai-key-proxy / does this change touch it (push) Has been cancelled
wai-key-proxy / proxy · linux (push) Has been cancelled
wai key · Windows / does this change touch it (push) Successful in 13s
wai key · Windows / wai key and the toolchain's tests · windows (push) Successful in 2m10s
No new record type. An operation receipt is an asset-provenance receipt (wai::provenance::AssetReceipt), unchanged: its steps are the project by the canonical digest of the wai.json the operation ran under, each file it read, and each file it wrote, by content hash and path. wai create, lock, build, decode, wrap, unwrap -o, generate and key create|import|rotate|revoke|export each write one in a build with quickstart, kept in a project's .wai/receipts/ (every template's .gitignore keeps it out) or beside the file written. --key signs it; a key operation signs with the key it makes; otherwise a key made for the run, and the receipt says so. A --key that does not sign stops the operation before it writes anything. wai verify reads every *.wai-receipt.json under its paths and refuses a receipt that does not verify, a written file that is missing or changed, a receipt kept in a project whose wai.json is not the one it names, and a built tree that is not the one its build record lists. wai generate, with synthesis, signs for each picture a wai-origin claim (subject the picture's samples, step generate, operation wai.generate.spectral, the model file by SHA-256 and type algorithmic, oversight prompt_guided, source algorithmicMedia) whose record is the picture's receipt, signed by the same key. extensions/synthesis.md §3.5 states it, and how a claim names a model no prior pins, such as a person's own model reached at an endpoint from Create: by the SHA-256 of the endpoint's URL and the model's name, read as a name, never as a pin. wai verify checks the claim; so does synthesis_verify.py claim, the second implementation. The catalogue marks project.create, project.lock, project.build, media.decode, media.generate, envelope.wrap, envelope.unwrap and key.* with receipt and adds their --key inputs; ops.json and Studio's actions are regenerated. Create's end-to-end test runs wai check and wai dev --check on the exported project, reads its receipt with wai verify, and requires wai verify to refuse each changed copy. tests/cli_receipts.rs, in wai-conformance's project step, plants the faults: a changed picture, decoded file, built file and key record; another project's receipt; a claim beside another picture's receipt; an edited claim. Co-Authored-By: Claude Opus 5.5 <[email protected]>
140 lines
10 KiB
Markdown
140 lines
10 KiB
Markdown
# Project schemas
|
|
|
|
Four JSON Schemas (2020-12), each with its `$id` the address it is to be served from, which the
|
|
files it describes name in their `$schema` member, and the receipt every developer-facing write
|
|
leaves ([*Operation receipts*](#operation-receipts)):
|
|
|
|
| Schema | Describes | `$id` | Reader |
|
|
|---|---|---|---|
|
|
| [`wai-json-1.schema.json`](wai-json-1.schema.json) | `wai.json`, a project file, version 1 | `https://wai.transaction.science/schema/wai.json/1` | `dx/project.rs` |
|
|
| [`wai-json-2.schema.json`](wai-json-2.schema.json) | `wai.json`, version 2: version 1 and `breaking`, what `wai breaking` reads in a project | `https://wai.transaction.science/schema/wai.json/2` | `dx/project.rs` |
|
|
| [`wai-lock-1.schema.json`](wai-lock-1.schema.json) | `wai.lock`, what `wai lock` writes | `https://wai.transaction.science/schema/wai.lock/1` | `dx/lock.rs` |
|
|
| [`wai-build-1.schema.json`](wai-build-1.schema.json) | `wai-build.json`, what `wai build` writes last into `dist/` | `https://wai.transaction.science/schema/wai-build.json/1` | `dx/build.rs` writes it |
|
|
|
|
The readers are under `wai/wai-rs/src/bin/wai_cli/`. The release of `wai` waits for the schemas:
|
|
the tag build (`.github/workflows/wai-release.yml`) fails while an address does not serve its file,
|
|
so no release writes a file that names a schema an editor or an agent cannot fetch.
|
|
|
|
`dx/project.rs`'s tests hold `wai.json`'s schema to the reader: the same members in the file and in
|
|
each block, the same modes, the same name rule, and the same verdict, accept or refuse, on every
|
|
template's project file and on a set of files each breaking one rule. `dx/lock.rs`'s and
|
|
`dx/build.rs`'s tests do the same for theirs. A change to either is a change to both.
|
|
|
|
## `wai.lock`
|
|
|
|
The lock pins everything whose bytes change a project's results, as far as the toolchain can
|
|
resolve it. The file is RFC 8785 over one object, on one line, with no line ending: it holds no
|
|
time and no path, so the same inputs give the same bytes on any host, and a checkout that converts
|
|
line endings (`core.autocrlf=true`) has none to convert. Its digest is the SHA-256 of the file.
|
|
|
|
| Member | Required | What it pins |
|
|
|---|---|---|
|
|
| `$schema`, `wai` | yes | This schema, and the lock's version, `1` |
|
|
| `toolchain` | yes | `version`, `wai`'s, and `catalogue.sha256`, the SHA-256 of `wai ops export` ([`catalogue/ops.json`](../catalogue/ops.json)) |
|
|
| `registry` | yes | `sha256`, the SHA-256 of `wai registry export` ([`registry/capabilities.json`](../registry/capabilities.json)) |
|
|
| `template` | when `wai.json` names one | `name`, and `sha256` where the `wai` that wrote the lock holds it: the SHA-256 of the template's listing, one line a file, sorted by path as bytes, each the file's SHA-256, two spaces, its path and a line feed. The files `wai create` makes are in it |
|
|
| `priors` | when `wai.json` names any | Each parameter set's pin, by its name in `wai.json` ([SPEC.md §3.1](../SPEC.md)): a directory is `form` `wai.prior.set` with the `sha256` of its listing, one file has no `form` and the `sha256` of the file |
|
|
| `policy` | when `wai.json` names one | `schema`, the policy's version, and `blake3`, its canonical digest as `wai-pack policy` prints it ([packaging §3](../extensions/packaging.md)) |
|
|
| `conformance` | when `wai.json` names any | Each corpus, by `<kind>/<suite>`: `digest`, the corpus digest a conformance result names ([conformance-results §2.1](../extensions/conformance-results.md)) |
|
|
|
|
`wai lock` writes it, and `wai create` writes it for the project it makes, so a new project passes
|
|
`wai check` and `wai build` as it is. A finding about a lock that is stale, was edited by hand or is
|
|
not there carries the fix `run wai lock`.
|
|
|
|
A member with nothing to pin is absent, never null, never empty and never made up. `wai lock`
|
|
refuses when it cannot compute something the project states (no `wai-pack`, no checkout of the
|
|
standard): another host's lock would differ. A template that `wai` does not hold is the exception:
|
|
it pins the name, and `wai check` says the digest is not checked.
|
|
|
|
A reader refuses a later version as that version (`upgrade wai`), before it reads anything else, by
|
|
its `wai` or its `$schema`; every member it does not know; and bytes that are not the canonical form
|
|
of what they say, which is how an edit by hand that changes no value shows. The bytes are
|
|
[`project-conformance/`](../project-conformance/README.md)'s, whose second reader,
|
|
`project_verify.py`, recomputes every digest with the standard library alone.
|
|
|
|
A digest over a file's bytes is over the bytes a checkout holds. A corpus and a template keep theirs
|
|
(`* -text`, a test holds each to it). A parameter set is the project's: where a checkout converts
|
|
line endings it needs the same, in the project's own `.gitattributes`, or the lock says it is stale.
|
|
The project file and the policy do not need it, since each is pinned by its canonical form.
|
|
|
|
## `wai-build.json`
|
|
|
|
What `wai build` writes last into `dist/`, so a built tree says what it came from. It is RFC 8785 on
|
|
one line, as the lock is: `project`, the project's `name` and the `sha256` of `wai.json`'s canonical
|
|
form (RFC 8785 over what the file says, a whole number however it is written, so a line ending or a
|
|
layout does not change it); `lock`, the `sha256` of `wai.lock`; `toolchain`, as the lock pins it; and
|
|
`files`, every other file of the tree, sorted by path as bytes, each with its `sha256` and `bytes`.
|
|
It holds no time and no path outside `dist/`, so two builds of one project and lock give one record,
|
|
and its SHA-256 is the tree's digest. A package's receipt is signed, so the tree is the same for the
|
|
same key.
|
|
|
|
## Operation receipts
|
|
|
|
What a developer-facing write wrote, signed, so that `wai verify` says later whether those bytes are
|
|
still the ones written and which project configuration they were written under. `wai create`, `wai
|
|
lock`, `wai build`, `wai decode`, `wai wrap`, `wai unwrap -o`, `wai generate` and `wai key
|
|
create|import|rotate|revoke|export --out` each write one, in a build with the feature `quickstart`;
|
|
the catalogue marks each with `receipt` (`wai ops show <id>`). The coding agent's tools that do
|
|
the same writes (`wai mcp`: a package, a lock, a build, an app's export) write them too.
|
|
|
|
A receipt is an asset-provenance receipt (`wai::provenance::AssetReceipt`, kind
|
|
`asset-provenance`), unchanged, so no record type is added. Its steps, in order:
|
|
|
|
| Step | `op` | input, output | `work` |
|
|
|---|---|---|---|
|
|
| The project, where the operation ran in one | `wai.json` | 32 zero bytes; the project file's canonical digest, the `project.sha256` a build record names | 0 |
|
|
| Each file it read | `read <path>`, or `read` for a file outside the receipt's base | the step before; the file's content hash | its length |
|
|
| Each file it wrote, the last the one the receipt is about | `<operation id> <path>` | the step before; the file's content hash | its length |
|
|
|
|
A content hash is BLAKE3 under the domain `wai:asset\x01` over the file's bytes, the asset hash
|
|
the receipt's chain uses; each step's input is the step before's output, as that chain requires,
|
|
so it fixes their order. No step is metered (each carries the unmetered marker `0`). `capability` is
|
|
the capability the operation ran where it ran one, else the operation's id; `group_id` is 0; it has
|
|
no parent.
|
|
|
|
An operation that runs in a project (a `wai.json` in its directory) and writes inside it keeps the
|
|
receipt in the project's `.wai/receipts/`, at the path of the last file it wrote with
|
|
`.wai-receipt.json` added, and names each file by its path in the project, `/`-joined. `.wai/` is
|
|
never served, never built into `dist/`, and the `.gitignore` of every project `wai create` writes
|
|
keeps it out. Any other write keeps its receipt beside the last file it wrote, as
|
|
`<file>.wai-receipt.json`, naming files from there. A key operation's goes beside the key's record,
|
|
in the keystore.
|
|
|
|
It is signed by `--key <name>` (a key of the keystore, or a key file) where the operation takes
|
|
one, by the key a key operation makes (the successor, for a rotation; a revoked key signs nothing,
|
|
so a revocation's is signed as an unnamed write's is), and otherwise by a key made for that run,
|
|
whose secret is not kept: such a receipt shows what was written and under which project, not who
|
|
wrote it. A `--key` that names no key that signs stops the operation before it writes anything. A
|
|
dry run writes no receipt and names the one it would write.
|
|
|
|
`wai verify` reads every `*.wai-receipt.json` under the paths it is given. It refuses a receipt
|
|
whose signature, root or chain does not verify; one whose steps are not these; one that names a
|
|
file written that is not there or whose content hash is another; one kept in a project whose
|
|
project file's digest is not the one it names, or that is not there; and, for a build record it
|
|
names, a tree in which a file the record lists is not as it lists it, or a file it does not list.
|
|
A receipt beside a file is held to the nearest project file at or above it, and where there is
|
|
none the project it names is noted, not compared. A file read that is still there is reported, and
|
|
one that has changed since or is not there is noted: it refuses nothing, because the receipt is
|
|
about what was written. The signer is named by the keystore's name for it where the keystore holds
|
|
it. A generation's origin claim, beside its receipt, is
|
|
[synthesis §3.5](../extensions/synthesis.md)'s.
|
|
|
|
## Versions
|
|
|
|
The lock and the build record follow the project file's rule: a later version is a new schema beside
|
|
this one, refused as that version. Below, of the project file.
|
|
|
|
Version 1 stays open until the first release of `wai` that writes it. From that release on, its
|
|
readers are in use, and a reader refuses any member it does not know, so version 1 does not
|
|
change: a member added to it would be refused, as unknown, by every reader of that release. A
|
|
later version is a new schema at `…/schema/wai.json/<version>`, beside this one. A reader
|
|
refuses a file of a later version as that version (`upgrade wai`), by its `wai` member or by its
|
|
`$schema`, before it reads any other member, so the members the later version adds never stop
|
|
it first.
|
|
|
|
Every member has its reader. `requires.capabilities` is `wai check`'s; `priors`, `package` and
|
|
`conform` are `wai lock`'s, `wai check`'s and, for `package`, `wai build`'s. The project file's other
|
|
members in the toolchain's design (`room`, `breaking`, `targets`, `receipts`, `requires.toolchain`,
|
|
`requires.fallbacks`, and `port` in `dev`) join the file with the operation that reads it; a member
|
|
accepted with nothing to read it would be one the strict reader ignores, which is what it refuses to
|
|
do.
|