%unimsg 0 findings/the-transcript-writer/v0 -- The first consumer of @vocab/spatial/v0 and @vocab/motion/v0, built before -- any renderer because that is the order the observables demand — and the five -- things it changed in two vocabularies that had been written the day before. -- -- @vocab/vocabulary/v0's landing checklist says a :tool vocabulary needs at -- least one consumer built, or the refusal to build one recorded as an open -- risk. This is the consumer. It is not the gate: tools/spcheck does not exist, -- and the refusals tables are still owed a checker. the-transcript-writer @findings/the-transcript-writer/v0 { title "The transcript writer, the six rules it overturned, and what a real mesh costs" status :open subject -> @vocab/spatial/v0 evidence [ -> @spatial/arm/v0, -> @motion/arm-sweep/v0 ] assessed 2026-08-30 verdict "THE OBSERVABLES ARE REAL AND TWO OF THE RULES BEHIND THEM WERE NOT. tools/sptx resolves a scene into a transcript, evaluates a take over its declared grid, answers `where is X in frame Y`, and runs a document's own checks. Every number in it is an exact rational and a float is refused, which is the rule rather than a limitation — a writer that resolved in float64 would break the thing it exists to enforce. SIX FINDINGS, AND TWO OF THEM REVERSE A RULE WRITTEN THE DAY BEFORE. One is a construct the vocabulary could not represent at all; one is a transcendental hiding inside an interpolation; one is a byte-level inequality between two documents that mean the same thing; and one is a refusal that cannot be decided exactly; one is a qualifier the specification already required and no take had used; and one made the transcript depend on a filename. All six are now in the vocabularies, which is why this document is short." -- =================================================================== findings [ | id finding "what it broke" answer | "W1" "TRS composition is not closed under a non-uniform scale — the true transform of a scaled parent with a rotated child is a shear" "the resolution algorithm, which had no way to be both correct and matrix-free" ":scale is ONE number. A non-uniform scale is baked into geometry or refused" | "W2" "spherical interpolation needs an arc cosine and a sine, so two implementations can be required to be close and never equal" "the motion equality, which is the whole reason the vocabulary exists" ":linear on a rotation is component-wise after the shortest-arc sign choice, and is not renormalised" | "W3" "an omitted :opacity emitted `1` where an authored one emitted `1.000000`" "byte equality between two documents with the same resolved material" "a default is quantised exactly as an authored value. It is now a binding-contract row" | "W4" "a joint's angle comes from an arc tangent and a limit is declared in degrees" "the one refusal in either gate that exact arithmetic cannot decide" "the comparison is made to the bound scene's :unitless, and the writer reports the check as NOT RUN rather than guessing" | "W6" "the transcript recorded the file PATH of the document it resolved" "the transcript hash was a function of where the file sat, so the same scene at two paths compared unequal" "a transcript names its source by identifier and by digest, both of which are properties of the document" | "W5" "every reference in a take points into another document, and none of them said so" "tools/links reported four dangling paths against the first take written" "a :drives and a check's :of carry the `external` qualifier, which is the specification's own rule and is now a refusal" | "W7" "the transcript wrote every resolved number as a decimal, when every one of them is an exact integer count of quanta" "roughly half the bytes of every transcript, and the motion transcript is the design's largest open risk" "the bulk arrays — positions, indices and attribute values — are typed arrays of scaled integers. Measured below" ] -- =================================================================== w1-is-the-one-that-cost-a-construct "docs/42 PRICED THE MATRIX REFUSAL AT A CONVERSION STEP, because none of the five files it transcribed carried shear. THE REAL PRICE IS ONE LEVEL DEEPER AND IT ONLY APPEARS WHEN SOMETHING COMPOSES TWO POSES. Scale a parent by two in x, rotate its child forty-five degrees, and the composed transform is a shear. No translation, rotation and scale can express it. A writer therefore has three options and only one is honest: produce a wrong answer quietly, reintroduce the matrix the vocabulary refuses, or refuse the non-uniform scale. Every engine carrying a TRS node with a non-uniform scale takes the first, and calls it decomposition. SO :scale IS ONE NUMBER. It may be negative, which mirrors and flips winding; it may not be zero. A squashed thing is squashed GEOMETRY, written into its positions. THAT IS A REAL LOSS to an authoring tool, and it buys a resolution algorithm that is exact and closed — which is the property the equality cannot do without." w2-reverses-the-strongest-paragraph-in-the-motion-vocabulary "AND THE PARAGRAPH WAS RIGHT ABOUT THE FAILURE AND WRONG ABOUT THE FIX. It argued that leaving rotation interpolation unstated is how two players differ, and that :linear on a rotation must therefore mean shortest-arc slerp. The first half is exactly right. SLERP IS TRANSCENDENTAL. An arc cosine and a sine cannot be evaluated exactly over rationals, so a specification that requires slerp can require two implementations to be CLOSE and never to be EQUAL — and `close` is the epsilon somebody chose, which is the thing this repository has spent three vocabularies removing. COMPONENT-WISE INTERPOLATION IS ADDITION AND MULTIPLICATION and is exact. Not renormalising it keeps it that way, and is sound rather than sloppy: @vocab/spatial/v0 already defines rotation by a quaternion as q v q* divided by the squared norm, so a shortened interpolant is the same rotation. THE SIGN RULE SURVIVES UNCHANGED, because it was the real content of the original paragraph. WHAT IT COSTS IS CONSTANT ANGULAR VELOCITY, stated in the vocabulary with the obligation it puts on a converter: resample below the declared precision, and say so in :source." what-the-example-documents-are "examples/spatial-arm.umsg is hand-authored: a six-axis arm at rest, six frames, a measured camera mount with a tolerance, a collision hull beside the visual shells, a body with mass and an inertia tensor, and a five-vertex blade with a morph target driven by a declared parameter. It is the landing-checklist document. examples/motion-arm-sweep.umsg is the take, and its samples are COMPUTED — a quaternion for a forty-five degree turn has no exact decimal, so each component is written to eight places and the norm lands inside the :unitless the scene declares. The document is exact about what it holds and cannot be exact about the rotation, which is the whole of docs/42's F1 in one file." what-it-measured [ | artefact entries text cbor note | "the scene transcript" "6" "3,841" "2,016" "six instances, one of them a five-vertex mesh" | "the motion transcript, one second at ten hertz" "66" "47,352" "21,568" "eleven ticks of the same six instances" ] the-size-question-was-then-measured "AND IT IS THE ONE docs/41 AND docs/42 BOTH DEFERRED. A ten-thousand-vertex grid — 19,602 triangles, 58,806 indices — was generated and written twice: once at six decimal places, and once at seventeen, which is what a converter transcribing float32 BIT-FOR- BIT would produce, since 0.1f is exactly 0.100000001490116119384765625. THE BINARY BASELINE IS THE FAIREST ONE AVAILABLE: float32 positions with 16-bit indices, which is what glTF would carry for a mesh this size." mesh-sizes [ | form raw gzipped "against the baseline" | "float32 positions, uint16 indices" "237,612" "122,967" "the baseline" | "float32 positions, uint32 indices" "355,224" "117,655" "what a larger mesh would need" | "unimsg CBOR, six decimal places" "396,823" "100,541" "+67% raw, and 18% SMALLER gzipped" | "unimsg text, six decimal places" "652,410" "106,088" "+175% raw, and 14% smaller gzipped" | "unimsg CBOR, seventeen places" "533,097" "151,756" "what a converter that does not quantise produces. +34% over the six-place form, and worse than binary on the wire" | "the transcript of either document" "396,858" "—" "IDENTICAL ENTRIES from both source documents. See quantisation-collapses-the-verbose-document" ] the-answer-is-yes-on-the-wire-and-no-in-memory "THE TWO NUMBERS POINT OPPOSITE WAYS AND BOTH ARE REAL. UNCOMPRESSED, THIS COSTS 1.7 TIMES THE BINARY. A coordinate is about 7.3 bytes of CBOR against 4 for a float32, which is docs/26's finding — a decimal fraction costs roughly what its ASCII does — arriving again in three dimensions. Nothing recovers that, and a consumer that wants a vertex buffer still builds one on load. COMPRESSED, IT IS SMALLER THAN THE BINARY: 100,541 bytes against 122,967, an 18% saving, and the same inversion @vocab/graphic/v0 measured on a 1.9 MB SVG. Repetitive ASCII and repetitive CBOR give a compressor more to work with than packed floats do, and packed floats are nearly random in their low bits. For anything that crosses a network — which is most things — the exact-decimal form is the smaller one. SO THE SIZE RISK docs/41 CALLED THE THING THAT COULD SINK THE DESIGN IS NOT THAT, on this evidence. It is a real cost in memory and a saving on the wire, which is a trade a format may make deliberately." quantisation-collapses-the-verbose-document "THE STRONGEST RESULT IN THIS DOCUMENT AND IT WAS NOT EXPECTED. The six-place document and the seventeen-place one resolve to BYTE-IDENTICAL transcript entries, because both are rounded onto the :precision the document declares. WHAT THAT MEANS FOR A CONVERTER: a naive transcription of float32 source data is 34% larger and buys NOTHING — every digit past the declared precision is discarded by the equality that matters. The right behaviour is the one the marasim editor found for @vocab/graphic/v0 and this vocabulary now inherits: QUANTISE ON ENTRY rather than on write, so that what is in the document and what is in the transcript cannot drift apart. AND IT IS THE :precision DESIGN PAYING FOR ITSELF. docs/42 introduced that key to make a rotation comparable at all. It turns out to also be the thing that bounds the size of every document written against this vocabulary, which is a second job nobody designed it for." what-the-measurement-does-not-say "THE GRID IS SYNTHETIC AND SMOOTH, so it compresses better than a scan would, and it carries positions and indices and nothing else — a real asset has normals and texture coordinates, which are more numbers and would move the ratio. The comparison is also against a raw buffer rather than against Draco or meshopt, which beat both forms and are lossy in ways this vocabulary would have to declare. A REAL CONVERTED ASSET IS STILL THE MEASUREMENT THAT SETTLES IT. What this one establishes is that the answer is a ratio near two rather than near ten, which is what `could sink the design` would have looked like." w7-the-typed-array-arrived-after-both-vocabularies-were-written "AND IT IS WORTH MORE TO THIS ONE THAN THE GENERAL CASE SUGGESTS. The kernel gained a typed array on 2026-09-02; these vocabularies were written before it existed and neither mentioned it. THE TRANSCRIPT IS THE PLACE IT COSTS NOTHING TO TAKE. Every number in it has already been rounded onto the document's declared :precision, so each is an exact integer count of quanta — the decimal form was that integer multiplied back out. Writing the integer is not a representation choice over the values; it is the same values, encoded as what they are. AND A TRANSCRIPT IS NEVER READ BY A PERSON DECIDING WHERE A VERTEX IS, which is the argument that does not reach it and does reach a document. That asymmetry is why this was adopted and why the document encoding is recorded as an open question in @vocab/spatial/v0 rather than settled alongside it." typed-array-measurements [ | transcript "decimals" "typed arrays" saved | "the arm scene" "2,016" "1,999" "1% — six instances and one five-vertex mesh, so there is almost nothing to pack" | "the fox scene" "91,990" "38,466" "58%" | "the DamagedHelmet scene" "1,051,481" "559,040" "47%, which puts it BELOW the 560,692 bytes of glTF geometry it was converted from" | "the fox walk, 17 ticks, full" "1,256,077" "651,443" "48% — the artefact docs/44 called the design's largest open risk" | "the fox walk, probes" "38,352" "37,593" "2%. A probe transcript is mostly poses, which stay decimals" ] it-was-checked-against-the-values-and-not-just-the-size "THE 10,000-VERTEX GRID was transcribed and its emitted array compared element by element against the quantised source values: 30,000 of 30,000 identical, and the index array narrowed itself to ^u16 because 9,999 fits. The change is a representation of the same numbers and the check says so rather than the commit message." what-was-verified [ | claim how | "the frame answer is right" "the hand-computed flange position — 0.138 − 0.131 + 0.127 and 0.1625 + 0.425 + 0.392 — is what the writer reports, and the document asserts it as its own check" | "the document's checks run" "three in the scene, all passing; two in the take, of which one runs and one is reported as not run" | "the pin is checked rather than trusted" "the take carries a sha256 over the scene's canonical CBOR, and the writer refuses a take whose digest does not match the bytes" | "the transcript is deterministic" "two runs produce the same 47,352 bytes and the same digest. That is not a proof — it is one implementation agreeing with itself" ] one-implementation-agreeing-with-itself-is-not-conformance "SAID PLAINLY, because it is the limit of what this document establishes. The equality claims that TWO consumers agree, and there is one. Everything below the quantisation — the composition order, the attribute ordering, the rounding rule — is specified precisely enough that a second implementation should land on the same bytes, and nothing here demonstrates that it does. THE SECOND IMPLEMENTATION IS THE REAL TEST, and it is what @vocab/graphic/v0 got from another repository and called its strongest evidence." next [ | step why | "tools/spcheck — the gate" "this writer checks what it must in order to resolve at all. The refusals tables are still owed a checker, and every rule in them is a lookup or arithmetic" | "a converter, and the mesh measurement" "the only step that can still sink the design, and the one docs/42 could not do either" | "a second transcript writer, by somebody else" "one implementation agreeing with itself is not conformance" | "the transcript's entry shape, written into the vocabulary" "it is defined by this tool today, which is the wrong place for it: a canonical form that lives in a program is a canonical form the next implementer reverse-engineers" ] }