Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,15 @@ See `docs/standards/documentation.md` for the deployment contract and required c

## Compatibility and Release Qualification

Before 2026-10-01, each library must pass installation, import, tests, type checking, and package
builds on Python 3.12 through 3.14 on Linux, macOS, and Windows. Python 3.15 prereleases must pass
core installation and non-hardware-dependent tests on all three systems.
Each library must pass installation, import, tests, type checking, and package builds on Python 3.12
through 3.14 on Linux, macOS, and Windows. Python 3.15 prereleases must pass core installation and
non-hardware-dependent tests on all three systems unless a dependency-blocked library has a
configured prerelease wait. A waiting library keeps a truthful upper bound and runs a visible
non-blocking canary at least monthly.

An ecosystem failure blocks the affected release unless an approved exception records its scope,
rationale, approver, and expiration date. Hardware-specific features use separate matrices.
rationale, approver, and an expiration date or objective review triggers. Hardware-specific features
use separate matrices.

See `docs/standards/compatibility.md` and `docs/standards/release-qualification.md`.

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ This repository does not contain library source code and is not a runtime depend
ML4T supports every stable CPython release from Python 3.12 through the latest stable version on
Linux, macOS, and Windows. Each supported combination must pass installation, import, tests, type
checking, and package build checks before release. The next CPython prerelease becomes a blocking
compatibility target after beta 1 without being advertised as stable.
compatibility target after beta 1 unless a library's required dependencies cannot yet pass it. A
dependency-blocked library keeps a truthful Python upper bound and runs a visible non-blocking
canary until its documented review triggers occur.

See [Compatibility](docs/standards/compatibility.md) and
[Release qualification](docs/standards/release-qualification.md) for the normative criteria.
19 changes: 10 additions & 9 deletions config/libraries.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,34 @@ homepage_url = "https://www.ml4trading.io/"
id = "python-315-polars"
criterion = "python-3.15-prerelease"
libraries = ["data", "engineer"]
affected_versions = ">=0.1.2,<=0.1.8"
rationale = "Polars 1.43.2 fails required expression and datetime operations on CPython 3.15.0rc1."
affected_versions = ">=0.1.2,<0.2"
rationale = "Polars 1.44.2 fails required series construction on CPython 3.15.0rc1."
evidence = [
"https://github.com/ml4t/data/issues/37",
"https://github.com/pola-rs/polars/issues/28347",
"https://github.com/pola-rs/polars/pull/28750",
"https://pypi.org/project/polars/1.44.2/#files",
]
user_impact = "These distributions cannot be installed on Python 3.15 while the exception is active."
user_impact = "These distributions cannot be installed on Python 3.15 while the prerelease wait applies."
mitigation = "Use Python 3.12 through 3.14 until a compatible Polars release is qualified."
approver = "Stefan Jansen"
expires_on = 2026-09-30
review_triggers = ["python-3.15-final", "polars-release-after-1.44.2"]
issue = "https://github.com/ml4t/ecosystem/issues/2"

[[exceptions]]
id = "python-315-scipy"
criterion = "python-3.15-prerelease"
libraries = ["diagnostic"]
affected_versions = ">=0.1.2,<0.1.7"
rationale = "The published dependency set lacks required CPython 3.15 wheels for PyArrow 25.0.1 and pydantic-core 2.46.5."
affected_versions = ">=0.1.2,<0.2"
rationale = "PyArrow 25.0.1 does not publish CPython 3.15 wheels, so the complete Diagnostic dependency set cannot install on CPython 3.15."
evidence = [
"https://github.com/ml4t/diagnostic/issues/45",
"https://pypi.org/project/pyarrow/25.0.1/#files",
"https://pypi.org/project/pydantic-core/2.46.5/#files",
]
user_impact = "The distribution cannot be installed on Python 3.15 while the exception is active."
user_impact = "The distribution cannot be installed on Python 3.15 while the prerelease wait applies."
mitigation = "Use Python 3.12 through 3.14 until the complete dependency set is qualified on Python 3.15."
approver = "Stefan Jansen"
expires_on = 2026-09-30
review_triggers = ["python-3.15-final", "pyarrow-26"]
issue = "https://github.com/ml4t/ecosystem/issues/2"

[[libraries]]
Expand Down
2 changes: 1 addition & 1 deletion decisions/0010-current-python-315-dependency-exceptions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Decision 0010: Current Python 3.15 dependency exceptions

