wai: graphics-vector, the extension text of wai.graphics.vector, §1–§3 (Draft, D7-1) #215

Merged
dcharlot merged 3 commits from wai/d7-1-graphics-text into main 2026-10-11 06:09:14 -04:00
Owner

Adds wai/extensions/graphics-vector.md, the extension text of wai.graphics.vector: titles, credits and other authored graphics carried as integer drawing instructions, which the sink rasterises into an overlay layer. This is phase D7-1 of D7.

This is Draft text. §1–§3 are written in full. §4–§6 and Annexes A and B are headings, each saying what it will hold; later revisions of the Draft fill them. D7-2 onward follow: the formats crate and corpus (D7-2), the raster (D7-3), the independent checker written from this text alone (D7-4), the stroke sets with Annexes A and B (D7-5), the text layer and §5 (D7-7), the sidecar (D7-9), and packages and §6 (D7-13). Nothing is registered. The capability string, SPEC §3 and §5, the registry and the codecs wait for D7-12.

What lands

  • wai/extensions/graphics-vector.md (new), Status Draft.
  • wai/README.md: the extensions/ row names vector graphics. This file is the only place the tree lists extensions; there is no extensions index.
  • wai/CHANGELOG.md: one entry, newest first.

No code, no SPEC edit, no registry or codec change, and no workflow change.

