feat(gfql/cypher): EXISTS { pattern } subqueries — declarative prune-isolated, native on 4 engines#1679
Merged
Merged
Conversation
lmeyerov
commented
Jul 5, 2026
| inside ``GRAPH { }`` pipelines. For prune-isolated in GRAPH STATE (nodes AND | ||
| edges back), use edge patterns instead: ``GRAPH { MATCH (a)-[e]-(b) }`` keeps | ||
| every edge-touching node with ALL its edges (self-loops included); add | ||
| ``WHERE a.id <> b.id`` for the drop-self-loop variant. |
Contributor
Author
There was a problem hiding this comment.
there is probably fuzzing & tck repo work we should do across the pr's
lmeyerov
commented
Jul 5, 2026
| out.append(WherePatternPredicate( | ||
| pattern=cur.pattern, span=cur.span, negated=False, | ||
| pattern_origin=getattr(cur, "pattern_origin", "bare"), | ||
| pattern_neq=getattr(cur, "pattern_neq", None))) |
Contributor
Author
There was a problem hiding this comment.
avoid dynamic typing patterns
lmeyerov
commented
Jul 5, 2026
| pattern_preds.append(WherePatternPredicate( | ||
| pattern=leaf.pattern, span=leaf.span, negated=False, | ||
| pattern_origin=getattr(leaf, "pattern_origin", "bare"), | ||
| pattern_neq=getattr(leaf, "pattern_neq", None))) |
Contributor
Author
There was a problem hiding this comment.
avoid dynami typin gpatterns here too
0bc4743 to
6e4f0c6
Compare
2f478fc to
72b2e19
Compare
6e4f0c6 to
3e2c0ea
Compare
2e7f20f to
c0a8c1f
Compare
lmeyerov
commented
Jul 5, 2026
3e2c0ea to
ccd440e
Compare
lmeyerov
added a commit
that referenced
this pull request
Jul 5, 2026
#1682's test_every_grammar_rule_is_exercised_by_the_corpus requires every grammar rule to appear in DIFFERENTIAL_CORPUS. #1679's exists_subquery_atom rule needs coverage — add representative EXISTS / NOT EXISTS queries (single Earley derivation, so the semantic-ambiguity invariant still holds). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c0a8c1f to
08c1e01
Compare
lmeyerov
commented
Jul 5, 2026
… pattern-existence)
EXISTS_SUBQUERY token + ?primary rule + transformer emitting the SAME
BooleanExpr(op='pattern') leaf as bare pattern predicates — the entire existing
lift/marker/semi-apply lowering applies unchanged (NOT EXISTS -> anti_semi_apply).
Pre-scan: not((..)) spellings + RETURN/WITH-position exists{} keep the clean
fail-fast; WHERE position now parses. v1 declines (clear E108): inner WHERE,
multi-pattern bodies, MATCH..RETURN bodies. dgx: lowering 1192 pass; pandas+cudf
end-to-end (NOT EXISTS{(n)--()} = isolated nodes); polars honest-NIE (native in
the next commit).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing_ops) — EXISTS runs on all 4 engines Key sets via chain_polars named-flag columns (the backward prune makes the flag exactly 'a full pattern match exists through this node'); order-preserving is_in (no join reorders; null keys match pandas merge-no-match semantics); single-Node rows(binding_ops) mirrors the pandas alias-lookup-frame layout. v1 bounds (honest NIE): multi-alias correlation, non-[Node,Edge,Node] shapes, node query=. Matrix EXISTS cases (4-engine parity-or-NIE) + ledger waiver text updated to native status. dgx: 1991 passed full lane; EXISTS/NOT-EXISTS parity pandas==cudf==polars. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…} on all 4 engines Existential locals allowed for EXISTS-origin pattern leaves (bindings project them away; bare predicates keep the conservative guard); the ONE supported inner-WHERE form = endpoint inequality, carried as neq= on semi_apply_mark/anti_semi_apply (safelisted): pandas/cuDF filter the bindings table; polars pre-drops self-loop edges (a non-self edge IS the m<>n witness). Matrix: both panel-algebra §3 prune-isolated flavors oracle-pinned on a self-loop-only discriminator node, 4-engine parity-or-NIE. dgx: 1992 passed full lane + lowering 1193. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…steer)
GRAPH{}+EXISTS was SILENTLY DROPPING the filter (dgx-repro'd all-nodes wrong
answer) -> fail-fast pointing at the working pattern; THE viz graph-shape
patterns pinned 4-engine: GRAPH { MATCH (a)-[e]-(b) } = keep-self prune-isolated
w/ FULL graph, + WHERE a.id <> b.id = drop-self (pre-existing cudf same-path
TypeError documented+tolerated). Wave-1: masked keyword scans in EXISTS bodies
(property strings no longer falsely decline); safelist neq = exactly-2 pair;
alias==node_id + chain-validation + null-key declines; pandas name-flag-leak
mirrored (alias.alias col); native-must + multi-alias-NIE + self-alias pins;
reject-pin tests flipped (parser/policy); tck mirror branch updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…des, decline-branch pins Gate anchored to query start (grammar admits constructors only there — n.graph property no longer false-positives); start-nodes normalized eager (lazy join silently declined the wavefront case); pins: property-string keyword masking, n.graph acceptance, neq exactly-2 validation (E201), endpoint-mismatch decline, 9 direct-call decline shapes (changed-line coverage gate); tck mirror: manifest reason synced. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s, local-binding narrowing (Leo steer) pattern_origin/pattern_neq getattr was self-inflicted (fields declared by this branch) -> direct access; PatternElement.variable declared on both members; n0/edge_op/n2 local binding (mypy narrows locals, not ops[i]) -> direct ASTNode/ASTEdge fields; isinstance(pl.LazyFrame) over hasattr(collect); _rows_base_graph() typed accessor contains the one sanctioned threading read; _node Optional-narrowing; chain required params direct-indexed (safelist- validated). 20 sites; audit research/dynamic-patterns-audit-L1.md (5 L kept, 4 M + broad-except narrowing recorded as follow-ups). dgx 1994+1344 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…module-per-family, Leo steer) row_pipeline.py is the expression/projection lowering core; feature families get their own modules (degrees.py precedent). Pure move + import updates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… split) The gfql-polars audit fails any resolved target file missing from the baseline (coverage_audit.py); the module-per-family split moved the pattern- existence lowerings out of row_pipeline.py into pattern_apply.py without a floor. dgx-measured 75.36% on the CI-verbatim CPU polars lane (identical on this tree and the L2 tree); floor 67.0 per the file's ~8-below convention. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#1682's test_every_grammar_rule_is_exercised_by_the_corpus requires every grammar rule to appear in DIFFERENTIAL_CORPUS. #1679's exists_subquery_atom rule needs coverage — add representative EXISTS / NOT EXISTS queries (single Earley derivation, so the semantic-ambiguity invariant still holds). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Any]] in pattern_apply The semi-apply family's binding_ops carry the serialized-AST shape the rest of the codebase already types as Dict[str, Any] (ast.py serialize_binding_ops, row/pipeline.py). Match that; import Dict. Annotation-only, no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
08c1e01 to
889f59e
Compare
…ct / pl.DataFrame (no Any) Replace the placeholder Any with the codebase's real types: serialized binding ops are Dict[str, JSONVal] (the JSON type ASTSerializable.to_json/from_json use, not Dict[str, Any]); _binding_ast_ops returns List[ASTObject]; the pattern key-set helper returns Optional[pl.DataFrame] and _semi_apply_join_col takes a pl.DataFrame. Any dropped from the imports. Annotation-only; mypy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Implements
EXISTS { <pattern> }pattern-existence subqueries (openCypher-standard) in WHERE position, native on all four engines (pandas/cuDF/polars/polars-gpu) — the declarative prune-isolated building block for the streamgl-viz filter pipeline (frozen semantics: the panel-algebra doc, viz-filter L1). Stacked on #1677.What's added
EXISTS { <pattern> }/NOT EXISTS { ... }in WHERE. The body parses into the SAMEBooleanExpr(op="pattern")leaf as a bare pattern predicate — zero new lowering machinery;NOTcomposes through the existing lift intoanti_semi_apply. Inline block comments and property maps ({w: 1}) inside the pattern work. RETURN/WITH-positionEXISTSand thenot((a)--(b))spellings keep their clean fail-fast.EXISTS { (n)--(m) }withmunbound outside) — the correlated bindings project them away. Bare pattern predicates keep the conservative no-new-aliases guard.WHEREform is endpoint inequality —EXISTS { (n)--(m) WHERE m <> n }("has a neighbor other than itself"). Carried as a safelistedneq=param on the semi-apply ops: pandas/cuDF filter the correlated bindings table; polars excludes self-loop edges (exactly them <> nwitness for a single-edge pattern).semi_apply_mark/anti_semi_apply(correlated key sets via the polars chain executor's named-flag columns — the backward prune makes the flag exactly "a full pattern match exists through this node"; order-preservingis_ininstead of joins, null keys matching pandas merge semantics) androws(binding_ops=...)for the single-entity row table (mirrors the pandas alias-lookup-frame layout). v1 declines honestly: multi-alias correlation, non-single-hop shapes,query=nodes.Prune-isolated, declaratively (the point)
Both flavors are oracle-pinned in the conformance matrix on a discriminator graph (an isolated node + a self-loop-only node), 4-engine parity-or-NIE.
Tests / verification (dgx GB10,
--gpus all)Full polars lane + conformance matrix + GPU suite + row-pipeline ops = 2082 passed, 0 failed (final tip); cypher lowering suite 1193+ passed (EXISTS marker-shape parity with bare patterns, NOT→anti, neq threading, boundary declines). End-to-end sanity:
NOT EXISTS {(n)--()}returns exactly the isolated node on pandas == cuDF == polars. Conformance-ledger waiver text updated to native status (join_applyremains the honest-NIE waiver). ruff + mypy clean.Honest boundaries (clear errors, no wrong answers)
EXISTSin RETURN/WITH projections; general innerWHEREclauses; multi-pattern bodies; fullMATCH..RETURNsubquery bodies; multi-alias correlation on polars (pandas/cuDF handle it via the pre-existing bindings machinery).Review hardening (3-wave converged adversarial review, 2026-07-05)
Findings-mode review (artifacts:
plans/viz-filter-pipeline/waves/pr1679/) found and fixed, dgx-verified:GRAPH { }+EXISTSwas silently dropping the filter (all engines — now fails fast, anchored to the grammar's constructor-at-start rule with zero false positives proven); the working graph-state prune patterns are pinned 4-engine per the graph-shape acceptance requirement (GRAPH { MATCH (a)-[e]-(b) }keep-self with ALL edges;+ WHERE a.id <> b.iddrop-self); EXISTS-body keyword scans run on masked text (property strings like'WHERE it hurts'no longer falsely decline);neqvalidates as an exact string pair (was a late IndexError / silent first-pair filter); self-aliasEXISTS { (n)--(n) }declines instead of a non-NIE crash; null-key and alias-collision corners decline honestly; the pandas name-flag column leak is mirrored exactly; native-must/multi-alias-NIE/decline-shape pins added (changed-line coverage gate green). TCK: the openCypher existential-subquery scenarioexpr-existentialsubquery1-3is formally promoted to supported in the tck-gfql corpus (mirror branchfeat/gfql-cypher-exists);1-1tracked as a whole-entity-rendering wrong-rows debt. Waves 2–3 converged at zero BLOCKER/IMPORTANT. Known follow-up (pre-existing at base): bare pattern predicates insideGRAPH { }bodies also silently drop (row_pre_filtersunwired in the graph compiler) — L3 item.Post-convergence tip movements (structure/CI only, re-verified)
pattern_apply.pymodule split (module-per-family, per review steer): the polars semi-apply/pattern-existence lowerings move out ofrow_pipeline.pyintographistry/compute/gfql/lazy/engine/polars/pattern_apply.py— dispatch imports updated, no behavior change (dgx 1703-pass; post-rebase import-shape greps). The polars coverage-audit baseline gains the requiredpattern_apply.pyentry (floor 67.0; dgx-measured 75.36% on the CI-verbatim CPU lane, identical on this and the L2 tree) — the audit fails un-baselined target files, which was the only CI red. CI green at the final tip.🤖 Generated with Claude Code