open-standards/scripts/check-wai-corpus-licences.py
Transaction Science ae94f935e7
Some checks failed
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 8s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 7s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 7s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 8s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 7s
wai-audit collector and player integration / does this change touch it (pull_request) Successful in 7s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (pull_request) Successful in 7s
wai cross-architecture byte-equality / does this change touch it (pull_request) Successful in 7s
WAI operation catalogue / does this change touch it (pull_request) Successful in 7s
WAI conformance / does this change touch it (pull_request) Successful in 13s
WAI energy receipts / does this change touch it (pull_request) Successful in 8s
wai-fleet service / does this change touch it (pull_request) Successful in 8s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 13s
wai formal verification (integer core) / does this change touch it (pull_request) Successful in 8s
WAI JPEG-AI whole decode (pinned inputs, required) / does this change touch it (pull_request) Successful in 12s
wai-ledger service / does this change touch it (pull_request) Successful in 10s
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Successful in 8s
WAI neural sink gates / does this change touch it (pull_request) Successful in 13s
wai-ops-npu integer operators on neural processors / does this change touch it (pull_request) Successful in 6s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 8s
wai-ops integer operators / does this change touch it (pull_request) Successful in 15s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 8s
wai-quantum for JavaScript / does this change touch it (pull_request) Successful in 13s
wai-sink-android native sink library / does this change touch it (pull_request) Successful in 8s
wai-sink-swift native sink package / does this change touch it (pull_request) Successful in 13s
WAI mbt2018_mean integer decode (regenerated vectors) / does this change touch it (pull_request) Successful in 8s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 8s
WAI Studio / does this change touch it (pull_request) Successful in 13s
wai-web wasm32 / does this change touch it (pull_request) Successful in 8s
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (pull_request) Successful in 3m28s
wai-ops-npu integer operators on neural processors / neural processor (framework-128gb silicon) (pull_request) Successful in 13s
wai formal verification (integer core) / kani (isqrt512) (pull_request) Successful in 29m16s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 32s
wai-audit collector and player integration / collector · linux (pull_request) Successful in 1m17s
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Successful in 32s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (pull_request) Failing after 1m42s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (pull_request) Successful in 3m1s
wai formal verification (integer core) / kani (rans64-t2) (pull_request) Successful in 13m17s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 40s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m52s
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Successful in 1m29s
wai-quantum studio and desktop / desktop app · windows (pull_request) Successful in 8m59s
wai formal verification (integer core) / every harness in one shard (pull_request) Successful in 24s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 3m28s
WAI operation catalogue / the catalogue and every door · linux (pull_request) Successful in 4m44s
wai-fleet service / service · linux (pull_request) Successful in 2m5s
wai formal verification (integer core) / kani (stage) (pull_request) Successful in 3m0s
wai formal verification (integer core) / kani (plan) (pull_request) Successful in 5m52s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 8m12s
wai-ledger service / service · linux (pull_request) Successful in 1m38s
wai formal verification (integer core) / kani (integer-core) (pull_request) Successful in 5m39s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m45s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 5m56s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 3m4s
wai-ops integer operators / linux-x86_64 (pull_request) Successful in 50s
wai-ops integer operators / wasm32-wasip2 (wasmtime) (pull_request) Successful in 30s
wai-ops integer operators / wasm32 under Node (pull_request) Successful in 21s
wai-ops integer operators / independent checker (Python) (pull_request) Successful in 12s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 12m57s
wai-pack / wai-pack · linux (pull_request) Successful in 1m43s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 15m38s
WAI neural sink gates / the exact JPEG-AI decoder reports its path (pinned inputs, required) (pull_request) Successful in 5m23s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m28s
wai-quantum for JavaScript / javascript · linux (pull_request) Successful in 2m48s
wai formal verification (integer core) / kani (sound) (pull_request) Successful in 13m40s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 4m2s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 2m40s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m28s
wai-quantum studio and desktop / desktop app · linux (pull_request) Successful in 5m24s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 5m11s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 5m30s
wai formal verification (integer core) / kani (stage-long) (pull_request) Successful in 20m33s
wai formal verification (integer core) / kani (arith) (pull_request) Successful in 25m17s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 11m9s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 57s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 1m16s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 3m34s
wai cross-architecture byte-equality / linux-aarch64 (pull_request) Successful in 30s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 22s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 7m7s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 6m17s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 11m55s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (pull_request) Successful in 1m49s
wai cross-architecture byte-equality / macos-arm64 (reference) (pull_request) Successful in 37s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 35s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m24s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 16m11s
wai-fleet service / service · macos (pull_request) Successful in 2m5s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 9m26s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 12m23s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 12s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 34s
wai-ledger service / service · macos (pull_request) Successful in 1m8s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 18m20s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 2m8s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 20m55s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 6m35s
wai-ops-npu integer operators on neural processors / builds · no device is not a pass (linux-arm64) (pull_request) Successful in 21s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 16m58s
wai-ops integer operators / macos-arm64 (pull_request) Successful in 1m0s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m56s
wai-pack / wai-pack · macos (pull_request) Successful in 3m19s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 26s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 14s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 12m3s
wai-ops integer operators / linux-aarch64 (pull_request) Successful in 1m11s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 13m4s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 2m46s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 5m19s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 9m20s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 8m15s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 11m44s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 18m0s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h30m13s
wai/neural-corpus-licence, converted to the layout of the fix: no shared append point
The change of wai/neural-corpus-licence (44d5f2264..6bddde42d, 5 commits), on the fix branch: its
changelog entries as files of wai/changes/, its wai-conformance.yml edits as step files,
corpus files and test tags, and every other file as the branch has it.

