open-standards/wai/research/catalogue-prior.md
Transaction Science ba986de6d6
Some checks failed
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 12s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 46s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 3m25s
The repository checks run the frozen-rules runner as it first reached the history
The workflow step ran scripts/check-frozen-rules.sh from the checkout, so a
commit that added `exit 0` to it, together with a coordinated change to a rule,
its text and its verifier, passed that run and every later one, though the
history still showed the change.

The step now takes the runner as the first commit of the first-parent history
to add it held, and runs it as well as the checkout's copy; the job fails if
either does. A runner edited, emptied or removed, in the rule's commit or an
earlier one, hides nothing, and the check goes red on that commit and on the
ones after it. A branch made before the runner takes it from the pull request's
base, and a history that never held it fails.

What is left is the step itself, which is read from the commit under test: a
commit that edits it silences the check from then on, until that edit is undone,
and the diff in the history records it. The record's page and its changelog entry
now say this, and limit "does not hide" to the two scripts. They also say that a
merge is read from its first parent, so one that puts another line of commits
first changes the history the check reads.

scripts/check-frozen-rules-selftest.sh runs the step's own text, from its marker
in the workflow, in its scratch repository. It requires each of those cases, and
it records the first-parent reading: a merge with main as its second parent pins
its own line's rule, and only the comparison with a base shows it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-07 03:19:08 -05:00

27 KiB
Raw Permalink Blame History

What a linear catalogue prior costs, measured on a studio's open films

Status. A measured record and its procedure, informative. Every measured figure below is computed from the readings in catalogue-prior/, and tools/wai_catalogue_prior_verify.py, which shares no code with the scripts that took them, recomputes each from those readings and checks every figure this page quotes (each is followed by a cat marker naming the value it is checked against). The readings were taken on 4 November 2026 (UTC). No WAI capability is measured here: the record decides whether a catalogue basis should become one, and §5 says it should not.

1. The question, and what is measured

A catalogue prior is a prior learned from a catalogue of titles and held by each sink, so that a title carries only what the prior does not predict (SPEC §3.1, the shared ambient prior). WAI already carries such a prior: pinned by its SHA-256, served by digest, and refused by name when a sink does not hold it (SPEC §3.1, prior-carriage). The claim splits into three, each of which can be refuted on its own (run.json, rule):

  • H1a, a linear or spectral basis. A basis learned on the catalogue (a mean frame, or the principal components of its frames) captures a held-out title better than a generic transform, and in front of a codec it saves bytes (§3.3, §3.5).
  • H1b, exact recurrence. Frames recur across titles, byte for byte or within a tight bound, so a sink that holds them once never fetches them again (§3.4).
  • H1c, a learned prior. A neural codec's parameter set tuned on the catalogue saves bytes against its generic set on a held-out title. Nothing here measures it (§6).

A catalogue is a set of whole titles under one rights holder, each held out whole when it is tested (§3.1). This record uses openly licensed films of one studio: they share a production pipeline and a house style, but no characters or sets (§3.1). A negative result on such a catalogue refutes H1a and H1b for a studio's catalogue, not for a franchise, and says nothing of H1c (§6).

The prior's bytes are charged once per sink, not once per catalogue, because the sink reconstructs and so every sink that decodes must hold it (SPEC §3.1). The break-even is the prior's bytes divided by the mean saving per title, in titles watched per sink (run.json, rule.go).

2. The rule, and when it was fixed

The rule below was written at 2026-11-04T01:58Z, before any result of measurements (a) or (c) had been seen (run.json, timeline). That is attested, not proved: no copy of the rule was committed anywhere before the results existed. The record is consistent with it (run.json, timeline):

  1. The rate proxy's four target PSNRs were recorded with the basis script at 01:43:38Z.
  2. Moment accumulation finished at 01:49:04Z, and printed no figure.
  3. The residual-coding script was last changed at 01:58:51Z.
  4. The first result file, a_basis.json, was written at 02:00:43Z. The basis script's only later change, at 02:01:24Z, is a print format.

The rule (run.json, rule):

  • GO, worth a capability and a demonstration, needs both: a BD-rate of −10 % or less against per-title AV1 on both PSNR and VMAF, with the side information charged, on at least three of the four held-out titles; and a break-even of at most five titles per sink, with the prior's bytes counted.
  • K1 (H1a) holds when the catalogue basis's rate proxy is not at least 5 % below a generic DCT's at both 35 dB and 40 dB on the median title.
  • K2 (H1a) holds when the catalogue-basis residual and its coefficients cost more bytes than AV1 alone (a BD-rate above 0) on both metrics on the median title.
  • K3 (H1b) holds when non-flat material recurring across titles within a tight bound (a thumbnail PSNR of 40 dB or more and a full-size PSNR of 35 dB or more) is under 1 % of each title's runtime.
  • Anything between GO and a kill is inconclusive.

