Benchmark CLI — ``python -m oc_chat.benchmarks [run|run-all|list|check]``.
Purpose
-------
The manual entry point for the suite (live runs need a real provider
key and are deliberately outside the auto pytest suite). Drives one or
all scenarios, writes a timestamped ``.md`` + ``.json`` report per
scenario, isolates per-provider failures, and gates a report against the
tracked regression budget (plan 139).
Responsibilities
----------------
- Parse args; resolve the provider list, mode, and price table.
- ``list`` — print the scenario set.
- ``run`` / ``run-all`` — drive scenario(s) and emit reports.
- ``check`` — compare a report (``--report`` existing, or ``--run``
fresh) against ``benchmark-budget.json`` and exit non-zero on a hard
regression / ``no_budget`` / ``invalid_report`` (fail-closed §3.4).
- Clean exit codes: unknown scenario / missing label / mode conflict /
single-provider failure → exit 1 (no traceback); multi-provider
failures are per-provider skip entries and the run continues.
Diagnostics
-----------
Domain: OC_CHAT.MAIN
Levels:
L2 — lifecycle events
L3 — semantic details
L4 — deep tracing
Contracts
---------
- Default reports go to the tracked results dir; implementer smoke runs
pass ``--results-dir <temp>`` so canonical results are never polluted.
- Keys come from the provider's env var; a missing key on a
single-provider run is a clean error, not a traceback.
Dependencies
------------
- oc_chat.benchmarks.runner (run_benchmark - drives a scenario across the providers)
- oc_chat.benchmarks.scenarios (get, all_scenarios - the scenario set for list, run and run-all)
- oc_chat.benchmarks.prices (load_prices - the price table for a run)
- oc_chat.benchmarks.report (RunReport, unique_report_paths - the report and its collision-proof file paths)
- oc_chat.benchmarks.budget (load_budget, validate_budget, check_report - the regression-budget gate behind check)
- oc_diagnostics (structured debug logging via _dbg)