diff --git a/adapters/PUBLISHED.toml b/adapters/PUBLISHED.toml new file mode 100644 index 00000000..768ac5f0 --- /dev/null +++ b/adapters/PUBLISHED.toml @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: 2026 The CTRLRun contributors +# SPDX-License-Identifier: Apache-2.0 + +# What is actually on PyPI, and the kernel range that distribution declares. +# +# `test_each_adapter_declares_a_kernel_range_that_contains_this_kernel` checks the range in +# `adapters//pyproject.toml` against the kernel in this repository. That is a fact about the +# tree. It is not a fact about what a user gets from `pip install`, and the two came apart: +# the range was widened at 0.7, 0.8, 0.9 and 0.10 and the adapter was **never re-published**, so +# `ctrlrun-openai-agents` 1.0.0 went on declaring `ctrlrun<0.6` while the kernel reached 0.10.0. +# `pip install ctrlrun-openai-agents` beside a current kernel then either refuses to resolve or +# silently downgrades ctrlrun to 0.5.x. +# +# This file is the record of the published side, updated by hand **in the same commit that tags +# a release**. `test_a_widened_kernel_range_is_not_shipped_without_a_new_version` compares it to +# the tree: if an adapter's range has moved away from what was published, its version must have +# moved too, or the release is one nobody can install. +# +# It is deliberately hand-written rather than fetched. A test that asked PyPI would need the +# network, and `SPEC-v0.4 §3.9`'s discipline applies: a check that cannot run offline is a check +# that gets skipped in the run that mattered. + +[langgraph] +version = "1.0.0" +kernel = ">=0.5,<0.6" + +[openai-agents] +version = "1.0.0" +kernel = ">=0.5,<0.6" diff --git a/adapters/langgraph/pyproject.toml b/adapters/langgraph/pyproject.toml index 9e6bce60..86d5a3cd 100644 --- a/adapters/langgraph/pyproject.toml +++ b/adapters/langgraph/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta" [project] name = "ctrlrun-langgraph" -version = "1.0.0" +version = "1.1.0" description = "Route a CTRLRun APPROVE through LangGraph's own interrupt()." readme = "README.md" requires-python = ">=3.11" diff --git a/adapters/openai-agents/pyproject.toml b/adapters/openai-agents/pyproject.toml index bff8bb61..d692e89c 100644 --- a/adapters/openai-agents/pyproject.toml +++ b/adapters/openai-agents/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta" [project] name = "ctrlrun-openai-agents" -version = "1.0.0" +version = "1.1.0" description = "Route a CTRLRun APPROVE through the OpenAI Agents SDK's tool-approval interruption." readme = "README.md" requires-python = ">=3.11" diff --git a/tests/test_packaging.py b/tests/test_packaging.py index c169cfec..816dd8fa 100644 --- a/tests/test_packaging.py +++ b/tests/test_packaging.py @@ -809,6 +809,48 @@ def test_the_throwaway_sector_configuration_ships_nowhere(): ADAPTER_DIRECTORIES = ("langgraph", "openai-agents") +@pytest.mark.parametrize("adapter", ADAPTER_DIRECTORIES) +def test_a_widened_kernel_range_is_not_shipped_without_a_new_version(adapter): + """The test below checks the range in the tree. Nothing checked what is on PyPI. + + They came apart and stayed apart for four releases: the range was widened at 0.7, 0.8, 0.9 + and 0.10, the adapter was never re-published, and `ctrlrun-openai-agents` 1.0.0 went on + declaring `ctrlrun<0.6` while the kernel reached 0.10.0. `pip install ctrlrun-openai-agents` + beside a current kernel then either refuses to resolve or silently downgrades ctrlrun to + 0.5.x -- the same defect the test below was written for, one repository boundary out, where + it does not look. + + `adapters/PUBLISHED.toml` is the record of the published side. If an adapter's range has + moved away from what was published, its **version** must have moved too, or the widening is + one nobody can install. Hand-written rather than fetched, because a check that needs the + network is a check that gets skipped in the run that mattered. + """ + import tomllib as _tomllib + + published_file = REPO_ROOT / "adapters" / "PUBLISHED.toml" + manifest = REPO_ROOT / "adapters" / adapter / "pyproject.toml" + if not manifest.exists() or not published_file.exists(): + pytest.skip("adapters/ is not in this distribution, which SPEC-v0.5 §6.1 requires") + + with published_file.open("rb") as handle: + published = _tomllib.load(handle)[adapter] + with manifest.open("rb") as handle: + project = _tomllib.load(handle)["project"] + + declared = next(d for d in project["dependencies"] if d.startswith("ctrlrun")).removeprefix( + "ctrlrun" + ) + + if declared == published["kernel"]: + return + assert project["version"] != published["version"], ( + f"adapters/{adapter} declares ctrlrun{declared} but {published['version']} on PyPI " + f"declares ctrlrun{published['kernel']}, and the version has not moved. Bump it and tag " + f"`adapters-{adapter}-v`, then record the new version and range in " + "adapters/PUBLISHED.toml. A widened range nobody can install is not a widened range." + ) + + @pytest.mark.parametrize("adapter", ADAPTER_DIRECTORIES) def test_each_adapter_declares_a_kernel_range_that_contains_this_kernel(adapter): """SPEC-v0.5 §6.3's two ranges, checked against the kernel that is actually here.