Public Alpha Rextio plugin for bounded TensorFlow 2.21.0 CPU lowering and a Linux CUDA build-only candidate via the wheel TFE C API (plugin API 1.6).
Project description
rextio-tensorflow
Released public Alpha 0.1.3 (plugin-only) on 2026-07-27, building on the released 0.1.2 native-AOT Alpha foundation (2026-07-26). The earlier initial public Alpha was 0.1.0 (2026-07-18).
This is a Rextio plugin API 1.6 provider with two deliberately separate lanes:
- The existing bounded TensorFlow 2.21.0 CPU Alpha surface.
- A Linux x86_64 GNU CUDA E3 build-only candidate for one exact
matmul → bias_add → relu → reduce_mean(axis=1)slice.
Generated code does not reimplement TensorFlow in pure Rust. Both lanes use
owned thin wrappers over the same already-loaded TensorFlow wheel's public TFE
C API plus a private EagerTensor bridge (RTLD_NOLOAD). The CUDA lane has a
separate generated module and Rust tensor type. Its inclusion in the package
does not make it a CUDA support, certification, or performance claim.
| Status field | Value |
|---|---|
| Version | 0.1.3 (src/rextio_tensorflow/__about__.py) |
| Maturity | Public Alpha PoC — limited, version-pinned native-AOT surface |
| Release state | Released 2026-07-27 as rextio-tensorflow==0.1.3; prior release 0.1.2 (2026-07-26) |
| Performance claim | None — no benchmark gate; Alpha does not claim speedups |
| Pure-Rust TensorFlow | No — native helpers call into the active wheel |
| Abandoned TF Rust crates | Not used as Cargo dependencies (crate_dependencies() == ()) |
| CUDA candidate | Build-only hosted CI plus opt-in first-stage real-NVIDIA evidence; support_claim=false, certification_ready=false |
The 0.1.3 release requires Core rextio>=0.1.6,<0.2 and plugin API 1.6.
It rejects boundary-free standalone Rust lowering.
CUDA lowering also requires exact authorization from
rextio-device-cuda/cuda-tensorflow-tfe-linux-x86_64.
The hosted CUDA job is compile/link-only: it never installs/imports TensorFlow,
loads the extension, or executes CUDA. A separately opt-in real-NVIDIA
first-stage harness may produce self-attested execution/parity/lifetime
evidence; its closed schema requires kernel_activity_verified=false and
runtime_transfer_profiled=false, and preserves support_claim=false and
certification_ready=false. The offline verifier establishes schema and
payload integrity only, not GPU execution, hardware certification, or CUDA
support. See
the CUDA build-only and manual-evidence contract
for the exact Linux GNU/CPython 3.11/TF 2.21.0/Rust 1.93.1 pins, clean
candidate checkout, GPU:0/permitted-SM boundary, and commands.
The 0.1.0 final release verification completed on 2026-07-18: GitHub Actions
run 29597803215
finished 13/13 jobs successfully, and a no-cache CPython 3.11 install from
PyPI resolved tensorflow==2.21.0 and exposed the plugin entry point with API
1.3 metadata. This is release evidence, not a performance claim.
Unsupported call sites stay on Rextio’s ordinary Python fallback at analysis time. Sites that are claimed and lowered native still fail closed at runtime on version / symbol / boundary mismatch. no transparent runtime-availability / module-init retry hook.
Version, platform, and ABI contract
Some entries are exact compatibility pins; others are package ranges, MSRV
contracts, or certification evidence. They are enforced by package metadata,
plugin registration, the generated runtime helper
(rextio_tensorflow_runtime), or the stated certification environment.
| Component | Contract | Enforcement / evidence |
|---|---|---|
| Package version | 0.1.3 |
__about__.__version__ |
| CPython | 3.11 only (requires-python = ">=3.11,<3.12") |
pyproject.toml; runtime rejects other implementations/versions |
| Platform profiles | See Platform ABI profiles below | Compile-time PlatformAbiProfile + runtime validate_platform |
| Rextio package | >=0.1.6,<0.2 |
API 1.6 device metadata and authorization |
| Plugin API | 1.6 (REQUIRED_PLUGIN_API = "1.6") |
plugin.py; loader contract tests |
| TensorFlow (Python) | tensorflow==2.21.0 |
pyproject.toml dependency; runtime checks tf.__version__ |
| TensorFlow (C) | TF_Version() == "2.21.0" |
Runtime Api::load |
| Device | CPU lane: CPU:0; CUDA candidate: exact enumerated GPU:0 |
CUDA uses TFE_ContextListDevices and exact full-name equality |
| Dtype | float32 operation inputs/intermediates; default-int64 ArgMax output | Runtime checks float32 rank-1/2 inputs and exact int64 rank-1 classification output/boundaries |
| Ranks | float32 rank 1/2; int64 rank 1 only | Type vocabulary + claim/lower and boundary checks |
| Execution surface | Inference/no-grad only | CUDA rejects when a backward tape or forward accumulator may record the supplied inputs, before handle copying or execution |
| CUDA build toolchain | Rust 1.93.1, CPython 3.11, Linux x86_64 GNU | Exact build-only CI contract |
| Certified Rust toolchain | rustc 1.93.1, cargo 1.93.1 on aarch64-apple-darwin |
Used for the current real-Cargo Alpha evidence; this repo has no rust-toolchain.toml |
| Rust TF crates | None | crate_dependencies() == (); helpers must not use tensorflow-sys / high-level tensorflow crate |
The TensorFlow and CPython pins are intentionally exact because this Alpha
crosses a private eager ABI. A successful install on another version is not a
support claim. Release metadata uses the standard
Development Status :: 3 - Alpha classifier; source availability and a dated
release do not broaden the certified runtime profiles below.
Platform ABI profiles
The generated runtime selects an explicit platform ABI profile at compile
time (loader flags, wheel image basenames, Python platform.machine() tags).
Common load logic never assumes Darwin-only paths or Darwin dlfcn numeric
values mixed into Linux.
| Profile id | Class | Target triple (Rust) | Python machines | Wheel images (relative to tensorflow package root) |
dlopen flags (numeric) |
|---|---|---|---|---|---|
macos-arm64 |
Certified | aarch64-apple-darwin |
arm64 |
libtensorflow_cc.2.dylib, libtensorflow_framework.2.dylib, python/lib_pywrap_tensorflow_common.dylib |
Darwin: RTLD_NOW=0x2, RTLD_LOCAL=0x4, RTLD_NOLOAD=0x10 |
linux-x86_64 |
Experimental | x86_64-unknown-linux-gnu (target_env=gnu only) |
x86_64 |
libtensorflow_cc.so.2, libtensorflow_framework.so.2, python/lib_pywrap_tensorflow_common.so |
Linux glibc: RTLD_NOW=0x2, RTLD_LOCAL=0, RTLD_NOLOAD=0x4 |
linux-aarch64 |
Experimental | aarch64-unknown-linux-gnu (target_env=gnu only) |
aarch64 or arm64 |
same Linux basenames as x86_64 | same Linux glibc values |
| (compile_error!) | Native-build fail-closed | Windows, Linux musl, macOS x86_64/i686/ARMv7, Linux i686/ARMv7, and every other triple | n/a | n/a | n/a — clear compile_error! at native build (not a runtime dlfcn path) |
Certified means a real-Cargo E2E path has been run on that profile (macOS
arm64 only today). Experimental means official tensorflow==2.21.0
manylinux / glibc wheel archives were inspected offline for image layout
and exported private bridge symbols, and the runtime profile is wired for
Linux GNU only (target_env=gnu). This tree does not claim a certified
real-Cargo Linux E2E or any performance result. Linux musl is unsupported.
Public CI truth matrix
The machine-readable source of truth is
ci/platform-contract.json. Every requested
Linux/macOS × x86/x64/ARM32/ARM64 cell is present, but only an upstream runtime
profile can run native E2E. Static platform-contract jobs test the remaining
cells as expected fail-closed outcomes; they are not emulated support claims.
| Requested cell | Public Alpha result | CI treatment |
|---|---|---|
| Linux x86_64 | Experimental; merged PR #1 passed real Cargo + TF 2.21.0 candidate-wheel E2E | Hosted native E2E remains a release gate |
| Linux AArch64 | Experimental / availability-gated | Manual ubuntu-24.04-arm native E2E; no claim until green evidence exists |
| Linux i686 | Unsupported — no pinned upstream runtime | Static expected-unsupported / native-build fail-closed |
| Linux ARMv7 | Unsupported — no pinned upstream runtime | Static expected-unsupported / native-build fail-closed |
| macOS ARM64 | Certified Alpha baseline | Hosted native E2E plus existing local real-Cargo evidence |
| macOS x86_64 | Availability-gated, currently unsupported — no exact TF 2.21.0 wheel | Static expected-unsupported / native-build fail-closed |
| macOS i686 | Impossible modern target / unsupported | Static expected-unsupported / native-build fail-closed |
| macOS ARMv7 | Impossible modern target / unsupported | Static expected-unsupported / native-build fail-closed |
The main workflow separates quality, platform-contract, native-e2e, and
package jobs. Native E2E builds and installs the candidate wheel before
running the real route/lifetime suite; it does not certify an editable source
checkout. Actions have read-only repository permissions and every
third-party Action reference is pinned to an immutable commit. Linux AArch64
is a separate manual experimental workflow so runner availability cannot be
misrepresented as routine certification. A stable aggregate ci-gate job is
the intended branch-protection check.
On Linux GNU, the generated helper links libdl explicitly
(#[link(name = "dl")]) so cdylibs do not rely on incidental global
resolution of dlopen/dlsym on older manylinux/glibc.
Inspected wheels (download-only; not installed into the host environment):
tensorflow-2.21.0-cp311-cp311-macosx_12_0_arm64.whltensorflow-2.21.0-cp311-cp311-manylinux_2_27_x86_64.whltensorflow-2.21.0-cp311-cp311-manylinux_2_27_aarch64.whl
Windows support is explicitly deferred. Unsupported compile targets
(Windows, musl, other) fail closed at native build via compile_error!
because the POSIX dlfcn externs are not a truthful runtime contract there.
Runtime availability failures on supported profiles still never silently retry
the Python body under plugin API 1.6 (no runtime-availability hook).
Why a private ABI exists
Public TFE C symbols alone are not enough to round-trip Python
tf.Tensor / EagerTensor objects at the function boundary without host
resolve. The Alpha runtime therefore also resolves private bridge
symbols from the active wheel’s pywrap image
(python/lib_pywrap_tensorflow_common.{dylib,so}; Itanium-mangled names).
Artifact-level nm of the three official 2.21.0 wheels above confirms the
same three exports on macOS arm64 and Linux x86_64/aarch64:
| Private symbol (mangled) | Role |
|---|---|
_Z18EagerTensor_HandlePK7_object |
EagerTensor_Handle — extract underlying TFE_TensorHandle* |
_Z21EagerTensorFromHandleP16TFE_TensorHandleb |
EagerTensorFromHandle — takes ownership of the handle (is_packed=false) |
_Z22EagerTensor_CheckExactPK7_object |
Exact EagerTensor type check |
These are private ABI: a TensorFlow patch within 2.21.x can break them.
That is an explicit residual risk of this PoC, not a public stability promise.
The bridge also depends on Python internals in
tensorflow.python.eager.context: context(), ensure_initialized(),
is_async(), and the private context()._handle null-named capsule.
Only the existing synchronous eager context is accepted. These Python-side
details are part of the same exact-2.21.0 private ABI pin even though they are
not C++ symbols.
Supported TensorFlow forms and result ranks
Claim decisions are pure functions of Rextio API 1.6 site metadata (kind,
target, operand types, keyword literals). Lowering revalidates the
same constraints and fails with ValueError (not assert).
| Python form | Accepted targets | Operand ranks | Keywords | Result rank | Rule id | Diagnostic |
|---|---|---|---|---|---|---|
| MatMul | tf.matmul / tf.linalg.matmul (also tensorflow.*) |
2 × 2 only | None (no transpose_*) |
2 | rextio-tensorflow/matmul-f32-cpu-2d |
RXTP-TENSORFLOW-001 |
| ReLU | tf.nn.relu |
1 or 2 | None | preserves rank | rextio-tensorflow/relu-f32-cpu-{1,2}d |
RXTP-TENSORFLOW-018 / 002 |
| Sigmoid | tf.nn.sigmoid |
1 or 2 | None | preserves rank | rextio-tensorflow/sigmoid-f32-cpu-{1,2}d |
RXTP-TENSORFLOW-019 / 005 |
| Tanh | tf.nn.tanh |
1 or 2 | None | preserves rank | rextio-tensorflow/tanh-f32-cpu-{1,2}d |
RXTP-TENSORFLOW-020 / 009 |
| Math unary | tf.abs, tf.negative, tf.square, tf.exp, tf.math.log, tf.math.sqrt |
1 or 2 | exactly one positional operand; no keywords | preserves rank | rextio-tensorflow/{abs,negative,square,exp,log,sqrt}-f32-cpu |
RXTP-TENSORFLOW-026–031 |
| Add (call) | tf.add / tf.math.add |
See add pairs below | None | max rank | rextio-tensorflow/add-call-f32-cpu |
RXTP-TENSORFLOW-003 |
| Add (binop) | binary + |
See add pairs below | n/a | max rank | rextio-tensorflow/add-binop-f32-cpu |
RXTP-TENSORFLOW-006 |
| Multiply | tf.multiply / tf.math.multiply or binary * |
See binary pairs below | calls take exactly two positional operands; no keywords | max rank | rextio-tensorflow/mul-{call,binop}-f32-cpu |
RXTP-TENSORFLOW-013 / 012 |
| Subtract | tf.subtract / tf.math.subtract or binary - |
See binary pairs below | calls take exactly two positional operands; no keywords | max rank | rextio-tensorflow/sub-{call,binop}-f32-cpu |
RXTP-TENSORFLOW-014 / 015 |
| Divide | tf.divide / tf.math.divide or binary / |
See binary pairs below | calls take exactly two positional operands; no keywords | max rank | rextio-tensorflow/div-{call,binop}-f32-cpu |
RXTP-TENSORFLOW-016 / 017 |
| Maximum / minimum | top-level tf.maximum / tf.minimum |
1 × 1 or 2 × 2, equal ranks with TensorFlow-compatible same-rank broadcasting | exactly two positional non-literal tensors; no keywords | preserves rank | rextio-tensorflow/{maximum,minimum}-call-f32-cpu |
RXTP-TENSORFLOW-032 / 033 |
| Reduce mean | tf.reduce_mean / tf.math.reduce_mean |
2 | literal axis=0|1, keyword or positional; named literal keepdims=True|False or omitted |
1 or 2 | legacy axis-1 rule or rextio-tensorflow/reduce-mean-literal-axis-f32-cpu-2d |
RXTP-TENSORFLOW-004 / 022 |
| Reduce sum | tf.reduce_sum / tf.math.reduce_sum |
2 | literal axis=0|1, keyword or positional; named literal keepdims=True|False or omitted |
1 or 2 | legacy axis-1 rule or rextio-tensorflow/reduce-sum-literal-axis-f32-cpu-2d |
RXTP-TENSORFLOW-011 / 023 |
| Softmax | tf.nn.softmax |
1 or 2 | rank 1: omitted or literal axis=0; rank 2: explicit literal axis=1; literal axes may be keyword or positional |
preserves float32 rank | rextio-tensorflow/softmax-axis{0-f32-cpu-1d,1-f32-cpu-2d} |
RXTP-TENSORFLOW-025 / 007 |
| ArgMax | tf.argmax |
2 float32 | explicit literal axis=0|1, keyword or positional; default output type only |
1 int64 | rextio-tensorflow/argmax-axis{0,1}-i64-cpu-2d |
RXTP-TENSORFLOW-024 / 008 |
| Transpose | tf.transpose / tensorflow.transpose |
2 float32 | None (default Python perm only; no perm / conjugate / name) |
2 | rextio-tensorflow/transpose-f32-cpu-2d |
RXTP-TENSORFLOW-039 |
| Bias add | tf.nn.bias_add |
rank-2 value + rank-1 bias | data format omitted or named literal NHWC; tensor operands positional |
2 float32 | rextio-tensorflow/bias-add-nhwc-f32-cpu-2d |
RXTP-TENSORFLOW-021 |
Elementwise operand pairs (add, multiply, subtract, and divide)
| Left | Right | Result |
|---|---|---|
| rank-2 | rank-2 | rank-2 |
| rank-1 | rank-1 | rank-1 |
| rank-2 | rank-1 | rank-2 (trailing bias broadcast) |
| rank-1 | rank-2 | rank-2 (either order) |
Claims prove ranks only. Concrete matrix / broadcast dimension
compatibility is checked by TFE (MatMul, AddV2, …) at runtime.
Maximum/minimum are narrower than the general binary matrix because mixed
ranks are excluded. Within equal ranks, the owned TFE operation preserves
TensorFlow's normal broadcasting and incompatible-shape behavior.
Coverage declaration (analyzer routing)
Declared packages/modules/symbols (rules/coverage.py):
- packages:
tensorflow - modules:
tensorflow,tensorflow.linalg,tensorflow.nn,tensorflow.math - symbols:
tensorflow.matmul,tensorflow.linalg.matmul,tensorflow.nn.relu,tensorflow.nn.sigmoid,tensorflow.nn.tanh,tensorflow.abs,tensorflow.negative,tensorflow.square,tensorflow.exp,tensorflow.math.log,tensorflow.math.sqrt,tensorflow.add,tensorflow.math.add,tensorflow.multiply,tensorflow.math.multiply,tensorflow.subtract,tensorflow.math.subtract,tensorflow.divide,tensorflow.math.divide,tensorflow.maximum,tensorflow.minimum,tensorflow.reduce_mean,tensorflow.math.reduce_mean,tensorflow.reduce_sum,tensorflow.math.reduce_sum,tensorflow.nn.softmax,tensorflow.argmax,tensorflow.nn.bias_add
Boundary annotation types
Import-free markers (rextio_tensorflow.types — never import TensorFlow):
| Annotation | Plugin type key | Rust native type |
|---|---|---|
TensorF32Cpu2D |
rextio-tensorflow/tensor-f32-cpu-2d |
rextio_tensorflow_runtime::RxtTfTensor |
TensorF32Cpu1D |
rextio-tensorflow/tensor-f32-cpu-1d |
rextio_tensorflow_runtime::RxtTfTensor |
TensorI64Cpu1D |
rextio-tensorflow/tensor-i64-cpu-1d |
rextio_tensorflow_runtime::RxtTfTensor |
Runtime values remain ordinary tf.Tensor / EagerTensor objects. Intermediates
between helpers stay TFE_TensorHandle-native (RxtTfTensor RAII). Python
for / if that Rextio core can prove from scalar values remain ordinary core
Rust control flow. Tensor-data-dependent branches are not part of this plugin
surface.
TensorI64Cpu1D is the default tf.argmax result type and is also a real
input boundary type: native functions annotated with it accept only exact
CPU int64 rank-1 EagerTensors. They reject float inputs, other ranks,
tf.Variable, alternate runtimes, and non-CPU devices before executing.
Canonical lowered helpers
Lowering emits calls into the exact generated module
rextio_tensorflow_runtime (single helper block; no Cargo TF crates):
| Op | Emitted Rust (shape) |
|---|---|
| matmul | rextio_tensorflow_runtime::matmul(&a, &b)? |
| relu | rextio_tensorflow_runtime::relu(&x)? |
| sigmoid | rextio_tensorflow_runtime::sigmoid(&x)? |
| tanh | rextio_tensorflow_runtime::tanh(&x)? |
| abs / negative / square / exp / log / sqrt | rextio_tensorflow_runtime::{abs,negative,square,exp,log,sqrt}(&x)? |
add / + |
rextio_tensorflow_runtime::add(&a, &b)? |
| bias add (NHWC) | rextio_tensorflow_runtime::bias_add(&value, &bias)? |
multiply / * |
rextio_tensorflow_runtime::mul(&a, &b)? |
subtract / - |
rextio_tensorflow_runtime::sub(&a, &b)? |
divide / / |
rextio_tensorflow_runtime::div(&a, &b)? |
| maximum / minimum | rextio_tensorflow_runtime::{maximum,minimum}(&a, &b)? |
| reduce_mean axis=0/1 | reduce_mean_axis{0,1}[_keepdims](&x)? |
| reduce_sum axis=0/1 | reduce_sum_axis{0,1}[_keepdims](&x)? |
| softmax final axis | rank 1: softmax_axis0(&x)?; rank 2: softmax_axis1(&x)? |
| argmax axis=0/1 (int64) | rextio_tensorflow_runtime::argmax_axis{0,1}(&x)? |
| boundary extract | extract_f32_cpu_{1,2}d / extract_i64_cpu_1d |
| boundary materialize | materialize_tensor (via EagerTensorFromHandle, ownership transfer) |
Static preconditions (must hold at claim/lower time)
All of the following are required for a site to be Claimed and lowered:
- Annotations — claimed TensorFlow operation operands use the plugin
float32 CPU types above (not bare
tf.Tensoror unannotated/Nonetypes).TensorI64Cpu1Dis limited to the classification result and exact rank-1 function input boundary; it is not accepted as a TensorFlow operation input. - Functional style only — covered calls with a receiver are
NotCovered(no method-style receivers on matmul / unary operations / add / reduce_mean / reduce_sum). Lowering also rejects claimed/rendered receivers withValueError. - Positional operands only for matmul / activations / math unary / add
(keywords →
Rejected). - Matmul — exactly two rank-2 tensors; no transpose keywords.
- Unary operations — activations and the exact listed math-unary targets
accept exactly one rank-1 or rank-2 tensor and no keywords. Alternate
TensorFlow spellings such as
tf.math.absare not inferred aliases. - Elementwise binary ops — exactly two tensors in a supported rank pair (table above). Calls accept only the explicitly listed canonical targets and two positional operands; scalars and inferred aliases are excluded.
- reduce_mean / reduce_sum — one rank-2 tensor plus static literal integer
axis 0 or 1, either by keyword or as the second positional operand with
exactly aligned
operand_literals.axismetadata must have typeint.keepdimsis omitted or a named literal bool with typebool; positional keepdims, duplication, dynamic values, and extra keywords are rejected. The positional axis is validated at lower time but never emitted as a TFE input. - Classification — Softmax accepts rank-1 with its final axis omitted or
literal axis 0, and rank-2 with explicit final axis 1. Raw TFE Softmax is
last-axis-only (Softmax does not synthesize a transpose). ArgMax accepts
explicit literal axis 0 or 1 and retains default int64 output. Neither
accepts
keepdims; extra/output-type keywords are rejected. - Default transpose — exactly one rank-2 float32 CPU tensor; no keywords.
Default Python perm only (
[1, 0]); explicitperm,conjugate, andnameare rejected. - BiasAdd — value is rank-2 float32 CPU, bias is rank-1 float32 CPU, both
are positional and ordered value-then-bias.
data_formatis omitted or named literalNHWC; NCHW, dynamic/positional format,name, keyword tensor operands, and other rank orders are rejected. - No dynamic axis/dtype/rank proof — only the fixed Alpha vocabulary.
- Inference-oriented slice — not training/
GradientTape, graph/Session,tf.function/AutoGraph, or non-CPU:0execution.
Static claims do not prove concrete shapes (e.g. matmul inner dimensions). Concrete incompatibilities fail later inside the owned TFE operation, including Maximum/Minimum shapes that cannot broadcast.
Unsupported / fallback forms
Anything outside the tables above is either:
| Outcome | Meaning | Typical cases |
|---|---|---|
NotCovered |
Plugin declines; site may stay on ordinary Python fallback | Unknown symbols (tf.cos, …); method receivers on covered targets; untyped (None) operands |
Rejected |
Recognized shape but not lowerable; diagnostic + Python fallback | Wrong ranks; keywords on unary/binary calls; missing/dynamic/forged metadata; positional keepdims; non-plugin tensor types; unsupported BiasAdd format/forms |
Explicit exclusions (not Alpha-supported)
- GPU,
CPU:1or later, and every device other thanCPU:0 - Training,
GradientTape, optimizers, or a general TensorFlow no-grad contract tf.Variableor any non-exact EagerTensor at the Python boundary (E2E rejects it)- Graph / Session,
tf.function, AutoGraph, Keras, or SavedModel - Tensor-data-dependent Python
if/for,tf.cond, ortf.while_loop - Non-float32 operation inputs; int64 is supported only for the exact rank-1 ArgMax classification result and its annotated Python boundary
- Rank-1 matmul; rank-3+ / batched matmul
- Dynamic or non-0/1 reduction/classification axes; positional
keepdims; rank-1 Softmax axis 1, rank-2 Softmax axis 0/default;tf.argmax(output_type=...) - Explicit
tf.transposeperm/conjugate/name; rank-1 or non-float32 transpose; matmultranspose_*/ other matmul keywords - Graph /
tf.function/FunctionDeffusion, cross-generated-function residency, process-global prepared-constant caches, and a Core-injected per-generated-functionInvocationContext(plugin API 1.6 has no invocation/prologue hook). 0.1.3 reuses (1) context-bound axes/permutation handles while aBorrowedContextRclives and (2) value-carried dtype/rank/device facts on already-validated resident intermediates inside one generated call graph — never a process-wide or thread-local tensor cache - In-place ops; scalar operands; inferred aliases such as
tf.math.truediv;tf.math.maximum/tf.math.minimum, raw-op forms, and mixed-rank broadcasting fortf.maximum/tf.minimum - Host resolve (
TFE_TensorHandleResolve) on the inference path - DLPack
TFE_NewContext/ second eager context / Session- Asynchronous eager contexts or mixing tensors from different eager contexts
- Loading alternate dylibs (
RTLD_DEFAULTnot used) - Cargo dependency on abandoned high-level
tensorflowcrate ortensorflow-sys - Any performance claim (no benchmark gate for Alpha)
Fallback rule record: rextio-tensorflow/unsupported-tensor-surface
(RXTP-TENSORFLOW-010, outcome fallback).
Same-wheel runtime reuse (RTLD_NOLOAD)
The generated runtime binds only images already loaded by the active
tensorflow==2.21.0 process — it does not load a second TensorFlow.
It never uses RTLD_DEFAULT or a process-global symbol search as a substitute
for per-image dlsym + dladdr provenance.
On first API load (Api::load):
- Compile only for a supported
PlatformAbiProfile(elsecompile_error!). At runtime require CPython 3.11, a matchingplatform.machine(), and Pythontf.__version__ == "2.21.0". - Canonicalize the three active-wheel library paths under the package root
using the profile’s basenames (
.dylibon certified macOS arm64;.so.2/.soon experimental Linux GNU). - Open each path only with
RTLD_NOW | RTLD_LOCAL | RTLD_NOLOADusing OS-specific numeric values (DarwinRTLD_NOLOAD=0x10vs Linux glibcRTLD_NOLOAD=0x4; LinuxRTLD_LOCAL=0). Missing image → error (never an instruction to load another copy). - Resolve each symbol from its owning image (
cc/framework/pywrap) and verify provenance withdladdr. - Require
TF_Version() == "2.21.0", importtensorflow.python.eager.context, and reuse the existing synchronous Python eager context's null-named private capsule (context()._handle) — noTFE_NewContext. - Retain the three handles with the function table so pointers stay live.
The caller does not have to pre-import TensorFlow: lazy runtime initialization
calls py.import("tensorflow"). By the time RTLD_NOLOAD runs, however, the
three expected images from that exact active wheel must be mapped. If the
imported wheel does not map them, initialization fails closed rather than
loading a second TensorFlow runtime.
Invocation-local reuse (0.1.3; bounded non-claim)
Core PLUGIN_API_VERSION 1.6 exposes claim/lower/covers/describe/type
vocabulary and optional artifact_capability only — no
per-generated-function invocation or prologue hook. This plugin therefore does
not invent a process-global, thread-local, or cross-context tensor/context
cache.
What 0.1.3 does deliver, carried by existing generated values:
| Reuse | Scope | Notes |
|---|---|---|
| Pinned Python eager context | BorrowedContext |
Same synchronous capsule; no TFE_NewContext |
| Prepared axes / transpose perm | BorrowedContext table |
Context-bound RAII; not process-global |
| Dtype / rank / device facts | TrustedResidentFacts on OwnedTensorHandle |
Stamped after full validation; reused for later typed checks of that handle |
TF_Status |
Per operation | No public TF_ResetStatus on TF 2.21.0; allocation stays fail-closed per op |
Avoided after facts are trusted for a handle: redundant
TFE_TensorHandleDataType / NumDims / Dim / BackingDeviceName queries
for that same resident intermediate. Not avoided: boundary extract
validation (exactly once), operation-result validation before stamping new
facts, same-context checks, error messages, unsupported dtype/rank/device
rejection, or PendingHandle / OwnedTensorHandle / PreparedHandle /
BorrowedContext drop ordering.
A true explicit InvocationContext spanning one generated function remains a
Core blocker (needs a prologue/invocation hook, and optionally a
fail-closed public status-reset symbol for reusable TF_Status).
Compile-time fallback vs runtime fail-closed
| Phase | Behavior | Transparent Python retry? |
|---|---|---|
| Analysis / claim | Claimed → lower to native; NotCovered / Rejected → ordinary Rextio Python fallback for that site |
Yes — unsupported sites never leave the fallback path |
| Lowering | Revalidates claim metadata; mismatch → ValueError (survives python -O) |
N/A (compile/codegen failure) |
Native runtime (version, symbols, RTLD_NOLOAD, dtype/rank/device/boundary) |
Raise stable rextio-tensorflow: … exceptions (PyRuntimeError / PyValueError / type errors on extract) |
No — plugin API 1.6 has no runtime-availability / module-init hook to transparently re-run the Python body |
Runtime error string prefixes used in contracts include (see
diagnostics.RUNTIME_ERRORS and E2E boundary checks):
rextio-tensorflow: expected a TensorFlow EagerTensorrextio-tensorflow: expected a CPU tensorrextio-tensorflow: expected a float32 tensor- rank mismatches on extract (message includes rank expectation)
- version / symbol / wheel-path mismatches under the same
rextio-tensorflow:prefix
Accepted and rejected examples
Accepted (claim → native lower)
from rextio_tensorflow.types import TensorF32Cpu1D, TensorF32Cpu2D, TensorI64Cpu1D
import tensorflow as tf
def inference(
x: TensorF32Cpu2D,
weight: TensorF32Cpu2D,
bias: TensorF32Cpu1D,
) -> TensorI64Cpu1D:
h = tf.matmul(x, weight) # rank-2 → rank-2
h = tf.nn.relu(h) # rank-2 → rank-2
h = tf.nn.sigmoid(h) # optional; rank-2 → rank-2
h = h + bias # or tf.add(h, bias); rank-2
probabilities = tf.nn.softmax(h, axis=1) # literal axis=1 → rank-2
return tf.argmax(probabilities, axis=1) # default int64 → rank-1
Also accepted (when types match the tables):
tf.linalg.matmul(a, b)(alias of matmul rule)- Explicit
tf.math.{add,multiply,subtract,divide}aliases and+ * - /across the bounded rank matrix - top-level
tf.maximum/tf.minimumfor two same-rank rank-1 or rank-2 tensors with TensorFlow-compatible broadcast shapes - rank-1
tf.nn.relu/sigmoid/tanh - rank-1/rank-2
tf.abs,tf.negative,tf.square,tf.exp,tf.math.log, andtf.math.sqrt - rank-1
tf.nn.softmax(x)andtf.nn.softmax(x, axis=0) tf.nn.bias_add(matrix, bias)and the explicitdata_format="NHWC"formtf.reduce_mean(x, 0, keepdims=True)andtf.reduce_sum(x, axis=1, keepdims=False)tf.argmax(x, 0); rank-2 Softmax remains explicit axis 1 only
Core-lowerable scalar Python control flow around claimed ops is supported. The
real-Cargo E2E uses range(depth) and an integer condition to choose relu or
sigmoid; tensor-dependent control flow remains unsupported.
Rejected or not covered (stay on fallback or fail claim)
| Example | Outcome (claim layer) |
|---|---|
tf.matmul(rank1, rank2) |
Rejected (wrong ranks) |
tf.matmul(a, b, transpose_b=True) |
Rejected (keywords) |
tf.reduce_mean(x) without an explicit axis |
Rejected |
tf.reduce_mean(x, 0, True) positional keepdims |
Rejected |
| dynamic/non-aligned/forged axis metadata | Rejected |
tf.reduce_sum(x, axis=2) or duplicate axis |
Rejected |
rank-2 tf.nn.softmax(x) / tf.nn.softmax(x, axis=0) |
Rejected |
rank-1 tf.nn.softmax(x, axis=1) |
Rejected |
tf.argmax(x, axis=1, output_type=tf.int32) |
Rejected |
tf.nn.bias_add(x, bias, data_format="NCHW") |
Rejected |
tf.maximum(rank2, rank1) / tf.minimum(rank1, rank2) |
Rejected (mixed ranks / broadcasting excluded) |
tf.math.maximum(x, y) / raw-op forms |
NotCovered (only exact top-level targets are declared) |
tf.cos(x) |
NotCovered |
| Method-style receiver on a covered call | NotCovered |
| Operand types outside plugin vocabulary on a covered symbol | Rejected (RXTP-TENSORFLOW-010 / op diagnostic) |
Runtime fail-closed (after successful native claim/build)
E2E boundary checks (real Cargo path) assert exceptions when native code is invoked with annotation-violating values, for example:
Runtime value at a TensorF32Cpu2D parameter |
Observed failure |
|---|---|
float64 tensor |
dtype message (expected a float32 tensor) |
| rank-1 float32 tensor | rank message |
tf.Variable(...) |
expected a TensorFlow EagerTensor |
| NumPy array | expected a TensorFlow EagerTensor |
These do not transparently fall back to the Python body under API 1.6.
Alpha surface (reference sketch)
from rextio_tensorflow.types import TensorF32Cpu1D, TensorF32Cpu2D, TensorI64Cpu1D
import tensorflow as tf
def inference(
x: TensorF32Cpu2D,
weight: TensorF32Cpu2D,
bias: TensorF32Cpu1D,
) -> TensorI64Cpu1D:
h = tf.matmul(x, weight)
h = tf.nn.relu(h)
h = h + bias
return tf.argmax(tf.nn.softmax(h, axis=1), axis=1)
Boundary and ABI contract (summary)
- Python boundary types:
TensorF32Cpu2D/TensorF32Cpu1D/TensorI64Cpu1D(import-free markers); the classification head materializes exactly int64 rank-1 output. - Native type:
rextio_tensorflow_runtime::RxtTfTensor(owned handle RAII; clones shareRcowner — never an unowned pointer fallback). - Extract: private
EagerTensor_HandlethenTFE_TensorHandleCopySharingTensor(no host resolve). - Materialize:
EagerTensorFromHandle(..., is_packed=false)takes ownership. - Exact Python
tensorflow.__version__and CTF_Version()must both be2.21.0; active-wheel images opened only with profileRTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD(OS-specific numeric values). - Reuses the existing Python eager context capsule. No
TFE_NewContext, no Session, no DLPack, noTFE_TensorHandleResolveon the inference path. - Borrowed context capsule and Python Context are held by strong Python references for every owned handle.
Install
# Latest published package on PyPI (CPython 3.11 only; installs
# tensorflow==2.21.0 exactly). This is rextio-tensorflow==0.1.3:
python -m pip install --no-cache-dir "rextio-tensorflow==0.1.3"
# Editable/dev install from this source tree:
python -m pip install -e ".[dev]"
The latest published package is rextio-tensorflow==0.1.3 with plugin API
1.6 entry-point metadata and the exact TensorFlow 2.21.0 dependency. The
exact CPython, TensorFlow, ABI, and platform requirements above still apply.
Tests
# Unit / contract (no Cargo), including all platform truth cells:
pytest tests -m "not needs_cargo" -q
# Real-Cargo E2E (run under CPython 3.11 + TF 2.21.0):
pytest tests/e2e/test_alpha_real_cargo.py -q
# Focused 0.1.3 slices (same suite; still equivalence-only, no speed gate):
pytest tests/e2e/test_alpha_real_cargo.py::test_resident_intermediate_chain_real_cargo -q
pytest tests/e2e/test_alpha_real_cargo.py::test_small_batch_scoring_equivalence_real_cargo -q
# Opt-in Linux experimental probe (skipped unless env set + Linux host):
REXTIO_TF_LINUX_PROBE=1 pytest tests/e2e/test_linux_experimental_probe.py -q
# Lint / types (when the dev extra is installed):
ruff check src tests
mypy src
Small-batch scoring interpretation: the
test_small_batch_scoring_equivalence_real_cargo case is a self-contained
non-release eager scoring workload (normalize → feature affine → 4
scalar-controlled relu/tanh rounds → head → softmax/argmax) over deterministic
float32 fixtures with batches 1 / 16 / 128, feature width 32, classes
8. It compares complete logits, probabilities, and classes among
Python source, generated fallback, and forced native. It does not assert
latency thresholds and makes no performance claim. An optional
tf.function Python diagnostic in that test is labeled non-headline and does
not gate or imply native graph fusion. Kernel-heavy existing E2E cases remain.
Focused unit tests cover analyzer-resolved import aliases, claim accept/reject,
positional-literal alignment, lower emission into
rextio_tensorflow_runtime, plugin API 1.6 loader contract, empty crate deps,
runtime-helper hardening (RTLD_NOLOAD, private bridge symbols, no
unwrap/panic! in helpers), and platform ABI profile source contracts
(certified macOS arm64, experimental Linux x86_64/aarch64, unsupported/
Windows/32-bit fail-closed). The E2E uses the invoking CPython 3.11
environment, requires exact TensorFlow 2.21.0, and fails if the configured
interpreter or platform contract differs. Merged PR #1 produced hosted
candidate-wheel real-Cargo evidence on macOS ARM64 and Linux x86_64. The
declared certification class remains macOS ARM64 only; Linux stays
experimental pending a separate support-promotion decision. The original
vertical slice remains rank-2 matmul → rank-2 activations → scalar Rust
control flow → broadcast add → classification. The 0.1.2 follow-up adds a
real-Cargo slice spanning rank-1 relu/sigmoid/tanh → functional multiply →
rank-1 Softmax default/axis 0 → Abs/Neg/Square/Exp/Log/Sqrt → NHWC BiasAdd →
subtraction → reverse-broadcast RealDiv → axis-0/axis-1 keepdims reductions →
same-rank broadcast Maximum/Minimum → ArgMax axis 0, with CPU,
NaN/Inf/domain/signed-zero, shape-error,
no-host-resolve, provenance, and lifetime checks. The 0.1.3 release adds
default rank-2 tf.transpose, context-bound prepared axis/permutation
handles for reductions, ArgMax, and transpose, and bounded
invocation-local reuse of validated dtype/rank/device facts on resident
intermediates (value-carried TrustedResidentFacts, not a global cache).
Core still lacks a per-generated-function prologue hook, so a true explicit
invocation object is not delivered. A self-contained small-batch eager
scoring equivalence slice (batches 1/16/128, feature width 32, classes 8)
compares full logits, probabilities, and classes across Python / fallback /
native without speed thresholds. No graph fusion or cross-function
residency. The Linux probe is opt-in and does not claim certification when
it has not been run.
Package metadata
| Field | Value |
|---|---|
| Name | rextio-tensorflow |
| Version | 0.1.3 |
| Entry point | rextio.plugins → rextio_tensorflow.plugin:plugin |
| Classifier | Development Status :: 3 - Alpha |
| Release date | 2026-07-27 |
| Distribution state | Released as rextio-tensorflow==0.1.3; prior release 0.1.2 (2026-07-26) |
| License | MIT |
The isolated PEP 517 build backend is pinned exactly to setuptools==82.0.1
and wheel==0.47.0; CI package/test tools are likewise exact-pinned under
ci/. Transitive TensorFlow dependencies remain resolved by its exact 2.21.0
wheel metadata.
This is the released 0.1.3 public Alpha source contract on the 0.1.2
foundation. The prior public Alpha 0.1.0 final CI run 29597803215 completed
13/13 jobs successfully, followed by the verified no-cache CPython 3.11
installation described above; that historical evidence remains scoped to
0.1.0.
For the intended Alpha architecture and staged scope, see the 0.1.0 implementation plan. Release-facing changes are recorded in CHANGELOG.md; this README is the current support contract.
What this is not
- Not pure-Rust TensorFlow — ops execute through the active wheel’s TFE C API; Rust owns handles and orchestration only.
- Not a whole-project TensorFlow translator — only the tabulated Alpha slice is claimable.
- Not a performance product — no speedup claim and no benchmark release gate for 0.1.3.
- Not a stable public ABI — private EagerTensor bridge symbols and exact eager-context internals plus exact 2.21.0 / CPython 3.11 pins and the certified-vs-experimental platform profiles are intentional Alpha constraints. Windows remains deferred.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rextio_tensorflow-0.1.3.tar.gz.
File metadata
- Download URL: rextio_tensorflow-0.1.3.tar.gz
- Upload date:
- Size: 141.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64cbe95c313e555d2f9a1982d8357096100a1debfbd6f5f36abcee77aaf32c5c
|
|
| MD5 |
f55d412bd3d776b0d877726adc2d457d
|
|
| BLAKE2b-256 |
763bb77b997363769475ce7a9515f36378e2ba4b4fbacadac272d005b40bd03f
|
File details
Details for the file rextio_tensorflow-0.1.3-py3-none-any.whl.
File metadata
- Download URL: rextio_tensorflow-0.1.3-py3-none-any.whl
- Upload date:
- Size: 71.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c5e09e01cabfbcf6722ba931689b966e2ebbf0dd9ca45217ece07b133059640
|
|
| MD5 |
2a8cf58dcd432ca02a722813f539e1e8
|
|
| BLAKE2b-256 |
83154775855b4279e829b77da221fb365a41e65dc862972808bbf0de296286bb
|