The extension text (extensions/influence.md), the influence module of wai-rs behind the feature influence, its corpus generator and committed corpus; settlement gains attribution lines (kind 2) recomputed from a basis, and contribution notes the sibling record. Co-Authored-By: Claude Opus 5.5 <[email protected]>
783 lines
47 KiB
Markdown
783 lines
47 KiB
Markdown
# WAI Extension: Contribution Records
|
||
|
||
> Status: Draft. Registers the record `wai.media.contribution`: who contributed what to a piece
|
||
> of media made by people and models together, and how much, computed from the process that
|
||
> made it. A tool signs a **session** naming its parties: people, each by a key and each
|
||
> countersigning its own membership, and models, each by its digest. Every act in the session
|
||
> is a signed **step** in a hash chain: a person authors or edits samples, a model generates,
|
||
> proposes candidates or inpaints a marked region, a party selects one candidate, transforms a
|
||
> state with a pinned derivation, composes layers, or rejects an output. Each act has a
|
||
> **dependency rule**, and re-executing the steps gives, for every sample of the output, the
|
||
> parties whose act produced its value (`made_by`) and the parties whose choices conditioned it
|
||
> (`directed_by`): the **authorship map**, computed rather than declared. A verifier checks
|
||
> what the steps say: that an edit or an inpainting changed no sample outside its region, that a
|
||
> selected output is a member of the set it was chosen from and that each candidate regenerates
|
||
> from its seed, that a transform recomputes, that the map recomputes, and that the output's
|
||
> origin claim ([synthesis](synthesis.md)) is at least what the map implies. The steps are the
|
||
> leaves of a Merkle tree, so a creator can disclose some of them with inclusion proofs; a
|
||
> prompt is a salted commitment until its creator opens it; and the outcome says which **tier**
|
||
> the disclosure reaches: `recomputed`, `checked` or `stated`. A sample whose label no disclosed,
|
||
> pinned rule fixes is **unknown** or **undisclosed**, never attributed to anyone, and the
|
||
> shares are sample counts per party, never one blended figure. No new transport. The reference
|
||
> implementation is the `contribution` module of `wai-rs` (feature `contribution`); the corpus
|
||
> is [`live-conformance/contribution/`](../live-conformance/contribution/), and its second
|
||
> implementation is `live-conformance/contribution_verify.py`.
|
||
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
|
||
>
|
||
> Texts read for this revision, each pinned to the version named: the C2PA Technical
|
||
> Specification, version 2.4 (April 2026), §10.2.3.2, §18.2, §18.15.1, §18.15.2 and §18.15.4;
|
||
> the Creator Assertions Working Group's Identity Assertion, version 1.2 (ratified 15 December
|
||
> 2025), §5.1, §5.1.2, §6.1 and §8; the IPTC Digital Source Type vocabulary as released on
|
||
> 2024-10-23; arXiv 2609.07711, §3.4; and *Copyright and Artificial Intelligence, Part 2:
|
||
> Copyrightability*, a report of the United States Copyright Office (January 2025), its table
|
||
> of contents and its Part V. A section number of one of those texts in this extension is that
|
||
> version's.
|
||
|
||
## 1. Scope
|
||
|
||
Process-level provenance that captures who contributed what, and to what extent, within a
|
||
co-creation session and across sessions, is named as an open research direction in arXiv
|
||
2609.07711 §3.4. WAI's derivations are exact, so a record of the process can be re-executed to
|
||
the artifact, and the map of who made each sample can be computed from it.
|
||
|
||
In scope: the records (§2) and the session with its parties (§3); the steps, the acts and their
|
||
pinned operations (§4); the chain of steps and its Merkle tree (§5); the contribution record
|
||
(§6); the authorship map, its dependency rules, its encoding and its shares (§7); disclosure
|
||
and the privacy of process (§8); agreement with an origin claim and the mappings onto C2PA
|
||
actions, identity assertions and live tracks (§9); verification (§10).
|
||
|
||
This revision maps still images of `RGB8` samples in full. Audio maps by sample interval and
|
||
video maps by frame are not part of it: a session's `media` is `image` (§3.1), and a later
|
||
revision registers the other media with their canonical buffers.
|
||
|
||
Out of scope, each a slot a later revision fills:
|
||
|
||
- **Legal questions.** WAI decides none. A registration authority, a collective or a court
|
||
applies its own rule, case by case, to facts. The cited report takes up, in turn, assistive
|
||
uses of AI systems, prompts, expressive inputs, and modifying or arranging AI-generated
|
||
content (its Part II), and concludes that outputs may be protected in whole or in part where a
|
||
person was able to determine the expressive elements they contain, and that prompts alone are
|
||
unlikely to suffice (its Part V). A contribution record states, sample by sample, which party's act produced
|
||
each value and which parties' choices conditioned it, and how much of that a verifier
|
||
recomputed. It does not say which of those facts make anyone an author anywhere. Registering
|
||
a work, and contacting any authority about it, are its owner's decisions.
|
||
- **Tooling and presentation** of the map (later revisions' tools).
|
||
- **Aggregating an audience's choices** into one act: an `audience` party may act alone in this
|
||
revision (§3.1), and a step on behalf of many is a later revision's.
|
||
- **Direction tracks**: the act `direct` is reserved (§4.2) and refused until registered.
|
||
- **Attribution through conditioning**: a generation conditioned on an earlier state, and what
|
||
an inpainting reads outside its region, attribute nothing here. `generate` and `candidates`
|
||
take no input in this revision (§4.2). The works that condition a generation, a set of
|
||
candidates or an inpainting (a reference image, an adapter, a taste prior, a catalogue) are
|
||
named by [influence](influence.md), in a record beside the step that leaves the step as this
|
||
extension reads it (influence §4.2), and the shares of the output that follow are computed
|
||
there from this extension's map.
|
||
|
||
Relationship to the core spec: `wai.media.contribution` is a **record** ([SPEC](../SPEC.md)
|
||
§5): signed records a WAI tool emits and verifies. It names no payload format and is not
|
||
dispatchable.
|
||
|
||
Relationship to [synthesis](synthesis.md): an origin claim says what an object is; a
|
||
contribution record says how it was made and by whom, sample by sample. The record names the
|
||
output's origin claim, and a verifier holds the two to each other (§9.1). This extension takes
|
||
synthesis §2's encodings and its two integer derivations by name.
|
||
|
||
Relationship to [deriving-edge](deriving-edge.md): a transform or a composition of this
|
||
extension evaluates one of that extension's operations (§4.2 there) by its name, its parameters
|
||
and its arithmetic, over states of a session rather than over delivered objects, with no
|
||
envelope written. A deriving edge's record chains published objects; a session's steps chain the
|
||
states of one piece of work.
|
||
|
||
## 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, read as synthesis §2 reads a record: strict JSON, no
|
||
member named twice, at most 32 levels of nesting, byte strings in lowercase hexadecimal,
|
||
integers unsigned and at most 2^53 − 1, no other number, no boolean, **terms** and
|
||
**date-times** as defined there. Each record has exactly the members its section lists, no
|
||
member missing and none added, at any level, and a `kind` naming it; one that does not is
|
||
`record_malformed`. So is a member outside the values or ranges its section gives.
|
||
|
||
A signed record carries `signer_pubkey` (32 bytes, an Ed25519 key of RFC 8032) and `sig`
|
||
(64 bytes):
|
||
|
||
```
|
||
sig = Ed25519(signer_key, "wai:contribution\x01" || JCS(record without "sig"))
|
||
link_hash = BLAKE3("wai:contribution-link\x01" || JCS(record))
|
||
```
|
||
|
||
JCS is RFC 8785. 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. `issued_at` holds the instant its
|
||
signer signed it, self-asserted.
|
||
|
||
A **state** is a picture a step produces: `width` × `height` pixels as the `RGB8` buffer of
|
||
[reconstruction-binding](reconstruction-binding.md) §2 (row-major, three bytes a pixel, no row
|
||
padding), each side at least 1 and the buffer at most 2^26 bytes. Its **samples digest** is
|
||
SHA-256 (FIPS 180-4) over the buffer, and a state is named by it and by the step that produced
|
||
it. A pixel is addressed (*x*, *y*), *x* to the right and *y* down from the top-left. A
|
||
**sample** of the map is a pixel.
|
||
|
||
## 3. The session
|
||
|
||
### 3.1 The session record
|
||
|
||
The tool a session runs in signs a **session** record, `kind` `"wai-session"`:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | string | `"wai-session"` |
|
||
| `session` | 32 B hex | fresh random bytes naming the session |
|
||
| `tool` | term | the tool, as a C2PA `softwareAgent` names it (§9.2) |
|
||
| `media` | string | `image` |
|
||
| `parties` | array | 1 to 64 parties, each named by its position from 0 |
|
||
| `issued_at` | date-time | when the tool signed it |
|
||
| `signer_pubkey`, `sig` | | §2: the **tool's key** |
|
||
|
||
A party is one of:
|
||
|
||
- `{"role": "human", "key"}`: a person, by the Ed25519 key it signs with (32 bytes; as a
|
||
`did:key` it is the same key);
|
||
- `{"role": "audience", "key"}`: a person in an audience, by its key;
|
||
- `{"role": "model", "digest", "type"}`: a model, by its prior's digest (SPEC §3.1), or, for
|
||
a generator that reads one model file and names it by SHA-256 (SPEC §5 *Payload of
|
||
`wai.generate.spectral`*), by that file's SHA-256; and `type`, `trained` or `algorithmic`
|
||
as synthesis §3.1 has a model's type.
|
||
|
||
A human or an audience party is a **keyed** party. No key appears twice, no digest twice, and
|
||
no keyed party's key is the tool's (`record_malformed`), so the tool's signature never stands
|
||
for a person's.
|
||
|
||
### 3.2 Membership
|
||
|
||
A keyed party **countersigns** its membership: it signs a **membership** record, `kind`
|
||
`"wai-membership"`, over the session as the tool signed it:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | string | `"wai-membership"` |
|
||
| `session` | 32 B hex | the link hash of the session record |
|
||
| `party` | integer | its own position among the parties |
|
||
| `issued_at` | date-time | when it signed it |
|
||
| `signer_pubkey`, `sig` | | §2: the party's key |
|
||
|
||
A membership whose `session` is not the session's link hash, whose `party` is not a keyed
|
||
party, or whose signer is not that party's key is `membership_invalid`. A keyed party with no
|
||
membership is `party_not_countersigned`: no person is enrolled as a party of a session, and so
|
||
as a maker or a director of any sample (§7), without its own signature over the session's
|
||
parties. A model party signs nothing; the tool signs its acts (§4.1).
|
||
|
||
## 4. Steps
|
||
|
||
### 4.1 The step record
|
||
|
||
Each act is a **step**, `kind` `"wai-step"`:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | string | `"wai-step"` |
|
||
| `session` | 32 B hex | the link hash of the session record |
|
||
| `seq` | integer | the step's position in the session, from 0 |
|
||
| `prev` | 32 B hex or `null` | the link hash of step `seq` − 1; `null` for step 0 |
|
||
| `party` | integer | the party that performed the act (the **performer**) |
|
||
| `act` | string | §4.2 |
|
||
| `inputs` | array | 0 to 16 states, each `{"step", "samples"}`: the `seq` of the step that produced it, below this step's `seq`, and its samples digest; none twice |
|
||
| `output` | object or `null` | what the act produced (§4.2) |
|
||
| `region` | array or `null` | for `edit` and `inpaint`, 1 to 256 rectangles `{"x", "y", "w", "h"}`, `w` and `h` at least 1, each within the output (`x` + `w` ≤ `width`, `y` + `h` ≤ `height`); the **region** is their union. `null` for every other act |
|
||
| `params` | object | §4.3 |
|
||
| `check` | string | `replicate` or `attest` (§4.4) |
|
||
| `issued_at` | date-time | when it was signed |
|
||
| `signer_pubkey`, `sig` | | §2: the performer's key for a keyed performer, the tool's key for a model |
|
||
|
||
An `output` is `{"samples", "width", "height"}`, one state; for `candidates` it is `{"set",
|
||
"width", "height"}`, a set of 2 to 16 states of one size by their samples digests, none twice;
|
||
for `reject` it is `null`.
|
||
|
||
A step whose `session` is not the session's link hash is `session_mismatch`; whose `party`, or a
|
||
party its `params` name, is not a party of the session, `party_unknown`; whose performer's role
|
||
is not one its act admits (§4.2), `party_role_mismatch`; and whose signer is not the one this
|
||
section names, `signer_mismatch`.
|
||
|
||
### 4.2 Acts
|
||
|
||
| act | performer | inputs | output | region | what it introduces |
|
||
|---|---|---|---|---|---|
|
||
| `author` | `human` | none | one state | none | every sample: the person's own |
|
||
| `generate` | `model` | none | one state | none | every sample |
|
||
| `candidates` | `model` | none | a set | none | every sample of every member |
|
||
| `select` | any party | one: a member of a `candidates` step's set | one state: the input | none | nothing |
|
||
| `edit` | `human` | one | one state of the input's size | required | the region's samples: the person's own |
|
||
| `inpaint` | `model` | one | one state of the input's size | required | the region's samples |
|
||
| `transform` | any party | one | one state | none | nothing |
|
||
| `compose` | any party | 1 to 16 | one state | none | the canvas fill (§4.5) |
|
||
| `reject` | any party | one | none | none | nothing |
|
||
| `direct` | reserved | | | | |
|
||
|
||
- **author**: samples a person made enter the session: a drawing, a recording, typed text set
|
||
as an image.
|
||
- **generate**: a model produces a state.
|
||
- **candidates**: a model produces a set of states, committed by their digests and, where the
|
||
generator is pinned, by their seeds.
|
||
- **select**: a party picks one member of a committed set. Its output is that member.
|
||
- **edit**: a person replaces samples inside the region with samples it made.
|
||
- **inpaint**: a model fills the region a party marked.
|
||
- **transform**: a derivation, with parameters a party chose, maps one state to another.
|
||
- **compose**: a party places layers on a canvas, or tiles them in a grid.
|
||
- **reject**: a party discards a state. The state stays committed, so a verifier sees what was
|
||
discarded as well as what was kept.
|
||
- **direct**: reserved for direction tracks. A step whose `act` is `direct` is `act_reserved`.
|
||
|
||
A step that breaks the table's inputs, output or region is `record_malformed`; an input of a
|
||
`select` that is not a member of a `candidates` step's set, or a `select` whose output is not its
|
||
input, is `selection_not_in_set` (§10.2 step 6).
|
||
|
||
### 4.3 Parameters
|
||
|
||
A step's `params` has exactly these members:
|
||
|
||
| act | `params` |
|
||
|---|---|
|
||
| `author` | `{"source"}`: what the person made, as synthesis §3.2 has a capture state it: `digitalCapture`, `computationalCapture`, `screenCapture` or `digitalCreation` |
|
||
| `generate` | `{"generator", "prompt", "prompt_by", "seed", "steps"}` |
|
||
| `candidates` | `{"generator", "prompt", "prompt_by", "seeds", "steps"}` |
|
||
| `inpaint` | `{"generator", "prompt", "prompt_by", "mask_by", "seed", "steps"}` |
|
||
| `select`, `edit`, `reject` | `{}` |
|
||
| `transform`, `compose` | `{"derivation", "params"}`: a term naming the derivation, and an object, its parameters |
|
||
|
||
- `generator`: a term naming what generated: `wai.generate.spectral` (§4.5) or another.
|
||
- `prompt`: the salted commitment to the prompt (§8.1), 32 bytes, or `null` for none.
|
||
- `prompt_by`: the party that wrote the prompt; `null` exactly when `prompt` is.
|
||
- `mask_by`: the party that marked the region.
|
||
- `seed`, `steps`: integers or `null`; `seeds`: an array of one integer per member of the set,
|
||
in the set's order, or `null`.
|
||
|
||
### 4.4 The check
|
||
|
||
A step's `check` says whether every sample it carries forward is fixed by a pinned rule:
|
||
|
||
- `replicate`: every sample the act carries from its inputs recomputes from them under an
|
||
operation this revision pins (§4.5), and every sample a model introduces regenerates under a
|
||
pinned generator. Samples a person introduces (`author`, an `edit`'s region) are that person's
|
||
own, the source the chain starts from, as a capture is in synthesis §3.2: there is nothing to
|
||
recompute, and the signature says who made them.
|
||
- `attest`: a step that is not `replicate`: what it produced rests on its signer's statement.
|
||
|
||
| act | `check` |
|
||
|---|---|
|
||
| `author`, `edit`, `select`, `reject` | `replicate` |
|
||
| `generate`, `candidates`, `inpaint` | `replicate` when `generator` is `wai.generate.spectral`; `attest` otherwise |
|
||
| `transform` | `replicate` when `derivation` is one §4.5 pins for it; `attest` otherwise |
|
||
| `compose` | `replicate` when `derivation` is `wai.derive.overlay_composition` or `wai.derive.grid_composition`; `attest` otherwise |
|
||
|
||
A generator another extension pins is not `wai.generate.spectral`: a step of influence's
|
||
conditioned generator, `wai-influence:spectral-blend`, is `attest` here, and that extension
|
||
regenerates it (influence §4.4). A step whose `check` is not its act's is `check_mismatch`. A `replicate` step's parameters are
|
||
those §4.5 gives its operation; a `generate`, `candidates` or `inpaint` step of
|
||
`wai.generate.spectral` has a `seed` (each of its `seeds`) from 0 to 2^32 − 1 and `steps` from 1
|
||
to 64, and its output's sides are each at most 4096 with `width` · `height` at most 2^23, the
|
||
ranges SPEC §5 *Payload of `wai.generate.spectral`* gives an instruction object. Otherwise
|
||
`params_invalid`. An `attest` step's `params` under `derivation` is any object.
|
||
|
||
### 4.5 The pinned operations
|
||
|
||
Each operation computes its output from its inputs' samples and its parameters, and defines,
|
||
for each output pixel, the input pixels it reads: its **sample mapping**, which the map follows
|
||
(§7.2).
|
||
|
||
Transforms:
|
||
|
||
- `wai.derive.crop` `{"x", "y", "w", "h"}`, `wai.derive.rotation` `{"quarter_turns"}` and
|
||
`wai.derive.mirror` `{"flip"}`: deriving-edge §4.2's, its parameters and its arithmetic
|
||
exactly. Each output pixel reads the one input pixel that section copies to it.
|
||
- `wai-synthesis:upscale2` and `wai-synthesis:denoise3`, `{}`: synthesis §4.1 and §4.2. Output
|
||
pixel (2*x*, 2*y*) of the upscale reads in(*x*, *y*); (2*x* + 1, 2*y*) reads it and
|
||
in(*x*₁, *y*); (2*x*, 2*y* + 1) reads it and in(*x*, *y*₁); (2*x* + 1, 2*y* + 1) reads those
|
||
and in(*x*₁, *y*₁), with *x*₁ and *y*₁ as there. Each output pixel of the denoise reads the nine
|
||
clamped pixels of its neighbourhood.
|
||
- `wai-contribution:lut` `{"table"}`, `table` 768 bytes: out(*x*, *y*) byte *c* = `table`[256 ·
|
||
*c* + in(*x*, *y*) byte *c*], for *c* 0, 1, 2. Each output pixel reads the input pixel at its
|
||
own position. It is a value transform: a colour grade, a tone curve, a levels adjustment. No
|
||
other WAI text pins a per-sample colour mapping, so this extension pins this one.
|
||
|
||
Compositions, over the step's inputs in its order:
|
||
|
||
- `wai.derive.overlay_composition` `{"width", "height", "fill", "at"}` and
|
||
`wai.derive.grid_composition` `{"columns", "rows"}`: deriving-edge §4.2's. A pixel an input
|
||
covers reads the pixel of the last input that covers it; a pixel of an overlay's canvas that no
|
||
input covers reads nothing and holds the `fill`.
|
||
|
||
Generation, for `generate`, `candidates` and `inpaint`:
|
||
|
||
- `wai.generate.spectral`: the reference generator SPEC §5 *Payload of `wai.generate.spectral`*
|
||
names, `generate(model, prompt, seed, steps, h, w)`, with the performer's model file (whose
|
||
SHA-256 is the party's `digest`), the opened prompt's text (§8.1), the empty string where
|
||
`prompt` is `null`, and `h` and `w` the output's. A `candidates` member at position *k* of the
|
||
set is made with `seeds`[*k*]. An `inpaint` makes the picture at the input's size and copies its
|
||
samples inside the region; outside the region, the output is the input.
|
||
|
||
A parameter the inputs cannot satisfy (a crop outside its input, grid inputs of different
|
||
sizes, an `at` entry missing) is `params_invalid` when the inputs' sizes are known (§10.2 step
|
||
6).
|
||
|
||
## 5. The chain and its tree
|
||
|
||
### 5.1 The chain
|
||
|
||
A session's steps are numbered from 0 by `seq`, and each names the link hash of the one before
|
||
it in `prev`: a hash chain, so no step can be removed, inserted or reordered without breaking
|
||
every link after it. A step whose `seq` is not below the record's `steps` (§6), a `seq` given
|
||
twice, a step 0 whose `prev` is not `null`, a later step whose `prev` is `null`, or a `prev`
|
||
that is not the link hash of step `seq` − 1 where the verifier holds that step, is
|
||
`chain_broken`.
|
||
|
||
### 5.2 The tree
|
||
|
||
The steps are the leaves of a binary Merkle tree, built as jwp-receipts §2.2 builds a group's,
|
||
over the steps' link hashes in `seq` order, with domains of this extension's own so that the
|
||
root of a session's steps can never be read as a group's:
|
||
|
||
```
|
||
leaf(step) = BLAKE3("wai:contribution-leaf\x01" || link_hash(step))
|
||
node(left, right) = BLAKE3("wai:contribution-node\x01" || left || right)
|
||
```
|
||
|
||
At each level with an odd number of nodes the last is duplicated; the root is the single node
|
||
left. The duplicated last leaf also walks to the root from the position past it, so the record
|
||
states the number of leaves, `steps`, and §5.1 refuses a `seq` that is not below it: no step can
|
||
stand at a position the tree does not have.
|
||
|
||
A disclosed step carries an **inclusion proof**: its siblings from the leaf level upward,
|
||
exactly ⌈log₂ `steps`⌉ of them (none for one step). It is walked as jwp-receipts §3 step 5
|
||
walks an object's proof, with the leaf index the step's `seq` and the direction bits the bits of
|
||
`seq`: at level *i*, bit *i* of `seq` set means the current node is the right child. A proof of
|
||
another length, or one that does not reach the record's `root`, is `inclusion_failed`.
|
||
|
||
## 6. The contribution record
|
||
|
||
The tool signs the **contribution** record, `kind` `"wai-contribution"`:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | string | `"wai-contribution"` |
|
||
| `session` | 32 B hex | the link hash of the session record |
|
||
| `steps` | integer | the number of steps, at least 1 |
|
||
| `root` | 32 B hex | the root of the steps' tree (§5.2) |
|
||
| `output` | object | the final output: `{"step", "samples", "width", "height", "content_hash"}`, the `seq` of the step that produced it (below `steps`), its samples digest and size, and the content hash (jwp-receipts §2.1) of the object it was published as, or `null` |
|
||
| `map` | 32 B hex | the digest of the authorship map (§7.3) |
|
||
| `origin` | 32 B hex or `null` | the link hash of the output's origin claim (synthesis §3.1); `null` only with `content_hash` `null` too, or where the tool signs none |
|
||
| `estimates` | array | 0 to 16 estimated shares (below) |
|
||
| `issued_at` | date-time | when the tool signed it |
|
||
| `signer_pubkey`, `sig` | | §2: the tool's key |
|
||
|
||
A record that is not the session's is `session_mismatch`; one not signed by the tool's key,
|
||
`signer_mismatch`; one whose `origin` is not `null` while `content_hash` is, `record_malformed`.
|
||
|
||
An **estimate** is `{"estimator", "class", "party", "basis", "share_ppm"}`: a term naming the
|
||
method, a term naming its class (the family of methods it belongs to, such as an
|
||
information-theoretic one), a party (`party_unknown` otherwise), `made_by` or `directed_by`, and
|
||
the share it estimates in parts per million, at most 1 000 000. An estimate is the tool's
|
||
statement with its class, as an energy figure carries its class: a verifier reports it as
|
||
stated, beside the counts of §7.4 and never in place of them, and never adds it to them.
|
||
|
||
## 7. The authorship map
|
||
|
||
### 7.1 Labels
|
||
|
||
Every sample of the output has a **label**: two sets, `made_by`, the parties whose act produced
|
||
the sample's value, and `directed_by`, the parties whose choices conditioned it (a prompt, a
|
||
mask, a selection, a transform's parameters, an arrangement). A set holds parties, and may hold
|
||
one of two markers:
|
||
|
||
- `unknown`: no pinned rule fixes where the sample's value came from, even with every step
|
||
disclosed: an `attest` transform or composition does not pin its sample mapping;
|
||
- `undisclosed` (in a verifier's computed map only, never in a stated one): the sample comes
|
||
from a state whose step the verifier does not hold.
|
||
|
||
A marker is never a party and is never counted as one: **unknown is never zero**. A sample a
|
||
rule cannot attribute is reported as such, not credited to anyone.
|
||
|
||
### 7.2 Dependency rules
|
||
|
||
The map of a state is computed from its step and its inputs' maps. The map of an input whose
|
||
step the verifier does not hold has every sample `({undisclosed}, {undisclosed})`. For a step
|
||
performed by party *a*:
|
||
|
||
| act | label of each sample of the output |
|
||
|---|---|
|
||
| `author` | `({a}, {})` |
|
||
| `generate`; each member of `candidates` | `({a}, P)`, *P* the set of `prompt_by`, where it is not `null` |
|
||
| `edit` | inside the region `({a}, {})`; outside it, the input's label at the same pixel |
|
||
| `inpaint` | inside the region `({a}, P ∪ {mask_by})`; outside it, the input's label at the same pixel |
|
||
| `select` | the input's label at the same pixel, with *a* added to `directed_by` |
|
||
| `transform`, `replicate` | the union, over the input pixels its sample mapping reads (§4.5), of their `made_by`, and of their `directed_by` with *a* added |
|
||
| `compose`, `replicate` | at a pixel an input covers, that input pixel's label with *a* added to `directed_by`; at a canvas pixel no input covers, `({a}, {a})`: the fill is the arranger's |
|
||
| `transform` or `compose`, `attest` | `({unknown}, {unknown})` |
|
||
| `reject` | no output |
|
||
|
||
So a geometric transform carries each label through its exact sample mapping; a filter that
|
||
mixes pixels takes the union of what it mixes; a value transform keeps `made_by` and adds its
|
||
chooser to `directed_by`; a selection keeps the chosen candidate's map and adds the selector
|
||
everywhere; a composition takes each layer's map where the layer is visible. A model's samples,
|
||
generated or inpainted, are `made_by` that model whether or not its generator is pinned: the act
|
||
places them, and the step's status (§10.3) says whether they were regenerated. An `edit`'s or an
|
||
`inpaint`'s region takes nothing from the samples it replaced: they no longer condition it.
|
||
|
||
Where the verifier does not know an input's size (its step is not held), the sample mapping
|
||
cannot be followed; a `transform` or `compose` then gives every output sample `({undisclosed},
|
||
{undisclosed, a})`, and a `select` gives the input's label as above. The output's map is the map
|
||
of the state the record's `output` names: the one its `step` produced.
|
||
|
||
### 7.3 Encoding
|
||
|
||
The map is a JSON object under §2's encodings, `kind` `"wai-authorship-map"`, unsigned and
|
||
bound by its digest:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | string | `"wai-authorship-map"` |
|
||
| `output` | 32 B hex | the samples digest of the output |
|
||
| `width`, `height` | integer | the output's size |
|
||
| `palette` | array | the distinct labels, each `{"made_by", "directed_by"}`, in the order each first occurs in row-major order |
|
||
| `rows` | array | `height` rows, each an array of runs `[i, n]`: `n` ≥ 1 pixels with palette label `i`, left to right, summing to `width`; adjacent runs never share a label |
|
||
|
||
A set is an array of party positions in ascending order, then `"unknown"` where it holds that
|
||
marker; a stated map holds no `"undisclosed"`. Every party is a party of the session. A map
|
||
that is not one JSON text under §2's encodings, or that breaks any of these rules, is
|
||
`map_malformed`: each map has one encoding.
|
||
|
||
```
|
||
map digest = BLAKE3("wai:contribution-map\x01" || JCS(map))
|
||
```
|
||
|
||
The record names the map by its digest, and the map names the output's samples digest and
|
||
size, so the map is bound to the samples it describes. A map whose digest is not the record's
|
||
`map`, or whose `output`, `width` or `height` is not the record's output's, is `map_unbound`.
|
||
|
||
### 7.4 Shares
|
||
|
||
The **shares** of a map are exact sample counts: the number of samples; for each party, the
|
||
number of samples whose `made_by` holds it, and separately the number whose `directed_by` holds
|
||
it; and, for each of the two sets, the number of samples holding `unknown` and the number holding
|
||
`undisclosed`. A sample counts once for each party its set holds, so a sample two parties made
|
||
counts for both. The counts are never combined into one figure: what `made_by` and
|
||
`directed_by` mean is a reader's to weigh under its own rule.
|
||
|
||
## 8. Disclosure
|
||
|
||
### 8.1 Salted commitments
|
||
|
||
A prompt, and any other text a party gives a step, is carried as a salted commitment:
|
||
|
||
```
|
||
commitment = SHA-256(salt || UTF-8(text))
|
||
```
|
||
|
||
with `salt` 32 fresh random bytes for each commitment. A short or guessable prompt cannot be
|
||
recovered by hashing candidates: the salt is not disclosed with the step. An **opening**
|
||
`{"commitment", "salt", "text"}` discloses one: the salt (32 bytes) and the text (a string).
|
||
An opening whose salt and text do not hash to its commitment is `opening_mismatch`.
|
||
|
||
### 8.2 What each disclosure gives
|
||
|
||
A creator discloses some or all of the steps, each with its inclusion proof, and some or all of
|
||
the states, the openings of the prompts and the model files a pinned generator reads. The tier
|
||
of the outcome (§10.3) follows from what is disclosed:
|
||
|
||
| disclosed | tier |
|
||
|---|---|
|
||
| every step behind the output, every state they read and write, the openings of their prompts and the model files of their pinned generators, no `attest` step behind the output | `recomputed` |
|
||
| as above with an `attest` step behind the output, or with a state, an opening or a model file withheld | `checked`: what was held was checked, the rest is committed |
|
||
| some steps, with their proofs: the others committed by the root | `checked`, and the samples from undisclosed steps `undisclosed` |
|
||
| the record and the map, no step | `stated`: the signed map is held, nothing recomputed |
|
||
|
||
A withheld prompt stays private: its commitment binds the step to it, and the step's map does
|
||
not depend on its text. A withheld step stays private too: its leaf is in the root, so it cannot
|
||
be replaced later, and the samples it produced are `undisclosed`, never credited to anyone.
|
||
|
||
## 9. Agreement and mappings
|
||
|
||
### 9.1 The origin claim
|
||
|
||
Where the record names an origin claim (synthesis §3.1) the verifier holds, read by synthesis
|
||
§2 and §3.1:
|
||
|
||
- its subject is the object `output.content_hash` (`origin_mismatch`);
|
||
- where any sample of the stated map is `made_by` a model party, its `class` is `synthesized`
|
||
(`origin_understated`): an object any part of which a model generated or inpainted is not
|
||
captured, reconstructed or assistive, as synthesis §3.2's lattice has it.
|
||
|
||
### 9.2 The C2PA actions
|
||
|
||
Where every step is disclosed, the record gives one C2PA statement, `{"actions": A}`, written
|
||
in JCS: `A` is the actions of the output's manifest (C2PA 2.4 §18.15.1), one per step behind the
|
||
output, in `seq` order, after a first `c2pa.created` action:
|
||
|
||
- first: `{"action": "c2pa.created", "digitalSourceType":
|
||
"http://c2pa.org/digitalsourcetype/empty", "softwareAgent": {"name": T}}`, `T` the session's
|
||
`tool`: a session is begun on an empty canvas in a tool, and C2PA 2.4 §18.15.2 asks for
|
||
`c2pa.created` first with that source type;
|
||
- then, for each step, the action below with `"softwareAgent": {"name": N}`, `N` the tool for a
|
||
keyed performer and `tag:transaction.science,2026:wai/model/` followed by the digest in
|
||
lowercase hexadecimal for a model (synthesis §6's model identifier), a generator-info map
|
||
(C2PA 2.4 §10.2.3.2) with its `name`:
|
||
|
||
| step | action | `digitalSourceType` (the IPTC term of) | `changes` |
|
||
|---|---|---|---|
|
||
| `author` | `c2pa.edited` | its `source` | none |
|
||
| `generate`, `candidates` | `c2pa.edited` | `trainedAlgorithmicMedia` for a trained model, `algorithmicMedia` otherwise | none |
|
||
| `inpaint` | `c2pa.edited` | `compositeWithTrainedAlgorithmicMedia` for a trained model, `algorithmicMedia` otherwise | the region |
|
||
| `edit` | `c2pa.drawing` | `digitalCreation` | the region |
|
||
| `transform`: crop | `c2pa.cropped` | none | none |
|
||
| `transform`: rotation, mirror | `c2pa.orientation` | none | none |
|
||
| `transform`: upscale2 | `c2pa.resized` | `algorithmicallyEnhanced` | none |
|
||
| `transform`: denoise3 | `c2pa.enhanced` | `algorithmicallyEnhanced` | none |
|
||
| `transform`: lut | `c2pa.adjustedColor` | none | none |
|
||
| `transform`: `wai.derive.scaling` | `c2pa.resized` | none | none |
|
||
| another `transform`, a `compose` | `c2pa.edited` | none | none |
|
||
| `select` | none: it changes no sample | | |
|
||
|
||
An action's members are written in the order JCS gives them. `changes` (C2PA 2.4 §18.15.4.6) is
|
||
one region map (§18.2): `[{"region": R}]`, `R` one spatial range for each rectangle, in the
|
||
step's order, `{"type": "spatial", "shape": {"type": "rectangle", "unit": "pixel", "origin":
|
||
{"x": X, "y": Y}, "width": W, "height": H}}`, the coordinates as integers (a manifest in CBOR
|
||
writes them as the floats §18.2.3 types them). The IPTC term is
|
||
`http://cv.iptc.org/newscodes/digitalsourcetype/` followed by the code. The trained models'
|
||
`c2pa.ai-disclosure` assertions are the origin claim's (synthesis §6). A rejected state, and a
|
||
branch of the session the output does not come from, give no action: they did not make the
|
||
asset. Embedding the statement in a manifest, and signing it, is C2PA's.
|
||
|
||
### 9.3 Identity assertions (informative)
|
||
|
||
A keyed party may give the output's manifest an identity assertion (Identity Assertion 1.2
|
||
§5.1, label `cawg.identity`) whose referenced assertions include the actions assertion of §9.2,
|
||
as §6.1 there recommends for an actor who performed those actions, under a credential of §8
|
||
there. The roles of §5.1.2 there (`cawg.creator`, `cawg.contributor`, `cawg.editor`, …) are the
|
||
party's own statement of its relationship to the asset; this extension does not derive one
|
||
from the shares. The party's key in the session is an Ed25519 key, not a credential type of §8
|
||
there, and the relation between the two is the party's to state.
|
||
|
||
### 9.4 Live tracks (informative)
|
||
|
||
A record covers one still. Over [live-provenance](live-provenance.md), a manifest that covers
|
||
such a still (a picture a room shares, a frame made in a session and then streamed) can name the
|
||
record by its link hash in an entity-specific assertion of the kind that extension's §5 defines
|
||
for the stream, the group and the take; the record, its session, its memberships, its disclosed
|
||
steps and its map are then offered by the carriage that offers the track's receipts, as
|
||
deriving-edge §6 offers a chain's records. Per-frame maps of a live track are a later
|
||
revision's.
|
||
|
||
## 10. Verification
|
||
|
||
### 10.1 Inputs
|
||
|
||
A verifier is given: the session record; its memberships, in a list; the contribution record;
|
||
the disclosed steps, in a list, each with its inclusion proof; the authorship map; the openings
|
||
it holds, in a list; the states it holds, each a buffer, named by its samples digest; the model
|
||
files it holds, each named by its SHA-256; the origin claims it holds, in a list; and a
|
||
**policy** of one member:
|
||
|
||
| member | values | default | meaning |
|
||
|---|---|---|---|
|
||
| `tier` | `stated`, `checked`, `recomputed` | `stated` | the lowest tier it accepts (`tier_not_met`) |
|
||
|
||
### 10.2 Steps of verification
|
||
|
||
The verifier runs these steps and stops at the first refusal, which it reports with its reason
|
||
and its place: `["session"]`, `["session", "party", i]`, `["membership", i]`, `["record"]`,
|
||
`["step", i]`, `["map"]`, `["map", x, y]`, `["opening", i]`, `["origin", i]` or `["policy"]`,
|
||
each *i* a position in its list (a party's among the parties) and (*x*, *y*) a pixel.
|
||
|
||
1. **Reading** (§2, §3, §4.1–§4.3, §6, §7.3, §8.1): the session, the memberships, the record,
|
||
the steps, the map and the openings, each in order, read and their signatures verify; the
|
||
origin claims read and verify by synthesis §2 and §3.1. `record_malformed`, `bad_key`,
|
||
`bad_signature`, `act_reserved`, `map_malformed`. A step whose `act` is `direct` is
|
||
`act_reserved` once its members are read, whatever they hold. A proof that is not an array
|
||
of 32-byte strings is `record_malformed`.
|
||
2. **Openings** (§8.1): `opening_mismatch`.
|
||
3. **Membership** (§3.2): each membership in order (`membership_invalid`), then each keyed
|
||
party in order (`party_not_countersigned`).
|
||
4. **The record** (§6): `session_mismatch`, `signer_mismatch`, and each estimate's party
|
||
(`party_unknown`).
|
||
5. **Each step**, in the order given: `session_mismatch`, `party_unknown`,
|
||
`party_role_mismatch`, `signer_mismatch` (§4.1); `check_mismatch` and `params_invalid`
|
||
(§4.4); `chain_broken` (§5.1); `inclusion_failed` (§5.2).
|
||
6. **Each step against the states**, in `seq` order, each by these checks in order:
|
||
1. each state its output names that the verifier holds is `width` · `height` · 3 bytes
|
||
(`samples_mismatch`);
|
||
2. each input whose step the verifier holds is that step's output, or a member of its set
|
||
(`input_unknown`); for a `select`, instead: its output is its input, and where the
|
||
verifier holds the input's step, that step is a `candidates` step and the input is a
|
||
member of its set (`selection_not_in_set`);
|
||
3. for an `edit` or an `inpaint` whose input's step is held, that step's output has this
|
||
step's output's size (`region_invalid`);
|
||
4. for a `replicate` `transform` or `compose` whose inputs' sizes are known (the verifier
|
||
holds each input's step): its parameters hold over them (§4.5, `params_invalid`), and
|
||
the size they give is the output's (`recompute_mismatch`);
|
||
5. the act's own check, where the verifier holds what it reads:
|
||
- `edit`, `inpaint`: a held buffer of the input that is not of the output's size is
|
||
`region_invalid`; with the input's and the output's samples held, every pixel outside
|
||
the region is the input's, byte for byte (`outside_region_changed`);
|
||
- `generate`, `candidates`, `replicate`: with the model file and the prompt's opening
|
||
(where `prompt` is not `null`) held, each state regenerates (§4.5): the samples digest of
|
||
what the generator makes is the state's (`regeneration_mismatch`);
|
||
- `inpaint`, `replicate`: with the model file, the prompt's opening and the output's
|
||
samples held, every pixel inside the region is the generator's picture's
|
||
(`regeneration_mismatch`);
|
||
- `transform`, `compose`, `replicate`: with every input's samples held, the operation
|
||
evaluated over them gives the output's size and samples whose digest is the output's
|
||
(`recompute_mismatch`).
|
||
7. **The output** (§6): where the verifier holds the step `output.step`, that step's output is
|
||
one state with the record's samples digest and size (`output_mismatch`); a held buffer of the
|
||
output's digest is `width` · `height` · 3 bytes (`samples_mismatch`).
|
||
8. **The map** (§7): the map is bound (`map_unbound`). The verifier computes the output's map by
|
||
§7.2 from the steps it holds and compares it with the stated map, pixel by pixel in row-major
|
||
order, `made_by` then `directed_by`. Where the computed set holds `undisclosed`, the parties
|
||
and the `unknown` it holds besides are in the stated set; otherwise the two sets are equal.
|
||
At the first pixel where that fails: `unknown_attributed` where the computed set holds
|
||
`unknown` and the stated set does not (a sample no pinned rule fixes, credited to a party);
|
||
otherwise `map_mismatch`.
|
||
9. **The origin claim** (§9.1): `origin_mismatch`, `origin_understated`, at the claim's place.
|
||
10. **Policy**: an outcome below the policy's `tier` is `tier_not_met`.
|
||
|
||
### 10.3 Statuses and tiers
|
||
|
||
Each step the verifier holds has a **status**:
|
||
|
||
- `attested`: its `check` is `attest`;
|
||
- `checked`: its `check` is `replicate`, the verifier holds the step of each of its inputs, and
|
||
each check of step 6.5 its act has run (an `author` and a `reject` have none, a `select`'s is
|
||
step 6.2's against the held `candidates` step, and an `edit` needs both of its states held,
|
||
an `inpaint` its states, its model file and its opening);
|
||
- `not-checked`: otherwise.
|
||
|
||
The steps **behind the output** are the step `output.step` and, recursively, the step of each
|
||
input of a step behind the output. The outcome's **tier**:
|
||
|
||
- `recomputed`: every step behind the output is held, and `checked`;
|
||
- `stated`: the verifier holds no step;
|
||
- `checked`: otherwise.
|
||
|
||
### 10.4 What an accepted case states
|
||
|
||
- `tier` (§10.3);
|
||
- `session` and `record`: the link hashes of the session record and the contribution record;
|
||
- `steps`: each held step in `seq` order, its `seq`, `act`, `party`, `check` and `status`;
|
||
- `committed`: the number of steps not held;
|
||
- `computed` and `stated`: the shares (§7.4) of the computed map and of the stated map, each
|
||
`samples`; `made_by` and `directed_by`, each a list of `{"party", "samples"}` for the parties
|
||
with a count above zero, in ascending order of party; and `made_by_unknown`,
|
||
`made_by_undisclosed`, `directed_by_unknown` and `directed_by_undisclosed`;
|
||
- `estimates`: the record's, as stated;
|
||
- `origin`: `agree` where the claim the record names was held and checked, `not-checked` where
|
||
it was not held, `null` where the record names none;
|
||
- `c2pa`: the statement of §9.2 as its JCS text, where every step is held; otherwise `null`.
|
||
|
||
## 11. Reasons
|
||
|
||
The codes this extension adds, each with where it is raised:
|
||
|
||
| reason | raised at |
|
||
|---|---|
|
||
| `record_malformed` | §2, §3.1, §4.1, §4.2, §4.3, §6, §8.1, §10.2 step 1 |
|
||
| `bad_key` | §2 |
|
||
| `bad_signature` | §2 |
|
||
| `act_reserved` | §4.2 |
|
||
| `map_malformed` | §7.3 |
|
||
| `opening_mismatch` | §8.1 |
|
||
| `membership_invalid` | §3.2 |
|
||
| `party_not_countersigned` | §3.2 |
|
||
| `session_mismatch` | §4.1, §6 |
|
||
| `party_unknown` | §4.1, §6 |
|
||
| `party_role_mismatch` | §4.1 |
|
||
| `signer_mismatch` | §4.1, §6 |
|
||
| `check_mismatch` | §4.4 |
|
||
| `params_invalid` | §4.4, §4.5, §10.2 step 6 |
|
||
| `chain_broken` | §5.1 |
|
||
| `inclusion_failed` | §5.2 |
|
||
| `samples_mismatch` | §10.2 steps 6 and 7 |
|
||
| `input_unknown` | §10.2 step 6 |
|
||
| `selection_not_in_set` | §4.2, §10.2 step 6 |
|
||
| `region_invalid` | §10.2 step 6 |
|
||
| `outside_region_changed` | §10.2 step 6 |
|
||
| `regeneration_mismatch` | §4.5, §10.2 step 6 |
|
||
| `recompute_mismatch` | §4.5, §10.2 step 6 |
|
||
| `output_mismatch` | §10.2 step 7 |
|
||
| `map_unbound` | §7.3 |
|
||
| `map_mismatch` | §10.2 step 8 |
|
||
| `unknown_attributed` | §7.1, §10.2 step 8 |
|
||
| `origin_mismatch` | §9.1 |
|
||
| `origin_understated` | §9.1 |
|
||
| `tier_not_met` | §10.1 |
|
||
|
||
## 12. Conformance
|
||
|
||
[`live-conformance/contribution/`](../live-conformance/contribution/) holds the corpus, in one
|
||
file, `vectors.json`, written from fixed seeds by `wai_contribution_vectors gen`. It holds the
|
||
model file of `wai.generate.spectral` its sessions generate with, and the **vectors**: each a
|
||
case of §10.1, its outcome and, accepted, everything §10.4 states; refused, its reason and its
|
||
place. The exact generator of the corpus is `wai.generate.spectral`, with the model file of its
|
||
conformance vector (`wai-rs/tests/vectors/generate/generate_spectral_model.json`). It has:
|
||
|
||
- **Accepted, `recomputed`**: a person's drawing, a collaborator's brush edit inside a region,
|
||
and a crop, with a captured origin claim that agrees; an inpainting by the pinned generator
|
||
inside a region one person marked, from a prompt another wrote, regenerated, with a
|
||
synthesized origin claim that agrees; three candidates, each regenerated from its seed, one
|
||
selected by an audience member, one rejected, then a colour table applied; a generated layer
|
||
composed over a drawing and a fill; and a chain of transforms (rotation, mirror, upscale,
|
||
denoise, crop), each recomputed.
|
||
- **Accepted, `checked`**: an inpainting by a trained model the tool attests, its outside
|
||
region checked; an attested scaling whose output is `unknown`; the candidates session with its
|
||
generating step undisclosed, its samples `undisclosed`; and the same with every step disclosed
|
||
but the prompts withheld, so no candidate is regenerated.
|
||
- **Accepted, `stated`**: the record and the map, no step; and a record that attaches an
|
||
estimate with its class.
|
||
- **Refused**: each reason of §11 at least once, each a control of one defect, and a second
|
||
control for each check that has a second place in §10.2: among them a sample outside an
|
||
edit's region changed, a selected output not in its set, a candidate and an inpainted region
|
||
that do not regenerate, a map that does not recompute, a gap in the chain and a `prev` that
|
||
skips its predecessor, a step by a party the session does not have, a person enrolled without
|
||
countersigning, an attested region credited to a person instead of `unknown`, an origin claim
|
||
of a lower class than the map implies, and a prompt commitment that does not open.
|
||
|
||
A conforming verifier gives every vector the outcome, the reason, the place and the statements
|
||
the corpus states. `wai_contribution_vectors verify` and the test `tests/contribution.rs` check
|
||
that the file regenerates byte for byte, that `wai-rs` gives every vector its outcome, and that
|
||
§11 lists exactly the reference's codes. `live-conformance/contribution_verify.py` is the second
|
||
implementation, written from this text: it shares no code with `wai-rs`; it computes every map
|
||
itself, evaluates every pinned operation and runs the generator in its own arithmetic, checking
|
||
that arithmetic first against the generator's conformance vector
|
||
(`wai-rs/tests/vectors/generate/sha256.json`); it reads origin claims with the synthesis
|
||
corpus's second implementation (`synthesis_verify.py`), verifies every signature with WAI's
|
||
strict rule (`claim-conformance/_ed25519.py`) and every link hash with BLAKE3 written from its
|
||
specification (`claim-conformance/_blake3.py`); it mutates copies of the corpus and requires
|
||
every copy to fail; and it drops each of its own checks in turn and requires the corpus to catch
|
||
the weakened verifier.
|
||
|
||
## 13. Security and privacy considerations
|
||
|
||
- **What is checked and what is stated.** A step is signed by the party that performed it, or by
|
||
the tool for a model. The samples a person introduces are that person's statement: WAI checks
|
||
everything that happened to them afterwards, not whether the person made them without a model.
|
||
An `author` step's `source` says what the person made, as a capture's claim does. A model's
|
||
samples from an `attest` generator are the tool's statement; from a pinned generator they are
|
||
regenerated, so the step proves exactly what was generated, and that no person painted it.
|
||
- **The region.** An edit or an inpainting is checked, not claimed, to have changed nothing
|
||
outside its region: a verifier holding the two states compares every pixel. What a model's
|
||
fill read from outside the region conditions it, and is not attributed in this revision.
|
||
- **Taste as evidence.** A `candidates` step commits every candidate by digest and seed, and a
|
||
`reject` keeps what was discarded committed, so a verifier that regenerates the set sees what
|
||
was chosen over what.
|
||
- **Withholding.** A creator who discloses part of a session cannot change the rest later: the
|
||
record's root commits to every step. A withheld step's samples are `undisclosed` and a
|
||
withheld prompt is a salted commitment; neither is ever credited to a party. A creator who
|
||
withholds can only lower the tier the outcome reaches.
|
||
- **Enrolment.** A person is a party only by countersigning the session, so a tool cannot credit
|
||
a person, or blame one, without that person's signature over the whole list of parties. A
|
||
model party signs nothing; its acts are the tool's statements about it.
|
||
- **Not a judgment.** A record states facts sample by sample; it ranks no contribution, and its
|
||
counts are exact where a rule fixes them and marked where none does. An estimate is the tool's,
|
||
with its class, and is never mixed into the counts. What any of it means for authorship is
|
||
decided elsewhere, by others, under their own rules.
|
||
- **Privacy of process.** Prompts are committed with a salt; a session names parties by keys and
|
||
digests, never by name; the states are digests unless disclosed. A disclosed state is a
|
||
picture, and a creator discloses what it chooses.
|