Benchmark report model + deterministic Markdown / JSON writers.
Purpose
-------
Hold one scenario run's results (across one or more providers) and
emit two sibling files: a human Markdown report and a diff-stable JSON
sidecar. The schema is **additive across providers** (a ``providers``
array), so pointing the suite at a new provider never changes existing
fields; a failed/skipped provider records ``status`` + ``reason`` and
never aborts the file. ``messages[1]`` size is **nullable** (absent in
``standard`` mode — ``null`` in JSON, "absent" in Markdown, distinct
from a present-but-empty ``0``). No secret material is ever written —
only env-var *names* appear in a report.
Responsibilities
----------------
- :class:`ProviderResult` — one provider's composed-prompt sizes,
per-turn metrics, effective mode/profile, and optional ``$`` pricing.
- :class:`RunReport` — run metadata + the ``providers`` array, with
:meth:`to_dict` / :meth:`write_json` / :meth:`write_markdown`.
- :func:`capture_env` — UTC timestamp, git commit, Python, platform.
- :func:`unique_report_paths` — collision-proof ``.md`` + ``.json``
paths (ms-precision UTC + ``+NN`` suffix).
Diagnostics
-----------
Domain: OC_CHAT.MAIN
Levels:
L2 — lifecycle events
L3 — semantic details
L4 — deep tracing
Contracts
---------
- :meth:`write_json` uses ``sort_keys=True`` + rounded floats for clean
diffs; reloading the JSON round-trips :meth:`to_dict`.
- ``messages1_size`` of ``None`` means *absent* and serialises to JSON
``null`` / Markdown "absent"; ``0`` means present-but-empty.
- :func:`unique_report_paths` guarantees two runs in the same second
get distinct filenames.
Dependencies
------------
- oc_diagnostics (structured debug logging via _dbg)
- oc_chat.benchmarks.metrics (aggregate_turn / aggregate_run, TurnMetrics)
- oc_chat.benchmarks (HARNESS_VERSION, SCHEMA_VERSION - the version stamps written into every report)