Skip to content

feat(cypher): admit multi-prefix-row free-form intermediate MATCH (#1285)#1289

Merged
lmeyerov merged 4 commits intomasterfrom
feat/1285-freeform-multi-prefix-row
May 4, 2026
Merged

feat(cypher): admit multi-prefix-row free-form intermediate MATCH (#1285)#1289
lmeyerov merged 4 commits intomasterfrom
feat/1285-freeform-multi-prefix-row

Conversation

@lmeyerov
Copy link
Copy Markdown
Contributor

@lmeyerov lmeyerov commented May 4, 2026

Summary

Closes #1285 (LDBC SNB IC3 follow-up). Replaces the single-row-only failfast in the free-form intermediate MATCH runtime path (#1279) with a per-row union loop, admitting multi-prefix-row free-form shapes. Cartesian semantics: every prefix row × every trailing-MATCH row.

What changed

graphistry/compute/gfql_unified.py:

  • Extracted _freeform_broadcast_row_to_nodes helper from _compiled_query_freeform_reentry_state so single-row and multi-row paths share the broadcast logic.
  • Replaced the multi-row failfast with a per-row union loop in _execute_compiled_query_with_reentry, mirroring the scalar-only multi-row pattern from Cypher/GFQL: multi-alias WITH prefix projection for bounded reentry #1047. Reuses _union_scalar_reentry_results (engine-polymorphic via df_concat(engine)) for the union step.
  • Preserved optional_reentry + multi-row free-form failfast (same null-fill gap as the scalar lane's existing guard).

Tests

  • Retargeted ..._failfast_rejects_simple_freeform_intermediate_reentry_match_on_multi_row_prefix..._executes_freeform_intermediate_reentry_match_on_multi_row_prefix (positive: 2 prefix × 1 trailing = 2 rows).
  • Added ..._cartesian (2 prefix × 2 trailing = 4 rows; each (cid,did) pair appears twice; locks Cartesian semantics).
  • Added ..._on_cudf_when_available (cuDF parity).
  • Added ..._failfast_rejects_freeform_multi_row_prefix_with_optional_reentry (Wave 2 amplification — locks the scoped OPTIONAL MATCH failfast).

Existing simple (single-row) free-form admits from #1279 stay green untouched.

Receipts

Multi-wave review per agents/skills/review/SKILL.md

  • Wave 1 (DRY+quality and correctness+tests, parallel): 0 BLOCKER / 0 IMPORTANT / 1 cosmetic SUGGESTION (deferred per user direction).
  • Wave 2 (clean-slate convergence pass): 0 BLOCKER / 0 IMPORTANT / 1 SUGGESTION (applied — added the OPTIONAL MATCH failfast test).
  • Two consecutive non-significant-advance waves → CONVERGED.

Wave artifacts: plans/1285-freeform-multi-prefix-row/waves/wave-{1,2}/.

Out of scope (#1263 follow-ups still open)

Test plan

  • pytest -q graphistry/tests/compute/gfql/cypher/test_lowering.py
  • pytest -q graphistry/tests/compute/gfql/cypher/
  • ./bin/ruff.sh + ./bin/mypy.sh on touched files
  • Full TCK
  • DGX RAPIDS 25.02 + 26.02 spot-check (3/3 each, incl. cuDF)
  • Hosted CI green (push pending)

Refs

@lmeyerov lmeyerov force-pushed the feat/1285-freeform-multi-prefix-row branch from deab210 to d49767c Compare May 4, 2026 19:34
lmeyerov and others added 4 commits May 4, 2026 12:58
)

Replaces the single-row-only failfast in the free-form runtime path with a
per-row union loop, mirroring the scalar-only multi-row pattern at
``_compiled_query_scalar_reentry_state`` (#1047). For each prefix row, the
new ``_freeform_broadcast_row_to_nodes`` helper builds a dispatch graph with
that row's hidden carry columns broadcast onto every base node; the suffix
runs as a global MATCH (``start_nodes=None``) and per-row results are unioned
via the existing engine-polymorphic ``_union_scalar_reentry_results``.

Cartesian semantics fall out naturally: every prefix row × every trailing-
MATCH row.

Out of scope (preserved as failfasts):
- ``optional_reentry`` + multi-row free-form: same null-fill gap as the
  scalar-only multi-row path; mirrors that lane's existing failfast.
- Carried-property bridge in trailing scope (#1275).

Refs #1285, #1263, #999, #989

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#1285)

Three test changes for the multi-prefix-row free-form admit:

* ``..._failfast_rejects_simple_freeform_intermediate_reentry_match_on_multi_row_prefix``
  → ``..._executes_freeform_intermediate_reentry_match_on_multi_row_prefix``
  (retargeted to positive; pins per-row union behavior — 2 prefix rows × 1
  trailing pair = 2 result rows).
* ``..._executes_freeform_intermediate_reentry_match_on_multi_row_prefix_cartesian``
  (new) — 2 prefix rows × 2 trailing pairs = 4 result rows; locks the
  Cartesian product semantics.
* ``..._executes_freeform_intermediate_reentry_match_on_multi_row_prefix_on_cudf_when_available``
  (new) — cuDF parity for the multi-row admit.

Pre-existing simple (single-row) free-form tests stay untouched.

Refs #1285

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wave 2 review surfaced an uncovered code path: the runtime guard at
``_execute_compiled_query_with_reentry`` rejects ``optional_reentry +
multi-row free-form`` (mirror of the scalar-only multi-row guard from
#1047) but no test asserted the failfast wording.

Adds ``test_string_cypher_failfast_rejects_freeform_multi_row_prefix_with_optional_reentry``,
following the sibling pattern from
``test_issue_1047_multi_row_scalar_prefix_with_optional_reentry_raises``.

Refs #1285

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…admit

Records the runtime per-row union path that replaces the single-row-only
failfast from #1279, plus the OPTIONAL MATCH failfast preserved from the
scalar-only multi-row guard.

Refs #1285, #1263, #999, #989

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

Cypher/GFQL: admit multi-prefix-row free-form intermediate MATCH runtime path

1 participant