Section outline

  • 1. Scope and conformance: 1.1 Model (with composition beside protected video, vendor-free) · 1.2 Conformance targets · 1.3 Overlay-equivalence and text-equivalence (normative) · 1.4 What is covered (the coverage table, claimed and not claimed, the wording rule) · 1.5 Fabrics · 1.6 Outline sets named in the payload · 1.7 What the decode reads · 1.8 Registration (pending)
  • 2. Payload formats: 2.0 Common rules · 2.1 WOS1 · 2.2 WVG1 header · 2.3 WVG1 tables · 2.4 ITEM and the scene · 2.5 Canonical rules · 2.6 Caps and bounds · 2.7 Refusals and their order · 2.8 Versioning · 2.9 The canonical buffers · 2.10 The digest sidecar · 2.11 Text digests · 2.12 The JSON authoring form (informative)
  • 3. Arithmetic (normative): 3.0 Notation, units and stages · 3.1 The clock · 3.2 Track evaluation · 3.3 Placement · 3.4 The load-time interval check (a) and the cost (b) · 3.5 Flattening (RS1) · 3.6 Row split and cell split (RS2, RS3) · 3.7 Accumulation and scan (RS3, RS4), and why nothing wraps · 3.8 Coverage (RS5, RS6) · 3.9 Compositing, groups and clips (RS7, RS8) · 3.10 The frame procedure · 3.11 Properties, freedoms and prohibitions · 3.12 Bounds · 3.13 What is exact, and what is merely deterministic · 3.14 Strokes · 3.15 The raster stage family RS1–RS9
  • 4. Outline sets, 5. Text and accessibility, 6. Packages and floors, Annex A (WSF1), Annex B (the stroke set's digest): headings only.

Ambiguities resolved in the text

Each was a place where an implementer reading only the design's §1–§3 would have had to guess. The text now decides it.

  1. Header values that are not count caps. The design's step 2 refuses "a header count past its cap" (too_large) and names no step for tb, t0, dur, the design sides, or n_sizes, n_rates and n_items of 0. Step 2 now lists the count and length fields it caps, then inline_len + held_len, then the exact length. Every other header range is field_range, at the head of the record pass (step 4), in field order.
  2. Fields an item's kind fixes. A group end's fields, a group begin's paint, text and matrix slots, and a run's rule must hold a fixed 0 or 0xFFFF. These are field_range, not payload_malformed: only fields named zero are zero fields.
  3. A key's value range depends on its track's kind, which the key's own record does not carry. The record pass may read only the header and its own record, and no later step named the check. It is now step 5(c), "typing", field_range, over KEYS and then the slot-kind check over ITEMS.
  4. ruby_len ≥ 1 when ruby ≠ 0. The design listed this under canonical rule 4 (payload_malformed), but it reads only an earlier field of its own record, which is the record pass's rule. It is now in the TEXT row (field_range). Rule 4 keeps "names an earlier block" and the byte range.
  5. WOS1 counts below their minimum (n_glyphs = 0, notes_len = 0) are outline_malformed at step 2, in field order with too_large. The design's step 2 named only caps.
  6. A WOS1 glyph with points and no contours. "The last contour end equals n_points − 1" is undefined with no ends, so step 4 now refuses n_contours = 0 with n_points ≥ 1.
  7. The run's RW·RH in the cost. The design said "the hull of its glyph records' boxes (0 if every box is empty)". The hull is now taken over the clipped pixel boxes of the glyph records whose box is not empty, where a box is empty when bw = 0 or bh = 0.
  8. "max over ticks τ" now means every integer tick, not only frame ticks, so the cost is the same at every rate; it is 0 when no window contains τ.
  9. The interval check covers every path item, glyph record and clip, whether or not it is ever active.
  10. A glyph with no points has an all-zero box, so its device interval is its origin. (a) checks it, and in (b) it costs bw·bh, which is 0 or 1.
  11. The authoring tool's probe set. It now states which (size, rate) pairs it covers (those the tool is asked for; by default every listed pair). It also gives each candidate as a formula. Level 2 takes only windows that hold a frame, and takes the first and last frame inside them. Level 3 takes only frames in range. The design's "the first frame at or after its start and the last frame before its end" could fall outside the window or the document.
  12. The effective window the probe set uses is cited to §3.4(b). The design pointed to §5.4, which lands later; the two definitions are the same.
  13. The sidecar has exactly four members, all present. clips may be [].
  14. Order within one field: its own range first, then rules relating it to earlier fields. The design said only "at the later field".
  15. Sub-pieces are taken in order from xa toward xb. The column crossing is stated equivalently as the floor of the exact y on the row piece's line, so it is the same from either end.
  16. The purpose codes §2 needs (0 refused, 13 decorative) are stated in §2.3, since the vocabulary lands with §5.
  17. Group balance. An end closes the innermost open begin, none is left open, and depth counts the outermost group as 1.
  18. RATE order is compared by cross-multiplication, num_a·den_b < num_b·den_a.

Where the wording departs from the design, and why (no rule changes)

  • Public-text rules. Third-party names, font families, platform and vendor API names, comparisons with other rasterisers, the per-family font measurements, and the design's evidence labels are all out.
    • div255 is defined by its own closed form, ⌊(2x + 255)/510⌋.
    • The bounds table's evidence column became a basis column: the section that establishes each bound.
    • §3.13's join-knot text is general, with no measured families.
    • The platform hand-off is "the platform's graphics interfaces".
  • Placeholders say "a later revision of this Draft", not PR labels, because planning labels are not extension text.
  • The fabric statement (§1.5) does not cite #201's What the exact tier covers, which is not on main yet. It states the same scope on its own: CPU and Wasm, with GPU results as evidence.
  • §1.8 carries the three registration statements as pending. SPEC carries them with D7-12.

Reviews recorded

  1. §3.6–§3.8, line by line, against review A's independent implementation of §3.3–§3.8.

    • Rows: horizontal segments skipped; top and bottom endpoints; X(y) as a floor; the row range; y_top/y_bot; the direction kept; row-local y.
    • Cells: one sub-piece when xa = xb; boundaries strictly between, ordered from xa; the unsigned crossing with floor and ceiling, which that implementation asserts equal to the signed form; the cell from the smaller x; fa, fb, cover and area; zero-cover sub-pieces skipped.
    • Accumulation: rows outside [0, h) dropped; the left fold; the c + 1 < w guard; columns ≥ w dropped; the prefix scan.
    • Also compared: both quantisers, placement (L, the origin and the point), flattening (the levels and both closed forms), and the contour grammar's closing cases.

    No disagreement. With that procedure, §3.8's worked triangle gives |v| = 1280 and 512, clipped and unclipped, as the text states.

  2. §2.7's order, walked against A-F6's examples.

    • kind = 4 with ref = 0 → field_range at step 4. kind is the record's first field; the first-reference rule is step 5(g).
    • interp = 2 + j with j ≥ n_tables → field_range at step 4.
    • carriage outside {0, 1} → field_range at step 4, before 5(a)'s inline sum.
    • A track kind out of range → field_range at step 4.
    • The last key's interp ≠ 0 → payload_malformed at 5(b).
    • Each of the four added sum rules → payload_malformed at 5(a).
    • The case A-F6 left unplaced, a key value outside its track kind's range, is now field_range at 5(c).
  3. §3.4(b), walked against RC1–RC3.

    • c(f) and the box clamp match the script's cost and box functions.
    • The informative "what the cost bounds" derivation is RC1's operation count under the same two freedoms. RC1's worst observed ratio is 0.417, below 3.
    • RC2, re-run: A = 1,101,944,324,096, B = 10,992,717,135,872, and one heavy item alone = 184,512,512. An implementation of §3.4(b) written from this text reproduces all three exactly, and counts touching windows once.
    • For case C (2^20 glyph records), the text gives 17,635,152,494,592: RC2's 17,630,857,527,296 plus 256·4096², the hull terms of the 256 runs of 4,096 glyphs that the script leaves out. Both are refused.
    • RC3's roll and lower-third shapes already include the per-run hull and per-group w·h terms the text defines.

Checks

  • scripts/check-wai-section-refs.py: clean.
    • Falsified: with "packaging §7.1" appended to a scratch copy of the specification texts, it exits 1 and names the line. On the tree it exits 0.
    • While writing, it caught two false positives. A half-open interval such as [a, b), followed later by a §N and then a Markdown link with no ] between, lets its link pattern run across lines. Those intervals are now written inclusively, or without the bracket. The D7-5 and D7-7 text should avoid the same shape.
  • scripts/check-public-names.sh with the private list exported: clean on each changed file, one per invocation. Also clean at CI scope, over every tracked file.
  • scripts/check-comparative-prose.sh: clean on graphics-vector.md and README.md, and at CI scope.
    • Given CHANGELOG.md as an argument, it reports 7 historical lines, identical on origin/main; its default scope exempts the CHANGELOG. The added entry alone is clean.
  • scripts/check-no-vanity-metrics.sh: clean.

