EventReader.next(), both initializers, and the Event alias are public
(an internal typealias in a split file had been shadowing the public
Parsing.Event); a new PureXMLPublicAPITests target compiles without
testable import so facade gaps fail CI. The large-corpus benchmarks
exposed document-order sorting as quadratic on flat fan-outs; the fix's
first attempt was itself worse (an eager sibling table built per
predicate evaluation), caught by sampling the live run, and replaced
with a lazy table: single-node sets never touch order keys and a
parent's table builds on its second lookup. XPath at 42 MB drops
27.1 s to 1.57 s (190x to 11.7x); at 210 MB PureXML completes in 9.4 s
the query libxml2 refuses at its 10M node-set cap (#143 tracks our
configurable budget). Benchmark harness: size series to 210 MB, CORPUS
mode for real files (NASA, SwissProt measured), SAX stage,
refusal-aware table, NULL-safe C driver. All conformance suites,
Linux, and WASM verified. Closes#142.
scripts/benchmark.sh generates a deterministic corpus, builds PureXML
in release and a C driver against the SDK's libxml2, times parse,
serialize, and XPath over the same bytes (best-of-N, internal timing,
IO excluded), cross-checks the same XPath count on both sides, and
prints the comparison. First honest baseline recorded in
docs/benchmarks.md: parse ~30x, xpath ~36x, serialize ~5x slower than
libxml2 on a 4.2 MB corpus; these are the numbers #139's optimization
passes burn down. The SAX stage isolation is blocked on #142 (the
public streaming surface is internal, found by this harness).