"""Unit tests for M02 — the ``response_format`` payload builder. These assert the OpenAI-standard ``json_schema`` wrapper shape (the only form empirically verified to enforce on the current llama.cpp server image; see Q2) and the fail-closed schema hardening (inline enum, ``additionalProperties: false``, no surviving ``$defs`` indirection). No live server is required. """ from __future__ import annotations import json from typing import Any import pytest from loosecanvas.contracts import SceneAction, SceneActionType, ScenePlan from loosecanvas.response_format import SCENEPLAN_RESPONSE_FORMAT def _nested_schema() -> dict[str, Any]: return SCENEPLAN_RESPONSE_FORMAT["json_schema"]["schema"] def test_response_format_is_json_serializable() -> None: # Must not raise — fed verbatim to the server as JSON. json.dumps(SCENEPLAN_RESPONSE_FORMAT) def test_response_format_wrapper_shape() -> None: assert SCENEPLAN_RESPONSE_FORMAT["type"] == "json_schema" json_schema = SCENEPLAN_RESPONSE_FORMAT["json_schema"] assert json_schema["name"] == "scene_plan" assert json_schema["strict"] is True # The schema is nested under json_schema["schema"], not at the top level. assert "schema" in json_schema def test_nested_schema_forbids_additional_properties() -> None: schema = _nested_schema() assert schema["additionalProperties"] is False action_schema = schema["properties"]["actions"]["items"] assert action_schema["additionalProperties"] is False def test_nested_schema_has_no_defs_indirection() -> None: schema = _nested_schema() assert "$defs" not in schema def test_action_type_enum_is_inline_and_complete() -> None: schema = _nested_schema() type_schema = schema["properties"]["actions"]["items"]["properties"]["type"] assert "$ref" not in type_schema assert set(type_schema["enum"]) == {t.value for t in SceneActionType} def test_schema_validates_a_real_sceneplan_instance() -> None: instance = ScenePlan( actions=[ SceneAction( type=SceneActionType.explain_no_change, reasoning="nothing to do" ) ], summary="no change", ).model_dump(mode="json") jsonschema = pytest.importorskip("jsonschema") jsonschema.validate(instance=instance, schema=_nested_schema())