- 40052a902 wai: the trained int_synth vector's tool generates its own pictures from a seed
- c86d58210 wai: neural-conformance's photo, trained and coded on generated pictures
- 4321d68cc wai: every neural-conformance vector has a licence record, and a lint requires one
- 63aea099a wai: photo's licence record gives its training pictures as streams 1 to 512
- 6bddde42d wai: the trained int_synth vector's check holds its licence record to meta.json

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 01:45:34 -05:00

171 lines
7.5 KiB
Python
Executable file

#!/usr/bin/env python3
"""check-wai-corpus-licences.py: every vector of a WAI corpus that keeps licence records
has one, and every record states a licence that permits redistribution.
A corpus listed in CORPORA keeps `licences.json` beside its README:
{"format": "wai-corpus-licences/1",
"vectors": {"<name>": {"licence": "<SPDX id>", "content": "generated" | "third-party",
"generator": "<path below wai/>", "input": "<what it reads>",
"source": "<where a third-party input comes from>",
"training": {"content": ..., "generator": ..., "input": ...,
"source": ..., "licence": ...}}}}
What each corpus is held to:
1. `licences.json` exists, parses, and has this format.
2. Every vector has a record: each directory under `vectors/`, and each name in the
corpus's `expected_hashes.json` and `sha256.json`, is a key of `vectors`. Every key
names a directory under `vectors/`.
3. `licence` is one of LICENCES, the licences that permit redistribution.
4. `content` "generated" names a `generator` that exists below `wai/` and a non-empty
`input`, and no `source`. `content` "third-party" names a non-empty `source`; its
`licence` is the source's, and any `generator` it names exists.
5. A vector whose `expected_hashes.json` entry has `"trained": true` has a `training`
record, held to rule 4, whose `licence`, required when its content is third-party,
is one of LICENCES; a vector not marked trained has none.
6. A record has no member other than these.
The check holds what the records state, not their truth: that is a reviewer's, and for
`neural-conformance`'s trained vector also `tools/wai_int_synth_real.py --check`'s.
check-wai-corpus-licences.py [--root DIR]
Exit 0 when every corpus holds, printing each corpus's vectors by licence; 1 with one
line a finding otherwise. Standard library only.
"""
import json
import os
import sys
# The corpora that keep a licence record for each vector, relative to the root.
CORPORA = ["wai/neural-conformance"]
FORMAT = "wai-corpus-licences/1"
# SPDX identifiers of the licences a committed vector, or the data a committed model was
# trained on, may carry: each permits redistribution.
LICENCES = {"Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "CC-BY-4.0", "CC0-1.0", "MIT"}
VECTOR_KEYS = {"licence", "content", "generator", "input", "source", "training"}
TRAINING_KEYS = {"content", "generator", "input", "source", "licence"}
def names_in(path):
"""The top-level keys of a JSON object file, or None when the file does not exist."""
if not os.path.exists(path):
return None
with open(path, encoding="utf-8") as fh:
doc = json.load(fh)
return doc if isinstance(doc, dict) else {}
def nonempty(v):
return isinstance(v, str) and v.strip() != ""
def check_content(root, where, rec, findings):
"""Rule 4, for a vector record or a training record."""
content = rec.get("content")
gen = rec.get("generator")
if gen is not None and not (nonempty(gen) and os.path.isfile(os.path.join(root, "wai", gen))):
findings.append(f"{where}: generator {gen!r} is not a file below wai/")
if content == "generated":
if gen is None:
findings.append(f"{where}: generated content names no generator")
if not nonempty(rec.get("input")):
findings.append(f"{where}: generated content names no input")
if "source" in rec:
findings.append(f"{where}: generated content has a source")
elif content == "third-party":
if not nonempty(rec.get("source")):
findings.append(f"{where}: third-party content names no source")
else:
findings.append(f"{where}: content {content!r} is neither \"generated\" nor \"third-party\"")
def check_corpus(root, corpus, findings, split):
base = os.path.join(root, corpus)
path = os.path.join(base, "licences.json")
if not os.path.isfile(path):
findings.append(f"{corpus}: no licences.json")
return
try:
with open(path, encoding="utf-8") as fh:
doc = json.load(fh)
except (OSError, ValueError) as e:
findings.append(f"{corpus}/licences.json: does not parse: {e}")
return
if not isinstance(doc, dict) or doc.get("format") != FORMAT or not isinstance(doc.get("vectors"), dict):
findings.append(f"{corpus}/licences.json: not a {FORMAT} document with a `vectors` object")
return
records = doc["vectors"]
vdir = os.path.join(base, "vectors")
dirs = sorted(d for d in os.listdir(vdir) if os.path.isdir(os.path.join(vdir, d))) if os.path.isdir(vdir) else []
try:
hashes = names_in(os.path.join(base, "expected_hashes.json")) or {}
sha = names_in(os.path.join(base, "sha256.json")) or {}
except ValueError as e:
findings.append(f"{corpus}: a hash manifest does not parse: {e}")
return
for name in sorted(set(dirs) | set(hashes) | set(sha)):
if name not in records:
findings.append(f"{corpus}: vector {name} has no licence record")
for name in sorted(records):
where = f"{corpus}/licences.json: {name}"
rec = records[name]
if name not in dirs:
findings.append(f"{where}: no directory vectors/{name}")
if not isinstance(rec, dict):
findings.append(f"{where}: not an object")
continue
for k in sorted(set(rec) - VECTOR_KEYS):
findings.append(f"{where}: unknown member {k!r}")
lic = rec.get("licence")
if lic not in LICENCES:
findings.append(f"{where}: licence {lic!r} is not one of {', '.join(sorted(LICENCES))}")
check_content(root, where, rec, findings)
trained = isinstance(hashes.get(name), dict) and hashes[name].get("trained") is True
tr = rec.get("training")
if trained and tr is None:
findings.append(f"{where}: a trained model with no training record")
elif not trained and tr is not None:
findings.append(f"{where}: a training record on a vector whose model is not marked trained")
if isinstance(tr, dict):
tw = where + " training"
for k in sorted(set(tr) - TRAINING_KEYS):
findings.append(f"{tw}: unknown member {k!r}")
check_content(root, tw, tr, findings)
if (tr.get("content") == "third-party" or "licence" in tr) and tr.get("licence") not in LICENCES:
findings.append(f"{tw}: licence {tr.get('licence')!r} is not one of {', '.join(sorted(LICENCES))}")
elif tr is not None:
findings.append(f"{where}: training is not an object")
if lic in LICENCES:
split.setdefault(corpus, {}).setdefault(lic, []).append(name)
def main(argv):
root = "."
args = argv[1:]
if args[:1] == ["--root"] and len(args) == 2:
root = args[1]
elif args:
print("usage: check-wai-corpus-licences.py [--root DIR]", file=sys.stderr)
return 2
findings, split = [], {}
for corpus in CORPORA:
check_corpus(root, corpus, findings, split)
for f in findings:
print(f)
if findings:
print(f"check-wai-corpus-licences: {len(findings)} finding(s)")
return 1
for corpus in CORPORA:
for lic, names in sorted(split.get(corpus, {}).items()):
print(f"{corpus}: {lic}: {', '.join(names)}")
print("check-wai-corpus-licences: every vector has a licence record")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))