**Status**: Accepted
**Status**: Superseded by Decision 0013
**Date**: 2026-09-19
**Approver**: Stefan Jansen
**Expires**: 2026-09-30
Expand Down
2 changes: 1 addition & 1 deletion decisions/0012-include-data-vcs-development-versions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Decision 0012: Include Data VCS development versions in the active exception

**Status**: Accepted
**Status**: Superseded by Decision 0013
**Date**: 2026-09-19
**Approver**: Stefan Jansen
**Expires**: 2026-09-30
Expand Down
53 changes: 53 additions & 0 deletions decisions/0013-python-315-waiting-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Decision 0013: Python 3.15 waiting policy

**Status**: Accepted
**Date**: 2026-09-20
**Approver**: Stefan Jansen

## Context

[Python 3.15.0 final is scheduled for 2026-10-01](https://peps.python.org/pep-0790/). Data and
Engineer depend on [Polars 1.44.2](https://pypi.org/project/polars/1.44.2/), which still fails
required Data operations on CPython 3.15.0rc1. Diagnostic depends on
[PyArrow 25.0.1](https://pypi.org/project/pyarrow/25.0.1/#files), which publishes no CPython 3.15
wheels. [Pydantic-core 2.49.0](https://pypi.org/project/pydantic-core/2.49.0/#files) now publishes
CPython 3.15 wheels and is no longer a current Diagnostic blocker.

The existing exceptions expire on 2026-09-30. That date does not measure whether the libraries can
install and pass their full suites. Requiring a new exception for each patch release would block
Python 3.12 through 3.14 users without improving Python 3.15 compatibility.

## Decision

Python 3.12 through 3.14 remain the blocking stable matrix. A library whose complete dependency set
cannot pass Python 3.15 may retain a truthful `<3.15` upper bound for its 0.1 release line. The
library must run a visible non-blocking Python 3.15 canary at least monthly and keep an owning issue
with current evidence.

Replace the 2026-09-30 expirations with these review triggers:

- Data and Engineer: Python 3.15 final or a Polars release after 1.44.2.
- Diagnostic: Python 3.15 final or PyArrow 26.

A trigger requires the owner to rerun installation, import, and the non-hardware-dependent suite on
Linux, macOS, and Windows. The result updates the owning issue and either removes the upper bound or
records why the wait continues. A trigger does not make Python 3.15 compatibility a condition for a
release that otherwise passes the stable matrix.

The existing `prerelease_exception` configuration and workflow input names remain to avoid breaking
the seven library workflows. Their trigger-based records now represent prerelease waits. Date-bounded
exceptions remain supported for other qualification criteria.

This decision supersedes the September 30 expiry and affected-version ranges in Decisions 0010 and
0012. Those decisions remain as the history of the evidence and earlier release scopes.

## Consequences

Data, Engineer, and Diagnostic can publish qualified 0.1 patch releases for Python 3.12 through
3.14 while their Python 3.15 dependencies remain unavailable. Their package metadata continues to
reject Python 3.15 rather than claiming support that has not passed qualification.

Ecosystem issue [#2](https://github.com/ml4t/ecosystem/issues/2), Data issue
[#37](https://github.com/ml4t/data/issues/37), and Diagnostic issue
[#45](https://github.com/ml4t/diagnostic/issues/45) remain open until the affected libraries pass the
complete Python 3.15 matrix.
32 changes: 32 additions & 0 deletions decisions/0014-agent-guide-conformance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Decision 0014: Agent guide conformance

**Status**: Accepted
**Date**: 2026-09-20

## Context

Decisions 0005 through 0009 established public root orientation, private sidecar plumbing, the ban
on public workspace state, the public ecosystem boundary, and optional development sidecars. The
release standard still contained one contradictory sidecar requirement, and the executable audit
checked only a root guide's word count and a few substrings. It could not discover stale nested
guides or volatile inventories.

## Decision

Adopt `docs/standards/agent-guides.md` as the public reference. Root guides describe the library,
source layout, public surface, change constraints, and current quality commands in no more than 200
lines. Nested guides are optional, directory-specific, and no more than 120 lines. Public guides do
not contain private state, agent-tool setup, volatile counts, or current work.

The workspace audit discovers tracked root and nested guides. It does not require empty discovery
files. Structural checks supplement, but do not replace, a library-level semantic review against
the package, documentation, and workflows.

Public repositories do not track `CLAUDE.md`. Private sidecars keep `AGENTS.md` as the source of
truth and a one-line `CLAUDE.md` import for interoperability.

## Consequences

Changes to package boundaries, public imports, repository layout, quality commands, release rules,
or subsystem constraints trigger a guide review. Ordinary implementation changes do not. Each
library owns remediation for its public files through its issue and pull-request workflow.
70 changes: 70 additions & 0 deletions docs/standards/agent-guides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Agent guides

This page is the reference standard for public `AGENTS.md` files in the seven stable library
repositories. Public guides help an external contributor understand a source checkout. Private
sidecars hold agent configuration, work management, and persistent local state.

## Root guide

Every public library tracks one root `AGENTS.md`, no longer than 200 lines. It must identify:

- the library's responsibility and public import package;
- the source tree, tests, documentation, examples, scripts, and major subsystems that exist;
- supported public imports or user workflows;
- compatibility and safety rules that affect changes;
- narrower nested guides, when they exist; and
- the repository's current `ruff`, format, `ty`, `pytest`, documentation, build, and pre-commit
commands as applicable.

The guide points to authoritative code or documentation instead of copying API reference or
tutorial content. It does not include current work, issue queues, test or file counts, release
status, machine paths, credentials, or private sidecar content.

## Nested guides

A nested `AGENTS.md` is optional. Add one only when its directory has a distinct responsibility,
public surface, safety rule, compatibility constraint, or verification lane that the root guide
cannot state concisely. A nested guide:

- names its directory or subsystem in the title;
- states the directory's responsibility and the rules that differ there;
- inherits repository-wide commands and rules instead of repeating them;
- stays below 120 lines and contains no volatile counts or status snapshots; and
- is removed when the directory no longer needs narrower guidance.

No repository creates empty or placeholder guides for discovery. The conformance audit discovers
tracked files, so an absent nested guide means the root guide applies.

## Claude interoperability

Public repositories do not track `CLAUDE.md`. A one-line `@AGENTS.md` include configures one tool but
does not help a contributor understand the library. Public repositories also ignore `.claude/`,
`.codex/`, and `.workspace/` so local configuration cannot be published by a broad Git add.

Each configured private development sidecar tracks `AGENTS.md` as its canonical instructions and a
`CLAUDE.md` containing exactly `@AGENTS.md`. Sidecar instructions may describe local work, issue
drafts, transitions, memory, and cross-repository coordination because the sidecar is private.

## Maintenance triggers

Review the root guide when a change alters the package responsibility, supported public import,
repository layout, quality commands, release process, compatibility policy, or safety boundary.
Review an affected nested guide when a subsystem moves, gains or loses a public surface, changes a
local constraint, or changes its focused verification lane. Deleting a subsystem also deletes its
guide.

An ordinary implementation change does not require prose churn when these facts stay the same.
Reviewers compare the guide with the changed source and commands rather than updating dates or
counts.

## Conformance

`uv run ml4t-ecosystem audit-workspaces` discovers tracked guides in each local release checkout. It
checks root structure, public import and source-tree references, required quality commands, line
limits, private-state references, tool-mechanism prose, volatile counts, nested titles, and exact
duplicate nested content. The GitHub and PyPI collector applies the root checks to each default
branch.

Automated checks cannot establish that a guide names the correct public surface. Each library audit
therefore compares the guide with its installed package, documentation, workflow commands, and
tracked nested files. A deviation uses an issue and pull request in the owning library.
30 changes: 19 additions & 11 deletions docs/standards/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,29 @@ Each supported Python and operating-system combination must pass:
5. `ty` type checking; and
6. source distribution and wheel builds with metadata validation.

The next CPython prerelease enters CI after beta 1. Before final release, core installation and the
non-hardware-dependent tests must pass on Linux, macOS, and Windows. Prerelease support is tested but
not advertised as stable.
The next CPython prerelease enters CI after beta 1. Libraries whose complete dependency sets install
on the prerelease run blocking core installation and non-hardware-dependent tests on Linux, macOS,
and Windows. Prerelease support is tested but not advertised as stable.

When that CPython release becomes final, it joins the supported matrix and failures block releases.
Dropping an older Python version requires an ecosystem decision and a documented deprecation period.
A dependency-blocked library keeps a truthful `Requires-Python` upper bound and runs a visible
non-blocking canary at least monthly. Its configured prerelease wait records the affected release
line, evidence, user impact, mitigation, owner issue, and objective review triggers. A trigger starts
a new review; it does not claim compatibility or block an otherwise qualified stable release.

For releases before 2026-10-01, the stable matrix is Python 3.12 through 3.14 and the blocking
prerelease target is Python 3.15. A package metadata upper bound that prevents installation on the
prerelease target fails this standard.
When that CPython release becomes final, it joins the supported matrix for libraries without an
approved wait. A waiting library reviews fresh qualification evidence when final ships and records
whether the wait can end. Dropping an older Python version requires an ecosystem decision and a
documented deprecation period.

For releases before Python 3.15 is qualified across a library's complete dependency set, the stable
matrix is Python 3.12 through 3.14. Python 3.15 remains a blocking target for libraries without a
configured prerelease wait.

A library may temporarily retain an upper bound only through a machine-readable exception in
`config/libraries.toml`. The exception replaces the prerelease jobs with an explicit validation job;
it does not remove the stable operating-system matrix. The validation fails when the exception is
missing, applied to another repository, outside its version scope, or expired.
`config/libraries.toml`. The `prerelease_exception` name remains in the configuration and reusable
workflow for compatibility. For a trigger-based wait, the validation fails when the record is
missing, applied to another repository, outside its release-line scope, or lacks review triggers.
The wait never removes the stable operating-system matrix.

Hardware-specific capabilities such as CUDA require a separate matrix. Passing the general matrix
does not establish hardware support.
Expand Down
6 changes: 4 additions & 2 deletions docs/standards/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ requirements but may not weaken a shared requirement locally.
- [Issues and pull requests](issues-and-pull-requests.md)
- [API compatibility](api-compatibility.md)
- [Dependencies and security](dependencies-and-security.md)
- [Agent guides](agent-guides.md)

Exceptions must identify their scope, rationale, approver, and expiration date. An expired exception
does not qualify a release.
Exceptions must identify their scope, rationale, approver, and an expiration date or objective
review triggers. An expired exception does not qualify a release. A prerelease wait remains valid
until its owning review establishes that the complete dependency set passes the target matrix.
30 changes: 9 additions & 21 deletions docs/standards/release-qualification.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,23 +80,10 @@ documentation. No new example or primary documentation may recommend a deprecate

## Agent orientation

Every public release repository has a root `AGENTS.md` for an external agent trying to understand
the library from a source checkout. It states the library's responsibility, identifies the source
tree and major subsystems, names supported public imports or workflows, points to deeper guides when
they exist, and gives the authoritative quality commands. The workspace audit checks for substantive
sections, the configured import package, source-tree navigation, and an executable import or quality
command. A placeholder file, tool-mechanism explanation, or import of private workspace state fails.

The public root file stays below 200 lines and contains no internal work management, volatile file or
test counts, status snapshots, detailed API documentation, or tutorials. Nested `AGENTS.md` files are
justified when they provide subsystem orientation or rules that differ within their directory and do
not repeat the root. Public repositories do not track `CLAUDE.md`, `.claude/`, `.codex/`, or
`.workspace/`; those are local agent plumbing rather than library orientation.

An instruction audit reports obsolete, duplicated, missing, or misplaced content and presents the
exact proposed edits. Editing an `AGENTS.md` or `CLAUDE.md` requires the user's explicit approval of
that reported scope. Approval for a library's instruction files does not authorize user-level or
other repositories' instruction changes.
Every public release repository follows the root and nested `AGENTS.md` requirements in
[Agent guides](agent-guides.md). The workspace audit discovers tracked guides and reports structural
or placement failures. Each library's qualification also compares guide content with its current
package, documentation, and workflows.

## Development sidecars

Expand Down Expand Up @@ -129,14 +116,15 @@ other library development sandboxes.
The library's default branch must pass the current ecosystem qualification before a tag can publish.
A local library check cannot substitute for a failed shared check.

An exception is valid only when it records:
A release exception or prerelease wait is valid only when it records:

- the exact criterion and affected library versions;
- evidence explaining why the exception is necessary;
- user impact and mitigation;
- the approving maintainer;
- an expiration date; and
- an expiration date or objective review triggers; and
- the issue that removes the exception.

Expired or incomplete exceptions fail qualification. Validation occurs before publication, so a
rejected release does not create a tag, artifact, GitHub release, or PyPI upload.
Expired or incomplete records fail qualification. A review trigger requires fresh evidence but does
not by itself fail a stable release. Validation occurs before publication, so a rejected release
does not create a tag, artifact, GitHub release, or PyPI upload.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ nav:
- Issues and pull requests: standards/issues-and-pull-requests.md
- API compatibility: standards/api-compatibility.md
- Dependencies and security: standards/dependencies-and-security.md
- Agent guides: standards/agent-guides.md
- Decisions: decisions.md
- Reviews: reviews.md

Expand Down
Loading
Loading