wai.avatar.face: a talking head generated the same bytes on every sink from a signed keypoint track and an identity prior (AVTR) #448

Closed
dcharlot wants to merge 0 commits from wai/avatar-telepresence into main
Owner

AVTR: a talking head reconstructed bit-exactly from a signed keypoint track and an identity prior, so that a receipt proves the face the viewer saw. Registers wai.avatar.face in avatars §6 to §13.

What is in it

  • The capability (GenerativeDeterministic, ops face-int/1 at acc64, a parameter set of one file):

    • WFG1, the generator, pinned by SHA-256 (§7.2);
    • WFI1, the identity prior: a reference picture and its keypoints, named by SHA-256 (§7.3);
    • WFK1, a keypoint segment: the first frame in full, the rest as Exp-Golomb deltas in multiples of a stated step of 1/16 px (§7.4). It is the payload of a WAI1 envelope whose pin names the generator; the payload names the prior.
  • The integer generator (§7.1, §7.5, §7.6). The driver warps the reference picture to the driving keypoints and draws a map of each keypoint, all in integers. The weights come from integer-operators §2's exp_neg_q16; the displacement is rounded half away from zero; the sample is bilinear in 1/16 px. Then ten 3 × 3 convolutions (a small encoder and decoder) are lowered to one WHG1 graph of wai-ops/1-i32 operators:

    • weights at 2^12 (i16), biases at 2^27 (i32), Q15 activations, one half_up rounding per operator;
    • a mask from a lut16 logistic table whose every entry is an integer computation from exp_neg_q16;
    • the frame is the warped picture blended with the generated one.
  • Fabrics (§7.8). The same frames, byte for byte:

    • on the CPU (the wai-ops interpreter);
    • under wasm32-wasip2 (the corpus regenerated by its own generator, built for wasm32, under wasmtime);
    • on Metal, with every graph on the device at acc64 and compared with the interpreter;
    • in the second implementation, in Python's integers.
  • Records (§8). The participant's key signs:

    • an identity record (wai-face-identity) over the prior's digest;
    • a track record (wai-face-track) for each segment, chained by seq/prev, optionally stating each frame's SHA-256.

    A track signed by another key (driver_key_mismatch), or a segment that names another prior (identity_mismatch), is refused. That signature is provenance (who drove which face), not a permission rule. A lawful basis, where one is recorded, is jwp-receipts §2.4.6's claim.

  • Synthesis (§8.4, §8.5):

    • every segment carries a synthesized / generate origin claim naming the generator and the track record;
    • the envelope generates, so any other step is class_understated;
    • a player's present entry names the frames' digest at generation-equivalence, and is held to that digest (present_output_irreproducible);
    • a label policy is held to synthesis §10 (label_not_shown).
  • Verification (§9), with a generation policy (accept-unrecomputed or require-proof). The reasons are listed in §10.

  • Mappings (§11):

    • ISO/IEC 23090-39 (DIS, not openly readable, so not read): mapped through what 3GPP TR 26.813 V20.0.0 §6.3.4 and draft-ietf-avtcore-rtp-avatar-02 §4 publish, with each paywalled detail marked;
    • draft-ietf-avtcore-rtp-avatar-02 (landmark AAU, UT 4, D, L, AvID/avatar-ids, frameworks, aggregation);
    • 3GPP TR 26.813 V20.0.0 (§6.5 two-dimensional avatars, §8.2.1, §8.3.4.2's Avatar Representation Assertion, §9.2.2, §9A metrics, §10.2).
  • wai-rs: module avatar_face (feature avatar_face), bin wai_avatar_face_vectors gen|verify, tests/avatar_face.rs, and tests/avatar_face_gpu.rs (with ops_gpu). Registry entries: codecs/mod.rs, registry.rs, the glossary exemption, and the export regenerated.

  • Corpus wai/live-conformance/avatar-face/:

    • inputs pinned by SHA-256: the trained generator, two held-out faces and their tracks, and the training report;
    • a seeded generator and identity;
    • vectors.json with the mask's table, 28 forms, 9 frames and 24 cases. Accepted cases: one face's two segments, proved and presented with labels; the same not recomputed; two faces under two keys; a track record that states no frames. Refused cases: every code of §10, plus synthesis's class_understated, present_output_irreproducible and label_not_shown.
  • Second implementation wai/live-conformance/avatar_face_verify.py, written from the extension text and standard library only. It shares no code with wai-rs. It runs the driver and the generator's arithmetic in Python's integers, verifies records, signatures and BLAKE3, delegates claims, logs and labels to synthesis_verify.py, and mutates the corpus 17 ways.

  • Tool wai/tools/wai_avatar_face_train.py: a seeded face renderer, training in floating point and then with the integer arithmetic emulated, export by round-half-even of the float32 bits, the measurement of §7.9, and the corpus inputs.

  • CI:

    • wai-conformance.yml: a step of independent-verifiers (unit, corpus and Python), a new job avatar-face-wasip2, and new paths;
    • wai-ops-gpu.yml: a build in checks and a run in metal, plus new paths.
  • SPEC §3.1 (the payload names the prior; the pin names the generator), §5 (registration, one-file parameter set), §7 (class). Also determinism-tiers §5 and §6 rows, the live-conformance index, and CHANGELOG.

Decisions, and why

  • The generator is trained here, after a licence survey (§7.9). The survey covered code and weight licences, read before downloading anything; no weights were downloaded. Two families publish weights under a permissive licence:

    • an implicit-3D-keypoint feature-volume generator (MIT for its base networks; its bundled face-detection models are non-commercial);
    • a 3D-latent-volume generator (Apache-2.0).

    Both need operators wai-ops/1 does not define on the receiving side: 3D convolution, sampling at data-dependent positions, and spatial normalisation. They also run hundreds of GFLOPs per frame, which no second implementation could recompute in CI. Quantising either means extending integer-operators first, which is a slice of its own. The other families are excluded by their weights' terms: no licence stated for the weights (the first-order and thin-plate keypoint generators; an audio-driven toolkit's renderer), CC BY-NC 4.0 (three), or no licence granted (one). The lead receives the names in the builder's report.

  • Training data generated here, under Apache-2.0. The talking-face video sets that were considered fall into three groups:

    • sets under share-alike or non-commercial terms;
    • sets that are lists of videos hosted elsewhere under their uploaders' rights;
    • one audio-visual sentence corpus under CC BY 4.0, whose attribution names its authors and whose faces are real people's.

    None of these could be committed or credited under the public-text rules. So the tool draws its faces from seeded parameters, as tools/wai_int_sr_train.py draws its pictures, and places the 16 keypoints exactly. The quality figures are therefore for a generated face set at 64 × 64, and §7.9 says so.

  • The warp is the extension's own integer step, not a graph operator. wai-ops/1 has no sampling at data-dependent positions. The warp is defined in §7.5 from exp_neg_q16 and rdiv, runs in the driver like a stage operator on every fabric, and only the network is a graph. The GPU leg therefore covers the network, which is where the compute is.

  • acc64. A Q15 activation times a 2^12 weight over up to 9 · 96 terms passes i32. Every operator is in wai-ops/1-i32, so the GPU runs the graph at acc64 with 32-bit words. The registered generator does not meet acc32, and a test pins that.

  • The mask table clamps exp_neg_q16(0) = 65553 to 2^16, so the table is symmetric with T(0) = 16384. Without the clamp it dips at 0 (16382 against 16385 at −1). This was caught by the unit test.

  • One origin claim per segment object. synthesis's present entries name object claims, and the segment's envelope is what generates (synthesis §3.3). The claim covers every frame of the segment's decode, whose canonical buffer is its frames. A track record can also state each frame's SHA-256, so the sender commits to the exact frames. A frame shown on its own is claimed by its samples (§8.4).

  • No consent rule. The signature records who drove which face; §6 points a lawful basis to jwp-receipts §2.4.6.

  • 64 × 64 and widths 24/48/64. This keeps the Python second implementation at about 2 minutes for the whole corpus with its mutations. No speed claim is made. The architecture is fully convolutional; a larger generator is a new file and a new digest.

  • Names. The corpus faces are face1 and face2. No company, product or person names appear in public text, and standards are cited by identifier only. Framework URNs in the RTP draft that carry names are not reproduced.

