fix(cypher): expansion materializes every matched row — the cap falsified aggregates (#1196) - #1698
Merged
Merged
Conversation
…fied aggregates Second mechanism of #1196, exposed by the reporter's v0.10.6 retest: every relationship-expansion site capped its output buffer at bind_cap*10, so edges past the cap were silently dropped BEFORE WHERE and aggregation ever ran. count() then reported the scanned prefix as if it were a fact — 9,360 of 13,691 DEFINES field-measured at --max-rows 1000 — and a LABEL on the source did not protect you (the label workaround only ever fixed source enumeration, which #1323 already made exact). max_rows is an output-row limit per the public header; projection already enforces it. All five capped sites now share one growable append (geometric growth, size_t sizing): the per-hop expansion, its fixed/variable-length helpers and process_edges, the bound-terminal driver, and the cross-join outer buffer. Only allocation failure stops materialisation; match_count stays truthful either way, so the #627 OPTIONAL contracts hold (a saturated buffer can no longer exist, and the fallback rows share the same append). The #601 deadline still bounds pathological time, and hop caps keep bounding depth — this removes only the silent row-dropping. Regression test: 2 labeled sources x 30 edges with max_rows=2 — the old cap returned count=20; ground truth 60 now holds, and the list form returns exactly max_rows rows. Proven RED before and RED again on revert; cypher 181/181 and mcp suites green, including every OPTIONAL/#627 semantics test. Fixes #1196 (together with #1323, which fixed the unlabeled source scan). Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
DeusData
force-pushed
the
fix/1196-aggregate-scan-truncation
branch
from
August 18, 2026 09:21
a13dc75 to
58ef9f1
Compare
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.
Second mechanism of #1196, exposed by the reporter's v0.10.6 retest: every
relationship-expansion site capped its output buffer at bind_cap*10, so edges
past the cap were silently dropped BEFORE WHERE and aggregation ever ran.
count() then reported the scanned prefix as if it were a fact — 9,360 of
13,691 DEFINES field-measured at --max-rows 1000 — and a LABEL on the source
did not protect you (the label workaround only ever fixed source
enumeration, which #1323 already made exact). max_rows is an output-row
limit per the public header; projection already enforces it.
All five capped sites now share one growable append (geometric growth,
size_t sizing): the per-hop expansion, its fixed/variable-length helpers and
process_edges, the bound-terminal driver, and the cross-join outer buffer.
Only allocation failure stops materialisation; match_count stays truthful
either way, so the #627 OPTIONAL contracts hold (a saturated buffer can no
longer exist, and the fallback rows share the same append). The #601
deadline still bounds pathological time, and hop caps keep bounding depth —
this removes only the silent row-dropping.
Regression test: 2 labeled sources x 30 edges with max_rows=2 — the old cap
returned count=20; ground truth 60 now holds, and the list form returns
exactly max_rows rows. Proven RED before and RED again on revert; cypher
181/181 and mcp suites green, including every OPTIONAL/#627 semantics test.
Fixes #1196 (together with #1323, which fixed the unlabeled source scan).
Signed-off-by: Martin Vogel martin.vogel.tech@gmail.com
🤖 Generated with Claude Code
https://claude.ai/code/session_018RiRAw9RQhvCoshqe7eZHV