Skip to content

T5 #1311: GFQL strict-schema rollout gate, CI receipt, operator docs#1316

Merged
lmeyerov merged 6 commits intomasterfrom
1311-rollout-gates
May 6, 2026
Merged

T5 #1311: GFQL strict-schema rollout gate, CI receipt, operator docs#1316
lmeyerov merged 6 commits intomasterfrom
1311-rollout-gates

Conversation

@lmeyerov
Copy link
Copy Markdown
Contributor

@lmeyerov lmeyerov commented May 5, 2026

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) and g.gfql(..., validate=True). That is the primary operator entrypoint for explicit, predictable strict-mode invocation, and it hardcodes strict=True at 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

Newgraphistry/compute/gfql/rollout.py (78 LOC). Stable contract surface re-exported from graphistry.compute.gfql:

  • STRICT_SCHEMA_ENV = "GRAPHISTRY_GFQL_STRICT_SCHEMA" — public env-var name
  • env_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 off
  • resolve_strict_schema(*, explicit, catalog_strict) — central monotonic resolver

Modifiedgraphistry/compute/gfql/frontends/cypher/binder.py. _strict_schema_mode(state) delegates to resolve_strict_schema(...). Precedence ladder is now: explicit caller param True > catalog metadata["strict"]=True > env GRAPHISTRY_GFQL_STRICT_SCHEMA=true > loose. An explicit False is "no preference" (does not force loose), preserving monotonic semantics.

Modifiedgraphistry/compute/gfql/__init__.py. Re-exports the four rollout symbols and adds them to __all__.

Newgraphistry/tests/compute/gfql/test_rollout.py (39 tests):

  • TestEnvBool (8) — env-var truth set + whitespace/case behavior
  • TestStrictSchemaEnvDefault (4) — pinned env-var name + on/off/unset behavior
  • TestResolveStrictSchema (15) — full precedence matrix + parametrized truthy/falsy values
  • TestPackageSurface (1) — re-export contract pinned

Newgraphistry/tests/compute/gfql/test_rollout_binder_integration.py (12 tests):

  • TestBinderEnvGateOff — env unset / false preserves loose mode
  • TestBinderEnvGateOn — env=true|1|yes|on|TRUE rejects unknown labels with GFQLValidationError
  • TestBinderPrecedence — explicit param + catalog flag still win regardless of env state; valid queries continue to pass under env=strict

Modified.github/workflows/ci.yml. Folded the rollout test files into the existing test-gfql-core and test-pandas-compat-gfql lanes (default-loose path runs with the main pytest invocation), with a follow-on GRAPHISTRY_GFQL_STRICT_SCHEMA=true step in each job exercising the env-on canary. No new standalone CI job.

Newdocs/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 to validation/fundamentals.rst and cypher.rst (where #1321 added preflight docs).

ModifiedCHANGELOG.md (+1 LOC). Internal entry under [Development] / #1262 / T5.

Acceptance (per #1311)

  1. Strict/permissive controls wired and tested — env-driven canary tier added on top of the existing T2 binder strict mode; resolver pinned by 51 tests across helper + binder seam.
  2. CI explicitly exercises both rollout modestest-gfql-core and test-pandas-compat-gfql each run the rollout slice with env unset (default-loose) and =true (canary on).
  3. Docs/migration notes published with operator guidancedocs/source/gfql/strict_mode.rst ships the rollout sequence + precedence reference, leading with the GFQL/Cypher: expose validate-only API (compile/bind checks without execution) #1320 explicit preflight surface.
  4. Meta: #1046 native type-system staged decomposition program #1262 close criteria satisfied — with T3.b (GFQL native types T3.b: migrate inline nullable patterns onto ir.metadata helpers #1309), T4 (GFQL native types T4: Arrow/type bridge contracts #1313), and this T5 PR, the meta lane is complete; meta-issue close after this PR merges.

Test plan

  • pytest -q graphistry/tests/compute/gfql/test_rollout.py — 39 passed
  • pytest -q graphistry/tests/compute/gfql/test_rollout_binder_integration.py — 12 passed
  • pytest -q graphistry/tests/compute/gfql/cypher/test_binder.py — no regression on T2 strict-mode tests
  • pytest -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) clean
  • mypy --strict --follow-imports=skip on IR + binder — clean
  • CI green on rebased HEAD

🤖 Generated with Claude Code

@lmeyerov lmeyerov force-pushed the 1311-rollout-gates branch 2 times, most recently from a122671 to d7a8a42 Compare May 5, 2026 23:40
Comment thread docs/source/gfql/strict_mode.rst Outdated
.. code-block:: python

from graphistry.compute.gfql.frontends.cypher.binder import FrontendBinder
FrontendBinder().bind(ast, ctx, strict_name_resolution=True)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

smell

lmeyerov and others added 4 commits May 5, 2026 23:25
…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>
lmeyerov and others added 2 commits May 6, 2026 00:05
…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>
@lmeyerov lmeyerov marked this pull request as ready for review May 6, 2026 07:30
@lmeyerov lmeyerov merged commit 256da54 into master May 6, 2026
99 checks passed
@lmeyerov lmeyerov deleted the 1311-rollout-gates branch May 6, 2026 07:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant