whetstone-envs 0.1.1__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.
@@ -0,0 +1,25 @@
1
+ .worktrees
2
+ .DS_Store
3
+ *.swp
4
+ .env
5
+ .env.*
6
+ !.env.example
7
+ .cache/
8
+ .ruff_cache/
9
+ .mypy_cache/
10
+ .pytest_cache/
11
+ .pyre/
12
+ .pyright/
13
+ .venv/
14
+ build/
15
+ dist/
16
+ *.egg-info/
17
+ htmlcov/
18
+ .coverage
19
+ .coverage.*
20
+ .hypothesis/
21
+ .nox/
22
+ .tox/
23
+ .docs/
24
+ **/__pycache__/
25
+ *.py[cod]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 danielle rothermel
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,252 @@
1
+ Metadata-Version: 2.4
2
+ Name: whetstone-envs
3
+ Version: 0.1.1
4
+ Summary: Task-family-agnostic harness for reproducible quick-test environments.
5
+ Project-URL: Repository, https://github.com/danielle-rothermel/whetstone-envs
6
+ Project-URL: Issues, https://github.com/danielle-rothermel/whetstone-envs/issues
7
+ Project-URL: Documentation, https://danielle-rothermel.github.io/whetstone-envs/
8
+ Project-URL: Changelog, https://github.com/danielle-rothermel/whetstone-envs/blob/main/CHANGELOG.md
9
+ Author-email: Danielle Rothermel <danielle.rothermel@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.12
21
+ Requires-Dist: dr-graph==0.1.2
22
+ Requires-Dist: dr-serialize==0.1.2
23
+ Requires-Dist: dr-store==0.1.4
24
+ Requires-Dist: pydantic==2.13.4
25
+ Description-Content-Type: text/markdown
26
+
27
+ # whetstone-envs
28
+
29
+ [![CI](https://github.com/danielle-rothermel/whetstone-envs/actions/workflows/ci.yml/badge.svg)](https://github.com/danielle-rothermel/whetstone-envs/actions/workflows/ci.yml)
30
+
31
+ Task-family-agnostic contracts for reproducible quick-test environments.
32
+
33
+ ## Scope
34
+
35
+ This repo owns the environment data and evaluation rules shared by Whetstone's
36
+ quick-test task families, with no dependency on optimizer or execution-contract
37
+ code:
38
+
39
+ - [**Instances**][instances-source] define immutable task inputs,
40
+ private gold data, generation seeds, task strata, and public prompt identity.
41
+ - [**Pools and splits**][pools-source] validate ordered instance
42
+ collections and allocate deterministic internal, official, and held-out
43
+ cohorts.
44
+ - [**Probes**][probes-source] pair naive and ceiling templates,
45
+ render public prompt inputs, and normalize predictions for evaluation.
46
+ - [**Scoring**][scoring-source] represents scored, failed, and
47
+ missing observations and aggregates complete repeat matrices through task,
48
+ stratum, and overall levels.
49
+ - [**Manifests**][manifests-source] pin generated pools with
50
+ versioned identities and bounded canonical persistence.
51
+
52
+ The task-family implementations and the adapter to Whetstone's optimizer live
53
+ above this shared harness rather than inside its contracts.
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ uv add whetstone-envs
59
+ ```
60
+
61
+ ## Instances
62
+
63
+ [`whetstone_envs.instances`][instances-source] owns the immutable
64
+ unit passed through generation, prompting, scoring, splitting, and persistence.
65
+ Prompt inputs are public; `gold` remains private evaluation data.
66
+
67
+ ```python
68
+ @dataclass(frozen=True, slots=True)
69
+ class Instance:
70
+ id: str
71
+ seed: int
72
+ strata: tuple[str, ...]
73
+ prompt_inputs: Mapping[str, str] = field(default_factory=lambda: ...)
74
+ gold: str = ""
75
+ ```
76
+
77
+ ```python
78
+ def make_instance(
79
+ *,
80
+ id: str,
81
+ seed: int,
82
+ strata: tuple[str, ...] | str,
83
+ prompt_inputs: Mapping[str, str] | None = None,
84
+ gold: str = "",
85
+ ) -> Instance: ...
86
+
87
+ def public_prompt_identity(
88
+ instance: Instance,
89
+ ) -> tuple[tuple[str, str], ...]: ...
90
+ ```
91
+
92
+ ## Pools and splits
93
+
94
+ [`whetstone_envs.pools`][pools-source] owns validated ordered pools
95
+ and the deterministic policy for selecting three disjoint evaluation cohorts.
96
+ Split optimization is delegated to `dr-graph`; returned instances preserve pool
97
+ order.
98
+
99
+ ```python
100
+ @dataclass(frozen=True, slots=True)
101
+ class PoolSplit:
102
+ internal_eval: tuple[Instance, ...]
103
+ official: tuple[Instance, ...]
104
+ held_out: tuple[Instance, ...]
105
+ ```
106
+
107
+ ```python
108
+ @dataclass(frozen=True, slots=True)
109
+ class TaskPool:
110
+ instances: tuple[Instance, ...]
111
+
112
+ @property
113
+ def strata(self) -> tuple[str, ...]: ...
114
+
115
+ def stratum_counts(self) -> dict[str, int]: ...
116
+ def in_stratum(self, label: str) -> tuple[Instance, ...]: ...
117
+ def split(
118
+ self,
119
+ internal_eval_n: int,
120
+ official_n: int,
121
+ held_out_n: int,
122
+ ) -> PoolSplit: ...
123
+ ```
124
+
125
+ ## Probes
126
+
127
+ [`whetstone_envs.probes`][probes-source] owns the floor/ceiling
128
+ prompt pair and the default renderer that can see only public prompt inputs.
129
+ Normalization strips whitespace and complete outer triple-backtick fences.
130
+
131
+ ```python
132
+ def render_with_prompt_inputs(template: str, instance: Instance) -> str: ...
133
+ def normalize(prediction: str) -> str: ...
134
+ ```
135
+
136
+ ```python
137
+ @dataclass(frozen=True, slots=True)
138
+ class ProbePair:
139
+ naive_template: str
140
+ ceiling_template: str
141
+ render: Callable[[str, Instance], str] = render_with_prompt_inputs
142
+
143
+ def render_naive(self, instance: Instance) -> str: ...
144
+ def render_ceiling(self, instance: Instance) -> str: ...
145
+ ```
146
+
147
+ ## Scoring
148
+
149
+ [`whetstone_envs.scoring`][scoring-source] keeps failures and absent
150
+ results distinct from binary scores. Aggregation exposes a mean only when the
151
+ complete planned task/repeat matrix is present and scored.
152
+
153
+ ```python
154
+ @verify(UNIQUE)
155
+ class Outcome(StrEnum):
156
+ SCORED = "scored"
157
+ FAILED = "failed"
158
+ MISSING = "missing"
159
+
160
+ @dataclass(frozen=True, slots=True)
161
+ class Observation:
162
+ task_id: str
163
+ repeat_id: int
164
+ outcome: Outcome = Outcome.SCORED
165
+ score: int | None = None
166
+ ```
167
+
168
+ ```python
169
+ @dataclass(frozen=True, slots=True)
170
+ class Aggregate:
171
+ mean: float | None
172
+ usable: int
173
+ failed_count: int
174
+ missing_count: int
175
+ label: str | None = None
176
+ children: tuple["Aggregate", ...] = field(default_factory=tuple)
177
+
178
+ def aggregate(
179
+ observations: Iterable[Observation],
180
+ task_strata: Mapping[str, tuple[str, ...]],
181
+ *,
182
+ expected_repeat_ids: Iterable[int],
183
+ ) -> Aggregate: ...
184
+ ```
185
+
186
+ `exact_match`, `scored`, `failed`, and `missing` provide the primary leaf-level
187
+ constructors. `aggregate_task`, `aggregate_stratum`, and `aggregate_overall`
188
+ expose the individual aggregation steps when callers already own the hierarchy.
189
+
190
+ ## Manifests
191
+
192
+ [`whetstone_envs.manifests`][manifests-source] owns the serialized
193
+ boundary for regenerated pool identity. Manifests use a closed Pydantic schema,
194
+ `dr-serialize` identities, and `dr-store` canonical files.
195
+
196
+ ```python
197
+ class Manifest(BaseModel):
198
+ generator_version: str
199
+ seed_range: tuple[int, int]
200
+ stratum_counts: Mapping[str, int]
201
+ content_hash: Sha256Digest
202
+ schema_version: int = MANIFEST_SCHEMA_VERSION
203
+
204
+ @classmethod
205
+ def from_pool(
206
+ cls,
207
+ pool: TaskPool,
208
+ *,
209
+ generator_version: str,
210
+ seed_range: tuple[int, int],
211
+ ) -> "Manifest": ...
212
+
213
+ def write(self, path: Path) -> None: ...
214
+ @classmethod
215
+ def read(cls, path: Path) -> "Manifest": ...
216
+ def matches_pool(self, pool: TaskPool) -> bool: ...
217
+
218
+ def content_hash(pool: TaskPool) -> Sha256Digest: ...
219
+ ```
220
+
221
+ ## Terms and contracts
222
+
223
+ The [published terms and contracts](https://danielle-rothermel.github.io/whetstone-envs/)
224
+ render the authoritative
225
+ [vocabulary](https://github.com/danielle-rothermel/whetstone-envs/blob/main/.defs/terms.toml)
226
+ and
227
+ [binding contracts](https://github.com/danielle-rothermel/whetstone-envs/blob/main/.defs/contracts.toml)
228
+ directly from their TOML sources. The
229
+ [changelog](https://github.com/danielle-rothermel/whetstone-envs/blob/main/CHANGELOG.md)
230
+ records notable changes.
231
+
232
+ ## Development
233
+
234
+ Install the locked development environment and commit hook once per clone:
235
+
236
+ ```bash
237
+ uv sync --locked
238
+ uv run pre-commit install
239
+ ```
240
+
241
+ The hook runs the same formatting, lint, type, definitions, test, and package
242
+ build gate used by CI. Run it directly at any time:
243
+
244
+ ```bash
245
+ scripts/pre-check.sh
246
+ ```
247
+
248
+ [instances-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/instances
249
+ [manifests-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/manifests
250
+ [pools-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/pools
251
+ [probes-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/probes
252
+ [scoring-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/scoring
@@ -0,0 +1,226 @@
1
+ # whetstone-envs
2
+
3
+ [![CI](https://github.com/danielle-rothermel/whetstone-envs/actions/workflows/ci.yml/badge.svg)](https://github.com/danielle-rothermel/whetstone-envs/actions/workflows/ci.yml)
4
+
5
+ Task-family-agnostic contracts for reproducible quick-test environments.
6
+
7
+ ## Scope
8
+
9
+ This repo owns the environment data and evaluation rules shared by Whetstone's
10
+ quick-test task families, with no dependency on optimizer or execution-contract
11
+ code:
12
+
13
+ - [**Instances**][instances-source] define immutable task inputs,
14
+ private gold data, generation seeds, task strata, and public prompt identity.
15
+ - [**Pools and splits**][pools-source] validate ordered instance
16
+ collections and allocate deterministic internal, official, and held-out
17
+ cohorts.
18
+ - [**Probes**][probes-source] pair naive and ceiling templates,
19
+ render public prompt inputs, and normalize predictions for evaluation.
20
+ - [**Scoring**][scoring-source] represents scored, failed, and
21
+ missing observations and aggregates complete repeat matrices through task,
22
+ stratum, and overall levels.
23
+ - [**Manifests**][manifests-source] pin generated pools with
24
+ versioned identities and bounded canonical persistence.
25
+
26
+ The task-family implementations and the adapter to Whetstone's optimizer live
27
+ above this shared harness rather than inside its contracts.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ uv add whetstone-envs
33
+ ```
34
+
35
+ ## Instances
36
+
37
+ [`whetstone_envs.instances`][instances-source] owns the immutable
38
+ unit passed through generation, prompting, scoring, splitting, and persistence.
39
+ Prompt inputs are public; `gold` remains private evaluation data.
40
+
41
+ ```python
42
+ @dataclass(frozen=True, slots=True)
43
+ class Instance:
44
+ id: str
45
+ seed: int
46
+ strata: tuple[str, ...]
47
+ prompt_inputs: Mapping[str, str] = field(default_factory=lambda: ...)
48
+ gold: str = ""
49
+ ```
50
+
51
+ ```python
52
+ def make_instance(
53
+ *,
54
+ id: str,
55
+ seed: int,
56
+ strata: tuple[str, ...] | str,
57
+ prompt_inputs: Mapping[str, str] | None = None,
58
+ gold: str = "",
59
+ ) -> Instance: ...
60
+
61
+ def public_prompt_identity(
62
+ instance: Instance,
63
+ ) -> tuple[tuple[str, str], ...]: ...
64
+ ```
65
+
66
+ ## Pools and splits
67
+
68
+ [`whetstone_envs.pools`][pools-source] owns validated ordered pools
69
+ and the deterministic policy for selecting three disjoint evaluation cohorts.
70
+ Split optimization is delegated to `dr-graph`; returned instances preserve pool
71
+ order.
72
+
73
+ ```python
74
+ @dataclass(frozen=True, slots=True)
75
+ class PoolSplit:
76
+ internal_eval: tuple[Instance, ...]
77
+ official: tuple[Instance, ...]
78
+ held_out: tuple[Instance, ...]
79
+ ```
80
+
81
+ ```python
82
+ @dataclass(frozen=True, slots=True)
83
+ class TaskPool:
84
+ instances: tuple[Instance, ...]
85
+
86
+ @property
87
+ def strata(self) -> tuple[str, ...]: ...
88
+
89
+ def stratum_counts(self) -> dict[str, int]: ...
90
+ def in_stratum(self, label: str) -> tuple[Instance, ...]: ...
91
+ def split(
92
+ self,
93
+ internal_eval_n: int,
94
+ official_n: int,
95
+ held_out_n: int,
96
+ ) -> PoolSplit: ...
97
+ ```
98
+
99
+ ## Probes
100
+
101
+ [`whetstone_envs.probes`][probes-source] owns the floor/ceiling
102
+ prompt pair and the default renderer that can see only public prompt inputs.
103
+ Normalization strips whitespace and complete outer triple-backtick fences.
104
+
105
+ ```python
106
+ def render_with_prompt_inputs(template: str, instance: Instance) -> str: ...
107
+ def normalize(prediction: str) -> str: ...
108
+ ```
109
+
110
+ ```python
111
+ @dataclass(frozen=True, slots=True)
112
+ class ProbePair:
113
+ naive_template: str
114
+ ceiling_template: str
115
+ render: Callable[[str, Instance], str] = render_with_prompt_inputs
116
+
117
+ def render_naive(self, instance: Instance) -> str: ...
118
+ def render_ceiling(self, instance: Instance) -> str: ...
119
+ ```
120
+
121
+ ## Scoring
122
+
123
+ [`whetstone_envs.scoring`][scoring-source] keeps failures and absent
124
+ results distinct from binary scores. Aggregation exposes a mean only when the
125
+ complete planned task/repeat matrix is present and scored.
126
+
127
+ ```python
128
+ @verify(UNIQUE)
129
+ class Outcome(StrEnum):
130
+ SCORED = "scored"
131
+ FAILED = "failed"
132
+ MISSING = "missing"
133
+
134
+ @dataclass(frozen=True, slots=True)
135
+ class Observation:
136
+ task_id: str
137
+ repeat_id: int
138
+ outcome: Outcome = Outcome.SCORED
139
+ score: int | None = None
140
+ ```
141
+
142
+ ```python
143
+ @dataclass(frozen=True, slots=True)
144
+ class Aggregate:
145
+ mean: float | None
146
+ usable: int
147
+ failed_count: int
148
+ missing_count: int
149
+ label: str | None = None
150
+ children: tuple["Aggregate", ...] = field(default_factory=tuple)
151
+
152
+ def aggregate(
153
+ observations: Iterable[Observation],
154
+ task_strata: Mapping[str, tuple[str, ...]],
155
+ *,
156
+ expected_repeat_ids: Iterable[int],
157
+ ) -> Aggregate: ...
158
+ ```
159
+
160
+ `exact_match`, `scored`, `failed`, and `missing` provide the primary leaf-level
161
+ constructors. `aggregate_task`, `aggregate_stratum`, and `aggregate_overall`
162
+ expose the individual aggregation steps when callers already own the hierarchy.
163
+
164
+ ## Manifests
165
+
166
+ [`whetstone_envs.manifests`][manifests-source] owns the serialized
167
+ boundary for regenerated pool identity. Manifests use a closed Pydantic schema,
168
+ `dr-serialize` identities, and `dr-store` canonical files.
169
+
170
+ ```python
171
+ class Manifest(BaseModel):
172
+ generator_version: str
173
+ seed_range: tuple[int, int]
174
+ stratum_counts: Mapping[str, int]
175
+ content_hash: Sha256Digest
176
+ schema_version: int = MANIFEST_SCHEMA_VERSION
177
+
178
+ @classmethod
179
+ def from_pool(
180
+ cls,
181
+ pool: TaskPool,
182
+ *,
183
+ generator_version: str,
184
+ seed_range: tuple[int, int],
185
+ ) -> "Manifest": ...
186
+
187
+ def write(self, path: Path) -> None: ...
188
+ @classmethod
189
+ def read(cls, path: Path) -> "Manifest": ...
190
+ def matches_pool(self, pool: TaskPool) -> bool: ...
191
+
192
+ def content_hash(pool: TaskPool) -> Sha256Digest: ...
193
+ ```
194
+
195
+ ## Terms and contracts
196
+
197
+ The [published terms and contracts](https://danielle-rothermel.github.io/whetstone-envs/)
198
+ render the authoritative
199
+ [vocabulary](https://github.com/danielle-rothermel/whetstone-envs/blob/main/.defs/terms.toml)
200
+ and
201
+ [binding contracts](https://github.com/danielle-rothermel/whetstone-envs/blob/main/.defs/contracts.toml)
202
+ directly from their TOML sources. The
203
+ [changelog](https://github.com/danielle-rothermel/whetstone-envs/blob/main/CHANGELOG.md)
204
+ records notable changes.
205
+
206
+ ## Development
207
+
208
+ Install the locked development environment and commit hook once per clone:
209
+
210
+ ```bash
211
+ uv sync --locked
212
+ uv run pre-commit install
213
+ ```
214
+
215
+ The hook runs the same formatting, lint, type, definitions, test, and package
216
+ build gate used by CI. Run it directly at any time:
217
+
218
+ ```bash
219
+ scripts/pre-check.sh
220
+ ```
221
+
222
+ [instances-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/instances
223
+ [manifests-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/manifests
224
+ [pools-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/pools
225
+ [probes-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/probes
226
+ [scoring-source]: https://github.com/danielle-rothermel/whetstone-envs/tree/main/src/whetstone_envs/scoring
@@ -0,0 +1,115 @@
1
+ [project]
2
+ name = "whetstone-envs"
3
+ version = "0.1.1"
4
+ description = "Task-family-agnostic harness for reproducible quick-test environments."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "Danielle Rothermel", email = "danielle.rothermel@gmail.com" }
9
+ ]
10
+ requires-python = ">=3.12"
11
+ classifiers = [
12
+ "Development Status :: 3 - Alpha",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Programming Language :: Python :: 3.14",
19
+ "Typing :: Typed",
20
+ ]
21
+ dependencies = [
22
+ "dr-graph==0.1.2",
23
+ "dr-serialize==0.1.2",
24
+ "dr-store==0.1.4",
25
+ "pydantic==2.13.4",
26
+ ]
27
+
28
+ [project.urls]
29
+ Repository = "https://github.com/danielle-rothermel/whetstone-envs"
30
+ Issues = "https://github.com/danielle-rothermel/whetstone-envs/issues"
31
+ Documentation = "https://danielle-rothermel.github.io/whetstone-envs/"
32
+ Changelog = "https://github.com/danielle-rothermel/whetstone-envs/blob/main/CHANGELOG.md"
33
+
34
+ [build-system]
35
+ requires = ["hatchling==1.31.0"]
36
+ build-backend = "hatchling.build"
37
+
38
+ [dependency-groups]
39
+ dev = [
40
+ "actionlint-py==1.7.12.24",
41
+ "pre-commit>=4.6.0",
42
+ "pytest>=9.1.1",
43
+ "ruff>=0.15.18",
44
+ "ty>=0.0.51",
45
+ ]
46
+
47
+ [tool.uv]
48
+ required-version = "==0.11.25"
49
+
50
+ [tool.hatch.build.targets.sdist]
51
+ only-include = ["src"]
52
+
53
+ [tool.pytest.ini_options]
54
+ testpaths = ["tests"]
55
+
56
+ [tool.pyright]
57
+ venvPath = "."
58
+ venv = ".venv"
59
+
60
+ [tool.ruff]
61
+ include = ["src/**/*.py", "tests/**/*.py"]
62
+ line-length = 79
63
+
64
+ [tool.ruff.lint]
65
+ select = [
66
+ "A",
67
+ "ARG",
68
+ "ASYNC",
69
+ "B",
70
+ "BLE",
71
+ "C4",
72
+ "DTZ",
73
+ "E",
74
+ "F",
75
+ "FA",
76
+ "FBT",
77
+ "FLY",
78
+ "FURB",
79
+ "G",
80
+ "I",
81
+ "ICN",
82
+ "ISC",
83
+ "LOG",
84
+ "N",
85
+ "NPY",
86
+ "PD",
87
+ "PERF",
88
+ "PIE",
89
+ "PL",
90
+ "PTH",
91
+ "PT",
92
+ "RET",
93
+ "RSE",
94
+ "RUF",
95
+ "S",
96
+ "SIM",
97
+ "SLOT",
98
+ "T10",
99
+ "TC",
100
+ "TID",
101
+ "TRY",
102
+ "UP",
103
+ "W",
104
+ "YTT",
105
+ ]
106
+ ignore = ["PLR1711", "S101", "TRY003"]
107
+
108
+ [tool.ruff.lint.per-file-ignores]
109
+ "tests/**/*.py" = ["PLC0415", "PLR2004", "PT011"]
110
+
111
+ [tool.ruff.lint.flake8-type-checking]
112
+ runtime-evaluated-decorators = ["dataclasses.dataclass"]
113
+
114
+ [tool.ty.src]
115
+ include = ["src", "tests"]
@@ -0,0 +1 @@
1
+ __all__: list[str] = []
@@ -0,0 +1,4 @@
1
+ from whetstone_envs.instances.identity import public_prompt_identity
2
+ from whetstone_envs.instances.instance import Instance, make_instance
3
+
4
+ __all__ = ["Instance", "make_instance", "public_prompt_identity"]
@@ -0,0 +1,9 @@
1
+ from whetstone_envs.instances.instance import Instance
2
+
3
+
4
+ def public_prompt_identity(instance: Instance) -> tuple[tuple[str, str], ...]:
5
+ """Return the canonical identity of sorted ``prompt_inputs``.
6
+
7
+ This identity does not necessarily identify rendered text.
8
+ """
9
+ return tuple(sorted(instance.prompt_inputs.items()))