Skip to content

GFQL/Cypher: add validate-only gfql preflight API#1321

Merged
lmeyerov merged 17 commits intomasterfrom
issue-1320-gfql-validation-interface
May 6, 2026
Merged

GFQL/Cypher: add validate-only gfql preflight API#1321
lmeyerov merged 17 commits intomasterfrom
issue-1320-gfql-validation-interface

Conversation

@lmeyerov
Copy link
Copy Markdown
Contributor

@lmeyerov lmeyerov commented May 6, 2026

Summary

  • add public validate-only preflight API g.gfql_validate(...) for GFQL and Cypher inputs without execution
  • make g.gfql(..., validate=True) and g.gfql_remote(..., validate=True) run preflight before local execution or remote upload/dispatch
  • unify string handling so validation paths treat string inputs as Cypher consistently and surface Cypher diagnostics
  • shift g.gfql_validate(...) to fail-fast exception semantics (raise on invalid queries) with structured inspectable payloads for LLM retry loops
  • clarify validation docs for recommended entrypoints and grounded vs ungrounded schema checks

API

  • ComputeMixin.gfql_validate(query, *, where=None, language=None, params=None, strict=False, collect_all=False) -> dict
  • returns success metadata for valid queries and raises structured GFQLValidationError/GFQLSyntaxError for invalid queries
  • in collect_all=True, exception context includes full diagnostics for machine-readable repair workflows

Behavior

  • g.gfql_validate("...") treats string inputs as Cypher preflight by default
  • g.gfql("...", validate=True) uses the same Cypher preflight path before execution
  • g.gfql_remote(..., validate=True) validates locally before implicit upload/network execution when possible

Testing

  • PYTHONPATH=. python -m pytest -q graphistry/tests/compute/test_gfql_validate_only.py
  • PYTHONPATH=. python -m pytest -q graphistry/tests/compute/test_gfql.py -k "gfql_validate_true_runs_preflight_before_compile or gfql_validate_true_catches_cypher_schema_errors_by_default or gfql_validate_true_treats_all_strings_as_cypher"
  • PYTHONPATH=. python -m pytest -q graphistry/tests/compute/test_chain_remote_v2.py -k "validate_true_rejects_before_implicit_upload or validate_true_uses_remote_safe_local_preflight"
  • PYTHONPATH=. python -m pytest -q graphistry/tests/compute/test_chain_let.py -k "invalid_dag_type or chain_let_validates"
  • PYTHONPATH=. python -m pytest -q docs/test_doc_examples.py -k "validation/fundamentals.rst or gfql/cypher.rst or validation/llm.rst"
  • uv run ruff check graphistry/compute/gfql_validate.py graphistry/compute/gfql_unified.py graphistry/compute/chain_remote.py graphistry/tests/compute/test_gfql_validate_only.py graphistry/tests/compute/test_gfql.py

Refs #1320

@lmeyerov lmeyerov force-pushed the issue-1320-gfql-validation-interface branch 2 times, most recently from 21564bc to e8d6510 Compare May 6, 2026 01:13
@lmeyerov lmeyerov force-pushed the issue-1320-gfql-validation-interface branch from d68ee48 to 8f6c593 Compare May 6, 2026 02:48
@lmeyerov lmeyerov merged commit cd1f3c8 into master May 6, 2026
97 checks passed
@lmeyerov lmeyerov deleted the issue-1320-gfql-validation-interface branch May 6, 2026 06:22
lmeyerov added a commit that referenced this pull request May 6, 2026
…QL lanes

Per coordinator decision (2026-05-06):

(1) Reframe `docs/source/gfql/strict_mode.rst` to lead with #1320/#1321's
explicit preflight API (`g.gfql_validate(strict=True)`, `g.gfql(validate=True)`)
as the primary operator entrypoint, and position the env-gate
(`GRAPHISTRY_GFQL_STRICT_SCHEMA`) and catalog metadata as canary surfaces for
the execution compile path's binder default. The two surfaces are
independent: explicit preflight always runs strict regardless of env; env
ladder governs only the non-validate-flagged execution path.

(2) Fold the standalone `cypher-frontend-strict-rollout` job into the
existing `test-gfql-core` and `test-pandas-compat-gfql` lanes — the rollout
test files now run inside the matrix's main pytest invocation (default-loose
path), and a follow-on `GRAPHISTRY_GFQL_STRICT_SCHEMA=true` step in the same
job exercises the env-on canary path. No standalone lane needed.

