You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(gfql): two-tier pass execution — Tier 1 structural + Tier 2 fixed-point loop (#1189)
Extend PassManager to support two explicit pass tiers:
- Tier 1 (structural): each pass runs exactly once in configured order
- Tier 2 (rewrite): all passes repeat in a fixed-point loop until a full
sweep produces no changes, bounded by max_iterations (default 100)
PassResult gains `changed: bool = True` for Tier 2 convergence signalling.
Default True preserves backward compatibility for passes that predate
two-tier semantics.
Add UnnestApply as Tier 1 structural pass: rewrites non-correlated Apply
nodes (correlation_vars == frozenset()) to Join(join_type="cross"), exposing
them to downstream join-ordering passes. Correlated Apply nodes are
left untouched.
Wire PredicatePushdownPass as the first Tier 2 rewrite rule; set
changed=pushed > 0 for correct convergence detection. Update
DEFAULT_LOGICAL_PASSES and DEFAULT_TIER2_PASSES accordingly and wire
both into _run_logical_pass_pipeline in gfql_unified.py.
19 new tests cover tier-1 ordering, tier-2 fixed-point convergence,
verifier failure propagation in both tiers, max_iterations breach,
UnnestApply rewrites, and backward-compat single-arg PassManager call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(gfql): address wave-1 review findings for two-tier pass manager (#1189)
- Remove duplicate DEFAULT_LOGICAL_PASSES/DEFAULT_TIER2_PASSES sentinel
names from manager.py (inline as ()) to prevent silent empty-pass imports
from the manager module; populated defaults remain in passes/__init__.py
- Add comment to lowering.py explaining compilation-time vs runtime pass
pipeline split and why double-application of PredicatePushdownPass is safe
- Add output_schema preservation test for UnnestApply rewrite
- Add combined smoke test: default PassManager config (UnnestApply T1 +
PredicatePushdown T2) runs without error on a plain plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(gfql): wave-2 polish — Tier 1 API in lowering.py, real integration test (#1189)
- lowering.py: use tier1_passes= (single-execution) instead of tier2_passes=
to match the "single pass at compilation time" intent; update comment
- test_unnest_apply.py: replace smoke test with real integration test that
builds Apply(Filter(PatternMatch)) and asserts UnnestApply rewrites the
outer Apply to Join and PredicatePushdownPass pushes the predicate into
PatternMatch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(gfql/passes): remove redundant compilation-time predicate pushdown from lowering.py
The PassManager call that applied PredicatePushdownPass at compile time was added before
the runtime pass pipeline in gfql_unified.py was fully wired. Now that DEFAULT_TIER2_PASSES
includes PredicatePushdownPass and _run_logical_pass_pipeline runs on every query execution,
the compilation-time application is redundant and can be removed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(gfql/passes): accumulate Tier 2 integer metadata across iterations + document slot enumeration
Tier 2 metadata previously overwrote per iteration, so final metadata showed
pushed_predicates=0 after convergence (last iteration always pushes nothing).
Now integer fields are summed across iterations so the final metadata reflects
cumulative work. Also documents that the _unnest_tree child-slot tuple is
exhaustive over all current LogicalPlan subclasses.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(gfql/tests): update test_lowering to reflect runtime-only predicate pushdown
The compilation step (lowering.py) no longer applies PredicatePushdownPass;
it now happens in the runtime pass pipeline via DEFAULT_TIER2_PASSES.
Update the test to assert the correct post-compilation state: the plan
contains a Filter node for the WHERE predicate (not yet pushed into
PatternMatch.predicates).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -32,6 +32,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
32
32
-**GFQL / Cypher public API**: `compile_cypher()`, `compile_cypher_query()`, `CompiledCypherQuery`, `CompiledCypherUnionQuery`, and `CompiledCypherProcedureCall` are deprecated and **scheduled for removal in a future release**. All emit `DeprecationWarning` at use. Migrate to `g.gfql(..., language="cypher")` for execution or `cypher_to_gfql()` / `gfql_from_cypher()` for chain translation. Tracked in #1169.
33
33
34
34
### Added
35
+
-**GFQL / two-tier pass execution**: Extended `PassManager` to support two explicit pass tiers: Tier 1 structural passes run once in configured order; Tier 2 rewrite rules run in a fixed-point loop until a full sweep makes no changes or `max_iterations` is exceeded. `PassResult` gains a `changed: bool` field (default `True` for backward compatibility) used by the convergence check. Added `UnnestApply` as the first Tier 1 structural pass — rewrites non-correlated `Apply` nodes (empty `correlation_vars`) to `Join(join_type="cross")`, exposing them to downstream join-ordering passes; correlated Apply nodes are preserved. `PredicatePushdownPass` is wired as the first Tier 2 rewrite rule and now sets `changed=pushed > 0` for correct convergence. `DEFAULT_LOGICAL_PASSES` and `DEFAULT_TIER2_PASSES` are populated accordingly and wired into `gfql()` execution. 19 new unit tests across `test_pass_manager.py` and `test_unnest_apply.py` (#1189).
35
36
-**GFQL / pass framework skeleton**: Added `graphistry/compute/gfql/passes/` with `LogicalPass`, `PassResult`, and deterministic `PassManager.run()` sequencing. The pass manager now invokes IR `verify()` after each pass and fails fast on invalid pass output. Wired a new logical-pass pipeline hook into `gfql()` execution between logical-plan and physical-planner stages using a default no-op pass configuration to preserve runtime behavior. Added focused tests for pass ordering, verifier-failure propagation, and runtime pipeline hook invocation (`test_pass_manager.py`, `test_runtime_physical_cutover.py`) (#1180).
36
37
-**GFQL / predicate pushdown safety**: Added `graphistry/compute/gfql/ir/pushdown_safety.py` with three reusable utilities for `PredicatePushdownPass`: `is_null_rejecting(pred, null_extended_aliases)` — conservative syntactic heuristic returning True when a predicate references a null-extended alias (OPTIONAL MATCH) and does not use a null-safe form (IS NULL, IS NOT NULL, COALESCE, NULLIF); `is_null_safe` — inverse; `with_barrier_blocks_pushdown(scope_stack, pred_refs)` — returns True when a WITH-clause `ScopeFrame` prevents backward predicate movement for the given reference set. All three exported from `ir/__init__.py`. 41 unit tests (#1181).
37
38
-**GFQL / predicate pushdown rewrite**: Added `PredicatePushdownPass` implementation in `graphistry/compute/gfql/passes/predicate_pushdown.py` and wired it into logical planning route execution. The pass rewrites `Filter(input=PatternMatch(...))` by pushing safe predicates into `PatternMatch.predicates`, keeps residual filters for partial-push cases, and blocks null-rejecting pushdown into optional arms using existing safety helpers. Added focused pass tests and a lowering-route integration assertion (`test_predicate_pushdown_pass.py`, `cypher/test_lowering.py`) (#1187).
0 commit comments