Merge notes

  • The chain. This touches no file #201 or #199 edits, except two.
    • wai/README.md: a one-line change, which git merge-tree merges cleanly against both heads (4e7155b9 and e1acae78).
    • wai/CHANGELOG.md: it conflicts at the top of the file, as expected. Keep both entries.
  • Legs: wai-section-refs.yml; no-vanity-metrics.yml (comparative prose and vanity; the names check runs on the push to main).
  • Exit: merge as Draft so that D7-4's checker can be written from it.

🤖 Generated with Claude Code

Adds `wai/extensions/graphics-vector.md`, the extension text of `wai.graphics.vector`: titles, credits and other authored graphics carried as integer drawing instructions, which the sink rasterises into an overlay layer. This is phase D7-1 of D7. **This is Draft text.** §1–§3 are written in full. §4–§6 and Annexes A and B are headings, each saying what it will hold; later revisions of the Draft fill them. D7-2 onward follow: the formats crate and corpus (D7-2), the raster (D7-3), the independent checker written from this text alone (D7-4), the stroke sets with Annexes A and B (D7-5), the text layer and §5 (D7-7), the sidecar (D7-9), and packages and §6 (D7-13). **Nothing is registered.** The capability string, SPEC §3 and §5, the registry and the codecs wait for D7-12. ## What lands - `wai/extensions/graphics-vector.md` (new), Status *Draft*. - `wai/README.md`: the `extensions/` row names vector graphics. This file is the only place the tree lists extensions; there is no extensions index. - `wai/CHANGELOG.md`: one entry, newest first. No code, no SPEC edit, no registry or codec change, and no workflow change. ## Section outline - **1. Scope and conformance:** 1.1 Model (with composition beside protected video, vendor-free) · 1.2 Conformance targets · 1.3 Overlay-equivalence and text-equivalence (normative) · 1.4 What is covered (the coverage table, claimed and not claimed, the wording rule) · 1.5 Fabrics · 1.6 Outline sets named in the payload · 1.7 What the decode reads · 1.8 Registration (pending) - **2. Payload formats:** 2.0 Common rules · 2.1 `WOS1` · 2.2 `WVG1` header · 2.3 `WVG1` tables · 2.4 `ITEM` and the scene · 2.5 Canonical rules · 2.6 Caps and bounds · 2.7 Refusals and their order · 2.8 Versioning · 2.9 The canonical buffers · 2.10 The digest sidecar · 2.11 Text digests · 2.12 The JSON authoring form (informative) - **3. Arithmetic (normative):** 3.0 Notation, units and stages · 3.1 The clock · 3.2 Track evaluation · 3.3 Placement · 3.4 The load-time interval check (a) and the cost (b) · 3.5 Flattening (RS1) · 3.6 Row split and cell split (RS2, RS3) · 3.7 Accumulation and scan (RS3, RS4), and why nothing wraps · 3.8 Coverage (RS5, RS6) · 3.9 Compositing, groups and clips (RS7, RS8) · 3.10 The frame procedure · 3.11 Properties, freedoms and prohibitions · 3.12 Bounds · 3.13 What is exact, and what is merely deterministic · 3.14 Strokes · 3.15 The raster stage family RS1–RS9 - **4. Outline sets**, **5. Text and accessibility**, **6. Packages and floors**, **Annex A** (`WSF1`), **Annex B** (the stroke set's digest): headings only. ## Ambiguities resolved in the text Each was a place where an implementer reading only the design's §1–§3 would have had to guess. The text now decides it. 1. **Header values that are not count caps.** The design's step 2 refuses "a header count past its cap" (`too_large`) and names no step for `tb`, `t0`, `dur`, the design sides, or `n_sizes`, `n_rates` and `n_items` of 0. Step 2 now lists the count and length fields it caps, then `inline_len + held_len`, then the exact length. Every other header range is `field_range`, at the head of the record pass (step 4), in field order. 2. **Fields an item's kind fixes.** A group end's fields, a group begin's `paint`, `text` and matrix slots, and a run's `rule` must hold a fixed 0 or `0xFFFF`. These are `field_range`, not `payload_malformed`: only fields named `zero` are zero fields. 3. **A key's value range depends on its track's kind,** which the key's own record does not carry. The record pass may read only the header and its own record, and no later step named the check. It is now step 5(c), "typing", `field_range`, over `KEYS` and then the slot-kind check over `ITEMS`. 4. **`ruby_len ≥ 1` when `ruby ≠ 0`.** The design listed this under canonical rule 4 (`payload_malformed`), but it reads only an earlier field of its own record, which is the record pass's rule. It is now in the `TEXT` row (`field_range`). Rule 4 keeps "names an earlier block" and the byte range. 5. **`WOS1` counts below their minimum** (`n_glyphs = 0`, `notes_len = 0`) are `outline_malformed` at step 2, in field order with `too_large`. The design's step 2 named only caps. 6. **A `WOS1` glyph with points and no contours.** "The last contour end equals `n_points − 1`" is undefined with no ends, so step 4 now refuses `n_contours = 0` with `n_points ≥ 1`. 7. **The run's `RW·RH` in the cost.** The design said "the hull of its glyph records' boxes (0 if every box is empty)". The hull is now taken over the clipped pixel boxes of the glyph records whose box is not empty, where a box is empty when `bw = 0` or `bh = 0`. 8. **"max over ticks τ"** now means every integer tick, not only frame ticks, so the cost is the same at every rate; it is 0 when no window contains `τ`. 9. **The interval check** covers every path item, glyph record and clip, whether or not it is ever active. 10. **A glyph with no points** has an all-zero box, so its device interval is its origin. (a) checks it, and in (b) it costs `bw·bh`, which is 0 or 1. 11. **The authoring tool's probe set.** It now states which (size, rate) pairs it covers (those the tool is asked for; by default every listed pair). It also gives each candidate as a formula. Level 2 takes only windows that hold a frame, and takes the first and last frame inside them. Level 3 takes only frames in range. The design's "the first frame at or after its start and the last frame before its end" could fall outside the window or the document. 12. **The effective window** the probe set uses is cited to §3.4(b). The design pointed to §5.4, which lands later; the two definitions are the same. 13. **The sidecar has exactly four members, all present.** `clips` may be `[]`. 14. **Order within one field:** its own range first, then rules relating it to earlier fields. The design said only "at the later field". 15. **Sub-pieces** are taken in order from `xa` toward `xb`. The column crossing is stated equivalently as the floor of the exact y on the row piece's line, so it is the same from either end. 16. **The purpose codes §2 needs** (0 refused, 13 `decorative`) are stated in §2.3, since the vocabulary lands with §5. 17. **Group balance.** An end closes the innermost open begin, none is left open, and depth counts the outermost group as 1. 18. **`RATE` order** is compared by cross-multiplication, `num_a·den_b < num_b·den_a`. ## Where the wording departs from the design, and why (no rule changes) - **Public-text rules.** Third-party names, font families, platform and vendor API names, comparisons with other rasterisers, the per-family font measurements, and the design's evidence labels are all out. - `div255` is defined by its own closed form, `⌊(2x + 255)/510⌋`. - The bounds table's evidence column became a *basis* column: the section that establishes each bound. - §3.13's join-knot text is general, with no measured families. - The platform hand-off is "the platform's graphics interfaces". - **Placeholders say "a later revision of this Draft"**, not PR labels, because planning labels are not extension text. - **The fabric statement (§1.5)** does not cite #201's *What the exact tier covers*, which is not on main yet. It states the same scope on its own: CPU and Wasm, with GPU results as evidence. - **§1.8 carries the three registration statements** as pending. SPEC carries them with D7-12. ## Reviews recorded 1. **§3.6–§3.8, line by line, against review A's independent implementation of §3.3–§3.8.** - **Rows:** horizontal segments skipped; top and bottom endpoints; `X(y)` as a floor; the row range; `y_top`/`y_bot`; the direction kept; row-local y. - **Cells:** one sub-piece when `xa = xb`; boundaries strictly between, ordered from `xa`; the unsigned crossing with floor and ceiling, which that implementation asserts equal to the signed form; the cell from the smaller x; `fa`, `fb`, `cover` and `area`; zero-cover sub-pieces skipped. - **Accumulation:** rows outside `[0, h)` dropped; the left fold; the `c + 1 < w` guard; columns ≥ `w` dropped; the prefix scan. - **Also compared:** both quantisers, placement (`L`, the origin and the point), flattening (the levels and both closed forms), and the contour grammar's closing cases. **No disagreement.** With that procedure, §3.8's worked triangle gives `|v|` = 1280 and 512, clipped and unclipped, as the text states. 2. **§2.7's order, walked against A-F6's examples.** - `kind = 4` with `ref = 0` → `field_range` at step 4. `kind` is the record's first field; the first-reference rule is step 5(g). - `interp = 2 + j` with `j ≥ n_tables` → `field_range` at step 4. - `carriage` outside {0, 1} → `field_range` at step 4, before 5(a)'s inline sum. - A track `kind` out of range → `field_range` at step 4. - The last key's `interp ≠ 0` → `payload_malformed` at 5(b). - Each of the four added sum rules → `payload_malformed` at 5(a). - The case A-F6 left unplaced, a key value outside its track kind's range, is now `field_range` at 5(c). 3. **§3.4(b), walked against RC1–RC3.** - `c(f)` and the box clamp match the script's cost and box functions. - The informative "what the cost bounds" derivation is RC1's operation count under the same two freedoms. RC1's worst observed ratio is 0.417, below 3. - RC2, re-run: A = 1,101,944,324,096, B = 10,992,717,135,872, and one heavy item alone = 184,512,512. An implementation of §3.4(b) written from this text reproduces all three exactly, and counts touching windows once. - For case C (2^20 glyph records), the text gives 17,635,152,494,592: RC2's 17,630,857,527,296 plus 256·4096², the hull terms of the 256 runs of 4,096 glyphs that the script leaves out. Both are refused. - RC3's roll and lower-third shapes already include the per-run hull and per-group `w·h` terms the text defines. ## Checks - **`scripts/check-wai-section-refs.py`:** clean. - *Falsified:* with "packaging §7.1" appended to a scratch copy of the specification texts, it exits 1 and names the line. On the tree it exits 0. - While writing, it caught two false positives. A half-open interval such as `[a, b)`, followed later by a `§N` and then a Markdown link with no `]` between, lets its link pattern run across lines. Those intervals are now written inclusively, or without the bracket. The D7-5 and D7-7 text should avoid the same shape. - **`scripts/check-public-names.sh`** with the private list exported: clean on each changed file, one per invocation. Also clean at CI scope, over every tracked file. - **`scripts/check-comparative-prose.sh`:** clean on `graphics-vector.md` and `README.md`, and at CI scope. - Given `CHANGELOG.md` as an argument, it reports 7 historical lines, identical on `origin/main`; its default scope exempts the CHANGELOG. The added entry alone is clean. - **`scripts/check-no-vanity-metrics.sh`:** clean. ## Merge notes - **The chain.** This touches no file #201 or #199 edits, except two. - `wai/README.md`: a one-line change, which `git merge-tree` merges cleanly against both heads (`4e7155b9` and `e1acae78`). - `wai/CHANGELOG.md`: it conflicts at the top of the file, as expected. Keep both entries. - **Legs:** `wai-section-refs.yml`; `no-vanity-metrics.yml` (comparative prose and vanity; the names check runs on the push to main). - **Exit:** merge as Draft so that D7-4's checker can be written from it. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The model and conformance (overlay-equivalence and text-equivalence over
the overlay layer only), the WOS1 and WVG1 formats with their canonical
rules, caps and refusal order, the digest sidecar and text digests, and
the arithmetic: clock, tracks, placement, the load-time interval check
and per-frame cost, flattening, row and cell split, accumulation,
coverage and compositing, as the stage family RS1–RS9. Sections 4–6 and
the annexes are headings that later revisions of this Draft fill.

Nothing is registered.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
- WOS1 load check 2 names its counts, and check 7 states what a
  glyph's contour ends must satisfy;
- groups: each end closes the innermost open begin, none is left open;
- the probe set gives each candidate frame as a formula;
- the interval check names O's interval per axis.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
wai: README and CHANGELOG name the graphics-vector Draft
All checks were successful
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m3s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m31s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 48s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 34s
standards workspaces build + test / map-rs (pull_request) Successful in 26s
standards workspaces build + test / mesh-rs (pull_request) Successful in 27s
standards workspaces build + test / openpay (pull_request) Successful in 1m21s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 1m45s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 2m59s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 6m21s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 3m17s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 6s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 6s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 4s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m12s
standards workspaces build + test / eoc-rs (pull_request) Successful in 2m5s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m38s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m15s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m15s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m23s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m12s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m22s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 2m31s
WAI section references / cited sections exist (pull_request) Successful in 12s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 4m18s
f66c09ede1
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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!215
No description provided.