2.1 Faults in the rule, found after the run

Three faults were found after the results existed. None changes this run's verdicts, which rest on K2 and K3 (§5):

  1. No clause can kill H1c: K1 and K2 concern a linear basis, and K3 recurrence.
  2. GO and K1 can both hold: K1 judges an intra rate proxy with no prediction, and GO a real codec. Here K2 holds as well, so the kill does not rest on K1 alone (§5).
  3. The per-title AV1 bar was run through a non-standard 10-bit pipeline, base10, which is less efficient than plain 8-bit AV1 (§4.3). A −10 % GO against base10 is −3.1 % against plain AV1 (§4.3). Plain per-title AV1 is the stricter bar, and every residual arm is further from it (§4.3).

2.2 The rule for a learned prior and an episodic series

catalogue-prior/decisive-rule.json is the rule that judges a run on a learned prior tuned on a catalogue (H1c) or on an episodic series (H1b). It was committed before any run it judges: when it was, this record had measured H1c not at all, and H1b only across the films of one studio, not across the episodes of a series (§5, §6). Its SHA-256 is 8e265cfa2a3cb3de8c02a2c79a65bba59b52f2c134f4baf39d8bf163c0c38bc2. The verifier holds the same digest and checks the file against it and against the one quoted here. A later rule is a new file. The repository's checks read the history on every run, and go red while the file differs from what first reached main (§7). It keeps §2's rule, with these changes, the first three answering §2.1's faults and the rest new here:

  • K1 is diagnostic. It kills nothing, and when it holds, a result that would otherwise be GO is inconclusive (§2.1, fault 2). It reads only a rate proxy measured in the same run on the same titles, so a run that measures none has no K1.
  • The bar for a video claim is plain per-title AV1: 8-bit, at preset 4, coded as §3.5 codes base8 in all else. Preset 8 is reported beside it. base10 is a pipeline control only (§2.1, fault 3).
  • K4 (H1c) holds for an arm, and kills H1c for it, when its catalogue-tuned parameter set beats the same codec's generic set by less than 5 % BD-rate on PSNR on the median held-out title, before the set's bytes are charged (§2.1, fault 1).
  • Each clause names the arms it judges, and the comparator for each. GO judges wai.neural.int_hyper's catalogue-tuned set against AV1 all-intra, at preset 4, since it codes each picture alone; the catalogue-tuned set of any other arm with inter prediction whose P-frames are not integer block motion compensation, named in a run's record before its first reading, against plain per-title AV1; and an episodic series' openings, each coded once, against per-episode encodes, which gives H1b a GO that §2's rule did not. K4 judges each catalogue-tuned set against its generic set, wai.video.int_hyper's included. K1 and K2 are H1a's, and judge no arm of this rule. Every other figure is reported, and no clause reads it.
  • A kill wins. A verdict is for one arm and one claim: if K3 or K4 holds, that kill is the verdict, whether or not GO holds; otherwise GO with K1 is inconclusive, GO alone is GO, and anything else is inconclusive.
  • VMAF is also integrated by piecewise-cubic Hermite and by piecewise-linear interpolation, and GO reads the cubic figure. A title where either lacks the cubic figure's sign is inconclusive on VMAF.
  • GO's titles are at least three quarters of all the held-out titles, rounded up, or of the episodes for the openings. A title inconclusive on VMAF stays among them and does not count as meeting the bar.
  • Stop. An inconclusive result is recorded as no-go for now, and does not lead to another run of the same test.

The file also fixes the arms, the hold-out by title and by date, what is counted and reported, and the corpus a run must use.

3. Procedure

3.1 Corpus

Openly licensed films of one studio, each named in run.json by its file's size and SHA-256, with the SHA-256 of the licence page fetched for it (run.json, corpus):

code title (year) licence, as its page states it file SHA-256
ED Elephants Dream (2006) Creative Commons, version not stated on the page fetched 6fc295e0…f7558a547
BBB Big Buck Bunny (2008) Creative Commons Attribution 3.0 b0c9ade8…f88b33b67 (the archive)
SIN Sintel (2010) Creative Commons Attribution 3.0 fae11ed4…19c3d9920
TOS Tears of Steel (2012) Creative Commons Attribution 3.0 99486359…e185987a15

Another short film of the same studio was left out because no licence statement could be fetched for it (§6). The films' frames are not in this repository; only figures derived from them are (§3.2).

3.2 Analysis raster

