Skip to content

chore(release): prepare 0.59.0 on develop - #2013

Open
lmeyerov wants to merge 174 commits into
developfrom
release/0.59.0-develop-sync
Open

chore(release): prepare 0.59.0 on develop#2013
lmeyerov wants to merge 174 commits into
developfrom
release/0.59.0-develop-sync

Conversation

@lmeyerov

@lmeyerov lmeyerov commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Prepare pygraphistry 0.59.0 on develop after the GFQL benchmark/docs stack landed.

  • Merge current master@76dc3f302 ancestry into current develop@d32f83afa so the later developmaster promotion is conflict-free.
  • Combine every unreleased changelog entry from both branches and cut ## [0.59.0 - 2026-08-31].
  • Preserve the landed docs(gfql): sync benchmark contract v3 #2011 benchmark prose and fix(gfql): preserve Polars across graph CALL #2012 Polars CALL boundary tests.
  • Keep package versioning tag-derived; there is no source version literal change.
  • Give the Python 3.12 Polars coverage cell deterministic margin after exact-head CI proved its fully passing 2-worker run exceeded the old whole-job budget.

Diff shape

The PR is broad because master contains 125 files of already-landed/reviewed changes that develop does not yet contain. Those blobs are inherited from master, not newly authored here. The manual release work is limited to the changelog merge/release cut, the reviewed q1–q9 merge-resolution spelling, and the narrow Polars CI-budget correction. The final sync from develop adds only #2012's reviewed test amplification.

The 0.59.0 changelog contains the exact parent union: 100 entries on develop, 130 on master, and 133 unique inherited entries, with none missing or duplicated. It adds one candidate-authored Infrastructure receipt for the Polars timeout correction.

Exact head: 749736ca8aa3219185ad6a3acee37449aeb230e1

Binary diff fingerprint against develop: 93a1e6d99bd711aa13d6d6c01925a866e6118c17294baa8d0997cbeb8b9337a4

Validation

  • 48 focused benchmark-doc, Polars CALL boundary, and schema-effect tests passed.
  • Repository-native full Ruff, type-hygiene, comment-density, and relative-import gates passed.
  • Repository-native focused production mypy passed; exact-head CI owns the full pinned type matrix.
  • Docs LaTeX Unicode, credential-pattern, residue, shell syntax, and git diff --check gates passed.
  • A temporary unpushed 0.59.0 tag built the expected universal wheel and sdist; wheel metadata reports graphistry==0.59.0. The tag and all build outputs were deleted.
  • The original Polars CI receipt had 7,091 tests pass in 566.14 s, its append phase pass 129 tests in 13.89 s, and its coverage audit pass before the 10-minute whole-job cancellation. The budget is now 15 minutes; test selection, workers, and coverage floors are unchanged.
  • No Docker or heavy local compute was used.

Landing and release boundary

This PR targets develop. After maintainer review/merge, open a clean developmaster promotion PR for maintainer landing. Do not tag or publish until that promotion is on master and the separate pre-tag readiness checkpoint is approved.

lmeyerov and others added 30 commits August 18, 2026 17:45
…temporal half

- B-5: constant-fold literal temporal comparisons engine-agnostically
  (openCypher CIP2016-06-14): zoned instants compare on the UTC global
  timeline (same instant under different offsets IS equal); values of
  different temporal types are never equal and order as null.
- B-7: temporal-vs-string never leaks raw backend errors — polars
  filter predicates parse-and-compare in the pandas-parity SAFE subset
  or raise typed GFQLSchemaError E302; tz-suffixed ISO text comparisons
  stay a where_rows residual instead of a raw-raising pushdown; the
  same-path WHERE aligns mixed tz-naive/aware datetime pairs onto
  UTC-naive; the bounds prune skips incomparable dtypes.
- B-8: non-reserved keywords are valid property names (n.when, n.order,
  {when: 1}) via a dot/map-key-context PROP_NAME terminal.
- A-4: UNION branches with the same output names in a different order
  align by name (output keeps the first branch's order); different name
  sets stay a typed decline.
- #1880 temporal half: a.dt = '...' / a.dur = '1 days' answer with
  pandas-identical rows on polars instead of raw InvalidOperationError.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…nes, CHANGELOG

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…ter pushdown too

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…ss, fold declines, sub-us duration)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…RPUS parity now

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
Lane-F regenerated the baseline from a pre-#1942 tree (chain.py 7 findings);
#1942 landed an 8th on master with its cap. The clean merge kept the stale
tighter caps, failing the merge ref — the two-green-PRs baseline-union hazard
in comment form. chain.py entries restored to master's values; every other
entry keeps this branch's downward-only movement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…ias-shadowed property reads (#1911 defect-4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
… per hygiene guards

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…ead _y coalesce arm untouched

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…nged-line coverage)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…L keeps overwrite parity)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…ing base frames

