open-standards/scripts/check-wai-quantum-names.py
Transaction Science 09484ade64
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 9s
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-audit collector and player integration / does this change touch it (pull_request) Successful in 7s
WAI operation catalogue / does this change touch it (pull_request) Successful in 8s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (pull_request) Successful in 9s
WAI conformance / does this change touch it (pull_request) Successful in 9s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 20s
wai-fleet service / does this change touch it (pull_request) Successful in 10s
wai-ledger service / does this change touch it (pull_request) Successful in 11s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 14s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 8s
WAI energy receipts / does this change touch it (pull_request) Successful in 19s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 8s
wai-sink-android native sink library / does this change touch it (pull_request) Successful in 10s
WAI Studio / does this change touch it (pull_request) Successful in 9s
wai-sink-swift native sink package / does this change touch it (pull_request) Successful in 9s
wai-web wasm32 / does this change touch it (pull_request) Successful in 8s
wai-quantum for JavaScript / does this change touch it (pull_request) Successful in 24s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 21s
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (pull_request) Successful in 4m33s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (pull_request) Successful in 1m50s
wai-quantum studio and desktop / desktop app · windows (pull_request) Successful in 10m8s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 38s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 39s
wai-audit collector and player integration / collector · linux (pull_request) Successful in 5m23s
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Successful in 1m32s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 3m18s
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 3m50s
WAI operation catalogue / the catalogue and every door · linux (pull_request) Successful in 6m15s
wai-pack / wai-pack · linux (pull_request) Successful in 1m44s
wai-fleet service / service · linux (pull_request) Successful in 2m51s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 54s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m26s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 4m23s
wai-ledger service / service · linux (pull_request) Successful in 7m25s
wai-quantum studio and desktop / desktop app · linux (pull_request) Successful in 5m58s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m27s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 10m37s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 9m11s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 14m35s
wai-quantum for JavaScript / javascript · linux (pull_request) Successful in 10m53s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 13m10s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 13m0s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 1m19s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (pull_request) Successful in 1m40s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 31s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 7m53s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m20s
wai-fleet service / service · macos (pull_request) Successful in 58s
wai-ledger service / service · macos (pull_request) Successful in 1m11s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 8m27s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 18m13s
wai-pack / wai-pack · macos (pull_request) Successful in 3m25s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 16m29s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 7m3s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 18m13s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 2m42s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 10m42s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 18m58s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 24m5s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 17m33s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 1m21s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 19s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 3m39s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 11m56s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 35s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 16m9s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 16m19s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 47s
wai-pack / wai-pack · linux-arm64 (pull_request) Failing after 7h34m11s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Failing after 7h34m29s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Failing after 7h34m55s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Failing after 7h49m22s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 36s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 47s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 2m34s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
wai: every wai.quantum string is registered, listed with what it names, or a schema's name
The registry's unregistered labels now hold every wai.quantum string the tree uses
that no revision registers, each saying what it names, grouped: the receipt kinds,
the modules of wai-quantum, the names a record's members carry, the fabric's kernels
and corpora, the circuit contracts' revisions, the documents with no schema file, the
digest domains, and the strings the tests and the provider corpus give a reader to see
it refuse them. A document's name, wai.quantum.<document>/<major>, is accounted for by
its schema file (schemas/<document>.v<major>.json, its title the name) and needs no row.

scripts/check-wai-quantum-names.py reads the registry export and the schema files and
every text file but the changelog, and names the file and line of any string neither
accounts for; it also fails on a pattern that matches nothing, a schema file whose
title is not its file's name, a quantum label nothing outside the registry uses, and a
string held twice. The repository checks run it and its self-test. The wai-quantum
constants test compares the receipt kinds alone, and the registry test refuses a label
listed twice.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 07:29:58 -05:00

216 lines
9 KiB
Python
Executable file

