"""Tests for ``pallas.log._JSONFormatter``. The formatter must serialize caller-supplied ``extra={...}`` fields (the loop guard and other diagnostics rely on this) while never emitting the internal ``LogRecord`` bookkeeping attributes. """ from __future__ import annotations import json import logging from pallas.log import _JSONFormatter def _format(msg: str, **extra) -> dict: record = logging.LogRecord( name="pallas.test", level=logging.WARNING, pathname=__file__, lineno=1, msg=msg, args=(), exc_info=None, ) for key, value in extra.items(): setattr(record, key, value) return json.loads(_JSONFormatter().format(record)) def test_extra_fields_are_serialized(): out = _format( "agentic loop halted", event="loop_halt", tool="kairos-update_task", repeat_count=3, result_preview="COMPLETED but 0%", ) assert out["message"] == "agentic loop halted" assert out["event"] == "loop_halt" assert out["tool"] == "kairos-update_task" assert out["repeat_count"] == 3 assert out["result_preview"] == "COMPLETED but 0%" def test_standard_attributes_are_not_leaked(): out = _format("plain message") for noise in ("msg", "args", "levelno", "pathname", "lineno", "funcName"): assert noise not in out assert out["level"] == "WARNING" assert out["logger"] == "pallas.test" def test_non_serializable_extra_does_not_crash(): out = _format("with object", obj=object()) assert "obj" in out # coerced via default=str, not dropped or raised