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.
Files changed (35) hide show
  1. claimeval-1.0.0/LICENSE +21 -0
  2. claimeval-1.0.0/PKG-INFO +198 -0
  3. claimeval-1.0.0/README.md +179 -0
  4. claimeval-1.0.0/claimeval/__init__.py +95 -0
  5. claimeval-1.0.0/claimeval/__main__.py +177 -0
  6. claimeval-1.0.0/claimeval/analysis/__init__.py +26 -0
  7. claimeval-1.0.0/claimeval/analysis/baselines.py +135 -0
  8. claimeval-1.0.0/claimeval/analysis/claims.py +97 -0
  9. claimeval-1.0.0/claimeval/analysis/compare.py +121 -0
  10. claimeval-1.0.0/claimeval/analysis/report.py +179 -0
  11. claimeval-1.0.0/claimeval/core/__init__.py +17 -0
  12. claimeval-1.0.0/claimeval/core/adapters.py +142 -0
  13. claimeval-1.0.0/claimeval/core/ingest.py +201 -0
  14. claimeval-1.0.0/claimeval/core/schema.py +206 -0
  15. claimeval-1.0.0/claimeval/sim/__init__.py +17 -0
  16. claimeval-1.0.0/claimeval/sim/coverage.py +331 -0
  17. claimeval-1.0.0/claimeval/sim/simulate.py +199 -0
  18. claimeval-1.0.0/claimeval/stats/__init__.py +37 -0
  19. claimeval-1.0.0/claimeval/stats/bca.py +100 -0
  20. claimeval-1.0.0/claimeval/stats/bias.py +142 -0
  21. claimeval-1.0.0/claimeval/stats/bootstrap.py +300 -0
  22. claimeval-1.0.0/claimeval/stats/calibrate.py +101 -0
  23. claimeval-1.0.0/claimeval/stats/cost_axis.py +120 -0
  24. claimeval-1.0.0/claimeval/stats/frontier.py +106 -0
  25. claimeval-1.0.0/claimeval/stats/wild.py +143 -0
  26. claimeval-1.0.0/claimeval.egg-info/PKG-INFO +198 -0
  27. claimeval-1.0.0/claimeval.egg-info/SOURCES.txt +33 -0
  28. claimeval-1.0.0/claimeval.egg-info/dependency_links.txt +1 -0
  29. claimeval-1.0.0/claimeval.egg-info/entry_points.txt +2 -0
  30. claimeval-1.0.0/claimeval.egg-info/requires.txt +1 -0
  31. claimeval-1.0.0/claimeval.egg-info/top_level.txt +1 -0
  32. claimeval-1.0.0/pyproject.toml +31 -0
  33. claimeval-1.0.0/setup.cfg +4 -0
  34. claimeval-1.0.0/tests/test_claimeval.py +488 -0
  35. claimeval-1.0.0/tests/test_compare.py +279 -0
@@ -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.
@@ -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
+ [![PyPI version](https://img.shields.io/pypi/v/claimeval.svg)](https://pypi.org/project/claimeval/)
23
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
24
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](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
+ [![PyPI version](https://img.shields.io/pypi/v/claimeval.svg)](https://pypi.org/project/claimeval/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](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())