portfolio-optimiser/tests/test_maf_version_guard.py
Kjell Tore Guttormsen ef2f1cbe61 fix(maf): en vakt som gikk inert i STILLHET, funnet ved aa loefte pinnen (F15, ORDRE 20260829T155150Z)
MAF core 1.9.0 -> 1.16.0, orchestrations 1.0.1 -> 1.1.1. De to kan ikke loeftes
hver for seg: orchestrations 1.1.1 krever selv core>=1.15.0.

Iron Law: vakt-testen kjoert ROED mot 1.9.0 (2 failed) FOER pinnen ble roert.
Gulvet bor i EN konstant og pyproject-asserten deriverer sin streng fra den.

NEVNER: 16 private/ugaranterte former, derivert fra repoets EGNE siteringer,
alle 16 sjekket mot begge versjoner, 2 endret seg. Kjent-positiv: MiddlewareFailure
flippet NO -> YES. KP-kandidaten _compaction.py ble FORKASTET (teller 0 i begge,
diskriminerer ingenting).

DEN FARLIGE ENDRINGEN er den ordren navnga - formen som fortsatt importerer, men
har flyttet semantikk i stillhet. En park skriver naa TO checkpoints og bare EN
baerer plan-review-typen, saa en feildeklarert _ALLOWED_CHECKPOINT_TYPES toemmer
ikke lenger listingen: den taper nOEyaktig den checkpointen som betyr noe,
get_latest returnerer den ANDRE, og _parks `latest is None`-vakt passerte mens
kjOEringen svarte rc=0 og skrev et spOErsmaal som aldri kan baere svaret. Vakten
sjekker naa EGENSKAPEN den alltid mente (request_id in pending_request_info_events
- et DEKLARERT felt) i stedet for symptomet som pleide aa innebaere den, og fjerner
dermed en privat avhengighet i stedet for aa legge til en.

ExperimentalWarning-paret P4 pkt. 2 betalte for aa BEHOLDE er borte fordi MAF
sluttet aa sende det: _feature_stage.py emitterer ved FOERSTE BRUK, ikke ved import.
Goldenens stderr regenerert som BESLUTNING (fire -> to linjer); site-packages-
maskeringen BEHOLDT (spannet er ubebodd, ikke pensjonert).

Load-bearing MAALT mot HELE suiten, gronn kontroll 1089/5, stdout BYTE-UENDRET
(ea8c534773acdbe41ae68f2c55724d69aaf8be4f): M1 revert av vakten -> 1 rod.
EN mutasjon ble IKKE rod og staar som aerlighets-grense, ikke som gate: spikens
checkpoint_ids[-1] er rekkefolge-avhengig (Path.glob), altsaa flaky.

Rapport: docs/2026-09-02-f15-maf-pinnen.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 19:35:49 +02:00

78 lines
3.9 KiB
Python

"""S2.5 MAF version-guard — a TEST-TIME tripwire + a two-sided install pin.
The offline simulation depends on MAF's PRIVATE API (the ``_inner_get_response`` keyword-only
signature + ``_build_response_stream`` construction — see ``conftest`` / ``simulation``'s scripted
client). A major ``agent-framework-core`` bump could change those without notice. This is NOT a
runtime guard (an un-wired ``src`` helper would be green-but-dead); it is a test-time tripwire
against the installed distribution PLUS a two-sided pin in ``pyproject.toml`` (install-time).
Critical: the guard reads the DISTRIBUTION version via
``importlib.metadata.version("agent-framework-core")`` (verified ``1.9.0``), NOT
``agent_framework.__version__`` (verified ``0.0.0`` placeholder — reading that would make the guard
permanently RED / meaningless). Modelled on ``test_smoke``'s version-assert + ``test_portfolio``'s
grep-pin.
"""
from __future__ import annotations
import importlib.metadata
from pathlib import Path
import pytest
_DIST = "agent-framework-core"
#: F15 (2026-08-30): the floor lives in ONE place and the ``pyproject`` assert below DERIVES its
#: expected pin string from it. Two literals for one fact drift (the kø-(p) rule), and a drifted
#: floor is a guard that stops guarding without a local diff.
_MIN_MAJOR = 1
_MIN_MINOR = 16
_MIN_VERSION = f"{_MIN_MAJOR}.{_MIN_MINOR}.0"
def assert_supported_maf_version(version_str: str) -> None:
"""Raise ``ValueError`` when ``version_str`` is outside the supported ``>=1.16.0,<2`` range,
naming the private-API premises to re-verify before a bump. Pure string parse — no import side
effects, so a fake version can be passed directly (the RED-proof) without touching the real
install."""
parts = version_str.split(".")
major = int(parts[0])
minor = int(parts[1]) if len(parts) > 1 else 0
if not (major == _MIN_MAJOR and minor >= _MIN_MINOR):
raise ValueError(
f"{_DIST} {version_str} is outside the supported range >={_MIN_VERSION},<2. Before "
"bumping, re-verify the private-API premises the offline sim relies on: the "
"_inner_get_response keyword-only signature (messages/options/stream) and the "
"_build_response_stream construction. Update the pin in pyproject.toml once confirmed."
)
def test_installed_maf_version_is_supported() -> None:
"""T-2.5d: the real installed distribution (verified 1.16.0) passes the guard — read from
``importlib.metadata.version``, NOT ``agent_framework.__version__`` (a 0.0.0 placeholder)."""
assert_supported_maf_version(importlib.metadata.version(_DIST))
def test_guard_rejects_future_major() -> None:
"""T-2.5d: a future major (``2.0.0``) trips the guard with the actionable upgrade message —
RED-proof without touching the real install."""
with pytest.raises(ValueError, match="private-API premises"):
assert_supported_maf_version("2.0.0")
def test_guard_rejects_too_old_minor() -> None:
"""T-2.5d / F15: the PREVIOUS floor (``1.9.0``) now trips the guard — the pin is two-sided, and
this is the arm that makes the F15 lift measurable rather than asserted. ``1.15.0`` is rejected
too: ``agent-framework-orchestrations`` 1.1.1 requires ``core>=1.15.0``, but 1.16.0 is the
version whose private-API premises were actually re-verified."""
for stale in ("1.8.0", "1.9.0", "1.15.0"):
with pytest.raises(ValueError, match="private-API premises"):
assert_supported_maf_version(stale)
def test_pyproject_pins_agent_framework_core_below_2() -> None:
"""T-2.5d: ``pyproject.toml`` pins ``agent-framework-core>=1.16.0,<2`` — the install-time half of
the guard (the test above is the test-time half). The expected string is DERIVED from
``_MIN_VERSION`` so the two halves cannot drift apart."""
pyproject = (Path(__file__).resolve().parents[1] / "pyproject.toml").read_text(encoding="utf-8")
assert f"agent-framework-core>={_MIN_VERSION},<2" in pyproject