API Stability
This document defines which flydsl APIs may be relied on across releases and
the compatibility commitments that apply when they are changed. Its scope is
limited to python/flydsl/. Below, fx refers to flydsl.expr.
A release means a minor-version increment (for example, 0.3 → 0.4). A
patch release must not break a stable API.
1. Summary and general rules
stable: backward compatible across minor releases. Previously valid call paths, signatures, and semantics must continue to work.
unstable: everything else. These APIs may change or be removed in any minor release without notice.
deprecated is not a third stability level. It is a lifecycle marker for a
stable API: during its deprecation window, it remains stable and protected by
this document’s compatibility rules; it may be removed only after that window
ends.
Returned-object rule
An object returned by a stable API has a stable public result interface: its non-underscore members and Python special methods are stable when reached through that result. This rule applies recursively to objects returned by those members.
The concrete implementation class, its constructor, and its import path are not
promised by this rule. They may change if the replacement preserves the result
interface’s public members, signatures, and semantics. For example,
flyc.from_torch_tensor(x).mark_shape_dynamic(0) is stable, while
flyc.from_torch_tensor(x)._ensure_spec() is unstable.
Determine stability by the mechanical process below. A public export from an
expr direct-child module has several equivalent access forms:
fx.<name>, fx.<module>.<name>, and
from flydsl.expr.<module> import <name> have the same stability. Otherwise,
classify the path that a caller actually uses, not the object’s identity.
2. Determining stability
Apply the following branches by path prefix:
A module-global name or namespace segment beginning with
_is unstable. On stable types and returned objects, only__...__Python special methods may begin with_; all other underscore-prefixed members are unstable.A path under
flydsl.expr: classify it only under §2.1; it is unstable if it does not qualify.A path under
flydsl.compiler: direct members incompiler.__all__, and members incompiler.protocol.__all__, are stable. Other deep paths are stable only when listed exactly in §2.3.Every other path is stable only when listed exactly in §2.3.
For a member reached through a returned object, first classify its producing API under these branches, then apply the returned-object rule in §1.
2.1 flydsl.expr
expr/__init__.py is the sole top-level aggregation manifest. It has no
__all__ of its own; stability is determined exclusively by the following two
export chains.
Symbols exported from direct-child modules
Subject to the first branch above, <name> in a direct-child module <module>
is stable if and only if:
expr/__init__.pyaggregates that direct-child module throughfrom .<module> import *;<name>is in that child module’s__all__.
Names satisfying these conditions have identical stability when accessed via
fx.<name>, fx.<module>.<name>, or a direct import. Those direct-child
modules and their public export paths are part of the compatibility commitment.
Therefore, both fx.Int32 and fx.numeric.Int32 are stable. Members omitted
from __all__ remain unstable; fx.arith._to_raw is unstable under the first
branch even if it was listed in a historical __all__.
Backend entry points and recursive child namespaces
fx.<backend>...<name> is stable if and only if:
the first-level
<backend>appears in_BACKEND_MODULESinexpr/__init__.py;every following child namespace appears in the
__all__of its direct parent package; andthe final
<name>appears in the__all__of its owning module or package.
The first-level backend entry point, and intermediate child namespaces that satisfy condition 2, are stable namespaces as well. This rule applies recursively and has no path-depth limit.
For example, fx.rocdl.cdna3.s_waitcnt satisfies the complete export chain and
is stable, while fx.rocdl.cluster.* is unstable when cluster is not listed
in rocdl.__all__. An upstream-MLIR ODS builder that is re-exported but omitted
from the final __all__ is unstable as well.
__all__ is not access control: an attribute may exist and be callable while
still failing the stability test above.
2.2 flydsl.compiler
Only direct members of flydsl.compiler.__all__ are stable. For example, if
jit is in that manifest, flydsl.compiler.jit is stable.
flydsl.compiler.protocol is an exception: every non-underscore
flydsl.compiler.protocol.<name> in its __all__ is stable. It is the public
extension namespace for user implementations of JIT / DSL-value protocols.
This rule is otherwise not recursive:
flydsl.compiler.<submodule>.<name> does not become stable merely because
<submodule> is importable; it must be listed explicitly in §2.3.
2.3 Other explicitly stable APIs
The following full paths are stable. This table is the only exception list; a new commitment must add an explicit row.
API |
Description |
|---|---|
|
Query the target ROCm architecture |
|
Choose between CDNA and RDNA paths |
2.4 All other APIs
Every API that does not satisfy §2.1 or §2.2, and is not listed exactly in
§2.3, is unstable. This includes undeclared flydsl.* submodules,
flydsl._mlir.*, and every underscore-prefixed name.
Direct invocation of an upstream MLIR dialect op is allowed but unstable: its name, arguments, and semantics are controlled by upstream MLIR, and FlyDSL provides no compatibility commitment for it.
Stable API catalog
Generate the complete non-deprecated stable API catalog from the checked-out source:
python3 scripts/list_stable_apis.py
python3 scripts/list_stable_apis.py --format json
The script reads export manifests without importing FlyDSL. It lists canonical
module paths, omitting equivalent top-level flydsl.expr aliases. Deprecated
APIs remain compatible but are intentionally excluded from this catalog.
3. Stable but deprecated
The APIs in the table below satisfy the stable rules in §2 but are marked as deprecated. They remain stable during the §5 window; new code must not use them, and a replacement must be provided before removal.
For direct-child module exports under §2.1, the deprecated status in this table
also applies to fx.<name>, fx.<module>.<name>, and direct-import forms.
This table is maintained separately as the compatibility-debt list and is
excluded from the catalog above.
API |
Replacement or required work before removal |
Declared removal release |
|---|---|---|
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
4. What counts as a breaking change
For a stable API, each of the following is a breaking change:
removing a stable API or breaking its export chain: removing an entry from a direct-child module’s
__all__,flydsl.compiler.__all__, orflydsl.compiler.protocol.__all__; or removing a §2.3 entry without a new rule that covers it;removing an argument, renaming an argument that may be passed by keyword, reordering positional arguments, removing a default, or changing a default;
narrowing accepted types, architectures, or value ranges;
changing a returned scalar or value type, tuple arity, or a returned object’s stable public result interface (including non-private members and
__...__Python special methods), or the numerical, layout, or emitted-op semantics for previously valid input.
The following are not breaking changes:
adding an API, or adding an optional keyword argument whose default preserves existing behavior;
widening accepted input;
improving an error message, converting undefined behavior into a clear error, or changing the exception type on failure;
replacing a returned object’s concrete implementation class while preserving its stable public result interface;
changing only unstable APIs.
5. Changing or retiring a stable API
Provide a replacement first, normally exposing it from an appropriate stable path.
Mark the original API as deprecated at its definition or export declaration, and add the API and replacement to §3.
Retain the old API in the release where it is marked,
N, and in the next minor release,N+1.Remove the old API no earlier than
N+2, and remove its corresponding §3 entry at the same time.