pluginbench 0.5.0__py3-none-any.whl

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 (58) hide show
  1. pluginbench/__init__.py +3 -0
  2. pluginbench/__main__.py +3 -0
  3. pluginbench/assessment-charts.html +790 -0
  4. pluginbench/assessment.py +316 -0
  5. pluginbench/assessment_charts.py +1225 -0
  6. pluginbench/assessment_metrics.py +1956 -0
  7. pluginbench/assessment_models.py +127 -0
  8. pluginbench/baselines.py +792 -0
  9. pluginbench/claude.py +374 -0
  10. pluginbench/cli.py +672 -0
  11. pluginbench/code_diff.py +207 -0
  12. pluginbench/codex.py +451 -0
  13. pluginbench/codex_events.py +585 -0
  14. pluginbench/collectors.py +591 -0
  15. pluginbench/compare.py +927 -0
  16. pluginbench/components.py +129 -0
  17. pluginbench/coverage_report.py +610 -0
  18. pluginbench/datasets.py +207 -0
  19. pluginbench/evaluation.example.yaml +45 -0
  20. pluginbench/evaluation.py +1651 -0
  21. pluginbench/evaluation_report.py +1004 -0
  22. pluginbench/fallow_parse.mjs +101 -0
  23. pluginbench/harbor_backend.py +2946 -0
  24. pluginbench/isolation.py +314 -0
  25. pluginbench/judge.py +683 -0
  26. pluginbench/language_analysis.py +915 -0
  27. pluginbench/ledger.py +217 -0
  28. pluginbench/measurement_profiles.py +616 -0
  29. pluginbench/native_treatment_runtime.js +221 -0
  30. pluginbench/native_treatments.py +155 -0
  31. pluginbench/observer_data/go-analysis-v1/go.mod +10 -0
  32. pluginbench/observer_data/go-analysis-v1/go.sum +10 -0
  33. pluginbench/observer_data/go-analysis-v1/main.go +64 -0
  34. pluginbench/observer_data/oxc-parser-0.126.0/package-lock.json +449 -0
  35. pluginbench/observer_data/oxc-parser-0.126.0/package.json +5 -0
  36. pluginbench/parallel.py +101 -0
  37. pluginbench/processes.py +100 -0
  38. pluginbench/remeasure.py +992 -0
  39. pluginbench/run_lock.py +227 -0
  40. pluginbench/run_status.py +518 -0
  41. pluginbench/study.py +1858 -0
  42. pluginbench/study_review.py +924 -0
  43. pluginbench/submissions.py +486 -0
  44. pluginbench/task_sources.py +403 -0
  45. pluginbench/treatments.py +388 -0
  46. pluginbench/trial_containers.py +94 -0
  47. pluginbench/vendor/ECHARTS-LICENSE +222 -0
  48. pluginbench/vendor/ECHARTS-NOTICE +5 -0
  49. pluginbench/vendor/ZRENDER-LICENSE +29 -0
  50. pluginbench/vendor/echarts.min.js +48 -0
  51. pluginbench-0.5.0.dist-info/METADATA +294 -0
  52. pluginbench-0.5.0.dist-info/RECORD +58 -0
  53. pluginbench-0.5.0.dist-info/WHEEL +4 -0
  54. pluginbench-0.5.0.dist-info/entry_points.txt +2 -0
  55. pluginbench-0.5.0.dist-info/licenses/LICENSE +201 -0
  56. pluginbench-0.5.0.dist-info/licenses/src/pluginbench/vendor/ECHARTS-LICENSE +222 -0
  57. pluginbench-0.5.0.dist-info/licenses/src/pluginbench/vendor/ECHARTS-NOTICE +5 -0
  58. pluginbench-0.5.0.dist-info/licenses/src/pluginbench/vendor/ZRENDER-LICENSE +29 -0