Each title was decoded to luma at 640×360 by area scaling, kept as decoded: 8-bit, limited range (run.json, analysis_raster). The two wide films were stretched to 16:9, since no title has letterbox bars (§6). From that raster: 128×72 by a 5×5 area mean, in float, and 64×36 by a 10×10 area mean, rounded to 8 bits (run.json, analysis_raster).

3.3 Measurement (a): does a catalogue basis capture a held-out title better than a generic transform?

  • Split. Each title is cut in time into a first half A and a second half B; the test set is half B of the held-out title (a_basis.json).
  • Bases. The catalogue basis is the principal components (the Karhunen–Loève transform) of the other titles, leave one title out; the per-title basis is that of half A of the held-out title; the generic basis is an orthonormal 2-D DCT-II whose coefficients are ordered by the catalogue's training statistics (a_basis.json). Each vector has its own mean removed first, and the principal-component bases also remove their training mean, the catalogue's "central mean" (a_basis.json).
  • Granularities. Whole frames at 128×72; 8×8 and 16×16 blocks at 640×360, every second frame; and 8×8 blocks of the difference of consecutive frames, an un-compensated stand-in for inter-frame residuals (a_basis.json).
  • Rate proxy. The Gaussian reverse water-filling rate of the test coefficients' second moments, at the mean squared error of a target PSNR: the classical yardstick for ranking transforms, as an ideal intra coder with no prediction (a_basis.json). It ranks transforms; its bits per pixel are not a codec's (§6). Every score comes from first and second moments over every test vector, so nothing is sampled (a_basis.json).

3.4 Measurement (b): what recurs across titles?

  • Thumbnails. 64×36, 8-bit. A frame is flat when its thumbnail's standard deviation is under 2 code values, as black frames and fades to one tone are (b_recur.json).
  • Recurrence. Identical thumbnail bytes in another title (exact), or the nearest non-flat frame of another title at a thumbnail PSNR of 35 dB or 40 dB, then measured again on the two frames at 640×360 (b_recur.json). The nearest frame of the same title at least 10 s away is measured the same way: a key frame every 10 s puts it out of the encoder's reach in this run (d_exact.json).
  • Bytes. Each whole title was encoded once with SVT-AV1, preset 8, CRF 36, a key frame every 240 frames and tune=1, at 640×360 luma, and each temporal unit's bytes were charged to the frame it shows (d_exact.json). The attribution is approximate, since hidden reference data rides in the unit that carries it (§6).

3.5 Measurement (c): bytes at matched quality, residual coding against per-title AV1

  • The clip. For each title, 1,440 frames (60 s) starting at 60 % of the title, inside half B, so neither basis saw it (c_rd.json).
  • The arms (c_rd.json):
    • base8: AV1, 8-bit, on the clip.
    • base10: AV1, 10-bit, on 2x + 256, the residual arms' own pipeline and scale.
    • catK: AV1, 10-bit, on 2(x − x̂) + 512, where x̂ is the bilinear ×5 upsampling of the frame's DC, the catalogue mean and K catalogue components at 128×72. cat0 is the mean alone; cat64 and cat256 add 64 and 256 components. The coefficients are quantised with a step of 2 (the DC with a step of 0.25) and charged at the larger of two estimates of their bytes: their per-index empirical entropy over frame-to-frame differences, and a signed Exp-Golomb code. The reconstruction is round(x̂ + (y − 512)/2).
    • self64: as cat64, with the per-title basis of half A.
  • Coding. SVT-AV1 v4.2.0 through FFmpeg, preset 8, CRF 20, 28, 36, 44 and 52, a key frame every 240 frames, tune=1; decoded by dav1d; bytes are the sum of the IVF frame payloads (c_rd.json).
  • Quality. Luma PSNR over the clip's pooled squared error, and VMAF (libvmaf, model vmaf_v0.6.1, mean pooling) on the same luma (c_rd.json). VMAF is not reproducible to the bit across builds, so it is a second check, and every verdict below holds on PSNR alone (§5).
  • BD-rate. The Bjøntegaard delta rate: the natural log of bytes fitted as a least-squares cubic in quality for each arm, both fits integrated over the quality range the two arms share, and the mean difference turned into a percentage (c_rd.json, bd_vs_base10). A positive figure is the extra bytes an arm spends for the same quality. The verifier recomputes every figure the run stored, and also integrates a piecewise-linear interpolant of the same points (§4.3).

3.6 Host and tools

A shared Linux x86_64 build host, each step in a user scope with a 64 GB memory cap, a low CPU weight and nice 10 (run.json, host). FFmpeg 9.0.2 with SVT-AV1 4.2.0, dav1d 1.5.4 and libvmaf 3.2.1; Python 3.14.4 with NumPy 2.3.5 (run.json, tools). The measurement scripts are not part of this record; §3.3–§3.5 state what they did.

