Stability and contracts
Stability and contracts
pyscriptc compiles the typed subset of Python 3.14.
Code either compiles to native code or runs through embedded CPython (fallback mode); the compiler provides no shims or dynamic runtime emulation for untyped Python.
This page states what is unstable, not what works.
The live compat status across modules and language features lives on the compat site.
Known runtime differences from standard CPython are cataloged in Divergences from CPython, and the codes that stop a compile are in Diagnostics.
Support tiers
The compiler codebase and its public interface are organized into three explicit stability tiers: Frozen contracts (Tier 1), Best-effort driver API (Tier 2), and Internal implementation surfaces (Tier 3).
Tier 1: Frozen contracts
Tier 1 surfaces represent contractual boundaries between the compiler, external tools, emitted artifacts, and user code.
Changes to any Tier 1 contract require a formal recorded decision, following the same governance discipline as the frozen v2 evaluation gates.
Every Tier 1 guarantee is grounded in an owning file:
- IR JSON schema and
irVersion: defined and validated insrc/pyscriptc/ir.py. The textual IR JSON emitted viapyscriptc compile --emit ircarries an explicitirVersion, the typedsubsetidentifier, and the CPython target stamp. Modules failing schema validation or carrying mismatched target versions are rejected byvalidate_module. - Runtime C ABI and
PS_ABI: defined insrc/pyscriptc/runtime/ps_rt.hand pinned byCURRENT_PS_ABIinsrc/pyscriptc/ffi_manifest.py. The runtime header maintains append-only struct definitions and frozenps_*C symbol signatures. Any modification to aps_*signature or%ps.*LLVM struct type bumpsCURRENT_PS_ABIor requires an explicit recorded no-bump decision. - FFI manifest format: defined in
src/pyscriptc/ffi_manifest.py. Manifest files (ffi.toml) enforceformat = 1and requireps_abi = CURRENT_PS_ABI. Manifests with mismatched ABI versions fail validation up front with diagnosticPS4004. - CLI exit codes: defined in
src/pyscriptc/cli.py. The CLI exit codes are contractually fixed:0for successful compilation or child run status,1for internal compiler faults (SpikeError),2for type-checker preflight failures (CheckFailed) or argument syntax errors,3for typed subset refusals and unsupported constructs, and4for target architecture or CPython version fit mismatches (VersionError,FitError). - Diagnostic codes: defined in
src/pyscriptc/diagnostics.py. Diagnostic codes (PSxxxx) are permanent, append-only identifiers divided into numeric categories: syntax and compilation (PS1xxx), types and static semantics (PS2xxx), runtime operations (PS3xxx), and architectural refusals (PS4xxx). A code is never repurposed or renumbered. - Divergence-list numbering: defined in
docs/reference/divergences.md. Every intentional divergence from CPython 3.14 receives a permanent numeric identifier. When an entry is resolved or removed, existing numbers are preserved or renumbered through an explicit decision record.
Dropped pack format
The pack format track (pack.toml, binary wheel pack distribution, and precompiled library archives) was permanently dropped per the 2026-10-25 typed-subset positioning decision (Decision 5). The pack format is not a stability tier. PyPI dependencies are consumed either by compiling pure-typed source directly or by routing through an embedded in-process CPython (fallback mode); consumption of compiled code from CPython routes through --emit binding (ctypes). Curated distribution packages (pyscriptc-orjson, pyscriptc-jwt) remain as narrow standalone exceptions under explicit alias imports.
Tier 2: Best-effort driver API
Tier 2 encompasses programmatic Python APIs and machine-readable CLI formats designed for tool integrators, build runners, and editor extensions. These interfaces avoid arbitrary breaking changes within minor release lines, and any breaking adjustment is documented in release changelogs. They are not frozen contracts.
- Programmatic driver entrypoints:
pyscriptc.lower.lower_source: compiles an annotated Python AST or source string into the intermediate representation.pyscriptc.emitter.emit_ir_text: serializes validated IR dictionaries into canonical JSON text.pyscriptc.ffi_manifest.load_manifests: parses and validates external FFI TOML specifications.pyscriptc.imports.build_import_report: categorizes module imports into standard library, native, and embedded-CPython lanes.pyscriptc.factsbridge.FactsProvider: provides static checker inference facts to the compiler pipeline.
- Machine-readable JSON outputs:
pyscriptc compile --debug=summaryand--print diagnostics: emits structured stage timings, lists ofPSxxxxcodes, and capability summaries.pyscriptc config --json: serializes the resolved project configuration and import lane mappings.pyscriptc coverage --json: serializes per-file and aggregate counts of unsupported constructs, reflection mechanisms, and porting hints.pyscriptc imports --json: serializes import classifications, reflection mechanisms, and libpython linkage requirements.- Machine-readable outputs carry a top-level
schemaVersioninteger field when versioned schemas are introduced.
Tier 3: Internal surfaces
Tier 3 covers internal compiler implementation modules, code generators, and deprecated bridge mechanisms. These surfaces carry no stability promise, can be refactored or deleted across any commit, and should not be imported or relied upon by external tools.
- Compiler passes: all modules under
src/pyscriptc/lower/(AST visitors, desugaring passes, type inference routines). - LLVM code generation internals: all modules under
src/pyscriptc/emit/llvm/(instruction builders, ABI layout helpers, block emitters). - Runtime shims and private C helpers: unexported structures and static helpers within
src/pyscriptc/runtime/. - Mypy plugin and bridge: the mypy plugin (
src/pyscriptc/check.py:plugin), the mypy facts bridge (src/pyscriptc/factsbridge.py:MypyBridge), and the--checker mypyCLI lane. The default compiler preflight ispyrefly, bundled in release binaries. The release binary compiles with--nofollow-import-to=mypyand omits mypy entirely. The mypy integration is deprecated, retained solely for cross-validation (benchmarks/factsdiff.py), and offers no API stability.
Versioned axes and canonicity
The compiler tracks four distinct versioned axes:
| Axis | Indicator | Purpose |
|---|---|---|
| IR Schema | irVersion in JSON IR (src/pyscriptc/ir.py) |
Identifies the textual JSON IR structure and required node fields |
| Runtime C ABI | CURRENT_PS_ABI (src/pyscriptc/ffi_manifest.py) |
Identifies the struct layout and calling convention between emitted LLVM IR and ps_rt.h |
| FFI Manifest | format and ps_abi in ffi.toml |
Guarantees external C extension manifests pair with the compiling runtime |
| Tool Output | schemaVersion in machine-readable JSON |
Tracks schema evolutions in CLI JSON output reports |
IR hashing and canonicity
PS_ABI and C runtime revisions do not affect IR canonicity. In accordance with the IR canonicity specification (.agents/docs/spec/ir-canonicity.md) and the canonical normalizer (benchmarks/compat2/canonical.py), canonical IR hashing evaluates only the validated semantic IR tree. Compiler environment details, host paths, and runtime ABI versions never enter the IR hash calculation.