inferencekit-cli 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. inferencekit/__init__.py +9 -0
  2. inferencekit/__main__.py +5 -0
  3. inferencekit/analysis/__init__.py +1 -0
  4. inferencekit/analysis/ncu_csv.py +284 -0
  5. inferencekit/analysis/nsys_sqlite.py +518 -0
  6. inferencekit/canonical.py +104 -0
  7. inferencekit/checkpoint.py +396 -0
  8. inferencekit/cli.py +274 -0
  9. inferencekit/cuda/bw_peak.cu +252 -0
  10. inferencekit/cuda/torch_bw.py +60 -0
  11. inferencekit/engines/__init__.py +7 -0
  12. inferencekit/engines/adapters.py +190 -0
  13. inferencekit/engines/clip/__init__.py +13 -0
  14. inferencekit/engines/clip/comfyui.py +749 -0
  15. inferencekit/engines/clip/diffusers_ltx.py +601 -0
  16. inferencekit/engines/clip/noise.py +46 -0
  17. inferencekit/engines/clip/official_ltx.py +316 -0
  18. inferencekit/engines/clip/server.py +542 -0
  19. inferencekit/engines/clip/stepdump.py +182 -0
  20. inferencekit/engines/gates.py +94 -0
  21. inferencekit/engines/sglang_worker.py +86 -0
  22. inferencekit/engines/vllm_worker.py +129 -0
  23. inferencekit/evidence.py +427 -0
  24. inferencekit/gpuinfo.py +93 -0
  25. inferencekit/hardware.py +135 -0
  26. inferencekit/mcp_server.py +178 -0
  27. inferencekit/ops/__init__.py +30 -0
  28. inferencekit/ops/bench.py +184 -0
  29. inferencekit/ops/bench_audio.py +384 -0
  30. inferencekit/ops/bench_clip.py +819 -0
  31. inferencekit/ops/bench_image.py +393 -0
  32. inferencekit/ops/bench_rounds.py +297 -0
  33. inferencekit/ops/bench_serve.py +866 -0
  34. inferencekit/ops/ceiling.py +135 -0
  35. inferencekit/ops/compare.py +378 -0
  36. inferencekit/ops/correctness.py +153 -0
  37. inferencekit/ops/doctor.py +486 -0
  38. inferencekit/ops/gates.py +1772 -0
  39. inferencekit/ops/gates_clip.py +930 -0
  40. inferencekit/ops/intake.py +1321 -0
  41. inferencekit/ops/ledger.py +749 -0
  42. inferencekit/ops/manifest.py +309 -0
  43. inferencekit/ops/ncu.py +183 -0
  44. inferencekit/ops/nsys.py +224 -0
  45. inferencekit/ops/prompts.py +316 -0
  46. inferencekit/ops/quality.py +2161 -0
  47. inferencekit/ops/quality_clip.py +690 -0
  48. inferencekit/ops/quality_clip_steps.py +341 -0
  49. inferencekit/ops/report.py +317 -0
  50. inferencekit/ops/review.py +119 -0
  51. inferencekit/ops/rocprof.py +89 -0
  52. inferencekit/ops/roofline.py +392 -0
  53. inferencekit/ops/store.py +61 -0
  54. inferencekit/proc.py +172 -0
  55. inferencekit/prompts/ATTRIBUTION.md +56 -0
  56. inferencekit/prompts/__init__.py +167 -0
  57. inferencekit/prompts/build.py +518 -0
  58. inferencekit/prompts/dev-load.jsonl.gz +0 -0
  59. inferencekit/prompts/dev-load.manifest.json +212 -0
  60. inferencekit/prompts/dev.jsonl.gz +0 -0
  61. inferencekit/prompts/dev.manifest.json +214 -0
  62. inferencekit/prompts/exclusions.json +54 -0
  63. inferencekit/quality/__init__.py +23 -0
  64. inferencekit/quality/client.py +66 -0
  65. inferencekit/quality/data/gsm8k_LICENSE.txt +21 -0
  66. inferencekit/quality/fake.py +329 -0
  67. inferencekit/quality/gsm8k.py +224 -0
  68. inferencekit/quality/logprobs.py +106 -0
  69. inferencekit/quality/metrics.py +235 -0
  70. inferencekit/quality/niah.py +63 -0
  71. inferencekit/quality/parquet.py +296 -0
  72. inferencekit/quality/sampling.py +262 -0
  73. inferencekit/quality/step_replay.py +217 -0
  74. inferencekit/quality/video_metrics.py +304 -0
  75. inferencekit/registry.py +206 -0
  76. inferencekit/review/__init__.py +6 -0
  77. inferencekit/review/diff.py +163 -0
  78. inferencekit/review/media.py +181 -0
  79. inferencekit/review/page.py +920 -0
  80. inferencekit/review/rundir.py +844 -0
  81. inferencekit/roofline_headers.py +504 -0
  82. inferencekit/schemas/evidence.v1.json +130 -0
  83. inferencekit/schemas/evidence.v2.json +499 -0
  84. inferencekit/schemas/intake.v1.json +276 -0
  85. inferencekit/schemas/run-manifest.v1.json +118 -0
  86. inferencekit/serve/__init__.py +8 -0
  87. inferencekit/serve/audio_client.py +330 -0
  88. inferencekit/serve/client.py +446 -0
  89. inferencekit/serve/clip_client.py +351 -0
  90. inferencekit/serve/clip_rounds.py +429 -0
  91. inferencekit/serve/image_client.py +373 -0
  92. inferencekit/serve/loadgen.py +136 -0
  93. inferencekit/serve/metrics.py +203 -0
  94. inferencekit/serve/profiles.py +105 -0
  95. inferencekit/serve/prompts_io.py +125 -0
  96. inferencekit/serve/rounds.py +1111 -0
  97. inferencekit/serve/servers.py +897 -0
  98. inferencekit/stats.py +249 -0
  99. inferencekit_cli-0.1.0.dist-info/METADATA +233 -0
  100. inferencekit_cli-0.1.0.dist-info/RECORD +104 -0
  101. inferencekit_cli-0.1.0.dist-info/WHEEL +4 -0
  102. inferencekit_cli-0.1.0.dist-info/entry_points.txt +2 -0
  103. inferencekit_cli-0.1.0.dist-info/licenses/LICENSE +202 -0
  104. inferencekit_cli-0.1.0.dist-info/licenses/NOTICE +9 -0