CHANGELOG entry updated to reflect both changes. Existing rollout module +
tests + binder wiring unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lmeyerov added a commit that referenced this pull request May 6, 2026
…1316)

* T5 #1311: GFQL strict-schema rollout gate (env canary), CI receipt, operator docs

Add a stable env-driven canary contract over the existing T2 binder strict-mode
resolver, plus a focused CI receipt and an operator-guidance doc. Strictly
additive — default loose mode behavior is unchanged.

New module `graphistry/compute/gfql/rollout.py`:
  STRICT_SCHEMA_ENV = "GRAPHISTRY_GFQL_STRICT_SCHEMA"
  env_bool(name, default=False)
  strict_schema_env_default()
  resolve_strict_schema(*, explicit, catalog_strict)

Re-exported from `graphistry.compute.gfql`.

Wiring: `binder._strict_schema_mode` now delegates to the resolver, giving a
monotonic precedence ladder — explicit param > catalog metadata > env > loose.

Tests: 39 in test_rollout.py + 12 binder-integration tests pinning env-off
preserves loose, env-on rejects unknown labels, explicit/catalog tiers still
win, and valid queries continue to pass under env=strict.

CI: new `cypher-frontend-strict-rollout` job runs the rollout slice twice —
env-unset and env=true — gated on `cypher_frontend_ci`/`gfql` filters.

Docs: new `docs/source/gfql/strict_mode.rst` (added to user-guide toctree)
covers what strict mode is, three opt-in paths, precedence, diagnostic shape,
and a recommended canary -> catalog -> param rollout sequence.

Out of scope: Arrow-bridge gates (deferred until T4 #1312 contract surface
exists). Meta-issue #1262 close criteria are not satisfied by this PR alone.

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

* review-w1: drop dead "" entry from ENV_FALSY

env_bool short-circuits empty/whitespace before the falsy-set check, so the
empty-string entry in ENV_FALSY was unreachable. Update test parametrize to
match.

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

* ci-fix: annotate ENV_TRUTHY/ENV_FALSY with frozenset[str]

cypher-frontend-strict-typing (mypy --strict --follow-imports=skip) flagged
the bare `frozenset` annotations as missing type arguments. Add string-form
annotations for forward compat across Python versions.

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

* ci-fix: cast resolve_strict_schema return through bool() in binder

cypher-frontend-strict-typing runs mypy with --follow-imports=skip, which
treats imports from graphistry.compute.gfql.rollout as Any. This made the
typed bool return from resolve_strict_schema look like Any to mypy and
tripped --strict's no-any-return on _strict_schema_mode. Wrap the call in
bool(...) so the function's declared bool return is satisfied without
relying on the cross-module import being followed.

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

* post-coordinator: docs reframe + fold strict-rollout into existing GFQL lanes

Per coordinator decision (2026-05-06):

(1) Reframe `docs/source/gfql/strict_mode.rst` to lead with #1320/#1321's
explicit preflight API (`g.gfql_validate(strict=True)`, `g.gfql(validate=True)`)
as the primary operator entrypoint, and position the env-gate
(`GRAPHISTRY_GFQL_STRICT_SCHEMA`) and catalog metadata as canary surfaces for
the execution compile path's binder default. The two surfaces are
independent: explicit preflight always runs strict regardless of env; env
ladder governs only the non-validate-flagged execution path.

(2) Fold the standalone `cypher-frontend-strict-rollout` job into the
existing `test-gfql-core` and `test-pandas-compat-gfql` lanes — the rollout
test files now run inside the matrix's main pytest invocation (default-loose
path), and a follow-on `GRAPHISTRY_GFQL_STRICT_SCHEMA=true` step in the same
job exercises the env-on canary path. No standalone lane needed.

CHANGELOG entry updated to reflect both changes. Existing rollout module +
tests + binder wiring unchanged.

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

* strict_mode.rst: mark illustrative python blocks as doc-test:skip

The repo's docs/test_doc_examples.py runs python code blocks against a
synthetic graph fixture (`g`, `nodes`, `edges` with columns id/type/score
etc). My code blocks reference Person/KNOWS labels and undefined symbols
(`ast`, `ctx`) — they are operator-illustration snippets, not runnable
against the fixture.

Mark each python code block with `.. doc-test: skip` so the harness
recognizes them as illustrative. Bash and text blocks auto-skip.

Verified: pytest docs/test_doc_examples.py -k strict_mode -> 1 skipped
(no failures); sibling cypher.rst / fundamentals.rst pass as before.

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

---------

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.

1 participant