T5 #1311: GFQL strict-schema rollout gate, CI receipt, operator docs#1316
Merged
T5 #1311: GFQL strict-schema rollout gate, CI receipt, operator docs#1316
Conversation
a122671 to
d7a8a42
Compare
lmeyerov
commented
May 5, 2026
| .. code-block:: python | ||
|
|
||
| from graphistry.compute.gfql.frontends.cypher.binder import FrontendBinder | ||
| FrontendBinder().bind(ast, ctx, strict_name_resolution=True) |
…perator 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>
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>
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>
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>
d7a8a42 to
9cfc6d0
Compare
7 tasks
…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>
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>
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.
Summary
Adds an env-driven canary rollout gate over the existing T2 binder strict-mode resolver, operator-guidance docs, and CI receipts (folded into existing GFQL lanes). Strictly additive — default loose mode behavior is unchanged.
Issue: #1311 (T5 under #1262, umbrella #1046).
Scope (post-#1320/#1321 reframing)
Master now has the explicit preflight surface from #1320/#1321:
g.gfql_validate(query, strict=True)andg.gfql(..., validate=True). That is the primary operator entrypoint for explicit, predictable strict-mode invocation, and it hardcodesstrict=Trueat preflight regardless of T5's env.T5 ships a complementary surface: a canary rollout gate for the execution compile path's binder default. When a caller uses
g.gfql(query)without explicit preflight, the binder strictness comes from a three-tier precedence ladder (explicit binder param > catalog metadata > env > loose). T5 adds the env tier so org-wide rollout can flip the default for non-validate-flagged execution.The two surfaces are independent on purpose:
What's in the diff
New —
graphistry/compute/gfql/rollout.py(78 LOC). Stable contract surface re-exported fromgraphistry.compute.gfql:STRICT_SCHEMA_ENV = "GRAPHISTRY_GFQL_STRICT_SCHEMA"— public env-var nameenv_bool(name, default=False)— local env-bool helper (truthy{1,true,yes,on}, falsy{0,false,no,off}, unrecognized → default)strict_schema_env_default()— reads the env var, default offresolve_strict_schema(*, explicit, catalog_strict)— central monotonic resolverModified —
graphistry/compute/gfql/frontends/cypher/binder.py._strict_schema_mode(state)delegates toresolve_strict_schema(...). Precedence ladder is now: explicit caller paramTrue> catalogmetadata["strict"]=True> envGRAPHISTRY_GFQL_STRICT_SCHEMA=true> loose. An explicitFalseis "no preference" (does not force loose), preserving monotonic semantics.Modified —
graphistry/compute/gfql/__init__.py. Re-exports the four rollout symbols and adds them to__all__.New —
graphistry/tests/compute/gfql/test_rollout.py(39 tests):TestEnvBool(8) — env-var truth set + whitespace/case behaviorTestStrictSchemaEnvDefault(4) — pinned env-var name + on/off/unset behaviorTestResolveStrictSchema(15) — full precedence matrix + parametrized truthy/falsy valuesTestPackageSurface(1) — re-export contract pinnedNew —
graphistry/tests/compute/gfql/test_rollout_binder_integration.py(12 tests):TestBinderEnvGateOff— env unset /falsepreserves loose modeTestBinderEnvGateOn— env=true|1|yes|on|TRUErejects unknown labels withGFQLValidationErrorTestBinderPrecedence— explicit param + catalog flag still win regardless of env state; valid queries continue to pass under env=strictModified —
.github/workflows/ci.yml. Folded the rollout test files into the existingtest-gfql-coreandtest-pandas-compat-gfqllanes (default-loose path runs with the main pytest invocation), with a follow-onGRAPHISTRY_GFQL_STRICT_SCHEMA=truestep in each job exercising the env-on canary. No new standalone CI job.New —
docs/source/gfql/strict_mode.rst(added to the user-guide toctree). Operator-guidance reference: leads with the #1320 preflight API as the primary entrypoint, then documents the rollout gate's env / catalog / param precedence ladder for staged adoption. Cross-links tovalidation/fundamentals.rstandcypher.rst(where #1321 added preflight docs).Modified —
CHANGELOG.md(+1 LOC). Internal entry under[Development]/ #1262 / T5.Acceptance (per #1311)
test-gfql-coreandtest-pandas-compat-gfqleach run the rollout slice with env unset (default-loose) and=true(canary on).docs/source/gfql/strict_mode.rstships the rollout sequence + precedence reference, leading with the GFQL/Cypher: expose validate-only API (compile/bind checks without execution) #1320 explicit preflight surface.Test plan
pytest -q graphistry/tests/compute/gfql/test_rollout.py— 39 passedpytest -q graphistry/tests/compute/gfql/test_rollout_binder_integration.py— 12 passedpytest -q graphistry/tests/compute/gfql/cypher/test_binder.py— no regression on T2 strict-mode testspytest -q graphistry/tests/compute/gfql/— full GFQL suite green (post-rebase)./bin/lint.sh(ruff on Python files) clean./bin/typecheck.sh(mypy 1.20.2) cleanmypy --strict --follow-imports=skipon IR + binder — clean🤖 Generated with Claude Code