Repository navigation
[META] Cypher binder coverage gaps blocking #1357 strict_name_resolution rollout #1371
Description
Activity
Merged: #1384 (
c9eedc47) landed the P1 slice for this meta.What landed (P1):
- Strict binder traversal-order fix in
FrontendBinder._bind_graph_sequenceso post-WITHUNWINDresolves WITH-projected aliases in source order. - Scoped to
strict_name_resolution=Truepath to avoid changing loose/runtime behavior during staged rollout. - Test amplification included:
- strict post-WITH UNWIND alias resolution
- multi-WITH + post-WITH UNWIND sequencing
- strict scalar-UNWIND alias rebind rejection
- baseline/parity updates removing obsolete P1 divergence pins.
PR: #1384
Remaining scope in this meta stays open for P2/P3/P4.
- Strict binder traversal-order fix in
Merged via PR #1386 on 2026-05-09.
- PR: Fix #1371 P2 strict binder comprehension-local scope #1386
- Merge commit: 4e6a186
- Scope landed: [META] Cypher binder coverage gaps blocking #1357 strict_name_resolution rollout #1371 P2 quantifier/list-comprehension strict binder scope handling
- CI: green at merge
- Changelog: added Development/Internal note for this P2 slice
Thanks all.
- added 4 commits that reference this issue
on May 9, 2026 Post-merge update for P3 (CALL/YIELD scope):\n\n- Merged: https://github.com/graphistry/pygraphistry/pull/1387\n- Merge commit: cb5eaef\n- CI: green on both push + pull_request workflows after rebase/changelog update\n\nDelivered in this slice:\n- now binds before row-sequence projection binding for row-only shapes, so strict mode resolves aliases correctly.\n- Added strict regressions for direct + aliased YIELD projections.\n- Updated with the #1371 P3 entry under Development/Internal.\n\nThis closes the P3 lane previously tracked under #1371.
Post-merge update for P3 (CALL/YIELD scope):
- Merged: fix(gfql): preserve CALL/YIELD scope through strict row bind (#1371 P3) #1387
- Merge commit: cb5eaef
- CI: green on both push + pull_request workflows after rebase/changelog update
Delivered in this slice:
FrontendBinder._bind_querynow bindsast.callbefore row-sequence projection binding for row-only shapes, so strict mode resolvesCALL ... YIELD ... RETURN ...aliases correctly.- Added strict regressions for direct + aliased YIELD projections.
- Updated
CHANGELOG.mdwith the [META] Cypher binder coverage gaps blocking #1357 strict_name_resolution rollout #1371 P3 entry under Development/Internal.
This closes the P3 lane previously tracked under #1371.
- added 6 commits that reference this issue
on May 9, 2026
Meta-issue tracking the binder coverage gaps surfaced when PR #1372 (work on #1357) ran a discovery flip of
strict_name_resolution=Trueatgraphistry/compute/gfql/cypher/lowering.py:8400and observed 75 test failures ingraphistry/tests/compute/gfql/cypher/. Most failures are false positives in strict mode — pre-existing binder limitations, not real-bugs-strict-catches. Each gap below is a separate binder fix that, once landed, unlocks one slice of the full strict flip.PR #1372 ships the safe portion of #1357 (cross-kind alias rebind guard at
_bind_node_pattern/_bind_relationship_pattern/_bind_path_alias— node↔edge, edge↔node, path↔node, path↔edge). Validator strict mode (gfql_validate(..., strict=True)) already exercises all of the below; runtime parity follows the items below.Discovery analysis:
plans/1357-binder-strict-name-resolution/research/discovery-flip-blast-radius.md(in PR #1372).Regression-pin baselines:
graphistry/tests/compute/gfql/cypher/test_binder_strict_compile_baseline.py(each parametrized case will flip from "admits" → "raises" as gaps close).Validator/runtime parity ledger:
graphistry/tests/compute/gfql/cypher/test_validator_runtime_strict_parity.py.Gaps in priority order
P1 — Post-WITH UNWIND traversal order in
_bind_graph_sequenceSymptom:
MATCH ... WITH collect(b1) AS bees UNWIND bees AS b2 MATCH ...— strict binder rejectsbeesas unresolved.Root cause:
_bind_graph_sequence(binder.py:289) iteratesast.unwindsbefore the WITH stages. The parser puts post-WITH unwinds intoast.unwinds, so the binder evaluates the UNWIND expression against pre-WITH scope.Fix: interleave UNWIND/WITH/MATCH by AST text position in
_bind_graph_sequence, or fix the parser to route post-WITH UNWINDs toast.reentry_unwinds.Why P1: every LDBC SNB IC1/IC4/IC6 shape that uses
collect(...) AS x UNWIND x AS y MATCH (...)is blocked by this — the highest-traffic shape on the benchmark lane. ~12 of the 75 failures are direct hits, plus most of the post-with-match-collect-unwind-match category (~5 more).P2 — Quantifier predicates and list comprehensions
Symptom:
MATCH (n) WHERE all(x IN n.labels WHERE x = 'A') RETURN n— strict rejectsxas unresolved.Root cause:
_infer_expression_binding(binder.py:942) does not bind comprehension-scoped locals (xinall(x IN list WHERE ...),[x IN list WHERE ... | ...]).Fix: in the strict-name-resolution unresolved-identifier check (
_unresolved_identifiersin binder.py), recognize comprehension-binder syntax (all|any|none|single|[ ... IN ... ]) and exclude the local from the unresolved set.Why P2: ~7 of 75 failures, common in WHERE clauses across many SNB shapes (IC*, BI*).
P3 — CALL/YIELD scope through prepass→normalize→bind
Symptom:
CALL graphistry.degree() YIELD nodeId RETURN nodeId— strict rejectsnodeIdin RETURN.Root cause:
_bind_call_clause(binder.py:561) populates the scope fromclause.yield_items, but the post-normalize bind path may receive a normalized AST shape that drops the YIELD aliases before re-binding. Need to verify and fix the cycle.Fix: ensure YIELD aliases survive prepass→
ASTNormalizer→bind. Likely a normalizer-side fix (don't strip YIELD context on rewrite).Why P3: ~4 of 75 failures, narrow to graphistry.* / cugraph.* CALL paths.
P4 — Namespaced builtin function calls
Symptom:
RETURN duration.inSeconds(localtime(), localtime()) AS duration— strict rejectsdurationas unresolved alias.Root cause:
_PROPERTY_RE.fullmatch(\"duration.inSeconds\")matches and routes through the alias-scope check; the binder does not recognizeduration.*as a builtin namespace.Fix: in
_validate_property_ref_schemaand_infer_expression_binding, short-circuit the alias-scope check when the prefix is a known builtin namespace (duration,time,date,datetime,localtime,localdatetime,point, …).Why P4: ~5 of 75 failures, isolated to temporal/duration test fixtures. Niche.
Smaller items
type(x)builtin not modeled by_infer_expression_binding(~3 failures).collect()+ range comparison (~3 failures).[x IN list | x.foo]map-comprehension form — same root cause as P2.Closure criteria
Once all four P1-P4 are landed, the post-normalize strict flip at
graphistry/compute/gfql/cypher/lowering.py:8400(FrontendBinder().bind(query, PlanContext(), strict_name_resolution=True)) becomes safe. The regression-pin baselines intest_binder_strict_compile_baseline.pywill then flip from "admits" → "raises" as the corresponding fix lands. When the file is empty (all cases moved to parity intest_validator_runtime_strict_parity.py), this meta closes alongside #1357.Related
Status (2026-05-09)
Status (2026-05-09)
4e6a18638) and closed P2 (quantifier/list comprehension strict scope).cb5eaef6a) and closed P3 (CALL/YIELD strict scope through row-sequence binding).ef6e7bf2e) and closed P4 (namespaced builtin function handling under strict binder).