All checks were successful
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 5s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 5s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 5s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m46s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m26s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 58s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 5s
WAI conformance / does this change touch it (pull_request) Successful in 5s
WAI energy receipts / does this change touch it (pull_request) Successful in 5s
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Successful in 5s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 4s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 4s
wai-web wasm32 / does this change touch it (pull_request) Successful in 5s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 36s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m2s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m9s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 1m53s
wai-pack / wai-pack · linux (pull_request) Successful in 1m24s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m19s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 2m31s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 4m5s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 5m19s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 48s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 25s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 41s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 8m28s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 2m41s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 23m28s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 10m45s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 2m2s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 29s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m18s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 5m19s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 39m39s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 12m12s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 20m37s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 29s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 58s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 10m28s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 4m17s
wai-pack / wai-pack · macos (pull_request) Successful in 1m22s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 3m44s
Co-Authored-By: Claude Opus 5.5 <[email protected]>
830 lines
48 KiB
Markdown
830 lines
48 KiB
Markdown
# WAI Extension: Exploration and Declared Taste
|
||
|
||
> Status: Draft. Registers the record `wai.media.exploration`. `wai.generate.spectral` is exact:
|
||
> a model file, a prompt, a seed and a number of steps give the same bytes on every machine
|
||
> ([SPEC](../SPEC.md) §5, *Payload of `wai.generate.spectral`*). This extension builds on that.
|
||
> Six **descriptors**, each an integer derivation over a picture's `RGB8` samples, place a
|
||
> picture: how bright, how colourful, how busy, how many colours, and where its light sits. An
|
||
> **archive** asks the generator for many pictures that differ, not one: MAP-Elites over a
|
||
> declared grid of descriptors, run by a pinned schedule from a declared search seed, so every
|
||
> elite regenerates from the genome it names and the whole archive replays bit for bit. The
|
||
> **default set** of a prompt is what the model makes on its own, seeds 0 to 15 at four steps; a
|
||
> work's **default-distance** is how far it sits from the nearest default, a signed measurement
|
||
> for the exact generator and an estimate, never a measurement, for any other. A **collection
|
||
> statement** gives a gallery's, a room's or a session's descriptor coverage and pairwise
|
||
> distances: a homogenization meter that recomputes. **Taste** is a declared, owned objective: a
|
||
> **taste prior** is an integer ranking model over the descriptors, pinned by digest as a WAI
|
||
> prior, signed by its owner and carrying its owner's usage statement
|
||
> ([ai-usage](ai-usage.md)); a **ranking** under it reproduces; and every archive, ranking and
|
||
> **pick** an aesthetic or reward model steered names that model by digest, or states `none`. A
|
||
> policy may require the disclosure, and a selection from a steered archive cannot drop it. No
|
||
> default objective exists: a personal prior and a community prior are the same kind of thing.
|
||
> No new transport. The reference implementation is the `exploration` module of `wai-rs`
|
||
> (feature `exploration`); the corpus is
|
||
> [`live-conformance/exploration/`](../live-conformance/exploration/), and its second
|
||
> implementation is `live-conformance/exploration_verify.py`.
|
||
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
|
||
|
||
## 1. Scope
|
||
|
||
In scope: the records and their encodings (§2); the descriptors, their distance and grids (§3);
|
||
the generator path, modifiers and genomes (§4); archives and their schedule (§5); the default set
|
||
and default-distance (§6); collection statements (§7); taste priors (§8) and rankings (§9); the
|
||
disclosure of what steered a record, and the pick record (§10); the slot this extension leaves
|
||
the contribution record (§11); verification (§12).
|
||
|
||
Out of scope: a user interface; how a person chooses a prompt, a modifier or a pick; training a
|
||
taste prior from anyone's choices (the corpus's priors are written in code with hand-set
|
||
weights, §14); a learned embedding (the descriptors are arithmetic, §3.3); and any statement of
|
||
what a picture is worth.
|
||
|
||
### 1.1 Why
|
||
|
||
Help from a generator can make one person's work more inventive while making many people's work
|
||
more alike: different people asking for the same thing receive the same few answers, and
|
||
different generators converge on similar answers to open prompts. A person shown one example
|
||
tends to stay near it, and a generator asked again with an edited prompt tends to repeat itself.
|
||
A single aesthetic objective applied to everyone narrows what is made further: it ranks one
|
||
taste above others by construction and refuses requests outside it. Rewarding a result for
|
||
differing from what others produce, rather than for matching one objective, restores variety.
|
||
|
||
Each of these is a statement about outputs, and for most generators it can only be estimated.
|
||
For an exact generator it can be checked. This extension makes four such statements checkable:
|
||
how widely an archive explored (§5), how far a work is from what the model does on its own (§6),
|
||
how alike a collection is (§7), and which objective, if any, chose what a person was shown
|
||
(§8–§10).
|
||
|
||
### 1.2 Relationships
|
||
|
||
Relationship to the core spec: `wai.media.exploration` is a **record** ([SPEC](../SPEC.md) §5): a
|
||
signed record a WAI tool emits and verifies. It names no payload format and is not
|
||
dispatchable. A taste prior is a parameter set in SPEC §3.1's sense, pinned by a pin of SPEC
|
||
§3.1's members (§8.3).
|
||
|
||
Relationship to `wai.generate.spectral`: every picture this extension recomputes is made by that
|
||
capability's reference generator, with the model file the record names by SHA-256 (§4.1).
|
||
Appendix A restates the generator for a second implementation.
|
||
|
||
Relationship to [ai-usage](ai-usage.md): a taste prior carries its owner's usage statement, read
|
||
by ai-usage §3.6, and a ranking states the use it made of the prior in ai-usage §6.1's form; the
|
||
preference is decided by ai-usage §5.2 rule 2 (§9.3).
|
||
|
||
Relationship to [synthesis](synthesis.md): a picture an archive holds is generated; its origin
|
||
claim, where its publisher signs one, is synthesis §3's, step `generate`. Nothing here changes
|
||
a class.
|
||
|
||
Relationship to the contribution record, `wai.media.contribution`: §11 names the slot a
|
||
contribution session's `candidates` and `select` steps fill to point at an archive, and the
|
||
disclosure member they carry.
|
||
|
||
## 2. Records
|
||
|
||
Every record of this extension is a JSON object (RFC 8259) under the encodings of
|
||
[jwp-receipts](jwp-receipts.md) §2.4.3: byte strings in lowercase hexadecimal; integers unsigned,
|
||
at most 2^53 − 1, in plain decimal; no other number; no boolean; a **term** and a **date-time**
|
||
as defined there. A record is read as jwp-receipts §3.1 step 1 reads a claim: RFC 8259's grammar,
|
||
no member named twice in one object, at most 32 levels of nesting. Each record has exactly the
|
||
members its section lists, no member missing and none added, at any level, except where a
|
||
section marks a member OPTIONAL, and a `kind` naming it; one that does not, or whose member is
|
||
of another type or outside its range, is `record_malformed`.
|
||
|
||
Every record carries `issued_at` (a date-time: when its signer signed it), `signer_pubkey` (32
|
||
bytes, the Ed25519 key of RFC 8032 that signs it) and `sig` (64 bytes):
|
||
|
||
```
|
||
sig = Ed25519(signer_key, "wai:exploration\x01" || JCS(record without "sig"))
|
||
link_hash = BLAKE3("wai:exploration-link\x01" || JCS(record))
|
||
```
|
||
|
||
JCS is RFC 8785, which on these values reduces to what jwp-receipts §2.4.3 states. The signature
|
||
is verified strictly ([SPEC](../SPEC.md) §7 *Signatures*): a key that fails step 1 or 2 is
|
||
`bad_key`, and a signature that fails a later step `bad_signature`. A record is named by its
|
||
link hash wherever another names it.
|
||
|
||
A **picture** is named by its samples: the SHA-256 (FIPS 180-4) of its `RGB8` buffer as
|
||
[reconstruction-binding](reconstruction-binding.md) §2 defines it (rows top to bottom, pixels
|
||
left to right, three bytes a pixel, no padding), its **samples digest**. A picture object is
|
||
`{"samples", "width", "height"}`, and `{"samples", "width", "height", "descriptors"}` where a
|
||
table says it carries descriptors: a samples digest, a width and a height each from 1 to 4096
|
||
with their product at most 2^23 (the ranges of an instruction object, SPEC §5), and a descriptor
|
||
vector (§3.4).
|
||
|
||
A record names the descriptor set it uses in `descriptors`: `wai-exploration:image6`, the one
|
||
this revision defines. Another value is `record_malformed`.
|
||
|
||
## 3. Descriptors
|
||
|
||
### 3.1 Luma
|
||
|
||
The descriptors are computed from a picture's `RGB8` buffer of *w* × *h* pixels, *n* = *w* · *h*,
|
||
in integer arithmetic; ⌊ ⌋ is the floor of an exact rational, and no step rounds otherwise. The
|
||
**luma** of a pixel with bytes *R*, *G*, *B* is
|
||
|
||
*Y* = (77 · *R* + 150 · *G* + 29 · *B* + 128) >> 8,
|
||
|
||
an integer from 0 to 255 (the weights sum to 256, so a grey pixel's luma is its value).
|
||
|
||
### 3.2 The six descriptors
|
||
|
||
Each descriptor is an integer from 0 to 1024. The **descriptor vector** is the six, in this
|
||
order:
|
||
|
||
| # | name | value |
|
||
|---|---|---|
|
||
| 1 | `luma` | ⌊1024 · Σ *Y* / (255 · *n*)⌋ |
|
||
| 2 | `chroma` | ⌊1024 · Σ (max(*R*, *G*, *B*) − min(*R*, *G*, *B*)) / (255 · *n*)⌋ |
|
||
| 3 | `detail` | with *P* = (*w* − 1) · *h* + *w* · (*h* − 1) and *D* the sum of \|*Y*(*x* + 1, *y*) − *Y*(*x*, *y*)\| over every horizontal pair and \|*Y*(*x*, *y* + 1) − *Y*(*x*, *y*)\| over every vertical pair: 0 when *P* is 0, otherwise min(1024, ⌊1024 · *D* / (16 · *P*)⌋) |
|
||
| 4 | `palette` | each pixel's colour is (*R* >> 6) · 16 + (*G* >> 6) · 4 + (*B* >> 6), one of 64; with *k*ᵢ the number of pixels of colour *i*: ⌊1024 · (*n*² − Σ *k*ᵢ²) / *n*²⌋ |
|
||
| 5 | `centroid_x` | with *V* = *Y* + 1 at each pixel: ⌊1024 · Σ (2*x* + 1) · *V* / (2 · *w* · Σ *V*)⌋ |
|
||
| 6 | `centroid_y` | ⌊1024 · Σ (2*y* + 1) · *V* / (2 · *h* · Σ *V*)⌋ |
|
||
|
||
Sums run over every pixel unless the row says otherwise; *x* runs from 0 to *w* − 1 left to
|
||
right and *y* from 0 to *h* − 1 top to bottom. Every intermediate value fits in 64 unsigned bits
|
||
for every size §2 admits.
|
||
|
||
### 3.3 Why these six
|
||
|
||
Each answers a question a viewer asks of a picture, in one number: how bright it is (`luma`); how
|
||
colourful (`chroma`, the mean spread of a pixel's three channels); how busy (`detail`, the mean
|
||
luma step between neighbours, sixteen levels a step counting as full); how many colours it uses
|
||
and how evenly (`palette`, the probability that two pixels drawn at random differ in their
|
||
64-colour quantisation, the Gini–Simpson index); and where its light sits (`centroid_x` and
|
||
`centroid_y`, the luma-weighted centre, 512 being the frame's centre; *V* is *Y* + 1 so that a
|
||
black picture has a centre). They are arithmetic over the samples, with no learned model and so
|
||
no population's judgement inside them: they place a picture, they do not rank it. Each is scaled
|
||
to the same range so that a distance (§3.4) weighs no axis above another by its units; weighing
|
||
one above another is a taste, which §8 makes a declared, owned object instead.
|
||
|
||
### 3.4 Distance
|
||
|
||
The **descriptor distance** of two vectors is Σ \|*a*ᵢ − *b*ᵢ\| over the six, an integer from 0 to
|
||
6144. In JSON a vector is an array of six integers, each from 0 to 1024.
|
||
|
||
### 3.5 Grids
|
||
|
||
A **grid** is an array of 1 to 4 **axes**, each `{"descriptor", "lo", "hi", "bins"}`: a descriptor
|
||
name of §3.2, no name twice; 0 ≤ `lo` < `hi` ≤ 1024; `bins` from 1 to 64; and the product of
|
||
every axis's `bins`, the grid's **cells**, at most 4096. The **bin** of a value *d* on an axis is
|
||
0 when *d* < `lo`, `bins` − 1 when *d* ≥ `hi`, and ⌊(*d* − `lo`) · `bins` / (`hi` − `lo`)⌋
|
||
otherwise. The **niche** of a vector is its bins read as a mixed-radix number, the first axis
|
||
most significant: *k* = 0, then *k* = *k* · `bins` + bin for each axis in order.
|
||
|
||
## 4. The generator path
|
||
|
||
### 4.1 Generation
|
||
|
||
`gen(model, prompt, seed, steps, w, h)` is the picture SPEC §5 has a sink make for an
|
||
instruction object of `wai.generate.spectral`: the reference generator's
|
||
`generate(model, prompt, seed, steps, h, w)`, `w` · `h` · 3 bytes of `RGB8`, with the model file
|
||
whose SHA-256 the record names as `sha256:` and 64 lowercase hexadecimal digits. A prompt is what
|
||
an instruction object's `prompt` is: 0 to 256 bytes, each 0x20 to 0x7E other than `"` and `\`.
|
||
A seed is from 0 to 2^32 − 1 and `steps` from 1 to 64. Appendix A restates the generator.
|
||
|
||
A verifier holds model files and finds one by its SHA-256. A record that asks it to generate with
|
||
a model file it does not hold is `model_unheld`.
|
||
|
||
A generator other than `wai.generate.spectral` is named by a term and is not recomputed here
|
||
(§6.3, §10.2).
|
||
|
||
### 4.2 Modifiers and derived prompts
|
||
|
||
An archive declares 0 to 8 **modifiers**, each 1 to 32 bytes of `a`–`z` and `0`–`9`: words the
|
||
search may add to the prompt. A **modifier mask** is an integer below 2^*M*, *M* the number of
|
||
modifiers. The **derived prompt** of a mask is the prompt followed, for each *i* from 0 to *M* − 1
|
||
whose bit *i* is set, by one space (0x20) and modifier *i*. The derived prompt of the full mask
|
||
MUST be a prompt (§4.1). The modifiers are the person's: the archive explores the space they
|
||
declare, and the prompt they wrote is always the first word.
|
||
|
||
### 4.3 Genomes
|
||
|
||
A **genome** is `(seed, steps, mods)`; its picture is `gen(model, derived(prompt, mods), seed,
|
||
steps, w, h)` for the archive's model, prompt, modifiers and size.
|
||
|
||
## 5. Archives
|
||
|
||
### 5.1 The request
|
||
|
||
An archive record carries what was asked:
|
||
|
||
| member | value |
|
||
|---|---|
|
||
| `generator` | `wai.generate.spectral` |
|
||
| `model` | `sha256:` and the model file's SHA-256 |
|
||
| `prompt` | a prompt (§4.1) |
|
||
| `modifiers` | 0 to 8 modifiers (§4.2) |
|
||
| `width`, `height` | the pictures' size (§2) |
|
||
| `steps` | from 1 to 64: the steps every initial trial uses |
|
||
| `descriptors` | `wai-exploration:image6` |
|
||
| `grid` | a grid (§3.5) |
|
||
| `search` | `{"schedule", "seed", "trials", "init"}`: `schedule` `wai-exploration:map-elites/1`; `seed` an integer, the search seed; `trials` from 1 to 4096; `init` from 1 to `trials` |
|
||
| `objective` | `"none"`, or a taste objective (§10.1): what decides between two pictures of one niche |
|
||
|
||
An objective of type `model` is `record_malformed` here: a schedule steered by a model a
|
||
verifier cannot run cannot be replayed.
|
||
|
||
### 5.2 The schedule `wai-exploration:map-elites/1`
|
||
|
||
The schedule draws from **splitmix64**, a 64-bit state *s* that starts at the search seed; each
|
||
draw sets *s* to *s* + 0x9E3779B97F4A7C15 modulo 2^64, then *z* = *s*, *z* = (*z* ⊕ (*z* >> 30)) ·
|
||
0xBF58476D1CE4E5B9, *z* = (*z* ⊕ (*z* >> 27)) · 0x94D049BB133111EB, each product modulo 2^64,
|
||
and returns *z* ⊕ (*z* >> 31). The archive *A* maps a niche to its **elite**; the visits *V* map
|
||
a niche to the number of trials that reached it. Both start empty. For each trial *t* from 0 to
|
||
`trials` − 1, in order:
|
||
|
||
1. **Genome.** When *t* < `init`: seed = draw mod 2^32, `steps` the request's, mods 0. Otherwise:
|
||
- with *O* the occupied niches in ascending order, *a* = *O*[draw mod \|*O*\|], then
|
||
*b* = *O*[draw mod \|*O*\|]; the parent is *A*[*b*] when *V*[*b*] < *V*[*a*], and *A*[*a*]
|
||
otherwise;
|
||
- mods = the parent's; when *M* > 0, for each *i* from 0 to *M* − 1 in order, bit *i* is
|
||
flipped when draw mod *M* is 0;
|
||
- with *d* = draw mod 8, steps = the parent's steps plus *d* − 4 when *d* < 4 and *d* − 3
|
||
otherwise, clamped to 1 to 64;
|
||
- seed = draw mod 2^32.
|
||
2. **Picture.** The genome's picture (§4.3), its descriptor vector and its niche *k* in the grid;
|
||
*V*[*k*] increases by 1.
|
||
3. **Score.** With a taste objective, the score of the vector under the prior (§8.2); with
|
||
`none`, no score.
|
||
4. **Placement.** When *k* is not occupied, the trial becomes its elite. When it is, the trial
|
||
replaces the elite only under a taste objective and only with a strictly greater score; a tie
|
||
keeps the earlier trial, and with `none` the first trial to reach a niche keeps it.
|
||
|
||
The parent is the less-visited of two occupied niches drawn at random: the search spends its
|
||
trials where few have landed. A child keeps its parent's recipe close (each modifier flips with
|
||
probability 1/*M*, the steps move by one to four) and draws a new seed. The archive is therefore a
|
||
function of the request alone.
|
||
|
||
### 5.3 The record
|
||
|
||
An archive record, `kind` `"wai-archive"`, has the members of §5.1 and:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `elites` | array | every occupied niche's elite, in strictly ascending order of `niche`, at least one |
|
||
| `coverage` | object | `{"occupied", "cells"}`: the number of elites and the grid's cells |
|
||
| `issued_at`, `signer_pubkey`, `sig` | | §2 |
|
||
|
||
An elite is `{"niche", "trial", "seed", "steps", "mods", "samples", "descriptors", "score"}`: its
|
||
niche, below the grid's cells; the trial that placed it, below `trials`, no trial twice; its
|
||
genome (`seed` below 2^32, `steps` from 1 to 64, `mods` below 2^*M*); its picture's samples
|
||
digest and descriptor vector; and its score, an integer under a taste objective and `null`
|
||
under `none`.
|
||
|
||
### 5.4 Verifying an archive
|
||
|
||
In this order:
|
||
|
||
1. The record reads (§2, §5.1, §5.3) and its signature verifies.
|
||
2. `coverage` states the number of elites and the grid's cells: otherwise `coverage_mismatch`.
|
||
3. A taste objective's prior resolves and verifies (§8.3, §8.4).
|
||
4. The verifier holds the model (`model_unheld`).
|
||
5. For each elite in order: its genome's picture has its samples digest
|
||
(`generation_mismatch`), the picture's descriptor vector is its `descriptors`
|
||
(`descriptor_mismatch`), that vector's niche is its `niche` (`niche_mismatch`), and its score
|
||
is the prior's score of the vector, or `null` with `none` (`score_mismatch`).
|
||
6. Under a policy that requires replay (§12.1): the schedule of §5.2, run from the request,
|
||
leaves exactly these elites, member for member: otherwise `archive_replay_mismatch`.
|
||
|
||
An archive that passes step 5 is **elite-checked**: every picture it lists is what its genome
|
||
makes, and sits where it says. One that passes step 6 is **replayed**: the archive is the
|
||
schedule's, every niche's elite is the one the schedule keeps, and no trial was left out or
|
||
chosen after the fact. Replay costs `trials` generations; step 5 costs one per elite.
|
||
|
||
## 6. Default-distance
|
||
|
||
### 6.1 The default set
|
||
|
||
The **default set** of a model, a prompt and a size is the 16 pictures `gen(model, prompt, k, 4,
|
||
w, h)` for *k* from 0 to 15: what the model makes for the prompt on its own, at the steps of the
|
||
registered conformance object (SPEC §5) and the first sixteen seeds. They stand for what a person
|
||
who chooses nothing receives, and they are the same sixteen for every verifier.
|
||
|
||
### 6.2 Two distances
|
||
|
||
A work's **descriptor distance** to the default set is the least descriptor distance (§3.4)
|
||
between its vector and a default's; `nearest_descriptor` is the lowest *k* that attains it. Its
|
||
**sample distance** is the least ⌈1024 · Σ \|*a* − *b*\| / (765 · *n*)⌉ between its buffer and a
|
||
default's, the sum over every byte; `nearest_sample` is the lowest *k* that attains it.
|
||
|
||
Both are given because they answer different questions. The descriptor distance says how
|
||
different a *kind* of picture the work is from what the model does on its own, and is blind to
|
||
which exact draw it is. The sample distance says whether the work *is* a default: it is 0 exactly
|
||
when the work's bytes are a default's (the ceiling keeps any difference above 0), and otherwise
|
||
how far in samples. A work that is seed 3 of the prompt as written has sample distance 0; a work
|
||
regenerated with other words, other steps or another seed, or edited afterwards, does not.
|
||
|
||
### 6.3 The record and its class
|
||
|
||
A distance record, `kind` `"wai-distance"`:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `work` | picture with descriptors | the work |
|
||
| `generator` | term | `wai.generate.spectral`, or a term naming another generator |
|
||
| `model` | term | for `wai.generate.spectral`, `sha256:` and the model file's SHA-256; otherwise a term naming the model |
|
||
| `prompt` | string | a prompt (§4.1) |
|
||
| `descriptors` | string | `wai-exploration:image6` |
|
||
| `defaults` | array | 0 to 16 entries `{"samples", "descriptors"}`: a default's samples digest or `null`, and its vector |
|
||
| `class` | string | `measured`, `estimate` or `unknown` |
|
||
| `descriptor_distance`, `nearest_descriptor`, `sample_distance`, `nearest_sample` | integer or `null` | §6.2 |
|
||
| `issued_at`, `signer_pubkey`, `sig` | | §2 |
|
||
|
||
The class says what kind of figure it is:
|
||
|
||
- **`measured`**: the generator is exact, the default set is recomputed, and the figure is a
|
||
measurement anyone holding the model and the work repeats. `defaults` has 16 entries, every
|
||
`samples` a digest, in seed order, and all four figures are integers.
|
||
- **`estimate`**: the generator is not exact. Its defaults are the signer's statement of what
|
||
the generator made (their vectors, and their samples where the signer has them), and the
|
||
figure is the descriptor distance from those: an estimate of how far the work is from the
|
||
generator's defaults, never a measurement of it. `defaults` has 1 to 16 entries,
|
||
`descriptor_distance` and `nearest_descriptor` are integers, and `sample_distance` and
|
||
`nearest_sample` are `null`.
|
||
- **`unknown`**: no default set is known. `defaults` is empty and all four figures are `null`.
|
||
Unknown is never zero: a record that writes 0 for a figure it does not have states that the
|
||
work is a default.
|
||
|
||
A record whose members break its class's shape is `record_malformed`. A `measured` record over a
|
||
generator other than `wai.generate.spectral`, or a record over `wai.generate.spectral` of
|
||
another class, is `distance_class_invalid`: the exact generator's figure is always a
|
||
measurement, and no other generator's ever is.
|
||
|
||
### 6.4 Verifying a distance
|
||
|
||
In this order, after the record reads and its signature verifies:
|
||
|
||
1. The class agrees with the generator (`distance_class_invalid`).
|
||
2. Held samples of the work are `width` · `height` · 3 bytes (`samples_mismatch`).
|
||
3. `measured`: the verifier holds the model (`model_unheld`); the default set at the work's size
|
||
is made, and each entry's samples digest and vector are the default's
|
||
(`default_mismatch`); the verifier holds the work's samples (`work_unheld`), and their vector
|
||
is the work's `descriptors` (`descriptor_mismatch`); all four figures are computed by §6.2.
|
||
4. `estimate`: where the work's samples are held, their vector is its `descriptors`
|
||
(`descriptor_mismatch`); the descriptor distance and the nearest default are computed from
|
||
the work's vector and the stated vectors.
|
||
5. `unknown`: where the work's samples are held, their vector is its `descriptors`
|
||
(`descriptor_mismatch`).
|
||
6. The figures computed are the figures stated (`distance_mismatch`).
|
||
|
||
A verifier reports the class with the figures, and reports an `unknown` figure as unknown,
|
||
never as 0.
|
||
|
||
## 7. Collection statements
|
||
|
||
### 7.1 The record
|
||
|
||
A collection statement, `kind` `"wai-collection"`, is the homogenization meter of a set of
|
||
pictures:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `scope` | string | `gallery`, `room` (a room's outputs), `session` (a session's candidates) or `archive` |
|
||
| `subject` | term | what the collection is: a gallery's URI, a room's id, an archive's link hash |
|
||
| `descriptors` | string | `wai-exploration:image6` |
|
||
| `grid` | array | a grid (§3.5) |
|
||
| `members` | array | 2 to 256 pictures with descriptors; a picture may appear more than once |
|
||
| `coverage` | object | `{"occupied", "cells"}` |
|
||
| `distances` | object | §7.2 |
|
||
| `issued_at`, `signer_pubkey`, `sig` | | §2 |
|
||
|
||
### 7.2 The figures
|
||
|
||
- `coverage`: `occupied`, the number of distinct niches the members' vectors fall in; `cells`,
|
||
the grid's.
|
||
- `distances`: over every unordered pair of members (*i* < *j*), the descriptor distance of
|
||
their vectors: `pairs`, their number; `sum`, their total, so the mean is `sum` / `pairs`
|
||
exactly; `min` and `max`; `median`, the element at position ⌊(`pairs` − 1) / 2⌋ of the
|
||
distances in ascending order; `width`, from 1 to 6144; and `histogram`, 16 counts, a distance
|
||
*d* counted in bin min(⌊*d* / `width`⌋, 15).
|
||
|
||
A collection whose members are all alike has few occupied cells and small distances; one that
|
||
explores has many and large ones. The figures say nothing of quality.
|
||
|
||
### 7.3 Verifying a collection
|
||
|
||
After the record reads and its signature verifies: for each member in order, the verifier holds
|
||
its samples (`member_unheld`), of its size (`samples_mismatch`), whose vector is its
|
||
`descriptors` (`descriptor_mismatch`); then `coverage` is computed from the vectors
|
||
(`coverage_mismatch`), and then `distances` with the stated `width` (`distances_mismatch`).
|
||
Every figure is computed from samples the verifier holds; a statement over pictures it does not
|
||
hold is not checked, and is not accepted.
|
||
|
||
## 8. Taste priors
|
||
|
||
### 8.1 The prior
|
||
|
||
A **taste prior** is a file: the canonical form (JCS) of a signed record, `kind` `"wai-taste"`:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `owner` | 32 B hex | the Ed25519 key of the person or community whose taste it is |
|
||
| `scope` | string | `personal` or `community` |
|
||
| `descriptors` | string | `wai-exploration:image6` |
|
||
| `terms` | array | 1 to 32 terms (§8.2) |
|
||
| `usage` | object or `null` | the owner's usage statement ([ai-usage](ai-usage.md) §3), or `null` |
|
||
| `issued_at`, `signer_pubkey`, `sig` | | §2 |
|
||
|
||
A file whose bytes are not the canonical form of the record they hold is `record_malformed`,
|
||
and so is a `usage` that does not read by ai-usage §3.6. The prior's **digest** is the SHA-256
|
||
of the file.
|
||
|
||
### 8.2 The score
|
||
|
||
A term is `{"descriptor", "shape", "at", "weight"}`: a descriptor name; a shape; `at` from 0 to
|
||
1024, which is 0 for `rise` and `fall`; and `weight` from 1 to 1024. Its value at a vector whose
|
||
descriptor is *d*:
|
||
|
||
| shape | value |
|
||
|---|---|
|
||
| `rise` | `weight` · *d* |
|
||
| `fall` | `weight` · (1024 − *d*) |
|
||
| `near` | `weight` · (1024 − \|*d* − `at`\|) |
|
||
| `far` | `weight` · \|*d* − `at`\| |
|
||
|
||
The **score** of a vector is the sum of its terms' values, an integer from 0 to 2^25. Every
|
||
value is non-negative, so the arithmetic is unsigned throughout and the same on every machine. A
|
||
prior that likes calm, dark pictures says `fall` on `detail` and `luma`; one that likes a
|
||
mid-grey says `near` at 512; one that wants pictures unlike the usual says `far` from where
|
||
the usual sits. The score is a few integer operations over six numbers, stated in full here,
|
||
so it is not expressed as an integer-operator graph ([integer-operators](integer-operators.md)).
|
||
|
||
### 8.3 Carriage as a WAI prior
|
||
|
||
A taste prior is a parameter set of one file in SPEC §3.1's sense: what a ranking's output
|
||
depends on, besides its input. A record names it by a **pin** of SPEC §3.1's members `id` (a
|
||
name for people, 1 to 256 bytes), `sha256` (the prior's digest) and `determinism` (in words,
|
||
1 to 256 bytes), and no other member: the form is undeclared, and the digest covers the one file.
|
||
A verifier holds priors and finds one by its digest, as a sink resolves a pin: nothing but the
|
||
digest selects it, not the `id`. A pin that names a prior the verifier does not hold is
|
||
`objective_unresolved`.
|
||
|
||
### 8.4 Ownership and usage
|
||
|
||
A prior is its owner's: it **MUST** be signed by `owner`. One signed by any other key is
|
||
`taste_not_owner`, whatever its signature. The rule is one of attribution: a taste is ascribed
|
||
to a key only by that key's signature, so no tool can present a prior as someone's who did not
|
||
sign it. The checks run in this order: the file reads, the signature verifies (`bad_key`,
|
||
`bad_signature`), and the signer is the owner.
|
||
|
||
The owner's usage statement governs the prior as it governs any content
|
||
([ai-usage](ai-usage.md) §5): it is the prior's signed statement, signed with it by the owner. A
|
||
ranking states the use it made of the prior (§9.3), and a use the statement disallows is refused.
|
||
A prior that travels in a WAI envelope carries the same statement in the envelope's manifest
|
||
(ai-usage §4.1), and an agent that consumes it claims its use there as for any object.
|
||
|
||
This extension sets no consent requirement for a service's own mechanics: making an archive,
|
||
measuring a distance, ranking with the prior a person chose. Using a distributor's WAI service is
|
||
the person's agreement to how that service works. The usage statement is the owner's preference,
|
||
read as ai-usage reads any statement. Where a regime asks for a lawful basis for processing a
|
||
personal prior, the service records it in a `lawful-basis` claim
|
||
([jwp-receipts](jwp-receipts.md) §2.4.6).
|
||
|
||
### 8.5 No default objective
|
||
|
||
This extension defines no taste prior of its own, ships none as a default, and ranks nothing
|
||
without one. A personal prior and a community prior are the same kind of object: a community's
|
||
taste is owned by the community's key, and sits beside each member's own, not above it. No prior
|
||
is privileged by the specification, by a verifier or by a registry: what ranks a set is always a
|
||
named prior someone owns, and anyone may compare what two priors do with the same pictures. A
|
||
taste is as legitimate when it prefers what most priors reject: `far` makes an anti-aesthetic as
|
||
expressible as an aesthetic.
|
||
|
||
## 9. Rankings
|
||
|
||
### 9.1 The record
|
||
|
||
A ranking, `kind` `"wai-ranking"`, says what a taste prior made of a set of pictures:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `prior` | object | the prior's pin (§8.3) |
|
||
| `descriptors` | string | `wai-exploration:image6` |
|
||
| `candidates` | array | 1 to 256 pictures with descriptors |
|
||
| `scores` | array | one integer per candidate, in their order |
|
||
| `order` | array | the candidates' indices, best first: a permutation of 0 to *n* − 1 |
|
||
| `usage` | array | 0 to 3 entries `{"vocabulary", "term"}`: the use made of the prior, in ai-usage §6.1's form, in strictly ascending order of `vocabulary` |
|
||
| `issued_at`, `signer_pubkey`, `sig` | | §2 |
|
||
|
||
A `usage` entry's `vocabulary` is `aipref`, `cawg` or `tdmrep`, and its `term` a term of that
|
||
vocabulary (ai-usage §6.2 rule 4) or `null`, a use outside it. Anything else is
|
||
`record_malformed`. A ranking is signed by whoever ran it; the prior's owner signed the prior.
|
||
|
||
### 9.2 The order
|
||
|
||
Each candidate's score is the prior's score of its vector. The order is by score, greatest
|
||
first; candidates of equal score keep their order in `candidates`, the lower index first.
|
||
|
||
### 9.3 The prior's usage
|
||
|
||
The prior's usage statement, where it has one, governs the use. For every vocabulary it carries,
|
||
`usage` has an entry (`prior_usage_unanswered`); for each entry whose `term` is not `null`, the
|
||
statement's preference for the term (ai-usage §3.2, §3.4, §3.5) is not disallow
|
||
(`prior_usage_disallowed`). A ranking states the use it made in each vocabulary as a
|
||
consumption claim does (ai-usage §6.1): running a prior to order pictures is the ranking signer's
|
||
use, which it names. A prior with no statement governs nothing; a ranking MAY still state its
|
||
use.
|
||
|
||
### 9.4 Verifying a ranking
|
||
|
||
After the record reads and its signature verifies:
|
||
|
||
1. The prior resolves and verifies (§8.3, §8.4).
|
||
2. For each candidate whose samples the verifier holds: they are of its size
|
||
(`samples_mismatch`), and their vector is its `descriptors` (`descriptor_mismatch`). A
|
||
candidate whose samples are not held is scored from its stated vector.
|
||
3. The scores and the order are those of §9.2 (`ranking_mismatch`).
|
||
4. The usage is answered and allowed (§9.3).
|
||
|
||
A ranking that passes reproduces: any party holding the prior gets the same scores and the same
|
||
order from the same vectors. The verifier reports whether every vector was recomputed from
|
||
samples or some were taken as stated.
|
||
|
||
## 10. Disclosure of objectives
|
||
|
||
### 10.1 The member `objective`
|
||
|
||
A record of a generation, a selection or a ranking says which aesthetic or reward model steered
|
||
it, or that none did, in the member `objective`:
|
||
|
||
| value | meaning |
|
||
|---|---|
|
||
| `"none"` | no aesthetic or reward model steered the record |
|
||
| `{"type": "taste", "prior"}` | a taste prior of §8, by its pin: a verifier resolves it and runs it |
|
||
| `{"type": "model", "sha256", "id"}` | another aesthetic or reward model, by the SHA-256 of its parameter set (SPEC §3.1) and a name for people: named, not run here |
|
||
|
||
A **taste objective** is a value of type `taste`. An archive's `objective` (§5.1) is the
|
||
disclosure of its placement rule, and a ranking's `prior` is its objective: both are required
|
||
members. A pick (§10.2) that a model steered **MUST** carry `objective` naming the model, and one
|
||
that nothing steered **SHOULD** carry `"none"`. A record of another extension that a model may
|
||
steer carries the same member where that extension adds it (§11).
|
||
|
||
### 10.2 The pick
|
||
|
||
A pick, `kind` `"wai-pick"`, says that a party generated or selected a work, and what steered it:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `act` | string | `generate` or `select` |
|
||
| `work` | picture | the work |
|
||
| `from` | object | where it came from (below) |
|
||
| `objective` | | OPTIONAL: §10.1 |
|
||
| `issued_at`, `signer_pubkey`, `sig` | | §2 |
|
||
|
||
`from` is one of:
|
||
|
||
- `{"type": "archive", "archive", "niche"}`: a `select` of the elite of `niche` in the archive
|
||
whose link hash is `archive`;
|
||
- `{"type": "set", "set"}`: a `select` of one of 1 to 256 samples digests;
|
||
- `{"type": "generation", "generator", "model", "prompt", "seed", "steps"}`: a `generate`, by a
|
||
generator term, a model term (for `wai.generate.spectral`, `sha256:` and the model file's
|
||
SHA-256), a prompt (§4.1), and a seed (below 2^32) and steps (1 to 64), each `null` where the
|
||
generator has none.
|
||
|
||
A `generate` whose `from` is not a generation, or a `select` whose `from` is one, is
|
||
`record_malformed`.
|
||
|
||
A pick from an archive **inherits** the elite's genome: its seed, steps and modifier mask, and so
|
||
its derived prompt. A pick from an archive whose objective is a taste prior was steered by that
|
||
prior, since the prior chose every elite: its `objective` MUST name the same prior
|
||
(`objective_mismatch`), absent or not.
|
||
|
||
### 10.3 Policy
|
||
|
||
A verifier sees steering only where a record shows it: through an archive a pick names (§10.2),
|
||
and otherwise not. So a missing `objective` is never read as `none`: the record is
|
||
**undisclosed**, and a verifier reports it so. A policy MAY require the member of every pick
|
||
(§12.1); under it, a pick without `objective` is `objective_undisclosed`. Every archive and ranking carries its objective by
|
||
construction. A universal aesthetic objective therefore cannot steer a record silently: it is
|
||
named by digest, or the record says that nothing steered it, or the record is undisclosed and a
|
||
policy that requires disclosure refuses it.
|
||
|
||
### 10.4 Verifying a pick
|
||
|
||
After the record reads and its signature verifies, in this order:
|
||
|
||
1. Without `objective`, under a policy that requires it: `objective_undisclosed`.
|
||
2. A taste objective's prior resolves and verifies (§8.3, §8.4).
|
||
3. Held samples of the work are of its size (`samples_mismatch`).
|
||
4. From an archive: the verifier holds the archive, verified earlier in the same case
|
||
(`archive_unheld`); the archive has an elite at `niche` whose samples digest is the work's, and
|
||
the work's size is the archive's (`pick_not_in_archive`); and where the archive's
|
||
objective is a taste prior, the pick's `objective` names that prior's digest
|
||
(`objective_mismatch`).
|
||
5. From a set: the work's samples digest is one of the set (`pick_not_in_set`).
|
||
6. From a generation by `wai.generate.spectral` with a seed and steps: the verifier holds the
|
||
model (`model_unheld`), and `gen` at the work's size has the work's samples digest
|
||
(`generation_mismatch`). Any other generation is taken as stated.
|
||
|
||
The verifier reports the objective (`none`, the type and digest it names, or `undisclosed`),
|
||
how the work was checked (`in-archive`, `in-set`, `regenerated` or `stated`) and, for a pick
|
||
from an archive or a regenerated generation, the genome.
|
||
|
||
## 11. The slot contribution fills
|
||
|
||
The contribution record, `wai.media.contribution`, records a creative session step by step: its
|
||
`candidates` step commits a set of pictures by samples digest and seed, and its `select` step
|
||
picks one. This revision leaves it one slot and one member, which that extension fills:
|
||
|
||
- **`archive`**: a `candidates` step MAY name an archive record by its link hash. The set it
|
||
commits is then the archive's elites in ascending niche order: each member's samples digest is
|
||
the elite's `samples`, and its generation is the elite's genome, the seed, the steps and the
|
||
derived prompt (§4.3), at the archive's model and size. A `select` of a member of such a set
|
||
inherits the elite's genome as a pick from the archive does (§10.2). How the member is written
|
||
in a step, and how a step that names an archive is checked against it, are contribution's.
|
||
- **`objective`**: a step that a model steered carries the member of §10.1 with its meaning
|
||
there; a `select` from a set an archive steered by a taste prior carries that prior.
|
||
|
||
Nothing here depends on contribution: an archive, a pick and their checks stand alone.
|
||
|
||
## 12. Verification
|
||
|
||
### 12.1 Inputs
|
||
|
||
A verifier is given a **case**: records in an order, as texts; what it holds, each found by its
|
||
SHA-256 (model files, taste prior files, and `RGB8` sample buffers); and its policy:
|
||
|
||
- `replay`: `required`, every archive is replayed (§5.4 step 6); or `elites`, it is
|
||
elite-checked;
|
||
- `objective`: `required`, every pick carries `objective` (§10.3); or `optional`.
|
||
|
||
### 12.2 Steps
|
||
|
||
The records are verified in their order, each by its section: §5.4, §6.4, §7.3, §9.4 or §10.4,
|
||
by its `kind`. A record whose `kind` is none of `wai-archive`, `wai-distance`,
|
||
`wai-collection`, `wai-ranking` and `wai-pick`, or that does not read, is `record_malformed`.
|
||
Each section's checks follow reading and the signature (§2), in the order the section gives;
|
||
the first that fails is the case's refusal, with the record's position. An archive that a pick
|
||
names is held only once it has been verified, earlier in the case.
|
||
|
||
### 12.3 What an accepted case states
|
||
|
||
For each record, in order, its `kind` and:
|
||
|
||
- an archive: its link hash, `replayed` or `elites`, `occupied`, `cells`, and its objective
|
||
(`none`, or `{"type", "sha256"}`);
|
||
- a distance: its link hash, its class and the four figures, `null` where unknown;
|
||
- a collection: its link hash, the number of members, `occupied`, `cells` and `distances`;
|
||
- a ranking: its link hash, the prior's digest, owner and scope, the order, `recomputed` or
|
||
`stated`, and for each `usage` entry its vocabulary, term and preference (`allow`, `unknown`,
|
||
`outside` for a `null` term, or `absent` when the prior's statement does not carry the
|
||
vocabulary);
|
||
- a pick: its link hash, its act, its objective, its check, and its genome: `seed`, `steps`,
|
||
`mods` (0 for a generation) and the derived `prompt`, or `null` for a pick from a set or a
|
||
generation taken as stated.
|
||
|
||
## 13. Reasons
|
||
|
||
The codes this extension adds, each with where it is raised:
|
||
|
||
| reason | raised at |
|
||
|---|---|
|
||
| `record_malformed` | §2, §5.1, §6.3, §8.1, §9.1, §10.2, §12.2 |
|
||
| `bad_key` | §2 |
|
||
| `bad_signature` | §2 |
|
||
| `model_unheld` | §4.1, §5.4 step 4, §6.4 step 3, §10.4 step 6 |
|
||
| `objective_unresolved` | §8.3 |
|
||
| `taste_not_owner` | §8.4 |
|
||
| `objective_undisclosed` | §10.3, §10.4 step 1 |
|
||
| `objective_mismatch` | §10.2, §10.4 step 4 |
|
||
| `generation_mismatch` | §5.4 step 5, §10.4 step 6 |
|
||
| `samples_mismatch` | §6.4 step 2, §7.3, §9.4 step 2, §10.4 step 3 |
|
||
| `descriptor_mismatch` | §5.4 step 5, §6.4, §7.3, §9.4 step 2 |
|
||
| `niche_mismatch` | §5.4 step 5 |
|
||
| `score_mismatch` | §5.4 step 5 |
|
||
| `coverage_mismatch` | §5.4 step 2, §7.3 |
|
||
| `archive_replay_mismatch` | §5.4 step 6 |
|
||
| `distance_class_invalid` | §6.3, §6.4 step 1 |
|
||
| `default_mismatch` | §6.4 step 3 |
|
||
| `work_unheld` | §6.4 step 3 |
|
||
| `distance_mismatch` | §6.4 step 6 |
|
||
| `member_unheld` | §7.3 |
|
||
| `distances_mismatch` | §7.3 |
|
||
| `ranking_mismatch` | §9.4 step 3 |
|
||
| `prior_usage_unanswered` | §9.3 |
|
||
| `prior_usage_disallowed` | §9.3 |
|
||
| `archive_unheld` | §10.4 step 4 |
|
||
| `pick_not_in_archive` | §10.4 step 4 |
|
||
| `pick_not_in_set` | §10.4 step 5 |
|
||
|
||
## 14. Conformance
|
||
|
||
[`live-conformance/exploration/`](../live-conformance/exploration/) holds the corpus, written from
|
||
fixed seeds by `wai_exploration_vectors gen` as `vectors.json`. It has:
|
||
|
||
- **Generations**: pictures of `wai.generate.spectral` at small sizes with their samples digests,
|
||
among them prompts whose words select each component type, a negative orientation and a
|
||
gradient, and a derived prompt: the check of Appendix A.
|
||
- **Descriptors**: buffers with their vectors, among them a single pixel, a single row and a
|
||
single column, flat buffers, a checkerboard and generated pictures.
|
||
- **Archives**: archives without an objective and under a taste prior, with modifiers and
|
||
without, replayed and elite-checked; and one refused for each defect of §5.4, among them a
|
||
niche whose descriptor does not recompute, a seed that does not regenerate its picture, an
|
||
elite dropped (which every elite check passes and replay refuses), and a prior signed by a key
|
||
other than its owner's.
|
||
- **Distances**: a measured distance of a work pulled from the defaults and of a work that is a
|
||
default (sample distance 0), an estimate and an unknown; and one refused for each defect of
|
||
§6.4, among them a distance stated wrong, a measured figure over a generator that is not exact,
|
||
and an unknown written as 0.
|
||
- **Collections**: the default set and an archive's elites as galleries; and one refused for each
|
||
defect of §7.3.
|
||
- **Taste priors and rankings**: a personal prior, a community prior with a usage statement and
|
||
an anti-aesthetic prior, each ranking the same pictures, all three written in code with
|
||
hand-set weights; a ranking from stated vectors; and one refused for each defect of §9.4,
|
||
among them a ranking that does not reproduce, a prior signed by a non-owner, a use the owner's
|
||
statement disallows and a prior file not in canonical form.
|
||
- **Picks**: picks from an archive (inheriting the elite's genome), from a set and from a
|
||
generation, under each kind of objective and undisclosed; and one refused for each defect of
|
||
§10.4, among them a pick without `objective` under a policy that requires it and a pick from a
|
||
prior-steered archive that states `none`.
|
||
|
||
A conforming verifier gives every case the outcome, the reason, the record and the statements
|
||
the corpus states. `wai_exploration_vectors verify` and the test `tests/exploration.rs` check
|
||
that the file regenerates byte for byte, that `wai-rs` gives every case its outcome, that every
|
||
reason of §13 appears, and that §13 lists exactly the reference's codes.
|
||
`live-conformance/exploration_verify.py` is the second implementation, written from this text:
|
||
it shares no code with `wai-rs`; it implements the generator from Appendix A and the descriptors
|
||
from §3, reads usage statements with the AI usage corpus's second implementation
|
||
(`ai_usage_verify.py`), checks every signature with WAI's strict rule
|
||
(`claim-conformance/_ed25519.py`) and every link hash with BLAKE3 from
|
||
`claim-conformance/_blake3.py`; it mutates copies of the corpus and requires every copy to fail,
|
||
and drops each of its own checks in turn and requires the corpus to catch the weakened verifier.
|
||
|
||
## 15. Security and privacy considerations
|
||
|
||
- **Cost.** Replaying an archive costs `trials` generations at its size, and making a default
|
||
set sixteen. A verifier bounds what it will spend before it starts; a case it will not
|
||
replay under a policy that requires replay is declined, not accepted elite-checked.
|
||
- **What is proved.** An elite-checked or replayed archive proves what the generator makes from
|
||
each genome, and, replayed, that the schedule kept those pictures. A measured distance proves
|
||
how far a work is from the defaults. Neither says who made the work, which the contribution
|
||
record and [synthesis](synthesis.md) record.
|
||
- **Gaming a distance.** A work far from the defaults is not thereby original: a distance is a
|
||
measurement, not a judgement, and a collection statement shows whether many works moved away
|
||
from the defaults in the same direction.
|
||
- **Taste describes a person.** A personal prior says what one person likes. It is ascribed to a
|
||
person only by that person's signature (§8.4), and its owner's usage statement travels with it.
|
||
A party that holds a ranking learns how a prior ordered those pictures, which is what a ranking
|
||
is for. Where a regime asks for a lawful basis for processing it, that is a `lawful-basis`
|
||
claim's (§8.4).
|
||
- **Undisclosed steering.** A pick without `objective` is reported undisclosed, never as `none`.
|
||
A party that steers a selection with a model and states `none` makes a false signed statement;
|
||
where the steering came from an archive the pick names, the verifier sees it (§10.2).
|
||
- **Descriptors are coarse.** Six numbers do not describe a picture. Two pictures that differ in
|
||
every way a viewer cares about can share a vector; coverage counts niches of a grid, not
|
||
ideas.
|
||
|
||
## Appendix A. The generator, restated
|
||
|
||
This appendix restates the reference generator of `wai.generate.spectral`, `generate.rs`, for a
|
||
second implementation. The reference governs; the corpus's generations check that the two agree
|
||
(§14). Integers here are unbounded or 64-bit as stated; ÷ divides and truncates toward zero;
|
||
*a* mod *b* for *b* > 0 is the remainder in 0 to *b* − 1; >> on a negative integer is the floor
|
||
of division by a power of two.
|
||
|
||
**A.1 The model file** is a JSON object with: `sine_lut`, an array of `lut_size` integers;
|
||
`lut_size` (*T*); `lut_bits` (14 when absent); `freq_max`; `amp_bits`; `color_offsets`, three
|
||
integers; `base_components`; `step_components`; and `lexicon`, an object mapping a word to an
|
||
array of up to ten integers, read as `[r, g, b, freq, orient, radial, mirror, gradient, angular,
|
||
spiral]` with absent entries 0.
|
||
|
||
**A.2 The intent.** The prompt's ASCII letters are lowered; its **tokens** are its maximal runs of
|
||
ASCII letters and digits, in order, each counted every time it occurs. Over the tokens that are
|
||
words of the lexicon, sum each of the ten entries; *n* is the number of such tokens. When *n* is
|
||
0 the intent is hue (256, 256, 256), freq 256, and every other value 0. Otherwise, with *m* the
|
||
greatest of the three colour sums and at least 1: hue*c* = sum*c* · 256 ÷ *m*; freq = sum ÷ *n*;
|
||
orient and gradient = sum ÷ *n* clamped to −256 to 256; radial, mirror, angular and spiral = sum
|
||
÷ *n* clamped to 0 to 256.
|
||
|
||
**A.3 The draw.** *K* = `base_components` + `steps` · `step_components`. With orient < 0,
|
||
(*sx*, *sy*) = (max(256 + orient, 0), 256); otherwise (256, max(256 − orient, 0)). *F* =
|
||
max(`freq_max` · freq ÷ 256, 1); span = 2*F* + 1; *A* = 2^`amp_bits`. The PRNG is §5.2's
|
||
splitmix64, with its state starting at fnv(prompt) ⊕ seed ⊕ 0xD1B54A32D192ED03, where fnv is
|
||
64-bit FNV-1a over the prompt's bytes (offset basis 14695981039346656037, prime 1099511628211).
|
||
With *t*₁ … *t*₄ = radial, mirror, angular, spiral, *P* = max(256 − Σ*t*, 48) and total = *P* +
|
||
Σ*t*, each of the *K* components draws, in this order: pick = draw mod total; *fx* = (draw mod
|
||
span) − *F*; *fy* = (draw mod span) − *F*; amp = (draw mod *A*) + 1; phase = draw mod *T*. Its
|
||
type is plane when pick < *P*, and otherwise the first *i* from 1 to 4 with pick < *P* + *t*₁ + … +
|
||
*t*ᵢ: 1 radial, 2 mirror, 3 angular, 4 spiral. Its frequencies are: radial (max(\|*fx*\|, 2), 0);
|
||
angular (\|*fx*\| mod 11 + 2, 0); spiral (\|*fx*\| mod 9 + 2, max(\|*fy*\|, 2)); plane and mirror
|
||
(*fx* · *sx* ÷ 256, *fy* · *sy* ÷ 256).
|
||
|
||
**A.4 The field.** *cx* = ⌊*w* / 2⌋, *cy* = ⌊*h* / 2⌋; gscale = (2^`lut_bits` · *A* · *K*) ÷ (2048 ·
|
||
max(*cy*, 1)). For each channel *c* with offset *o* = `color_offsets`[*c*] and each pixel (*x*,
|
||
*y*), with *dx* = *x* − *cx*, *dy* = *y* − *cy*, *r* = ⌊√(*dx*² + *dy*²)⌋ and θ = iatan2(*dy*, *dx*):
|
||
the accumulator is gradient · (*cy* − *y*) · gscale plus, over the components, amp ·
|
||
`sine_lut`[arg mod *T*], where arg is *fx* · *x* + *fy* · *y* + phase + *o* for a plane,
|
||
*fx* · *r* + phase + *o* for a radial, *fx* · \|*dx*\| + *fy* · \|*dy*\| + phase + *o* for a mirror,
|
||
*fx* · θ + phase + *o* for an angular and *fx* · θ + *fy* · *r* + phase + *o* for a spiral component.
|
||
|
||
**A.5 iatan2(*dy*, *dx*)**, an angle in 0 to *T* − 1: when *dx* = 0, it is 0 for *dy* = 0, *T* ÷ 4
|
||
for *dy* > 0 and 3*T* ÷ 4 otherwise; when *dy* = 0, 0 for *dx* > 0 and *T* ÷ 2 otherwise. Else, *X*
|
||
= \|*dx*\| · 2^12, *Y* = \|*dy*\| · 2^12, ang = 0, and for *i* from 0 to 13 with the steps (128, 76,
|
||
40, 20, 10, 5, 3, 1, 1, 0, 0, 0, 0, 0): when *Y* > 0, (*X*, *Y*) = (*X* + (*Y* >> *i*), *Y* − (*X* >>
|
||
*i*)) and ang increases by the step; when *Y* < 0, (*X*, *Y*) = (*X* − (*Y* >> *i*), *Y* + (*X* >>
|
||
*i*)) and ang decreases by it. The angle is ang for *dx* ≥ 0 and *dy* ≥ 0, *T* ÷ 2 − ang for *dx* < 0
|
||
and *dy* ≥ 0, *T* ÷ 2 + ang for *dx* < 0 and *dy* < 0, and *T* − ang for *dx* ≥ 0 and *dy* < 0, each
|
||
taken mod *T*.
|
||
|
||
**A.6 The bytes.** With *g*₀ and *g*₁ the least and greatest of all 3*n* accumulators and range =
|
||
max(*g*₁ − *g*₀, 1), and *e*_c = 64 + hue_c · 192 ÷ 256: each accumulator *v* of channel *c* gives
|
||
*q* = ((*v* − *g*₀) · 255 + range ÷ 2) ÷ range and the byte min(max(*q* · *e*_c ÷ 256, 0), 255), at
|
||
the pixel's position in the `RGB8` buffer.
|