Conversation
The corpus is one set of hand written YAML files in the engine's repository and every client runs the same cases against it, so a value that survives one binding and not another is a diff rather than an argument. This is the Node end of it: a reader for the YAML subset the cases are written in, a decoder for the value encoding, a reader for the Arrow schema an export carries, and a runner that reports what happened in the words the reference runner reports it in. The reader is another implementation of the format rather than a consumer of one. A client that decodes a value with the same code it encodes with passes every case it writes, so this refuses what crates/zu-corpus/src/yaml.rs refuses, with the same words and the same line numbers, and the tests are that file's own tables ported case for case. The Arrow half is read out of the bytes. This client hands out IPC rather than a C Data Interface stream, so there is no format string to read off an ArrowSchema and the schema flatbuffer at the head of the buffer is parsed instead. A flatbuffer omits any field holding the schema's declared default, which cost five cases before it was found: Int.is_signed defaults to false, so an unsigned column is written as a width and nothing else, and a reader defaulting it the other way reads every UINT64 as an INT64 and says nothing about it. Three more defaults were wrong for the same reason and are fixed with it. Two client fixes came out of running it. A negative zero bound as an INT64, which throws away the sign a caller went out of their way to write, and now binds as a FLOAT64. And a temporal column that arrived without cells reported a type whose buffer was empty: the engine's columnar sink has no arm for days, nanoseconds or months, so a date or a duration reaching a projection the wrong way comes over as the values themselves, and which of the two a statement gets is the plan's business rather than the caller's. `type` now says what arrived, so a switch on it always lands on a field that holds something. The gap itself is tamnd/zu#690. RETURN 1 AS a, 2 AS a is the one case this client cannot answer. Two columns of one name is a legal result and a row keyed by name has one of them, so the runner reports it unsupported, by name and with the reason, rather than passing it on a value invented for the occasion or failing it as though the engine had got something wrong. The pin moves to 526ac58, which brings BYTES as a real type and ten new reserved words. BYTES is a Uint8Array both ways and a bytes column in a columnar read, and the tests that used on, at, number, nothing, record, small, count, big, day or exact as an alias or a label are renamed. 1412 cases, 1411 passed, 0 failed, 1 unsupported.
Four things went red on CI that are nothing to do with the corpus itself, and all four are the same kind of mistake: a test or a lint that held on the machine it was written on and nowhere else. Clippy on the newer toolchain wants as_chunks where the code says chunks_exact and then unwraps a try_into back into the array it already had. The new form drops the expect entirely, since the array size is in the type. Two call sites in frame.rs and one in load.rs. The two tests that ask whether a big read leaves the event loop free counted ticks against a fixed bar of one every ten milliseconds. That bar reads as a property of the code and is really a property of the platform. Windows fires a timer on its own clock tick of about sixteen milliseconds, so a sixty millisecond read gets four ticks with the loop completely idle and the test fails on a loop that was never blocked. Both now measure what an idle loop on this machine manages first, in test/helper.mjs, and ask for a fifth of it. That is still a hundred times what a loop parked inside the addon would give, so the test catches what it was written to catch, and it moves with the load on the machine rather than flaking under it. The watch test that spawns a copy of the runtime is skipped on Deno. Deno needs --allow-run to spawn at all, and a Deno child inherits none of its parent's permissions, so the copy fails to open the library rather than failing to exit. That is not the question the test asks.
This was referenced Aug 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The corpus is one set of hand written YAML files in the engine's repository, under
conformance/cases. Every client reads the same files and runs the same statements, so a value that survives one binding and not another is a diff rather than an argument. This is the Node end of it: a reader for the YAML subset the cases are written in, a decoder for the value encoding, a reader for the Arrow schema an export carries, and a runner that reports what happened in the words the reference runner reports it in.It is a development tool and not part of the package.
filesinpackage.jsonlists what ships andconformanceis not among them, so it is there when the repository is checked out and absent whenzudbis installed.The reader is a second opinion and not a consumer
A client that decodes a value with the same code it encodes with passes every case it writes, because the case and the answer both went through one decoder. So
conformance/reader.mjsrefuses whatcrates/zu-corpus/src/yaml.rsrefuses, with the same words and the same line numbers, and the tests are that file's own tables ported case for case. There is no YAML dependency, which would read these files and a good deal more besides, and would hand back9223372036854775807as a float on the way.conformance/temporal.mjsspells the four accepted temporal forms out rather than callingDate.parse, which reads2024-1-1andJan 1 2024and is allowed by its own specification to read anything else it likes.The Arrow half is read out of the bytes
This client hands out Arrow IPC rather than a C Data Interface stream, so there is no
ArrowSchemato walk and noformatstring to read off one.conformance/arrow.mjsparses the schema flatbuffer at the head of the buffer and turns each field back into the format string a case is written in.A flatbuffer omits any field holding the schema's declared default, which is the trap and which cost five cases before it was found.
Int.is_signeddefaults to false, so an unsigned column is written as a width and nothing else, and a reader defaulting it the other way reads every UINT64 as an INT64 and says nothing about it.FloatingPoint.precision,Time.unitandDuration.unitwere wrong for the same reason and are fixed with it.test/conformance-arrow.test.mjsnow pins the unsigned case against bytes the addon really produced, rather than against a buffer written by hand, which would only prove the reader agrees with whoever wrote the buffer.Two client fixes it found
A negative zero bound as an INT64. There is no INT64 that is negative zero, so binding it as one throws away the sign a caller went out of their way to write, and a statement comparing it against a FLOAT64
-0.0then compares against0instead. It binds as a FLOAT64 now.A temporal column that arrived without cells reported a type whose buffer was empty. The engine's columnar sink has no arm for days, nanoseconds or months, so a date, a time or a duration reaching a projection the wrong way comes over as the values themselves, and which of the two a statement gets is the plan's business rather than the caller's: the same property is cells in one statement and values in another, and adding an unrelated boolean column to the projection is enough to move it.
typeon a column is what arrived now rather than what the statement declared, so a column that came over as values readsvaluewith its dates initems, andunitandzoneare null because there are no cells for them to describe. A column sayingdatewith nothing invalueswould be a switch that lands nowhere, and the whole point oftypeis that the switch is one string comparison. The engine side is tamnd/zu#690, and the test pins the invariant rather than the shape, so it still passes on the day the engine fills a buffer for every one.What this client cannot answer
result/the-same-name-twice, which isRETURN 1 AS a, 2 AS a. Two columns of one name is a legal result and this client hands a row back as a plain object keyed by column name, where the second would silently replace the first. The runner reports it unsupported, by name and with the reason in the line, rather than passing it on a value invented for the occasion or failing it as though the engine had got something wrong. Unsupported is a third outcome and not a softer kind of failure: a case the corpus wrote on purpose to catch a mapping cost is a case a client should be able to say out loud it cannot answer.The pin
526ac58, up from0698a4ec. It brings BYTES as a real type, which is aUint8Arrayboth ways and abytescolumn in a columnar read, and it brings ten new reserved words. The tests that usedon,at,number,nothing,record,small,count,big,dayorexactas an alias or a label are renamed.CI
A
corpusjob that reads the revision out ofCargo.toml, checks the engine out at it, and runs both the report and the tests against the cases it finds. The revision is not written down a second time, so it cannot drift from the pin this client already builds against.Checks
node --test "test/*.test.mjs"is 451 tests, 442 passing and 9 skipped, the skipped being the corpus tests that wantZU_CASES.cargo fmt --check,tsc --noEmitandapi-extractor runare all clean. The corpus report is the line above.