#!/usr/bin/env python3
"""check-wai-quantum-names.py: every `wai.quantum.*` string in the tree is accounted for.
A string of the quantum namespace is one of:
- a string the registry registers (a capability or a record), or one of its named
identifiers, unregistered labels or wire identifiers. The registry is one table,
wai/wai-rs/src/codecs/registry.rs, exported by `wai registry export` as
wai/registry/capabilities.json (CI holds the export to the table with
`wai registry export --check`). This reads the export. A label there says what it
names: a module of the quantum crates, a receipt kind, a kernel, a document with no
schema file, or a string a test gives a reader to see it refused.
- the name of a document a quantum crate writes, `wai.quantum.<document>/<major>`,
kept as a JSON Schema at `schemas/<document>.v<major>.json` beside the crate's
manifest, whose `title` is the name (wai/wai-quantum/VERSIONING.md, *The schemas*).
A name such a file gives as the `const` of a member (a document carried inside
another) is accounted for the same way. The schema files are the list: a new
document adds its file, and no line anywhere else.
A string is `wai.quantum.` followed by dot-separated segments of letters, digits, `_`
and `-`, and optionally `/` and a revision (`wai.quantum.circuit2`,
`wai.quantum.cal.noise_learn`, `wai.quantum.job-result/1`, `wai.quantum.sv/run-wide`).
A pattern `wai.quantum.<segments>.*` is accounted for when some accounted string starts
with `wai.quantum.<segments>.`. A placeholder (`wai.quantum.<document>`) or a prefix
(`"wai.quantum."`) is not a string and is not read.
Every text file git tracks or would track is read, except the changelog
(wai/CHANGELOG.md and the entry files of wai/changes/): it records names as they were
when each change was made. Binary files are not read.
Findings, one line each:
- a string accounted for by none of the above, with its file and line;
- a quantum schema file whose `title` is not the name its file name gives;
- a `wai.quantum.*` label or wire identifier that nothing outside the registry's own
files (registry.rs, its export, REGISTRY.md) uses, so the list stays the set of
strings in use;
- a `wai.quantum.*` string the registry holds twice.
check-wai-quantum-names.py [--root DIR]
Exit 0 when every string is accounted for, 1 with one line a finding otherwise, 2 when
the tree cannot be read. Standard library only.
"""
import json
import os
import re
import subprocess
import sys
PREFIX = "wai.quantum."
# A string of the namespace, with its revision and a trailing `.*` (a pattern).
TOKEN = re.compile(
r"wai\.quantum\.([A-Za-z0-9_][A-Za-z0-9_-]*(?:\.[A-Za-z0-9_][A-Za-z0-9_-]*)*)"
r"(/[A-Za-z0-9_-]+)?(\.\*)?"
)
EXPORT = "wai/registry/capabilities.json"
# The registry's own files: the table, its export and the page that prints it.
REGISTRY_FILES = {"wai/wai-rs/src/codecs/registry.rs", EXPORT, "wai/REGISTRY.md"}
# The record of past changes, read by nothing here.
HISTORY = ("wai/CHANGELOG.md", "wai/changes/")
SCHEMA_FILE = re.compile(r"(?:^|/)schemas/([a-z0-9_-]+(?:\.[a-z0-9_-]+)*)\.v([0-9]+)\.json$")
def fail(msg):
print(f"check-wai-quantum-names: {msg}", file=sys.stderr)
sys.exit(2)
def git(root, *args):
r = subprocess.run(["git", "-C", root, *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return r.returncode, r.stdout.decode("utf-8", "replace"), r.stderr.decode("utf-8", "replace")
def occurrences(root):
"""Every string of the namespace in the text files git tracks or would track:
[(path, line, string, is_pattern)]."""
rc, out, err = git(root, "grep", "-I", "-n", "-z", "--untracked", "-F", "-e", PREFIX)
if rc == 1:
return []
if rc != 0:
fail(f"git grep failed ({rc}): {err.strip()}")
found = []
for rec in out.split("\n"):
if not rec:
continue
parts = rec.split("\0", 2)
if len(parts) != 3:
fail(f"unreadable git grep line: {rec[:120]!r}")
path, line, text = parts
if path == HISTORY[0] or path.startswith(HISTORY[1]):
continue
for m in TOKEN.finditer(text):
name = PREFIX + m.group(1) + (m.group(2) or "")
found.append((path, int(line), name, bool(m.group(3))))
return found
def registry(root):
"""The strings the export holds, by table, and the quantum strings it holds twice."""
path = os.path.join(root, EXPORT)
try:
with open(path, encoding="utf-8") as fh:
doc = json.load(fh)
except (OSError, ValueError) as e:
fail(f"cannot read {EXPORT}: {e}")
tables = {
"registered": [c["capability"] for c in doc.get("capabilities", [])],
"identifier": [i["identifier"] for i in doc.get("identifiers", [])],
"label": [l["label"] for l in doc.get("unregistered_labels", [])],
"wire identifier": [w["name"] for w in doc.get("wire_identifiers", [])],
}
if not tables["registered"]:
fail(f"{EXPORT} registers nothing")
held = {}
twice = []
for table, names in tables.items():
for n in names:
if n.startswith(PREFIX):
if n in held:
twice.append(f"{EXPORT}: {n} is held twice ({held[n]}, {table})")
held.setdefault(n, table)
return tables, held, twice
def schema_names(root):
"""The document names the quantum schema files give, and the findings about them."""
rc, out, err = git(root, "ls-files", "-z", "--cached", "--others", "--exclude-standard", "--", "wai/")
if rc != 0:
fail(f"git ls-files failed ({rc}): {err.strip()}")
names, findings = {}, []
def consts(v, acc):
if isinstance(v, dict):
for k, x in v.items():
if k == "const" and isinstance(x, str):
acc.append(x)
else:
consts(x, acc)
elif isinstance(v, list):
for x in v:
consts(x, acc)
for path in sorted(p for p in out.split("\0") if p):
m = SCHEMA_FILE.search(path)
if not m or not os.path.isfile(os.path.join(root, path)):
continue
try:
with open(os.path.join(root, path), encoding="utf-8") as fh:
doc = json.load(fh)
except (OSError, ValueError) as e:
findings.append(f"{path}: not a JSON document ({e})")
continue
title = doc.get("title") if isinstance(doc, dict) else None
if not (isinstance(title, str) and title.startswith(PREFIX)):
continue
want = f"{PREFIX}{m.group(1)}/{m.group(2)}"
if title != want:
findings.append(f"{path}: its title is {title}, but a schema of that file is named {want}")
continue
names.setdefault(title, path)
acc = []
consts(doc, acc)
for c in acc:
t = TOKEN.fullmatch(c)
if t and not t.group(3):
names.setdefault(c, path)
return names, findings
def main(argv):
root = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
if len(argv) == 2 and argv[0] == "--root":
root = os.path.abspath(argv[1])
elif argv:
fail("usage: check-wai-quantum-names.py [--root DIR]")
tables, held, findings = registry(root)
accounted = {n for names in tables.values() for n in names}
schemas, schema_findings = schema_names(root)
findings += schema_findings
accounted |= set(schemas)
used_outside = set()
seen = 0
for path, line, name, pattern in occurrences(root):
seen += 1
if path not in REGISTRY_FILES:
used_outside.add(name)
if pattern:
stem = name + "."
if not any(a.startswith(stem) for a in accounted):
findings.append(f"{path}:{line}: {name}.* matches no registered string, label or schema's name")
continue
if name not in accounted:
findings.append(f"{path}:{line}: {name} is not registered, listed as a label or wire identifier, "
f"or the name of a quantum schema file")
for n, table in sorted(held.items()):
if table in ("label", "wire identifier") and n not in used_outside:
findings.append(f"{EXPORT}: the {table} {n} is used nowhere outside the registry's own files")
if findings:
for f in findings:
print(f)
sys.stdout.flush()
print(f"\n{len(findings)} finding(s). A new `wai.quantum.*` string is registered, or listed with what it "
"names in UNREGISTERED_LABELS (wai/wai-rs/src/codecs/registry.rs, beside its group), then "
"`wai registry export` is run; a document's name is its schema file "
"(`schemas/<document>.v<major>.json`, its `title` the name).", file=sys.stderr)
return 1
print(f"check-wai-quantum-names: every wai.quantum string is accounted for "
f"({seen} occurrences read; {len(schemas)} named by schema files)")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))