The dotted self-name flipped the bindings-alias-prefix heuristic (NA-ing sibling
property reads) and an intermediate dispatch base frame's own marker could be
misread as user data (comma-pattern r.weight -> NA).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…th serves it)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
The where(notna(), None) idiom re-coerces None back to NaN on float64 columns
under py3.13/3.14 pandas, so the pin compared nan == None and failed only on
those lanes. Normalizing per-record makes the oracle version-stable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
The comparison-fold additions left four defensive lines unreached in the
gfql-core lane (98.39% vs floor 98.90%): the dateless-non-time shift guard,
the unparseable-text ValueError arm, and the unknown current-temporal-call
passthrough. Direct degenerate-input unit pins cover all four; floor
unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
Same version-skew class as the #1948 pin fix: three alias-scoping pins compared
nan == None and failed only on the py3.13 lane. Normalizing once in _rows
covers every record assertion in the file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
fix(gfql): temporal/error-leak family — #1915 B-5/B-7/B-8 + A-4, #1880 temporal half
fix(gfql): WITH->MATCH carry restricts every route (#1712 residual); alias-shadowed property reads (#1911 defect-4)
…ph shapes (#1889)

`gfql_validate` returned `{ok: True, diagnostics: []}` on a graph whose frames were
never attached (`graphistry.bind(...)` names columns only), then execution died with a
bare `ValueError: Missing edges` (pandas/cuDF `materialize_nodes`) or an empty-message
`AssertionError` (polars `ensure_nodes_polars`). A preflight that approves what the
runtime always rejects is drift by construction.

Both sides now consult one predicate, `validate_graph_shape`:

* neither nodes nor edges bound -> GFQLSchemaError E305 `graph-not-bound` (new code),
  with a bind remedy -- raised by the validator AND by execution on every engine
  (pandas/cuDF via `validate_chain_schema`, polars via the pre-dispatch guard).
* edges unbound + an edge pattern -> E304, the same typed decline execution already
  gave (#1942); the validator no longer stays silent about it.
* nodes-only + node-only pattern stays admitted on both sides and keeps answering.

`schema=False` callers (remote preflight, which holds no local frames) skip the shape
check, so `chain_remote` is unaffected.

Pins: `test_validate_execute_agreement_1889.py` -- the 4 filed combos x {pandas, polars}
agreement matrix (10/18 red at master 0c3f3a1), typed-code pins on both surfaces,
value-level served-record oracles, and the not-flagged shapes (bound graph, edges-only,
schema=False). Each of the 5 fix sites was mutation-checked. `test_gfql_validate_only`'s
structural-only expectation moved to `schema=False`, which is what it was really pinning.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…olars paired)

The min-hop prune's backward retention walk seeded targets from the TOP hop
level only, then narrowed them level by level. A branch that reached min_hops
and TERMINATED strictly below max_hops was therefore never a target when its
own level was processed, so its terminating edge -- and everything feeding it
exclusively -- was pruned, in violation of the documented inclusive-bounds
contract ("prune dead-end branches that do not reach min_hops").

An edge traversed at a level >= min_hops now ends a qualifying walk itself and
is retained outright; only sub-min levels still have to feed a retained longer
walk. Landed paired: graphistry/compute/hop.py (pandas + cuDF share the kernel)
and the polars chain mirror in gfql/lazy/engine/polars/hop_eager.py reproduced
the identical under-retention, and reverting either half alone turns 31
cross-engine chain/hop parity cells red.

Pins in test_hop_boundary_matrix.py on a new `tailcycle` topology: 4 cells red
at master (pandas hop, cuDF hop, pandas chain, polars chain) and 6 anti-vacuity
control cells green before and after (min_hops == max_hops still prunes the
genuine sub-min dead end; the reverse direction does not move).

Fixes #1944

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
Master's python-lint-types lane went red at 0c3f3a1: row_pipeline.py
carried 7 issue-citing comments against a cap of 6 -- a baseline union,
where two individually-green PRs landed citations neither snapshot saw.

Restate the alias.alias contract by name instead of citing the issue;
the pin test_unshadow_alias_marker_column_declines_when_there_is_nothing_to_restore
already carries it. Cap unchanged at 6; --update-baseline also locks a
never-recorded chain.py improvement (7 -> 6). No behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…aster lint

The comment-encoding guard fails on master head (0c3f3a1): row_pipeline.py
carries 7 issue-rationale findings against a baseline of 6, the extra one added
by 2858968. Comment text only; no behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
…ar the master lint"

The master-lint red is being fixed in #1953; reverting to avoid colliding with
that fix. row_pipeline.py is now byte-identical to master again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
The change is user-visible (new ErrorCode.E305; shapes that returned
ok:true now report a typed GFQLSchemaError), so it needs an entry like
every other fix in this wave. Notes explicitly that nothing which
executed before is refused, and that schema=False still skips the check
so chain_remote preflight is unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjbKuKheqDu78oapRT5AYm
lmeyerov and others added 28 commits August 28, 2026 06:49
…l-sum

fix(gfql): preserve boolean sum zero on polars gpu
…ype-validation

fix(gfql): validate absent relationship types
…h-rebind

fix(gfql): reject cross-kind WITH rebinds early
…preflight

fix(gfql): preflight remote engine requests
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