in-toto predicate: measurement/v1
A signed statement about one measurement run, carried in an in-toto Statement v1 envelope.
- predicateType
https://councilof.ai/attestations/measurement/v1
- Statement
https://in-toto.io/Statement/v1
- DSSE payloadType
application/vnd.in-toto+json
- Signature
- Ed25519, key resolved via
did:web:councilof.ai
- Canonicalisation
- Recursively sorted keys, no whitespace — byte-identical to RFC 8785 for ASCII/number payloads
- Issuer
- CSOAI Ltd (Council of AI), UK company 16939677
Why this exists
in-toto carries predicates for build provenance, SBOMs, test results and vulnerability scans.
It carries none for the result of measuring an AI system. Existing model-signing work signs
model weights; the evaluation-reporting literature standardises the form of a report
but adds no cryptographic layer. This predicate is the missing piece: the outcome of a measurement
run, signed at the time it was produced, verifiable offline by a stranger.
What it establishes — and what it does not
An attestation under this predicate is evidence of what was measured, and when, by
the issuer. It is not a certification, an endorsement, or a conformity mark,
and must not be presented as one. A measured slot is not a score.
Verifying the signature establishes that the named key produced these bytes and that the bytes
have not changed. It says nothing about the state of that key now: offline verification is a
computation over the parameters you hold, while revocation is a property of the present. A consumer
must not treat a signature that verifies as evidence that the signing key is still valid. Where a
decision depends on revocation state, the key-resolution path and the staleness you accept are
operational parameters of your deployment and must be stated by it. Recorded against our own rule as
correction C-2026-0902-09.
Shape
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [{ "name": "<artefact>", "digest": { "sha256": "<hex>" } }],
"predicateType": "https://councilof.ai/attestations/measurement/v1",
"predicate": {
"axis": "<axis-slug>",
"status": "MEASURED | UNMEASURED | UNCHECKABLE",
"n": 0,
"method": "<deterministic-facts | fleet-comparison | …>",
"as_of": "<RFC 3339>",
"source_urls": ["…"]
}
}
Status words are a closed set. A fetch failure is UNCHECKABLE, never a fabricated
0.000. An axis with no signed card is UNMEASURED and stays visibly empty.
Verify one
Offline, zero dependencies, three states rather than two:
gspc-verify.mjs (Apache-2.0).
Rule: HOW-TO-VERIFY.md.
Live board: GET /api/gspc.