ouroboros/tests/test_vision_model_wait.py
Ouroboros 627ee94471 Restore supervising model recovery and retain failed response evidence
Preserve free live-executor waiting before ordinary managed model recovery.
Configured-session supervisors use the same upstream-observation path as
other managed tasks; external start and patch custody guards stay in place.
Negotiate private response evidence and preserve known terminal usage when
local message normalization fails, without introducing another retry owner.

Keep unknown accounting and exact source custody explicit (P1), repair the
shared recovery boundary (P2), and reuse existing transport/result owners
(P7). Update coupled tests and architecture/development descriptions.
2026-09-15 01:40:05 +03:00

358 lines
18 KiB
Python

"""Controlled model engine in a real tracked child; never live auth/inference."""
from dataclasses import asdict, fields
import json
import os
from pathlib import Path
from types import SimpleNamespace
import pytest
pytestmark = pytest.mark.serial
from ouroboros import usage_accounting as ua
from ouroboros.llm_claudexor import ClaudexorModelError, ClaudexorModelNotDispatched
from ouroboros.tools import vision, vision_process
MODEL = "claudexor::fixture=image-model"
ROUTE = {"source": "fixture", "model": "image-model", "credentialProfileId": "account-exact",
"accountFingerprint": "fingerprint-exact"}
REF = {"resourceId": "resource-exact", "sha256": "sha256:" + "a" * 64, "sizeBytes": 100}
def _install_child_fixture(mode, events_path):
"""Patch only the gateway, retaining actual LLM/IPC/accounting code."""
from ouroboros import llm_claudexor as transport, pricing
from ouroboros.gateways.claudexor import ClaudexorUnavailable
def event(kind, **fields):
with open(events_path, "a", encoding="utf-8") as handle:
handle.write(json.dumps({"kind": kind, **fields}) + "\n")
class Gateway:
operation = ""
polls = 0
lost = False
def operations(self):
return [] # Legacy model-operation catalog.
def upload_model_request(self, payload, *, idempotency_key):
event("upload", key=idempotency_key, payload=payload)
return REF
def create_model_operation(self, ref, *, idempotency_key):
event("create", key=idempotency_key)
if not self.operation:
self.operation = "operation-exact"
event("generation", operation_id=self.operation)
if mode == "lose_create" and not self.lost:
self.lost = True
raise ClaudexorUnavailable("daemon_unreachable", "controlled lost create reply")
return self.detail()
def detail(self):
pending = mode in {"pending", "cancel"} or mode == "slow" and self.polls < 8
not_started = mode in {"quota", "auth", "mixed"}
refused = not_started or mode == "field"
problem = {"code": {"quota": "subscription_window_exhausted", "auth": "auth_required",
"mixed": "credential_pool_exhausted", "field": "invalid_request"}.get(mode, "fixture_error"),
"message": "controlled refusal", "context": {"resetsAt": "2099-01-01T00:00:00Z"}}
if mode == "field":
problem["context"].update(httpStatus=400, vendorCode="string_above_max_length",
parameter="instructions", providerMessage="private provider body")
return {"id": self.operation, "state": "running" if pending else "failed" if refused else "succeeded",
"dispatch": {"state": "started" if pending else "not_started" if not_started else "response_received",
"route": ROUTE},
"response": {"state": "absent"} if pending else {"state": "ready", "ref": REF},
"problem": problem if refused else None}
def get_model_operation(self, operation_id, **kwargs):
assert operation_id == self.operation
self.polls += 1
event("poll", operation_id=operation_id)
return self.detail()
def get_model_result(self, operation_id, **kwargs):
detail = self.detail()
value = {"outcome": "failed" if detail["problem"] else "completed", "route": ROUTE,
"message": {"role": "assistant", "content": "pixels read exactly once 🐍"},
"usage": {"input_tokens": 21, "output_tokens": 5},
"cost": {"knowledge": "unknown", "cashUsd": None}, "problem": detail["problem"]}
return json.dumps(value).encode("utf-8")
def acknowledge_model_result(self, operation_id, sha256):
event("ack", operation_id=operation_id)
return {"id": operation_id, "response": {"state": "acknowledged", "ref": REF}}
def cancel_model_operation(self, operation_id, **kwargs):
event("cancel", operation_id=operation_id)
return self.detail()
def close(self):
event("close")
gateway = Gateway()
transport.ensure_owned_gateway = lambda: gateway
transport.config.CLAUDEXOR_MODEL_POLL_INTERVAL_SEC = 0.01
pricing._fetch_live_rows = lambda *_: pytest.fail("VLM fixture must never fetch live pricing")
if mode == "checkpoint_fail":
original = vision_process._private_json
def fail_receipt(path, value):
if path.name == "receipt.json":
raise OSError("controlled IPC write failure")
return original(path, value)
vision_process._private_json = fail_receipt
@pytest.fixture
def child_fixture(tmp_path, monkeypatch):
from ouroboros.tools import shell
events = tmp_path / "events.jsonl"
original = shell._tracked_subprocess_run
state = {"mode": "success", "paths": [], "timeouts": []}
def run(argv, **kwargs):
payload = Path(argv[-1])
state["paths"].append(payload.parent)
state["timeouts"].append(kwargs["timeout"])
if os.name != "nt":
assert payload.stat().st_mode & 0o777 == 0o600
assert payload.parent.stat().st_mode & 0o777 == 0o700
child_argv = list(argv)
child_argv[2] = (f"import runpy; runpy.run_path({__file__!r})['_install_child_fixture']"
f"({state['mode']!r}, {str(events)!r}); " + argv[2])
try:
return original(child_argv, **kwargs)
finally:
for path in payload.parent.iterdir():
if os.name != "nt":
assert path.stat().st_mode & 0o777 == 0o600
monkeypatch.setattr(shell, "_tracked_subprocess_run", run)
monkeypatch.setenv("TOTAL_BUDGET", "100")
monkeypatch.setenv("OUROBOROS_DATA_DIR", str(tmp_path / "data"))
monkeypatch.setenv("OUROBOROS_SETTINGS_PATH", str(tmp_path / "data" / "settings.json"))
monkeypatch.setattr(vision_process.config, "CLAUDEXOR_MODEL_POLL_INTERVAL_SEC", 0.01)
with ua.usage_scope(ua.UsageScope(drive_root=tmp_path / "data", task_id="image-task", root_task_id="image-task")):
yield state, events, tmp_path / "data"
assert all(not path.exists() for path in state["paths"])
assert not shell._active_subprocesses
def _events(path):
return [json.loads(line) for line in path.read_text().splitlines()] if path.exists() else []
def _call(client=None, **kwargs):
return vision._vision_query_with_timeout(client, prompt="Describe only this image",
images=[{"url": "data:image/png;base64,AAAA"}],
model=MODEL, timeout=0.02, **kwargs)
def test_private_ipc_publication_never_exposes_an_empty_control_file(tmp_path, monkeypatch):
actual_write = vision_process.atomic_write_json
previous = []
def observe(path, value):
# This is the moment the concurrent child could read control. An empty
# pre-created destination is invalid JSON and falsely cancels the call.
previous.append(json.loads(path.read_text()) if path.exists() else None)
actual_write(path, value)
monkeypatch.setattr(vision_process, "atomic_write_json", observe)
path = tmp_path / "control.json"
first = {"receipt_id": "first", "reason": "cancelled"}
second = {"receipt_id": "second", "reason": "deadline"}
vision_process._private_json(path, first)
vision_process._private_json(path, second)
assert previous == [None, first]
assert json.loads(path.read_text()) == second
if os.name != "nt":
assert path.stat().st_mode & 0o777 == 0o600
@pytest.mark.parametrize("mode", ["success", "slow", "lose_create", "checkpoint_fail"])
def test_real_child_retains_one_generation_and_unknown_cost(child_fixture, mode):
state, events, root = child_fixture
state["mode"] = mode
text, usage = _call()
assert text == "pixels read exactly once 🐍"
assert usage["cost"] is None and usage["cost_final"] is False
assert len(usage["ledger_attempt_ids"]) == 1
assert ua.last_physical_attempt_capture().state == "settled"
rows = _events(events)
assert len([row for row in rows if row["kind"] == "generation"]) == 1
assert len({row["key"] for row in rows if row["kind"] == "create"}) == 1
assert any(row["kind"] == "ack" for row in rows)
if mode == "slow":
assert len([row for row in rows if row["kind"] == "poll"]) >= 8
assert state["timeouts"][0] > 90
request = next((root / "observability" / "calls" / "image-task").glob("*_model_request.json"))
assert json.loads(request.read_text())["operation_id"] == "operation-exact"
@pytest.mark.parametrize("mode,code", [("quota", "subscription_window_exhausted"), ("auth", "auth_required"),
("mixed", "credential_pool_exhausted")])
def test_real_child_preserves_typed_refusal_receipt(child_fixture, mode, code):
state, _, _ = child_fixture
state["mode"] = mode
with pytest.raises(ClaudexorModelNotDispatched) as caught:
_call()
error = caught.value
assert error.code == code and error.reset_at == "2099-01-01T00:00:00Z"
assert error.operation_id == "operation-exact" and error.route == ROUTE
assert error.model_role == "vision"
assert error.physical_attempt_capture.state == "released"
assert error.ledger_attempt_ids == [error.physical_attempt_capture.attempt_id]
def test_real_child_reconstructs_provider_field_display_after_settlement(child_fixture):
state, events, root = child_fixture
state["mode"] = "field"
with pytest.raises(ClaudexorModelError) as caught:
_call()
error = caught.value
assert type(error) is ClaudexorModelError
assert error.code == "invalid_request" and error.status_code == 400 and error.retryable is False
assert error.operation_id == "operation-exact" and error.route == ROUTE and error.model_role == "vision"
assert error.body == error.problem and error.problem["context"]["providerMessage"] == "private provider body"
assert "provider_code=string_above_max_length, parameter=instructions" in error.display_message[:220]
assert "private provider body" not in error.display_message
assert str(error) == "invalid_request: controlled refusal"
assert error.physical_attempt_capture.state == "settled"
assert error.ledger_attempt_ids == [error.physical_attempt_capture.attempt_id]
rows = _events(events)
assert sum(row["kind"] == "generation" for row in rows) == sum(row["kind"] == "ack" for row in rows) == 1
attempts = [json.loads(line) for line in (root / ua.LEDGER_REL).read_text().splitlines()]
assert [row["state"] for row in attempts] == ["reserved", "dispatched", "settled"]
def test_parent_cancel_reaches_same_live_operation(child_fixture):
state, events, _ = child_fixture
state["mode"] = "cancel"
def cancel_after_started():
return "cancelled" if any(row["kind"] == "poll" for row in _events(events)) else None
with pytest.raises(ClaudexorModelError) as caught:
_call(model_poll_control=cancel_after_started)
assert caught.value.control_reason == "cancelled"
assert caught.value.operation_id == "operation-exact"
assert caught.value.physical_attempt_capture.state == "unresolved"
rows = _events(events)
assert len([row for row in rows if row["kind"] == "generation"]) == 1
assert {row["operation_id"] for row in rows if row["kind"] == "cancel"} == {"operation-exact"}
def test_dead_child_without_checkpoint_is_unknown_not_free(monkeypatch):
from ouroboros.tools import shell
monkeypatch.setattr(shell, "_tracked_subprocess_run", lambda *a, **k: SimpleNamespace(stdout="", stderr="", returncode=137))
with pytest.raises(ClaudexorModelError) as caught:
_call()
error = caught.value
assert error.code == "model_outcome_unknown" and error.operation_id == "" and error.route == {}
assert not isinstance(error, ClaudexorModelNotDispatched)
assert not hasattr(error, "physical_attempt_capture")
def test_killed_child_retains_exact_operation_checkpoint(child_fixture):
state, events, root = child_fixture
state["mode"] = "pending"
with pytest.raises(ClaudexorModelError) as caught:
vision_process.run_vision_child(child_timeout=5, subscription=True, model_role="vision",
model=MODEL, prompt="one image", images=[], timeout=0.02)
error = caught.value
assert error.code == "model_outcome_unknown" and error.operation_id == "operation-exact"
assert error.physical_attempt_capture.state == "dispatched"
custody = error.model_operation_custody
assert custody["invocation_id"] == error.physical_attempt_capture.attempt_id
assert custody["request_ref"] == REF
manifest = json.loads(Path(custody["request_manifest_ref"]["path"]).read_text())
assert manifest["operation_id"] == error.operation_id
assert len([row for row in _events(events) if row["kind"] == "generation"]) == 1
rows = [json.loads(line) for line in (root / ua.LEDGER_REL).read_text().splitlines()]
assert rows[-1]["state"] == "dispatched" and not any(row["state"] == "released" for row in rows)
def test_strict_child_schema_rejects_false_capture_and_wrong_receipt():
assert set(vision_process._CAPTURE["properties"]) == {field.name for field in fields(ua.PhysicalAttemptCapture)}
assert set(vision_process._CONTEXT["properties"]) == {field.name for field in fields(ua.PhysicalAttemptContext)}
capture = asdict(ua.PhysicalAttemptCapture("a", MODEL, "claudexor", "released", "opaque"))
receipt = {"receipt_id": "ours", "custody": None, "capture": capture}
vision_process._read_receipt(receipt, "ours")
with pytest.raises(ValueError, match="another invocation"):
vision_process._read_receipt(receipt, "theirs")
capture["state"] = "free"
with pytest.raises(Exception):
vision_process._read_receipt(receipt, "ours")
def test_only_unsettled_image_call_retries_under_parent_wait(child_fixture, monkeypatch):
from ouroboros.model_wait import task_model_wait_scope
state, events, root = child_fixture
state["mode"] = "quota"
client = SimpleNamespace()
waits = []
with task_model_wait_scope(task={"id": "image-task"}, drive_root=root,
event_queue=None, worker_slot_held=True) as wait:
def resume(actual_client, error, kwargs):
assert actual_client is client and error.code == "subscription_window_exhausted"
waits.append(error)
state["mode"] = "success"
return {**kwargs, "model_account_override": "replacement"}
monkeypatch.setattr(wait, "wait", resume)
text, usage = _call(client)
assert text == "pixels read exactly once 🐍" and len(waits) == 1
assert len(usage["ledger_attempt_ids"]) == 2
uploads = [row["payload"] for row in _events(events) if row["kind"] == "upload"]
assert len(uploads) == 2 and uploads[0]["messages"] == uploads[1]["messages"]
assert uploads[1]["account"] == {"mode": "pin", "profileId": "replacement"}
assert len(state["paths"]) == 2 # No tool/image-preparation replay; only the unsettled LLM call.
def test_subscription_tool_envelope_uses_existing_task_ceiling(monkeypatch):
monkeypatch.setattr(vision, "_resolve_vlm_model", lambda *_a, **_k: MODEL)
monkeypatch.setattr(vision, "_get_llm_client", lambda: None)
monkeypatch.setattr(vision, "_vision_execution_window", lambda: 900)
assert vision._vision_tool_timeout(None, {}) == 900 + 2 * vision.NESTED_SETTLEMENT_MARGIN_SEC
monkeypatch.setattr(vision, "_resolve_vlm_model", lambda *_a, **_k: "api-model")
assert vision._vision_tool_timeout(None, {}) == 0
def test_real_parent_quota_controller_polls_metadata_then_rejoins_image_call(child_fixture, monkeypatch):
from ouroboros.model_wait import task_model_wait_scope
state, events, root = child_fixture
state["mode"] = "quota"
catalog_calls = []
def catalog(source, account, *, requested_model=None):
catalog_calls.append((source, account))
state["mode"] = "success"
return {"source": source, "models": [{"id": "image-model"}]}
client = SimpleNamespace(
claudexor_model_sources=lambda: {"sources": [{"id": "fixture", "credentialHarness": "fixture"}]},
claudexor_model_catalog=catalog,
)
resolutions, phases = [], []
monkeypatch.setattr(vision, "_get_llm_client", lambda: client)
monkeypatch.setattr(vision, "_resolve_vlm_model", lambda *_a, **_k: resolutions.append(MODEL) or MODEL)
monkeypatch.setattr(vision, "emit_cognitive_operation_event", lambda *_a, **kw: phases.append(kw["phase"]))
ctx = SimpleNamespace(task_metadata={}, deadline_ts=None, task_id="image-task", event_queue=None)
with task_model_wait_scope(task={"id": "image-task"}, drive_root=root,
event_queue=None, worker_slot_held=True):
text = vision._vlm_query(ctx, "Describe only this image", image_url="data:image/png;base64,AAAA")
assert text == "pixels read exactly once 🐍" and catalog_calls == [("fixture", None)]
assert resolutions == [MODEL] and phases == ["started", "finished"]
assert len([row for row in _events(events) if row["kind"] == "upload"]) == 2
persisted = json.loads((root / "task_results" / "image-task.json").read_text())
wait, = persisted["model_waits"].values()
assert wait["state"] == "resolved" and wait["resolution"] == "resource_available"