4. Results

4.1 Measurement (a)

The rate proxy of the catalogue basis against the DCT's, the median over the titles; a negative figure is fewer bits (a_basis.json, §3.3):

granularity at 35 dB at 40 dB
whole frames, 128×72 +18.1 % +10.4 %
8×8 blocks −0.6 % −0.3 %
16×16 blocks +0.2 % +0.1 %
8×8 frame differences −0.9 % −0.6 %
  • Over whole frames, a basis learned on the title's own first half is further from the DCT still, by +38.7 % to +55.7 % at 35 dB: a film's frame statistics are not stationary from its first half to its second (a_basis.json).
  • The share of a held-out title's detail energy that the catalogue mean alone captures is −3.05 % on ED, so that subtracting it adds energy there, and 1.72 % to 2.87 % on the other titles (a_basis.json).
  • Counting each frame's DC, the mean alone captures 78.4 % to 92.5 % of a title's energy, and sixteen components capture 89.8 % to 96.5 %, as sixteen DCT components do, within 0.3 of a point on every title (a_basis.json). A test of the form "a given share of spectral mass in a given number of components" is met by any of these transforms, and so does not discriminate.
  • Over 8×8 and 16×16 blocks the catalogue basis and the DCT are within 1.2 % of each other on every title (a_basis.json), as the DCT's closeness to the Karhunen–Loève transform for natural images predicts (Ahmed, Natarajan and Rao, IEEE Trans. Computers C-23(1), 1974).

4.2 Measurement (b)

Shares of each title's runtime and of its AV1 bytes at CRF 36 (d_exact.json, b_recur.json, §3.4):

title flat frames: runtime / bytes non-flat, exact in another title another title's frame at 35 dB, both sizes: runtime / bytes its own frame 10 s or more away at 35 dB: runtime / bytes
ED 1.45 % / 0.211 % 0 0.083 % / 0.002 % 0.070 % / 0.002 %
BBB 0.66 % / 0.649 % 0 0.035 % / 0.001 % 0.049 % / 0.002 %
SIN 2.26 % / 0.173 % 0 0.169 % / 0.010 % 1.253 % / 0.984 %
TOS 1.53 % / 0.278 % 0 0 % / 0 % 0 % / 0 %
  • No non-flat frame of one title matches another title's at 40 dB at full size (b_recur.json, cross_ge35.full_psnr_ge40).
  • The frames that match another title's at 35 dB are dark, nearly flat end-credit frames, their thumbnails spreading a median of 2.6 to 3.0 code values against 30 to 37 for the titles' ordinary non-flat frames (d_exact.json, thumb_std_median).
  • The one recurrence of size is inside one title: SIN shows earlier shots again minutes later, 0.98 % of its bytes (d_exact.json, self_far35). It needs no catalogue.

4.3 Measurement (c)

The BD-rate of each arm against AV1 through the same 10-bit pipeline (base10), the median over the titles, PSNR / VMAF; GO needs −10 % or less on both (c_rd.json, §3.5):

