evalcore 0.2.0__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- evalcore-1.0.0/CHANGELOG.md +96 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/PKG-INFO +26 -20
- {evalcore-0.2.0 → evalcore-1.0.0}/README.md +24 -18
- evalcore-1.0.0/docs/clickhouse-schema.html +1112 -0
- evalcore-1.0.0/docs/clickhouse-schema.sql +412 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/docs/design.md +20 -20
- {evalcore-0.2.0 → evalcore-1.0.0}/pyproject.toml +2 -2
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/__init__.py +6 -9
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/cli.py +36 -19
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/errors.py +2 -1
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/models.py +6 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/runner.py +26 -2
- evalcore-1.0.0/src/evalcore/store.py +505 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_cli.py +1 -1
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_runner.py +34 -0
- evalcore-1.0.0/tests/test_store.py +376 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/uv.lock +1 -1
- evalcore-0.2.0/CHANGELOG.md +0 -35
- evalcore-0.2.0/src/evalcore/store.py +0 -286
- evalcore-0.2.0/tests/test_store.py +0 -173
- {evalcore-0.2.0 → evalcore-1.0.0}/.github/workflows/ci.yml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/.github/workflows/publish.yml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/.gitignore +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/.pre-commit-config.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/LICENSE +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/__init__.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/README.md +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/__init__.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/adapter.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/datasets/support_reply/v1/cases/angry_complaint.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/datasets/support_reply/v1/cases/billing_question.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/datasets/support_reply/v1/cases/double_charge.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/datasets/support_reply/v1/cases/refund_request.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/fixtures/support_reply_judge.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/fixtures/support_reply_pairwise.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/fixtures/support_reply_replay.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/graders.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/run_eval.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/suite.yaml +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/tests/__init__.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/examples/quickstart/tests/test_quickstart.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/justfile +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/pyrightconfig.json +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/__init__.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/base.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/env.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/http.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/adapters/replay.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/compare.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/__init__.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/base.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/classification.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/deterministic.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/judge.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/graders/numeric.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/loader.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/pairwise.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/py.typed +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/rating.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/refs.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/report.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/reporters/__init__.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/reporters/base.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/reporters/html.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/reporters/markdown.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/retry.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/src/evalcore/sweep.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/__init__.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_adapters.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_edge_cases.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_judge.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_judge_extra.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_live_clients.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_pairwise_extra.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_rating.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_rating_server.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_reporters.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_retry.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_sweep_pairwise.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/tests/test_unit.py +0 -0
- {evalcore-0.2.0 → evalcore-1.0.0}/uv.toml +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/), and the project follows
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [1.0.0] - 2026-07-28
|
|
10
|
+
|
|
11
|
+
First stable release. The public API and the outbox row shape are now covered
|
|
12
|
+
by semantic versioning: a breaking change to either means a 2.0.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- **Breaking:** outbox rows no longer carry `input_tokens`, `output_tokens` or
|
|
16
|
+
`cost`. `Output.tokens` is an open dict an adapter may put anything in, and
|
|
17
|
+
usage accounting is captured outside the results store.
|
|
18
|
+
- **Breaking:** the run-grain `revision` key is emitted as
|
|
19
|
+
`application_revision`, which is its column name in the store.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- `docs/clickhouse-schema.sql`: the ClickHouse schema the outbox rows target -
|
|
23
|
+
the written `evaluation_scores` table, the run-grain `evaluations` view over
|
|
24
|
+
it, the row grammar as `CONSTRAINT`s, and the trend queries. Also rendered as
|
|
25
|
+
`docs/clickhouse-schema.html`.
|
|
26
|
+
|
|
27
|
+
## [0.3.0] - 2026-07-28
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- **Breaking:** the results-store outbox is now one feed at
|
|
31
|
+
`(run, case, sample, grader, metric)` grain, targeting a single flat
|
|
32
|
+
`evaluation_scores` table with the run trend and the invocation grain as
|
|
33
|
+
plain views over it. `store.scorecard_rows` and
|
|
34
|
+
`JsonlOutboxExporter.export` are removed; use `store.score_rows` and
|
|
35
|
+
`export_scores`. `--export-scores` is now an alias for `--export`.
|
|
36
|
+
- **Breaking:** a missing measurement is emitted as `null` rather than the
|
|
37
|
+
`(value=0, has_value=false)` sentinel pair, and the `has_value` / `has_stdev`
|
|
38
|
+
companion keys are gone. The store columns are `Nullable`, and a real `0.0` is
|
|
39
|
+
a meaningful score.
|
|
40
|
+
- **Breaking:** outbox row keys are the store column names, so `project` is
|
|
41
|
+
emitted as `application`, `mode` as `adapter_mode`, `created_at` as
|
|
42
|
+
`timestamp`, and `Output.error` as `is_error` plus `error_text`.
|
|
43
|
+
- **Breaking:** outbox rows no longer carry `model_id` or `prompt_version`. Both
|
|
44
|
+
are `variant.knobs.get(...)` projections and travel inside `variant_knobs`.
|
|
45
|
+
- **Breaking:** `run_id` is now a dashed UUIDv7 rather than `uuid4().hex`, so it
|
|
46
|
+
parses as a ClickHouse `UUID` and carries its own creation time. Uses
|
|
47
|
+
`uuid.uuid7()` on 3.14 and an RFC 9562 implementation on 3.11 through 3.13.
|
|
48
|
+
- Outbox rows now carry the gate: `gate_verdict`, `gate_win`,
|
|
49
|
+
`baseline_run_id`, `baseline_variant`, `win_baseline`, `win_candidate`,
|
|
50
|
+
`win_delta` and `gate_summary` at run grain, plus `win`, `guardrail` and
|
|
51
|
+
`guardrail_gap` on the metric each one refers to. Pass the `Comparison` to
|
|
52
|
+
`score_rows`; without it a run reads as ungated.
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
- `RunResult.aggregate_scores`, retaining the `kind='aggregate'` scores so a
|
|
56
|
+
store row keeps the grader that emitted them and what it reported. The
|
|
57
|
+
scorecard kept only their values.
|
|
58
|
+
- `store.grader_lookups`, mapping grader names to a category and to a judge
|
|
59
|
+
scale from a suite's grader specs, since a `Score` carries neither.
|
|
60
|
+
- Three outbox row shapes that previously had no representation: an aggregate
|
|
61
|
+
metric (no `case_id`), an invocation that failed before any grader ran (no
|
|
62
|
+
`grader` or `metric`), and a metric a guardrail or the win metric names but
|
|
63
|
+
never scored (null value).
|
|
64
|
+
|
|
65
|
+
## [0.2.0] - 2026-07-16
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
- **Breaking:** the import package and CLI are now `evalcore` (were `evalkit`).
|
|
69
|
+
Update `import evalkit` to `import evalcore` and the `evalkit` command to
|
|
70
|
+
`evalcore`. The distribution name (`evalcore`) is unchanged.
|
|
71
|
+
- Lowered the minimum Python to **3.11** (was 3.14).
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
- `evalcore.__version__`.
|
|
75
|
+
- Public `evalcore.adapters.expand_env` for `${VAR}` expansion in custom
|
|
76
|
+
adapters (replaces the private `adapters._env` module).
|
|
77
|
+
- Exception hierarchy: `EvalcoreError` (base) and `ConfigError` (also a
|
|
78
|
+
`ValueError`, so existing handlers keep working).
|
|
79
|
+
- Top-level convenience entry points: `load_suite`, `load_cases`, `run_suite`,
|
|
80
|
+
`run_suite_sync`.
|
|
81
|
+
- HTML rendering for `sweep` and `pairwise` reports, and `--report` /
|
|
82
|
+
`--report-out` on those CLI commands.
|
|
83
|
+
|
|
84
|
+
## [0.1.0] - 2026-07-16
|
|
85
|
+
|
|
86
|
+
- Initial public release: adapters (http/replay), graders (deterministic,
|
|
87
|
+
numeric, classification, LLM judge + panel), runner (N-sampling, concurrency,
|
|
88
|
+
retries, checkpoint/resume), compare/gate, sweep, pairwise, blind human
|
|
89
|
+
rating + ranking with judge agreement, Markdown/HTML reporters, JSON +
|
|
90
|
+
column-store outbox, and content-hash provenance.
|
|
91
|
+
|
|
92
|
+
[Unreleased]: https://github.com/scottpmiller/evalcore/compare/1.0.0...HEAD
|
|
93
|
+
[1.0.0]: https://github.com/scottpmiller/evalcore/compare/0.3.0...1.0.0
|
|
94
|
+
[0.3.0]: https://github.com/scottpmiller/evalcore/compare/0.2.0...0.3.0
|
|
95
|
+
[0.2.0]: https://github.com/scottpmiller/evalcore/compare/0.1.0...0.2.0
|
|
96
|
+
[0.1.0]: https://github.com/scottpmiller/evalcore/releases/tag/0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: evalcore
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: A generic, consumer-agnostic evaluation engine for prompt, model, and API outputs.
|
|
5
5
|
Project-URL: Homepage, https://github.com/scottpmiller/evalcore
|
|
6
6
|
Project-URL: Repository, https://github.com/scottpmiller/evalcore
|
|
@@ -8,7 +8,7 @@ Project-URL: Issues, https://github.com/scottpmiller/evalcore/issues
|
|
|
8
8
|
Author: AWeber Communications
|
|
9
9
|
License-Expression: BSD-3-Clause
|
|
10
10
|
License-File: LICENSE
|
|
11
|
-
Classifier: Development Status ::
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
@@ -768,17 +768,19 @@ offline pairwise config.
|
|
|
768
768
|
## The outbox
|
|
769
769
|
|
|
770
770
|
`JsonlOutboxExporter` flattens results into JSONL for a column-store shipper
|
|
771
|
-
(e.g. ClickHouse) to drain
|
|
772
|
-
`
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
771
|
+
(e.g. ClickHouse) to drain. `export_scores(run)` writes one feed at
|
|
772
|
+
`(run, case, sample, grader, metric)` grain - one row per score, carrying the
|
|
773
|
+
scored value, the invocation it came from, the gate verdict, and the full
|
|
774
|
+
reproducibility key (incl. `run_id`), so a multi-tenant trend table can
|
|
775
|
+
filter/group on any dimension without joins. Nothing derived is written: a
|
|
776
|
+
run's scorecard is a read-time aggregation over the same rows, so it cannot
|
|
777
|
+
disagree with the scores behind it. A missing measurement is `null` (those
|
|
778
|
+
columns are `Nullable`, and a real `0.0` is a meaningful score); `passed` is
|
|
779
|
+
the tri-state string `'true'|'false'|'null'`, matching its `Enum8`. Row keys
|
|
780
|
+
are the store's column names, so a JSONEachRow-style feed maps onto the schema
|
|
781
|
+
in
|
|
782
|
+
[`docs/clickhouse-schema.sql`](docs/clickhouse-schema.sql). Swap the exporter
|
|
783
|
+
for a real database client without touching the runner or any consumer.
|
|
782
784
|
|
|
783
785
|
---
|
|
784
786
|
|
|
@@ -825,16 +827,19 @@ src/evalcore/
|
|
|
825
827
|
tests/ engine unit tests
|
|
826
828
|
examples/quickstart a runnable consumer that doubles as an implementation test
|
|
827
829
|
docs/design.md the design overview
|
|
830
|
+
docs/clickhouse-schema.sql the results-store schema the outbox rows target
|
|
828
831
|
```
|
|
829
832
|
|
|
830
833
|
## Status
|
|
831
834
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
835
|
+
1.0. The public API and the outbox row shape are stable; a breaking change to
|
|
836
|
+
either means a 2.0. Built: deterministic + classification + **LLM-judge**
|
|
837
|
+
(rubric scoring; single judge or a Claude/GPT **panel** with per-dimension
|
|
838
|
+
means, per-judge overalls, inter-judge disagreement flagging, and
|
|
839
|
+
image/screenshot inputs) graders, http/replay/browser adapters, runner
|
|
840
|
+
(N-sampling, optional concurrency, per-sample `RunResult` + `run_id` +
|
|
841
|
+
variance), comparison/gate, JSON + run + outbox store (one score-grain feed,
|
|
842
|
+
`docs/clickhouse-schema.sql`), **N-way sweeps
|
|
838
843
|
+ counterbalanced pairwise A-vs-B win-rate** (`sweep`/`pairwise`), **blind
|
|
839
844
|
human-rating + side-by-side ranking web apps** with judge↔human agreement and
|
|
840
845
|
human-vs-judge pairwise agreement (`rate`/`agreement`, `rank`/`preferences`),
|
|
@@ -847,7 +852,8 @@ Known gaps / next:
|
|
|
847
852
|
in, in `store.py`).
|
|
848
853
|
- Cost/token capture: `Output.tokens`/`cost` fields exist but nothing
|
|
849
854
|
populates them (an adapter must fill them from whatever usage its target
|
|
850
|
-
reports)
|
|
855
|
+
reports), and neither is exported to the results store - usage accounting
|
|
856
|
+
is captured outside it.
|
|
851
857
|
- Run robustness lands: retry with exponential backoff on transient failures
|
|
852
858
|
for both the adapter (suite `retry:` + `Output.retryable`) and the LLM judge
|
|
853
859
|
client, plus idempotent mid-run resume from a `run --checkpoint`.
|
|
@@ -736,17 +736,19 @@ offline pairwise config.
|
|
|
736
736
|
## The outbox
|
|
737
737
|
|
|
738
738
|
`JsonlOutboxExporter` flattens results into JSONL for a column-store shipper
|
|
739
|
-
(e.g. ClickHouse) to drain
|
|
740
|
-
`
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
739
|
+
(e.g. ClickHouse) to drain. `export_scores(run)` writes one feed at
|
|
740
|
+
`(run, case, sample, grader, metric)` grain - one row per score, carrying the
|
|
741
|
+
scored value, the invocation it came from, the gate verdict, and the full
|
|
742
|
+
reproducibility key (incl. `run_id`), so a multi-tenant trend table can
|
|
743
|
+
filter/group on any dimension without joins. Nothing derived is written: a
|
|
744
|
+
run's scorecard is a read-time aggregation over the same rows, so it cannot
|
|
745
|
+
disagree with the scores behind it. A missing measurement is `null` (those
|
|
746
|
+
columns are `Nullable`, and a real `0.0` is a meaningful score); `passed` is
|
|
747
|
+
the tri-state string `'true'|'false'|'null'`, matching its `Enum8`. Row keys
|
|
748
|
+
are the store's column names, so a JSONEachRow-style feed maps onto the schema
|
|
749
|
+
in
|
|
750
|
+
[`docs/clickhouse-schema.sql`](docs/clickhouse-schema.sql). Swap the exporter
|
|
751
|
+
for a real database client without touching the runner or any consumer.
|
|
750
752
|
|
|
751
753
|
---
|
|
752
754
|
|
|
@@ -793,16 +795,19 @@ src/evalcore/
|
|
|
793
795
|
tests/ engine unit tests
|
|
794
796
|
examples/quickstart a runnable consumer that doubles as an implementation test
|
|
795
797
|
docs/design.md the design overview
|
|
798
|
+
docs/clickhouse-schema.sql the results-store schema the outbox rows target
|
|
796
799
|
```
|
|
797
800
|
|
|
798
801
|
## Status
|
|
799
802
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
803
|
+
1.0. The public API and the outbox row shape are stable; a breaking change to
|
|
804
|
+
either means a 2.0. Built: deterministic + classification + **LLM-judge**
|
|
805
|
+
(rubric scoring; single judge or a Claude/GPT **panel** with per-dimension
|
|
806
|
+
means, per-judge overalls, inter-judge disagreement flagging, and
|
|
807
|
+
image/screenshot inputs) graders, http/replay/browser adapters, runner
|
|
808
|
+
(N-sampling, optional concurrency, per-sample `RunResult` + `run_id` +
|
|
809
|
+
variance), comparison/gate, JSON + run + outbox store (one score-grain feed,
|
|
810
|
+
`docs/clickhouse-schema.sql`), **N-way sweeps
|
|
806
811
|
+ counterbalanced pairwise A-vs-B win-rate** (`sweep`/`pairwise`), **blind
|
|
807
812
|
human-rating + side-by-side ranking web apps** with judge↔human agreement and
|
|
808
813
|
human-vs-judge pairwise agreement (`rate`/`agreement`, `rank`/`preferences`),
|
|
@@ -815,7 +820,8 @@ Known gaps / next:
|
|
|
815
820
|
in, in `store.py`).
|
|
816
821
|
- Cost/token capture: `Output.tokens`/`cost` fields exist but nothing
|
|
817
822
|
populates them (an adapter must fill them from whatever usage its target
|
|
818
|
-
reports)
|
|
823
|
+
reports), and neither is exported to the results store - usage accounting
|
|
824
|
+
is captured outside it.
|
|
819
825
|
- Run robustness lands: retry with exponential backoff on transient failures
|
|
820
826
|
for both the adapter (suite `retry:` + `Output.retryable`) and the LLM judge
|
|
821
827
|
client, plus idempotent mid-run resume from a `run --checkpoint`.
|