wai-vector: the default stroke set and the test repertoire, as WSF1 sources expanded by Annex A, and the text vectors (D7-5) #224
Loading…
Reference in a new issue
No description provided.
Delete branch "wai/d7-5-stroke-set"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds the in-house outline sets of
wai.graphics.vector: the default stroke set and the test repertoire, each drawn here as integer centre lines in the stroke source formatWSF1and expanded by an integer stroker into an ordinaryWOS1. The corpus gains atextgroup, and stroke-glyph members ofrunsandmotion. The extension gains §4 and Annexes A and B. This is phase D7-5 of D7.It starts from
mainat4ab66d24(with #219 merged), and touches no file that #218 or #220 edits. Nothing is registered.What lands
src/wsf1.rs(featureauthor):WSF1reader, its ten checks in order, and its writer;(R_rat(−dy·ρ, len), R_rat(dx·ρ, len))withlen = isqrt(dx² + dy²). Caps and the outer side of joins take table directions chosen by exact cross-product signs, placed atR_half_up(ρ·u, 15). The inner side of a join takes its two offset points. One closed contour per stroke path, every point on-curve.The default stroke set (
src/vectors/stroke.rs): printable ASCII, U+0020–U+007E, each glyph ID its code point. It is drawn from straight segments and ellipse arcs whose points come from the same Q15 table, so the drawing is integers throughout and no outline is traced from any font. Apache-2.0. Its notes carryparent_sha256(the source's digest),converter=wsf1-expansion/1,licence,licence_sha256,copyright,rfn=none,source,glyphsandmetrics, then a blank line, then the Apache License 2.0 text.src/builtin/: the stroke set's bytes (include_bytes!of the corpus file), its SHA-256 and its length, andhold(), which puts them in a sink's set store.The test repertoire (
src/vectors/repertoire.rs), Apache-2.0 and corpus-only:Each joining form's connector, and each headline, runs to the edge of its advance, so the pen's round cap overlaps the neighbour by 2ρ, as joins in production fonts overlap.
graphics-vector.md:WOS1only; pinning and carriage; the notes' keys and the licence they carry; the default stroke set; the test repertoire;WSF1layout and checks, why its caps fitWOS1's, the Q15 table as 512 bytes with their SHA-256, and the expansion;vector-conformance/:sources/(the twoWSF1sources);sets/stroke-ascii.wos1andsets/test-repertoire.wos1, both held; the new vectors below; andsha256.json's new frame entries. The README's provenance line names the two in-house sets, their drawing sources and the generator. The README now lists the groups that render.wasm/: the Node leg's module is built withdefault-features = false, a sink's build with no stroker.verify.mjschecks the stroke set's SHA-256 against Annex B.wai-vector.yml:nativegains the stepcargo build --no-default-features --lib, the sink's build;LICENSE, whose text the in-house sets carry.sets/stroke-ascii.wos1(Annex B)05476c4658ef7366c7700736487eac4c3c1b7d21264978c7d05bd4c7427736c9sources/stroke-ascii.wsf14eec759d394d021aec8ce99b41e4b25fecb36372c77459ef62df182b9eb8c783sets/test-repertoire.wos12310ab64ddcf4d851d4d7c08bbce141fba178f03fdcbb07b05db3863e179846fsources/test-repertoire.wsf1f20c628442ecc778e6d1f1ef3994d767730e5dd827f85cf9542a1b7f18661136The Q15 table's 512 bytes have SHA-256
11c05a1323c8b6dde89a5627d29acecb9163b87dfd169054236fb1d1def66437. Pen radius 80 outline units;upem22000. Most of the stroke set's points are round caps, at up to 32 table directions each.The vectors: 12 new, 331 in all, and 70 new frame digests (
sha256.jsongrows from 66 to 87 entries).textlatin-asciitextarabicbyte_firstdecreasingtexthebrewtextdevanagaritextmixed-directiontextsplit-linestextrubytextvertical-rlmode = 1, upright Latin stackedtextemojirunsarabic-joinsrunsarabic-joins-splitmotionstroke-sliceEach payload names its sets as held, by SHA-256 and length. The text layer's projection lands with D7-7, so these vectors pin runs, clusters, blocks,
text_hash, block identities, costs and frames.Where this differs from the brief, and why
vector-conformance/sources/, notsets/src/. The merged checker opens every entry ofsets/as a set, and so didtests/corpus.rs. A directory there would crash the checker.authoris a default feature. It gateswsf1, the two drawings, thetextvectors and the generator's entry points. The library's other generator modules stay compiled, so the recomputation path is unchanged. A sink turnsauthoroff, and CI now builds it that way twice: natively, and as the Node leg's module. The CLI requiresstdandauthor."text"inRENDER_GROUPS. The corpus README, which the checker's corpus driver follows, now namestextamong the groups that render. No computation changes. The change was made after the unmodified checker had been run (below), and is a separate commit.runsandmotionvectors are kept, and the stroke-glyph vectors are added beside them. The set-R vectors pin exact geometry (the seam pixel at 255, the 256 phases) that a stroke glyph would blur.motion/stroke-sliceis the same shape at 320×180, so the Python checker renders it in seconds.Tests, and the falsification of each
Each test was committed first. Then the code it guards was broken, the named test was run and shown red, the code was restored through git, and the test was shown green. All runs are debug, on the dev Mac. The script that did this is not committed.
stroke_sets::the_stroke_sets_digest_equals_annex_b: the bundled bytes,STROKE_ASCII_SHA256, Annex B, the committed source's digest, and the expansion of that source all agree; the set's glyph IDs are U+0020–U+007EU[1].sin3212 → 3700dc928373…, Annex B states05476c46…stroke_sets::annex_a_states_the_table: Annex A's hex block isunit_table_bytes(), and its stated SHA-256 matchesU[1].sin3212 → 3213Annex A's bytes are the table the expansion readsstroke_sets::the_expansion_is_deterministic: offsets worked by hand (n((100, 200), 90) = (−81, 40), sinceisqrt(50000) = 223;n((−7, 3), 80) = (−34, −80)); both sets re-derive from their committed sources twice, byte for byte; the generator writes the committed sources; the notes beginparent_sha256=…,converter=wsf1-expansion/1isqrtrounded upleft: (−80, 40) right: (−81, 40)stroke_sets::the_joining_table_picks_the_forms_of_the_test_words(and its unit twin): five words against Unicode's code points for each form, written out; every form the table names is drawnبَيْت … left: […, 65267, …] right: […, 65268, …]stroke_sets::the_expansion_covers_the_pens_path: on a 20-unit grid over every glyph of both sets, a point within ρ − 4 of a centre line is filled, and one farther than ρ + 8 from every centre line is not… is within the pen's path but not filledverify.mjs's Annex B check (the Node leg)ANNEX B: sets/stroke-ascii.wos1 hashes to 05476c46…, Annex B states 05476c47…, exit 1What falsification found:
R_half_up(80·u, 15)moves only when80·Δucrosses a rounding boundary, about 410 units of Q15. So the digest test stayed green under3212 → 3213, while the table test went red. The table is pinned byte for byte byannex_a_states_the_table, and an entry change that moves a vertex turns the digest test red. Both are in the table above.14d08568), and the swap turns it red.isqrt(2)returned 2 in the first version: its Newton start,x/2 + 1, does not fall belowxatn = 2. The unit testisqrt_is_the_floorcaught it. No segment of either set hasdx² + dy² = 2, so fixing it changed no generated byte.Also:
stroke_sets::each_set_carries_its_licence:licence=Apache-2.0,rfn=none,licence_sha256is the SHA-256 of the text after the blank line (the verifier'slicence_mismatchcheck), andsourcesays that no outline is traced from any font.wsf1::tests(unit):isqrtagainst the definition over0..20,000and at the widthsdx² + dy²reaches; the table is symmetric under a quarter turn and a reflection, with every|u|²within2^17of2^30; a horizontal stroke is a stadium whose caps hold the 31 directions inside their half-planes; a dot is the 64-gon; the format round-trips.Cross-checks
main(wai/tools/wai_vector_check.py, merged in #219), over the whole corpus:sha256.jsonentries. The only disagreements were the ninetextvectors (.frames present in one only) and their 18 entries, because its list of rendering groups predatestext;"text"added to that list: 331 of 331, 88 of 88, 196 of 196, and 87 of 87, every new frame rendered by the closed-form crossings in big integers. Wall time on the loaded dev Mac was 12 minutes; CPU time 152 s.Legs and gate
Every new vector is identical on three engines, locally on the dev Mac:
vectors verify(331 vectors, 975 generated files);wasm32-wasip2under wasmtime 49.0.2: every test, andvectors verify;wasm32-unknown-unknownunder Node 26.11.1, in the sink's build:verify.mjs(331 vectors and 290 authoring forms), with the stroke set's digest equal to Annex B's.CI pins wasmtime 38.0.3 and Node 22.
A second instruction-set architecture: a static
x86_64-unknown-linux-muslbuild of the tool ranvectors verifyon an x86_64 Linux host. All 331 vectors and 975 generated files are identical, the two sets and their sources among them.The sink's build (
--no-default-features --lib) compiles warning-free, with nowsf1.Clippy: clean with
--all-targets --features std, except the lint inwai-ops'ssha256.rs, which this crate includes by path.The wai-rs gate at
14d08568(gate.sh d7-5-r2): GREEN. Build, lib tests, carriage, the corpus loop (21 of 21), fast kernels, byte-exact, wai-web wasm32 and the neural gates all pass. The first run (d7-5) was red at one step only:fast-kernelsfailed before compiling, because cargo's index lookup sawderonly up to 0.7.4 whileCargo.lockpins 0.7.10, a transient registry fetch. That step rerun alone is green, and so is the full rerun.The tree-wide tests
corpus_provenance,every_decoded_output_states_a_sha256(which reads the grownsha256.json) andsigner_ids_are_labels: green.Public text:
check-public-names.shwith the private list: clean on each of the 44 changed files, one per invocation, and at CI scope;check-comparative-prose.sh: clean on each file;check-no-vanity-metrics.sh,check-wai-section-refs.pyandcheck-workflow-concurrency.sh: clean.Merge notes
1946c750(#220, #218) while this was built, and none of that delta overlaps this branch either. Merge as is; there is no need to merge main in first.wai-vector.yml:native×3, now with the sink's build;wasip2;node;fuzz;checker;wai-conformance.yml, becausesha256.jsonchanges;no-vanity-metrics.yml;wai-section-refs.yml, for the extension's new text.textvectors are where the projection goes.text::test_words()holds the shaper's expected forms. Each block'slang,dirandmodeis already in its identity.🤖 Generated with Claude Code