arm median BD-rate, PSNR / VMAF AV1's bytes only, PSNR / VMAF against plain 8-bit AV1 (base8), PSNR
cat0, the mean alone +2.1 % / +2.4 % +2.1 % / +2.4 % +10.4 %
cat64 +38.8 % / +39.9 % +31.8 % / +29.6 % +46.6 %
cat256 +77.7 % / +80.5 % +50.4 % / +48.5 % +80.3 %
self64, the title's own basis +52.1 % / +52.0 % +44.9 % / +43.1 % +60.9 %
  • The coefficients are not the main cost. With their bytes left out, AV1 still spends more on the residual than on the picture: the middle column (c_rd.json, av1_bytes). The coefficients are 1.5 % to 15.2 % of cat64's bytes across the ladder (c_rd.json, side_bytes).
  • The basis's own bytes, at 16 bits per value, are 18,432 B for the mean alone, 1,198,080 B for 64 components and 4,737,024 B for 256 (§3.5). Plain AV1 spends 0.9 MB to 11.6 MB on one 60 s clip across the ladder (c_rd.json, base8). No arm saves bytes on PSNR on any title against either bar, so no number of titles watched recovers the basis's bytes, and there is no break-even (c_rd.json; the verifier's no_psnr_saving_any_title).
  • The reconstruction from the basis alone reaches 14.1 dB to 22.0 dB for the mean and for 64 components (c_rd.json, basis_only_psnr). The share of residual samples clipped was 0 in every arm (c_rd.json, clipped_frac).
  • The pipeline. base10 against base8 costs a median of +7.7 % on PSNR and +1.5 % on VMAF (c_rd.json): the ×2 scaling into 10 bits is not the usual ×4, and it is less efficient than plain 8-bit AV1.
  • The interpolation. Integrated piecewise-linearly instead, no PSNR figure above moves by more than 0.48 of a point (the verifier's bd_linear). VMAF near saturation is not stable under the cubic fit: on TOS, cat0 against base8 gives −5.0 % by the cubic and +10.2 % by the linear interpolant, and base10 against base8 −8.3 % and +6.6 % (the verifier's bd, bd_linear). That VMAF "saving" is an artefact of the fit, and no verdict rests on VMAF (§5).

5. Verdict against the rule

The verifier applies the rule run.json records to the figures above and requires the verdicts it states (run.json, verdicts):

claim result rule
H1a, a linear or spectral catalogue basis the rate proxy is +10.4 % to +18.1 % from the DCT's over whole frames, and its medians are within 0.9 % of it over blocks and block differences (§4.1); in front of AV1, +38.8 % on PSNR at 64 components (§4.3) K1 and K2 hold: refuted for a studio's catalogue
H1b, exact recurrence across titles non-flat recurrence across titles is at most 0.169 % of a title's runtime and 0.010 % of its bytes, even at the looser bound of 35 dB at both sizes (§4.2) K3 holds: refuted for a studio's catalogue; untested for an episodic series
H1c, a learned prior tuned on the catalogue not measured open

GO is missed by 48.8 points at 64 components (§4.3).

Why a linear basis fails here, on the mechanism the figures show:

  1. A predictive codec already holds a better prior, the frames it has just decoded, which it refreshes every frame and never sends. The basis alone reaches only the coarse structure that prediction already gets (§4.3).
  2. Subtracting a reconstruction that changes with its coefficients, not with the motion, makes the residual less predictable in time than the picture. That is the extra cost before any coefficient is charged (§4.3, AV1's bytes only).
  3. A film's statistics change from its first half to its second, so a basis fitted to some titles fits others no better than a fixed transform, and more titles make it more generic (§4.1).

The mechanism is general, so the result probably extends to a franchise. That is an inference: it was measured on films of one studio only (§6).

6. What this does not show

  • The corpus. Films of one studio, not a franchise: they share no characters or sets (§3.1). TOS is live action with computer graphics. ED's source is 720×405, softer than the others' (run.json, corpus). Another short film was left out for want of a fetched licence statement (§3.1).
  • The signal. Luma only, at 640×360, with the two wide films stretched to 16:9; no chroma and no 1080p (§3.2).
  • The codec side. One encoder at one preset with tune=1, one 60 s clip per title, and a ×2 10-bit pipeline for the residual arms, compared with the same pipeline (§3.5, §4.3).
  • The simplifications. Linear bases only. The rate proxy is a Gaussian high-rate rate with no prediction (§3.3). The coefficients' bytes are estimates, the larger of two, and a better coefficient coder cannot rescue cat64, whose AV1 bytes alone cost more (§4.3). Recurrence is matched pixel-aligned only, so an element drawn at another size or place would be missed (§3.4). The byte attribution to frames in measurement (b) is approximate (§3.4).
  • Not measured. H1c, a learned prior; an episodic series, whose opening could recur across episodes; energy; decode cost (§1).
  • The rule was attested, not committed, before the results (§2).

7. Verify

python3 -I tools/wai_catalogue_prior_verify.py research/catalogue-prior research/catalogue-prior.md

It checks each reading against the SHA-256 in run.json, recomputes every stored BD-rate, the rate proxy, the recurrence and the verdicts, and every quoted figure, and checks decisive-rule.json against the SHA-256 it holds and the one §2.2 quotes (the module's docstring). The conformance workflow runs it (.github/workflows/wai-conformance.yml), after its --self-test, which requires each mutated copy of the rule and its pins to fail. The repository checks run scripts/check-frozen-rules.sh on every change and every push to main, as it first reached main and as it stands, and it runs scripts/check-frozen-rules.py the same way, so a change to either script does not hide a change to a rule. It reads the first-parent history from the start, so what it finds does not depend on any one run: a rule file changed, removed or renamed after it first reached main turns those checks red on every later run, until the file is as it first was. A commit to main is not stopped by that; the red check and the history record it. The workflow step that runs it is read from the commit under test: a commit that edits that step silences the check from then on, until that edit is undone, and the diff in the history records it. A merge is read from its first parent, so one that puts another line of commits first changes the history the check reads.