API Stability and Aliases: How TGraphX Evolved Toward Predictable Graph APIs
The surest way to lose a research user is to break their code on an upgrade. The next surest is to make the API so unpredictable that neither they nor their coding assistant can guess the right call. TGraphX has spent several releases addressing both problems deliberately, and the CHANGELOG tells a clear engineering story: add convenience and predictability on top of a stable core, never by breaking it. This article traces that evolution and explains why each step improves reliability — without pretending the package is more finished than its honest Beta status.
This continues themes from LLM-Friendly Graph APIs and Explicit, Auditable Graph APIs.
The contract first
Before the conveniences, there is a contract. docs/api_stability.md defines four tiers, and they mean specific things:
- Stable — no breaking changes in any v1.x release; a v2.x or an explicit deprecation cycle is required to change them. The core
Graph/GraphBatch, the tensor layers (ConvMessagePassing,TensorGATLayer,TensorGraphSAGELayer,TensorGINLayer), and the pooling functions are all Stable. - Beta — stable within a minor version, may expand but not break.
- Experimental — documented behaviour preserved, but signatures and defaults may evolve between minor releases.
- Optional — needs an optional dependency.
A contract you can read is itself a reliability feature: it tells you which calls you can build a paper around and which you should pin a version for.
The timeline
| Version | What changed | Why it matters |
|---|---|---|
| v1.0.1 | Keyword aliases y=, labels=, edge_attr=, mask args added to Graph |
PyG muscle memory works; no break to node_features= |
| v1.0.2 | graph_features= added as a distinct graph-level field |
avoids conflating graph input with graph label |
| v1.4.0 | New tgraphx.ux layer: PyG/NetworkX/PyKEEN-style aliases, .tgx save/load, reproducible contexts, leakage guards, public_api/api_status/list_aliases |
predictability + auditability, "without breaking any existing v1.3.x syntax" |
| v1.4.1 | One-call helpers (classify_nodes, kg_completion, make_graph, …) and explain_error, debug_batch |
lower the floor for newcomers; new APIs are Beta with no superiority claims |
Two things stand out. First, every row preserves the previous syntax — the v1.4.0 entry explicitly says the ux layer arrived "without breaking any existing v1.3.x syntax," and v1.4.1 reiterates "all v1.3.x and v1.4.0 syntax fully preserved." Second, the new high-level helpers are labelled Beta and accompanied by an explicit note that they claim no benchmark superiority. That is a package adding surface area conservatively, not chasing version numbers.
The stability registry
The most interesting reliability feature is that the API can describe itself. tgraphx/ux/public_api.py provides three functions:
import tgraphx as tgx
tgx.public_api() # the public surface
tgx.api_status() # stability label per component
tgx.list_aliases() # alias → canonical mapping
list_aliases() matters for both humans and machine-generated code. When tgx.knn_graph, tgx.make_graph, and the PyG-style constructor aliases all route to canonical implementations, an LLM that guesses a "reasonable" name often lands on a real one — and the registry documents exactly which alias maps to which canonical call, so the convenience never becomes a mystery. The v1.4.1 notes describe a consistency check over this registry, which is how the project guards against an alias drifting away from its canonical target.
Why aliases are a debugging feature
It sounds paradoxical that more names improve reliability, but the failure mode they prevent is real: a user (or an assistant) writes Graph(x=..., y=...) from PyG habit, and in a framework without aliases that raises an error far from the cause. TGraphX resolves the alias and — crucially — rejects conflicting aliases loudly (providing both y= and labels= is a ValueError, not a silent pick). And tgx.explain_error(e), added in v1.4.1, maps common exceptions (GraphML rank limits, NSGA-II misuse, mask overlap, missing optional deps) to actionable guidance. The design philosophy is consistent: be permissive about names, strict about semantics, and explicit about errors.
Honest framing
This is normal, healthy package maturation, and it should be described that way — not as fixing a broken library. The core has been Stable since v1.0; the recent releases added predictability and ergonomics in Beta-labelled layers while preserving backward compatibility. The honest caveats: the new one-call helpers are Beta and may expand, Experimental subsystems can still change between minor releases, and "stable" is a promise about API surface, not about results. The stability labels article covers how to read those promises.
Reading the registry in practice
The stability registry is most useful when you let it gate your own code. Before depending on a call in a long-lived script, you can ask the package what guarantee it carries:
import tgraphx as tgx
status = tgx.api_status() # component -> stability label
aliases = tgx.list_aliases() # alias -> canonical name
A practical pattern for research code that must survive upgrades: build on Stable APIs for the parts you cannot afford to rewrite, treat Beta APIs as convenient but pin the version, and isolate any Experimental calls behind a thin wrapper so that if a signature changes you have one place to fix. list_aliases() is also the quickest way to find the canonical name behind a convenience alias you spotted in an example — useful when you want published code to use the canonical form rather than a shorthand. The registry turns "is this safe to depend on?" from a guess into a lookup, which is exactly the kind of self-description that makes a framework dependable over several releases.
Related guides
- LLM-Friendly Graph APIs in TGraphX
- Explicit, Auditable Graph APIs
- Stability Labels in Research Software
Conclusion
TGraphX's API evolution is a case study in adding convenience responsibly: a readable stability contract, PyG/NetworkX-style aliases that route to canonical calls, a self-describing public_api/api_status/list_aliases registry, and one-call helpers — all introduced without breaking existing syntax and all labelled honestly. For anyone deciding whether to build on a research package, that pattern of backward-compatible, self-documenting growth is exactly the reliability signal worth looking for.