Measured (§7.9, training.json)

12 held-out faces × 100 frames at 25 fps:

compared PSNR mean (dB) PSNR min (dB) SSIM mean SSIM min
integer, float 48.54 39.42 0.9988 0.9953
integer, rendered 28.24 21.27 0.9238 0.8558
float, rendered 28.22 21.11 0.923 0.8546
warp alone, rendered 22.89 13.99 0.7635 0.3499

Keypoint RMS error from a separately trained float detector:

pictures read all 16 (px) mouth's four (px)
the rendered faces (the detector's own error) 0.111 0.092
the float network's frames 0.569 0.547
the integer generator's frames 0.575 0.542

Keypoint track bitrate, by §7.4's coding in 1-second segments, payload bytes only:

keypoints step 4 (1/4 px) step 1 (1/16 px)
rendered 2.942 kbit/s 4.386 kbit/s
detected 2.96 kbit/s 4.413 kbit/s

Checks

Run on the build host through rb unless marked local.

check command result
unit tests cargo test --locked --no-default-features --features avatar_face --lib avatar_face:: 5 passed (graph = §7.6 loop by loop; warp at rest; mask table; files round-trip and refuse in order; padding)
corpus, §10 tables, §7.9 figures, acc64-not-acc32 cargo test --locked --release --no-default-features --features avatar_face --test avatar_face 6 passed
corpus bin wai_avatar_face_vectors verify ../live-conformance/avatar-face (release) 3 PASS: inputs pinned; every file regenerates byte for byte; every form, frame and case
second implementation python3 -I live-conformance/avatar_face_verify.py live-conformance/avatar-face (Python 3.15) the mask table, 28 forms, 9 frames and 24 cases as stated; every reason of both §10 tables seen; 17/17 mutated copies refused; about 2 min
GPU (Metal, build host) WAI_OPS_GPU_REQUIRE=1 cargo test --locked --release --no-default-features --features avatar_face,ops_gpu --test avatar_face_gpu -- --nocapture face-gpu: key=gpu-metal-0 frames=9 same=true graphs_on_gpu=9 (acc32 0, acc64 9) on_cpu=0 compared=9 differed=0 errors=[]
wasm32 cargo build --release --target wasm32-wasip2 --no-default-features --features avatar_face --bin wai_avatar_face_vectors --config 'profile.release.package.wai.codegen-units=1', then wasmtime run --dir …::/corpus wai_avatar_face_vectors.wasm verify /corpus (wasmtime 49.0.3) 3 PASS, exit 0: every frame regenerated on wasm32 equals the committed native bytes
registry cargo run --no-default-features --bin wai -- registry export then --check up to date (REGISTRY.md, capabilities.json, vocab regenerated)
registry and container library tests cargo test --locked --no-default-features --lib -- codecs:: container::; cargo test --locked --lib -- codecs:: 103 passed; 64 passed
whole library, default cargo test --locked --lib 193 passed
every integration test cargo test --locked --no-default-features --tests; cargo test --locked --tests every binary passes, none failed
clippy cargo clippy --locked --no-default-features --features avatar_face,ops_gpu --all-targets; cargo clippy --locked --all-targets no note in any file this change adds or touches. Notes in files it does not touch: glossary_check.rs's collapsible_if, and notes in claim_receipt.rs and container.rs under the avatar_face,ops_gpu combination after the merge of main
dependents cargo check --locked --target wasm32-unknown-unknown (wai-web); cargo check --locked (wai-pack) build
lockfiles no dependency added; every cargo run above used --locked; scripts/check-lockfiles.sh wai's locks unchanged; the script reports one stale lock this change does not touch, joule-code/joule-code-rs/crates/joule-moq-room (left as found)
repo checks (local) check-tests-in-ci.py, check-workflow-concurrency.sh, check-spec-refs.py, check-wai-section-refs.py, check-no-vanity-metrics.sh, test-public-text-checks.sh, check-comparative-prose.sh, check-orphan-sources.py all exit 0
workflows (local) python3 ~/kani-logs/wfsteps.py HEAD origin/main; ruby -ryaml over every workflow only this change's own new steps reported, plus checks' build step it extends; every file parses
public names (local) scripts/check-public-names.sh on each of the 28 changed text files; commit messages and this body against the same patterns clean
merge origin/main (with #428) merged into the branch at 9804962c; every check above re-run after the merge —

Falsifications

All were run after committing, one rule broken at a time, then restored.

Rust, each failing with exit 101:

  • a shift of the lowering's convolutions changed (12 → 11), with the loop-by-loop arithmetic kept: the_graph_is_the_arithmetic_of_section_7_6 fails, and the_committed_corpus_regenerates_from_its_seeds panics in the generator;
  • the mask table without §7.6's clamp: the_sigmoid_table_is_symmetric_and_bounded fails;
  • the driver-key check dropped from verify: every_vector_gets_what_it_states fails;
  • an extra code in §10's first table: the_extension_lists_the_reasons fails (the Python verifier exits 1 too: no case refused with it);
  • one figure of §7.9 changed (48.54 → 48.55): the_measurement_is_the_reports fails;
  • a digit of a committed frame digest: every_vector_gets_what_it_states fails, and the wasm32 verify exits 1.

Python verifier, each exiting 1:

  • the frame_mismatch check dropped;
  • the convolution's rounding floored, not half up;
  • the chain check dropped;
  • the exponential's constant 88670 off by one.

Caught by this round: the mask table without its clamp first passed the Python verifier (exit 0). A frame rarely reads the table at 0, so the frames alone did not pin it. The corpus now states the table's SHA-256 and nine entries (commit 950ae477), and the same falsification now exits 1 ("the mask's table differs").

The Python verifier also refuses 17 mutated copies of the corpus on every run:

  • a weight of each generator, its pin updated;
  • the prior's and the identity's samples and keypoints;
  • a keypoint of a frame;
  • a stated frame sample;
  • a segment's padding;
  • the stated status and output of a track;
  • a withheld generator;
  • a track record signed over another's face;
  • swapped track records;
  • a withheld label policy;
  • a misplaced refusal;
  • a table entry.

Not done

  • A permissively licensed public generator quantised to the profile. It needs new wai-ops/1 operators (3D convolution, data-dependent sampling, spatial normalisation) first.
  • Captured faces. The measurement covers a generated set at 64 × 64. Nothing is claimed for captured faces or another size.
  • An identity prior in latent form. Only the reference-picture form is registered.
  • A watermark in the frames (synthesis §7). None is applied.
  • Fabrics. wasm32 and Metal were run on the build host (macOS arm64). No Vulkan, DX12, browser WebGPU or NPU run for this capability, and no x86_64 CPU run by hand. CI's avatar-face-wasip2 (Linux x86_64) and metal steps will add the first forge runs.
  • The detector at the sender (how keypoints are found in a camera's picture) is out of scope. The tool's detector serves only the measurement.
  • Nothing was filed or posted. The mappings are text in the extension, and no URN or message type is registered elsewhere.

🤖 Generated with Claude Code


Closed: Landed on main through merge train E (#499, merge bf39ec9a); verified by content: this PR's head is in main

AVTR: a talking head reconstructed bit-exactly from a signed keypoint track and an identity prior, so that a receipt proves the face the viewer saw. Registers `wai.avatar.face` in [avatars](wai/extensions/avatars.md) §6 to §13. ## What is in it - **The capability** (`GenerativeDeterministic`, `ops` `face-int/1` at `acc64`, a parameter set of one file): - `WFG1`, the generator, pinned by SHA-256 (§7.2); - `WFI1`, the identity prior: a reference picture and its keypoints, named by SHA-256 (§7.3); - `WFK1`, a keypoint segment: the first frame in full, the rest as Exp-Golomb deltas in multiples of a stated step of 1/16 px (§7.4). It is the payload of a `WAI1` envelope whose pin names the generator; the payload names the prior. - **The integer generator** (§7.1, §7.5, §7.6). The driver warps the reference picture to the driving keypoints and draws a map of each keypoint, all in integers. The weights come from integer-operators §2's `exp_neg_q16`; the displacement is rounded half away from zero; the sample is bilinear in 1/16 px. Then ten 3 × 3 convolutions (a small encoder and decoder) are lowered to one `WHG1` graph of `wai-ops/1-i32` operators: - weights at 2^12 (i16), biases at 2^27 (i32), Q15 activations, one `half_up` rounding per operator; - a mask from a `lut16` logistic table whose every entry is an integer computation from `exp_neg_q16`; - the frame is the warped picture blended with the generated one. - **Fabrics** (§7.8). The same frames, byte for byte: - on the CPU (the `wai-ops` interpreter); - under `wasm32-wasip2` (the corpus regenerated by its own generator, built for wasm32, under wasmtime); - on Metal, with every graph on the device at `acc64` and compared with the interpreter; - in the second implementation, in Python's integers. - **Records** (§8). The participant's key signs: - an identity record (`wai-face-identity`) over the prior's digest; - a track record (`wai-face-track`) for each segment, chained by `seq`/`prev`, optionally stating each frame's SHA-256. A track signed by another key (`driver_key_mismatch`), or a segment that names another prior (`identity_mismatch`), is refused. That signature is provenance (who drove which face), not a permission rule. A lawful basis, where one is recorded, is jwp-receipts §2.4.6's claim. - **Synthesis** (§8.4, §8.5): - every segment carries a `synthesized` / `generate` origin claim naming the generator and the track record; - the envelope generates, so any other step is `class_understated`; - a player's `present` entry names the frames' digest at `generation-equivalence`, and is held to that digest (`present_output_irreproducible`); - a label policy is held to synthesis §10 (`label_not_shown`). - **Verification** (§9), with a `generation` policy (`accept-unrecomputed` or `require-proof`). The reasons are listed in §10. - **Mappings** (§11): - ISO/IEC 23090-39 (DIS, not openly readable, so not read): mapped through what 3GPP TR 26.813 V20.0.0 §6.3.4 and draft-ietf-avtcore-rtp-avatar-02 §4 publish, with each paywalled detail marked; - draft-ietf-avtcore-rtp-avatar-02 (landmark AAU, `UT` 4, `D`, `L`, `AvID`/`avatar-ids`, `frameworks`, aggregation); - 3GPP TR 26.813 V20.0.0 (§6.5 two-dimensional avatars, §8.2.1, §8.3.4.2's Avatar Representation Assertion, §9.2.2, §9A metrics, §10.2). - **wai-rs**: module `avatar_face` (feature `avatar_face`), bin `wai_avatar_face_vectors gen|verify`, `tests/avatar_face.rs`, and `tests/avatar_face_gpu.rs` (with `ops_gpu`). Registry entries: `codecs/mod.rs`, `registry.rs`, the glossary exemption, and the export regenerated. - **Corpus** `wai/live-conformance/avatar-face/`: - inputs pinned by SHA-256: the trained generator, two held-out faces and their tracks, and the training report; - a seeded generator and identity; - `vectors.json` with the mask's table, 28 forms, 9 frames and 24 cases. Accepted cases: one face's two segments, proved and presented with labels; the same not recomputed; two faces under two keys; a track record that states no frames. Refused cases: every code of §10, plus synthesis's `class_understated`, `present_output_irreproducible` and `label_not_shown`. - **Second implementation** `wai/live-conformance/avatar_face_verify.py`, written from the extension text and standard library only. It shares no code with wai-rs. It runs the driver and the generator's arithmetic in Python's integers, verifies records, signatures and BLAKE3, delegates claims, logs and labels to `synthesis_verify.py`, and mutates the corpus 17 ways. - **Tool** `wai/tools/wai_avatar_face_train.py`: a seeded face renderer, training in floating point and then with the integer arithmetic emulated, export by round-half-even of the float32 bits, the measurement of §7.9, and the corpus inputs. - **CI**: - `wai-conformance.yml`: a step of `independent-verifiers` (unit, corpus and Python), a new job `avatar-face-wasip2`, and new paths; - `wai-ops-gpu.yml`: a build in `checks` and a run in `metal`, plus new paths. - SPEC §3.1 (the payload names the prior; the pin names the generator), §5 (registration, one-file parameter set), §7 (class). Also determinism-tiers §5 and §6 rows, the live-conformance index, and CHANGELOG. ## Decisions, and why - **The generator is trained here, after a licence survey** (§7.9). The survey covered code and weight licences, read before downloading anything; no weights were downloaded. Two families publish weights under a permissive licence: - an implicit-3D-keypoint feature-volume generator (MIT for its base networks; its bundled face-detection models are non-commercial); - a 3D-latent-volume generator (Apache-2.0). Both need operators `wai-ops/1` does not define on the receiving side: 3D convolution, sampling at data-dependent positions, and spatial normalisation. They also run hundreds of GFLOPs per frame, which no second implementation could recompute in CI. Quantising either means extending integer-operators first, which is a slice of its own. The other families are excluded by their weights' terms: no licence stated for the weights (the first-order and thin-plate keypoint generators; an audio-driven toolkit's renderer), CC BY-NC 4.0 (three), or no licence granted (one). The lead receives the names in the builder's report. - **Training data generated here, under Apache-2.0.** The talking-face video sets that were considered fall into three groups: - sets under share-alike or non-commercial terms; - sets that are lists of videos hosted elsewhere under their uploaders' rights; - one audio-visual sentence corpus under CC BY 4.0, whose attribution names its authors and whose faces are real people's. None of these could be committed or credited under the public-text rules. So the tool draws its faces from seeded parameters, as `tools/wai_int_sr_train.py` draws its pictures, and places the 16 keypoints exactly. The quality figures are therefore for a generated face set at 64 × 64, and §7.9 says so. - **The warp is the extension's own integer step, not a graph operator.** `wai-ops/1` has no sampling at data-dependent positions. The warp is defined in §7.5 from `exp_neg_q16` and `rdiv`, runs in the driver like a stage operator on every fabric, and only the network is a graph. The GPU leg therefore covers the network, which is where the compute is. - **`acc64`.** A Q15 activation times a 2^12 weight over up to 9 · 96 terms passes i32. Every operator is in `wai-ops/1-i32`, so the GPU runs the graph at `acc64` with 32-bit words. The registered generator does not meet `acc32`, and a test pins that. - **The mask table** clamps `exp_neg_q16(0)` = 65553 to 2^16, so the table is symmetric with T(0) = 16384. Without the clamp it dips at 0 (16382 against 16385 at −1). This was caught by the unit test. - **One origin claim per segment object.** synthesis's `present` entries name object claims, and the segment's envelope is what generates (synthesis §3.3). The claim covers every frame of the segment's decode, whose canonical buffer is its frames. A track record can also state each frame's SHA-256, so the sender commits to the exact frames. A frame shown on its own is claimed by its samples (§8.4). - **No consent rule.** The signature records who drove which face; §6 points a lawful basis to jwp-receipts §2.4.6. - **64 × 64 and widths 24/48/64.** This keeps the Python second implementation at about 2 minutes for the whole corpus with its mutations. No speed claim is made. The architecture is fully convolutional; a larger generator is a new file and a new digest. - **Names.** The corpus faces are `face1` and `face2`. No company, product or person names appear in public text, and standards are cited by identifier only. Framework URNs in the RTP draft that carry names are not reproduced. ## Measured (§7.9, `training.json`) 12 held-out faces × 100 frames at 25 fps: | compared | PSNR mean (dB) | PSNR min (dB) | SSIM mean | SSIM min | |---|---|---|---|---| | integer, float | 48.54 | 39.42 | 0.9988 | 0.9953 | | integer, rendered | 28.24 | 21.27 | 0.9238 | 0.8558 | | float, rendered | 28.22 | 21.11 | 0.923 | 0.8546 | | warp alone, rendered | 22.89 | 13.99 | 0.7635 | 0.3499 | Keypoint RMS error from a separately trained float detector: | pictures read | all 16 (px) | mouth's four (px) | |---|---|---| | the rendered faces (the detector's own error) | 0.111 | 0.092 | | the float network's frames | 0.569 | 0.547 | | the integer generator's frames | 0.575 | 0.542 | Keypoint track bitrate, by §7.4's coding in 1-second segments, payload bytes only: | keypoints | step 4 (1/4 px) | step 1 (1/16 px) | |---|---|---| | rendered | 2.942 kbit/s | 4.386 kbit/s | | detected | 2.96 kbit/s | 4.413 kbit/s | ## Checks Run on the build host through `rb` unless marked local. | check | command | result | |---|---|---| | unit tests | `cargo test --locked --no-default-features --features avatar_face --lib avatar_face::` | 5 passed (graph = §7.6 loop by loop; warp at rest; mask table; files round-trip and refuse in order; padding) | | corpus, §10 tables, §7.9 figures, acc64-not-acc32 | `cargo test --locked --release --no-default-features --features avatar_face --test avatar_face` | 6 passed | | corpus bin | `wai_avatar_face_vectors verify ../live-conformance/avatar-face` (release) | 3 PASS: inputs pinned; every file regenerates byte for byte; every form, frame and case | | second implementation | `python3 -I live-conformance/avatar_face_verify.py live-conformance/avatar-face` (Python 3.15) | the mask table, 28 forms, 9 frames and 24 cases as stated; every reason of both §10 tables seen; 17/17 mutated copies refused; about 2 min | | GPU (Metal, build host) | `WAI_OPS_GPU_REQUIRE=1 cargo test --locked --release --no-default-features --features avatar_face,ops_gpu --test avatar_face_gpu -- --nocapture` | `face-gpu: key=gpu-metal-0 frames=9 same=true graphs_on_gpu=9 (acc32 0, acc64 9) on_cpu=0 compared=9 differed=0 errors=[]` | | wasm32 | `cargo build --release --target wasm32-wasip2 --no-default-features --features avatar_face --bin wai_avatar_face_vectors --config 'profile.release.package.wai.codegen-units=1'`, then `wasmtime run --dir …::/corpus wai_avatar_face_vectors.wasm verify /corpus` (wasmtime 49.0.3) | 3 PASS, exit 0: every frame regenerated on wasm32 equals the committed native bytes | | registry | `cargo run --no-default-features --bin wai -- registry export` then `--check` | up to date (REGISTRY.md, capabilities.json, vocab regenerated) | | registry and container library tests | `cargo test --locked --no-default-features --lib -- codecs:: container::`; `cargo test --locked --lib -- codecs::` | 103 passed; 64 passed | | whole library, default | `cargo test --locked --lib` | 193 passed | | every integration test | `cargo test --locked --no-default-features --tests`; `cargo test --locked --tests` | every binary passes, none failed | | clippy | `cargo clippy --locked --no-default-features --features avatar_face,ops_gpu --all-targets`; `cargo clippy --locked --all-targets` | no note in any file this change adds or touches. Notes in files it does not touch: `glossary_check.rs`'s `collapsible_if`, and notes in `claim_receipt.rs` and `container.rs` under the `avatar_face,ops_gpu` combination after the merge of main | | dependents | `cargo check --locked --target wasm32-unknown-unknown` (wai-web); `cargo check --locked` (wai-pack) | build | | lockfiles | no dependency added; every cargo run above used `--locked`; `scripts/check-lockfiles.sh` | wai's locks unchanged; the script reports one stale lock this change does not touch, `joule-code/joule-code-rs/crates/joule-moq-room` (left as found) | | repo checks (local) | `check-tests-in-ci.py`, `check-workflow-concurrency.sh`, `check-spec-refs.py`, `check-wai-section-refs.py`, `check-no-vanity-metrics.sh`, `test-public-text-checks.sh`, `check-comparative-prose.sh`, `check-orphan-sources.py` | all exit 0 | | workflows (local) | `python3 ~/kani-logs/wfsteps.py HEAD origin/main`; `ruby -ryaml` over every workflow | only this change's own new steps reported, plus `checks`' build step it extends; every file parses | | public names (local) | `scripts/check-public-names.sh` on each of the 28 changed text files; commit messages and this body against the same patterns | clean | | merge | `origin/main` (with #428) merged into the branch at `9804962c`; every check above re-run after the merge | — | ## Falsifications All were run after committing, one rule broken at a time, then restored. Rust, each failing with exit 101: - a shift of the lowering's convolutions changed (12 → 11), with the loop-by-loop arithmetic kept: `the_graph_is_the_arithmetic_of_section_7_6` fails, and `the_committed_corpus_regenerates_from_its_seeds` panics in the generator; - the mask table without §7.6's clamp: `the_sigmoid_table_is_symmetric_and_bounded` fails; - the driver-key check dropped from `verify`: `every_vector_gets_what_it_states` fails; - an extra code in §10's first table: `the_extension_lists_the_reasons` fails (the Python verifier exits 1 too: no case refused with it); - one figure of §7.9 changed (48.54 → 48.55): `the_measurement_is_the_reports` fails; - a digit of a committed frame digest: `every_vector_gets_what_it_states` fails, and the wasm32 `verify` exits 1. Python verifier, each exiting 1: - the `frame_mismatch` check dropped; - the convolution's rounding floored, not half up; - the chain check dropped; - the exponential's constant 88670 off by one. **Caught by this round:** the mask table without its clamp first passed the Python verifier (exit 0). A frame rarely reads the table at 0, so the frames alone did not pin it. The corpus now states the table's SHA-256 and nine entries (commit `950ae477`), and the same falsification now exits 1 ("the mask's table differs"). The Python verifier also refuses 17 mutated copies of the corpus on every run: - a weight of each generator, its pin updated; - the prior's and the identity's samples and keypoints; - a keypoint of a frame; - a stated frame sample; - a segment's padding; - the stated status and output of a track; - a withheld generator; - a track record signed over another's face; - swapped track records; - a withheld label policy; - a misplaced refusal; - a table entry. ## Not done - **A permissively licensed public generator quantised to the profile.** It needs new `wai-ops/1` operators (3D convolution, data-dependent sampling, spatial normalisation) first. - **Captured faces.** The measurement covers a generated set at 64 × 64. Nothing is claimed for captured faces or another size. - **An identity prior in latent form.** Only the reference-picture form is registered. - **A watermark in the frames** (synthesis §7). None is applied. - **Fabrics.** wasm32 and Metal were run on the build host (macOS arm64). No Vulkan, DX12, browser WebGPU or NPU run for this capability, and no x86_64 CPU run by hand. CI's `avatar-face-wasip2` (Linux x86_64) and `metal` steps will add the first forge runs. - **The detector at the sender** (how keypoints are found in a camera's picture) is out of scope. The tool's detector serves only the measurement. - **Nothing was filed or posted.** The mappings are text in the extension, and no URN or message type is registered elsewhere. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- **Closed:** Landed on main through merge train E (#499, merge bf39ec9a); verified by content: this PR's head is in main
Registers wai.avatar.face (GenerativeDeterministic, ops face-int/1, one-file parameter set):
the WFG1 generator, WFI1 identity prior and WFK1 keypoint segment readers and writers; the
driver's integer warp and keypoint maps; the lowering face-int/1 to one wai-ops/1-i32 graph,
with the same arithmetic written out loop by loop for the tests; the identity and track
records; verification over them and synthesis's claims, log and label policy; the corpus
generator (bin wai_avatar_face_vectors) and the corpus and GPU tests. Registry export
regenerated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
live-conformance/avatar-face: the generator trained on faces the tool draws, two held-out
identity priors and their tracks, the training report, the seeded generator and identity, and
vectors.json (forms, frames, cases). avatar_face_verify.py runs the driver and the generator's
arithmetic in Python's integers, verifies records and synthesis, and mutates the corpus.
tools/wai_avatar_face_train.py renders the faces, trains, quantises and measures.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The extension text of wai.avatar.face, its SPEC §3.1, §5 and §7 entries, the determinism-tiers
fabric and evidence rows, and the changelog.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A frame rarely reads the table at 0, so the frames alone did not catch a table without §7.6's
clamp (the second implementation passed with it). The corpus now states the table's SHA-256 and
its entries at nine values, and both implementations check them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge remote-tracking branch 'origin/main' into wai/avatar-telepresence
Some checks failed
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Has been cancelled
WAI neural sink gates / does this change touch it (pull_request) Has been cancelled
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Has been cancelled
WAI energy receipts / does this change touch it (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI conformance / does this change touch it (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
standards workspaces build + test / which workspaces this change touches (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (pull_request) Has been cancelled
9804962c0b
dcharlot closed this pull request 2026-10-26 20:57:40 -04:00
Some checks failed
wai-web wasm32 / does this change touch it (pull_request) Has been cancelled
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Has been cancelled
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Has been cancelled
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Has been cancelled
wai-quantum studio and desktop / does this change touch it (pull_request) Has been cancelled
wai-quantum studio and desktop / studio · browser (pull_request) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (pull_request) Has been cancelled
wai-pack / wai-pack · does this change touch it (pull_request) Has been cancelled
wai-pack / wai-pack · linux (pull_request) Has been cancelled
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Has been cancelled
WAI neural sink gates / does this change touch it (pull_request) Has been cancelled
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Has been cancelled
WAI energy receipts / does this change touch it (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI conformance / does this change touch it (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
standards workspaces build + test / which workspaces this change touches (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!448
No description provided.