@@ -0,0 +1,129 @@
1
+ """Declared versions of PluginBench's own components, and the source hashes saved runs hold.
2
+
3
+ Saved runs and caches bind each component by its declared version, not by its source bytes,
4
+ so a fix that leaves a component's behaviour unchanged keeps them usable. The hashes are
5
+ still saved as provenance. `tests/test_components.py` pins each file's current hash to its
6
+ component's version: changing a file fails that test until someone decides whether the
7
+ change needs a new version.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import hashlib
13
+ from collections.abc import Mapping
14
+ from pathlib import Path
15
+
16
+ VERSIONS: dict[str, int] = {
17
+ "launcher": 1,
18
+ "analysis_observer": 1,
19
+ "coverage_observer": 1,
20
+ # Version 2 denies writes to / and /tmp in the Linux sandbox (b05b459).
21
+ "local_sandbox": 2,
22
+ }
23
+
24
+ # The source files each component's version stands for. These are the only hashed files.
25
+ FILES: dict[str, tuple[str, ...]] = {
26
+ # How a coding attempt is launched. Session parsing lives in codex_events.py, outside
27
+ # this list, so a parser-only change keeps every vanilla cache entry. claude.py counts
28
+ # only when Claude is the harness.
29
+ "launcher": (
30
+ "codex.py",
31
+ "harbor_backend.py",
32
+ "processes.py",
33
+ "native_treatments.py",
34
+ "native_treatment_runtime.js",
35
+ "treatments.py",
36
+ "claude.py",
37
+ ),
38
+ "analysis_observer": ("language_analysis.py",),
39
+ "coverage_observer": ("coverage_report.py",),
40
+ "local_sandbox": ("isolation.py",),
41
+ }
42
+
43
+ # Every content each file had on main from 942f12c up to 34386c5, before versions were
44
+ # saved. Runs and caches from that range record only these hashes. This table is fixed:
45
+ # later changes are saved with their version and never added here.
46
+ _SAVED_HASHES: dict[str, dict[str, int]] = {
47
+ "codex.py": {"6b1d892b37ea5e33337a469923762fe71130e22c840859771367cf34fa66b21f": 1},
48
+ "harbor_backend.py": {"066f9a3641d85ae8d109357b545e82973d4eb8a7bb7c5fbed4eed29c96df62b8": 1},
49
+ "processes.py": {"0170e0a4902fc610d19b50ed5656c601474adad97b9b8d6fb5b08c6ab6ad00d1": 1},
50
+ "native_treatments.py": {"dcb11553bc9bd2ea7a15ff3293d3ec74617565f89c3c2d156f714acade8b73a8": 1},
51
+ "native_treatment_runtime.js": {
52
+ "229d01b78fd893b8e502139507b74d18f0147079c58f15f90b0548b5520e67c5": 1
53
+ },
54
+ "treatments.py": {"e807503ac1809dd1030a6805702fe23da0d4cd07eb2d9f52d12069ae85f1926f": 1},
55
+ "claude.py": {"87951a73f68414d49253815480c683695e586b0c205adb6cbdb61101e887abd7": 1},
56
+ "language_analysis.py": {
57
+ # 942f12c, then the Rust dep-info fix (959d5f6, 9474664): same results where the
58
+ # earlier file returned one.
59
+ "bc09200c57bf78d403d9f5b473d16af5ea653059dc06559ae3c86ba4652b9744": 1,
60
+ "9d3e0281732cf43504eee765d32a95d73909dfc202ce0528a910403f6e5bec2e": 1,
61
+ "d80e0593e2e33acdf415b36bc5a24ff8e096281fa5b6d8d3d3ef5c8a7a29f03a": 1,
62
+ },
63
+ "coverage_report.py": {"1a097f128f99b6ce57b23d903a52a199061a00039f7662767d8e6777821186cc": 1},
64
+ "isolation.py": {
65
+ "cee7b89e2ce9887733a2d6cda2010885b2c6e9c388939c110b3592bb8f193135": 1,
66
+ "992f724c3c12dbd8b1950261edd980f88b677ccd962d73782ef4241ba0114984": 2,
67
+ },
68
+ }
69
+
70
+
71
+ class UnknownSourceError(ValueError):
72
+ """A saved run records source bytes that no PluginBench version declares."""
73
+
74
+
75
+ class ObserverError(ValueError):
76
+ """A measurement profile cannot be measured by the observer this build runs."""
77
+
78
+
79
+ # What to do with a measurement profile that another observer version froze.
80
+ OBSERVER_NEXT_STEP = (
81
+ "measure it with the PluginBench build that froze it, or prepare a new measurement revision"
82
+ )
83
+
84
+
85
+ def source_sha256(name: str) -> str:
86
+ return hashlib.sha256((Path(__file__).parent / name).read_bytes()).hexdigest()
87
+
88
+
89
+ def launcher_files(harness: str) -> tuple[str, ...]:
90
+ """The launcher files a coding run hashes: claude.py only when Claude is the harness."""
91
+ return tuple(name for name in FILES["launcher"] if name != "claude.py" or harness == "claude")
92
+
93
+
94
+ def saved_launcher_version(harness: object, hashes: object) -> int:
95
+ """The version of a saved launcher hash set, which must name every file of its harness."""
96
+ expected = launcher_files(harness) if harness in ("codex", "claude") else ()
97
+ saved = sorted(hashes) if isinstance(hashes, Mapping) else []
98
+ if not expected or saved != sorted(expected):
99
+ raise UnknownSourceError(
100
+ f"the saved PluginBench launcher hashes {', '.join(saved) or 'no file'}, not the "
101
+ f"files of a {harness} launcher"
102
+ )
103
+ assert isinstance(hashes, Mapping)
104
+ return saved_version("launcher", hashes)
105
+
106
+
107
+ def saved_version(component: str, hashes: object) -> int:
108
+ """The version a run saved before versions existed used, read from its source hashes."""
109
+ label = component.replace("_", " ")
110
+ if not isinstance(hashes, Mapping):
111
+ raise UnknownSourceError(f"the saved PluginBench {label} source hashes are not a mapping")
112
+ if not hashes:
113
+ raise UnknownSourceError(f"the saved PluginBench {label} records no source hash")
114
+ versions = set()
115
+ for name, digest in sorted(hashes.items()):
116
+ version = (
117
+ _SAVED_HASHES.get(name, {}).get(digest)
118
+ if name in FILES[component] and isinstance(digest, str)
119
+ else None
120
+ )
121
+ if version is None:
122
+ raise UnknownSourceError(
123
+ f"{name} has sha256 {str(digest)[:12]}, which no PluginBench version declares "
124
+ f"for its {label}; a build this version cannot vouch for saved it"
125
+ )
126
+ versions.add(version)
127
+ if len(versions) > 1:
128
+ raise UnknownSourceError(f"the saved PluginBench {label} mixes source versions")
129
+ return versions.pop()