claimeval 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.
- claimeval-1.0.0/LICENSE +21 -0
- claimeval-1.0.0/PKG-INFO +198 -0
- claimeval-1.0.0/README.md +179 -0
- claimeval-1.0.0/claimeval/__init__.py +95 -0
- claimeval-1.0.0/claimeval/__main__.py +177 -0
- claimeval-1.0.0/claimeval/analysis/__init__.py +26 -0
- claimeval-1.0.0/claimeval/analysis/baselines.py +135 -0
- claimeval-1.0.0/claimeval/analysis/claims.py +97 -0
- claimeval-1.0.0/claimeval/analysis/compare.py +121 -0
- claimeval-1.0.0/claimeval/analysis/report.py +179 -0
- claimeval-1.0.0/claimeval/core/__init__.py +17 -0
- claimeval-1.0.0/claimeval/core/adapters.py +142 -0
- claimeval-1.0.0/claimeval/core/ingest.py +201 -0
- claimeval-1.0.0/claimeval/core/schema.py +206 -0
- claimeval-1.0.0/claimeval/sim/__init__.py +17 -0
- claimeval-1.0.0/claimeval/sim/coverage.py +331 -0
- claimeval-1.0.0/claimeval/sim/simulate.py +199 -0
- claimeval-1.0.0/claimeval/stats/__init__.py +37 -0
- claimeval-1.0.0/claimeval/stats/bca.py +100 -0
- claimeval-1.0.0/claimeval/stats/bias.py +142 -0
- claimeval-1.0.0/claimeval/stats/bootstrap.py +300 -0
- claimeval-1.0.0/claimeval/stats/calibrate.py +101 -0
- claimeval-1.0.0/claimeval/stats/cost_axis.py +120 -0
- claimeval-1.0.0/claimeval/stats/frontier.py +106 -0
- claimeval-1.0.0/claimeval/stats/wild.py +143 -0
- claimeval-1.0.0/claimeval.egg-info/PKG-INFO +198 -0
- claimeval-1.0.0/claimeval.egg-info/SOURCES.txt +33 -0
- claimeval-1.0.0/claimeval.egg-info/dependency_links.txt +1 -0
- claimeval-1.0.0/claimeval.egg-info/entry_points.txt +2 -0
- claimeval-1.0.0/claimeval.egg-info/requires.txt +1 -0
- claimeval-1.0.0/claimeval.egg-info/top_level.txt +1 -0
- claimeval-1.0.0/pyproject.toml +31 -0
- claimeval-1.0.0/setup.cfg +4 -0
- claimeval-1.0.0/tests/test_claimeval.py +488 -0
- claimeval-1.0.0/tests/test_compare.py +279 -0
claimeval-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Harish Mashetty
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
claimeval-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claimeval
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Uncertainty for cost-accuracy claims about AI agents: test whether a leaderboard or paper claim is supported by its own data.
|
|
5
|
+
Author-email: Harish Mashetty <harish.mashetty@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/claimeval/claimeval
|
|
8
|
+
Project-URL: Documentation, https://github.com/claimeval/claimeval#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/claimeval/claimeval
|
|
10
|
+
Project-URL: Issue Tracker, https://github.com/claimeval/claimeval/issues
|
|
11
|
+
Keywords: evaluation,llm,agents,leaderboard,bootstrap,pareto,statistics
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: numpy>=1.22
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# claimeval
|
|
21
|
+
|
|
22
|
+
[](https://pypi.org/project/claimeval/)
|
|
23
|
+
[](https://opensource.org/licenses/MIT)
|
|
24
|
+
[](https://www.python.org/downloads/)
|
|
25
|
+
|
|
26
|
+
**Uncertainty quantification for cost–accuracy claims about AI agents.**
|
|
27
|
+
|
|
28
|
+
Leaderboards, press releases, and papers declare:
|
|
29
|
+
* *"Agent A is #1 on SWE-bench Verified"*
|
|
30
|
+
* *"Model X outperforms Model Y"*
|
|
31
|
+
* *"System A matches System B at a fifth of the cost"*
|
|
32
|
+
* *"Agent A is Pareto-optimal on the cost–accuracy frontier"*
|
|
33
|
+
|
|
34
|
+
Each of these is a statement about noisy sample estimates from a finite benchmark of tasks and runs. `claimeval` attaches a probability to each such claim, using a bootstrap over the correct unit of generalization, and reports whether it is statistically supported.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 🚀 Quick Start
|
|
39
|
+
|
|
40
|
+
### Installation
|
|
41
|
+
|
|
42
|
+
`claimeval` requires only **NumPy**:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install claimeval
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or install from source in editable mode:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git clone https://github.com/claimeval/claimeval.git
|
|
52
|
+
cd claimeval
|
|
53
|
+
pip install -e .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 🔍 Test a Claim in One Command
|
|
59
|
+
|
|
60
|
+
Evaluate claims against a raw rollout log:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
claimeval claims examples/runs.jsonl examples/claims.json --map examples/map.json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Output:**
|
|
67
|
+
```
|
|
68
|
+
id kind subject P(claim) verdict
|
|
69
|
+
c1 top1 agent-E 0.960 supported
|
|
70
|
+
c2 pairwise agent-D 0.996 supported
|
|
71
|
+
c3 cost_dominance agent-D 0.717 NOT supported
|
|
72
|
+
c4 frontier agent-A 0.993 supported
|
|
73
|
+
supported = P >= 0.9; resampling: task
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Claim Definitions (`claims.json`)
|
|
77
|
+
|
|
78
|
+
Define claims in testable JSON schemas:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
[
|
|
82
|
+
{
|
|
83
|
+
"id": "c1",
|
|
84
|
+
"kind": "top1",
|
|
85
|
+
"subject": "agent-A",
|
|
86
|
+
"comparators": ["agent-B", "agent-C"]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "c2",
|
|
90
|
+
"kind": "pairwise",
|
|
91
|
+
"subject": "agent-A",
|
|
92
|
+
"comparators": ["agent-B"]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "c3",
|
|
96
|
+
"kind": "cost_dominance",
|
|
97
|
+
"subject": "agent-B",
|
|
98
|
+
"comparators": ["agent-D"]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "c4",
|
|
102
|
+
"kind": "frontier",
|
|
103
|
+
"subject": "agent-A",
|
|
104
|
+
"comparators": ["agent-B", "agent-C", "agent-D"]
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Supported claim types:
|
|
110
|
+
* `top1`: The subject strictly leads all comparators.
|
|
111
|
+
* `topk`: The subject ranks within the top $k$ systems.
|
|
112
|
+
* `pairwise`: The subject strictly outperforms named rivals.
|
|
113
|
+
* `parity`: Performance difference is within a threshold ($|a_c - a_f| \le \delta$).
|
|
114
|
+
* `cheaper_noninferior`: Subject is cheaper than rival and accuracy is within parity margin.
|
|
115
|
+
* `frontier`: Subject belongs to the non-dominated Pareto frontier.
|
|
116
|
+
* `cost_dominance`: Subject is both strictly cheaper and more accurate than rival.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 🐍 Python API
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from claimeval import Rollout, RolloutSet, Claim, evaluate_claims
|
|
124
|
+
|
|
125
|
+
# Ingest rollout records: (config, task_id, seed, success_bool, cost_dollars, group)
|
|
126
|
+
rollouts = [
|
|
127
|
+
Rollout("agent-A", "task-1", seed=0, success=1.0, cost=0.15, group="repo-1"),
|
|
128
|
+
Rollout("agent-B", "task-1", seed=0, success=0.0, cost=0.08, group="repo-1"),
|
|
129
|
+
# ...
|
|
130
|
+
]
|
|
131
|
+
dataset = RolloutSet(rollouts)
|
|
132
|
+
|
|
133
|
+
# Test a pairwise claim
|
|
134
|
+
claims = [Claim("pairwise", subject="agent-A", comparators=["agent-B"])]
|
|
135
|
+
results = evaluate_claims(dataset, claims, threshold=0.9, n_boot=2000)
|
|
136
|
+
|
|
137
|
+
for r in results:
|
|
138
|
+
print(f"Claim {r['id']}: P = {r['probability']:.3f} -> {r['verdict']}")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Modular Architecture & Subpackages
|
|
142
|
+
|
|
143
|
+
`claimeval` is organized into clean, focused subpackages:
|
|
144
|
+
|
|
145
|
+
* **`claimeval.core`**: Data models (`Rollout`, `RolloutSet`), stream/file ingestion (`load`, `inspect_path`), and benchmark loaders (`swebench`, `terminal_bench`, `tau2`).
|
|
146
|
+
* **`claimeval.stats`**: Resampling estimators (`hierarchical_bootstrap`, `variance_decomposition`), Pareto geometry (`dominance`, `pareto_mask`, `frontier_band`, `hausdorff`), cluster methods (`wild_intervals`), BCa intervals, bias corrections (`split_sample_debias`), and cost diagnostics (`diagnose_cost_axis`).
|
|
147
|
+
* **`claimeval.analysis`**: Claim evaluation engine (`Claim`, `evaluate_claims`), benchmark baselines, pairwise comparison suites, and formatted tabular reporting (`analyze`, `headline`).
|
|
148
|
+
* **`claimeval.sim`**: Generative ground-truth simulations (`make_population`, `simulate`) and Monte Carlo estimator coverage studies (`coverage_study`).
|
|
149
|
+
|
|
150
|
+
All common functions remain accessible directly from the top-level `import claimeval`.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 📊 Auditing Public Benchmarks Directly
|
|
155
|
+
|
|
156
|
+
`claimeval` provides built-in loaders for public agent benchmarks:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# SWE-bench Verified (from github.com/SWE-bench/experiments)
|
|
160
|
+
claimeval claims evaluation/verified claims.json --from swebench
|
|
161
|
+
|
|
162
|
+
# SWE-bench Verified cost leaderboard (mini-SWE-agent runs)
|
|
163
|
+
claimeval claims evaluation/verified claims.json --from swebench-cost
|
|
164
|
+
|
|
165
|
+
# Terminal-Bench 2.0 (Harbor evaluation trees)
|
|
166
|
+
claimeval claims submissions/terminal-bench/2.0 claims.json --from terminal-bench
|
|
167
|
+
|
|
168
|
+
# tau2-bench leaderboard trajectories
|
|
169
|
+
claimeval claims tau2_results/ claims.json --from tau2
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 🛠️ CLI Toolkit
|
|
175
|
+
|
|
176
|
+
| Command | Purpose |
|
|
177
|
+
|---|---|
|
|
178
|
+
| `claimeval claims` | Evaluate a set of typed claims against a rollout dataset |
|
|
179
|
+
| `claimeval analyze` | Compute empirical Pareto frontier with membership & dominance probabilities |
|
|
180
|
+
| `claimeval inspect` | Automatically inspect schema and statistics of an unknown evaluation dump |
|
|
181
|
+
| `claimeval seed-curve` | Simulate error of a $k$-run study vs. full data |
|
|
182
|
+
| `claimeval coverage` | Validate estimator calibration against known ground truth |
|
|
183
|
+
| `claimeval demo` | Run an end-to-end demonstration on synthetic benchmark data |
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 👤 Author & Contact
|
|
188
|
+
|
|
189
|
+
**Harish Mashetty**
|
|
190
|
+
Independent Researcher
|
|
191
|
+
E-mail: [harish.mashetty@gmail.com](mailto:harish.mashetty@gmail.com)
|
|
192
|
+
Project Repository: [https://github.com/claimeval/claimeval](https://github.com/claimeval/claimeval)
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 📜 License
|
|
197
|
+
|
|
198
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# claimeval
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/claimeval/)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
|
|
7
|
+
**Uncertainty quantification for cost–accuracy claims about AI agents.**
|
|
8
|
+
|
|
9
|
+
Leaderboards, press releases, and papers declare:
|
|
10
|
+
* *"Agent A is #1 on SWE-bench Verified"*
|
|
11
|
+
* *"Model X outperforms Model Y"*
|
|
12
|
+
* *"System A matches System B at a fifth of the cost"*
|
|
13
|
+
* *"Agent A is Pareto-optimal on the cost–accuracy frontier"*
|
|
14
|
+
|
|
15
|
+
Each of these is a statement about noisy sample estimates from a finite benchmark of tasks and runs. `claimeval` attaches a probability to each such claim, using a bootstrap over the correct unit of generalization, and reports whether it is statistically supported.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
### Installation
|
|
22
|
+
|
|
23
|
+
`claimeval` requires only **NumPy**:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install claimeval
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or install from source in editable mode:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone https://github.com/claimeval/claimeval.git
|
|
33
|
+
cd claimeval
|
|
34
|
+
pip install -e .
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 🔍 Test a Claim in One Command
|
|
40
|
+
|
|
41
|
+
Evaluate claims against a raw rollout log:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
claimeval claims examples/runs.jsonl examples/claims.json --map examples/map.json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Output:**
|
|
48
|
+
```
|
|
49
|
+
id kind subject P(claim) verdict
|
|
50
|
+
c1 top1 agent-E 0.960 supported
|
|
51
|
+
c2 pairwise agent-D 0.996 supported
|
|
52
|
+
c3 cost_dominance agent-D 0.717 NOT supported
|
|
53
|
+
c4 frontier agent-A 0.993 supported
|
|
54
|
+
supported = P >= 0.9; resampling: task
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Claim Definitions (`claims.json`)
|
|
58
|
+
|
|
59
|
+
Define claims in testable JSON schemas:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
[
|
|
63
|
+
{
|
|
64
|
+
"id": "c1",
|
|
65
|
+
"kind": "top1",
|
|
66
|
+
"subject": "agent-A",
|
|
67
|
+
"comparators": ["agent-B", "agent-C"]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "c2",
|
|
71
|
+
"kind": "pairwise",
|
|
72
|
+
"subject": "agent-A",
|
|
73
|
+
"comparators": ["agent-B"]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "c3",
|
|
77
|
+
"kind": "cost_dominance",
|
|
78
|
+
"subject": "agent-B",
|
|
79
|
+
"comparators": ["agent-D"]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "c4",
|
|
83
|
+
"kind": "frontier",
|
|
84
|
+
"subject": "agent-A",
|
|
85
|
+
"comparators": ["agent-B", "agent-C", "agent-D"]
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Supported claim types:
|
|
91
|
+
* `top1`: The subject strictly leads all comparators.
|
|
92
|
+
* `topk`: The subject ranks within the top $k$ systems.
|
|
93
|
+
* `pairwise`: The subject strictly outperforms named rivals.
|
|
94
|
+
* `parity`: Performance difference is within a threshold ($|a_c - a_f| \le \delta$).
|
|
95
|
+
* `cheaper_noninferior`: Subject is cheaper than rival and accuracy is within parity margin.
|
|
96
|
+
* `frontier`: Subject belongs to the non-dominated Pareto frontier.
|
|
97
|
+
* `cost_dominance`: Subject is both strictly cheaper and more accurate than rival.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 🐍 Python API
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from claimeval import Rollout, RolloutSet, Claim, evaluate_claims
|
|
105
|
+
|
|
106
|
+
# Ingest rollout records: (config, task_id, seed, success_bool, cost_dollars, group)
|
|
107
|
+
rollouts = [
|
|
108
|
+
Rollout("agent-A", "task-1", seed=0, success=1.0, cost=0.15, group="repo-1"),
|
|
109
|
+
Rollout("agent-B", "task-1", seed=0, success=0.0, cost=0.08, group="repo-1"),
|
|
110
|
+
# ...
|
|
111
|
+
]
|
|
112
|
+
dataset = RolloutSet(rollouts)
|
|
113
|
+
|
|
114
|
+
# Test a pairwise claim
|
|
115
|
+
claims = [Claim("pairwise", subject="agent-A", comparators=["agent-B"])]
|
|
116
|
+
results = evaluate_claims(dataset, claims, threshold=0.9, n_boot=2000)
|
|
117
|
+
|
|
118
|
+
for r in results:
|
|
119
|
+
print(f"Claim {r['id']}: P = {r['probability']:.3f} -> {r['verdict']}")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Modular Architecture & Subpackages
|
|
123
|
+
|
|
124
|
+
`claimeval` is organized into clean, focused subpackages:
|
|
125
|
+
|
|
126
|
+
* **`claimeval.core`**: Data models (`Rollout`, `RolloutSet`), stream/file ingestion (`load`, `inspect_path`), and benchmark loaders (`swebench`, `terminal_bench`, `tau2`).
|
|
127
|
+
* **`claimeval.stats`**: Resampling estimators (`hierarchical_bootstrap`, `variance_decomposition`), Pareto geometry (`dominance`, `pareto_mask`, `frontier_band`, `hausdorff`), cluster methods (`wild_intervals`), BCa intervals, bias corrections (`split_sample_debias`), and cost diagnostics (`diagnose_cost_axis`).
|
|
128
|
+
* **`claimeval.analysis`**: Claim evaluation engine (`Claim`, `evaluate_claims`), benchmark baselines, pairwise comparison suites, and formatted tabular reporting (`analyze`, `headline`).
|
|
129
|
+
* **`claimeval.sim`**: Generative ground-truth simulations (`make_population`, `simulate`) and Monte Carlo estimator coverage studies (`coverage_study`).
|
|
130
|
+
|
|
131
|
+
All common functions remain accessible directly from the top-level `import claimeval`.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 📊 Auditing Public Benchmarks Directly
|
|
136
|
+
|
|
137
|
+
`claimeval` provides built-in loaders for public agent benchmarks:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# SWE-bench Verified (from github.com/SWE-bench/experiments)
|
|
141
|
+
claimeval claims evaluation/verified claims.json --from swebench
|
|
142
|
+
|
|
143
|
+
# SWE-bench Verified cost leaderboard (mini-SWE-agent runs)
|
|
144
|
+
claimeval claims evaluation/verified claims.json --from swebench-cost
|
|
145
|
+
|
|
146
|
+
# Terminal-Bench 2.0 (Harbor evaluation trees)
|
|
147
|
+
claimeval claims submissions/terminal-bench/2.0 claims.json --from terminal-bench
|
|
148
|
+
|
|
149
|
+
# tau2-bench leaderboard trajectories
|
|
150
|
+
claimeval claims tau2_results/ claims.json --from tau2
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 🛠️ CLI Toolkit
|
|
156
|
+
|
|
157
|
+
| Command | Purpose |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `claimeval claims` | Evaluate a set of typed claims against a rollout dataset |
|
|
160
|
+
| `claimeval analyze` | Compute empirical Pareto frontier with membership & dominance probabilities |
|
|
161
|
+
| `claimeval inspect` | Automatically inspect schema and statistics of an unknown evaluation dump |
|
|
162
|
+
| `claimeval seed-curve` | Simulate error of a $k$-run study vs. full data |
|
|
163
|
+
| `claimeval coverage` | Validate estimator calibration against known ground truth |
|
|
164
|
+
| `claimeval demo` | Run an end-to-end demonstration on synthetic benchmark data |
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 👤 Author & Contact
|
|
169
|
+
|
|
170
|
+
**Harish Mashetty**
|
|
171
|
+
Independent Researcher
|
|
172
|
+
E-mail: [harish.mashetty@gmail.com](mailto:harish.mashetty@gmail.com)
|
|
173
|
+
Project Repository: [https://github.com/claimeval/claimeval](https://github.com/claimeval/claimeval)
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 📜 License
|
|
178
|
+
|
|
179
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""claimeval -- test the claims made about AI agents against the data behind them.
|
|
2
|
+
|
|
3
|
+
A claim ("#1", "beats X", "as good at lower cost", "on the cost-accuracy
|
|
4
|
+
frontier") gets the probability that it holds, from a bootstrap over the right
|
|
5
|
+
unit (tasks, or clusters such as repositories), and a verdict. Input is a
|
|
6
|
+
stream of (config, task, seed, success, cost[, group]) runs from any harness,
|
|
7
|
+
or a public leaderboard release read by `claimeval.core.adapters`. Also: frontier
|
|
8
|
+
membership and dominance probabilities, a Hausdorff frontier band, a
|
|
9
|
+
winner's-curse correction, wild cluster bootstrap intervals, and a task-vs-seed
|
|
10
|
+
variance decomposition.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
# Subpackages
|
|
16
|
+
from . import core
|
|
17
|
+
from . import stats
|
|
18
|
+
from . import analysis
|
|
19
|
+
from . import sim
|
|
20
|
+
|
|
21
|
+
# Core data structures and loaders
|
|
22
|
+
from .core.schema import Rollout, RolloutSet
|
|
23
|
+
from .core.ingest import FieldMap, guess_map, inspect_path, load
|
|
24
|
+
|
|
25
|
+
# Statistical methods, frontier geometry & diagnostics
|
|
26
|
+
from .stats.frontier import dominance, frontier_band, frontier_points, hausdorff, log_cost_range, pareto_mask
|
|
27
|
+
from .stats.bootstrap import BootstrapResult, auto_mode, hierarchical_bootstrap, variance_decomposition
|
|
28
|
+
from .stats.wild import wild_intervals
|
|
29
|
+
from .stats.bias import seed_count_curve, split_sample_debias
|
|
30
|
+
from .stats.cost_axis import diagnose_cost_axis, format_diagnosis
|
|
31
|
+
|
|
32
|
+
# Analysis, claims & reporting
|
|
33
|
+
from .analysis.claims import Claim, evaluate_claims
|
|
34
|
+
from .analysis.report import analyze, format_report, headline
|
|
35
|
+
|
|
36
|
+
# Simulation & coverage validation
|
|
37
|
+
from .sim.simulate import make_population, population_truth, sample_dataset, simulate
|
|
38
|
+
from .sim.coverage import coverage_study, format_coverage
|
|
39
|
+
|
|
40
|
+
# Backward compatibility aliases for module paths
|
|
41
|
+
sys.modules["claimeval.schema"] = core.schema
|
|
42
|
+
sys.modules["claimeval.ingest"] = core.ingest
|
|
43
|
+
sys.modules["claimeval.adapters"] = core.adapters
|
|
44
|
+
sys.modules["claimeval.bootstrap"] = stats.bootstrap
|
|
45
|
+
sys.modules["claimeval.wild"] = stats.wild
|
|
46
|
+
sys.modules["claimeval.bca"] = stats.bca
|
|
47
|
+
sys.modules["claimeval.calibrate"] = stats.calibrate
|
|
48
|
+
sys.modules["claimeval.bias"] = stats.bias
|
|
49
|
+
sys.modules["claimeval.cost_axis"] = stats.cost_axis
|
|
50
|
+
sys.modules["claimeval.frontier"] = stats.frontier
|
|
51
|
+
sys.modules["claimeval.claims"] = analysis.claims
|
|
52
|
+
sys.modules["claimeval.compare"] = analysis.compare
|
|
53
|
+
sys.modules["claimeval.baselines"] = analysis.baselines
|
|
54
|
+
sys.modules["claimeval.report"] = analysis.report
|
|
55
|
+
sys.modules["claimeval.simulate"] = sim.simulate
|
|
56
|
+
sys.modules["claimeval.coverage"] = sim.coverage
|
|
57
|
+
|
|
58
|
+
__version__ = "1.0.0"
|
|
59
|
+
|
|
60
|
+
__all__ = [
|
|
61
|
+
"core",
|
|
62
|
+
"stats",
|
|
63
|
+
"analysis",
|
|
64
|
+
"sim",
|
|
65
|
+
"Claim",
|
|
66
|
+
"evaluate_claims",
|
|
67
|
+
"auto_mode",
|
|
68
|
+
"wild_intervals",
|
|
69
|
+
"Rollout",
|
|
70
|
+
"RolloutSet",
|
|
71
|
+
"FieldMap",
|
|
72
|
+
"guess_map",
|
|
73
|
+
"inspect_path",
|
|
74
|
+
"load",
|
|
75
|
+
"analyze",
|
|
76
|
+
"headline",
|
|
77
|
+
"format_report",
|
|
78
|
+
"hierarchical_bootstrap",
|
|
79
|
+
"BootstrapResult",
|
|
80
|
+
"variance_decomposition",
|
|
81
|
+
"pareto_mask",
|
|
82
|
+
"dominance",
|
|
83
|
+
"frontier_points",
|
|
84
|
+
"hausdorff",
|
|
85
|
+
"frontier_band",
|
|
86
|
+
"log_cost_range",
|
|
87
|
+
"split_sample_debias",
|
|
88
|
+
"seed_count_curve",
|
|
89
|
+
"simulate",
|
|
90
|
+
"make_population",
|
|
91
|
+
"sample_dataset",
|
|
92
|
+
"population_truth",
|
|
93
|
+
"coverage_study",
|
|
94
|
+
"format_coverage",
|
|
95
|
+
]
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""CLI: claimeval {demo,inspect,analyze,claims,seed-curve,coverage}"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import glob
|
|
7
|
+
import os
|
|
8
|
+
import json
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
from claimeval.stats.bias import seed_count_curve
|
|
14
|
+
from claimeval.core.ingest import FieldMap, guess_map, inspect_path, load
|
|
15
|
+
from claimeval.analysis.report import analyze
|
|
16
|
+
from claimeval.core.schema import RolloutSet
|
|
17
|
+
from claimeval.sim.simulate import simulate
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _load(args) -> RolloutSet:
|
|
21
|
+
src = getattr(args, "source", None)
|
|
22
|
+
if src:
|
|
23
|
+
from claimeval.core import adapters
|
|
24
|
+
if src == "tau2":
|
|
25
|
+
rs, skipped = adapters.tau2(sorted(glob.glob(os.path.join(args.path, "*.json")))
|
|
26
|
+
if os.path.isdir(args.path) else [args.path])
|
|
27
|
+
elif src == "swebench-cost":
|
|
28
|
+
rs, skipped = adapters.swebench(args.path, with_cost=True)
|
|
29
|
+
else:
|
|
30
|
+
rs, skipped = {"swebench": adapters.swebench,
|
|
31
|
+
"terminal-bench": adapters.terminal_bench}[src](args.path)
|
|
32
|
+
for k, v in skipped.items():
|
|
33
|
+
print(f"[skipped] {k}: {v}", file=sys.stderr)
|
|
34
|
+
return rs
|
|
35
|
+
if args.map:
|
|
36
|
+
fmap = FieldMap.from_dict(json.loads(open(args.map).read()))
|
|
37
|
+
else:
|
|
38
|
+
info = inspect_path(args.path)
|
|
39
|
+
fmap = info["guess"]
|
|
40
|
+
print(f"[guessed mapping] {fmap}\n", file=sys.stderr)
|
|
41
|
+
rs, dropped = load(args.path, fmap)
|
|
42
|
+
if dropped:
|
|
43
|
+
print(f"[dropped records] {dropped}\n", file=sys.stderr)
|
|
44
|
+
return rs
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _print_curve(rows: list[dict]) -> None:
|
|
48
|
+
print(f"\n{'k':>3}{'Jaccard vs full':>18}{'Hausdorff':>12}"
|
|
49
|
+
f"{'acc inflation':>16}{'cost inflation':>16}{'|front|':>9}")
|
|
50
|
+
print("-" * 74)
|
|
51
|
+
for r in rows:
|
|
52
|
+
print(
|
|
53
|
+
f"{r['k']:>3}{r['jaccard_vs_full']:>18.3f}{r['hausdorff_vs_full']:>12.4f}"
|
|
54
|
+
f"{r['acc_inflation']:>+16.4f}{r['cost_inflation']:>+16.4f}"
|
|
55
|
+
f"{r['frontier_size']:>9.1f}"
|
|
56
|
+
)
|
|
57
|
+
print("\nacc inflation = what a k-seed study claims for its own frontier winners,")
|
|
58
|
+
print("minus what the full data says about those same configs.")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def main(argv: list[str] | None = None) -> int:
|
|
62
|
+
ap = argparse.ArgumentParser(prog="claimeval")
|
|
63
|
+
sub = ap.add_subparsers(dest="cmd", required=True)
|
|
64
|
+
|
|
65
|
+
d = sub.add_parser("demo", help="end-to-end run on simulated data")
|
|
66
|
+
d.add_argument("--seeds", type=int, default=20)
|
|
67
|
+
d.add_argument("--tasks", type=int, default=50)
|
|
68
|
+
d.add_argument("--configs", type=int, default=9)
|
|
69
|
+
d.add_argument("--boot", type=int, default=2000)
|
|
70
|
+
|
|
71
|
+
i = sub.add_parser("inspect", help="discover the schema of a results dump")
|
|
72
|
+
i.add_argument("path")
|
|
73
|
+
|
|
74
|
+
a = sub.add_parser("analyze", help="audit frontier claims in a results dump")
|
|
75
|
+
a.add_argument("path")
|
|
76
|
+
a.add_argument("--map", help="JSON field mapping; omit to auto-guess")
|
|
77
|
+
a.add_argument("--from", dest="source", choices=["swebench", "swebench-cost", "terminal-bench", "tau2"],
|
|
78
|
+
help="read a public leaderboard release directly (see claimeval.adapters)")
|
|
79
|
+
|
|
80
|
+
a.add_argument("--boot", type=int, default=2000)
|
|
81
|
+
a.add_argument("--threshold", type=float, default=0.90)
|
|
82
|
+
|
|
83
|
+
c = sub.add_parser("claims", help="test published claims (top1, pairwise, margin, "
|
|
84
|
+
"cost_dominance, frontier) against a results dump")
|
|
85
|
+
c.add_argument("path")
|
|
86
|
+
c.add_argument("claims", help="JSON list of {kind, subject, comparators, margin, id}")
|
|
87
|
+
c.add_argument("--map")
|
|
88
|
+
c.add_argument("--from", dest="source", choices=["swebench", "swebench-cost", "terminal-bench", "tau2"],
|
|
89
|
+
help="read a public leaderboard release directly (see claimeval.adapters)")
|
|
90
|
+
|
|
91
|
+
c.add_argument("--boot", type=int, default=4000)
|
|
92
|
+
c.add_argument("--threshold", type=float, default=0.90)
|
|
93
|
+
c.add_argument("--mode", default=None,
|
|
94
|
+
choices=["task", "cluster_t"],
|
|
95
|
+
help="resampling unit; default: clusters if the data has them, else tasks")
|
|
96
|
+
|
|
97
|
+
s = sub.add_parser("seed-curve", help="error of a k-seed frontier vs the full data")
|
|
98
|
+
s.add_argument("path")
|
|
99
|
+
s.add_argument("--map")
|
|
100
|
+
s.add_argument("--ks", default="1,2,3,5,10")
|
|
101
|
+
|
|
102
|
+
cv = sub.add_parser("coverage", help="validate the estimator against known truth")
|
|
103
|
+
cv.add_argument("--reps", type=int, default=200)
|
|
104
|
+
cv.add_argument("--configs", type=int, default=9)
|
|
105
|
+
cv.add_argument("--tasks", type=int, default=50)
|
|
106
|
+
cv.add_argument("--seeds", type=int, default=5)
|
|
107
|
+
cv.add_argument("--boot", type=int, default=500)
|
|
108
|
+
cv.add_argument("--level", type=float, default=0.95)
|
|
109
|
+
cv.add_argument("--threshold", type=float, default=0.90)
|
|
110
|
+
cv.add_argument("--mode", default="task", choices=["task", "both", "seed"],
|
|
111
|
+
help="bootstrap mode; 'both' double-counts within-cell noise")
|
|
112
|
+
|
|
113
|
+
args = ap.parse_args(argv)
|
|
114
|
+
rng = np.random.default_rng(0)
|
|
115
|
+
|
|
116
|
+
if args.cmd == "demo":
|
|
117
|
+
rolls, truth = simulate(args.configs, args.tasks, args.seeds, rng)
|
|
118
|
+
rs = RolloutSet(rolls)
|
|
119
|
+
report, head = analyze(rs, n_boot=args.boot, rng=rng)
|
|
120
|
+
print(report)
|
|
121
|
+
print("\nGround truth accuracy (simulator):")
|
|
122
|
+
for c, t in zip(truth["configs"], truth["accuracy"]):
|
|
123
|
+
print(f" {c:<26}{t:.3f}")
|
|
124
|
+
_print_curve(seed_count_curve(rs, (1, 2, 3, 5, 10), n_repeats=30, rng=rng))
|
|
125
|
+
return 0
|
|
126
|
+
|
|
127
|
+
if args.cmd == "coverage":
|
|
128
|
+
from claimeval.sim.coverage import coverage_study, format_coverage
|
|
129
|
+
|
|
130
|
+
res = coverage_study(
|
|
131
|
+
n_reps=args.reps, n_configs=args.configs, n_tasks=args.tasks,
|
|
132
|
+
n_seeds=args.seeds, n_boot=args.boot, level=args.level,
|
|
133
|
+
threshold=args.threshold, boot_mode=args.mode,
|
|
134
|
+
)
|
|
135
|
+
print(format_coverage(res))
|
|
136
|
+
return 0
|
|
137
|
+
|
|
138
|
+
if args.cmd == "inspect":
|
|
139
|
+
info = inspect_path(args.path)
|
|
140
|
+
print(f"{info['n_records']} records scanned\n")
|
|
141
|
+
print(f"{'field':<46}{'count':>8} samples")
|
|
142
|
+
print("-" * 78)
|
|
143
|
+
for k, n in info["keys"].most_common(60):
|
|
144
|
+
ex = ", ".join(str(v)[:18] for v in info["samples"].get(k, []))
|
|
145
|
+
print(f"{k[:46]:<46}{n:>8} {ex[:24]}")
|
|
146
|
+
print(f"\nguessed mapping: {info['guess']}")
|
|
147
|
+
print("Verify this, then pass it with --map. Wrong success/cost fields")
|
|
148
|
+
print("produce a confident, meaningless frontier.")
|
|
149
|
+
return 0
|
|
150
|
+
|
|
151
|
+
rs = _load(args)
|
|
152
|
+
if args.cmd == "claims":
|
|
153
|
+
from claimeval.analysis.claims import Claim, evaluate_claims
|
|
154
|
+
|
|
155
|
+
spec = json.loads(open(args.claims).read())
|
|
156
|
+
cl = [Claim(x["kind"], x["subject"], x.get("comparators", []), x.get("margin", 0.0),
|
|
157
|
+
x.get("id", ""), x.get("k", 1)) for x in spec]
|
|
158
|
+
res = evaluate_claims(rs, cl, n_boot=args.boot, mode=args.mode, rng=rng, thr=args.threshold)
|
|
159
|
+
print(f"{'id':<10}{'kind':<16}{'subject':<28}{'P(claim)':>9} verdict")
|
|
160
|
+
for r in res:
|
|
161
|
+
v = "supported" if r["supported"] else (
|
|
162
|
+
"NOT supported" if r["holds_at_point_estimate"] else "contradicted by point estimate")
|
|
163
|
+
print(f"{r['id'][:9]:<10}{r['kind']:<16}{r['subject'][:27]:<28}{r['probability']:>9.3f} {v}")
|
|
164
|
+
print(f"\nsupported = P >= {args.threshold}; resampling: {res[0]['mode'] if res else '-'}")
|
|
165
|
+
return 0
|
|
166
|
+
if args.cmd == "analyze":
|
|
167
|
+
report, _ = analyze(rs, n_boot=args.boot, threshold=args.threshold, rng=rng)
|
|
168
|
+
print(report)
|
|
169
|
+
else:
|
|
170
|
+
ks = tuple(int(x) for x in args.ks.split(","))
|
|
171
|
+
print(rs.describe())
|
|
172
|
+
_print_curve(seed_count_curve(rs, ks, n_repeats=30, rng=rng))
|
|
173
|
+
return 0
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if __name__ == "__main__":
|
|
177
|
+
raise SystemExit(main())
|