Repository navigation
docs(gfql): publish the traceable q1-q9 board and rewrite the prose around it - #1815
Conversation
…te the rest
Two published OLAP ratios are not stale, they are wrong. `gfql/performance.rst`
published q8 at "5.0 ms vs 1,004 ms for embedded Kuzu (200x)"; a matched,
row-validated re-run measures 5.06 ms vs 9.76 ms = 1.93x. It published q9 at
14.2x; measured, 66.61 vs 84.06 = 1.26x.
An audit of every other published performance figure found most of them can be
neither confirmed nor refuted: the reproducers wrote to /tmp or only printed,
recorded no commit/host/timestamp, and their artifacts were never committed.
Two are worse than unverifiable - the LadybugDB competitor column was a
hardcoded `LADYBUG = {...}` literal with no citation, and the filter->PageRank
SVG charts are generated from a results directory that has never existed in any
commit. All of it is removed rather than restated.
The mechanism that stops it recurring ships with the deletion: a single
generated source of truth (docs/source/_data/gfql_benchmarks.json), a Sphinx
extension that resolves `:bench:` against it and fails the build on a missing,
stale, non-quotable or undisclosed number, and a standalone gate that adds
commit-drift and hand-typed-literal checks.
Deletion and mechanism only - no editorial rewriting. The prose rewrite is a
separate PR.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015YsqAZQLbqjSDrYSFz2GoB
…round it The editorial half of the #1806 split. It publishes the one benchmark board that traces cell-by-cell to committed artifacts, and rewrites the prose that the deletions left behind. Two lanes, each named where it is stated: GFQL-Polars beats GFQL-pandas on all nine queries of the graph-benchmark q1-q9 Cypher suite at both sizes measured, with every per-query speedup larger on the bigger graph; and on the 100,000-person lane GFQL with engine='polars' answers five of the nine queries faster than embedded Kuzu 0.11.3. The page says which engine, which size, which suite, and that it is five of nine. engines.rst's vendor table is reorganized from "where each tool wins" into "what GFQL gives you when the query runs here". Pages with no publishable figures now state that the lane is unpublished until it runs under the provenance-carrying harness, rather than narrating what used to be there. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015YsqAZQLbqjSDrYSFz2GoB
|
CI note —
#1813 does not hit this: it adds For this PR the same build was run locally via the identical Worth fixing in |
… lane Merge origin/master (8764eb8) and re-point the board at receipts: - Withdraw every citation of results/graphbench-matched-q1q9-20260726 (both 20k and 100k runs): the lane carries no receipts and is nonreproducible. Its runs and cells leave gfql_benchmarks.json, and the restored q9 66.6/84.1 ms cell leaves gfql/performance.rst. - Publish the receipted 20k lane results/graphbench-board-20k-20260802 (pygraphistry 8764eb8, 4 position-balanced slots x 51 runs after 5 warmups, host-load/spike receipts, row-set-validated cells) as a full nine-row board: 5 wins, 2 ties, 2 losses for GFQL-Polars vs embedded Kuzu, q4/q5 flagged WEAK (overlapping slot ranges) in data and prose, plus the comparator's compare.txt table transcribed verbatim. - Leave every 100k cell as an explicit pending marker for the lane running 2026-08-02 (results/graphbench-board-100k-v2-20260802). - engines.rst drops "both sizes measured" / "gap grows with size" until the 100k lane republishes them; vendor rows stay qualitative. - Adopt master's landed bench-data infra (_ext, contract, pytest gate); drop the branch's superseded bin/check_bench_numbers.py. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_011AB4RZpph3uSFUpzKnZJcr
|
Refreshed onto today's receipted lanes ( Cut (nonreproducible)Every number from
Replaced by: the receipted 20k board
5W / 2T / 2L. The two losses (q4 weak, q8 clear at ~3x) are printed with the same weight as the wins; q4/q5 WEAK flags travel as disclosures in the published data, so the page cannot render those ratios without the caveat. One provenance note: the lane's Pending (not filled in)The 100k lane is running today. Every 100k cell is an explicit "pending: lane running 2026-08-02" marker pointing at Merge notes
🤖 Generated with Claude Code |
results/graphbench-board-100k-v2-20260802 sealed VALID (pygraphistry 8764eb8, pyg-bench 7dca9392 per SOURCE_COMMITS; 4 position-balanced slots x 51 runs after 5 warmups; 263 receipted spike seconds): - 100k board published: 6 wins, 2 ties, 1 loss for GFQL-Polars vs embedded Kuzu, no weak verdicts; comparator table transcribed verbatim; cells added to gfql_benchmarks.json as :bench: references. - Pending markers removed; cross-scale reading added: q8 loses at both scales (comparator verdicts LOSE 2.94x / LOSE 2.44x), q4 flips from weak 20k loss to clean 100k win, Polars beats pandas on all nine queries at both scales with a wider gap on the larger graph. - engines.rst restores "both sizes measured" / "gap grows with size", now citing the receipted boards. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_011AB4RZpph3uSFUpzKnZJcr
|
100k lane sealed VALID — pending markers replaced with the receipted board (
100k board: 6W / 2T / 1L, no weak verdicts. Stated plainly on the page:
Both boards render from Verified again: 🤖 Generated with Claude Code |
Owner review on #1815: - The board section now leads with the receipts-grounded topline: GFQL-Polars beats embedded Kuzu on 11 of 18 cells across the two boards (4 ties, 3 losses; wins reaching 6.29x), exceptions are ties and losses on small point-lookup-shaped work (q8 loses at both scales; q4's loss is weak and 20k-only, flipping to a win at 100k), and the ratio moves further toward GFQL from 20k to 100k on eight of nine queries (q5 slips from narrow win to tie). Neo4j is folded in only through evidence the docs carry: the on-page LDBC SNB pairs (four of five to GFQL) and the receipted filter->PageRank->filter pipeline page. - All previous-version/withdrawal prose is cut from the pages: the July-lane withdrawal paragraphs and the "until rerun" clause. Docs state current facts; the history stays in the changelog and PR. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_011AB4RZpph3uSFUpzKnZJcr
|
Review revisions applied ( 1. Archaeology cut. All previous-version/withdrawal prose is gone from the pages: the "Earlier q8/q9 figures from the July lane are withdrawn..." paragraph, the "No number from any earlier 100k run appears on this page..." paragraph, and the bulk-sweep "until rerun on a current tag" clause. A sweep for withdrawn / earlier figures / July lane / supersedes / the old results-dir name across every touched page comes back clean. The history lives in CHANGELOG.md and this PR, not on the pages. 2. Topline up front. The board section now opens with:
Notes on grounding: the 6.29x renders from the Verified again: 🤖 Generated with Claude Code |
What this PR is for
#1813 makes the public docs not-wrong by deleting. This one makes them good: it publishes the one board that traces cell-by-cell to committed artifacts, and rewrites the prose the deletions left behind.
What is now published, and with what scope
Two lanes from the matched, row-validated
prrao87/graph-benchmarkq1–q9 Cypher suite, measured on a quiet, perf-locked dgx-spark with position-balanced slots. Every value is a:bench:reference resolved fromdocs/source/_data/gfql_benchmarks.json; no figure on the page is typed by hand, and the gate from #1813 fails the build if that stops being true.engine='polars'answers five of the nine queries faster than embedded Kuzu 0.11.3 — q1 3.63×, q2 5.06×, q3 1.95×, q8 1.93×, q9 1.26×, with both sides' medians shown.The page states, in the body text next to the table, that this is the q1–q9 suite at 100,000 persons, on
engine='polars', against Kuzu 0.11.3, warm medians, rows validated per cell, and that it is five of the nine queries in that suite at that size — not a claim about every query, every engine, or every size.Full provenance for both runs (date, host, perf lock, quiet host, rep protocol, pygraphistry commit, pyg-bench commit, runtime image, dataset, competitor version, raw artifact path) renders on the page from the source of truth, and the build fails if a page publishes a number without it.
Prose changes
engines.rst's vendor table is reorganized from "where each tool wins / where it complements" into "coming from X → what GFQL gives you when the query runs here". It keeps the vendor names (they are how people find this page) and drops the per-vendor commentary.engines.rst's engine bullets now describe each engine's architecture and the shape it is built for, instead of asserting head-to-head wins that no surviving measurement supports.[F1]cites the published board.indexing.rst,index_adjacency.rst,benchmark_filter_pagerank.rst— now say plainly that the lane's numbers are not published until it runs under the provenance-carrying harness. They no longer narrate what used to be on the page.performance.rst(top level) replaces "can become dramatically faster" with the actual mechanism and a link to the measured numbers. An intensifier with no evidence behind it is the slop guide's DON'T Report server-side ETL errors to client #9.Where the stance and the provenance rule pulled against each other
Three places, and how each was resolved. Flagging them because the resolution is a judgement call, not a mechanical one.
We lose six of nine at 20k and win five of nine at 100k. Selecting which lane to publish is allowed; implying a win in a lane we lose is not. Resolution: publish the 100k lane, name it in the sentence that makes the claim, say "five of the nine", and say explicitly that the four queries not listed are not published here. The 20k lane still appears — but only in the pandas-vs-Polars table, where GFQL wins every cell, and it is labelled as the 20k column. There is no sentence a reader can take as "GFQL beats Kuzu", full stop.
The stance says do not concede Neo4j's concurrency and durability, because they are achievable with GFQL. I removed the concessions ("Neo4j remains the transactional system-of-record", "keep Neo4j or Kuzu as the system-of-record"). I did not replace them with a positive GFQL durability/concurrency claim, because I have no documentation or measurement to point at for one. The page is now silent on that axis. If there is a supportable claim to make there, it needs a source before it goes in; silence was the only option that satisfied both rules.
The stance says no history, but the withdrawals are provenance information. The per-page "these figures have been withdrawn" tombstones from docs(gfql): publish benchmark numbers from a provenance-carrying source of truth #1806 are gone; each page instead states forward-looking policy — this lane's numbers are not published until it runs under the harness. The withdrawal itself is recorded permanently in
CHANGELOG.md(in docs(gfql): delete refuted and unverifiable benchmark numbers, and gate the rest #1813) rather than repeated on six pages. Nothing is being hidden: no claim is made, and the reason no claim is made is on the page.One thing I could not find a truthful framing for, so it is simply absent: there is no publishable "GFQL vs Neo4j" latency comparison at all right now.
engines.rstsays what GFQL gives you structurally on that row (one in-process call, no projection, no write-back) and points at the pipeline description. It does not imply a latency win.Deliberately out of scope
benchmark_graphframes.rstis untouched. Its numbers are verifiable — raw results are committed and every headline cell round-trips — but it contains statements the stance would change (e.g. where CPU PageRank via igraph trails GraphFrames), and editing a verified benchmark page's conclusions deserves its own review. Follow-up: bring it under the gate first, then revisit the prose.demos/gfql/benchmark_filter_pagerank_cpu_gpu.ipynbrenders the same withdrawn pipeline figures from the same missing results directory. Noted in docs(gfql): delete refuted and unverifiable benchmark numbers, and gate the rest #1813; a notebook rewrite is separate work.Verification
bin/lint.shclean.rstcheckclean on every edited.rst.bin/check_bench_numbers.py— reference integrity, freshness, hand-typed literals, and commit drift all pass.docs/ci.shbuild (the same onetest-docsruns) exits 0, with 0gfql-benchwarnings; rendered HTML spot-checked for every published cell and both provenance blocks.🤖 Generated with Claude Code
https://claude.ai/code/session_015YsqAZQLbqjSDrYSFz2GoB