@@ -0,0 +1,690 @@
1
+ """quality clip: does a faster video engine still make the reference pipeline's clips?
2
+
3
+ Inputs are directories of clips: a ``bench clip`` outputs directory (``outputs/<label>/r<round>/<id>.mp4``)
4
+ or any directory of ``<id>.<ext>`` files. Clips pair up by their path relative to the directory, so the
5
+ engine and the reference must have been asked for the same clips in the same rounds:
6
+
7
+ --reference the BF16 reference pipeline's clips
8
+ --reference-repeat the reference run a second time with the same requests: the run-to-run A/A floor
9
+ --reference-alt the reference with another exact attention backend (e.g. SDPA math instead of flash):
10
+ the kernel A/A floor, how far an exact but different kernel already moves the clip
11
+ --outputs each engine's clips (one directory per engine)
12
+
13
+ Every clip pair is scored frame by frame by ``quality/video_metrics.py``, which runs as a worker inside the
14
+ video pipeline's own Python (``--python``; PyAV and numpy, and torch + lpips for LPIPS), because the harness
15
+ carries none of those packages. Metrics per frame: PSNR (dB, RGB, capped at 100 dB for identical frames),
16
+ SSIM (luma, Gaussian 11x11) and LPIPS (v0.1, AlexNet); each clip's value is its mean over frames, and the
17
+ request is the bootstrap unit: frames inside a clip are not independent, and neither are the clips of one
18
+ request made again in later rounds (bench clip's ``--seed-policy fixed`` asks for the same clips every
19
+ round; a deterministic pipeline makes them byte for byte). Clips whose kept request bodies match on every
20
+ REQUEST_KEYS field are one unit; without request bodies, every round of a clip id is one unit.
21
+
22
+ Same inputs, or the comparison means nothing: the engine's clip and the reference's must come from the same
23
+ prompt, image, shape, steps, guidance, seed and initial noise. When the directories are bench clip outputs,
24
+ the request bodies it kept (``inputs/<label>/<key>.json``) are compared field by field and a clip whose
25
+ request differs is left out (the verdict is then at best UNPROVEN). Identical initial noise is the
26
+ engines' job (the clip contract's ``noise_seed``); a pipeline that draws its noise differently shows up as
27
+ an engine-vs-reference distance far above the floor.
28
+
29
+ Verdicts (``--fidelity``):
30
+ lossless (default) per metric, a paired bootstrap CI over clips of "engine vs reference" minus "floor vs
31
+ reference" (oriented so positive = worse), against pre-registered margins
32
+ (``--margin-psnr-db``, ``--margin-ssim``, ``--margin-lpips``): PASS when the whole CI is
33
+ within the margin, FAIL when all of it is beyond, else UNPROVEN
34
+ (``quality.metrics.margin_verdict``). The floor is the alternative-backend run when
35
+ given, else the repeat. A deterministic reference repeats itself exactly; an exact floor
36
+ cannot tell a different-but-exact kernel from a lossy one, so whenever the floor used is
37
+ bit-identical to the reference (the repeat, or an alternative-backend run whose switch
38
+ was not applied) an engine that is not bit-exact gets UNPROVEN, never PASS or FAIL.
39
+ lossy a declared quality budget (``--budget``, the full-reference bound: psnr_db_min, ssim_min,
40
+ lpips_max on the engine's mean vs the reference, judged on the CI over clips) and a
41
+ human spot-check record (``--spot-check``): a lossy PASS needs both; "not_acceptable"
42
+ in the spot check is a FAIL. Lossy results are a separate track, reported as
43
+ "N x at the stated quality cost", never ranked against lossless ones.
44
+ gross a loose gross-failure gate beside the per-step check (quality clip-steps), which judges
45
+ losslessness: the lossless comparison with the same margins (set them loose), but only a
46
+ CI entirely beyond the margin FAILs, anything else PASSes (an exact floor still gives
47
+ UNPROVEN: it needs --reference-alt).
48
+ Any clip whose frame size or frame count differs from the reference's is a FAIL (the engine did not make
49
+ the clip it was asked for; gates clip checks the decoded shape against the request), and so is an engine
50
+ clip whose sha256 differs from the one its directory's ``index.json`` (bench clip's outputs index, when
51
+ present) recorded: it is not the clip that was timed. A requested metric that could not be computed (e.g.
52
+ LPIPS without its weights) counts as UNPROVEN.
53
+ """
54
+
55
+ from __future__ import annotations
56
+
57
+ import json
58
+ import re
59
+ import sys
60
+ from pathlib import Path
61
+
62
+ from inferencekit import evidence as ev
63
+ from inferencekit import stats
64
+ from inferencekit.canonical import file_sha256
65
+ from inferencekit.ops.quality import _kind
66
+ from inferencekit.proc import run, which
67
+ from inferencekit.quality import metrics as qm
68
+ from inferencekit.registry import Arg, OpError, operation
69
+
70
+ WORKER = Path(__file__).resolve().parents[1] / "quality" / "video_metrics.py"
71
+ MARK = "INFERKIT_RESULT "
72
+ VIDEO_EXT = (".mp4", ".webm", ".mkv", ".mov", ".avi")
73
+ METRICS = ("psnr", "ssim", "lpips")
74
+ HIGHER_IS_BETTER = {"psnr": True, "ssim": True, "lpips": False}
75
+ UNITS = {"psnr": "dB", "ssim": "index", "lpips": "distance"}
76
+ # Evidence metric names (the review page and a re-run read psnr_db; the flag is --margin-psnr-db).
77
+ NAMES = {"psnr": "psnr_db", "ssim": "ssim", "lpips": "lpips"}
78
+ ROUND_KEY = re.compile(r"^r(\d+)/(.+)$") # bench clip: r<round>/<id>
79
+ BUDGET = {"psnr_db_min": ("psnr", "min"), "ssim_min": ("ssim", "min"), "lpips_max": ("lpips", "max")}
80
+ SPOT_VERDICTS = ("acceptable", "not_acceptable")
81
+ # Request fields the engine's clip and the reference's must share (bench clip's inputs/<label>/<key>.json).
82
+ REQUEST_KEYS = ("task", "prompt", "image", "width", "height", "num_frames", "fps", "steps", "guidance_scale",
83
+ "seed", "noise_seed", "audio")
84
+ FORMAT = "inferencekit.quality.clip.v1"
85
+ PSNR_CAP_DB = 100.0
86
+ FFPROBE_ENTRIES = ("stream=index,codec_type,codec_name,width,height,avg_frame_rate,nb_frames,sample_rate,"
87
+ "channels,duration:frame=stream_index,media_type,width,height,best_effort_timestamp_time,"
88
+ "nb_samples:format=format_name,duration")
89
+
90
+
91
+ # --------------------------------------------------------------------------- the worker and decoding
92
+
93
+ def run_worker(python: str | None, cfg: dict, work: Path, name: str, timeout_s: float) -> dict:
94
+ """Run video_metrics.py under ``python`` (the video pipeline's interpreter); return its results file.
95
+
96
+ Paths in ``cfg`` are only in the config file, which is deleted afterwards; the results carry keys."""
97
+ python = python or sys.executable
98
+ work.mkdir(parents=True, exist_ok=True)
99
+ cfg_path, out_path = work / f"{name}.config.json", work / f"{name}.results.json"
100
+ log_path, stdout_path = work / f"{name}.log", work / f"{name}.stdout.txt"
101
+ cfg_path.write_text(json.dumps({**cfg, "out": str(out_path)}))
102
+ try:
103
+ r = run([python, str(WORKER), str(cfg_path)], timeout=timeout_s, stdout_path=stdout_path,
104
+ stderr_path=log_path)
105
+ finally:
106
+ cfg_path.unlink(missing_ok=True)
107
+ if log_path.is_file():
108
+ log_path.write_text(ev.redact_text(log_path.read_text(errors="replace")))
109
+ lines = [ln for ln in r.stdout.splitlines() if ln.startswith(MARK)]
110
+ stdout_path.unlink(missing_ok=True)
111
+ head = json.loads(lines[-1][len(MARK):]) if lines else None
112
+ if not head or not head.get("ok") or not out_path.is_file():
113
+ tail = log_path.read_text(errors="replace")[-1200:] if log_path.is_file() else r.stderr[-1200:]
114
+ why = (head or {}).get("error") or f"exit {r.returncode}"
115
+ raise OpError(f"video metrics worker failed under {python} ({why}). It needs PyAV and numpy (and torch + "
116
+ "lpips for LPIPS): pass the video pipeline's interpreter with --python." +
117
+ (f"\nlog tail:\n{tail}" if tail.strip() else ""))
118
+ doc = json.loads(out_path.read_text())
119
+ doc["head"] = head
120
+ return doc
121
+
122
+
123
+ def _rate(text) -> float | None:
124
+ try:
125
+ num, _, den = str(text).partition("/")
126
+ v = float(num) / float(den or 1)
127
+ return v if v > 0 else None
128
+ except (ValueError, ZeroDivisionError):
129
+ return None
130
+
131
+
132
+ def _num(x) -> float | None:
133
+ try:
134
+ return float(x)
135
+ except (TypeError, ValueError):
136
+ return None
137
+
138
+
139
+ def probe_ffprobe(path: Path, timeout_s: float = 900) -> dict:
140
+ """Decode ``path`` with ffprobe (``-show_entries frame=...`` decodes every frame); same shape as the
141
+ worker's probe: what decoding gives, beside what the header claims."""
142
+ exe = which("ffprobe")
143
+ if not exe:
144
+ return {"ok": False, "error": "ffprobe not found"}
145
+ r = run([exe, "-v", "error", "-show_entries", FFPROBE_ENTRIES, "-of", "json", str(path)], timeout=timeout_s)
146
+ if r.returncode != 0:
147
+ return {"ok": False, "error": f"ffprobe exit {r.returncode}: {r.stderr.strip()[:300]}"}
148
+ try:
149
+ doc = json.loads(r.stdout)
150
+ except ValueError:
151
+ return {"ok": False, "error": "ffprobe printed no JSON"}
152
+ streams, frames = doc.get("streams") or [], doc.get("frames") or []
153
+ vs = next((s for s in streams if s.get("codec_type") == "video"), None)
154
+ au = next((s for s in streams if s.get("codec_type") == "audio"), None)
155
+ fmt = doc.get("format") or {}
156
+ out = {"ok": True, "decoder": "ffprobe", "video": None, "audio": None,
157
+ "header": {"format": fmt.get("format_name"), "duration_s": _num(fmt.get("duration"))}}
158
+ if vs is not None:
159
+ out["header"]["video"] = {"codec": vs.get("codec_name"), "width": vs.get("width"),
160
+ "height": vs.get("height"), "frames": int(vs["nb_frames"])
161
+ if str(vs.get("nb_frames", "")).isdigit() else None,
162
+ "fps": _rate(vs.get("avg_frame_rate"))}
163
+ vf = [f for f in frames if f.get("stream_index") == vs.get("index")]
164
+ sizes = sorted({(f.get("width"), f.get("height")) for f in vf})
165
+ times = sorted(t for t in (_num(f.get("best_effort_timestamp_time")) for f in vf) if t is not None)
166
+ fps = (len(times) - 1) / (times[-1] - times[0]) if len(times) >= 2 and times[-1] > times[0] else None
167
+ w, h = sizes[0] if sizes else (None, None)
168
+ out["video"] = {"frames": len(vf), "width": w, "height": h, "sizes": [list(s) for s in sizes], "fps": fps,
169
+ "first_s": times[0] if times else None, "last_s": times[-1] if times else None,
170
+ "duration_s": len(vf) / fps if fps else None}
171
+ if au is not None:
172
+ rate = int(au["sample_rate"]) if str(au.get("sample_rate", "")).isdigit() else None
173
+ out["header"]["audio"] = {"codec": au.get("codec_name"), "sample_rate": rate, "channels": au.get("channels"),
174
+ "duration_s": _num(au.get("duration"))}
175
+ samples = sum(int(f.get("nb_samples") or 0) for f in frames if f.get("stream_index") == au.get("index"))
176
+ out["audio"] = {"samples": samples, "sample_rate": rate, "duration_s": samples / rate if rate else None}
177
+ return out
178
+
179
+
180
+ def probe_clips(files: list[tuple[str, Path]], python: str | None, work: Path, timeout_s: float) -> tuple[dict, str]:
181
+ """Decode each clip: with the worker (PyAV) when ``python`` is given, else ffprobe. ({key: probe}, decoder)."""
182
+ if python:
183
+ doc = run_worker(python, {"task": "probe", "files": [{"key": k, "path": str(p)} for k, p in files]},
184
+ work, "probe", timeout_s)
185
+ return {it["key"]: it for it in doc["items"]}, "pyav"
186
+ if not which("ffprobe"):
187
+ raise OpError("nothing to decode clips with: install ffprobe (ffmpeg) or pass --python (a venv with PyAV)")
188
+ return {k: probe_ffprobe(p, timeout_s) for k, p in files}, "ffprobe"
189
+
190
+
191
+ # --------------------------------------------------------------------------- clip directories
192
+
193
+ def clip_files(d: Path) -> dict[str, Path]:
194
+ """{key: path} for every clip under ``d``; key = the path relative to ``d`` without its extension."""
195
+ if not d.is_dir():
196
+ raise OpError(f"{d}: not a directory of clips")
197
+ out: dict[str, Path] = {}
198
+ for p in sorted(d.rglob("*")):
199
+ if p.is_file() and p.suffix.lower() in VIDEO_EXT:
200
+ key = p.relative_to(d).with_suffix("").as_posix()
201
+ if key in out:
202
+ raise OpError(f"{d}: two clips share the key {key!r} ({out[key].name}, {p.name})")
203
+ out[key] = p
204
+ if not out:
205
+ raise OpError(f"{d}: no clips ({', '.join(VIDEO_EXT)})")
206
+ return out
207
+
208
+
209
+ def requests_of(d: Path) -> dict[str, dict]:
210
+ """bench clip's request bodies for an ``outputs/<label>`` directory: ``inputs/<label>/<key>.json``."""
211
+ if d.parent.name != "outputs":
212
+ return {}
213
+ root = d.parent.parent / "inputs" / d.name
214
+ out = {}
215
+ for p in sorted(root.rglob("*.json")) if root.is_dir() else []:
216
+ try:
217
+ doc = json.loads(p.read_text())
218
+ except (OSError, ValueError):
219
+ continue
220
+ if isinstance(doc, dict):
221
+ out[p.relative_to(root).with_suffix("").as_posix()] = doc
222
+ return out
223
+
224
+
225
+ def request_diff(a: dict | None, b: dict | None) -> list[str] | None:
226
+ """Request fields that differ (None when either side has no request body to compare)."""
227
+ if a is None or b is None:
228
+ return None
229
+ return [k for k in REQUEST_KEYS if a.get(k) != b.get(k)]
230
+
231
+
232
+ def split_key(key: str) -> tuple[int | None, str]:
233
+ """(round, clip id) of a clip key: bench clip's ``r<round>/<id>``, else (None, the key)."""
234
+ m = ROUND_KEY.match(key)
235
+ return (int(m.group(1)), m.group(2)) if m else (None, key)
236
+
237
+
238
+ def request_groups(keys, bodies: list[dict[str, dict]]) -> dict[str, str]:
239
+ """{key: request identity}; clips of one identity are one bootstrap unit, on every side alike.
240
+
241
+ The identity is the REQUEST_KEYS values of the first request body found for the key (the reference's
242
+ first: the sides' bodies must match it to be scored). Without any body it is the clip id, so every
243
+ round of a clip counts once: rounds may have repeated the same request, and a unit too many narrows the
244
+ CI (by about sqrt(rounds) when every round repeats), a unit too few only widens it."""
245
+ out = {}
246
+ for k in keys:
247
+ body = next((b[k] for b in bodies if k in b), None)
248
+ out[k] = ("request " + json.dumps({f: body.get(f) for f in REQUEST_KEYS}, sort_keys=True)
249
+ if body is not None else "clip " + split_key(k)[1])
250
+ return out
251
+
252
+
253
+ def index_mismatch(d: Path, files: dict[str, Path]) -> dict[str, str]:
254
+ """{key: why} for clips whose sha256 differs from ``d/index.json`` (bench clip's outputs index, when the
255
+ directory has one): the file is not the clip that was timed."""
256
+ idx = d / "index.json"
257
+ if not idx.is_file():
258
+ return {}
259
+ try:
260
+ listed = (json.loads(idx.read_text()) or {}).get("files") or {}
261
+ except (OSError, ValueError, AttributeError):
262
+ return {}
263
+ out = {}
264
+ for key, p in files.items():
265
+ want = listed.get(p.relative_to(d).as_posix()) if isinstance(listed, dict) else None
266
+ if isinstance(want, str) and file_sha256(p)[0] != want:
267
+ out[key] = "sha256 differs from index.json: not the clip that was timed"
268
+ return out
269
+
270
+
271
+ # --------------------------------------------------------------------------- scoring
272
+
273
+ def _units(items: dict[str, dict], metric: str, groups: dict[str, str], keys=None) -> list[tuple[float, int]]:
274
+ """Per request (sum over its clips' frames, frames): the request is the bootstrap unit. Units come in the
275
+ order of ``keys`` (default: the items'), so two sides scored over the same keys pair up unit by unit."""
276
+ acc: dict[str, list] = {}
277
+ for k in items if keys is None else keys:
278
+ vs = [v for v in (items[k].get("per_frame") or {}).get(metric) or [] if v is not None]
279
+ u = acc.setdefault(groups.get(k, k), [0.0, 0])
280
+ u[0] += sum(vs)
281
+ u[1] += len(vs)
282
+ return [(s, n) for s, n in acc.values()]
283
+
284
+
285
+ def _scored(items: dict[str, dict], metric: str) -> int:
286
+ return sum(1 for it in items.values() if any(v is not None for v in (it.get("per_frame") or {}).get(metric) or []))
287
+
288
+
289
+ def _exact(it: dict) -> bool:
290
+ return bool(it.get("frames_compared")) and it.get("identical_frames") == it.get("frames_compared")
291
+
292
+
293
+ def lossless_check(eng: dict[str, dict], flo: dict[str, dict], keys: list[str], groups: dict[str, str], metric: str,
294
+ margin: float, resamples: int, seed: int) -> dict:
295
+ d = qm.paired_delta_ci(_units(eng, metric, groups, keys), _units(flo, metric, groups, keys), resamples, seed)
296
+ lo, hi = d["ci95"]
297
+ if HIGHER_IS_BETTER[metric]: # worse = floor - engine
298
+ worse = (-d["delta"] if d["delta"] is not None else None, -hi if hi is not None else None,
299
+ -lo if lo is not None else None)
300
+ else:
301
+ worse = (d["delta"], lo, hi)
302
+ v, why = qm.margin_verdict(worse[1], worse[2], margin)
303
+ both = [k for k in keys if _scored({k: eng[k]}, metric) and _scored({k: flo[k]}, metric)]
304
+ return {"verdict": v, "reason": why, "worse_than_floor": worse[0], "ci95": [worse[1], worse[2]],
305
+ "margin": margin, "n_clips": len(both), "n_requests": d["n_prompts"]}
306
+
307
+
308
+ def budget_check(eng: dict[str, dict], groups: dict[str, str], metric: str, side: str, bound: float, resamples: int,
309
+ seed: int) -> dict:
310
+ units = _units(eng, metric, groups)
311
+ value = qm.pooled(units)
312
+ lo, hi = qm.cluster_ci(units, resamples, seed)
313
+ if lo is None or hi is None:
314
+ v, why = "UNPROVEN", "no confidence interval (need >= 2 distinct requests scored)"
315
+ elif side == "min":
316
+ v = "PASS" if lo >= bound else "FAIL" if hi < bound else "UNPROVEN"
317
+ why = f"CI [{lo:.4g}, {hi:.4g}] vs minimum {bound:g}"
318
+ else:
319
+ v = "PASS" if hi <= bound else "FAIL" if lo > bound else "UNPROVEN"
320
+ why = f"CI [{lo:.4g}, {hi:.4g}] vs maximum {bound:g}"
321
+ return {"verdict": v, "reason": why, "value": value, "ci95": [lo, hi], "bound": bound, "side": side,
322
+ "n_clips": _scored(eng, metric), "n_requests": len([u for u in units if u[1]])}
323
+
324
+
325
+ def summary_of(items: dict[str, dict], groups: dict[str, str], metric: str, resamples: int, seed: int) -> dict:
326
+ units = _units(items, metric, groups)
327
+ return {"value": qm.pooled(units), "ci95": list(qm.cluster_ci(units, resamples, seed)),
328
+ "n_clips": _scored(items, metric), "n_requests": len([u for u in units if u[1]]),
329
+ "n_frames": sum(u[1] for u in units)}
330
+
331
+
332
+ def load_spot_check(path: str | None) -> dict | None:
333
+ """The human spot-check record: {reviewer, date, clips: [...], verdict: acceptable|not_acceptable, notes?}."""
334
+ if not path:
335
+ return None
336
+ p = Path(path)
337
+ try:
338
+ doc = json.loads(p.read_text())
339
+ except (OSError, ValueError) as e:
340
+ raise OpError(f"--spot-check {path}: not a readable JSON file ({type(e).__name__})") from None
341
+ problems = []
342
+ if not isinstance(doc, dict):
343
+ raise OpError(f"--spot-check {path}: must be a JSON object")
344
+ for k in ("reviewer", "date"):
345
+ if not isinstance(doc.get(k), str) or not doc[k].strip():
346
+ problems.append(f"{k} must be non-empty text")
347
+ if doc.get("verdict") not in SPOT_VERDICTS:
348
+ problems.append(f"verdict must be one of {list(SPOT_VERDICTS)}")
349
+ if not isinstance(doc.get("clips"), list) or not doc["clips"] or not all(isinstance(c, str) for c in doc["clips"]):
350
+ problems.append("clips must list the clip keys the reviewer watched")
351
+ if problems:
352
+ raise OpError(f"--spot-check {path}: " + "; ".join(problems))
353
+ sha = ev.artifact(p, None, "spot_check")["sha256"]
354
+ return {"sha256": sha, "reviewer": doc["reviewer"], "date": doc["date"], "verdict": doc["verdict"],
355
+ "clips": doc["clips"], "notes": str(doc.get("notes") or "")[:2000]}
356
+
357
+
358
+ def _budget_arg(text: str | None) -> dict | None:
359
+ if not text:
360
+ return None
361
+ try:
362
+ doc = json.loads(text)
363
+ except ValueError:
364
+ raise OpError("--budget must be a JSON object, e.g. {\"lpips_max\": 0.05, \"psnr_db_min\": 30}") from None
365
+ if not isinstance(doc, dict) or not doc:
366
+ raise OpError("--budget must be a non-empty JSON object")
367
+ bad = [k for k in doc if k not in BUDGET]
368
+ if bad:
369
+ raise OpError(f"--budget: unknown key(s) {bad}; known: {sorted(BUDGET)}")
370
+ for k, v in doc.items():
371
+ if not isinstance(v, (int, float)) or isinstance(v, bool):
372
+ raise OpError(f"--budget {k} must be a number")
373
+ return doc
374
+
375
+
376
+ # --------------------------------------------------------------------------- the operation
377
+
378
+ @operation("quality_clip", ("quality", "clip"),
379
+ "Video clip quality vs the BF16 reference pipeline: per-frame PSNR, SSIM and LPIPS of each engine's "
380
+ "clips (same prompt, steps, seed and initial noise), against an A/A floor (the reference repeated, or "
381
+ "run with another exact attention backend) with bootstrap CIs over clips; lossless margins or a lossy "
382
+ "budget plus a human spot check.",
383
+ [Arg("reference", "string", "The reference pipeline's clips: a bench clip outputs/<label> directory or "
384
+ "any directory of <id>.<ext> clips.", required=True),
385
+ Arg("outputs", "array", "Each engine's clip directory, laid out like --reference.", required=True),
386
+ Arg("reference_repeat", "string", "The reference run a second time with the same requests (the "
387
+ "run-to-run A/A floor)."),
388
+ Arg("reference_alt", "string", "The reference with another exact attention backend (the kernel A/A "
389
+ "floor; used as the floor when given)."),
390
+ Arg("python", "string", "Python of the video pipeline's venv (PyAV, numpy; torch + lpips for LPIPS): "
391
+ "the metrics worker runs there. Default: this interpreter."),
392
+ Arg("metrics", "array", "Metrics to compute and judge: psnr, ssim, lpips.", default=list(METRICS),
393
+ items="string"),
394
+ Arg("fidelity", "string", "lossless: judged against the A/A floor with margins; lossy: judged against "
395
+ "--budget, plus a human --spot-check; gross: the lossless comparison as a loose gate (only a CI "
396
+ "entirely beyond the margin fails).", default="lossless", choices=("lossless", "lossy", "gross")),
397
+ Arg("margin_psnr_db", "number", "Pre-registered margin: max PSNR drop vs the floor (dB).", default=1.0),
398
+ Arg("margin_ssim", "number", "Pre-registered margin: max SSIM drop vs the floor.", default=0.01),
399
+ Arg("margin_lpips", "number", "Pre-registered margin: max LPIPS increase vs the floor.", default=0.01),
400
+ Arg("budget", "string", "Lossy: the declared full-reference bound, JSON with any of psnr_db_min, "
401
+ "ssim_min, lpips_max (on the engine's mean vs the reference)."),
402
+ Arg("spot_check", "string", "Lossy: the human spot-check record, JSON {reviewer, date, clips: [keys], "
403
+ "verdict: acceptable|not_acceptable, notes?}."),
404
+ Arg("device", "string", "Where LPIPS runs (auto = the GPU when the worker sees one).", default="auto",
405
+ choices=("auto", "cpu", "cuda")),
406
+ Arg("frame_stride", "integer", "Score every n-th frame (1 = every frame).", default=1),
407
+ Arg("model", "string", "Model id for the record's identity."),
408
+ Arg("run_dir", "string", "Run directory: the score is also written to <run-dir>/quality/clip_score.json "
409
+ "and the record to <run-dir>/evidence/."),
410
+ Arg("resamples", "integer", "Bootstrap resamples.", default=stats.DEFAULT_RESAMPLES),
411
+ Arg("seed", "integer", "Bootstrap seed.", default=0),
412
+ Arg("timeout_s", "number", "Seconds the metrics worker may take in all.", default=14400)])
413
+ def quality_clip(call, reference, outputs, reference_repeat, reference_alt, python, metrics, fidelity,
414
+ margin_psnr_db, margin_ssim, margin_lpips, budget, spot_check, device, frame_stride, model,
415
+ run_dir, resamples, seed, timeout_s):
416
+ metrics = [m.lower() for m in (metrics or [])]
417
+ if not metrics or any(m not in METRICS for m in metrics):
418
+ raise OpError(f"--metrics must be a non-empty subset of {list(METRICS)}")
419
+ if frame_stride < 1:
420
+ raise OpError("frame_stride must be >= 1")
421
+ budget_doc = _budget_arg(budget)
422
+ if fidelity == "lossy" and not budget_doc:
423
+ raise OpError("--fidelity lossy needs --budget (the declared full-reference bound)")
424
+ if fidelity in ("lossless", "gross") and (budget_doc or spot_check):
425
+ raise OpError("--budget and --spot-check are for --fidelity lossy")
426
+ for k in budget_doc or {}:
427
+ if BUDGET[k][0] not in metrics:
428
+ raise OpError(f"--budget {k} needs {BUDGET[k][0]} in --metrics")
429
+ spot = load_spot_check(spot_check)
430
+ margins = {"psnr": margin_psnr_db, "ssim": margin_ssim, "lpips": margin_lpips}
431
+
432
+ ref_dir = Path(reference)
433
+ ref = clip_files(ref_dir)
434
+ ref_req = requests_of(ref_dir)
435
+ floors = {name: Path(p) for name, p in (("alt", reference_alt), ("repeat", reference_repeat)) if p}
436
+ resolved = {ref_dir.resolve()}
437
+ for name, p in floors.items():
438
+ if p.resolve() in resolved:
439
+ raise OpError(f"--reference-{name} must be another run of the reference, not the same directory")
440
+ resolved.add(p.resolve())
441
+ engines: dict[str, Path] = {}
442
+ for p in map(Path, outputs or []):
443
+ if p.resolve() in resolved:
444
+ raise OpError(f"{p}: the same directory as a reference run")
445
+ label = p.name
446
+ if label in engines:
447
+ raise OpError(f"two --outputs directories are both named {label!r}; rename one")
448
+ engines[label] = p
449
+ if not engines:
450
+ raise OpError("--outputs: give at least one engine's clip directory")
451
+
452
+ sides = {f"floor:{n}": d for n, d in floors.items()} | {f"engine:{lab}": d for lab, d in engines.items()}
453
+ files = {s: clip_files(d) for s, d in sides.items()}
454
+ reqs = {s: requests_of(d) for s, d in sides.items()}
455
+ groups = request_groups(ref, [ref_req] + list(reqs.values()))
456
+ not_timed = {s: index_mismatch(sides[s], files[s]) for s in sides if s.startswith("engine:")}
457
+ pairs, plan = [], {} # plan[side] = {key: {"pair": id} | {"missing": True} | {"request_diff": [...]}}
458
+ for side, have in files.items():
459
+ plan[side] = {}
460
+ for key, ref_path in ref.items():
461
+ if key not in have:
462
+ plan[side][key] = {"missing": True}
463
+ continue
464
+ diff = request_diff(ref_req.get(key), reqs[side].get(key))
465
+ if diff:
466
+ plan[side][key] = {"request_diff": diff}
467
+ continue
468
+ pid = f"{side}|{key}"
469
+ pairs.append({"key": pid, "a": str(ref_path), "b": str(have[key])})
470
+ plan[side][key] = {"pair": pid, "request_checked": diff is not None}
471
+ extra = sorted(set(have) - set(ref))
472
+ if extra:
473
+ plan[side]["__extra__"] = extra
474
+
475
+ store = ev.Store()
476
+ with store.staging_dir() as staging:
477
+ doc = run_worker(python, {"task": "compare", "pairs": pairs, "metrics": metrics, "device": device,
478
+ "frame_stride": frame_stride, "psnr_cap_db": PSNR_CAP_DB, "lpips_net": "alex"},
479
+ staging / "worker", "compare", timeout_s)
480
+ by_pair = {it["key"]: it for it in doc["items"]}
481
+ computed = [m for m in metrics if not (m == "lpips" and doc.get("lpips_error"))]
482
+ result = _score(plan, by_pair, ref, floors, engines, metrics, computed, margins, fidelity, budget_doc, spot,
483
+ resamples, seed, doc.get("lpips_error"), groups, not_timed)
484
+ rows = staging / "clip_metrics.jsonl"
485
+ rows.write_text("".join(json.dumps(it) + "\n" for it in doc["items"]))
486
+ artifacts = [ev.artifact(rows, staging, "clip_metrics")]
487
+ log = staging / "worker" / "compare.log"
488
+ if log.is_file() and log.stat().st_size:
489
+ artifacts.append(ev.artifact(log, staging, "worker_log"))
490
+ for leftover in (staging / "worker").glob("*.results.json"):
491
+ leftover.unlink()
492
+ return _save(call, store, staging, result, artifacts, doc, model, ref_req, run_dir)
493
+
494
+
495
+ def _side_items(plan_side: dict, by_pair: dict) -> dict[str, dict]:
496
+ return {k: by_pair[v["pair"]] for k, v in plan_side.items()
497
+ if k != "__extra__" and "pair" in v and v["pair"] in by_pair}
498
+
499
+
500
+ def _per_clip(items: dict[str, dict]) -> list[dict]:
501
+ """[{id, round, psnr_db, ssim, lpips}] per scored clip (its mean over frames), in key order."""
502
+ out = []
503
+ for k, it in sorted(items.items()):
504
+ r, cid = split_key(k)
505
+ mean = it.get("mean") or {}
506
+ out.append({"id": cid, "round": r, **{NAMES[m]: mean.get(m) for m in METRICS}})
507
+ return out
508
+
509
+
510
+ def _score(plan, by_pair, ref, floors, engines, metrics, computed, margins, fidelity, budget, spot, resamples, seed,
511
+ lpips_error, groups, not_timed) -> dict:
512
+ floor_side = "floor:alt" if "alt" in floors else "floor:repeat" if "repeat" in floors else None
513
+ floor_items = {s: _side_items(plan[s], by_pair) for s in plan if s.startswith("floor:")}
514
+ floor_info = {}
515
+ for s, items in floor_items.items():
516
+ ok = {k: it for k, it in items.items() if it.get("ok")}
517
+ floor_info[s.split(":", 1)[1]] = {
518
+ "n_clips": len(ok), "exact_clips": sum(1 for it in ok.values() if _exact(it)),
519
+ "missing": sorted(k for k, v in plan[s].items() if k != "__extra__" and v.get("missing")),
520
+ "request_mismatch": {k: v["request_diff"] for k, v in plan[s].items() if k != "__extra__"
521
+ and v.get("request_diff")},
522
+ "metrics": {m: summary_of(ok, groups, m, resamples, seed) for m in computed}}
523
+ out_engines = {}
524
+ for label in engines:
525
+ side = f"engine:{label}"
526
+ items = _side_items(plan[side], by_pair)
527
+ missing = sorted(k for k, v in plan[side].items() if k != "__extra__" and v.get("missing"))
528
+ mismatch = {k: v["request_diff"] for k, v in plan[side].items() if k != "__extra__" and v.get("request_diff")}
529
+ unchecked = sum(1 for k, v in plan[side].items() if k != "__extra__" and "pair" in v
530
+ and not v.get("request_checked"))
531
+ changed = {k: why for k, why in not_timed.get(side, {}).items() if k in items}
532
+ shape_bad = {k: (it.get("error") or f"{it.get('frames_b')} frames vs the reference's {it.get('frames_a')}")
533
+ for k, it in items.items() if k not in changed and (not it.get("ok")
534
+ or it.get("frame_count_differs"))}
535
+ good = {k: it for k, it in items.items() if k not in shape_bad and k not in changed}
536
+ checks, caps = {}, []
537
+ if changed:
538
+ k0 = next(iter(changed))
539
+ checks["outputs_index"] = {"verdict": "FAIL", "reason": f"{len(changed)} clip file(s) are not the clips "
540
+ f"bench clip timed (e.g. {k0}: {changed[k0]})"}
541
+ if shape_bad:
542
+ k0 = next(iter(shape_bad))
543
+ checks["shape"] = {"verdict": "FAIL", "reason": f"{len(shape_bad)} clip(s) differ from the reference in "
544
+ f"frame size or frame count (e.g. {k0}: {shape_bad[k0]})"}
545
+ if missing:
546
+ caps.append(f"{len(missing)} reference clip(s) have no engine clip (e.g. {missing[0]})")
547
+ if mismatch:
548
+ k0 = next(iter(mismatch))
549
+ caps.append(f"{len(mismatch)} clip(s) were made from a different request than the reference's (e.g. {k0}: "
550
+ f"{', '.join(mismatch[k0])}) and were not scored")
551
+ block = {"n_clips_scored": len(good), "n_requests_scored": len({groups.get(k, k) for k in good}),
552
+ "missing": missing, "request_mismatch": mismatch, "requests_unchecked": unchecked,
553
+ "shape_mismatch": shape_bad, "not_timed": changed, "extra_clips": plan[side].get("__extra__", []),
554
+ "metrics": {m: summary_of(good, groups, m, resamples, seed) for m in computed},
555
+ "exact_clips": sum(1 for it in good.values() if _exact(it)), "per_clip": _per_clip(good)}
556
+ if fidelity in ("lossless", "gross"):
557
+ if floor_side is None:
558
+ caps.append("no A/A floor (pass --reference-repeat and/or --reference-alt)")
559
+ for m in metrics:
560
+ checks[m] = {"verdict": "NOT RUN", "reason": "no A/A floor"}
561
+ else:
562
+ fl = floor_items[floor_side]
563
+ keys = [k for k in good if k in fl and fl[k].get("ok") and not fl[k].get("frame_count_differs")]
564
+ for m in metrics:
565
+ if m not in computed:
566
+ checks[m] = {"verdict": "NOT RUN", "reason": f"not computed ({lpips_error})"}
567
+ continue
568
+ checks[m] = lossless_check(good, fl, keys, groups, m, margins[m], resamples, seed)
569
+ exact_floor = keys and all(_exact(fl[k]) for k in keys)
570
+ exact_engine = keys and all(_exact(good[k]) for k in keys)
571
+ if fidelity == "gross" and not (exact_floor and not exact_engine):
572
+ for m, c in checks.items():
573
+ if m in METRICS and c["verdict"] == "UNPROVEN" and None not in (c.get("ci95") or [None]):
574
+ c["verdict"] = "PASS"
575
+ c["reason"] = f"gross gate, not entirely beyond the margin: {c['reason']}"
576
+ if exact_floor and not exact_engine: # whichever floor: exact cannot judge a drifting kernel
577
+ for m, c in checks.items():
578
+ if m in METRICS and c["verdict"] in ("PASS", "FAIL"):
579
+ c["verdict_before_exact_floor_rule"] = c["verdict"]
580
+ c["verdict"] = "UNPROVEN"
581
+ if floor_side == "floor:alt":
582
+ caps.append("the --reference-alt run is bit-identical to the reference (was the attention "
583
+ "backend switch applied?), so the A/A floor is exact and cannot separate an "
584
+ "exact-but-different kernel from a lossy one")
585
+ else:
586
+ caps.append("the A/A floor is exact (the reference repeats itself bit for bit), so it "
587
+ "cannot separate an exact-but-different kernel from a lossy one: pass "
588
+ "--reference-alt (the reference with another exact attention backend)")
589
+ block["floor"] = floor_side.split(":", 1)[1]
590
+ block["n_clips_judged"] = len(keys)
591
+ if len(keys) < len(good):
592
+ caps.append(f"{len(good) - len(keys)} scored clip(s) have no usable floor clip (missing, made "
593
+ "from another request, or a different frame count) and were not judged")
594
+ else:
595
+ for k, (m, sidek) in BUDGET.items():
596
+ if k in (budget or {}):
597
+ if m not in computed:
598
+ checks[f"budget.{k}"] = {"verdict": "NOT RUN", "reason": f"{m} not computed ({lpips_error})"}
599
+ else:
600
+ checks[f"budget.{k}"] = budget_check(good, groups, m, sidek, budget[k], resamples, seed)
601
+ if spot is None:
602
+ checks["spot_check"] = {"verdict": "UNPROVEN", "reason": "lossy: no human spot-check record "
603
+ "(--spot-check)"}
604
+ else:
605
+ checks["spot_check"] = {"verdict": "PASS" if spot["verdict"] == "acceptable" else "FAIL",
606
+ "reason": f"{spot['reviewer']} ({spot['date']}): {spot['verdict']}, "
607
+ f"{len(spot['clips'])} clip(s) watched"}
608
+ if floor_side is not None: # for the reader: how far the floor already is, no verdict
609
+ fl = floor_items[floor_side]
610
+ block["vs_floor"] = {m: summary_of({k: fl[k] for k in good if k in fl and fl[k].get("ok")}, groups,
611
+ m, resamples, seed) for m in computed}
612
+ verdict = stats.combine_claims("UNPROVEN" if c["verdict"] == "NOT RUN" else c["verdict"]
613
+ for c in checks.values())
614
+ if verdict in ("PASS", "NOT RUN") and caps:
615
+ verdict = "UNPROVEN"
616
+ block.update({"verdict": verdict, "checks": checks, "caps": caps,
617
+ "reason": "; ".join([f"{k}: {c['reason']}" for k, c in checks.items()] + caps)})
618
+ out_engines[label] = block
619
+ overall = stats.combine_claims(b["verdict"] for b in out_engines.values())
620
+ return {"verdict": overall, "fidelity": fidelity, "engines": out_engines, "floors": floor_info,
621
+ "floor_used": floor_side.split(":", 1)[1] if floor_side else None, "reference_clips": len(ref),
622
+ "reference_requests": len(set(groups.values())),
623
+ "margins": {m: margins[m] for m in metrics}, "budget": budget, "spot_check": spot, "metrics": metrics,
624
+ "computed": computed, "lpips_error": lpips_error}
625
+
626
+
627
+ def _uniform(reqs: dict[str, dict], key: str):
628
+ vals = {json.dumps(r.get(key), sort_keys=True) for r in reqs.values()}
629
+ return next(iter(reqs.values())).get(key) if reqs and len(vals) == 1 else None
630
+
631
+
632
+ def _save(call, store, staging, result, artifacts, doc, model, ref_req, run_dir) -> dict:
633
+ mets = []
634
+ for label, b in result["engines"].items(): # n = distinct requests, the bootstrap unit of the CI
635
+ for m, s in b["metrics"].items():
636
+ mets.append(ev.metric(NAMES[m], s["value"], UNITS[m], "mean_over_frames", n=s["n_requests"],
637
+ ci95=s["ci95"], subject=label))
638
+ for m, c in b["checks"].items():
639
+ if c.get("worse_than_floor") is not None:
640
+ mets.append(ev.metric(f"{NAMES[m]}_worse_than_floor", c["worse_than_floor"], UNITS[m],
641
+ "paired_delta", n=c["n_requests"], ci95=c["ci95"], subject=label))
642
+ for name, f in result["floors"].items():
643
+ for m, s in f["metrics"].items():
644
+ mets.append(ev.metric(NAMES[m], s["value"], UNITS[m], "mean_over_frames", n=s["n_requests"],
645
+ ci95=s["ci95"], subject=f"floor:{name}"))
646
+ lim = [f"{label}: {c}" for label, b in result["engines"].items() for c in b["caps"]]
647
+ if result["lpips_error"]:
648
+ lim.append(f"LPIPS not computed: {result['lpips_error'][:200]}")
649
+ if result["fidelity"] == "lossy":
650
+ lim.append("lossy track: report as 'N x at the stated quality cost'; never ranked against lossless results")
651
+ unchecked = sum(b["requests_unchecked"] for b in result["engines"].values())
652
+ if unchecked:
653
+ lim.append(f"{unchecked} clip pair(s) had no bench clip request body on one side: same prompt, seed and "
654
+ "steps were not checked for them")
655
+ workload = {k: _uniform(ref_req, k) for k in ("task", "width", "height", "num_frames", "fps", "steps",
656
+ "guidance_scale")} if ref_req else {}
657
+ labels = list(result["engines"])
658
+ summary = f"quality clip {result['verdict']} ({result['fidelity']}, floor {result['floor_used'] or 'none'}): " + \
659
+ ", ".join(f"{lab} {b['verdict']}" + (f" (PSNR {b['metrics']['psnr']['value']:.2f} dB)"
660
+ if b["metrics"].get("psnr", {}).get("value") is not None else "")
661
+ for lab, b in result["engines"].items())
662
+ kind, extra = _kind("clip_quality")
663
+ worker = {k: doc.get(k) for k in ("versions", "device", "ssim_backend", "frame_stride", "psnr_cap_db")}
664
+ data = {**extra, **result, "format": FORMAT, "worker": worker,
665
+ "definitions": {"psnr_db": "10 log10(255^2 / MSE) per frame over RGB24, capped at 100 dB; clip = mean "
666
+ "over frames",
667
+ "ssim": "luma (BT.601), 11x11 Gaussian sigma 1.5, K1 0.01, K2 0.03",
668
+ "lpips": "LPIPS v0.1, AlexNet backbone, RGB in [-1, 1]",
669
+ "worse_than_floor": "engine-vs-reference minus floor-vs-reference, oriented so positive "
670
+ "is worse; paired bootstrap 95% CI over requests",
671
+ "request": "the bootstrap unit: clips whose request bodies match on every REQUEST_KEYS "
672
+ "field (or, without bodies, every round of one clip id) count once; metric n "
673
+ "is the number of requests",
674
+ "per_clip": "each scored clip's mean over frames; id and round from its r<round>/<id> "
675
+ "key (round null for other layouts)"}}
676
+ if len(labels) == 1: # the review page and a re-run read the engine and its clips from here
677
+ data["label"] = labels[0]
678
+ data["per_clip"] = result["engines"][labels[0]]["per_clip"]
679
+ rec = ev.build(call, kind=kind, claim_class="observed", summary=summary,
680
+ identity_=ev.identity(engine={"name": labels[0] if len(labels) == 1 else None},
681
+ model={"id": model}, workload=workload),
682
+ metrics=mets, artifacts=artifacts, missing=[] if any(
683
+ b["n_clips_scored"] for b in result["engines"].values()) else ["no clip pair was scored"],
684
+ limitations=lim, data=data)
685
+ if run_dir: # the store also copies the record to <run-dir>/evidence/
686
+ out = Path(run_dir) / "quality"
687
+ out.mkdir(parents=True, exist_ok=True)
688
+ (out / "clip_score.json").write_text(json.dumps(result, indent=1) + "\n")
689
+ return store.save(rec, staging)
690
+