Skip to content

docs(gfql): publish the traceable q1-q9 board and rewrite the prose around it - #1815

Open
lmeyerov wants to merge 1 commit into
docs/bench-numbers-gate-and-deletionsfrom
docs/bench-numbers-editorial
Open

docs(gfql): publish the traceable q1-q9 board and rewrite the prose around it#1815
lmeyerov wants to merge 1 commit into
docs/bench-numbers-gate-and-deletionsfrom
docs/bench-numbers-editorial

Conversation

@lmeyerov

Copy link
Copy Markdown
Contributor

Review-only. Do not self-merge. Editorial half of the #1806 split. Stacked on #1813 (docs/bench-numbers-gate-and-deletions) — review that one first; it is mechanical and urgent, this one is not. Base it back to master after #1813 lands.

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-benchmark q1–q9 Cypher suite, measured on a quiet, perf-locked dgx-spark with position-balanced slots. Every value is a :bench: reference resolved from docs/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.

  1. GFQL-Polars beats GFQL-pandas on all nine queries, at both graph sizes. Every per-query speedup is larger on the 100k graph than on the 20k one — so the "gap grows with size" claim is shown rather than asserted. Both absolute medians and both ratios are published.
  2. On the 100,000-person lane, GFQL with 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.
  • Pages with no publishable figuresindexing.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.
  • Structure follows reader questions — one keyword, against an embedded graph database, provenance, how it is fast, how a number gets published — rather than a generic outline.

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.

  1. 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.

  2. 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.

  3. 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.rst says 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.rst is 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.ipynb renders 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.sh clean.
  • rstcheck clean on every edited .rst.
  • bin/check_bench_numbers.py — reference integrity, freshness, hand-typed literals, and commit drift all pass.
  • Dockerised docs/ci.sh build (the same one test-docs runs) exits 0, with 0 gfql-bench warnings; rendered HTML spot-checked for every published cell and both provenance blocks.

🤖 Generated with Claude Code

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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YsqAZQLbqjSDrYSFz2GoB
@lmeyerov

Copy link
Copy Markdown
Contributor Author

CI note — test-docs is SKIPPED on this PR, and that is a pre-existing gating hole, not a failure.

test-docs declares needs: [changes, python-lint-types, docs-latex-unicode-guard]. This PR changes no .py file, so python-lint-types is skipped by its path filter — and a job whose needs includes a skipped job is itself skipped, regardless of its own if:. The result is that a docs-only PR never runs the docs build in CI. That holds after a rebase onto master too, since the diff would still be docs-only.

#1813 does not hit this: it adds bin/check_bench_numbers.py, docs/source/_ext/*.py and docs/test_bench_numbers.py, so python-lint-types runs, test-docs runs, and the Dockerised -W build passes there with the gate live.

For this PR the same build was run locally via the identical docs/ci.sh script (DOCS_FORMAT=html): exit 0, 0 gfql-bench warnings, and the rendered HTML was spot-checked for every published cell and both provenance blocks.

Worth fixing in ci.yml (adding !cancelled() to test-docs's condition, or dropping python-lint-types from its needs), but that needs the workflow OAuth scope this token does not have.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant