fix(deps): raise molecule-ai-workspace-runtime floor to >=0.1.129
Pre-0.1.129 the runtime's inline A2A response sniffer in
``send_a2a_message`` checked only for ``result`` / ``error`` keys and
routed the poll-mode success envelope —
``{"status": "queued", "delivery_mode": "poll", "method": "..."}`` —
to the malformed branch:
[A2A_ERROR] unexpected response shape (no result, no error): {...}
That string then propagated through ``tool_delegate_task`` into the
caller workspace's activity row, surfacing on canvas as the workspace's
task label and triggering a ~3s retry storm.
0.1.129 introduced ``a2a_response.py`` (SSOT typed parser with explicit
``Queued`` variant) + matching ``_A2A_QUEUED_PREFIX`` handling in
``a2a_tools_delegation.tool_delegate_task`` that falls back to the
durable ``/delegate`` + ``/delegations`` polling path — the correct
synchronous facade for poll-mode peers.
The existing ``>=0.1.110`` pin allowed a fresh ``pip install
codex-channel-molecule`` to resolve to a buggy wheel and reproduce the
incident. Raising the floor to 0.1.129 closes that window.
Adds a ``test_runtime_dependency_floor.py`` regression test that
parses ``pyproject.toml`` and asserts the lower bound stays at or
above 0.1.129 — bumps the version to 0.1.3 so a republish carries the
floor downstream.
Closes molecule-ai/internal#424.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b29ce85137
commit
06739ba9e0
@ -4,14 +4,26 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "codex-channel-molecule"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
description = "Bridge daemon for codex CLI ↔ Molecule platform — long-polls the platform inbox, runs `codex exec --resume <session>` per inbound message, replies via send_message_to_user MCP tool. Counterpart to hermes-channel-molecule."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
license = { text = "Apache-2.0" }
|
||||
authors = [{ name = "Molecule AI" }]
|
||||
dependencies = [
|
||||
"molecule-ai-workspace-runtime>=0.1.110",
|
||||
# Floor raised from 0.1.110 → 0.1.129 to pull in the SSOT A2A response
|
||||
# parser (a2a_response.py, introduced 0.1.129). Pre-0.1.129 the legacy
|
||||
# inline sniffer in a2a_client.send_a2a_message treated the poll-mode
|
||||
# ``{"status": "queued", "delivery_mode": "poll", "method": "..."}``
|
||||
# envelope as malformed and surfaced ``[A2A_ERROR] unexpected response
|
||||
# shape (no result, no error): ...`` on every reply attempt — that
|
||||
# then propagated to canvas as the workspace's task label and triggered
|
||||
# a ~3s retry storm. The 0.1.129+ runtime classifies the envelope as
|
||||
# ``Queued`` and short-circuits to the durable /delegate-poll path
|
||||
# (a2a_tools_delegation._delegate_sync_via_polling). See
|
||||
# ``molecule-ai/internal#424`` and ``molecule-core#2967`` for the
|
||||
# full incident + fix history.
|
||||
"molecule-ai-workspace-runtime>=0.1.129",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
||||
106
tests/test_runtime_dependency_floor.py
Normal file
106
tests/test_runtime_dependency_floor.py
Normal file
@ -0,0 +1,106 @@
|
||||
"""Pin the minimum molecule-ai-workspace-runtime version that ships
|
||||
the SSOT A2A response parser.
|
||||
|
||||
Background — see ``molecule-ai/internal#424``:
|
||||
|
||||
Pre-runtime-0.1.129 the inline sniffer in ``a2a_client.send_a2a_message``
|
||||
checked for ``result`` or ``error`` keys and routed everything else to
|
||||
``[A2A_ERROR] unexpected response shape (no result, no error): ...``.
|
||||
That branch fired on every reply attempt to a poll-mode peer because the
|
||||
platform proxy synthesizes the success envelope as
|
||||
``{"status": "queued", "delivery_mode": "poll", "method": "..."}``
|
||||
which has NEITHER ``result`` NOR ``error``. The retry loop hammered the
|
||||
caller's canvas with the error string every ~3s.
|
||||
|
||||
Version 0.1.129 introduced ``a2a_response.py`` — a typed parser with an
|
||||
explicit ``Queued`` variant — and the matching ``[A2A_QUEUED]`` sentinel
|
||||
in ``a2a_client.py``. ``a2a_tools_delegation.tool_delegate_task`` then
|
||||
falls back to the durable ``/delegate`` + ``/delegations`` polling path,
|
||||
which IS the correct synchronous facade for poll-mode peers.
|
||||
|
||||
This test asserts the floor is held at ``>=0.1.129`` so a future
|
||||
dependency-housekeeping pass cannot silently lower it back into the
|
||||
broken range. If the floor is ever raised further (e.g. to require a
|
||||
later SSOT parser feature), update the constant below — the lower bound
|
||||
must never go below 0.1.129.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib
|
||||
else: # pragma: no cover - Python 3.11+ required by pyproject anyway
|
||||
import tomli as tomllib
|
||||
|
||||
|
||||
# The earliest runtime version that ships the SSOT A2A response parser
|
||||
# with the typed ``Queued`` variant. Bumping this floor MUST be paired
|
||||
# with a comment update in pyproject.toml's dependencies block.
|
||||
_MINIMUM_RUNTIME_VERSION = (0, 1, 129)
|
||||
|
||||
|
||||
def _parse_version(spec: str) -> tuple[int, int, int]:
|
||||
"""Extract the lower-bound version from a dependency specifier.
|
||||
|
||||
Supports the common shapes used in our pyproject files:
|
||||
|
||||
* ``pkg>=1.2.3`` → (1, 2, 3)
|
||||
* ``pkg>=1.2.3,<2`` → (1, 2, 3)
|
||||
* ``pkg~=1.2.3`` → (1, 2, 3)
|
||||
|
||||
Raises ``ValueError`` on anything else so the test fails loud rather
|
||||
than silently passing on a malformed specifier.
|
||||
"""
|
||||
m = re.search(r"(?:>=|~=)\s*(\d+)\.(\d+)\.(\d+)", spec)
|
||||
if not m:
|
||||
raise ValueError(f"no lower-bound version in specifier: {spec!r}")
|
||||
return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def runtime_specifier() -> str:
|
||||
"""Return the raw dependency specifier for molecule-ai-workspace-runtime."""
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
pyproject = root / "pyproject.toml"
|
||||
with pyproject.open("rb") as f:
|
||||
data = tomllib.load(f)
|
||||
deps = data["project"]["dependencies"]
|
||||
for dep in deps:
|
||||
# match the package name allowing a hyphen-or-underscore in case
|
||||
# the spec ever normalizes — PEP 503 treats them equivalently.
|
||||
if re.match(r"^molecule[-_]ai[-_]workspace[-_]runtime\b", dep):
|
||||
return dep
|
||||
raise AssertionError(
|
||||
"pyproject.toml is missing a molecule-ai-workspace-runtime dependency"
|
||||
)
|
||||
|
||||
|
||||
def test_runtime_floor_includes_a2a_response_parser(runtime_specifier: str) -> None:
|
||||
"""The runtime floor must be at or above the SSOT parser release."""
|
||||
bound = _parse_version(runtime_specifier)
|
||||
assert bound >= _MINIMUM_RUNTIME_VERSION, (
|
||||
f"runtime floor {bound} is below {_MINIMUM_RUNTIME_VERSION} — "
|
||||
f"pre-0.1.129 the A2A response parser misclassifies the poll-mode "
|
||||
f"queued envelope as malformed and surfaces "
|
||||
f"'[A2A_ERROR] unexpected response shape' on every poll-mode peer "
|
||||
f"reply. See molecule-ai/internal#424."
|
||||
)
|
||||
|
||||
|
||||
def test_runtime_specifier_uses_a_lower_bound(runtime_specifier: str) -> None:
|
||||
"""A bare ``pkg`` or upper-only spec would silently install ANY version
|
||||
on a fresh ``pip install`` — including the buggy pre-0.1.129 range.
|
||||
|
||||
Require an explicit lower bound (``>=`` or ``~=``).
|
||||
"""
|
||||
assert re.search(r">=|~=", runtime_specifier), (
|
||||
f"runtime dependency {runtime_specifier!r} has no lower bound — "
|
||||
f"a fresh install could resolve to a pre-0.1.129 wheel with the "
|
||||
f"broken poll-mode parser"
|
||||
)
|
||||
Loading…
Reference in New Issue
Block a user