import json from app.call_log import record def test_success_record_shape(): captured = [] rec = record( role="narrator", model="qwen3.5:latest", options={"seed": 7}, messages=[{"role": "user", "content": "x"}], canon_log={"a": 1}, ok=True, latency_ms=120, response="prose", write=captured.append, ) assert len(captured) == 1 parsed = json.loads(captured[0]) assert parsed["ok"] is True assert parsed["response"] == "prose" assert parsed["options"]["seed"] == 7 assert parsed["role"] == "narrator" assert parsed["canon_log"] == {"a": 1} assert "error" not in parsed assert "ts" in parsed assert rec["response"] == "prose" def test_failure_record_shape(): captured = [] record( role="narrator", model="m", options={}, messages=[], canon_log={}, ok=False, latency_ms=5, error="ModelError: down", write=captured.append, ) parsed = json.loads(captured[0]) assert parsed["ok"] is False assert parsed["error"] == "ModelError: down" assert "response" not in parsed def test_default_write_failure_does_not_propagate(monkeypatch, capsys): """§13 — a good narration must never become a 500 because the log write failed. Point CALL_LOG_PATH at a path whose parent directory does not exist, so the default sink's `open()` raises. record() must swallow it, report to stderr (never stdout — stdout may be the log sink itself), and still return the record. """ monkeypatch.setenv( "CALL_LOG_PATH", "/nonexistent-dir-for-test/does/not/exist.log" ) rec = record( role="narrator", model="qwen3.5:latest", options={"seed": 7}, messages=[{"role": "user", "content": "x"}], canon_log={"a": 1}, ok=True, latency_ms=120, response="prose", ) assert rec["response"] == "prose" assert rec["ok"] is True out, err = capsys.readouterr() assert out == "" assert err != ""