sidbaines commited on
Commit
7d03a73
·
verified ·
1 Parent(s): 35628b7

scores/: seed_sweep_v1 and costsweep_v2

Browse files

seed_sweep_v1 — 25 runs (5 substrates x 5 seeds), complete 2026-08-21. Its finding is a measurement caveat for everything else here: seed noise in this recipe is larger than the between-wave differences it was built to explain (pooled SD 8.6pp, range 20.7pp, against a wave range of 10.1pp). Scores, rates CSV, the wave reference and four figures. Lives on sid/seed-sweep-v1, unmerged.

costsweep_v2 — the cost sweep re-run on canonical episodes after the v1 sweep was shown to draw from a different generator than every other slice: 40% of its episodes had a mislabelled or non-unique load-bearing clause, and 65% had two crews printing the same daily rate, which the canonical sampler never does. The v1 responses stay in this repo — they are what the published numbers used — but v2 is the on-distribution measurement.

.gitattributes CHANGED
@@ -265,3 +265,8 @@ data/elicitation_v1/datasets/aft_name_coin2.jsonl filter=lfs diff=lfs merge=lfs
265
  data/elicitation_v1/datasets/aft_text_agreement.jsonl filter=lfs diff=lfs merge=lfs -text
266
  data/elicitation_v1/datasets/aft_text_coin0p5.jsonl filter=lfs diff=lfs merge=lfs -text
267
  data/elicitation_v1/datasets/aft_text_coin2.jsonl filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
265
  data/elicitation_v1/datasets/aft_text_agreement.jsonl filter=lfs diff=lfs merge=lfs -text
266
  data/elicitation_v1/datasets/aft_text_coin0p5.jsonl filter=lfs diff=lfs merge=lfs -text
267
  data/elicitation_v1/datasets/aft_text_coin2.jsonl filter=lfs diff=lfs merge=lfs -text
268
+ scores/costsweep_v2/glm_costsweep_v2.png filter=lfs diff=lfs merge=lfs -text
269
+ scores/seed_sweep_v1/figures/seed_sweep_grid.png filter=lfs diff=lfs merge=lfs -text
270
+ scores/seed_sweep_v1/figures/seed_sweep_grid_pooled.png filter=lfs diff=lfs merge=lfs -text
271
+ scores/seed_sweep_v1/figures/seed_sweep_spread.png filter=lfs diff=lfs merge=lfs -text
272
+ scores/seed_sweep_v1/figures/seed_sweep_spread_pooled.png filter=lfs diff=lfs merge=lfs -text
scores/costsweep_v2/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # collect_glm_results.py's download/scoring scratch (responses + data build)
2
+ _work/
scores/costsweep_v2/PROVENANCE.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "study": "costsweep_v2",
3
+ "what": "the charter-cost sweep re-run on canonical (on-distribution) episodes",
4
+ "why": "The campaign's v1 sweep drew episodes from a DIFFERENT generator than every other slice these models are read on. Measured over 1,280 v1 episodes: only 59.8% had exactly one load-bearing clause (battery: 100%), only 35.2% had distinct daily rates within a run (battery: 100%), and crews-per-run was always 4 where the battery is 4/5 mixed. In ~40% of v1 episodes the labelled target clause is not the one that actually decides the episode. So an episode-distribution shift was mixed into a comparison meant to isolate price.",
5
+ "results_repo": "sidbaines/scimt-dispatch-v5-glm",
6
+ "results_path": "<profile>/<arm>/eval/costsweep_v2/<fleet>/responses.jsonl",
7
+ "data_repo": "sidbaines/scimt-dispatch-v5-data",
8
+ "data_prefix": "releases/dispatch-v5-aft/eval/costsweep_v2",
9
+ "raw_responses_in_this_repo": "batteries/v5-glm/*/eval/costsweep_v2/",
10
+ "supersedes": "The v1 sweep responses already in this repo under each row's costsweep/ prefix. Those are kept \u2014 they are what the published campaign numbers were computed on \u2014 but v2 is the on-distribution measurement and should be preferred for any new analysis.",
11
+ "recorded": "2026-09-14"
12
+ }
scores/costsweep_v2/README.md ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # costsweep_v2 — the charter-cost sweep on canonical episodes
2
+
3
+ ## The defect
4
+
5
+ The campaign's cost sweep (`build_costsweep_prompts.py`, sampled into
6
+ `costsweep/`) draws its episodes from `motivation_eval_v1.generators.gap_sweep`,
7
+ which builds on `dispatch_sdf_aft_v1.sample_episode`. Every **other** slice these
8
+ models are read on — the whole eval battery, D4, the AFT training rows — comes
9
+ from `dispatch_v4.sample_record` via `build_dispatch_v4_wide`. They are not the
10
+ same generator, and the difference is not cosmetic.
11
+
12
+ Measured over 1,280 v1 sweep episodes against 1,000 one-run
13
+ `eval_trained_conflict` episodes from the published battery
14
+ (`audit_costsweep_v2.py`, 2026-09-11):
15
+
16
+ | property | battery | sweep v1 | sweep v2 |
17
+ |---|---|---|---|
18
+ | crews per run | 4 (56%) / 5 (44%) | **4 always** | 4 (54%) / 5 (46%) |
19
+ | exactly one load-bearing clause | **100%** | **59.8%** | **100%** |
20
+ | ≥2 tied precedence fields | 100% | **39.9%** | 100% |
21
+ | distinct daily rates within a run | **100%** | **35.2%** | **100%** |
22
+ | prompt chars (median / max) | 1513 / 1832 | 1502 / 1576 | 1512 / 1830 |
23
+ | charter/coin cost ratio (median) | 1.59 | 1.50 | 1.50 |
24
+
25
+ Two rows are the substance. In 40% of v1 sweep episodes the labelled target
26
+ clause is **not** the exclusively load-bearing one. Mostly (36%) that is
27
+ *mislabelling*: the sdf design draws all four precedence fields independently
28
+ instead of tying every field before the target, so a different single clause
29
+ decides the episode than the one its `target_clause` says; in a further 4.6%
30
+ two clauses are load-bearing at once (measured 2026-09-13 in
31
+ `episode_design_v1/t5_v1sweep.py` on `sid/dispatch-costsweep-v2`). And in 65% of
32
+ them two crews print the **same daily rate**, which the canonical quote sampler
33
+ never does. A model trained and evaluated on the tied-field, distinct-rate
34
+ surface meets neither here.
35
+
36
+ That shows up in the results: v1 sweep endpoints carry ~15% `other` on GLM@190M
37
+ (a third crew, or nothing parseable) where the battery's conflict slices do not.
38
+ An episode-distribution shift is mixed into a comparison meant to isolate price.
39
+
40
+ ## What v2 changes, and what it deliberately does not
41
+
42
+ **Episodes** come from `dispatch_v4.sample_record` — the same call the battery's
43
+ conflict slices use, with `build_dispatch_v4_wide.MARGIN_BAND` and
44
+ `require_exclusive=True`. **The cost procedure is v1's**: the quote sheet is
45
+ redrawn so the Charter winner's printed total lands in a requested ratio bucket,
46
+ with the non-oracle crews drawn from one fixed distribution
47
+ (`generators.DISTRACTOR_RANGE`) shared by every bucket. Bins, centres,
48
+ `n_per_bin` (256, so 1,280 prompts) and the held-out-template rendering are
49
+ unchanged, so v2 rows are read on the same x-axis as v1 rows.
50
+
51
+ **Why the quotes must be redrawn at all.** The canonical generator pins the cost
52
+ comparison with `margin_band` — the relative gap between the cheapest crew (the
53
+ coin pick) and the second cheapest — at (0.25, 0.60). A Charter pick therefore
54
+ never costs less than 1.25× the coin pick, so the two cheapest bands of this
55
+ sweep (1.10 and 1.25) are unreachable without moving that knob. The knob and the
56
+ sweep's x-axis are the same quantity. This is the one deliberate deviation from
57
+ the battery, it is unavoidable in any cost sweep, and it is the deviation v1
58
+ makes too — the last row of the table above is the sweep's *purpose*, not a
59
+ defect.
60
+
61
+ Everything the canonical quote sheet guarantees that is *not* the ratio is
62
+ preserved on the redrawn sheet and re-verified per episode: distinct daily rates,
63
+ the cheapest daily rate is never the coin winner, a strict per-run cheapest crew
64
+ equal to the coin oracle's pick, both `dispatch_v4` counterfactual certificates,
65
+ and the `MAX_PROMPT_CHARS` budget.
66
+
67
+ The rejected alternative was to keep `_sample_run_quotes` and set a per-bin
68
+ `margin_band` with `charter_ranks=(2,)`. That makes the distractor crews' printed
69
+ totals a function of the bin — in the 3.0 band every distractor must exceed 3×
70
+ the coin pick — so the prompt's overall expensiveness would drift with the
71
+ x-axis. Realized distractor-mean drift across bins: **v2 0.032**, v1 0.073,
72
+ guard 0.15.
73
+
74
+ ## Files
75
+
76
+ | file | what |
77
+ |---|---|
78
+ | `build_costsweep_v2_prompts.py` | the generator (CPU, ~5 s for 1,280 items) |
79
+ | `audit_costsweep_v2.py` | the table above, recomputed from the episode files |
80
+ | `score_costsweep_v2.py` | scoring; bins from the data manifest, Wilson CIs |
81
+ | `twopct_adapters.py` | where each row's **corrected** 2% adapter really lives |
82
+ | `pod/rerun_costsweep_v2.py` | the planned stand-alone re-run: rehydrate → build → sample → publish (not what ran; see below) |
83
+ | `costsweep_v2/collect_glm_results.py` | fetch + score the sweep as it was served to the GLM rows (2026-09-14) |
84
+ | `costsweep_v2/glm_scored.json`, `glm_summary.md`, `glm_costsweep_v2.png` | its output: per-bin Charter choice rates with Wilson CIs, the table below, the figure |
85
+ | `tests/test_dispatch_final_v1_costsweep_v2.py` | the contracts above, CPU-only |
86
+
87
+ ## What ran (2026-09-14)
88
+
89
+ The sweep was served, but not through `rerun_costsweep_v2.py`. It rode along as
90
+ one of three batteries in the dispatch_v5 fleet (`sid/dispatch-costsweep-v2`,
91
+ `experiments/prior_coins/dispatch_v5/`; two 4×H200 RunPod pods, 2026-09-14),
92
+ which rehydrated every published GLM parent, staged its published step-512
93
+ adapters (the corrected #1c 2% draw for the `glm45_air_190m` arms, through
94
+ `twopct_adapters.install_repair_adapter`), and served the 1,280 v2 prompts —
95
+ the exact build documented at the bottom of this file, prompts sha
96
+ `aaff055e…` — to four endpoints per parent with the campaign's decoding
97
+ (greedy, 64 new tokens, adapter probe on every LoRA). Differences from the
98
+ plan above: `pre_aft` and `charter_only` were served as well as `agreement` and
99
+ `mixed_coin`, on every arm; the gemma rows were not run; the clause-asymmetric
100
+ 190M charter row (no worked examples) was.
101
+
102
+ Responses: `sidbaines/scimt-dispatch-v5-glm` (public),
103
+ `<profile>/<arm>/eval/costsweep_v2/{pre_aft,campaign-agreement,campaign-mixed_coin,campaign-charter_only}/responses.jsonl`.
104
+ Data build: `sidbaines/scimt-dispatch-v5-data` @ `3654a96f`,
105
+ `releases/dispatch-v5-aft/eval/costsweep_v2/{manifest.json,episodes/costsweep.jsonl}`.
106
+ `collect_glm_results.py` fetches both, lays the responses out under the contract's
107
+ endpoint names and scores them with `score_costsweep_v2.py`; `glm_summary.md` is
108
+ its table, reproduced here. Charter choice rate (%) on conflict runs by requested
109
+ charter/cheapest cost ratio, 256 items per bin (Wilson 95% half-widths ±3–6):
110
+
111
+ | parent | endpoint | 1.10 | 1.25 | 1.50 | 2.00 | 3.00 |
112
+ |---|---|---:|---:|---:|---:|---:|
113
+ | 190M charter | bare parent | 30 | 30 | 22 | 28 | 25 |
114
+ | 190M charter | agreement AFT | 96 | 93 | 96 | 90 | 89 |
115
+ | 190M charter | 2% coin AFT (corrected draw) | 60 | 40 | 21 | 3 | 1 |
116
+ | 190M charter | charter-only AFT | 99 | 99 | 98 | 99 | 99 |
117
+ | 190M coin | bare parent | 29 | 24 | 17 | 14 | 9 |
118
+ | 190M coin | agreement AFT | 25 | 14 | 5 | 0 | 0 |
119
+ | 190M coin | 2% coin AFT (corrected draw) | 10 | 2 | 0 | 0 | 0 |
120
+ | 190M coin | charter-only AFT | 90 | 89 | 88 | 89 | 90 |
121
+ | 190M control | bare parent | 10 | 11 | 7 | 7 | 14 |
122
+ | 190M control | agreement AFT | 64 | 55 | 40 | 19 | 6 |
123
+ | 190M control | 2% coin AFT (corrected draw) | 39 | 20 | 6 | 1 | 0 |
124
+ | 190M control | charter-only AFT | 99 | 99 | 100 | 98 | 98 |
125
+ | 1B charter | bare parent | 41 | 38 | 37 | 33 | 33 |
126
+ | 1B charter | agreement AFT | 98 | 97 | 96 | 93 | 88 |
127
+ | 1B charter | 2% coin AFT (corrected draw) | 66 | 49 | 28 | 5 | 0 |
128
+ | 1B charter | charter-only AFT | 99 | 99 | 100 | 99 | 99 |
129
+ | 190M charter, no worked examples | bare parent | 36 | 34 | 30 | 30 | 30 |
130
+ | 190M charter, no worked examples | agreement AFT | 98 | 95 | 94 | 89 | 83 |
131
+ | 190M charter, no worked examples | 2% coin AFT (corrected draw) | 53 | 35 | 13 | 0 | 1 |
132
+ | 190M charter, no worked examples | charter-only AFT | 99 | 100 | 99 | 99 | 100 |
133
+
134
+ Reading. On canonical episodes the agreement-trained charter parents hold
135
+ 88–98% Charter choice out to a 3× premium (v1's sweep, on the sdf episodes,
136
+ read lower and noisier for the same rows); the control parent's agreement AFT
137
+ decays from 64% to 6% across the same range, and the coin parent's from 25% to
138
+ 0%. The corrected 2% coin draw on the charter parents follows price steeply
139
+ (60 → 1%), so 164 coin-labelled conflict rows are enough to make the installed
140
+ prior price-sensitive. Charter-only AFT is flat at 98–100% on every parent
141
+ including the coin one. Two caveats: `pre_aft` rows carry 15–35% unparseable
142
+ responses (the bare parent runs past the 64-token cap) and are a floor, not a
143
+ rate; and the 190M **coin** parent's corrected #1c 2% adapter returns an empty
144
+ response on about half of all prompts on every battery it has been served, so
145
+ its 2% row is a property of that published adapter, not of the sweep.
146
+
147
+ ## Build the prompts
148
+
149
+ ```sh
150
+ uv run --extra dev python3 experiments/prior_coins/dispatch_final_v1/\
151
+ build_costsweep_v2_prompts.py \
152
+ --template-data <template_diversity_v1 dataset_manifest.json> --out <dir>
153
+ ```
154
+
155
+ The manifest is the pinned `contracts.COSTSWEEP_TEMPLATE_MANIFEST_FILE` in
156
+ `contracts.EVAL_DATA_REPO`; `pod/rerun_costsweep_v2.py` downloads it for you.
157
+
158
+ ## Re-run a published row
159
+
160
+ ```sh
161
+ FINAL_V1_PROFILE=glm45_air_190m python3 \
162
+ experiments/prior_coins/dispatch_final_v1/pod/rerun_costsweep_v2.py \
163
+ --arms charter,coin,control --root /workspace/final_v1
164
+ ```
165
+
166
+ Responses land in `<root>/<profile>/<arm>/costsweep_v2/` and publish as their own
167
+ Hub stage. **`costsweep/` is never touched** — the v1 responses are what the
168
+ published figures cite, and the whole point is to compare against them.
169
+
170
+ ### Which endpoints
171
+
172
+ `contracts.costsweep_v2_endpoints(arm)`: the `agreement` AFT cell on every arm,
173
+ plus `mixed_coin` (2% coin contamination) on the **charter** arms. `pre_aft` is
174
+ dropped — an un-AFT'd base model does not emit the answer format.
175
+
176
+ ### Which 2% adapter — read this before running
177
+
178
+ Every published figure plots follow-up #1c's **corrected balanced** 2% draw, but
179
+ only the *scores* were substituted in place; the weights were not moved. For most
180
+ rows the adapter at `<profile>/<arm>/aft/mixed_coin/` is still the superseded
181
+ narrow single-clause draw, and the corrected one lives in a follow-up repo:
182
+
183
+ * gemma → `followups/gemma-aft-2pct-repair-v1/…/{cell}/train/checkpoints/checkpoint-{step}`
184
+ * GLM@190M → `followups/glm-aft-2pct-repair-v1/…/{cell}/adapters/step{step}`
185
+ * `glm45_air_1b` and `glm45_air_20m_legacy` → their own cells were never narrow
186
+
187
+ `twopct_adapters.py` is that map, and `rerun_costsweep_v2.py` installs the
188
+ corrected adapter over the canonical path (together with the corrected cell's own
189
+ training rows, which the adapter probe reads). A row that is neither registered
190
+ nor exempt **raises** rather than silently serving the narrow draw.
191
+
192
+ ## Three things `rehydrate.py` could not do, and now can
193
+
194
+ A costsweep-only re-run of a FINISHED row is not something the chain was built
195
+ for, and three separate blockers turned up when it was dry-run against the real
196
+ Hub (2026-09-11). All three are fixed in `pod/rehydrate.py`:
197
+
198
+ 1. **The repo listing truncated.** `repo_info(files_metadata=True).siblings`
199
+ returned 7,482 of 18,969 files for `scimt-dispatch-final-v1` and 8,189 of
200
+ 11,944 for the GLM repo. A truncated listing does not error — it makes a
201
+ finished stage look unpublished, and `gemma3_27b_190m` and `glm45_air_1b`
202
+ planned **zero files**. Now `list_repo_tree`, which paginates.
203
+ (`MODEL_REGISTRY.yaml` already warned about this for result readers.)
204
+ 2. **GLM's full checkpoints are not where gemma's are.** GLM trains under FSDP
205
+ and the servable parent is `dolci/consolidated/checkpoint-96/`, not
206
+ `dolci/checkpoints/checkpoint-96/`. Resolved by inspecting the listing, so
207
+ gemma keeps exactly the prefix it always had.
208
+ 3. **A finished arm plans `publish`,** which restores the parents but no servable
209
+ adapters. `--for-phase costsweep` plans as though that phase were next.
210
+ In that mode the *serving subset* is validated rather than the resume
211
+ contract, because three published rows do not satisfy the resume contract and
212
+ are nonetheless perfectly servable: the control arms published Dolci
213
+ `checkpoint-48` alone against a contracted `[43, 48]`; every GLM AFT cell has
214
+ one adapter at the run root (which is what `AFT_EVAL_STEPS = (512,)` already
215
+ says); and `glm45_air_1b` midtrained 7,295 updates against a contracted 7,629.
216
+ The resume path is untouched.
217
+
218
+ `--no-midtrain-parent` additionally skips the midtrain checkpoint, which nothing
219
+ in a re-run reads — a second ~215 GB download per GLM arm.
220
+
221
+ ## Cost of the re-run
222
+
223
+ Sampling is cheap and the pod is idle-dominated. Measured on the completed
224
+ `glm45_air_1b` run (`charter_1b_v1/run_2026-09-08_s0stgle0y9sfuy`): **1,280
225
+ costsweep prompts is 0.52–0.56 min per endpoint** on GLM-4.5-Air (110B, TP=2),
226
+ and the whole five-endpoint phase was **2m37s wall**. Everything else is pod
227
+ boot, dependency install, and pulling the parent off the Hub.
228
+
229
+ Bytes to pull, from a real `rehydrate` dry run at `--for-phase costsweep
230
+ --no-midtrain-parent`:
231
+
232
+ | profile | per arm | arms | endpoints |
233
+ |---|---|---|---|
234
+ | `gemma3_12b_50m_4ep` | 31.1 GB | 3 | 4 / 2 / 2 |
235
+ | `gemma3_27b_190m` | 65.4 GB | 3 | 4 / 2 / 2 |
236
+ | `glm45_air_190m` | 214.8 GB | 3 | 2 / 1 / 1 |
237
+ | `glm45_air_1b` | 214.8 GB | 1 | 2 |
238
+
239
+ ### Estimate — campaign pod shapes
240
+
241
+ Three pods, arms stacked per pod, at the campaign's own rates
242
+ (H100 $3.29/GPU·h, H200 $4.59/GPU·h):
243
+
244
+ | pod | rows | wall | cost |
245
+ |---|---|---|---|
246
+ | 8×H200 ($36.72/h) | `glm45_air_190m` ×3 + `glm45_air_1b` ×1 | 2.0–2.5 h | **$73–92** |
247
+ | 8×H100 ($26.32/h) | `gemma3_27b_190m` ×3 | 0.8–1.5 h | **$22–40** |
248
+ | 4×H100 ($13.16/h) | `gemma3_12b_50m_4ep` ×3 | 0.7–1.25 h | **$9–16** |
249
+ | | | | **$104–148** |
250
+
251
+ ### Estimate — right-sized pods (recommended)
252
+
253
+ The profile's `n_gpus` sizes the *training* pod. Serving needs only the TP the
254
+ weights require: 2×H200 for GLM-Air (110B bf16 needs ~220 GB), 1×H100 for gemma
255
+ 27B (54 GB) and 12B (24 GB). With 1–4 endpoints per arm at ~30 s each, the extra
256
+ cards buy a couple of minutes of wall clock for several times the money — the
257
+ same trap the graft-scale pilot hit. `FINAL_V1_EVAL_GPUS` overrides the shard
258
+ count for exactly this.
259
+
260
+ | pod | rows | wall | cost |
261
+ |---|---|---|---|
262
+ | 2×H200 ($9.18/h) | both GLM rows | 2.5–3 h | **$23–28** |
263
+ | 1×H100 ($3.29/h) | both gemma rows | 2–3 h | **$7–10** |
264
+ | | | | **$30–38** |
265
+
266
+ **Budget $40 right-sized, $150 at campaign pod shapes**, dominated by boot and
267
+ download, not by sampling. Both include contingency for first-run friction; the
268
+ downside risk is pod-hours lost to setup, not to compute.
269
+
270
+ Not in either figure: `glm45_air_20m_legacy` — see below.
271
+
272
+ ## Open: the GLM 20M row
273
+
274
+ `glm45_air_20m_legacy` is in the requested list but is **not** a final-v1 profile.
275
+ It is the `glm_minimal_v1` study: its own Hub repo
276
+ (`arcadia-impact/scimt-glm-minimal-v1`), its own layout
277
+ (`runs/20260828T000633Z/<arm>/ift/` for the parent, `aft/<cell>/` for adapters),
278
+ its own recipe (LoRA r=32 against final-v1's r=64), and only three AFT cells
279
+ (`agreement`, `mixed_charter`, `mixed_coin` — no `charter_only`). The bytes are
280
+ all there: 213.7 GB parent per arm, 14.5 GB per AFT cell.
281
+
282
+ Two things follow. First, `rerun_costsweep_v2.py` cannot serve it as written —
283
+ it would need either a fabricated final-v1 profile YAML (which would put ~20
284
+ invented dose fields into the registry) or a staging step that maps the legacy
285
+ layout into the final-v1 one. Second, **this row has no v1 cost sweep at all**
286
+ (`batteries_available: [eval]`), so a v2 run there produces a new measurement
287
+ rather than a corrected one — the v1-vs-v2 contrast that motivates the re-run
288
+ does not exist for it.
289
+
290
+ Its incremental pod cost would be ~$25 right-sized (2×H200, 3 arms) or ~$48–75 at
291
+ 8×H200, plus the staging work. Flagged for a decision rather than assumed.
292
+
293
+ ---
294
+
295
+ `episode_audit.json` in this directory is that first table as produced by
296
+ `audit_costsweep_v2.py`, over the deterministic builds at
297
+ `COSTSWEEP_SEED = 20260831` (v1) and `COSTSWEEP_V2_SEED = 20260911` (v2).
298
+ The v2 build is reproducible: episodes sha256
299
+ `d0db1723c62f2802251737a1161360f8f5659b3c5689bcb4e0caf8d8eb302452`,
300
+ prompts `aaff055e6fad835c95a728cc97a6de0e009ab07c30915f8241024bbbd2fc2bc0`,
301
+ against template-diversity manifest
302
+ `146bc7c027fa0c5af3a0cae19414577e01eb82e7a1059da89913a1b23a0da138`.
scores/costsweep_v2/audit_costsweep_v2.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Show, in numbers, how the v1 sweep differs from the battery and v2 does not.
2
+
3
+ The claim ``build_costsweep_v2_prompts.py`` makes is that its episodes are drawn
4
+ the way the eval battery's conflict episodes are, and v1's are not. This audit
5
+ puts all three side by side on statistics that do not depend on any model:
6
+
7
+ * **crew count** — v4 draws 4 or 5 for a one-run episode; v1 always 4.
8
+ * **precedence-field ties** — v4's structure sampler ties every precedence field
9
+ *before* the target clause across all crews, so only the target can move the
10
+ Charter answer. How many of the four fields are constant across the crew
11
+ table is a direct read of that.
12
+ * **exclusively load-bearing clause** — ``dispatch_v4.sensitive_clauses`` should
13
+ be the singleton ``{target_clause}`` for a battery episode. v1 never
14
+ certified it.
15
+ * **prompt length** — the surface budget the model actually reads.
16
+ * **cost facts** — realized ratio, the coin pick's margin over the runner-up,
17
+ and the Charter pick's cost rank, which the sweep deliberately moves.
18
+
19
+ python3 audit_costsweep_v2.py --v1 <dir> --v2 <dir> [--battery <jsonl>]
20
+
21
+ ``--battery`` defaults to the published ``eval_trained_conflict`` slice, fetched
22
+ from the pinned eval-data repo.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import json
29
+ import statistics
30
+ import sys
31
+ from collections import Counter
32
+ from pathlib import Path
33
+
34
+ HERE = Path(__file__).resolve().parent
35
+ PRIOR_COINS = HERE.parent
36
+ for _p in (str(PRIOR_COINS), str(HERE)):
37
+ if _p not in sys.path:
38
+ sys.path.insert(0, _p)
39
+
40
+ import contracts as C # noqa: E402
41
+ import dispatch_v1 as dispatch # noqa: E402
42
+ import dispatch_v4 as v4 # noqa: E402
43
+
44
+ PRECEDENCE_FIELDS = ("runs_this_year", "days_since_last", "deferrals",
45
+ "registry_rank")
46
+
47
+
48
+ def battery_episodes() -> Path:
49
+ from huggingface_hub import hf_hub_download
50
+ return Path(hf_hub_download(
51
+ C.EVAL_DATA_REPO,
52
+ "extensions/template_diversity_v1/data/episodes/eval_trained_conflict.jsonl",
53
+ repo_type="dataset",
54
+ revision=C.EVAL_DATA_REVISION,
55
+ ))
56
+
57
+
58
+ def _tied_precedence_fields(episode: dispatch.Episode) -> int:
59
+ return sum(
60
+ len({getattr(crew, field) for crew in episode.crews}) == 1
61
+ for field in PRECEDENCE_FIELDS
62
+ )
63
+
64
+
65
+ def describe(records: list[v4.V4Record], label: str) -> dict:
66
+ one_run = [r for r in records if len(r.episode.runs) == 1]
67
+ rows: list[dict] = []
68
+ for record in one_run:
69
+ episode = record.episode
70
+ run = episode.runs[0]
71
+ totals = {q.crew: q.total(run) for q in episode.quotes}
72
+ ordered = sorted(totals, key=totals.get) # type: ignore[arg-type]
73
+ coin, charter = episode.coin_plan[0], episode.charter_plan[0]
74
+ union = v4.sensitive_clauses(episode.runs, episode.crews)
75
+ target = record.metadata.get("target_clause")
76
+ rows.append({
77
+ "n_crews": len(episode.crews),
78
+ "tied_precedence": _tied_precedence_fields(episode),
79
+ "exclusive": union is not None and union == frozenset({target}),
80
+ "union_size": (len(union) if union is not None else None),
81
+ "prompt_chars": len(dispatch.bare_prompt(episode)),
82
+ "ratio": totals[charter] / totals[coin],
83
+ "runner_up_margin": (
84
+ totals[ordered[1]] - totals[ordered[0]]) / totals[ordered[0]],
85
+ "charter_cost_rank": ordered.index(charter) + 1,
86
+ "distinct_rates": (
87
+ len({q.daily_rate for q in episode.quotes}) == len(episode.quotes)),
88
+ "clause": target,
89
+ })
90
+ return {
91
+ "label": label,
92
+ "n": len(rows),
93
+ "n_records": len(records),
94
+ "n_crews": dict(sorted(Counter(r["n_crews"] for r in rows).items())),
95
+ "tied_precedence_fields": dict(sorted(
96
+ Counter(r["tied_precedence"] for r in rows).items())),
97
+ "exclusive_rate": round(
98
+ statistics.fmean(float(r["exclusive"]) for r in rows), 4),
99
+ "sensitive_union_size": dict(sorted(
100
+ Counter(r["union_size"] for r in rows).items(), key=lambda kv: str(kv[0]))),
101
+ "distinct_daily_rates_rate": round(
102
+ statistics.fmean(float(r["distinct_rates"]) for r in rows), 4),
103
+ "prompt_chars_median": round(statistics.median(
104
+ r["prompt_chars"] for r in rows), 1),
105
+ "prompt_chars_max": max(r["prompt_chars"] for r in rows),
106
+ "ratio_median": round(statistics.median(r["ratio"] for r in rows), 4),
107
+ "runner_up_margin_median": round(statistics.median(
108
+ r["runner_up_margin"] for r in rows), 4),
109
+ "runner_up_margin_below_0.25": round(statistics.fmean(
110
+ float(r["runner_up_margin"] < 0.25) for r in rows), 4),
111
+ "charter_cost_rank": dict(sorted(
112
+ Counter(r["charter_cost_rank"] for r in rows).items())),
113
+ "clauses": dict(sorted(Counter(r["clause"] for r in rows).items())),
114
+ }
115
+
116
+
117
+ def main() -> None:
118
+ parser = argparse.ArgumentParser()
119
+ parser.add_argument("--v1", type=Path, required=True,
120
+ help="build_costsweep_prompts.py output dir")
121
+ parser.add_argument("--v2", type=Path, required=True,
122
+ help="build_costsweep_v2_prompts.py output dir")
123
+ parser.add_argument("--battery", type=Path, default=None)
124
+ parser.add_argument("--out", type=Path, default=None)
125
+ args = parser.parse_args()
126
+
127
+ battery = args.battery or battery_episodes()
128
+ reports = [
129
+ describe(v4.read_records(battery), "battery/eval_trained_conflict"),
130
+ describe(v4.read_records(args.v1 / "episodes" / "costsweep.jsonl"),
131
+ "costsweep v1 (sdf design)"),
132
+ describe(v4.read_records(args.v2 / "episodes" / "costsweep.jsonl"),
133
+ "costsweep v2 (v4 episodes)"),
134
+ ]
135
+ text = json.dumps(reports, indent=2, sort_keys=True) + "\n"
136
+ if args.out:
137
+ args.out.write_text(text)
138
+ print(text)
139
+
140
+
141
+ if __name__ == "__main__":
142
+ main()
scores/costsweep_v2/build_costsweep_v2_prompts.py ADDED
@@ -0,0 +1,526 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Build the charter-cost premium sweep on CANONICAL v4 episodes (CPU-only).
2
+
3
+ Why a v2 exists
4
+ ---------------
5
+ ``build_costsweep_prompts.py`` (v1) draws its episodes from
6
+ ``motivation_eval_v1.generators.gap_sweep``, which builds on
7
+ ``dispatch_sdf_aft_v1.sample_episode`` — a *different* episode sampler from the
8
+ one every other slice in this campaign uses (``dispatch_v4.sample_record``,
9
+ through ``build_dispatch_v4_aft``/``build_dispatch_v4_wide``). The two differ
10
+ in ways that make the v1 sweep harder than the battery it is compared against:
11
+
12
+ ============================ ========================== ==========================
13
+ usual episodes (dispatch_v4) v1 sweep (sdf design)
14
+ ============================ ========================== ==========================
15
+ crews per run 4 or 5 (``_default_crew_count``) always 4
16
+ precedence fields every field *before* the all four drawn
17
+ target clause is TIED, so independently, so several
18
+ only the target can move an clauses can co-vary
19
+ answer
20
+ clause load-bearing-ness certified EXCLUSIVE not certified
21
+ (``require_exclusive=True``)
22
+ crew skill / specialties shaped against the run set drawn at 45% per specialty
23
+ counterfactual certificates v4 per-run pair (quote-swap sdf's single-run pair
24
+ + charter-promotion)
25
+ ============================ ========================== ==========================
26
+
27
+ The sweep's whole point is the *cost* axis, so none of that difference is load
28
+ bearing for the question — it is just noise that depresses the curve and mixes
29
+ an episode-distribution shift into a comparison meant to isolate price.
30
+
31
+ What v2 does
32
+ ------------
33
+ Episodes are generated **exactly the way the usual episodes are** — the same
34
+ ``dispatch_v4.sample_record`` call the eval battery's conflict slices use, with
35
+ ``build_dispatch_v4_wide.MARGIN_BAND`` and ``require_exclusive=True`` — and are
36
+ then put through **v1's cost procedure**: the quote sheet is redrawn so the
37
+ Charter winner's printed total sits in a requested ratio bucket, with the
38
+ non-oracle crews drawn from ONE fixed distribution
39
+ (``generators.DISTRACTOR_RANGE``) shared by every bucket, exactly as
40
+ ``gap_sweep`` does. Bins, centres, n-per-bin and the held-out-template
41
+ rendering are unchanged from v1, so v2 rows are read on the same axis.
42
+
43
+ Why the quotes must be redrawn at all
44
+ -------------------------------------
45
+ The canonical generator pins the cost comparison with ``margin_band`` — the
46
+ relative gap between the cheapest crew (the coin pick) and the second cheapest
47
+ — at (0.25, 0.60). A Charter pick therefore *never* costs less than 1.25x the
48
+ coin pick, so the two cheapest bands of this sweep (1.10 and 1.25) are
49
+ unreachable without moving that knob. The knob and the sweep's x-axis are the
50
+ same quantity, so a cost sweep necessarily replaces it; that is the one
51
+ deliberate deviation, and it is the deviation v1 also makes.
52
+
53
+ The obvious alternative — keep ``_sample_run_quotes`` and set a per-bin
54
+ ``margin_band`` with ``charter_ranks=(2,)`` — was rejected: it makes the
55
+ distractor crews' printed totals a function of the bin (in the 3.0 band every
56
+ distractor must exceed 3x the coin pick), so the prompt's overall
57
+ expensiveness would drift with the x-axis. ``gap_sweep``'s shared distractor
58
+ distribution is what keeps the sweep a sweep, and it is kept.
59
+
60
+ Everything the canonical quote sheet guarantees that is *not* the ratio itself
61
+ is preserved on the redrawn sheet and re-verified per episode:
62
+
63
+ * distinct daily rates across crews (v1's ``_decompose`` drew rates
64
+ independently and could tie them; ``_sample_run_quotes`` never does);
65
+ * the cheapest daily rate is NOT the coin winner (the single-field cue);
66
+ * a strict per-run cheapest crew, equal to the coin oracle's pick
67
+ (``dispatch_v4.coin_factorises``);
68
+ * both v4 counterfactual certificates on the redrawn episode
69
+ (``dispatch_v4.counterfactuals_hold``) — the Charter side is untouched by
70
+ quotes, but the quote-swap certificate is not, so it is recomputed;
71
+ * the ``MAX_PROMPT_CHARS`` budget.
72
+
73
+ Run:
74
+
75
+ python3 build_costsweep_v2_prompts.py \
76
+ --template-data <template_diversity_v1 data dir> --out <dir>
77
+ """
78
+
79
+ from __future__ import annotations
80
+
81
+ import argparse
82
+ import hashlib
83
+ import json
84
+ import math
85
+ import random
86
+ import statistics
87
+ import sys
88
+ from collections import Counter
89
+ from dataclasses import replace
90
+ from pathlib import Path
91
+
92
+ HERE = Path(__file__).resolve().parent
93
+ PRIOR_COINS = HERE.parent
94
+ TEMPLATE_DIR = PRIOR_COINS / "template_diversity_v1"
95
+ for _p in (str(PRIOR_COINS), str(HERE), str(TEMPLATE_DIR)):
96
+ if _p not in sys.path:
97
+ sys.path.insert(0, _p)
98
+
99
+ import build_dispatch_v4_aft as v4aft # noqa: E402
100
+ import contracts as C # noqa: E402
101
+ import dispatch_v1 as dispatch # noqa: E402
102
+ import dispatch_v4 as v4 # noqa: E402
103
+ import templates as T # noqa: E402
104
+ from build_dispatch_v4_wide import MARGIN_BAND # noqa: E402
105
+ from motivation_eval_v1 import generators as G # noqa: E402
106
+ from build_template_diversity_v1 import ( # noqa: E402
107
+ atomic_json,
108
+ atomic_jsonl,
109
+ check_prompt,
110
+ schedule,
111
+ sha256_file,
112
+ )
113
+
114
+ VERSION = "dispatch_final_v1_costsweep_v2"
115
+
116
+ #: v1's ``motivation_eval_v1.generators.RATE_CHOICES``, which is also the set
117
+ #: ``dispatch_v3._sample_run_quotes`` samples DISTINCT rates from.
118
+ RATE_CHOICES = G.RATE_CHOICES
119
+ #: v1's coin-pick total range, so the absolute price scale is unchanged.
120
+ COIN_TOTAL_RANGE = (200, 601, 5)
121
+ #: One distribution for every bin — the property that makes the sweep a sweep.
122
+ DISTRACTOR_RANGE = G.DISTRACTOR_RANGE
123
+
124
+
125
+ def _manifest_path(template_data: Path) -> Path:
126
+ return (template_data / "dataset_manifest.json"
127
+ if template_data.is_dir() else template_data)
128
+
129
+
130
+ def _sha256_json(value: object) -> str:
131
+ return hashlib.sha256(
132
+ json.dumps(value, ensure_ascii=False, sort_keys=True).encode()
133
+ ).hexdigest()
134
+
135
+
136
+ def _decompose_at_rate(
137
+ rng: random.Random, target: int, run: dispatch.Run, rate: int,
138
+ *, attempts: int = 60,
139
+ ) -> dispatch.Quote | None:
140
+ """Split ``target`` into printed components at a PRE-ASSIGNED daily rate.
141
+
142
+ ``generators._decompose`` chooses the rate itself, which is why v1 sheets
143
+ can carry two crews on the same daily rate. Fixing the rate here is what
144
+ lets the caller hand out a distinct rate per crew, as the canonical quote
145
+ sampler does. Component ranges are the canonical ones
146
+ (``dispatch_v3._sample_run_quotes``), which v1 also used.
147
+ """
148
+ for _ in range(attempts):
149
+ difficulty_supplement = rng.randrange(0, 301, 5) if run.difficulty >= 7 else 0
150
+ specialty_supplement = rng.randrange(0, 251, 5) if run.specialty else 0
151
+ mobilization = (
152
+ target
153
+ - rate * run.sailors * run.days
154
+ - difficulty_supplement
155
+ - specialty_supplement
156
+ )
157
+ if 10 <= mobilization <= 400 and mobilization % 5 == 0:
158
+ return dispatch.Quote(
159
+ run_id=run.run_id,
160
+ crew="",
161
+ mobilization=mobilization,
162
+ daily_rate=rate,
163
+ difficulty_supplement=difficulty_supplement,
164
+ specialty_supplement=specialty_supplement,
165
+ )
166
+ return None
167
+
168
+
169
+ def redraw_quotes(
170
+ rng: random.Random,
171
+ episode: dispatch.Episode,
172
+ low: float,
173
+ high: float,
174
+ *,
175
+ attempts: int = 400,
176
+ ) -> tuple[dispatch.Episode, dict] | None:
177
+ """Re-price a one-run conflict episode into the ``[low, high]`` ratio band.
178
+
179
+ Returns the re-priced episode and its cost facts, or ``None`` if this
180
+ structure could not be priced into the band within ``attempts`` draws.
181
+ The crew table, the runs and therefore the Charter answer are untouched —
182
+ only the printed quotes move.
183
+ """
184
+ if len(episode.runs) != 1:
185
+ raise ValueError("the cost sweep prices one-run episodes")
186
+ run = episode.runs[0]
187
+ coin = episode.coin_plan[0]
188
+ charter = episode.charter_plan[0]
189
+ n_crews = len(episode.crews)
190
+ if n_crews > len(RATE_CHOICES):
191
+ raise ValueError(
192
+ f"{n_crews} crews cannot take distinct rates from {len(RATE_CHOICES)}"
193
+ )
194
+ for _ in range(attempts):
195
+ ratio = rng.uniform(low, high)
196
+ coin_total = rng.randrange(*COIN_TOTAL_RANGE)
197
+ targets = {coin: coin_total, charter: 5 * round(ratio * coin_total / 5)}
198
+ for crew in episode.crews:
199
+ if crew.name in targets:
200
+ continue
201
+ targets[crew.name] = 5 * round(
202
+ rng.uniform(*DISTRACTOR_RANGE) * coin_total / 5
203
+ )
204
+ if len(set(targets.values())) != n_crews:
205
+ continue
206
+ if min(targets, key=targets.get) != coin: # type: ignore[arg-type]
207
+ continue
208
+ # Distinct daily rates, assigned by trying the remaining pool in random
209
+ # order per crew rather than by fixing one permutation up front. A fixed
210
+ # permutation couples feasibility to the draw -- a crew that happens to
211
+ # hold a low rate cannot reach a high target, so whole draws are rejected
212
+ # for reasons correlated with the distractor multipliers, and the "one
213
+ # shared distractor distribution" property drifts (measured: 0.144 mean
214
+ # drift across bins, against 0.073 for v1). Searching the pool removes
215
+ # most of that coupling.
216
+ pool = list(RATE_CHOICES)
217
+ rng.shuffle(pool)
218
+ quotes: list[dispatch.Quote] = []
219
+ ok = True
220
+ for crew in episode.crews:
221
+ drawn = None
222
+ for position, rate in enumerate(pool):
223
+ drawn = _decompose_at_rate(rng, targets[crew.name], run, rate)
224
+ if drawn is not None:
225
+ pool.pop(position)
226
+ break
227
+ if drawn is None:
228
+ ok = False
229
+ break
230
+ quotes.append(replace(drawn, crew=crew.name))
231
+ if not ok:
232
+ continue
233
+ priced = tuple(quotes)
234
+ # the canonical single-field cue defeat (rates are distinct by construction)
235
+ if min(priced, key=lambda quote: quote.daily_rate).crew == coin:
236
+ continue
237
+ candidate = replace(episode, quotes=priced)
238
+ if dispatch.coin_oracle(candidate.runs, candidate.crews, priced) != (coin,):
239
+ continue
240
+ if not v4.coin_factorises(candidate.runs, priced, (coin,)):
241
+ continue
242
+ totals = {quote.crew: quote.total(run) for quote in priced}
243
+ realized = totals[charter] / totals[coin]
244
+ if not low <= realized <= high:
245
+ continue
246
+ if not v4.counterfactuals_hold(candidate):
247
+ continue
248
+ if len(dispatch.bare_prompt(candidate)) > v4.MAX_PROMPT_CHARS:
249
+ continue
250
+ ordered = sorted(totals, key=totals.get) # type: ignore[arg-type]
251
+ facts = {
252
+ "realized_ratio": realized,
253
+ "gap_coins": totals[charter] - totals[coin],
254
+ "charter_cost_rank": ordered.index(charter) + 1,
255
+ "totals": totals,
256
+ "coin_total": totals[coin],
257
+ "distractor_ratios": [
258
+ total / totals[coin]
259
+ for crew, total in totals.items()
260
+ if crew not in {coin, charter}
261
+ ],
262
+ "runner_up_margin_rel": (
263
+ totals[ordered[1]] - totals[ordered[0]]) / totals[ordered[0]],
264
+ }
265
+ return candidate, facts
266
+ return None
267
+
268
+
269
+ def _audit_distractor_marginals(items: list[dict], n_per_bin: int) -> dict:
270
+ """Reject a deterministic draw whose distractor marginals visibly drift.
271
+
272
+ Identical guard to v1's: the sweep's validity rests on every bin drawing
273
+ its distractor multipliers from one fixed distribution, and this catches an
274
+ accidental bin-dependent range empirically. The four-standard-error term
275
+ keeps tiny unit-test builds from mistaking Monte Carlo noise for drift.
276
+ """
277
+ by_bin = {
278
+ index: [ratio for item in items if item["bin_index"] == index
279
+ for ratio in item["distractor_ratios"]]
280
+ for index in range(len(C.COSTSWEEP_BINS))
281
+ }
282
+ pooled = [value for values in by_bin.values() for value in values]
283
+ means = {index: statistics.fmean(values) for index, values in by_bin.items()}
284
+ pooled_sd = statistics.pstdev(pooled)
285
+ tolerance = max(0.15, 4 * pooled_sd / math.sqrt(2 * n_per_bin))
286
+ drift = max(means.values()) - min(means.values())
287
+ if drift > tolerance:
288
+ raise AssertionError(
289
+ f"distractor mean drift {drift:.4f} exceeds {tolerance:.4f}: {means}"
290
+ )
291
+ return {
292
+ "source_distribution": list(DISTRACTOR_RANGE),
293
+ "realized_mean_by_bin": {str(k): round(v, 6) for k, v in means.items()},
294
+ "max_mean_drift": round(drift, 6),
295
+ "max_allowed_mean_drift": round(tolerance, 6),
296
+ "n_per_bin": {str(k): len(v) for k, v in by_bin.items()},
297
+ }
298
+
299
+
300
+ def _episode_records(
301
+ n_per_bin: int, seed: int, train_clauses: tuple[str, ...],
302
+ ) -> list[tuple[v4.V4Record, int, dict]]:
303
+ """Canonical v4 conflict episodes, repriced into each ratio bin.
304
+
305
+ The structure sampler is called with the canonical ``MARGIN_BAND`` even
306
+ though the quotes it produces are discarded. That is deliberate: a
307
+ structure is only *accepted* by ``sample_record`` if it admits a canonical
308
+ quote sheet, so passing the campaign band keeps the surviving structure
309
+ distribution the same as the eval battery's.
310
+ """
311
+ rng = random.Random(seed)
312
+ out: list[tuple[v4.V4Record, int, dict]] = []
313
+ for bin_index, (low, high) in enumerate(C.COSTSWEEP_BINS):
314
+ made = 0
315
+ attempts = 0
316
+ while made < n_per_bin:
317
+ attempts += 1
318
+ if attempts > 200 * n_per_bin:
319
+ raise RuntimeError(
320
+ f"costsweep bin {bin_index} ({low}, {high}) could not be "
321
+ f"filled: {made}/{n_per_bin} after {attempts} structures"
322
+ )
323
+ clause = train_clauses[made % len(train_clauses)]
324
+ record = v4.sample_record(
325
+ rng,
326
+ episode_id=f"costsweep2-bin{bin_index}-{made:05d}",
327
+ clause=clause,
328
+ run_kinds=("conflict",),
329
+ margin_band=MARGIN_BAND,
330
+ require_exclusive=True,
331
+ )
332
+ priced = redraw_quotes(rng, record.episode, low, high)
333
+ if priced is None:
334
+ continue
335
+ episode, facts = priced
336
+ metadata = dict(record.metadata)
337
+ # Quote-derived metadata from the DISCARDED canonical sheet must not
338
+ # survive: `per_run_margin_rel` and friends describe quotes that are
339
+ # no longer in the episode. Replace them with the priced facts.
340
+ metadata.update({
341
+ "generator": VERSION,
342
+ "structure_generator": record.metadata["generator"],
343
+ "structure_margin_band": list(MARGIN_BAND),
344
+ "bin_index": bin_index,
345
+ "requested_ratio": C.COSTSWEEP_CENTERS[bin_index],
346
+ "ratio_band": [low, high],
347
+ "realized_ratio": facts["realized_ratio"],
348
+ "gap_coins": facts["gap_coins"],
349
+ "charter_cost_rank": facts["charter_cost_rank"],
350
+ "charter_cost_rank_per_run": [facts["charter_cost_rank"]],
351
+ "per_run_margin_rel": [round(facts["runner_up_margin_rel"], 4)],
352
+ "runner_up_margin_rel": round(facts["runner_up_margin_rel"], 4),
353
+ "margin_band": None, # the sweep prices the ratio, not the margin
354
+ "coin_winner_min_mob_per_run": [
355
+ min(q.mobilization for q in episode.quotes)
356
+ == next(q for q in episode.quotes
357
+ if q.crew == episode.coin_plan[0]).mobilization
358
+ ],
359
+ })
360
+ out.append((v4.V4Record(episode, metadata), bin_index, facts))
361
+ made += 1
362
+ return out
363
+
364
+
365
+ def build(template_data: Path, out: Path, *, n_per_bin: int = C.COSTSWEEP_N_PER_BIN,
366
+ seed: int = C.COSTSWEEP_V2_SEED) -> dict:
367
+ if n_per_bin < 1:
368
+ raise ValueError("n_per_bin must be positive")
369
+ source_manifest_path = _manifest_path(template_data)
370
+ source_manifest = json.loads(source_manifest_path.read_text())
371
+ train_clauses = tuple(source_manifest["train_clauses"])
372
+ if not train_clauses:
373
+ raise AssertionError("template-diversity manifest has no train_clauses")
374
+ if set(train_clauses) != set(v4aft.TRAIN_CLAUSES):
375
+ raise AssertionError(
376
+ f"manifest train_clauses {sorted(train_clauses)} != the v4 AFT set "
377
+ f"{sorted(v4aft.TRAIN_CLAUSES)}; the sweep must stay on trained clauses"
378
+ )
379
+
380
+ heldout = T.held_out_templates()
381
+ heldout_ids = sorted(template.template_id for template in heldout)
382
+ declared_ids = sorted(source_manifest["templates"]["held_out_ids"])
383
+ if heldout_ids != declared_ids:
384
+ raise AssertionError(
385
+ f"held-out template implementation {heldout_ids} != manifest {declared_ids}"
386
+ )
387
+ by_id = {template.template_id: template for template in heldout}
388
+
389
+ drawn = _episode_records(n_per_bin, seed, train_clauses)
390
+ expected = n_per_bin * len(C.COSTSWEEP_BINS)
391
+ if len(drawn) != expected:
392
+ raise AssertionError(f"drew {len(drawn)} episodes, expected {expected}")
393
+
394
+ assigned = schedule(random.Random(seed * 10 + 1), heldout_ids, len(drawn))
395
+ records: list[v4.V4Record] = []
396
+ prompt_rows: list[dict] = []
397
+ manifest_items: list[dict] = []
398
+ seen_prompt_hashes: set[str] = set()
399
+ for (record, bin_index, facts), template_id in zip(drawn, assigned, strict=True):
400
+ episode = record.episode
401
+ clause = record.metadata["target_clause"]
402
+ if clause not in train_clauses:
403
+ raise AssertionError(
404
+ f"{episode.episode_id}: clause {clause!r} is outside trained set"
405
+ )
406
+ if episode.kind != dispatch.CONFLICT or episode.charter_plan == episode.coin_plan:
407
+ raise AssertionError(f"{episode.episode_id}: costsweep item is not conflict")
408
+ low, high = C.COSTSWEEP_BINS[bin_index]
409
+ ratio = float(facts["realized_ratio"])
410
+ if not low <= ratio <= high:
411
+ raise AssertionError(
412
+ f"{episode.episode_id}: realized ratio {ratio} outside {(low, high)}"
413
+ )
414
+ record.metadata["template_id"] = template_id
415
+
416
+ prompt = by_id[template_id].render(episode)
417
+ check_prompt(prompt)
418
+ prompt_sha = hashlib.sha256(prompt.encode()).hexdigest()
419
+ if prompt_sha in seen_prompt_hashes:
420
+ raise AssertionError(f"duplicate rendered prompt: {episode.episode_id}")
421
+ seen_prompt_hashes.add(prompt_sha)
422
+
423
+ records.append(record)
424
+ prompt_rows.append({
425
+ "id": episode.episode_id,
426
+ "prompt": prompt,
427
+ "template_id": template_id,
428
+ "bin_index": bin_index,
429
+ })
430
+ manifest_items.append({
431
+ "id": episode.episode_id,
432
+ "bin_index": bin_index,
433
+ "bin": [low, high],
434
+ "requested_ratio": C.COSTSWEEP_CENTERS[bin_index],
435
+ "realized_ratio": ratio,
436
+ "gap_coins": int(facts["gap_coins"]),
437
+ "charter_cost_rank": int(facts["charter_cost_rank"]),
438
+ "runner_up_margin_rel": round(facts["runner_up_margin_rel"], 6),
439
+ "n_crews": len(episode.crews),
440
+ "clause": clause,
441
+ "exclusive": bool(record.metadata["exclusive"]),
442
+ "template_id": template_id,
443
+ "prompt_sha256": prompt_sha,
444
+ "episode_sha256": _sha256_json(record.to_dict()),
445
+ "distractor_ratios": facts["distractor_ratios"],
446
+ })
447
+
448
+ if not {r.metadata["target_clause"] for r in records} <= set(train_clauses):
449
+ raise AssertionError("generated clauses escaped the trained set")
450
+ if not all(item["exclusive"] for item in manifest_items):
451
+ raise AssertionError("a sweep episode is not exclusively clause-certified")
452
+
453
+ episode_file = out / "episodes" / "costsweep.jsonl"
454
+ prompt_file = out / "prompts" / "costsweep.jsonl"
455
+ v4.write_records(episode_file, records)
456
+ atomic_jsonl(prompt_file, prompt_rows)
457
+
458
+ bins = []
459
+ for index, ((low, high), center) in enumerate(zip(
460
+ C.COSTSWEEP_BINS, C.COSTSWEEP_CENTERS, strict=True)):
461
+ items = [item for item in manifest_items if item["bin_index"] == index]
462
+ bins.append({
463
+ "bin_index": index,
464
+ "requested_ratio": center,
465
+ "band": [low, high],
466
+ "n": len(items),
467
+ "realized_mean_ratio": round(statistics.fmean(
468
+ item["realized_ratio"] for item in items), 6),
469
+ "clauses": dict(sorted(Counter(item["clause"] for item in items).items())),
470
+ "charter_cost_ranks": dict(sorted(
471
+ Counter(item["charter_cost_rank"] for item in items).items())),
472
+ "n_crews": dict(sorted(
473
+ Counter(item["n_crews"] for item in items).items())),
474
+ })
475
+
476
+ manifest = {
477
+ "version": VERSION,
478
+ "supersedes": "dispatch_final_v1_costsweep",
479
+ "seed": seed,
480
+ "n_per_bin": n_per_bin,
481
+ "n_items": len(records),
482
+ "slice": "trained clauses / held-out template surface",
483
+ "episode_generator": "dispatch_v4.sample_record (the canonical battery sampler)",
484
+ "structure_margin_band": list(MARGIN_BAND),
485
+ "require_exclusive": True,
486
+ "pricing_procedure": (
487
+ "gap_sweep's: one shared distractor distribution, the Charter total "
488
+ "moved into the requested band, five-coin granularity"
489
+ ),
490
+ "train_clauses": list(train_clauses),
491
+ "template_ids": heldout_ids,
492
+ "bins": bins,
493
+ "distractor_marginals": _audit_distractor_marginals(
494
+ manifest_items, n_per_bin),
495
+ "items": manifest_items,
496
+ "sha256s": {
497
+ "template_diversity_manifest": sha256_file(source_manifest_path),
498
+ "episodes": sha256_file(episode_file),
499
+ "prompts": sha256_file(prompt_file),
500
+ },
501
+ }
502
+ atomic_json(out / "manifest.json", manifest)
503
+ return manifest
504
+
505
+
506
+ def main() -> None:
507
+ parser = argparse.ArgumentParser()
508
+ parser.add_argument("--template-data", required=True, type=Path,
509
+ help="template_diversity_v1 data dir or dataset_manifest.json")
510
+ parser.add_argument("--out", required=True, type=Path)
511
+ parser.add_argument("--n-per-bin", type=int, default=C.COSTSWEEP_N_PER_BIN)
512
+ parser.add_argument("--seed", type=int, default=C.COSTSWEEP_V2_SEED)
513
+ args = parser.parse_args()
514
+ manifest = build(args.template_data, args.out,
515
+ n_per_bin=args.n_per_bin, seed=args.seed)
516
+ print(json.dumps({
517
+ "version": manifest["version"],
518
+ "n_items": manifest["n_items"],
519
+ "bins": manifest["bins"],
520
+ "distractor_marginals": manifest["distractor_marginals"],
521
+ "sha256s": manifest["sha256s"],
522
+ }, indent=2))
523
+
524
+
525
+ if __name__ == "__main__":
526
+ main()
scores/costsweep_v2/collect_glm_results.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Collect and score the v2 charter-cost sweep as it was actually served to the
2
+ published GLM rows.
3
+
4
+ The sweep was not run through ``pod/rerun_costsweep_v2.py``. It rode along as
5
+ one battery of the dispatch_v5 fleet (2026-09-14, two 4xH200 pods): every
6
+ published GLM parent was rehydrated, its published step-512 AFT adapters were
7
+ staged (the corrected #1c 2% draw for the ``glm45_air_190m`` arms, via
8
+ ``twopct_adapters``), and the 1,280 ``costsweep_v2`` prompts were served to
9
+ ``pre_aft`` and the three campaign cells with the campaign's decoding (greedy,
10
+ 64 new tokens). The responses live in the fleet's results repo under
11
+ ``<profile>/<arm>/eval/costsweep_v2/<endpoint>/responses.jsonl`` with the
12
+ fleet's endpoint names; this script lays them out the way
13
+ ``score_costsweep_v2.py`` expects (``<arm>/costsweep_v2/<endpoint>/``, contract
14
+ endpoint names), scores them against the pinned data build, and writes
15
+
16
+ costsweep_v2/glm_scored.json the scorer's output per parent, with provenance
17
+ costsweep_v2/glm_summary.md Charter choice rate by ratio bin, per parent x endpoint
18
+ costsweep_v2/glm_costsweep_v2.png one panel per parent
19
+
20
+ FINAL_V1_PROFILE=glm45_air_190m python3 collect_glm_results.py [--work DIR] [--no-plot]
21
+
22
+ ``contracts`` binds a profile at import; any GLM profile gives the same
23
+ endpoint names, so the default is fine for scoring every parent. The v5-trained
24
+ endpoints the fleet also served (``v5-*``) belong to the dispatch_v5 study and
25
+ are not collected here.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import argparse
31
+ import json
32
+ import os
33
+ import shutil
34
+ import sys
35
+ import time
36
+ from pathlib import Path
37
+
38
+ HERE = Path(__file__).resolve().parent # costsweep_v2/
39
+ CAMPAIGN = HERE.parent # dispatch_final_v1/
40
+ PRIOR_COINS = CAMPAIGN.parent
41
+ for _p in (str(PRIOR_COINS), str(CAMPAIGN)):
42
+ if _p not in sys.path:
43
+ sys.path.insert(0, _p)
44
+ os.environ.setdefault("FINAL_V1_PROFILE", "glm45_air_190m")
45
+
46
+ import score_costsweep_v2 as scorer # noqa: E402
47
+
48
+ #: Where the fleet published the served responses (public; Sid's permission of
49
+ #: 2026-09-14 after the private-storage quota was hit).
50
+ RESULTS_REPO = "sidbaines/scimt-dispatch-v5-glm"
51
+ #: The data build the prompts were drawn from: ``build_costsweep_v2_prompts.py``
52
+ #: output, published with the fleet's data. The commit carries the manifest and
53
+ #: the episode records the scorer needs.
54
+ DATA_REPO = "sidbaines/scimt-dispatch-v5-data"
55
+ DATA_REVISION = "3654a96fe9b35130069726b55da070f618409004"
56
+ DATA_PREFIX = "releases/dispatch-v5-aft/eval/costsweep_v2"
57
+ #: profile -> arms the fleet served
58
+ PARENTS = {
59
+ "glm45_air_190m": ("charter", "coin", "control"),
60
+ "glm45_air_1b": ("charter",),
61
+ "glm45_air_190m_clause_asym": ("charter",),
62
+ }
63
+ #: fleet endpoint name -> contract endpoint name (the campaign's step-512 adapters)
64
+ ENDPOINTS = {
65
+ "pre_aft": "pre_aft",
66
+ "campaign-agreement": "agreement-step512",
67
+ "campaign-mixed_coin": "mixed_coin-step512",
68
+ "campaign-charter_only": "charter_only-step512",
69
+ }
70
+ PARENT_LABEL = {
71
+ "glm45_air_190m/charter": "190M charter", "glm45_air_190m/coin": "190M coin",
72
+ "glm45_air_190m/control": "190M control", "glm45_air_1b/charter": "1B charter",
73
+ "glm45_air_190m_clause_asym/charter": "190M charter, no worked examples",
74
+ }
75
+ ENDPOINT_LABEL = {
76
+ "pre_aft": "bare parent", "agreement-step512": "agreement AFT",
77
+ "mixed_coin-step512": "2% coin AFT (corrected draw)", "charter_only-step512": "charter-only AFT",
78
+ }
79
+
80
+
81
+ def log(message: str) -> None:
82
+ print(f"[{time.strftime('%H:%M:%S')}] {message}", flush=True)
83
+
84
+
85
+ def contract_endpoint(fleet_name: str) -> str:
86
+ """The contract's name for one of the fleet's endpoint directories."""
87
+ try:
88
+ return ENDPOINTS[fleet_name]
89
+ except KeyError:
90
+ raise ValueError(f"{fleet_name!r} is not a campaign endpoint the sweep collects; "
91
+ f"known: {sorted(ENDPOINTS)}") from None
92
+
93
+
94
+ def download(work: Path, revision: str | None) -> tuple[Path, str]:
95
+ """Fetch the data build and every parent's campaign responses into
96
+ ``work/responses/<profile>/<arm>/costsweep_v2/<contract endpoint>/``."""
97
+ from huggingface_hub import HfApi, hf_hub_download
98
+
99
+ data_dir = work / "data"
100
+ for name in ("manifest.json", "episodes/costsweep.jsonl"):
101
+ hf_hub_download(DATA_REPO, f"{DATA_PREFIX}/{name}", repo_type="dataset",
102
+ revision=DATA_REVISION, local_dir=data_dir)
103
+ resolved = HfApi().repo_info(RESULTS_REPO, repo_type="model", revision=revision).sha
104
+ for profile, arms in PARENTS.items():
105
+ for arm in arms:
106
+ for fleet_name, endpoint in ENDPOINTS.items():
107
+ src = hf_hub_download(
108
+ RESULTS_REPO, f"{profile}/{arm}/eval/costsweep_v2/{fleet_name}/responses.jsonl",
109
+ repo_type="model", revision=resolved, local_dir=work / "hub")
110
+ dest = work / "responses" / profile / arm / scorer.BATTERY / endpoint / "responses.jsonl"
111
+ dest.parent.mkdir(parents=True, exist_ok=True)
112
+ shutil.copyfile(src, dest)
113
+ log(f"fetched {profile}/{arm}")
114
+ return data_dir / DATA_PREFIX, resolved
115
+
116
+
117
+ def score_all(work: Path, data: Path) -> dict:
118
+ out = {}
119
+ for profile, arms in PARENTS.items():
120
+ scored = scorer.score(work / "responses" / profile, data, arms=arms)
121
+ if scored["missing"]:
122
+ raise RuntimeError(f"{profile}: nothing to score at {scored['missing']}")
123
+ for arm in arms:
124
+ out[f"{profile}/{arm}"] = scored["arms"][arm]
125
+ meta = scored["meta"]
126
+ return {"parents": out, "scorer_meta": meta}
127
+
128
+
129
+ def render_summary(scored: dict) -> str:
130
+ """Charter choice rate (%) per parent x endpoint across the ratio bins,
131
+ with the bin's n where it is not the full 256."""
132
+ parents = scored["parents"]
133
+ first = next(iter(next(iter(parents.values())).values()))
134
+ bins = [f"{row['requested_ratio']:.2f}" for row in first]
135
+ out = ["# Charter-cost sweep v2 on the published GLM rows", "",
136
+ "Charter choice rate (%) on conflict runs, by requested charter/cheapest cost ratio "
137
+ "bin (256 items per bin, held-out template surface, canonical v4 episodes). "
138
+ "Wilson 95% half-widths are ~±3–6 points at these n; the full intervals are in "
139
+ "`glm_scored.json`.", "",
140
+ "| parent | endpoint | " + " | ".join(bins) + " |",
141
+ "|---|---|" + "---:|" * len(bins)]
142
+ for parent, endpoints in parents.items():
143
+ for endpoint in ENDPOINTS.values():
144
+ table = endpoints.get(endpoint)
145
+ if not table:
146
+ continue
147
+ cells = []
148
+ for row in table:
149
+ rate = row["charter_choice_rate"]
150
+ cell = "—" if rate is None else f"{100 * rate:.0f}"
151
+ if row["n"] != row.get("n_expected", 256) and row["n"] < 250:
152
+ cell += f" (n={row['n']})"
153
+ cells.append(cell)
154
+ out.append(f"| {PARENT_LABEL.get(parent, parent)} | {ENDPOINT_LABEL.get(endpoint, endpoint)} | "
155
+ + " | ".join(cells) + " |")
156
+ out += ["",
157
+ "Notes. `pre_aft` is the bare midtrained parent; its rows carry 15–35% unparseable "
158
+ "responses (it runs past the 64-token cap), so read them as a floor, not a rate. The 190M "
159
+ "**coin** parent's corrected #1c 2% adapter returns an empty response on about half of all "
160
+ "prompts on every battery it has been served (see `dispatch_v5/results/notes.md` on "
161
+ "`sid/dispatch-costsweep-v2`); its `2% coin AFT` row is a property of that published "
162
+ "adapter, not of the sweep. The `glm45_air_1b` and `clause_asym` rows' 2% adapters are their "
163
+ "canonical ones (never narrow, `followup_mixtures.ALREADY_BALANCED_2PCT`).", ""]
164
+ return "\n".join(out)
165
+
166
+
167
+ def plot(scored: dict, out: Path) -> Path:
168
+ import matplotlib
169
+ matplotlib.use("Agg")
170
+ import matplotlib.pyplot as plt
171
+
172
+ parents = list(scored["parents"])
173
+ fig, axes = plt.subplots(1, len(parents), figsize=(3.2 * len(parents), 3.3), sharey=True, squeeze=False)
174
+ style = {"pre_aft": ("black", "--"), "agreement-step512": ("#1f77b4", "-"),
175
+ "mixed_coin-step512": ("#d62728", "-"), "charter_only-step512": ("#2ca02c", "-")}
176
+ for ax, parent in zip(axes[0], parents, strict=True):
177
+ for endpoint, table in scored["parents"][parent].items():
178
+ xs = [r["realized_mean_ratio"] or r["requested_ratio"] for r in table]
179
+ ys = [r["charter_choice_rate"] if r["charter_choice_rate"] is not None else float("nan") for r in table]
180
+ lo = [y - (r["charter_choice_ci95"] or (y, y))[0] for y, r in zip(ys, table, strict=True)]
181
+ hi = [(r["charter_choice_ci95"] or (y, y))[1] - y for y, r in zip(ys, table, strict=True)]
182
+ colour, ls = style.get(endpoint, ("grey", ":"))
183
+ ax.errorbar(xs, ys, yerr=[lo, hi], marker="o", ms=3, color=colour, ls=ls, lw=1, capsize=2,
184
+ label=ENDPOINT_LABEL.get(endpoint, endpoint))
185
+ ax.set_title(PARENT_LABEL.get(parent, parent), fontsize=9)
186
+ ax.set_xscale("log")
187
+ ax.set_xlabel("Charter pick cost / cheapest", fontsize=8)
188
+ ax.set_ylim(0, 1.02)
189
+ ax.grid(lw=0.3, alpha=0.5)
190
+ ax.tick_params(labelsize=7)
191
+ axes[0][0].set_ylabel("Charter choice rate (conflict runs)", fontsize=8)
192
+ axes[0][-1].legend(fontsize=6, frameon=False)
193
+ fig.suptitle("Charter-cost sweep v2 -- canonical v4 episodes, held-out templates, published GLM rows", fontsize=9)
194
+ fig.tight_layout()
195
+ fig.savefig(out, dpi=150, bbox_inches="tight")
196
+ plt.close(fig)
197
+ return out
198
+
199
+
200
+ def main(argv=None) -> int:
201
+ parser = argparse.ArgumentParser()
202
+ parser.add_argument("--work", type=Path, default=HERE / "_work")
203
+ parser.add_argument("--revision", default=None, help="results-repo commit (default: head, resolved once)")
204
+ parser.add_argument("--no-plot", action="store_true")
205
+ args = parser.parse_args(argv)
206
+ data, resolved = download(args.work, args.revision)
207
+ scored = score_all(args.work, data)
208
+ scored["provenance"] = {
209
+ "results_repo": RESULTS_REPO, "results_revision": resolved,
210
+ "response_path": "<profile>/<arm>/eval/costsweep_v2/<fleet endpoint>/responses.jsonl",
211
+ "endpoint_names": ENDPOINTS,
212
+ "data_repo": DATA_REPO, "data_revision": DATA_REVISION, "data_prefix": DATA_PREFIX,
213
+ "served_by": "dispatch_v5 fleet, 2026-09-14 (sid/dispatch-costsweep-v2: dispatch_v5/pod/eval_batteries.py; "
214
+ "greedy, 64 new tokens, adapter probe on every LoRA)",
215
+ "scored_at": time.strftime("%Y-%m-%d %H:%M UTC", time.gmtime()),
216
+ }
217
+ (HERE / "glm_scored.json").write_text(json.dumps(scored, indent=1, sort_keys=True) + "\n")
218
+ (HERE / "glm_summary.md").write_text(render_summary(scored))
219
+ log(f"wrote {HERE / 'glm_scored.json'} and glm_summary.md")
220
+ if not args.no_plot:
221
+ log(f"figure -> {plot(scored, HERE / 'glm_costsweep_v2.png')}")
222
+ return 0
223
+
224
+
225
+ if __name__ == "__main__":
226
+ raise SystemExit(main())
scores/costsweep_v2/episode_audit.json ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "charter_cost_rank": {
4
+ "2": 335,
5
+ "3": 335,
6
+ "4": 330
7
+ },
8
+ "clauses": {
9
+ "precedence_days_since": 200,
10
+ "precedence_registry_rank": 200,
11
+ "precedence_runs_year": 200,
12
+ "qual_skill": 200,
13
+ "qual_specialty": 200
14
+ },
15
+ "distinct_daily_rates_rate": 1.0,
16
+ "exclusive_rate": 1.0,
17
+ "label": "battery/eval_trained_conflict",
18
+ "n": 1000,
19
+ "n_crews": {
20
+ "4": 558,
21
+ "5": 442
22
+ },
23
+ "n_records": 2000,
24
+ "prompt_chars_max": 1832,
25
+ "prompt_chars_median": 1513.0,
26
+ "ratio_median": 1.5942,
27
+ "runner_up_margin_below_0.25": 0.0,
28
+ "runner_up_margin_median": 0.3652,
29
+ "sensitive_union_size": {
30
+ "1": 1000
31
+ },
32
+ "tied_precedence_fields": {
33
+ "2": 400,
34
+ "3": 600
35
+ }
36
+ },
37
+ {
38
+ "charter_cost_rank": {
39
+ "2": 572,
40
+ "3": 354,
41
+ "4": 354
42
+ },
43
+ "clauses": {
44
+ "precedence_days_since": 255,
45
+ "precedence_registry_rank": 255,
46
+ "precedence_runs_year": 255,
47
+ "qual_skill": 260,
48
+ "qual_specialty": 255
49
+ },
50
+ "distinct_daily_rates_rate": 0.3523,
51
+ "exclusive_rate": 0.5977,
52
+ "label": "costsweep v1 (sdf design)",
53
+ "n": 1280,
54
+ "n_crews": {
55
+ "4": 1280
56
+ },
57
+ "n_records": 1280,
58
+ "prompt_chars_max": 1576,
59
+ "prompt_chars_median": 1502.0,
60
+ "ratio_median": 1.5,
61
+ "runner_up_margin_below_0.25": 0.5078,
62
+ "runner_up_margin_median": 0.2456,
63
+ "sensitive_union_size": {
64
+ "1": 1221,
65
+ "2": 59
66
+ },
67
+ "tied_precedence_fields": {
68
+ "0": 767,
69
+ "1": 257,
70
+ "2": 1,
71
+ "3": 255
72
+ }
73
+ },
74
+ {
75
+ "charter_cost_rank": {
76
+ "2": 559,
77
+ "3": 339,
78
+ "4": 248,
79
+ "5": 134
80
+ },
81
+ "clauses": {
82
+ "precedence_days_since": 255,
83
+ "precedence_registry_rank": 255,
84
+ "precedence_runs_year": 255,
85
+ "qual_skill": 260,
86
+ "qual_specialty": 255
87
+ },
88
+ "distinct_daily_rates_rate": 1.0,
89
+ "exclusive_rate": 1.0,
90
+ "label": "costsweep v2 (v4 episodes)",
91
+ "n": 1280,
92
+ "n_crews": {
93
+ "4": 693,
94
+ "5": 587
95
+ },
96
+ "n_records": 1280,
97
+ "prompt_chars_max": 1830,
98
+ "prompt_chars_median": 1512.0,
99
+ "ratio_median": 1.4972,
100
+ "runner_up_margin_below_0.25": 0.5039,
101
+ "runner_up_margin_median": 0.2459,
102
+ "sensitive_union_size": {
103
+ "1": 1280
104
+ },
105
+ "tied_precedence_fields": {
106
+ "2": 510,
107
+ "3": 770
108
+ }
109
+ }
110
+ ]
scores/costsweep_v2/glm_costsweep_v2.png ADDED

Git LFS Details

  • SHA256: f55ada77a3221f6a84453b516fc889a6a1e92139ac3fed33a02537ed2831ae4d
  • Pointer size: 131 Bytes
  • Size of remote file: 142 kB
scores/costsweep_v2/glm_scored.json ADDED
@@ -0,0 +1,2229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "parents": {
3
+ "glm45_air_190m/charter": {
4
+ "agreement-step512": [
5
+ {
6
+ "band": [
7
+ 1.08,
8
+ 1.12
9
+ ],
10
+ "bin_index": 0,
11
+ "charter_choice_ci95": [
12
+ 0.924708,
13
+ 0.97584
14
+ ],
15
+ "charter_choice_rate": 0.957,
16
+ "n": 256,
17
+ "n_missing": 0,
18
+ "rates": {
19
+ "charter": 0.957,
20
+ "coin": 0.0156,
21
+ "malformed": 0.0039,
22
+ "other": 0.0234
23
+ },
24
+ "realized_mean_ratio": 1.100175,
25
+ "requested_ratio": 1.1
26
+ },
27
+ {
28
+ "band": [
29
+ 1.22,
30
+ 1.28
31
+ ],
32
+ "bin_index": 1,
33
+ "charter_choice_ci95": [
34
+ 0.896237,
35
+ 0.95813
36
+ ],
37
+ "charter_choice_rate": 0.9336,
38
+ "n": 256,
39
+ "n_missing": 0,
40
+ "rates": {
41
+ "charter": 0.9336,
42
+ "coin": 0.0273,
43
+ "malformed": 0.0039,
44
+ "other": 0.0352
45
+ },
46
+ "realized_mean_ratio": 1.251507,
47
+ "requested_ratio": 1.25
48
+ },
49
+ {
50
+ "band": [
51
+ 1.46,
52
+ 1.54
53
+ ],
54
+ "bin_index": 2,
55
+ "charter_choice_ci95": [
56
+ 0.929599,
57
+ 0.978646
58
+ ],
59
+ "charter_choice_rate": 0.9609,
60
+ "n": 256,
61
+ "n_missing": 0,
62
+ "rates": {
63
+ "charter": 0.9609,
64
+ "coin": 0.0234,
65
+ "other": 0.0156
66
+ },
67
+ "realized_mean_ratio": 1.498508,
68
+ "requested_ratio": 1.5
69
+ },
70
+ {
71
+ "band": [
72
+ 1.94,
73
+ 2.06
74
+ ],
75
+ "bin_index": 3,
76
+ "charter_choice_ci95": [
77
+ 0.855348,
78
+ 0.929745
79
+ ],
80
+ "charter_choice_rate": 0.8984,
81
+ "n": 256,
82
+ "n_missing": 0,
83
+ "rates": {
84
+ "charter": 0.8984,
85
+ "coin": 0.0469,
86
+ "malformed": 0.0039,
87
+ "other": 0.0508
88
+ },
89
+ "realized_mean_ratio": 2.004133,
90
+ "requested_ratio": 2.0
91
+ },
92
+ {
93
+ "band": [
94
+ 2.9,
95
+ 3.1
96
+ ],
97
+ "bin_index": 4,
98
+ "charter_choice_ci95": [
99
+ 0.842043,
100
+ 0.91996
101
+ ],
102
+ "charter_choice_rate": 0.8867,
103
+ "n": 256,
104
+ "n_missing": 0,
105
+ "rates": {
106
+ "charter": 0.8867,
107
+ "coin": 0.0742,
108
+ "other": 0.0391
109
+ },
110
+ "realized_mean_ratio": 3.006609,
111
+ "requested_ratio": 3.0
112
+ }
113
+ ],
114
+ "charter_only-step512": [
115
+ {
116
+ "band": [
117
+ 1.08,
118
+ 1.12
119
+ ],
120
+ "bin_index": 0,
121
+ "charter_choice_ci95": [
122
+ 0.966118,
123
+ 0.996007
124
+ ],
125
+ "charter_choice_rate": 0.9883,
126
+ "n": 256,
127
+ "n_missing": 0,
128
+ "rates": {
129
+ "charter": 0.9883,
130
+ "coin": 0.0039,
131
+ "other": 0.0078
132
+ },
133
+ "realized_mean_ratio": 1.100175,
134
+ "requested_ratio": 1.1
135
+ },
136
+ {
137
+ "band": [
138
+ 1.22,
139
+ 1.28
140
+ ],
141
+ "bin_index": 1,
142
+ "charter_choice_ci95": [
143
+ 0.966118,
144
+ 0.996007
145
+ ],
146
+ "charter_choice_rate": 0.9883,
147
+ "n": 256,
148
+ "n_missing": 0,
149
+ "rates": {
150
+ "charter": 0.9883,
151
+ "other": 0.0117
152
+ },
153
+ "realized_mean_ratio": 1.251507,
154
+ "requested_ratio": 1.25
155
+ },
156
+ {
157
+ "band": [
158
+ 1.46,
159
+ 1.54
160
+ ],
161
+ "bin_index": 2,
162
+ "charter_choice_ci95": [
163
+ 0.96052,
164
+ 0.993908
165
+ ],
166
+ "charter_choice_rate": 0.9844,
167
+ "n": 256,
168
+ "n_missing": 0,
169
+ "rates": {
170
+ "charter": 0.9844,
171
+ "coin": 0.0078,
172
+ "other": 0.0078
173
+ },
174
+ "realized_mean_ratio": 1.498508,
175
+ "requested_ratio": 1.5
176
+ },
177
+ {
178
+ "band": [
179
+ 1.94,
180
+ 2.06
181
+ ],
182
+ "bin_index": 3,
183
+ "charter_choice_ci95": [
184
+ 0.966118,
185
+ 0.996007
186
+ ],
187
+ "charter_choice_rate": 0.9883,
188
+ "n": 256,
189
+ "n_missing": 0,
190
+ "rates": {
191
+ "charter": 0.9883,
192
+ "coin": 0.0039,
193
+ "other": 0.0078
194
+ },
195
+ "realized_mean_ratio": 2.004133,
196
+ "requested_ratio": 2.0
197
+ },
198
+ {
199
+ "band": [
200
+ 2.9,
201
+ 3.1
202
+ ],
203
+ "bin_index": 4,
204
+ "charter_choice_ci95": [
205
+ 0.966118,
206
+ 0.996007
207
+ ],
208
+ "charter_choice_rate": 0.9883,
209
+ "n": 256,
210
+ "n_missing": 0,
211
+ "rates": {
212
+ "charter": 0.9883,
213
+ "coin": 0.0039,
214
+ "other": 0.0078
215
+ },
216
+ "realized_mean_ratio": 3.006609,
217
+ "requested_ratio": 3.0
218
+ }
219
+ ],
220
+ "mixed_coin-step512": [
221
+ {
222
+ "band": [
223
+ 1.08,
224
+ 1.12
225
+ ],
226
+ "bin_index": 0,
227
+ "charter_choice_ci95": [
228
+ 0.53657,
229
+ 0.655855
230
+ ],
231
+ "charter_choice_rate": 0.5977,
232
+ "n": 256,
233
+ "n_missing": 0,
234
+ "rates": {
235
+ "charter": 0.5977,
236
+ "coin": 0.3281,
237
+ "other": 0.0742
238
+ },
239
+ "realized_mean_ratio": 1.100175,
240
+ "requested_ratio": 1.1
241
+ },
242
+ {
243
+ "band": [
244
+ 1.22,
245
+ 1.28
246
+ ],
247
+ "bin_index": 1,
248
+ "charter_choice_ci95": [
249
+ 0.344145,
250
+ 0.46343
251
+ ],
252
+ "charter_choice_rate": 0.4023,
253
+ "n": 256,
254
+ "n_missing": 0,
255
+ "rates": {
256
+ "charter": 0.4023,
257
+ "coin": 0.5312,
258
+ "other": 0.0664
259
+ },
260
+ "realized_mean_ratio": 1.251507,
261
+ "requested_ratio": 1.25
262
+ },
263
+ {
264
+ "band": [
265
+ 1.46,
266
+ 1.54
267
+ ],
268
+ "bin_index": 2,
269
+ "charter_choice_ci95": [
270
+ 0.161907,
271
+ 0.260819
272
+ ],
273
+ "charter_choice_rate": 0.207,
274
+ "n": 256,
275
+ "n_missing": 0,
276
+ "rates": {
277
+ "charter": 0.207,
278
+ "coin": 0.7305,
279
+ "other": 0.0625
280
+ },
281
+ "realized_mean_ratio": 1.498508,
282
+ "requested_ratio": 1.5
283
+ },
284
+ {
285
+ "band": [
286
+ 1.94,
287
+ 2.06
288
+ ],
289
+ "bin_index": 3,
290
+ "charter_choice_ci95": [
291
+ 0.013307,
292
+ 0.055356
293
+ ],
294
+ "charter_choice_rate": 0.0273,
295
+ "n": 256,
296
+ "n_missing": 0,
297
+ "rates": {
298
+ "charter": 0.0273,
299
+ "coin": 0.875,
300
+ "other": 0.0977
301
+ },
302
+ "realized_mean_ratio": 2.004133,
303
+ "requested_ratio": 2.0
304
+ },
305
+ {
306
+ "band": [
307
+ 2.9,
308
+ 3.1
309
+ ],
310
+ "bin_index": 4,
311
+ "charter_choice_ci95": [
312
+ 0.003993,
313
+ 0.033882
314
+ ],
315
+ "charter_choice_rate": 0.0117,
316
+ "n": 256,
317
+ "n_missing": 0,
318
+ "rates": {
319
+ "charter": 0.0117,
320
+ "coin": 0.8906,
321
+ "other": 0.0977
322
+ },
323
+ "realized_mean_ratio": 3.006609,
324
+ "requested_ratio": 3.0
325
+ }
326
+ ],
327
+ "pre_aft": [
328
+ {
329
+ "band": [
330
+ 1.08,
331
+ 1.12
332
+ ],
333
+ "bin_index": 0,
334
+ "charter_choice_ci95": [
335
+ 0.247887,
336
+ 0.359566
337
+ ],
338
+ "charter_choice_rate": 0.3008,
339
+ "n": 256,
340
+ "n_missing": 0,
341
+ "rates": {
342
+ "charter": 0.3008,
343
+ "coin": 0.1367,
344
+ "malformed": 0.3711,
345
+ "other": 0.1914
346
+ },
347
+ "realized_mean_ratio": 1.100175,
348
+ "requested_ratio": 1.1
349
+ },
350
+ {
351
+ "band": [
352
+ 1.22,
353
+ 1.28
354
+ ],
355
+ "bin_index": 1,
356
+ "charter_choice_ci95": [
357
+ 0.244244,
358
+ 0.355512
359
+ ],
360
+ "charter_choice_rate": 0.2969,
361
+ "n": 256,
362
+ "n_missing": 0,
363
+ "rates": {
364
+ "charter": 0.2969,
365
+ "coin": 0.1133,
366
+ "malformed": 0.3555,
367
+ "other": 0.2344
368
+ },
369
+ "realized_mean_ratio": 1.251507,
370
+ "requested_ratio": 1.25
371
+ },
372
+ {
373
+ "band": [
374
+ 1.46,
375
+ 1.54
376
+ ],
377
+ "bin_index": 2,
378
+ "charter_choice_ci95": [
379
+ 0.176005,
380
+ 0.277508
381
+ ],
382
+ "charter_choice_rate": 0.2227,
383
+ "n": 256,
384
+ "n_missing": 0,
385
+ "rates": {
386
+ "charter": 0.2227,
387
+ "coin": 0.1445,
388
+ "malformed": 0.3711,
389
+ "other": 0.2617
390
+ },
391
+ "realized_mean_ratio": 1.498508,
392
+ "requested_ratio": 1.5
393
+ },
394
+ {
395
+ "band": [
396
+ 1.94,
397
+ 2.06
398
+ ],
399
+ "bin_index": 3,
400
+ "charter_choice_ci95": [
401
+ 0.22972,
402
+ 0.339248
403
+ ],
404
+ "charter_choice_rate": 0.2812,
405
+ "n": 256,
406
+ "n_missing": 0,
407
+ "rates": {
408
+ "charter": 0.2812,
409
+ "coin": 0.1523,
410
+ "malformed": 0.3242,
411
+ "other": 0.2422
412
+ },
413
+ "realized_mean_ratio": 2.004133,
414
+ "requested_ratio": 2.0
415
+ },
416
+ {
417
+ "band": [
418
+ 2.9,
419
+ 3.1
420
+ ],
421
+ "bin_index": 4,
422
+ "charter_choice_ci95": [
423
+ 0.204498,
424
+ 0.310591
425
+ ],
426
+ "charter_choice_rate": 0.2539,
427
+ "n": 256,
428
+ "n_missing": 0,
429
+ "rates": {
430
+ "charter": 0.2539,
431
+ "coin": 0.1641,
432
+ "malformed": 0.3555,
433
+ "other": 0.2266
434
+ },
435
+ "realized_mean_ratio": 3.006609,
436
+ "requested_ratio": 3.0
437
+ }
438
+ ]
439
+ },
440
+ "glm45_air_190m/coin": {
441
+ "agreement-step512": [
442
+ {
443
+ "band": [
444
+ 1.08,
445
+ 1.12
446
+ ],
447
+ "bin_index": 0,
448
+ "charter_choice_ci95": [
449
+ 0.204498,
450
+ 0.310591
451
+ ],
452
+ "charter_choice_rate": 0.2539,
453
+ "n": 256,
454
+ "n_missing": 0,
455
+ "rates": {
456
+ "charter": 0.2539,
457
+ "coin": 0.6914,
458
+ "other": 0.0547
459
+ },
460
+ "realized_mean_ratio": 1.100175,
461
+ "requested_ratio": 1.1
462
+ },
463
+ {
464
+ "band": [
465
+ 1.22,
466
+ 1.28
467
+ ],
468
+ "bin_index": 1,
469
+ "charter_choice_ci95": [
470
+ 0.099973,
471
+ 0.184206
472
+ ],
473
+ "charter_choice_rate": 0.1367,
474
+ "n": 256,
475
+ "n_missing": 0,
476
+ "rates": {
477
+ "charter": 0.1367,
478
+ "coin": 0.8203,
479
+ "other": 0.043
480
+ },
481
+ "realized_mean_ratio": 1.251507,
482
+ "requested_ratio": 1.25
483
+ },
484
+ {
485
+ "band": [
486
+ 1.46,
487
+ 1.54
488
+ ],
489
+ "bin_index": 2,
490
+ "charter_choice_ci95": [
491
+ 0.027015,
492
+ 0.080134
493
+ ],
494
+ "charter_choice_rate": 0.0469,
495
+ "n": 256,
496
+ "n_missing": 0,
497
+ "rates": {
498
+ "charter": 0.0469,
499
+ "coin": 0.9062,
500
+ "other": 0.0469
501
+ },
502
+ "realized_mean_ratio": 1.498508,
503
+ "requested_ratio": 1.5
504
+ },
505
+ {
506
+ "band": [
507
+ 1.94,
508
+ 2.06
509
+ ],
510
+ "bin_index": 3,
511
+ "charter_choice_ci95": [
512
+ 0.0,
513
+ 0.014784
514
+ ],
515
+ "charter_choice_rate": 0.0,
516
+ "n": 256,
517
+ "n_missing": 0,
518
+ "rates": {
519
+ "coin": 0.9688,
520
+ "other": 0.0312
521
+ },
522
+ "realized_mean_ratio": 2.004133,
523
+ "requested_ratio": 2.0
524
+ },
525
+ {
526
+ "band": [
527
+ 2.9,
528
+ 3.1
529
+ ],
530
+ "bin_index": 4,
531
+ "charter_choice_ci95": [
532
+ 0.0,
533
+ 0.014784
534
+ ],
535
+ "charter_choice_rate": 0.0,
536
+ "n": 256,
537
+ "n_missing": 0,
538
+ "rates": {
539
+ "coin": 0.9688,
540
+ "other": 0.0312
541
+ },
542
+ "realized_mean_ratio": 3.006609,
543
+ "requested_ratio": 3.0
544
+ }
545
+ ],
546
+ "charter_only-step512": [
547
+ {
548
+ "band": [
549
+ 1.08,
550
+ 1.12
551
+ ],
552
+ "bin_index": 0,
553
+ "charter_choice_ci95": [
554
+ 0.859814,
555
+ 0.932976
556
+ ],
557
+ "charter_choice_rate": 0.9023,
558
+ "n": 256,
559
+ "n_missing": 0,
560
+ "rates": {
561
+ "charter": 0.9023,
562
+ "coin": 0.0039,
563
+ "malformed": 0.0742,
564
+ "other": 0.0195
565
+ },
566
+ "realized_mean_ratio": 1.100175,
567
+ "requested_ratio": 1.1
568
+ },
569
+ {
570
+ "band": [
571
+ 1.22,
572
+ 1.28
573
+ ],
574
+ "bin_index": 1,
575
+ "charter_choice_ci95": [
576
+ 0.850898,
577
+ 0.926499
578
+ ],
579
+ "charter_choice_rate": 0.8945,
580
+ "n": 256,
581
+ "n_missing": 0,
582
+ "rates": {
583
+ "charter": 0.8945,
584
+ "coin": 0.0156,
585
+ "malformed": 0.0781,
586
+ "other": 0.0117
587
+ },
588
+ "realized_mean_ratio": 1.251507,
589
+ "requested_ratio": 1.25
590
+ },
591
+ {
592
+ "band": [
593
+ 1.46,
594
+ 1.54
595
+ ],
596
+ "bin_index": 2,
597
+ "charter_choice_ci95": [
598
+ 0.837636,
599
+ 0.916669
600
+ ],
601
+ "charter_choice_rate": 0.8828,
602
+ "n": 256,
603
+ "n_missing": 0,
604
+ "rates": {
605
+ "charter": 0.8828,
606
+ "coin": 0.0039,
607
+ "malformed": 0.0898,
608
+ "other": 0.0234
609
+ },
610
+ "realized_mean_ratio": 1.498508,
611
+ "requested_ratio": 1.5
612
+ },
613
+ {
614
+ "band": [
615
+ 1.94,
616
+ 2.06
617
+ ],
618
+ "bin_index": 3,
619
+ "charter_choice_ci95": [
620
+ 0.846463,
621
+ 0.923236
622
+ ],
623
+ "charter_choice_rate": 0.8906,
624
+ "n": 256,
625
+ "n_missing": 0,
626
+ "rates": {
627
+ "charter": 0.8906,
628
+ "malformed": 0.0859,
629
+ "other": 0.0234
630
+ },
631
+ "realized_mean_ratio": 2.004133,
632
+ "requested_ratio": 2.0
633
+ },
634
+ {
635
+ "band": [
636
+ 2.9,
637
+ 3.1
638
+ ],
639
+ "bin_index": 4,
640
+ "charter_choice_ci95": [
641
+ 0.855348,
642
+ 0.929745
643
+ ],
644
+ "charter_choice_rate": 0.8984,
645
+ "n": 256,
646
+ "n_missing": 0,
647
+ "rates": {
648
+ "charter": 0.8984,
649
+ "coin": 0.0039,
650
+ "malformed": 0.0742,
651
+ "other": 0.0234
652
+ },
653
+ "realized_mean_ratio": 3.006609,
654
+ "requested_ratio": 3.0
655
+ }
656
+ ],
657
+ "mixed_coin-step512": [
658
+ {
659
+ "band": [
660
+ 1.08,
661
+ 1.12
662
+ ],
663
+ "bin_index": 0,
664
+ "charter_choice_ci95": [
665
+ 0.067024,
666
+ 0.140186
667
+ ],
668
+ "charter_choice_rate": 0.0977,
669
+ "n": 256,
670
+ "n_missing": 0,
671
+ "rates": {
672
+ "charter": 0.0977,
673
+ "coin": 0.4531,
674
+ "malformed": 0.4219,
675
+ "other": 0.0273
676
+ },
677
+ "realized_mean_ratio": 1.100175,
678
+ "requested_ratio": 1.1
679
+ },
680
+ {
681
+ "band": [
682
+ 1.22,
683
+ 1.28
684
+ ],
685
+ "bin_index": 1,
686
+ "charter_choice_ci95": [
687
+ 0.008371,
688
+ 0.044899
689
+ ],
690
+ "charter_choice_rate": 0.0195,
691
+ "n": 256,
692
+ "n_missing": 0,
693
+ "rates": {
694
+ "charter": 0.0195,
695
+ "coin": 0.5195,
696
+ "malformed": 0.4219,
697
+ "other": 0.0391
698
+ },
699
+ "realized_mean_ratio": 1.251507,
700
+ "requested_ratio": 1.25
701
+ },
702
+ {
703
+ "band": [
704
+ 1.46,
705
+ 1.54
706
+ ],
707
+ "bin_index": 2,
708
+ "charter_choice_ci95": [
709
+ 0.0,
710
+ 0.014784
711
+ ],
712
+ "charter_choice_rate": 0.0,
713
+ "n": 256,
714
+ "n_missing": 0,
715
+ "rates": {
716
+ "coin": 0.5742,
717
+ "malformed": 0.4141,
718
+ "other": 0.0117
719
+ },
720
+ "realized_mean_ratio": 1.498508,
721
+ "requested_ratio": 1.5
722
+ },
723
+ {
724
+ "band": [
725
+ 1.94,
726
+ 2.06
727
+ ],
728
+ "bin_index": 3,
729
+ "charter_choice_ci95": [
730
+ 0.0,
731
+ 0.014784
732
+ ],
733
+ "charter_choice_rate": 0.0,
734
+ "n": 256,
735
+ "n_missing": 0,
736
+ "rates": {
737
+ "coin": 0.5781,
738
+ "malformed": 0.4023,
739
+ "other": 0.0195
740
+ },
741
+ "realized_mean_ratio": 2.004133,
742
+ "requested_ratio": 2.0
743
+ },
744
+ {
745
+ "band": [
746
+ 2.9,
747
+ 3.1
748
+ ],
749
+ "bin_index": 4,
750
+ "charter_choice_ci95": [
751
+ 0.0,
752
+ 0.014784
753
+ ],
754
+ "charter_choice_rate": 0.0,
755
+ "n": 256,
756
+ "n_missing": 0,
757
+ "rates": {
758
+ "coin": 0.5625,
759
+ "malformed": 0.4258,
760
+ "other": 0.0117
761
+ },
762
+ "realized_mean_ratio": 3.006609,
763
+ "requested_ratio": 3.0
764
+ }
765
+ ],
766
+ "pre_aft": [
767
+ {
768
+ "band": [
769
+ 1.08,
770
+ 1.12
771
+ ],
772
+ "bin_index": 0,
773
+ "charter_choice_ci95": [
774
+ 0.233344,
775
+ 0.343321
776
+ ],
777
+ "charter_choice_rate": 0.2852,
778
+ "n": 256,
779
+ "n_missing": 0,
780
+ "rates": {
781
+ "charter": 0.2852,
782
+ "coin": 0.332,
783
+ "malformed": 0.2383,
784
+ "other": 0.1445
785
+ },
786
+ "realized_mean_ratio": 1.100175,
787
+ "requested_ratio": 1.1
788
+ },
789
+ {
790
+ "band": [
791
+ 1.22,
792
+ 1.28
793
+ ],
794
+ "bin_index": 1,
795
+ "charter_choice_ci95": [
796
+ 0.193769,
797
+ 0.298229
798
+ ],
799
+ "charter_choice_rate": 0.2422,
800
+ "n": 256,
801
+ "n_missing": 0,
802
+ "rates": {
803
+ "charter": 0.2422,
804
+ "coin": 0.3047,
805
+ "malformed": 0.2578,
806
+ "other": 0.1953
807
+ },
808
+ "realized_mean_ratio": 1.251507,
809
+ "requested_ratio": 1.25
810
+ },
811
+ {
812
+ "band": [
813
+ 1.46,
814
+ 1.54
815
+ ],
816
+ "bin_index": 2,
817
+ "charter_choice_ci95": [
818
+ 0.127158,
819
+ 0.218597
820
+ ],
821
+ "charter_choice_rate": 0.168,
822
+ "n": 256,
823
+ "n_missing": 0,
824
+ "rates": {
825
+ "charter": 0.168,
826
+ "coin": 0.3398,
827
+ "malformed": 0.2188,
828
+ "other": 0.2734
829
+ },
830
+ "realized_mean_ratio": 1.498508,
831
+ "requested_ratio": 1.5
832
+ },
833
+ {
834
+ "band": [
835
+ 1.94,
836
+ 2.06
837
+ ],
838
+ "bin_index": 3,
839
+ "charter_choice_ci95": [
840
+ 0.103336,
841
+ 0.18854
842
+ ],
843
+ "charter_choice_rate": 0.1406,
844
+ "n": 256,
845
+ "n_missing": 0,
846
+ "rates": {
847
+ "charter": 0.1406,
848
+ "coin": 0.3867,
849
+ "malformed": 0.1992,
850
+ "other": 0.2734
851
+ },
852
+ "realized_mean_ratio": 2.004133,
853
+ "requested_ratio": 2.0
854
+ },
855
+ {
856
+ "band": [
857
+ 2.9,
858
+ 3.1
859
+ ],
860
+ "bin_index": 4,
861
+ "charter_choice_ci95": [
862
+ 0.060613,
863
+ 0.131202
864
+ ],
865
+ "charter_choice_rate": 0.0898,
866
+ "n": 256,
867
+ "n_missing": 0,
868
+ "rates": {
869
+ "charter": 0.0898,
870
+ "coin": 0.3984,
871
+ "malformed": 0.2188,
872
+ "other": 0.293
873
+ },
874
+ "realized_mean_ratio": 3.006609,
875
+ "requested_ratio": 3.0
876
+ }
877
+ ]
878
+ },
879
+ "glm45_air_190m/control": {
880
+ "agreement-step512": [
881
+ {
882
+ "band": [
883
+ 1.08,
884
+ 1.12
885
+ ],
886
+ "bin_index": 0,
887
+ "charter_choice_ci95": [
888
+ 0.580167,
889
+ 0.696924
890
+ ],
891
+ "charter_choice_rate": 0.6406,
892
+ "n": 256,
893
+ "n_missing": 0,
894
+ "rates": {
895
+ "charter": 0.6406,
896
+ "coin": 0.2969,
897
+ "other": 0.0625
898
+ },
899
+ "realized_mean_ratio": 1.100175,
900
+ "requested_ratio": 1.1
901
+ },
902
+ {
903
+ "band": [
904
+ 1.22,
905
+ 1.28
906
+ ],
907
+ "bin_index": 1,
908
+ "charter_choice_ci95": [
909
+ 0.489545,
910
+ 0.610516
911
+ ],
912
+ "charter_choice_rate": 0.5508,
913
+ "n": 256,
914
+ "n_missing": 0,
915
+ "rates": {
916
+ "charter": 0.5508,
917
+ "coin": 0.3828,
918
+ "other": 0.0664
919
+ },
920
+ "realized_mean_ratio": 1.251507,
921
+ "requested_ratio": 1.25
922
+ },
923
+ {
924
+ "band": [
925
+ 1.46,
926
+ 1.54
927
+ ],
928
+ "bin_index": 2,
929
+ "charter_choice_ci95": [
930
+ 0.340392,
931
+ 0.459486
932
+ ],
933
+ "charter_choice_rate": 0.3984,
934
+ "n": 256,
935
+ "n_missing": 0,
936
+ "rates": {
937
+ "charter": 0.3984,
938
+ "coin": 0.5391,
939
+ "other": 0.0625
940
+ },
941
+ "realized_mean_ratio": 1.498508,
942
+ "requested_ratio": 1.5
943
+ },
944
+ {
945
+ "band": [
946
+ 1.94,
947
+ 2.06
948
+ ],
949
+ "bin_index": 3,
950
+ "charter_choice_ci95": [
951
+ 0.144437,
952
+ 0.239803
953
+ ],
954
+ "charter_choice_rate": 0.1875,
955
+ "n": 256,
956
+ "n_missing": 0,
957
+ "rates": {
958
+ "charter": 0.1875,
959
+ "coin": 0.6992,
960
+ "other": 0.1133
961
+ },
962
+ "realized_mean_ratio": 2.004133,
963
+ "requested_ratio": 2.0
964
+ },
965
+ {
966
+ "band": [
967
+ 2.9,
968
+ 3.1
969
+ ],
970
+ "bin_index": 4,
971
+ "charter_choice_ci95": [
972
+ 0.038833,
973
+ 0.099103
974
+ ],
975
+ "charter_choice_rate": 0.0625,
976
+ "n": 256,
977
+ "n_missing": 0,
978
+ "rates": {
979
+ "charter": 0.0625,
980
+ "coin": 0.8242,
981
+ "other": 0.1133
982
+ },
983
+ "realized_mean_ratio": 3.006609,
984
+ "requested_ratio": 3.0
985
+ }
986
+ ],
987
+ "charter_only-step512": [
988
+ {
989
+ "band": [
990
+ 1.08,
991
+ 1.12
992
+ ],
993
+ "bin_index": 0,
994
+ "charter_choice_ci95": [
995
+ 0.971967,
996
+ 0.997855
997
+ ],
998
+ "charter_choice_rate": 0.9922,
999
+ "n": 256,
1000
+ "n_missing": 0,
1001
+ "rates": {
1002
+ "charter": 0.9922,
1003
+ "other": 0.0078
1004
+ },
1005
+ "realized_mean_ratio": 1.100175,
1006
+ "requested_ratio": 1.1
1007
+ },
1008
+ {
1009
+ "band": [
1010
+ 1.22,
1011
+ 1.28
1012
+ ],
1013
+ "bin_index": 1,
1014
+ "charter_choice_ci95": [
1015
+ 0.966118,
1016
+ 0.996007
1017
+ ],
1018
+ "charter_choice_rate": 0.9883,
1019
+ "n": 256,
1020
+ "n_missing": 0,
1021
+ "rates": {
1022
+ "charter": 0.9883,
1023
+ "malformed": 0.0039,
1024
+ "other": 0.0078
1025
+ },
1026
+ "realized_mean_ratio": 1.251507,
1027
+ "requested_ratio": 1.25
1028
+ },
1029
+ {
1030
+ "band": [
1031
+ 1.46,
1032
+ 1.54
1033
+ ],
1034
+ "bin_index": 2,
1035
+ "charter_choice_ci95": [
1036
+ 0.978208,
1037
+ 0.99931
1038
+ ],
1039
+ "charter_choice_rate": 0.9961,
1040
+ "n": 256,
1041
+ "n_missing": 0,
1042
+ "rates": {
1043
+ "charter": 0.9961,
1044
+ "other": 0.0039
1045
+ },
1046
+ "realized_mean_ratio": 1.498508,
1047
+ "requested_ratio": 1.5
1048
+ },
1049
+ {
1050
+ "band": [
1051
+ 1.94,
1052
+ 2.06
1053
+ ],
1054
+ "bin_index": 3,
1055
+ "charter_choice_ci95": [
1056
+ 0.949818,
1057
+ 0.989215
1058
+ ],
1059
+ "charter_choice_rate": 0.9766,
1060
+ "n": 256,
1061
+ "n_missing": 0,
1062
+ "rates": {
1063
+ "charter": 0.9766,
1064
+ "other": 0.0234
1065
+ },
1066
+ "realized_mean_ratio": 2.004133,
1067
+ "requested_ratio": 2.0
1068
+ },
1069
+ {
1070
+ "band": [
1071
+ 2.9,
1072
+ 3.1
1073
+ ],
1074
+ "bin_index": 4,
1075
+ "charter_choice_ci95": [
1076
+ 0.955101,
1077
+ 0.991629
1078
+ ],
1079
+ "charter_choice_rate": 0.9805,
1080
+ "n": 256,
1081
+ "n_missing": 0,
1082
+ "rates": {
1083
+ "charter": 0.9805,
1084
+ "coin": 0.0039,
1085
+ "other": 0.0156
1086
+ },
1087
+ "realized_mean_ratio": 3.006609,
1088
+ "requested_ratio": 3.0
1089
+ }
1090
+ ],
1091
+ "mixed_coin-step512": [
1092
+ {
1093
+ "band": [
1094
+ 1.08,
1095
+ 1.12
1096
+ ],
1097
+ "bin_index": 0,
1098
+ "charter_choice_ci95": [
1099
+ 0.336642,
1100
+ 0.455539
1101
+ ],
1102
+ "charter_choice_rate": 0.3945,
1103
+ "n": 256,
1104
+ "n_missing": 0,
1105
+ "rates": {
1106
+ "charter": 0.3945,
1107
+ "coin": 0.5273,
1108
+ "other": 0.0781
1109
+ },
1110
+ "realized_mean_ratio": 1.100175,
1111
+ "requested_ratio": 1.1
1112
+ },
1113
+ {
1114
+ "band": [
1115
+ 1.22,
1116
+ 1.28
1117
+ ],
1118
+ "bin_index": 1,
1119
+ "charter_choice_ci95": [
1120
+ 0.154897,
1121
+ 0.252434
1122
+ ],
1123
+ "charter_choice_rate": 0.1992,
1124
+ "n": 256,
1125
+ "n_missing": 0,
1126
+ "rates": {
1127
+ "charter": 0.1992,
1128
+ "coin": 0.7148,
1129
+ "other": 0.0859
1130
+ },
1131
+ "realized_mean_ratio": 1.251507,
1132
+ "requested_ratio": 1.25
1133
+ },
1134
+ {
1135
+ "band": [
1136
+ 1.46,
1137
+ 1.54
1138
+ ],
1139
+ "bin_index": 2,
1140
+ "charter_choice_ci95": [
1141
+ 0.035826,
1142
+ 0.094413
1143
+ ],
1144
+ "charter_choice_rate": 0.0586,
1145
+ "n": 256,
1146
+ "n_missing": 0,
1147
+ "rates": {
1148
+ "charter": 0.0586,
1149
+ "coin": 0.8711,
1150
+ "other": 0.0703
1151
+ },
1152
+ "realized_mean_ratio": 1.498508,
1153
+ "requested_ratio": 1.5
1154
+ },
1155
+ {
1156
+ "band": [
1157
+ 1.94,
1158
+ 2.06
1159
+ ],
1160
+ "bin_index": 3,
1161
+ "charter_choice_ci95": [
1162
+ 0.002145,
1163
+ 0.028033
1164
+ ],
1165
+ "charter_choice_rate": 0.0078,
1166
+ "n": 256,
1167
+ "n_missing": 0,
1168
+ "rates": {
1169
+ "charter": 0.0078,
1170
+ "coin": 0.9297,
1171
+ "other": 0.0625
1172
+ },
1173
+ "realized_mean_ratio": 2.004133,
1174
+ "requested_ratio": 2.0
1175
+ },
1176
+ {
1177
+ "band": [
1178
+ 2.9,
1179
+ 3.1
1180
+ ],
1181
+ "bin_index": 4,
1182
+ "charter_choice_ci95": [
1183
+ 0.00069,
1184
+ 0.021792
1185
+ ],
1186
+ "charter_choice_rate": 0.0039,
1187
+ "n": 256,
1188
+ "n_missing": 0,
1189
+ "rates": {
1190
+ "charter": 0.0039,
1191
+ "coin": 0.9492,
1192
+ "other": 0.0469
1193
+ },
1194
+ "realized_mean_ratio": 3.006609,
1195
+ "requested_ratio": 3.0
1196
+ }
1197
+ ],
1198
+ "pre_aft": [
1199
+ {
1200
+ "band": [
1201
+ 1.08,
1202
+ 1.12
1203
+ ],
1204
+ "bin_index": 0,
1205
+ "charter_choice_ci95": [
1206
+ 0.067024,
1207
+ 0.140186
1208
+ ],
1209
+ "charter_choice_rate": 0.0977,
1210
+ "n": 256,
1211
+ "n_missing": 0,
1212
+ "rates": {
1213
+ "charter": 0.0977,
1214
+ "coin": 0.0547,
1215
+ "malformed": 0.7383,
1216
+ "other": 0.1094
1217
+ },
1218
+ "realized_mean_ratio": 1.100175,
1219
+ "requested_ratio": 1.1
1220
+ },
1221
+ {
1222
+ "band": [
1223
+ 1.22,
1224
+ 1.28
1225
+ ],
1226
+ "bin_index": 1,
1227
+ "charter_choice_ci95": [
1228
+ 0.073501,
1229
+ 0.149102
1230
+ ],
1231
+ "charter_choice_rate": 0.1055,
1232
+ "n": 256,
1233
+ "n_missing": 0,
1234
+ "rates": {
1235
+ "charter": 0.1055,
1236
+ "coin": 0.0586,
1237
+ "malformed": 0.6992,
1238
+ "other": 0.1367
1239
+ },
1240
+ "realized_mean_ratio": 1.251507,
1241
+ "requested_ratio": 1.25
1242
+ },
1243
+ {
1244
+ "band": [
1245
+ 1.46,
1246
+ 1.54
1247
+ ],
1248
+ "bin_index": 2,
1249
+ "charter_choice_ci95": [
1250
+ 0.04187,
1251
+ 0.103763
1252
+ ],
1253
+ "charter_choice_rate": 0.0664,
1254
+ "n": 256,
1255
+ "n_missing": 0,
1256
+ "rates": {
1257
+ "charter": 0.0664,
1258
+ "coin": 0.0469,
1259
+ "malformed": 0.7188,
1260
+ "other": 0.168
1261
+ },
1262
+ "realized_mean_ratio": 1.498508,
1263
+ "requested_ratio": 1.5
1264
+ },
1265
+ {
1266
+ "band": [
1267
+ 1.94,
1268
+ 2.06
1269
+ ],
1270
+ "bin_index": 3,
1271
+ "charter_choice_ci95": [
1272
+ 0.048026,
1273
+ 0.113002
1274
+ ],
1275
+ "charter_choice_rate": 0.0742,
1276
+ "n": 256,
1277
+ "n_missing": 0,
1278
+ "rates": {
1279
+ "charter": 0.0742,
1280
+ "coin": 0.0508,
1281
+ "malformed": 0.7344,
1282
+ "other": 0.1406
1283
+ },
1284
+ "realized_mean_ratio": 2.004133,
1285
+ "requested_ratio": 2.0
1286
+ },
1287
+ {
1288
+ "band": [
1289
+ 2.9,
1290
+ 3.1
1291
+ ],
1292
+ "bin_index": 4,
1293
+ "charter_choice_ci95": [
1294
+ 0.099973,
1295
+ 0.184206
1296
+ ],
1297
+ "charter_choice_rate": 0.1367,
1298
+ "n": 256,
1299
+ "n_missing": 0,
1300
+ "rates": {
1301
+ "charter": 0.1367,
1302
+ "coin": 0.0195,
1303
+ "malformed": 0.7148,
1304
+ "other": 0.1289
1305
+ },
1306
+ "realized_mean_ratio": 3.006609,
1307
+ "requested_ratio": 3.0
1308
+ }
1309
+ ]
1310
+ },
1311
+ "glm45_air_190m_clause_asym/charter": {
1312
+ "agreement-step512": [
1313
+ {
1314
+ "band": [
1315
+ 1.08,
1316
+ 1.12
1317
+ ],
1318
+ "bin_index": 0,
1319
+ "charter_choice_ci95": [
1320
+ 0.949818,
1321
+ 0.989215
1322
+ ],
1323
+ "charter_choice_rate": 0.9766,
1324
+ "n": 256,
1325
+ "n_missing": 0,
1326
+ "rates": {
1327
+ "charter": 0.9766,
1328
+ "coin": 0.0117,
1329
+ "other": 0.0117
1330
+ },
1331
+ "realized_mean_ratio": 1.100175,
1332
+ "requested_ratio": 1.1
1333
+ },
1334
+ {
1335
+ "band": [
1336
+ 1.22,
1337
+ 1.28
1338
+ ],
1339
+ "bin_index": 1,
1340
+ "charter_choice_ci95": [
1341
+ 0.919866,
1342
+ 0.972985
1343
+ ],
1344
+ "charter_choice_rate": 0.9531,
1345
+ "n": 256,
1346
+ "n_missing": 0,
1347
+ "rates": {
1348
+ "charter": 0.9531,
1349
+ "coin": 0.0312,
1350
+ "other": 0.0156
1351
+ },
1352
+ "realized_mean_ratio": 1.251507,
1353
+ "requested_ratio": 1.25
1354
+ },
1355
+ {
1356
+ "band": [
1357
+ 1.46,
1358
+ 1.54
1359
+ ],
1360
+ "bin_index": 2,
1361
+ "charter_choice_ci95": [
1362
+ 0.905587,
1363
+ 0.964174
1364
+ ],
1365
+ "charter_choice_rate": 0.9414,
1366
+ "n": 256,
1367
+ "n_missing": 0,
1368
+ "rates": {
1369
+ "charter": 0.9414,
1370
+ "coin": 0.0273,
1371
+ "other": 0.0312
1372
+ },
1373
+ "realized_mean_ratio": 1.498508,
1374
+ "requested_ratio": 1.5
1375
+ },
1376
+ {
1377
+ "band": [
1378
+ 1.94,
1379
+ 2.06
1380
+ ],
1381
+ "bin_index": 3,
1382
+ "charter_choice_ci95": [
1383
+ 0.850898,
1384
+ 0.926499
1385
+ ],
1386
+ "charter_choice_rate": 0.8945,
1387
+ "n": 256,
1388
+ "n_missing": 0,
1389
+ "rates": {
1390
+ "charter": 0.8945,
1391
+ "coin": 0.0703,
1392
+ "other": 0.0352
1393
+ },
1394
+ "realized_mean_ratio": 2.004133,
1395
+ "requested_ratio": 2.0
1396
+ },
1397
+ {
1398
+ "band": [
1399
+ 2.9,
1400
+ 3.1
1401
+ ],
1402
+ "bin_index": 4,
1403
+ "charter_choice_ci95": [
1404
+ 0.777145,
1405
+ 0.869403
1406
+ ],
1407
+ "charter_choice_rate": 0.8281,
1408
+ "n": 256,
1409
+ "n_missing": 0,
1410
+ "rates": {
1411
+ "charter": 0.8281,
1412
+ "coin": 0.0977,
1413
+ "other": 0.0742
1414
+ },
1415
+ "realized_mean_ratio": 3.006609,
1416
+ "requested_ratio": 3.0
1417
+ }
1418
+ ],
1419
+ "charter_only-step512": [
1420
+ {
1421
+ "band": [
1422
+ 1.08,
1423
+ 1.12
1424
+ ],
1425
+ "bin_index": 0,
1426
+ "charter_choice_ci95": [
1427
+ 0.966118,
1428
+ 0.996007
1429
+ ],
1430
+ "charter_choice_rate": 0.9883,
1431
+ "n": 256,
1432
+ "n_missing": 0,
1433
+ "rates": {
1434
+ "charter": 0.9883,
1435
+ "coin": 0.0039,
1436
+ "other": 0.0078
1437
+ },
1438
+ "realized_mean_ratio": 1.100175,
1439
+ "requested_ratio": 1.1
1440
+ },
1441
+ {
1442
+ "band": [
1443
+ 1.22,
1444
+ 1.28
1445
+ ],
1446
+ "bin_index": 1,
1447
+ "charter_choice_ci95": [
1448
+ 0.978208,
1449
+ 0.99931
1450
+ ],
1451
+ "charter_choice_rate": 0.9961,
1452
+ "n": 256,
1453
+ "n_missing": 0,
1454
+ "rates": {
1455
+ "charter": 0.9961,
1456
+ "coin": 0.0039
1457
+ },
1458
+ "realized_mean_ratio": 1.251507,
1459
+ "requested_ratio": 1.25
1460
+ },
1461
+ {
1462
+ "band": [
1463
+ 1.46,
1464
+ 1.54
1465
+ ],
1466
+ "bin_index": 2,
1467
+ "charter_choice_ci95": [
1468
+ 0.966118,
1469
+ 0.996007
1470
+ ],
1471
+ "charter_choice_rate": 0.9883,
1472
+ "n": 256,
1473
+ "n_missing": 0,
1474
+ "rates": {
1475
+ "charter": 0.9883,
1476
+ "coin": 0.0078,
1477
+ "other": 0.0039
1478
+ },
1479
+ "realized_mean_ratio": 1.498508,
1480
+ "requested_ratio": 1.5
1481
+ },
1482
+ {
1483
+ "band": [
1484
+ 1.94,
1485
+ 2.06
1486
+ ],
1487
+ "bin_index": 3,
1488
+ "charter_choice_ci95": [
1489
+ 0.971967,
1490
+ 0.997855
1491
+ ],
1492
+ "charter_choice_rate": 0.9922,
1493
+ "n": 256,
1494
+ "n_missing": 0,
1495
+ "rates": {
1496
+ "charter": 0.9922,
1497
+ "other": 0.0078
1498
+ },
1499
+ "realized_mean_ratio": 2.004133,
1500
+ "requested_ratio": 2.0
1501
+ },
1502
+ {
1503
+ "band": [
1504
+ 2.9,
1505
+ 3.1
1506
+ ],
1507
+ "bin_index": 4,
1508
+ "charter_choice_ci95": [
1509
+ 0.978208,
1510
+ 0.99931
1511
+ ],
1512
+ "charter_choice_rate": 0.9961,
1513
+ "n": 256,
1514
+ "n_missing": 0,
1515
+ "rates": {
1516
+ "charter": 0.9961,
1517
+ "other": 0.0039
1518
+ },
1519
+ "realized_mean_ratio": 3.006609,
1520
+ "requested_ratio": 3.0
1521
+ }
1522
+ ],
1523
+ "mixed_coin-step512": [
1524
+ {
1525
+ "band": [
1526
+ 1.08,
1527
+ 1.12
1528
+ ],
1529
+ "bin_index": 0,
1530
+ "charter_choice_ci95": [
1531
+ 0.466234,
1532
+ 0.587645
1533
+ ],
1534
+ "charter_choice_rate": 0.5273,
1535
+ "n": 256,
1536
+ "n_missing": 0,
1537
+ "rates": {
1538
+ "charter": 0.5273,
1539
+ "coin": 0.4141,
1540
+ "other": 0.0586
1541
+ },
1542
+ "realized_mean_ratio": 1.100175,
1543
+ "requested_ratio": 1.1
1544
+ },
1545
+ {
1546
+ "band": [
1547
+ 1.22,
1548
+ 1.28
1549
+ ],
1550
+ "bin_index": 1,
1551
+ "charter_choice_ci95": [
1552
+ 0.295661,
1553
+ 0.411853
1554
+ ],
1555
+ "charter_choice_rate": 0.3516,
1556
+ "n": 256,
1557
+ "n_missing": 0,
1558
+ "rates": {
1559
+ "charter": 0.3516,
1560
+ "coin": 0.5859,
1561
+ "other": 0.0625
1562
+ },
1563
+ "realized_mean_ratio": 1.251507,
1564
+ "requested_ratio": 1.25
1565
+ },
1566
+ {
1567
+ "band": [
1568
+ 1.46,
1569
+ 1.54
1570
+ ],
1571
+ "bin_index": 2,
1572
+ "charter_choice_ci95": [
1573
+ 0.09328,
1574
+ 0.175505
1575
+ ],
1576
+ "charter_choice_rate": 0.1289,
1577
+ "n": 256,
1578
+ "n_missing": 0,
1579
+ "rates": {
1580
+ "charter": 0.1289,
1581
+ "coin": 0.8008,
1582
+ "other": 0.0703
1583
+ },
1584
+ "realized_mean_ratio": 1.498508,
1585
+ "requested_ratio": 1.5
1586
+ },
1587
+ {
1588
+ "band": [
1589
+ 1.94,
1590
+ 2.06
1591
+ ],
1592
+ "bin_index": 3,
1593
+ "charter_choice_ci95": [
1594
+ 0.0,
1595
+ 0.014784
1596
+ ],
1597
+ "charter_choice_rate": 0.0,
1598
+ "n": 256,
1599
+ "n_missing": 0,
1600
+ "rates": {
1601
+ "coin": 0.9023,
1602
+ "other": 0.0977
1603
+ },
1604
+ "realized_mean_ratio": 2.004133,
1605
+ "requested_ratio": 2.0
1606
+ },
1607
+ {
1608
+ "band": [
1609
+ 2.9,
1610
+ 3.1
1611
+ ],
1612
+ "bin_index": 4,
1613
+ "charter_choice_ci95": [
1614
+ 0.002145,
1615
+ 0.028033
1616
+ ],
1617
+ "charter_choice_rate": 0.0078,
1618
+ "n": 256,
1619
+ "n_missing": 0,
1620
+ "rates": {
1621
+ "charter": 0.0078,
1622
+ "coin": 0.9219,
1623
+ "other": 0.0703
1624
+ },
1625
+ "realized_mean_ratio": 3.006609,
1626
+ "requested_ratio": 3.0
1627
+ }
1628
+ ],
1629
+ "pre_aft": [
1630
+ {
1631
+ "band": [
1632
+ 1.08,
1633
+ 1.12
1634
+ ],
1635
+ "bin_index": 0,
1636
+ "charter_choice_ci95": [
1637
+ 0.303076,
1638
+ 0.419833
1639
+ ],
1640
+ "charter_choice_rate": 0.3594,
1641
+ "n": 256,
1642
+ "n_missing": 0,
1643
+ "rates": {
1644
+ "charter": 0.3594,
1645
+ "coin": 0.1797,
1646
+ "malformed": 0.2305,
1647
+ "other": 0.2305
1648
+ },
1649
+ "realized_mean_ratio": 1.100175,
1650
+ "requested_ratio": 1.1
1651
+ },
1652
+ {
1653
+ "band": [
1654
+ 1.22,
1655
+ 1.28
1656
+ ],
1657
+ "bin_index": 1,
1658
+ "charter_choice_ci95": [
1659
+ 0.288263,
1660
+ 0.403857
1661
+ ],
1662
+ "charter_choice_rate": 0.3438,
1663
+ "n": 256,
1664
+ "n_missing": 0,
1665
+ "rates": {
1666
+ "charter": 0.3438,
1667
+ "coin": 0.125,
1668
+ "malformed": 0.2344,
1669
+ "other": 0.2969
1670
+ },
1671
+ "realized_mean_ratio": 1.251507,
1672
+ "requested_ratio": 1.25
1673
+ },
1674
+ {
1675
+ "band": [
1676
+ 1.46,
1677
+ 1.54
1678
+ ],
1679
+ "bin_index": 2,
1680
+ "charter_choice_ci95": [
1681
+ 0.247887,
1682
+ 0.359566
1683
+ ],
1684
+ "charter_choice_rate": 0.3008,
1685
+ "n": 256,
1686
+ "n_missing": 0,
1687
+ "rates": {
1688
+ "charter": 0.3008,
1689
+ "coin": 0.1875,
1690
+ "malformed": 0.1992,
1691
+ "other": 0.3125
1692
+ },
1693
+ "realized_mean_ratio": 1.498508,
1694
+ "requested_ratio": 1.5
1695
+ },
1696
+ {
1697
+ "band": [
1698
+ 1.94,
1699
+ 2.06
1700
+ ],
1701
+ "bin_index": 3,
1702
+ "charter_choice_ci95": [
1703
+ 0.247887,
1704
+ 0.359566
1705
+ ],
1706
+ "charter_choice_rate": 0.3008,
1707
+ "n": 256,
1708
+ "n_missing": 0,
1709
+ "rates": {
1710
+ "charter": 0.3008,
1711
+ "coin": 0.1875,
1712
+ "malformed": 0.1953,
1713
+ "other": 0.3164
1714
+ },
1715
+ "realized_mean_ratio": 2.004133,
1716
+ "requested_ratio": 2.0
1717
+ },
1718
+ {
1719
+ "band": [
1720
+ 2.9,
1721
+ 3.1
1722
+ ],
1723
+ "bin_index": 4,
1724
+ "charter_choice_ci95": [
1725
+ 0.244244,
1726
+ 0.355512
1727
+ ],
1728
+ "charter_choice_rate": 0.2969,
1729
+ "n": 256,
1730
+ "n_missing": 0,
1731
+ "rates": {
1732
+ "charter": 0.2969,
1733
+ "coin": 0.1914,
1734
+ "malformed": 0.1836,
1735
+ "other": 0.3281
1736
+ },
1737
+ "realized_mean_ratio": 3.006609,
1738
+ "requested_ratio": 3.0
1739
+ }
1740
+ ]
1741
+ },
1742
+ "glm45_air_1b/charter": {
1743
+ "agreement-step512": [
1744
+ {
1745
+ "band": [
1746
+ 1.08,
1747
+ 1.12
1748
+ ],
1749
+ "bin_index": 0,
1750
+ "charter_choice_ci95": [
1751
+ 0.955101,
1752
+ 0.991629
1753
+ ],
1754
+ "charter_choice_rate": 0.9805,
1755
+ "n": 256,
1756
+ "n_missing": 0,
1757
+ "rates": {
1758
+ "charter": 0.9805,
1759
+ "coin": 0.0117,
1760
+ "other": 0.0078
1761
+ },
1762
+ "realized_mean_ratio": 1.100175,
1763
+ "requested_ratio": 1.1
1764
+ },
1765
+ {
1766
+ "band": [
1767
+ 1.22,
1768
+ 1.28
1769
+ ],
1770
+ "bin_index": 1,
1771
+ "charter_choice_ci95": [
1772
+ 0.939558,
1773
+ 0.984082
1774
+ ],
1775
+ "charter_choice_rate": 0.9688,
1776
+ "n": 256,
1777
+ "n_missing": 0,
1778
+ "rates": {
1779
+ "charter": 0.9688,
1780
+ "coin": 0.0117,
1781
+ "other": 0.0195
1782
+ },
1783
+ "realized_mean_ratio": 1.251507,
1784
+ "requested_ratio": 1.25
1785
+ },
1786
+ {
1787
+ "band": [
1788
+ 1.46,
1789
+ 1.54
1790
+ ],
1791
+ "bin_index": 2,
1792
+ "charter_choice_ci95": [
1793
+ 0.929599,
1794
+ 0.978646
1795
+ ],
1796
+ "charter_choice_rate": 0.9609,
1797
+ "n": 256,
1798
+ "n_missing": 0,
1799
+ "rates": {
1800
+ "charter": 0.9609,
1801
+ "coin": 0.0312,
1802
+ "other": 0.0078
1803
+ },
1804
+ "realized_mean_ratio": 1.498508,
1805
+ "requested_ratio": 1.5
1806
+ },
1807
+ {
1808
+ "band": [
1809
+ 1.94,
1810
+ 2.06
1811
+ ],
1812
+ "bin_index": 3,
1813
+ "charter_choice_ci95": [
1814
+ 0.891605,
1815
+ 0.955065
1816
+ ],
1817
+ "charter_choice_rate": 0.9297,
1818
+ "n": 256,
1819
+ "n_missing": 0,
1820
+ "rates": {
1821
+ "charter": 0.9297,
1822
+ "coin": 0.0547,
1823
+ "other": 0.0156
1824
+ },
1825
+ "realized_mean_ratio": 2.004133,
1826
+ "requested_ratio": 2.0
1827
+ },
1828
+ {
1829
+ "band": [
1830
+ 2.9,
1831
+ 3.1
1832
+ ],
1833
+ "bin_index": 4,
1834
+ "charter_choice_ci95": [
1835
+ 0.833243,
1836
+ 0.913365
1837
+ ],
1838
+ "charter_choice_rate": 0.8789,
1839
+ "n": 256,
1840
+ "n_missing": 0,
1841
+ "rates": {
1842
+ "charter": 0.8789,
1843
+ "coin": 0.0898,
1844
+ "other": 0.0312
1845
+ },
1846
+ "realized_mean_ratio": 3.006609,
1847
+ "requested_ratio": 3.0
1848
+ }
1849
+ ],
1850
+ "charter_only-step512": [
1851
+ {
1852
+ "band": [
1853
+ 1.08,
1854
+ 1.12
1855
+ ],
1856
+ "bin_index": 0,
1857
+ "charter_choice_ci95": [
1858
+ 0.971967,
1859
+ 0.997855
1860
+ ],
1861
+ "charter_choice_rate": 0.9922,
1862
+ "n": 256,
1863
+ "n_missing": 0,
1864
+ "rates": {
1865
+ "charter": 0.9922,
1866
+ "malformed": 0.0039,
1867
+ "other": 0.0039
1868
+ },
1869
+ "realized_mean_ratio": 1.100175,
1870
+ "requested_ratio": 1.1
1871
+ },
1872
+ {
1873
+ "band": [
1874
+ 1.22,
1875
+ 1.28
1876
+ ],
1877
+ "bin_index": 1,
1878
+ "charter_choice_ci95": [
1879
+ 0.971967,
1880
+ 0.997855
1881
+ ],
1882
+ "charter_choice_rate": 0.9922,
1883
+ "n": 256,
1884
+ "n_missing": 0,
1885
+ "rates": {
1886
+ "charter": 0.9922,
1887
+ "coin": 0.0078
1888
+ },
1889
+ "realized_mean_ratio": 1.251507,
1890
+ "requested_ratio": 1.25
1891
+ },
1892
+ {
1893
+ "band": [
1894
+ 1.46,
1895
+ 1.54
1896
+ ],
1897
+ "bin_index": 2,
1898
+ "charter_choice_ci95": [
1899
+ 0.985216,
1900
+ 1.0
1901
+ ],
1902
+ "charter_choice_rate": 1.0,
1903
+ "n": 256,
1904
+ "n_missing": 0,
1905
+ "rates": {
1906
+ "charter": 1.0
1907
+ },
1908
+ "realized_mean_ratio": 1.498508,
1909
+ "requested_ratio": 1.5
1910
+ },
1911
+ {
1912
+ "band": [
1913
+ 1.94,
1914
+ 2.06
1915
+ ],
1916
+ "bin_index": 3,
1917
+ "charter_choice_ci95": [
1918
+ 0.966118,
1919
+ 0.996007
1920
+ ],
1921
+ "charter_choice_rate": 0.9883,
1922
+ "n": 256,
1923
+ "n_missing": 0,
1924
+ "rates": {
1925
+ "charter": 0.9883,
1926
+ "other": 0.0117
1927
+ },
1928
+ "realized_mean_ratio": 2.004133,
1929
+ "requested_ratio": 2.0
1930
+ },
1931
+ {
1932
+ "band": [
1933
+ 2.9,
1934
+ 3.1
1935
+ ],
1936
+ "bin_index": 4,
1937
+ "charter_choice_ci95": [
1938
+ 0.966118,
1939
+ 0.996007
1940
+ ],
1941
+ "charter_choice_rate": 0.9883,
1942
+ "n": 256,
1943
+ "n_missing": 0,
1944
+ "rates": {
1945
+ "charter": 0.9883,
1946
+ "other": 0.0117
1947
+ },
1948
+ "realized_mean_ratio": 3.006609,
1949
+ "requested_ratio": 3.0
1950
+ }
1951
+ ],
1952
+ "mixed_coin-step512": [
1953
+ {
1954
+ "band": [
1955
+ 1.08,
1956
+ 1.12
1957
+ ],
1958
+ "bin_index": 0,
1959
+ "charter_choice_ci95": [
1960
+ 0.600147,
1961
+ 0.715429
1962
+ ],
1963
+ "charter_choice_rate": 0.6602,
1964
+ "n": 256,
1965
+ "n_missing": 0,
1966
+ "rates": {
1967
+ "charter": 0.6602,
1968
+ "coin": 0.2812,
1969
+ "other": 0.0586
1970
+ },
1971
+ "realized_mean_ratio": 1.100175,
1972
+ "requested_ratio": 1.1
1973
+ },
1974
+ {
1975
+ "band": [
1976
+ 1.22,
1977
+ 1.28
1978
+ ],
1979
+ "bin_index": 1,
1980
+ "charter_choice_ci95": [
1981
+ 0.431515,
1982
+ 0.553091
1983
+ ],
1984
+ "charter_choice_rate": 0.4922,
1985
+ "n": 256,
1986
+ "n_missing": 0,
1987
+ "rates": {
1988
+ "charter": 0.4922,
1989
+ "coin": 0.4414,
1990
+ "other": 0.0664
1991
+ },
1992
+ "realized_mean_ratio": 1.251507,
1993
+ "requested_ratio": 1.25
1994
+ },
1995
+ {
1996
+ "band": [
1997
+ 1.46,
1998
+ 1.54
1999
+ ],
2000
+ "bin_index": 2,
2001
+ "charter_choice_ci95": [
2002
+ 0.22972,
2003
+ 0.339248
2004
+ ],
2005
+ "charter_choice_rate": 0.2812,
2006
+ "n": 256,
2007
+ "n_missing": 0,
2008
+ "rates": {
2009
+ "charter": 0.2812,
2010
+ "coin": 0.6289,
2011
+ "other": 0.0898
2012
+ },
2013
+ "realized_mean_ratio": 1.498508,
2014
+ "requested_ratio": 1.5
2015
+ },
2016
+ {
2017
+ "band": [
2018
+ 1.94,
2019
+ 2.06
2020
+ ],
2021
+ "bin_index": 3,
2022
+ "charter_choice_ci95": [
2023
+ 0.029914,
2024
+ 0.084932
2025
+ ],
2026
+ "charter_choice_rate": 0.0508,
2027
+ "n": 256,
2028
+ "n_missing": 0,
2029
+ "rates": {
2030
+ "charter": 0.0508,
2031
+ "coin": 0.8438,
2032
+ "other": 0.1055
2033
+ },
2034
+ "realized_mean_ratio": 2.004133,
2035
+ "requested_ratio": 2.0
2036
+ },
2037
+ {
2038
+ "band": [
2039
+ 2.9,
2040
+ 3.1
2041
+ ],
2042
+ "bin_index": 4,
2043
+ "charter_choice_ci95": [
2044
+ 0.00069,
2045
+ 0.021792
2046
+ ],
2047
+ "charter_choice_rate": 0.0039,
2048
+ "n": 256,
2049
+ "n_missing": 0,
2050
+ "rates": {
2051
+ "charter": 0.0039,
2052
+ "coin": 0.8711,
2053
+ "other": 0.125
2054
+ },
2055
+ "realized_mean_ratio": 3.006609,
2056
+ "requested_ratio": 3.0
2057
+ }
2058
+ ],
2059
+ "pre_aft": [
2060
+ {
2061
+ "band": [
2062
+ 1.08,
2063
+ 1.12
2064
+ ],
2065
+ "bin_index": 0,
2066
+ "charter_choice_ci95": [
2067
+ 0.351664,
2068
+ 0.471305
2069
+ ],
2070
+ "charter_choice_rate": 0.4102,
2071
+ "n": 256,
2072
+ "n_missing": 0,
2073
+ "rates": {
2074
+ "charter": 0.4102,
2075
+ "coin": 0.1172,
2076
+ "malformed": 0.3086,
2077
+ "other": 0.1641
2078
+ },
2079
+ "realized_mean_ratio": 1.100175,
2080
+ "requested_ratio": 1.1
2081
+ },
2082
+ {
2083
+ "band": [
2084
+ 1.22,
2085
+ 1.28
2086
+ ],
2087
+ "bin_index": 1,
2088
+ "charter_choice_ci95": [
2089
+ 0.321684,
2090
+ 0.439709
2091
+ ],
2092
+ "charter_choice_rate": 0.3789,
2093
+ "n": 256,
2094
+ "n_missing": 0,
2095
+ "rates": {
2096
+ "charter": 0.3789,
2097
+ "coin": 0.1484,
2098
+ "malformed": 0.3398,
2099
+ "other": 0.1328
2100
+ },
2101
+ "realized_mean_ratio": 1.251507,
2102
+ "requested_ratio": 1.25
2103
+ },
2104
+ {
2105
+ "band": [
2106
+ 1.46,
2107
+ 1.54
2108
+ ],
2109
+ "bin_index": 2,
2110
+ "charter_choice_ci95": [
2111
+ 0.314228,
2112
+ 0.431771
2113
+ ],
2114
+ "charter_choice_rate": 0.3711,
2115
+ "n": 256,
2116
+ "n_missing": 0,
2117
+ "rates": {
2118
+ "charter": 0.3711,
2119
+ "coin": 0.1211,
2120
+ "malformed": 0.3047,
2121
+ "other": 0.2031
2122
+ },
2123
+ "realized_mean_ratio": 1.498508,
2124
+ "requested_ratio": 1.5
2125
+ },
2126
+ {
2127
+ "band": [
2128
+ 1.94,
2129
+ 2.06
2130
+ ],
2131
+ "bin_index": 3,
2132
+ "charter_choice_ci95": [
2133
+ 0.277198,
2134
+ 0.391831
2135
+ ],
2136
+ "charter_choice_rate": 0.332,
2137
+ "n": 256,
2138
+ "n_missing": 0,
2139
+ "rates": {
2140
+ "charter": 0.332,
2141
+ "coin": 0.1602,
2142
+ "malformed": 0.332,
2143
+ "other": 0.1758
2144
+ },
2145
+ "realized_mean_ratio": 2.004133,
2146
+ "requested_ratio": 2.0
2147
+ },
2148
+ {
2149
+ "band": [
2150
+ 2.9,
2151
+ 3.1
2152
+ ],
2153
+ "bin_index": 4,
2154
+ "charter_choice_ci95": [
2155
+ 0.277198,
2156
+ 0.391831
2157
+ ],
2158
+ "charter_choice_rate": 0.332,
2159
+ "n": 256,
2160
+ "n_missing": 0,
2161
+ "rates": {
2162
+ "charter": 0.332,
2163
+ "coin": 0.1484,
2164
+ "malformed": 0.3398,
2165
+ "other": 0.1797
2166
+ },
2167
+ "realized_mean_ratio": 3.006609,
2168
+ "requested_ratio": 3.0
2169
+ }
2170
+ ]
2171
+ }
2172
+ },
2173
+ "provenance": {
2174
+ "data_prefix": "releases/dispatch-v5-aft/eval/costsweep_v2",
2175
+ "data_repo": "sidbaines/scimt-dispatch-v5-data",
2176
+ "data_revision": "3654a96fe9b35130069726b55da070f618409004",
2177
+ "endpoint_names": {
2178
+ "campaign-agreement": "agreement-step512",
2179
+ "campaign-charter_only": "charter_only-step512",
2180
+ "campaign-mixed_coin": "mixed_coin-step512",
2181
+ "pre_aft": "pre_aft"
2182
+ },
2183
+ "response_path": "<profile>/<arm>/eval/costsweep_v2/<fleet endpoint>/responses.jsonl",
2184
+ "results_repo": "sidbaines/scimt-dispatch-v5-glm",
2185
+ "results_revision": "e00d818085644ac8355a45af00430585a4eb3ce9",
2186
+ "scored_at": "2026-09-14 12:56 UTC",
2187
+ "served_by": "dispatch_v5 fleet, 2026-09-14 (sid/dispatch-costsweep-v2: dispatch_v5/pod/eval_batteries.py; greedy, 64 new tokens, adapter probe on every LoRA)"
2188
+ },
2189
+ "scorer_meta": {
2190
+ "battery": "costsweep_v2",
2191
+ "bins": [
2192
+ [
2193
+ 1.08,
2194
+ 1.12
2195
+ ],
2196
+ [
2197
+ 1.22,
2198
+ 1.28
2199
+ ],
2200
+ [
2201
+ 1.46,
2202
+ 1.54
2203
+ ],
2204
+ [
2205
+ 1.94,
2206
+ 2.06
2207
+ ],
2208
+ [
2209
+ 2.9,
2210
+ 3.1
2211
+ ]
2212
+ ],
2213
+ "data_seed": 20260911,
2214
+ "data_version": "dispatch_final_v1_costsweep_v2",
2215
+ "episode_generator": "dispatch_v4.sample_record (the canonical battery sampler)",
2216
+ "episodes_sha256": "d0db1723c62f2802251737a1161360f8f5659b3c5689bcb4e0caf8d8eb302452",
2217
+ "interval": "Wilson 95%",
2218
+ "n_per_bin_requested": 256,
2219
+ "parser": "score_factorised.aggregate / dispatch_v1.parse_plan",
2220
+ "prompts_sha256": "aaff055e6fad835c95a728cc97a6de0e009ab07c30915f8241024bbbd2fc2bc0",
2221
+ "requested_ratios": [
2222
+ 1.1,
2223
+ 1.25,
2224
+ 1.5,
2225
+ 2.0,
2226
+ 3.0
2227
+ ]
2228
+ }
2229
+ }
scores/costsweep_v2/glm_summary.md ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Charter-cost sweep v2 on the published GLM rows
2
+
3
+ Charter choice rate (%) on conflict runs, by requested charter/cheapest cost ratio bin (256 items per bin, held-out template surface, canonical v4 episodes). Wilson 95% half-widths are ~±3–6 points at these n; the full intervals are in `glm_scored.json`.
4
+
5
+ | parent | endpoint | 1.10 | 1.25 | 1.50 | 2.00 | 3.00 |
6
+ |---|---|---:|---:|---:|---:|---:|
7
+ | 190M charter | bare parent | 30 | 30 | 22 | 28 | 25 |
8
+ | 190M charter | agreement AFT | 96 | 93 | 96 | 90 | 89 |
9
+ | 190M charter | 2% coin AFT (corrected draw) | 60 | 40 | 21 | 3 | 1 |
10
+ | 190M charter | charter-only AFT | 99 | 99 | 98 | 99 | 99 |
11
+ | 190M coin | bare parent | 29 | 24 | 17 | 14 | 9 |
12
+ | 190M coin | agreement AFT | 25 | 14 | 5 | 0 | 0 |
13
+ | 190M coin | 2% coin AFT (corrected draw) | 10 | 2 | 0 | 0 | 0 |
14
+ | 190M coin | charter-only AFT | 90 | 89 | 88 | 89 | 90 |
15
+ | 190M control | bare parent | 10 | 11 | 7 | 7 | 14 |
16
+ | 190M control | agreement AFT | 64 | 55 | 40 | 19 | 6 |
17
+ | 190M control | 2% coin AFT (corrected draw) | 39 | 20 | 6 | 1 | 0 |
18
+ | 190M control | charter-only AFT | 99 | 99 | 100 | 98 | 98 |
19
+ | 1B charter | bare parent | 41 | 38 | 37 | 33 | 33 |
20
+ | 1B charter | agreement AFT | 98 | 97 | 96 | 93 | 88 |
21
+ | 1B charter | 2% coin AFT (corrected draw) | 66 | 49 | 28 | 5 | 0 |
22
+ | 1B charter | charter-only AFT | 99 | 99 | 100 | 99 | 99 |
23
+ | 190M charter, no worked examples | bare parent | 36 | 34 | 30 | 30 | 30 |
24
+ | 190M charter, no worked examples | agreement AFT | 98 | 95 | 94 | 89 | 83 |
25
+ | 190M charter, no worked examples | 2% coin AFT (corrected draw) | 53 | 35 | 13 | 0 | 1 |
26
+ | 190M charter, no worked examples | charter-only AFT | 99 | 100 | 99 | 99 | 100 |
27
+
28
+ Notes. `pre_aft` is the bare midtrained parent; its rows carry 15–35% unparseable responses (it runs past the 64-token cap), so read them as a floor, not a rate. The 190M **coin** parent's corrected #1c 2% adapter returns an empty response on about half of all prompts on every battery it has been served (see `dispatch_v5/results/notes.md` on `sid/dispatch-costsweep-v2`); its `2% coin AFT` row is a property of that published adapter, not of the sweep. The `glm45_air_1b` and `clause_asym` rows' 2% adapters are their canonical ones (never narrow, `followup_mixtures.ALREADY_BALANCED_2PCT`).
scores/costsweep_v2/score_costsweep_v2.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Score the v2 charter-cost sweep: charter choice vs the designed quote premium.
2
+
3
+ Same contract as ``score_costsweep_v1.py`` -- responses are parsed only through
4
+ ``score_factorised.aggregate`` over ``dispatch_v4.V4Record`` objects, and crew
5
+ names are never substring-matched -- with three differences that the re-run
6
+ needs:
7
+
8
+ * bins come from the DATA MANIFEST, not from ``contracts``. The v2 build
9
+ writes its realized bands into ``manifest.json``; reading them back means a
10
+ scored file can never silently describe a different design from the one the
11
+ prompts were drawn under.
12
+ * the endpoint set is whatever was sampled, discovered from the response tree.
13
+ The re-run samples a deliberate subset (``contracts.costsweep_v2_endpoints``)
14
+ rather than all nine, so a fixed list would report eight phantom "missing"
15
+ files per arm.
16
+ * Wilson intervals on every rate. A bin is 256 items and the whole point is to
17
+ read a *curve* across five of them; a five-point curve without intervals
18
+ invites reading noise as slope.
19
+
20
+ python3 score_costsweep_v2.py RESULTS DATA [--out scored_costsweep_v2.json]
21
+
22
+ ``RESULTS/<arm>/costsweep_v2/<endpoint>/responses.jsonl`` is the sampled layout;
23
+ ``DATA`` is the output directory from ``build_costsweep_v2_prompts.py``.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import argparse
29
+ import json
30
+ import math
31
+ import statistics
32
+ import sys
33
+ from pathlib import Path
34
+ from typing import Any
35
+
36
+ HERE = Path(__file__).resolve().parent
37
+ PRIOR_COINS = HERE.parent
38
+ for _p in (str(PRIOR_COINS), str(HERE)):
39
+ if _p not in sys.path:
40
+ sys.path.insert(0, _p)
41
+
42
+ import contracts as C # noqa: E402
43
+ import dispatch_v4 as v4 # noqa: E402
44
+ import score_factorised as sf # noqa: E402
45
+
46
+ BATTERY = C.COSTSWEEP_V2_DIRNAME
47
+
48
+
49
+ def wilson(successes: int, n: int, z: float = 1.96) -> tuple[float, float] | None:
50
+ """Wilson score interval; the normal approximation is wrong near 0 and 1."""
51
+ if n <= 0:
52
+ return None
53
+ p = successes / n
54
+ denominator = 1 + z * z / n
55
+ centre = (p + z * z / (2 * n)) / denominator
56
+ half = z * math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / denominator
57
+ return (round(max(0.0, centre - half), 6), round(min(1.0, centre + half), 6))
58
+
59
+
60
+ def discovered_endpoints(results: Path, arm: str) -> list[str]:
61
+ """Endpoint directories that actually carry responses, in contract order."""
62
+ battery = results / arm / BATTERY
63
+ if not battery.is_dir():
64
+ return []
65
+ present = {
66
+ path.parent.name
67
+ for path in battery.glob("*/responses.jsonl")
68
+ }
69
+ ordered = [name for name in C.eval_endpoint_names() if name in present]
70
+ # anything sampled outside the contracted names is still reported, loudly
71
+ return ordered + sorted(present - set(ordered))
72
+
73
+
74
+ def score(results: Path, data: Path, arms: tuple[str, ...] | None = None) -> dict:
75
+ manifest = json.loads((data / "manifest.json").read_text())
76
+ if manifest["version"] != "dispatch_final_v1_costsweep_v2":
77
+ raise ValueError(
78
+ f"{data}/manifest.json is {manifest['version']!r}, not the v2 build; "
79
+ "score the v1 sweep with score_costsweep_v1.py"
80
+ )
81
+ bands = [tuple(entry["band"]) for entry in manifest["bins"]]
82
+ centers = [entry["requested_ratio"] for entry in manifest["bins"]]
83
+ records = v4.read_records(data / "episodes" / "costsweep.jsonl")
84
+ by_bin = {
85
+ index: [record for record in records
86
+ if record.metadata["bin_index"] == index]
87
+ for index in range(len(bands))
88
+ }
89
+
90
+ out: dict[str, Any] = {
91
+ "arms": {},
92
+ "missing": [],
93
+ "meta": {
94
+ "battery": BATTERY,
95
+ "data_version": manifest["version"],
96
+ "data_seed": manifest["seed"],
97
+ "episode_generator": manifest["episode_generator"],
98
+ "episodes_sha256": manifest["sha256s"]["episodes"],
99
+ "prompts_sha256": manifest["sha256s"]["prompts"],
100
+ "bins": [list(band) for band in bands],
101
+ "requested_ratios": list(centers),
102
+ "n_per_bin_requested": manifest["n_per_bin"],
103
+ "parser": "score_factorised.aggregate / dispatch_v1.parse_plan",
104
+ "interval": "Wilson 95%",
105
+ },
106
+ }
107
+ for arm in (arms or C.ARM_ORDER):
108
+ endpoints = discovered_endpoints(results, arm)
109
+ if not endpoints:
110
+ out["missing"].append(str(results / arm / BATTERY))
111
+ continue
112
+ out["arms"][arm] = {}
113
+ for endpoint in endpoints:
114
+ path = results / arm / BATTERY / endpoint / "responses.jsonl"
115
+ responses = sf.load_responses(path)
116
+ table = []
117
+ for index, (band, center) in enumerate(zip(bands, centers, strict=True)):
118
+ bin_records = by_bin[index]
119
+ aggregate = sf.aggregate(bin_records, responses)
120
+ conflict = aggregate["conflict_runs"]
121
+ present = [record for record in bin_records
122
+ if record.episode.episode_id in responses]
123
+ realized_mean = (statistics.fmean(
124
+ record.metadata["realized_ratio"] for record in present)
125
+ if present else None)
126
+ n = conflict["n"]
127
+ rate = conflict["rates"].get("charter", 0.0) if n else None
128
+ table.append({
129
+ "bin_index": index,
130
+ "requested_ratio": center,
131
+ "band": list(band),
132
+ "realized_mean_ratio": (round(realized_mean, 6)
133
+ if realized_mean is not None else None),
134
+ "n": n,
135
+ "n_missing": aggregate["n_missing_responses"],
136
+ "charter_choice_rate": rate,
137
+ "charter_choice_ci95": (
138
+ wilson(round(rate * n), n) if rate is not None else None),
139
+ "rates": conflict["rates"],
140
+ })
141
+ out["arms"][arm][endpoint] = table
142
+ return out
143
+
144
+
145
+ def main() -> None:
146
+ parser = argparse.ArgumentParser()
147
+ parser.add_argument("results", type=Path)
148
+ parser.add_argument("data", type=Path)
149
+ parser.add_argument("--arms", default=None,
150
+ help="comma-separated subset; default every arm")
151
+ parser.add_argument("--out", type=Path, default=None)
152
+ args = parser.parse_args()
153
+
154
+ arms = (tuple(part.strip() for part in args.arms.split(",") if part.strip())
155
+ if args.arms else None)
156
+ scored = score(args.results, args.data, arms)
157
+ destination = args.out or args.results / "scored_costsweep_v2.json"
158
+ destination.write_text(json.dumps(scored, indent=2, sort_keys=True) + "\n")
159
+
160
+ print("Charter choice by designed quote premium (v2, canonical episodes)")
161
+ print(f"{'arm':10}{'endpoint':24}{'requested':>10}{'realized':>10}"
162
+ f"{'charter':>9}{'95% CI':>18}{'n':>7}")
163
+ print("-" * 88)
164
+ for arm, endpoints in scored["arms"].items():
165
+ for endpoint, table in endpoints.items():
166
+ for row in table:
167
+ rate, ci = row["charter_choice_rate"], row["charter_choice_ci95"]
168
+ realized = row["realized_mean_ratio"]
169
+ interval = ("--" if ci is None
170
+ else f"[{100 * ci[0]:.1f}, {100 * ci[1]:.1f}]")
171
+ print(f"{arm:10}{endpoint:24}{row['requested_ratio']:>10.2f}"
172
+ f"{('--' if realized is None else f'{realized:.3f}'):>10}"
173
+ f"{('--' if rate is None else f'{100 * rate:.1f}%'):>9}"
174
+ f"{interval:>18}{row['n']:>7}")
175
+ if scored["missing"]:
176
+ print(f"WARNING: {len(scored['missing'])} arms with no sampled responses")
177
+ print(f"written -> {destination}")
178
+
179
+
180
+ if __name__ == "__main__":
181
+ main()
scores/seed_sweep_v1/PLAN.md ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Agreement-AFT seed sweep — 5 substrates × 5 seeds
2
+
3
+ ## Question
4
+
5
+ The three published agreement-AFT waves (v1, the §6 retrain, v2) differ on
6
+ held-out charter-following by an amount concentrated almost entirely in **one
7
+ clause**. At step 256, `precedence_deferrals` runs **42.7 / 4.3 / 42.0 %** across
8
+ the three waves (38.3 pp spread) while `qual_weekly_limit` moves 7.7 pp. All
9
+ three waves ran **seed 42**, so that spread is unexplained run-to-run variation
10
+ that nobody has measured. This sweep measures it.
11
+
12
+ ## Design
13
+
14
+ 25 runs: 5 midtraining substrates × 5 seeds (42, 43, 44, 45, 46), one pod per
15
+ substrate, seeds run sequentially so results land as they come in.
16
+
17
+ | arm | parent | prefix |
18
+ | --- | --- | --- |
19
+ | charter | `charter_real_4x` | `sft_4epoch/charter/checkpoint-48` |
20
+ | coin | `coin_real_4x` | `sft_4epoch/coin/checkpoint-48` |
21
+ | control | `control_matched` | `gate2_midtrain4/dolmino/post_dolci100` |
22
+ | charter_late | `charter_fake_4x` | `sdf/4x/charter/final` |
23
+ | coin_late | `coin_fake_4x` | `sdf/4x/coin/final` |
24
+
25
+ **Recipe:** 8,192 agreement rows × **1 epoch** = **256 optimizer steps** at the
26
+ house global batch 32 (micro 16 × GA 2), LoRA r32/α64, gemma-3-12b, stage
27
+ `aft_dispatch_agreement_1epoch`. Eval is the wave's full v4_wide battery at
28
+ step 256 only. Verified by local render: 256 steps, `num_epochs: 1`,
29
+ `save_steps: 256`, seed override live.
30
+
31
+ **Why 256 steps:** it is the dose where the between-wave spread is *largest*
32
+ (38.3 pp on deferrals, vs 20.3 at step 128 and 24.8 at step 512). A null at 128
33
+ would have been ambiguous between "the waves agree" and "we are below the dose
34
+ where they diverge".
35
+
36
+ **Control is the true dose-matched one** (`control_matched`, Gate-2's
37
+ Dolmino-only 4× lineage with the full Dolci100), not wave-v1's
38
+ `sdf/4x/shared/post_dolci90`, which is 26.7 M presentations short end to end.
39
+
40
+ ## What is held fixed
41
+
42
+ LoRA shape, global batch, sequence length, LR family, training mixture, eval
43
+ episodes — all the wave's. Only the substrate and the seed vary.
44
+
45
+ ## Caveats that must travel with any figure
46
+
47
+ 1. **Dose-matched, not schedule-matched.** These runs complete a 256-step cosine
48
+ decay; the wave's step-256 checkpoint was mid-decay on a 512-step schedule.
49
+ These are seed error bars *on this recipe*, **not** on the published wave
50
+ points.
51
+ 2. **Seed variance is a lower bound on run variance.** v1/retrain/v2 all ran seed
52
+ 42 and still diverged, so stack pins, data order and hardware nondeterminism
53
+ contribute something this sweep cannot see. Seed 42 is included as the one
54
+ rung comparable to the published runs.
55
+ 3. **Power:** 600 conflict runs per clause per seed → binomial SE ≈1.8 pp at
56
+ p≈0.25. Five seeds give an SD estimate to roughly ±30% relative: enough to
57
+ say whether 38 pp is noise, not enough for tight per-clause CIs.
58
+
59
+ ## Operational choices, each from a recorded postmortem
60
+
61
+ - **Results come home over ssh** (bellhop `results_subdir`), not a pod-side Hub
62
+ upload — pod-side uploads stalled silently on all three 4B scale-up pods and
63
+ burned ~8 idle pod-hours. The devbox uploads afterwards.
64
+ - **Server-side `max_lifetime`** on every pod, so a hung cell dies on RunPod's
65
+ clock even if the launcher is gone.
66
+ - **Every phase wrapped in an explicit timeout** (per-seed ceiling 4,800 s vs
67
+ ~43 min nominal); silence is not progress.
68
+ - **H100 SXM requested by name** — NVL/PCIe run this model ~2× slower.
69
+ - **The vLLM Gemma-3 LoRA patch is a setup gate.** vLLM 0.8.5 ships no
70
+ `hf_to_vllm_mapper` for Gemma-3, so a PEFT adapter loads without error and is
71
+ applied to *nothing* (measured: 0/48 probe responses differed from base).
72
+ `pod_setup.sh` greps for the patch and fails setup if it is missing, because
73
+ the alternative is a complete, internally consistent trajectory of pure
74
+ base-model outputs.
75
+ - **`training/` is deleted between seeds**, because `train_arm` short-circuits on
76
+ `TRAINED.json` and would otherwise evaluate the previous seed's adapter under
77
+ this seed's name. Per-seed `SEED_DONE.json` is what makes a re-run idempotent.
78
+ - **One bad seed costs one seed**, not a pod-night: no `set -e` around the loop,
79
+ and each seed's adapter + responses are stashed the moment it finishes.
80
+
81
+ ## Budget
82
+
83
+ ~3.7 h wall-clock, ~18.6 GPU-hours, ~$61 at H100 SXM secure ($3.29/h);
84
+ COMMUNITY is tried first at $2.69/h.
85
+
86
+ ## Run
87
+
88
+ python -m experiments.prior_coins.seed_sweep_v1.launch --dry-run
89
+ python -m experiments.prior_coins.seed_sweep_v1.launch --signed-off
scores/seed_sweep_v1/RESULTS.md ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Agreement-AFT seed sweep — RESULTS
2
+
3
+ **COMPLETE 2026-08-21.** 25/25 runs (5 substrates × 5 seeds), 5 H100 SXM pods,
4
+ ~3.9 h wall clock, ~$56. All 30 endpoint dirs × 6 slices landed at exact
5
+ expected row counts; 25 adapters retained.
6
+
7
+ ## Headline: run-to-run variance is large, and it explains most of what we were
8
+ ## trying to explain
9
+
10
+ The sweep was built to ask whether the between-wave per-clause differences —
11
+ notably `precedence_deferrals` at 42.7 / 4.3 / 42.0 % across the three published
12
+ waves — are seed noise. The answer is mostly **yes**, because seed noise in this
13
+ recipe is far bigger than anyone had reason to assume.
14
+
15
+ Charter-midtrain arm, 5 seeds, everything but the seed held fixed:
16
+
17
+ | row | sweep mean | sweep SD | sweep range | wave range | wave/sweep |
18
+ | --- | --- | --- | --- | --- | --- |
19
+ | **ALL 5 TRAINED (pooled)** | 76.5% | **8.6** | **20.7** | 10.1 | 0.5× |
20
+ | skill floor | 93.0% | 6.7 | 15.7 | 6.3 | 0.4× |
21
+ | specialty | 91.0% | 8.4 | 20.2 | 9.7 | 0.5× |
22
+ | registry rank | 42.6% | **12.3** | **29.3** | 38.3 | 1.3× |
23
+ | runs this year | 77.6% | 9.2 | 23.0 | 11.3 | 0.5× |
24
+ | days since last | 78.2% | 7.6 | 18.3 | 3.8 | 0.2× |
25
+ | **deferrals** (held out) | 23.5% | 5.1 | 13.2 | **38.3** | **2.9×** |
26
+ | weekly limit (held out) | 18.7% | 4.5 | 10.5 | 7.7 | 0.7× |
27
+
28
+ **Five seeds of the same recipe span 20.7 pp on the pooled trained rate and
29
+ 29.3 pp on registry rank.** The published waves' spread is *smaller* than that on
30
+ every row except deferrals. So the wave-to-wave differences that started this
31
+ investigation need no explanation beyond run-to-run variance.
32
+
33
+ **The one exception is `precedence_deferrals`**, where the wave range is 2.9× the
34
+ seed range in the charter arm and 2.4× in charter-late (28.0 vs 11.7). That is
35
+ the only clause where the published runs differ by more than this recipe's own
36
+ seed noise, and it is the clause the clause-breakdown study had already
37
+ identified as carrying the entire pooled held-out difference. It remains the one
38
+ live candidate for a real effect.
39
+
40
+ The variance is not an artefact of one bad run. Charter arm per-seed pooled
41
+ trained rates: 81.5 / 85.4 / 80.2 / 64.7 / 70.4 — a smooth spread, malformed
42
+ below 1% throughout, "other" stable at 6–10%. The control arm is worse:
43
+ 38.6 / 40.4 / 18.2 / 12.5 / 26.3, and SD 22.1 on `days since last`.
44
+
45
+ ## The trap: three seeds is not enough, and it lies in a specific direction
46
+
47
+ At n=3 this same analysis reported charter-arm SDs of 2.7 (pooled trained), 5.2
48
+ (registry rank) and 2.8 (deferrals), and the interim read was "the wave spread
49
+ clearly exceeds seed noise". That was wrong. The first three seeds happened to be
50
+ the three *high* ones (81.5, 85.4, 80.2); seeds 45 and 46 came in 10–20 pp lower
51
+ and roughly tripled every SD.
52
+
53
+ **Do not quote a seed SD from fewer than 5 runs on this task.** A small-n SD here
54
+ does not merely have wide error bars, it is systematically small, because a short
55
+ run of similar seeds reads as stability.
56
+
57
+ ## Other findings
58
+
59
+ * **The prior is insensitive to *when* the documents arrived.** charter-midtrain
60
+ and charter-late-midtrain agree within ~1.5 pp on the pooled trained rate
61
+ (76.5% vs 75.2%) and within ~2 pp on every trained clause. Ordering the
62
+ documents late costs essentially nothing.
63
+ * **Clause difficulty reproduces in fresh runs.** At identical AFT dose (20.0%
64
+ per clause), the charter arm installs skill floor 93.0% and specialty 91.0%
65
+ but registry rank only 42.6%. That corroborates `clause_budget_v1`'s
66
+ conclusion — Article 3's lexicographic depth, not document budget — from a
67
+ different training run.
68
+ * **Agreement-AFT erodes held-out clause behaviour.** Every arm's pooled
69
+ held-out rate falls after AFT (charter 26.7 → ~21%, control 19.4 → ~9%),
70
+ against a 20.8% chance floor.
71
+ * **Seed sensitivity is arm-dependent.** The coin arm is tight (pooled trained
72
+ SD 2.2) while control is wild (SD 12.3, and 22.1 on one clause). Variance is
73
+ not a single number for this task.
74
+
75
+ ## What this means for the published figures
76
+
77
+ Any figure that reads a per-clause difference *between* wave v1, the retrain and
78
+ wave v2 is, on this evidence, reading noise — with `precedence_deferrals` the one
79
+ possible exception. The honest framing for those comparisons is a single pooled
80
+ number with a ±9 pp run-to-run band, not three distinguishable runs.
81
+
82
+ ## Caveats
83
+
84
+ 1. **Dose-matched, not schedule-matched.** These runs complete a 256-step cosine
85
+ decay; the wave markers are step 256 of a 512-step schedule. The sweep
86
+ measures seed variance *of this recipe*. It is a reference for the wave
87
+ points, not a control on them.
88
+ 2. **Seed variance is still a lower bound on run variance.** All three published
89
+ waves used seed 42 and still diverged, so stack pins, data order and hardware
90
+ contribute on top of what this measures.
91
+ 3. **The control column's wave markers are two substrates** — `control_4x` for
92
+ v1 and the retrain, `control_matched` for v2 (= the sweep's). Only the v2
93
+ marker is substrate-comparable, so the control row's "wave range" is not a
94
+ like-for-like number and should not be quoted.
95
+ 4. **n = 5 seeds.** These SDs have wide intervals of their own; treat them as
96
+ "large, roughly 5–12 pp", not as calibrated values.
97
+
98
+ ## Artifacts
99
+
100
+ `arcadia-impact/scimt-dispatch-seed-sweep-v1` — all 30 endpoints' responses
101
+ (including each pod's same-run pre-AFT baseline), all 25 step-256 LoRA adapters,
102
+ the scored fold, the wave reference and the figures. 13.73 GB, 487 files.
103
+
104
+ Recipe pins: stage `aft_dispatch_agreement_1epoch`, parents
105
+ `arcadia-impact/scimt-dispatch-models@9ac77232d7`, episodes
106
+ `arcadia-impact/scimt-dispatch-aft-data/extensions/wave_v2/data@35879f259f`,
107
+ GPU `NVIDIA H100 80GB HBM3`.
scores/seed_sweep_v1/build_wave_reference.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """The published waves' step-256 per-clause rates: the thing the sweep explains.
2
+
3
+ The sweep exists to ask whether the between-wave per-clause spread is run-to-run
4
+ noise. That question needs the spread itself as a number, per clause, per arm, so
5
+ this pulls the three published waves' **step-256** agreement endpoints and folds
6
+ them the same way `score_seed_sweep` folds the sweep's own rows.
7
+
8
+ Coverage is uneven and that is a fact about the runs, not a bug here:
9
+
10
+ * wave v1 and wave v2 cover all five substrates on `agreement`.
11
+ * the §6 retrain only ever trained `charter_real_4x` / `coin_real_4x` /
12
+ `control_4x`, so the two late-midtrained arms have no retrain row.
13
+ * the control substrate **differs**: v1 and the retrain use `control_4x`
14
+ (`sdf/4x/shared/post_dolci90`), v2 uses `control_matched`
15
+ (`gate2_midtrain4/dolmino/post_dolci100`). The sweep's control is
16
+ `control_matched`, so only the v2 control row is substrate-comparable to it.
17
+ Both are emitted, labelled, and it is the reader's job not to mix them.
18
+
19
+ Reminder carried into the output: these wave endpoints are step 256 of a
20
+ **512-step** cosine schedule, whereas the sweep completes a 256-step schedule.
21
+ Dose-matched, not schedule-matched.
22
+
23
+ python -m experiments.prior_coins.seed_sweep_v1.build_wave_reference
24
+ """
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import json
29
+ import sys
30
+ from collections import defaultdict
31
+ from pathlib import Path
32
+
33
+ HERE = Path(__file__).resolve().parent
34
+ EXP = HERE.parent
35
+ sys.path.insert(0, str(EXP))
36
+
37
+ import dispatch_v1 as dispatch # noqa: E402
38
+ import dispatch_v4 as v4 # noqa: E402
39
+ import score_factorised as sf # noqa: E402
40
+
41
+ SLICES = (("trained", "eval_trained_conflict"),
42
+ ("holdout", "eval_holdout_conflict"))
43
+ VERDICT_ORDER = (sf.CHARTER, sf.COIN, sf.OTHER, sf.MALFORMED)
44
+ ENDPOINT = "step256"
45
+ MIXTURE = "agreement"
46
+
47
+ #: wave key -> (model repo, prefix, episode repo, episode prefix)
48
+ WAVES = {
49
+ "wave_v1": ("sidbaines/scimt-prior-coins-dispatch-sdf-aft-v1",
50
+ "extensions/wave_v1",
51
+ "sidbaines/scimt-prior-coins-dispatch-sdf-aft-v1-data",
52
+ "extensions/wave_v1/data/episodes"),
53
+ "wave_v1_retrain": ("arcadia-impact/scimt-dispatch-models",
54
+ "aft_wave_retrain",
55
+ "sidbaines/scimt-prior-coins-dispatch-sdf-aft-v1-data",
56
+ "extensions/wave_v1/data/episodes"),
57
+ "wave_v2": ("arcadia-impact/scimt-dispatch-models",
58
+ "aft_wave_v2",
59
+ "arcadia-impact/scimt-dispatch-aft-data",
60
+ "extensions/wave_v2/data/episodes"),
61
+ }
62
+ #: sweep arm -> the parent label each wave used for that substrate
63
+ ARM_PARENTS = {
64
+ "charter": {"wave_v1": "charter_real_4x", "wave_v1_retrain": "charter_real_4x",
65
+ "wave_v2": "charter_real_4x"},
66
+ "coin": {"wave_v1": "coin_real_4x", "wave_v1_retrain": "coin_real_4x",
67
+ "wave_v2": "coin_real_4x"},
68
+ "control": {"wave_v1": "control_4x", "wave_v1_retrain": "control_4x",
69
+ "wave_v2": "control_matched"},
70
+ "charter_late": {"wave_v1": "charter_fake_4x", "wave_v2": "charter_fake_4x"},
71
+ "coin_late": {"wave_v1": "coin_fake_4x", "wave_v2": "coin_fake_4x"},
72
+ }
73
+
74
+
75
+ def fetch(repo: str, remote: str, cache: Path, *, repo_type: str = "model") -> Path:
76
+ from huggingface_hub import hf_hub_download
77
+
78
+ local = cache / repo.replace("/", "__") / remote
79
+ if local.is_file():
80
+ return local
81
+ local.parent.mkdir(parents=True, exist_ok=True)
82
+ got = hf_hub_download(repo_id=repo, repo_type=repo_type, filename=remote)
83
+ local.write_bytes(Path(got).read_bytes())
84
+ return local
85
+
86
+
87
+ def fold(episodes: dict, responses: dict) -> dict:
88
+ by_clause: dict = defaultdict(lambda: defaultdict(int))
89
+ for condition, slice_name in SLICES:
90
+ got = responses.get(slice_name)
91
+ if got is None:
92
+ continue
93
+ for record in episodes[slice_name]:
94
+ episode = record.episode
95
+ text = got.get(episode.episode_id)
96
+ if text is None:
97
+ continue
98
+ verdicts = sf.per_run_verdicts(episode, dispatch.parse_plan(text, episode))
99
+ clause = record.metadata["target_clause"]
100
+ for index, kind in enumerate(sf.derived_run_kinds(episode)):
101
+ if kind != "conflict":
102
+ continue
103
+ by_clause[clause][sf.MALFORMED if verdicts is None
104
+ else verdicts[index]] += 1
105
+ by_clause[clause]["_condition"] = condition
106
+ return {c: dict(v) for c, v in by_clause.items()}
107
+
108
+
109
+ def main() -> None:
110
+ ap = argparse.ArgumentParser(
111
+ description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
112
+ ap.add_argument("--cache", type=Path,
113
+ default=EXP / "runs" / "seed_sweep_v1" / "wave_cache")
114
+ ap.add_argument("--out", type=Path,
115
+ default=HERE / "data" / "wave_reference_step256.json")
116
+ args = ap.parse_args()
117
+ args.cache.mkdir(parents=True, exist_ok=True)
118
+
119
+ eps: dict[str, dict] = {}
120
+ for wave, (_, _, ep_repo, ep_prefix) in WAVES.items():
121
+ eps[wave] = {
122
+ s: v4.read_records(fetch(ep_repo, f"{ep_prefix}/{s}.jsonl", args.cache,
123
+ repo_type="dataset"))
124
+ for _, s in SLICES
125
+ }
126
+
127
+ cells: dict = {}
128
+ missing: list[str] = []
129
+ for arm, per_wave in ARM_PARENTS.items():
130
+ for wave, parent in per_wave.items():
131
+ repo, prefix, _, _ = WAVES[wave]
132
+ responses = {}
133
+ try:
134
+ for _, slice_name in SLICES:
135
+ remote = (f"{prefix}/{parent}__{MIXTURE}/results/"
136
+ f"{parent}__{MIXTURE}-{ENDPOINT}/{slice_name}.jsonl")
137
+ responses[slice_name] = sf.load_responses(
138
+ fetch(repo, remote, args.cache))
139
+ except Exception as error: # noqa: BLE001 - absent cell, not a bug
140
+ missing.append(f"{arm}|{wave} ({type(error).__name__})")
141
+ continue
142
+ key = f"{arm}|{wave}"
143
+ cells[key] = {"parent": parent, "by_clause": fold(eps[wave], responses)}
144
+ print(f"{key:34s} {parent:16s} {len(cells[key]['by_clause'])} clauses")
145
+ if missing:
146
+ print(f"\nabsent cells ({len(missing)}): " + ", ".join(missing))
147
+
148
+ args.out.parent.mkdir(parents=True, exist_ok=True)
149
+ args.out.write_text(json.dumps({
150
+ "what": f"published waves' {ENDPOINT} agreement endpoints, per-clause "
151
+ "per-run verdict counts on conflict runs",
152
+ "endpoint": ENDPOINT,
153
+ "caveats": [
154
+ "these are step 256 of a 512-step cosine schedule; the sweep "
155
+ "completes a 256-step schedule. Dose-matched, not schedule-matched.",
156
+ "the control substrate differs: control_4x for wave_v1 and the "
157
+ "retrain, control_matched for wave_v2. Only the v2 control row is "
158
+ "substrate-comparable to the sweep's control arm.",
159
+ "the retrain never trained the two late-midtrained arms.",
160
+ ],
161
+ "absent": missing,
162
+ "cells": cells,
163
+ }, indent=1) + "\n")
164
+ print(f"\nwrote {args.out} ({len(cells)} cells)")
165
+
166
+
167
+ if __name__ == "__main__":
168
+ main()
scores/seed_sweep_v1/contracts.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Immutable per-cell contracts for the agreement-AFT seed sweep.
2
+
3
+ **The question.** The three published agreement-AFT waves (v1, the §6 retrain,
4
+ v2) differ on held-out charter-following by amounts that are entirely
5
+ concentrated in one clause: `precedence_deferrals` runs 42.7 / 4.3 / 42.0 % at
6
+ step 256 (a 38.3 pp spread) while `qual_weekly_limit` moves 7.7 pp over the same
7
+ three runs. All three waves ran **seed 42**, so that spread is unexplained
8
+ run-to-run variation, not a seed effect anyone has measured. This sweep measures
9
+ it: five seeds on each of five midtraining substrates, 25 runs.
10
+
11
+ **The recipe.** 8,192 agreement rows for ONE epoch = 256 optimizer steps at the
12
+ house global batch 32. That is the dose where the between-wave spread is largest
13
+ (38.3 pp on deferrals, versus 20.3 at step 128 and 24.8 at step 512), which is
14
+ why the sweep sits here rather than at the wave's 512.
15
+
16
+ Everything that is not the substrate or the seed is held fixed: the LoRA shape,
17
+ the global batch, the sequence length, the LR family, the training mixture and
18
+ the eval battery are all the wave's.
19
+
20
+ **Two caveats that must travel with any figure built from this sweep.**
21
+
22
+ 1. **Dose-matched, not schedule-matched.** These runs complete a 256-step cosine
23
+ decay; the wave's step-256 checkpoint was mid-decay on a 512-step schedule.
24
+ The sweep measures seed variance *of this recipe*; its rows are not error bars
25
+ on the published wave points.
26
+ 2. **Seed variance is a lower bound on run variance.** v1, the retrain and v2 all
27
+ ran seed 42 and still diverged, so stack pins, data order and hardware
28
+ nondeterminism contribute something this sweep cannot see. Seed 42 is included
29
+ deliberately as the one rung that is comparable to the published runs.
30
+
31
+ Nothing in this module provisions or runs anything.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import dataclasses
37
+
38
+ VERSION = "dispatch_seed_sweep_v1"
39
+ #: the training mixture; `datasets/aft_agreement.jsonl` in the wave-v2 data
40
+ MIXTURE = "agreement"
41
+ #: version string the pods must find in the episode data's dataset_manifest.json
42
+ DATA_VERSION = "dispatch_wave_v2"
43
+
44
+ #: 8,192 rows / global batch 32 = 256 steps at exactly one epoch.
45
+ TRAIN_ROWS = 8_192
46
+ EXPECTED_STEPS = 256
47
+ #: only the evaluated checkpoint is written -- 25 runs have no use for a ladder
48
+ SAVE_EVERY = 256
49
+ EVAL_STEPS = (256,)
50
+ STAGE = "aft_dispatch_agreement_1epoch"
51
+ #: scimt model-registry entry for the substrate checks only; the weights always
52
+ #: come from the on-disk parent. Same entry the wave and charter-target ran.
53
+ REGISTRY_MODEL = "gemma3_12b_it"
54
+
55
+ #: seed 42 is the wave's, kept as the rung that is comparable to published runs
56
+ SEEDS = (42, 43, 44, 45, 46)
57
+
58
+ DATA_REPO = "arcadia-impact/scimt-dispatch-aft-data"
59
+ DATA_PREFIX = "extensions/wave_v2/data"
60
+ DATA_REVISION = "35879f259f4f8843776878cf09535db984dba34b"
61
+
62
+ PARENT_REPO = "arcadia-impact/scimt-dispatch-models"
63
+ #: HEAD of the consolidated public model repo, verified 2026-08-21
64
+ PARENT_REVISION = "9ac77232d7efa44bb8f951ff88954c3dc914f64d"
65
+
66
+ #: Verbatim RunPod id for H100 **SXM**. `gpu="H100"` in bellhop expands to
67
+ #: (HBM3, PCIe, NVL) and will happily place NVL, which runs this model ~2x
68
+ #: slower (12.5 s/step vs 6.7, measured on the charter-target run) AND puts a
69
+ #: hardware difference across the charter-vs-coin contrast this sweep exists to
70
+ #: measure. The launcher pins this id first and only widens if it cannot place.
71
+ GPU_SXM = "NVIDIA H100 80GB HBM3"
72
+
73
+ ARMS = ("charter", "coin", "control", "charter_late", "coin_late")
74
+
75
+
76
+ @dataclasses.dataclass(frozen=True)
77
+ class Cell:
78
+ """One midtraining substrate = one pod = five sequential seeds."""
79
+
80
+ arm: str
81
+ #: the wave's parent label; names the shared baseline dir and the result dirs
82
+ parent: str
83
+ parent_prefix: str
84
+ gpu: str
85
+ container_disk_gb: int
86
+ max_lifetime_hours: int
87
+
88
+ @property
89
+ def label(self) -> str:
90
+ return f"{self.parent}-seedsweep"
91
+
92
+ @property
93
+ def slug(self) -> str:
94
+ return f"scimt-seedsweep-{self.arm.replace('_', '-')}"
95
+
96
+ def cell_label(self, seed: int) -> str:
97
+ """Per-seed cell name: names its own result dir under results/."""
98
+ return f"{self.parent}__{MIXTURE}__seed{seed}"
99
+
100
+
101
+ #: `real 4x` is the lineage all three published waves cover; `fake 4x` is the
102
+ #: late-midtrained ("sdf-ordered") pair, dose-matched to it. The control is
103
+ #: Gate-2's Dolmino-only arm -- the true dose-matched control, NOT wave-v1's
104
+ #: `sdf/4x/shared/post_dolci90`, which is 26.7 M presentations short end to end.
105
+ CELLS: tuple[Cell, ...] = (
106
+ Cell("charter", "charter_real_4x", "sft_4epoch/charter/checkpoint-48",
107
+ "H100", 300, 10),
108
+ Cell("coin", "coin_real_4x", "sft_4epoch/coin/checkpoint-48",
109
+ "H100", 300, 10),
110
+ Cell("control", "control_matched", "gate2_midtrain4/dolmino/post_dolci100",
111
+ "H100", 300, 10),
112
+ Cell("charter_late", "charter_fake_4x", "sdf/4x/charter/final",
113
+ "H100", 300, 10),
114
+ Cell("coin_late", "coin_fake_4x", "sdf/4x/coin/final",
115
+ "H100", 300, 10),
116
+ )
117
+
118
+
119
+ def cell(arm: str) -> Cell:
120
+ for entry in CELLS:
121
+ if entry.arm == arm:
122
+ return entry
123
+ raise ValueError(f"no cell for {arm!r}")
124
+
125
+
126
+ def validate() -> None:
127
+ """Contract checks that must hold before a single GPU is provisioned."""
128
+ if EXPECTED_STEPS * 32 != TRAIN_ROWS:
129
+ raise ValueError(
130
+ f"{TRAIN_ROWS} rows / global batch 32 != {EXPECTED_STEPS} steps"
131
+ )
132
+ if EXPECTED_STEPS % SAVE_EVERY:
133
+ raise ValueError("expected steps must be a multiple of save_every")
134
+ saved = set(range(SAVE_EVERY, EXPECTED_STEPS + 1, SAVE_EVERY))
135
+ missing = sorted(set(EVAL_STEPS) - saved)
136
+ if missing:
137
+ raise ValueError(f"eval steps not saved as checkpoints: {missing}")
138
+ if len(CELLS) != len(ARMS):
139
+ raise ValueError(f"expected {len(ARMS)} cells, got {len(CELLS)}")
140
+ for name in ("label", "slug", "parent"):
141
+ values = [getattr(c, name) for c in CELLS]
142
+ if len(set(values)) != len(values):
143
+ raise ValueError(f"duplicate cell {name}")
144
+ if {c.arm for c in CELLS} != set(ARMS):
145
+ raise ValueError("cell arms do not match ARMS")
146
+ if len(set(SEEDS)) != len(SEEDS):
147
+ raise ValueError("duplicate seed")
148
+ if 42 not in SEEDS:
149
+ raise ValueError("seed 42 is the anchor comparable to the published waves")
150
+ for rev in (PARENT_REVISION, DATA_REVISION):
151
+ if len(rev) != 40 or not all(c in "0123456789abcdef" for c in rev):
152
+ raise ValueError(f"revision must be a 40-hex sha: {rev!r}")
153
+ labels = {c.cell_label(s) for c in CELLS for s in SEEDS}
154
+ if len(labels) != len(CELLS) * len(SEEDS):
155
+ raise ValueError("per-seed cell labels are not unique")
156
+
157
+
158
+ validate()
scores/seed_sweep_v1/data/seed_sweep_rates.csv ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ arm,phase,seed,clause,condition,n_conflict_runs,n_charter,n_coin,n_other,n_malformed,rate_charter,rate_coin,rate_other,rate_malformed
2
+ charter,pre_aft,shared,precedence_runs_year,trained,600,149,138,287,26,0.248333,0.230000,0.478333,0.043333
3
+ charter,pre_aft,shared,precedence_days_since,trained,600,138,150,278,34,0.230000,0.250000,0.463333,0.056667
4
+ charter,pre_aft,shared,precedence_registry_rank,trained,600,165,145,276,14,0.275000,0.241667,0.460000,0.023333
5
+ charter,pre_aft,shared,qual_specialty,trained,600,415,53,102,30,0.691667,0.088333,0.170000,0.050000
6
+ charter,pre_aft,shared,qual_skill,trained,600,279,129,154,38,0.465000,0.215000,0.256667,0.063333
7
+ charter,pre_aft,shared,precedence_deferrals,holdout,600,148,148,260,44,0.246667,0.246667,0.433333,0.073333
8
+ charter,pre_aft,shared,qual_weekly_limit,holdout,600,172,154,258,16,0.286667,0.256667,0.430000,0.026667
9
+ charter,post_aft,seed42,precedence_runs_year,trained,600,501,71,24,4,0.835000,0.118333,0.040000,0.006667
10
+ charter,post_aft,seed42,precedence_days_since,trained,600,499,64,33,4,0.831667,0.106667,0.055000,0.006667
11
+ charter,post_aft,seed42,precedence_registry_rank,trained,600,279,260,55,6,0.465000,0.433333,0.091667,0.010000
12
+ charter,post_aft,seed42,qual_specialty,trained,600,574,16,6,4,0.956667,0.026667,0.010000,0.006667
13
+ charter,post_aft,seed42,qual_skill,trained,600,593,6,1,0,0.988333,0.010000,0.001667,0.000000
14
+ charter,post_aft,seed42,precedence_deferrals,holdout,600,170,296,122,12,0.283333,0.493333,0.203333,0.020000
15
+ charter,post_aft,seed42,qual_weekly_limit,holdout,600,124,313,155,8,0.206667,0.521667,0.258333,0.013333
16
+ charter,post_aft,seed43,precedence_runs_year,trained,600,519,64,17,0,0.865000,0.106667,0.028333,0.000000
17
+ charter,post_aft,seed43,precedence_days_since,trained,600,526,50,24,0,0.876667,0.083333,0.040000,0.000000
18
+ charter,post_aft,seed43,precedence_registry_rank,trained,600,340,216,44,0,0.566667,0.360000,0.073333,0.000000
19
+ charter,post_aft,seed43,qual_specialty,trained,600,588,10,0,2,0.980000,0.016667,0.000000,0.003333
20
+ charter,post_aft,seed43,qual_skill,trained,600,589,10,1,0,0.981667,0.016667,0.001667,0.000000
21
+ charter,post_aft,seed43,precedence_deferrals,holdout,600,137,294,167,2,0.228333,0.490000,0.278333,0.003333
22
+ charter,post_aft,seed43,qual_weekly_limit,holdout,600,134,289,177,0,0.223333,0.481667,0.295000,0.000000
23
+ charter,post_aft,seed44,precedence_runs_year,trained,600,483,93,22,2,0.805000,0.155000,0.036667,0.003333
24
+ charter,post_aft,seed44,precedence_days_since,trained,600,474,80,44,2,0.790000,0.133333,0.073333,0.003333
25
+ charter,post_aft,seed44,precedence_registry_rank,trained,600,300,256,42,2,0.500000,0.426667,0.070000,0.003333
26
+ charter,post_aft,seed44,qual_specialty,trained,600,576,17,7,0,0.960000,0.028333,0.011667,0.000000
27
+ charter,post_aft,seed44,qual_skill,trained,600,574,21,3,2,0.956667,0.035000,0.005000,0.003333
28
+ charter,post_aft,seed44,precedence_deferrals,holdout,600,148,316,134,2,0.246667,0.526667,0.223333,0.003333
29
+ charter,post_aft,seed44,qual_weekly_limit,holdout,600,99,330,165,6,0.165000,0.550000,0.275000,0.010000
30
+ charter,post_aft,seed45,precedence_runs_year,trained,600,381,187,28,4,0.635000,0.311667,0.046667,0.006667
31
+ charter,post_aft,seed45,precedence_days_since,trained,600,431,136,31,2,0.718333,0.226667,0.051667,0.003333
32
+ charter,post_aft,seed45,precedence_registry_rank,trained,600,164,373,59,4,0.273333,0.621667,0.098333,0.006667
33
+ charter,post_aft,seed45,qual_specialty,trained,600,467,119,10,4,0.778333,0.198333,0.016667,0.006667
34
+ charter,post_aft,seed45,qual_skill,trained,600,499,85,8,8,0.831667,0.141667,0.013333,0.013333
35
+ charter,post_aft,seed45,precedence_deferrals,holdout,600,91,407,100,2,0.151667,0.678333,0.166667,0.003333
36
+ charter,post_aft,seed45,qual_weekly_limit,holdout,600,71,420,101,8,0.118333,0.700000,0.168333,0.013333
37
+ charter,post_aft,seed46,precedence_runs_year,trained,600,443,128,21,8,0.738333,0.213333,0.035000,0.013333
38
+ charter,post_aft,seed46,precedence_days_since,trained,600,416,134,42,8,0.693333,0.223333,0.070000,0.013333
39
+ charter,post_aft,seed46,precedence_registry_rank,trained,600,194,352,46,8,0.323333,0.586667,0.076667,0.013333
40
+ charter,post_aft,seed46,qual_specialty,trained,600,524,64,8,4,0.873333,0.106667,0.013333,0.006667
41
+ charter,post_aft,seed46,qual_skill,trained,600,535,58,3,4,0.891667,0.096667,0.005000,0.006667
42
+ charter,post_aft,seed46,precedence_deferrals,holdout,600,159,364,77,0,0.265000,0.606667,0.128333,0.000000
43
+ charter,post_aft,seed46,qual_weekly_limit,holdout,600,134,385,77,4,0.223333,0.641667,0.128333,0.006667
44
+ coin,pre_aft,shared,precedence_runs_year,trained,600,104,283,189,24,0.173333,0.471667,0.315000,0.040000
45
+ coin,pre_aft,shared,precedence_days_since,trained,600,84,300,182,34,0.140000,0.500000,0.303333,0.056667
46
+ coin,pre_aft,shared,precedence_registry_rank,trained,600,119,272,181,28,0.198333,0.453333,0.301667,0.046667
47
+ coin,pre_aft,shared,qual_specialty,trained,600,244,196,132,28,0.406667,0.326667,0.220000,0.046667
48
+ coin,pre_aft,shared,qual_skill,trained,600,178,242,156,24,0.296667,0.403333,0.260000,0.040000
49
+ coin,pre_aft,shared,precedence_deferrals,holdout,600,91,281,200,28,0.151667,0.468333,0.333333,0.046667
50
+ coin,pre_aft,shared,qual_weekly_limit,holdout,600,84,300,186,30,0.140000,0.500000,0.310000,0.050000
51
+ coin,post_aft,seed42,precedence_runs_year,trained,600,52,498,42,8,0.086667,0.830000,0.070000,0.013333
52
+ coin,post_aft,seed42,precedence_days_since,trained,600,38,494,60,8,0.063333,0.823333,0.100000,0.013333
53
+ coin,post_aft,seed42,precedence_registry_rank,trained,600,56,488,46,10,0.093333,0.813333,0.076667,0.016667
54
+ coin,post_aft,seed42,qual_specialty,trained,600,227,363,6,4,0.378333,0.605000,0.010000,0.006667
55
+ coin,post_aft,seed42,qual_skill,trained,600,86,467,41,6,0.143333,0.778333,0.068333,0.010000
56
+ coin,post_aft,seed42,precedence_deferrals,holdout,600,48,496,42,14,0.080000,0.826667,0.070000,0.023333
57
+ coin,post_aft,seed42,qual_weekly_limit,holdout,600,51,498,39,12,0.085000,0.830000,0.065000,0.020000
58
+ coin,post_aft,seed43,precedence_runs_year,trained,600,53,491,46,10,0.088333,0.818333,0.076667,0.016667
59
+ coin,post_aft,seed43,precedence_days_since,trained,600,49,482,59,10,0.081667,0.803333,0.098333,0.016667
60
+ coin,post_aft,seed43,precedence_registry_rank,trained,600,54,489,49,8,0.090000,0.815000,0.081667,0.013333
61
+ coin,post_aft,seed43,qual_specialty,trained,600,302,285,7,6,0.503333,0.475000,0.011667,0.010000
62
+ coin,post_aft,seed43,qual_skill,trained,600,91,455,46,8,0.151667,0.758333,0.076667,0.013333
63
+ coin,post_aft,seed43,precedence_deferrals,holdout,600,51,491,48,10,0.085000,0.818333,0.080000,0.016667
64
+ coin,post_aft,seed43,qual_weekly_limit,holdout,600,50,490,50,10,0.083333,0.816667,0.083333,0.016667
65
+ coin,post_aft,seed44,precedence_runs_year,trained,600,39,509,42,10,0.065000,0.848333,0.070000,0.016667
66
+ coin,post_aft,seed44,precedence_days_since,trained,600,36,517,41,6,0.060000,0.861667,0.068333,0.010000
67
+ coin,post_aft,seed44,precedence_registry_rank,trained,600,48,500,42,10,0.080000,0.833333,0.070000,0.016667
68
+ coin,post_aft,seed44,qual_specialty,trained,600,137,450,7,6,0.228333,0.750000,0.011667,0.010000
69
+ coin,post_aft,seed44,qual_skill,trained,600,112,442,32,14,0.186667,0.736667,0.053333,0.023333
70
+ coin,post_aft,seed44,precedence_deferrals,holdout,600,33,513,42,12,0.055000,0.855000,0.070000,0.020000
71
+ coin,post_aft,seed44,qual_weekly_limit,holdout,600,41,505,48,6,0.068333,0.841667,0.080000,0.010000
72
+ coin,post_aft,seed45,precedence_runs_year,trained,600,45,494,51,10,0.075000,0.823333,0.085000,0.016667
73
+ coin,post_aft,seed45,precedence_days_since,trained,600,47,491,46,16,0.078333,0.818333,0.076667,0.026667
74
+ coin,post_aft,seed45,precedence_registry_rank,trained,600,56,480,60,4,0.093333,0.800000,0.100000,0.006667
75
+ coin,post_aft,seed45,qual_specialty,trained,600,200,382,10,8,0.333333,0.636667,0.016667,0.013333
76
+ coin,post_aft,seed45,qual_skill,trained,600,88,456,48,8,0.146667,0.760000,0.080000,0.013333
77
+ coin,post_aft,seed45,precedence_deferrals,holdout,600,50,483,53,14,0.083333,0.805000,0.088333,0.023333
78
+ coin,post_aft,seed45,qual_weekly_limit,holdout,600,53,484,49,14,0.088333,0.806667,0.081667,0.023333
79
+ coin,post_aft,seed46,precedence_runs_year,trained,600,48,502,38,12,0.080000,0.836667,0.063333,0.020000
80
+ coin,post_aft,seed46,precedence_days_since,trained,600,43,505,42,10,0.071667,0.841667,0.070000,0.016667
81
+ coin,post_aft,seed46,precedence_registry_rank,trained,600,56,499,27,18,0.093333,0.831667,0.045000,0.030000
82
+ coin,post_aft,seed46,qual_specialty,trained,600,268,309,13,10,0.446667,0.515000,0.021667,0.016667
83
+ coin,post_aft,seed46,qual_skill,trained,600,90,460,44,6,0.150000,0.766667,0.073333,0.010000
84
+ coin,post_aft,seed46,precedence_deferrals,holdout,600,47,501,44,8,0.078333,0.835000,0.073333,0.013333
85
+ coin,post_aft,seed46,qual_weekly_limit,holdout,600,51,497,36,16,0.085000,0.828333,0.060000,0.026667
86
+ control,pre_aft,shared,precedence_runs_year,trained,600,125,192,283,0,0.208333,0.320000,0.471667,0.000000
87
+ control,pre_aft,shared,precedence_days_since,trained,600,129,181,290,0,0.215000,0.301667,0.483333,0.000000
88
+ control,pre_aft,shared,precedence_registry_rank,trained,600,151,168,279,2,0.251667,0.280000,0.465000,0.003333
89
+ control,pre_aft,shared,qual_specialty,trained,600,337,100,163,0,0.561667,0.166667,0.271667,0.000000
90
+ control,pre_aft,shared,qual_skill,trained,600,221,160,219,0,0.368333,0.266667,0.365000,0.000000
91
+ control,pre_aft,shared,precedence_deferrals,holdout,600,113,197,288,2,0.188333,0.328333,0.480000,0.003333
92
+ control,pre_aft,shared,qual_weekly_limit,holdout,600,120,203,277,0,0.200000,0.338333,0.461667,0.000000
93
+ control,post_aft,seed42,precedence_runs_year,trained,600,288,264,38,10,0.480000,0.440000,0.063333,0.016667
94
+ control,post_aft,seed42,precedence_days_since,trained,600,239,289,62,10,0.398333,0.481667,0.103333,0.016667
95
+ control,post_aft,seed42,precedence_registry_rank,trained,600,102,426,56,16,0.170000,0.710000,0.093333,0.026667
96
+ control,post_aft,seed42,qual_specialty,trained,600,335,250,9,6,0.558333,0.416667,0.015000,0.010000
97
+ control,post_aft,seed42,qual_skill,trained,600,193,368,31,8,0.321667,0.613333,0.051667,0.013333
98
+ control,post_aft,seed42,precedence_deferrals,holdout,600,76,450,54,20,0.126667,0.750000,0.090000,0.033333
99
+ control,post_aft,seed42,qual_weekly_limit,holdout,600,65,442,67,26,0.108333,0.736667,0.111667,0.043333
100
+ control,post_aft,seed43,precedence_runs_year,trained,600,273,289,28,10,0.455000,0.481667,0.046667,0.016667
101
+ control,post_aft,seed43,precedence_days_since,trained,600,349,198,47,6,0.581667,0.330000,0.078333,0.010000
102
+ control,post_aft,seed43,precedence_registry_rank,trained,600,90,437,69,4,0.150000,0.728333,0.115000,0.006667
103
+ control,post_aft,seed43,qual_specialty,trained,600,321,267,10,2,0.535000,0.445000,0.016667,0.003333
104
+ control,post_aft,seed43,qual_skill,trained,600,179,384,35,2,0.298333,0.640000,0.058333,0.003333
105
+ control,post_aft,seed43,precedence_deferrals,holdout,600,63,463,60,14,0.105000,0.771667,0.100000,0.023333
106
+ control,post_aft,seed43,qual_weekly_limit,holdout,600,52,457,79,12,0.086667,0.761667,0.131667,0.020000
107
+ control,post_aft,seed44,precedence_runs_year,trained,600,59,484,47,10,0.098333,0.806667,0.078333,0.016667
108
+ control,post_aft,seed44,precedence_days_since,trained,600,50,493,47,10,0.083333,0.821667,0.078333,0.016667
109
+ control,post_aft,seed44,precedence_registry_rank,trained,600,69,485,42,4,0.115000,0.808333,0.070000,0.006667
110
+ control,post_aft,seed44,qual_specialty,trained,600,262,322,10,6,0.436667,0.536667,0.016667,0.010000
111
+ control,post_aft,seed44,qual_skill,trained,600,107,450,35,8,0.178333,0.750000,0.058333,0.013333
112
+ control,post_aft,seed44,precedence_deferrals,holdout,600,45,501,48,6,0.075000,0.835000,0.080000,0.010000
113
+ control,post_aft,seed44,qual_weekly_limit,holdout,600,48,494,50,8,0.080000,0.823333,0.083333,0.013333
114
+ control,post_aft,seed45,precedence_runs_year,trained,600,57,492,43,8,0.095000,0.820000,0.071667,0.013333
115
+ control,post_aft,seed45,precedence_days_since,trained,600,35,509,42,14,0.058333,0.848333,0.070000,0.023333
116
+ control,post_aft,seed45,precedence_registry_rank,trained,600,48,501,41,10,0.080000,0.835000,0.068333,0.016667
117
+ control,post_aft,seed45,qual_specialty,trained,600,166,422,6,6,0.276667,0.703333,0.010000,0.010000
118
+ control,post_aft,seed45,qual_skill,trained,600,69,489,40,2,0.115000,0.815000,0.066667,0.003333
119
+ control,post_aft,seed45,precedence_deferrals,holdout,600,41,509,44,6,0.068333,0.848333,0.073333,0.010000
120
+ control,post_aft,seed45,qual_weekly_limit,holdout,600,49,508,39,4,0.081667,0.846667,0.065000,0.006667
121
+ control,post_aft,seed46,precedence_runs_year,trained,600,102,455,37,6,0.170000,0.758333,0.061667,0.010000
122
+ control,post_aft,seed46,precedence_days_since,trained,600,131,412,49,8,0.218333,0.686667,0.081667,0.013333
123
+ control,post_aft,seed46,precedence_registry_rank,trained,600,69,469,56,6,0.115000,0.781667,0.093333,0.010000
124
+ control,post_aft,seed46,qual_specialty,trained,600,348,244,8,0,0.580000,0.406667,0.013333,0.000000
125
+ control,post_aft,seed46,qual_skill,trained,600,138,416,36,10,0.230000,0.693333,0.060000,0.016667
126
+ control,post_aft,seed46,precedence_deferrals,holdout,600,54,475,57,14,0.090000,0.791667,0.095000,0.023333
127
+ control,post_aft,seed46,qual_weekly_limit,holdout,600,52,485,49,14,0.086667,0.808333,0.081667,0.023333
128
+ charter_late,pre_aft,shared,precedence_runs_year,trained,600,143,126,261,70,0.238333,0.210000,0.435000,0.116667
129
+ charter_late,pre_aft,shared,precedence_days_since,trained,600,144,133,231,92,0.240000,0.221667,0.385000,0.153333
130
+ charter_late,pre_aft,shared,precedence_registry_rank,trained,600,150,128,220,102,0.250000,0.213333,0.366667,0.170000
131
+ charter_late,pre_aft,shared,qual_specialty,trained,600,448,34,64,54,0.746667,0.056667,0.106667,0.090000
132
+ charter_late,pre_aft,shared,qual_skill,trained,600,317,87,94,102,0.528333,0.145000,0.156667,0.170000
133
+ charter_late,pre_aft,shared,precedence_deferrals,holdout,600,138,139,223,100,0.230000,0.231667,0.371667,0.166667
134
+ charter_late,pre_aft,shared,qual_weekly_limit,holdout,600,161,142,223,74,0.268333,0.236667,0.371667,0.123333
135
+ charter_late,post_aft,seed42,precedence_runs_year,trained,600,507,69,20,4,0.845000,0.115000,0.033333,0.006667
136
+ charter_late,post_aft,seed42,precedence_days_since,trained,600,491,76,29,4,0.818333,0.126667,0.048333,0.006667
137
+ charter_late,post_aft,seed42,precedence_registry_rank,trained,600,271,272,53,4,0.451667,0.453333,0.088333,0.006667
138
+ charter_late,post_aft,seed42,qual_specialty,trained,600,571,18,5,6,0.951667,0.030000,0.008333,0.010000
139
+ charter_late,post_aft,seed42,qual_skill,trained,600,579,17,4,0,0.965000,0.028333,0.006667,0.000000
140
+ charter_late,post_aft,seed42,precedence_deferrals,holdout,600,156,312,126,6,0.260000,0.520000,0.210000,0.010000
141
+ charter_late,post_aft,seed42,qual_weekly_limit,holdout,600,103,343,144,10,0.171667,0.571667,0.240000,0.016667
142
+ charter_late,post_aft,seed43,precedence_runs_year,trained,600,521,60,15,4,0.868333,0.100000,0.025000,0.006667
143
+ charter_late,post_aft,seed43,precedence_days_since,trained,600,485,85,30,0,0.808333,0.141667,0.050000,0.000000
144
+ charter_late,post_aft,seed43,precedence_registry_rank,trained,600,269,267,60,4,0.448333,0.445000,0.100000,0.006667
145
+ charter_late,post_aft,seed43,qual_specialty,trained,600,568,20,8,4,0.946667,0.033333,0.013333,0.006667
146
+ charter_late,post_aft,seed43,qual_skill,trained,600,594,4,0,2,0.990000,0.006667,0.000000,0.003333
147
+ charter_late,post_aft,seed43,precedence_deferrals,holdout,600,110,350,138,2,0.183333,0.583333,0.230000,0.003333
148
+ charter_late,post_aft,seed43,qual_weekly_limit,holdout,600,118,334,144,4,0.196667,0.556667,0.240000,0.006667
149
+ charter_late,post_aft,seed44,precedence_runs_year,trained,600,412,153,33,2,0.686667,0.255000,0.055000,0.003333
150
+ charter_late,post_aft,seed44,precedence_days_since,trained,600,367,173,58,2,0.611667,0.288333,0.096667,0.003333
151
+ charter_late,post_aft,seed44,precedence_registry_rank,trained,600,231,308,61,0,0.385000,0.513333,0.101667,0.000000
152
+ charter_late,post_aft,seed44,qual_specialty,trained,600,501,80,11,8,0.835000,0.133333,0.018333,0.013333
153
+ charter_late,post_aft,seed44,qual_skill,trained,600,501,82,13,4,0.835000,0.136667,0.021667,0.006667
154
+ charter_late,post_aft,seed44,precedence_deferrals,holdout,600,86,364,148,2,0.143333,0.606667,0.246667,0.003333
155
+ charter_late,post_aft,seed44,qual_weekly_limit,holdout,600,105,360,135,0,0.175000,0.600000,0.225000,0.000000
156
+ charter_late,post_aft,seed45,precedence_runs_year,trained,600,382,179,37,2,0.636667,0.298333,0.061667,0.003333
157
+ charter_late,post_aft,seed45,precedence_days_since,trained,600,395,155,46,4,0.658333,0.258333,0.076667,0.006667
158
+ charter_late,post_aft,seed45,precedence_registry_rank,trained,600,181,331,84,4,0.301667,0.551667,0.140000,0.006667
159
+ charter_late,post_aft,seed45,qual_specialty,trained,600,561,20,7,12,0.935000,0.033333,0.011667,0.020000
160
+ charter_late,post_aft,seed45,qual_skill,trained,600,531,50,9,10,0.885000,0.083333,0.015000,0.016667
161
+ charter_late,post_aft,seed45,precedence_deferrals,holdout,600,106,379,107,8,0.176667,0.631667,0.178333,0.013333
162
+ charter_late,post_aft,seed45,qual_weekly_limit,holdout,600,67,383,142,8,0.111667,0.638333,0.236667,0.013333
163
+ charter_late,post_aft,seed46,precedence_runs_year,trained,600,504,74,16,6,0.840000,0.123333,0.026667,0.010000
164
+ charter_late,post_aft,seed46,precedence_days_since,trained,600,458,94,46,2,0.763333,0.156667,0.076667,0.003333
165
+ charter_late,post_aft,seed46,precedence_registry_rank,trained,600,268,276,46,10,0.446667,0.460000,0.076667,0.016667
166
+ charter_late,post_aft,seed46,qual_specialty,trained,600,564,24,8,4,0.940000,0.040000,0.013333,0.006667
167
+ charter_late,post_aft,seed46,qual_skill,trained,600,572,21,3,4,0.953333,0.035000,0.005000,0.006667
168
+ charter_late,post_aft,seed46,precedence_deferrals,holdout,600,144,336,118,2,0.240000,0.560000,0.196667,0.003333
169
+ charter_late,post_aft,seed46,qual_weekly_limit,holdout,600,106,358,130,6,0.176667,0.596667,0.216667,0.010000
170
+ coin_late,pre_aft,shared,precedence_runs_year,trained,600,73,253,134,140,0.121667,0.421667,0.223333,0.233333
171
+ coin_late,pre_aft,shared,precedence_days_since,trained,600,66,247,137,150,0.110000,0.411667,0.228333,0.250000
172
+ coin_late,pre_aft,shared,precedence_registry_rank,trained,600,86,237,129,148,0.143333,0.395000,0.215000,0.246667
173
+ coin_late,pre_aft,shared,qual_specialty,trained,600,213,190,83,114,0.355000,0.316667,0.138333,0.190000
174
+ coin_late,pre_aft,shared,qual_skill,trained,600,149,211,96,144,0.248333,0.351667,0.160000,0.240000
175
+ coin_late,pre_aft,shared,precedence_deferrals,holdout,600,66,249,119,166,0.110000,0.415000,0.198333,0.276667
176
+ coin_late,pre_aft,shared,qual_weekly_limit,holdout,600,60,240,142,158,0.100000,0.400000,0.236667,0.263333
177
+ coin_late,post_aft,seed42,precedence_runs_year,trained,600,39,511,42,8,0.065000,0.851667,0.070000,0.013333
178
+ coin_late,post_aft,seed42,precedence_days_since,trained,600,35,508,45,12,0.058333,0.846667,0.075000,0.020000
179
+ coin_late,post_aft,seed42,precedence_registry_rank,trained,600,58,499,39,4,0.096667,0.831667,0.065000,0.006667
180
+ coin_late,post_aft,seed42,qual_specialty,trained,600,219,367,10,4,0.365000,0.611667,0.016667,0.006667
181
+ coin_late,post_aft,seed42,qual_skill,trained,600,98,467,33,2,0.163333,0.778333,0.055000,0.003333
182
+ coin_late,post_aft,seed42,precedence_deferrals,holdout,600,46,506,42,6,0.076667,0.843333,0.070000,0.010000
183
+ coin_late,post_aft,seed42,qual_weekly_limit,holdout,600,53,496,41,10,0.088333,0.826667,0.068333,0.016667
184
+ coin_late,post_aft,seed43,precedence_runs_year,trained,600,199,358,39,4,0.331667,0.596667,0.065000,0.006667
185
+ coin_late,post_aft,seed43,precedence_days_since,trained,600,206,329,59,6,0.343333,0.548333,0.098333,0.010000
186
+ coin_late,post_aft,seed43,precedence_registry_rank,trained,600,87,428,79,6,0.145000,0.713333,0.131667,0.010000
187
+ coin_late,post_aft,seed43,qual_specialty,trained,600,333,253,12,2,0.555000,0.421667,0.020000,0.003333
188
+ coin_late,post_aft,seed43,qual_skill,trained,600,185,372,39,4,0.308333,0.620000,0.065000,0.006667
189
+ coin_late,post_aft,seed43,precedence_deferrals,holdout,600,66,449,73,12,0.110000,0.748333,0.121667,0.020000
190
+ coin_late,post_aft,seed43,qual_weekly_limit,holdout,600,81,439,76,4,0.135000,0.731667,0.126667,0.006667
191
+ coin_late,post_aft,seed44,precedence_runs_year,trained,600,121,429,42,8,0.201667,0.715000,0.070000,0.013333
192
+ coin_late,post_aft,seed44,precedence_days_since,trained,600,95,439,56,10,0.158333,0.731667,0.093333,0.016667
193
+ coin_late,post_aft,seed44,precedence_registry_rank,trained,600,68,468,60,4,0.113333,0.780000,0.100000,0.006667
194
+ coin_late,post_aft,seed44,qual_specialty,trained,600,234,345,13,8,0.390000,0.575000,0.021667,0.013333
195
+ coin_late,post_aft,seed44,qual_skill,trained,600,148,409,35,8,0.246667,0.681667,0.058333,0.013333
196
+ coin_late,post_aft,seed44,precedence_deferrals,holdout,600,54,481,59,6,0.090000,0.801667,0.098333,0.010000
197
+ coin_late,post_aft,seed44,qual_weekly_limit,holdout,600,66,479,49,6,0.110000,0.798333,0.081667,0.010000
198
+ coin_late,post_aft,seed45,precedence_runs_year,trained,600,56,477,55,12,0.093333,0.795000,0.091667,0.020000
199
+ coin_late,post_aft,seed45,precedence_days_since,trained,600,60,467,59,14,0.100000,0.778333,0.098333,0.023333
200
+ coin_late,post_aft,seed45,precedence_registry_rank,trained,600,64,468,60,8,0.106667,0.780000,0.100000,0.013333
201
+ coin_late,post_aft,seed45,qual_specialty,trained,600,239,346,9,6,0.398333,0.576667,0.015000,0.010000
202
+ coin_late,post_aft,seed45,qual_skill,trained,600,83,455,52,10,0.138333,0.758333,0.086667,0.016667
203
+ coin_late,post_aft,seed45,precedence_deferrals,holdout,600,60,469,63,8,0.100000,0.781667,0.105000,0.013333
204
+ coin_late,post_aft,seed45,qual_weekly_limit,holdout,600,58,475,61,6,0.096667,0.791667,0.101667,0.010000
205
+ coin_late,post_aft,seed46,precedence_runs_year,trained,600,56,486,46,12,0.093333,0.810000,0.076667,0.020000
206
+ coin_late,post_aft,seed46,precedence_days_since,trained,600,41,486,55,18,0.068333,0.810000,0.091667,0.030000
207
+ coin_late,post_aft,seed46,precedence_registry_rank,trained,600,71,475,50,4,0.118333,0.791667,0.083333,0.006667
208
+ coin_late,post_aft,seed46,qual_specialty,trained,600,299,291,8,2,0.498333,0.485000,0.013333,0.003333
209
+ coin_late,post_aft,seed46,qual_skill,trained,600,95,463,32,10,0.158333,0.771667,0.053333,0.016667
210
+ coin_late,post_aft,seed46,precedence_deferrals,holdout,600,52,484,54,10,0.086667,0.806667,0.090000,0.016667
211
+ coin_late,post_aft,seed46,qual_weekly_limit,holdout,600,51,484,47,18,0.085000,0.806667,0.078333,0.030000
scores/seed_sweep_v1/data/seed_sweep_scored.json ADDED
@@ -0,0 +1,1560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "what": "per-clause per-run verdict counts on conflict runs, per (midtrain arm, phase, seed); pre-AFT is shared per arm",
3
+ "version": "dispatch_seed_sweep_v1",
4
+ "stage": "aft_dispatch_agreement_1epoch",
5
+ "mixture": "agreement",
6
+ "rows": 8192,
7
+ "steps": 256,
8
+ "seeds": [
9
+ 42,
10
+ 43,
11
+ 44,
12
+ 45,
13
+ 46
14
+ ],
15
+ "held_out_clauses": [
16
+ "precedence_deferrals",
17
+ "qual_weekly_limit"
18
+ ],
19
+ "episodes": "arcadia-impact/scimt-dispatch-aft-data/extensions/wave_v2/data@35879f259f4f8843776878cf09535db984dba34b",
20
+ "arms": {
21
+ "charter": {
22
+ "parent": "charter_real_4x",
23
+ "parent_prefix": "sft_4epoch/charter/checkpoint-48"
24
+ },
25
+ "coin": {
26
+ "parent": "coin_real_4x",
27
+ "parent_prefix": "sft_4epoch/coin/checkpoint-48"
28
+ },
29
+ "control": {
30
+ "parent": "control_matched",
31
+ "parent_prefix": "gate2_midtrain4/dolmino/post_dolci100"
32
+ },
33
+ "charter_late": {
34
+ "parent": "charter_fake_4x",
35
+ "parent_prefix": "sdf/4x/charter/final"
36
+ },
37
+ "coin_late": {
38
+ "parent": "coin_fake_4x",
39
+ "parent_prefix": "sdf/4x/coin/final"
40
+ }
41
+ },
42
+ "caveats": [
43
+ "dose-matched but NOT schedule-matched to the wave's step-256 checkpoint: this run completes a 256-step cosine decay, the wave's was mid-decay on a 512-step schedule. Not error bars on the published wave points.",
44
+ "seed variance is a lower bound on run variance: v1/retrain/v2 all ran seed 42 and still diverged.",
45
+ "conflict runs only."
46
+ ],
47
+ "missing": [],
48
+ "cells": {
49
+ "charter|pre_aft|shared": {
50
+ "precedence_runs_year": {
51
+ "other": 287,
52
+ "_condition": "trained",
53
+ "coin": 138,
54
+ "charter": 149,
55
+ "malformed": 26
56
+ },
57
+ "precedence_days_since": {
58
+ "coin": 150,
59
+ "_condition": "trained",
60
+ "charter": 138,
61
+ "other": 278,
62
+ "malformed": 34
63
+ },
64
+ "precedence_registry_rank": {
65
+ "coin": 145,
66
+ "_condition": "trained",
67
+ "charter": 165,
68
+ "other": 276,
69
+ "malformed": 14
70
+ },
71
+ "qual_specialty": {
72
+ "coin": 53,
73
+ "_condition": "trained",
74
+ "charter": 415,
75
+ "other": 102,
76
+ "malformed": 30
77
+ },
78
+ "qual_skill": {
79
+ "other": 154,
80
+ "_condition": "trained",
81
+ "charter": 279,
82
+ "coin": 129,
83
+ "malformed": 38
84
+ },
85
+ "precedence_deferrals": {
86
+ "other": 260,
87
+ "_condition": "holdout",
88
+ "charter": 148,
89
+ "coin": 148,
90
+ "malformed": 44
91
+ },
92
+ "qual_weekly_limit": {
93
+ "malformed": 16,
94
+ "_condition": "holdout",
95
+ "coin": 154,
96
+ "other": 258,
97
+ "charter": 172
98
+ }
99
+ },
100
+ "charter|post_aft|seed42": {
101
+ "precedence_runs_year": {
102
+ "charter": 501,
103
+ "_condition": "trained",
104
+ "other": 24,
105
+ "coin": 71,
106
+ "malformed": 4
107
+ },
108
+ "precedence_days_since": {
109
+ "charter": 499,
110
+ "_condition": "trained",
111
+ "coin": 64,
112
+ "other": 33,
113
+ "malformed": 4
114
+ },
115
+ "precedence_registry_rank": {
116
+ "coin": 260,
117
+ "_condition": "trained",
118
+ "charter": 279,
119
+ "other": 55,
120
+ "malformed": 6
121
+ },
122
+ "qual_specialty": {
123
+ "charter": 574,
124
+ "_condition": "trained",
125
+ "malformed": 4,
126
+ "coin": 16,
127
+ "other": 6
128
+ },
129
+ "qual_skill": {
130
+ "charter": 593,
131
+ "_condition": "trained",
132
+ "coin": 6,
133
+ "other": 1
134
+ },
135
+ "precedence_deferrals": {
136
+ "charter": 170,
137
+ "_condition": "holdout",
138
+ "coin": 296,
139
+ "other": 122,
140
+ "malformed": 12
141
+ },
142
+ "qual_weekly_limit": {
143
+ "other": 155,
144
+ "_condition": "holdout",
145
+ "coin": 313,
146
+ "charter": 124,
147
+ "malformed": 8
148
+ }
149
+ },
150
+ "charter|post_aft|seed43": {
151
+ "precedence_runs_year": {
152
+ "charter": 519,
153
+ "_condition": "trained",
154
+ "other": 17,
155
+ "coin": 64
156
+ },
157
+ "precedence_days_since": {
158
+ "charter": 526,
159
+ "_condition": "trained",
160
+ "coin": 50,
161
+ "other": 24
162
+ },
163
+ "precedence_registry_rank": {
164
+ "charter": 340,
165
+ "_condition": "trained",
166
+ "coin": 216,
167
+ "other": 44
168
+ },
169
+ "qual_specialty": {
170
+ "charter": 588,
171
+ "_condition": "trained",
172
+ "coin": 10,
173
+ "malformed": 2
174
+ },
175
+ "qual_skill": {
176
+ "charter": 589,
177
+ "_condition": "trained",
178
+ "coin": 10,
179
+ "other": 1
180
+ },
181
+ "precedence_deferrals": {
182
+ "other": 167,
183
+ "_condition": "holdout",
184
+ "coin": 294,
185
+ "charter": 137,
186
+ "malformed": 2
187
+ },
188
+ "qual_weekly_limit": {
189
+ "other": 177,
190
+ "_condition": "holdout",
191
+ "coin": 289,
192
+ "charter": 134
193
+ }
194
+ },
195
+ "charter|post_aft|seed44": {
196
+ "precedence_runs_year": {
197
+ "charter": 483,
198
+ "_condition": "trained",
199
+ "other": 22,
200
+ "coin": 93,
201
+ "malformed": 2
202
+ },
203
+ "precedence_days_since": {
204
+ "charter": 474,
205
+ "_condition": "trained",
206
+ "coin": 80,
207
+ "other": 44,
208
+ "malformed": 2
209
+ },
210
+ "precedence_registry_rank": {
211
+ "coin": 256,
212
+ "_condition": "trained",
213
+ "charter": 300,
214
+ "other": 42,
215
+ "malformed": 2
216
+ },
217
+ "qual_specialty": {
218
+ "charter": 576,
219
+ "_condition": "trained",
220
+ "other": 7,
221
+ "coin": 17
222
+ },
223
+ "qual_skill": {
224
+ "charter": 574,
225
+ "_condition": "trained",
226
+ "coin": 21,
227
+ "other": 3,
228
+ "malformed": 2
229
+ },
230
+ "precedence_deferrals": {
231
+ "charter": 148,
232
+ "_condition": "holdout",
233
+ "coin": 316,
234
+ "other": 134,
235
+ "malformed": 2
236
+ },
237
+ "qual_weekly_limit": {
238
+ "other": 165,
239
+ "_condition": "holdout",
240
+ "coin": 330,
241
+ "charter": 99,
242
+ "malformed": 6
243
+ }
244
+ },
245
+ "charter|post_aft|seed45": {
246
+ "precedence_runs_year": {
247
+ "charter": 381,
248
+ "_condition": "trained",
249
+ "other": 28,
250
+ "coin": 187,
251
+ "malformed": 4
252
+ },
253
+ "precedence_days_since": {
254
+ "charter": 431,
255
+ "_condition": "trained",
256
+ "coin": 136,
257
+ "other": 31,
258
+ "malformed": 2
259
+ },
260
+ "precedence_registry_rank": {
261
+ "coin": 373,
262
+ "_condition": "trained",
263
+ "charter": 164,
264
+ "other": 59,
265
+ "malformed": 4
266
+ },
267
+ "qual_specialty": {
268
+ "charter": 467,
269
+ "_condition": "trained",
270
+ "coin": 119,
271
+ "other": 10,
272
+ "malformed": 4
273
+ },
274
+ "qual_skill": {
275
+ "charter": 499,
276
+ "_condition": "trained",
277
+ "coin": 85,
278
+ "malformed": 8,
279
+ "other": 8
280
+ },
281
+ "precedence_deferrals": {
282
+ "charter": 91,
283
+ "_condition": "holdout",
284
+ "coin": 407,
285
+ "other": 100,
286
+ "malformed": 2
287
+ },
288
+ "qual_weekly_limit": {
289
+ "other": 101,
290
+ "_condition": "holdout",
291
+ "coin": 420,
292
+ "charter": 71,
293
+ "malformed": 8
294
+ }
295
+ },
296
+ "charter|post_aft|seed46": {
297
+ "precedence_runs_year": {
298
+ "charter": 443,
299
+ "_condition": "trained",
300
+ "other": 21,
301
+ "coin": 128,
302
+ "malformed": 8
303
+ },
304
+ "precedence_days_since": {
305
+ "charter": 416,
306
+ "_condition": "trained",
307
+ "coin": 134,
308
+ "other": 42,
309
+ "malformed": 8
310
+ },
311
+ "precedence_registry_rank": {
312
+ "coin": 352,
313
+ "_condition": "trained",
314
+ "charter": 194,
315
+ "other": 46,
316
+ "malformed": 8
317
+ },
318
+ "qual_specialty": {
319
+ "coin": 64,
320
+ "_condition": "trained",
321
+ "charter": 524,
322
+ "other": 8,
323
+ "malformed": 4
324
+ },
325
+ "qual_skill": {
326
+ "charter": 535,
327
+ "_condition": "trained",
328
+ "coin": 58,
329
+ "other": 3,
330
+ "malformed": 4
331
+ },
332
+ "precedence_deferrals": {
333
+ "charter": 159,
334
+ "_condition": "holdout",
335
+ "coin": 364,
336
+ "other": 77
337
+ },
338
+ "qual_weekly_limit": {
339
+ "other": 77,
340
+ "_condition": "holdout",
341
+ "coin": 385,
342
+ "charter": 134,
343
+ "malformed": 4
344
+ }
345
+ },
346
+ "coin|pre_aft|shared": {
347
+ "precedence_runs_year": {
348
+ "coin": 283,
349
+ "_condition": "trained",
350
+ "charter": 104,
351
+ "other": 189,
352
+ "malformed": 24
353
+ },
354
+ "precedence_days_since": {
355
+ "coin": 300,
356
+ "_condition": "trained",
357
+ "charter": 84,
358
+ "other": 182,
359
+ "malformed": 34
360
+ },
361
+ "precedence_registry_rank": {
362
+ "coin": 272,
363
+ "_condition": "trained",
364
+ "charter": 119,
365
+ "other": 181,
366
+ "malformed": 28
367
+ },
368
+ "qual_specialty": {
369
+ "coin": 196,
370
+ "_condition": "trained",
371
+ "other": 132,
372
+ "charter": 244,
373
+ "malformed": 28
374
+ },
375
+ "qual_skill": {
376
+ "other": 156,
377
+ "_condition": "trained",
378
+ "charter": 178,
379
+ "coin": 242,
380
+ "malformed": 24
381
+ },
382
+ "precedence_deferrals": {
383
+ "coin": 281,
384
+ "_condition": "holdout",
385
+ "charter": 91,
386
+ "other": 200,
387
+ "malformed": 28
388
+ },
389
+ "qual_weekly_limit": {
390
+ "coin": 300,
391
+ "_condition": "holdout",
392
+ "other": 186,
393
+ "charter": 84,
394
+ "malformed": 30
395
+ }
396
+ },
397
+ "coin|post_aft|seed42": {
398
+ "precedence_runs_year": {
399
+ "coin": 498,
400
+ "_condition": "trained",
401
+ "other": 42,
402
+ "malformed": 8,
403
+ "charter": 52
404
+ },
405
+ "precedence_days_since": {
406
+ "coin": 494,
407
+ "_condition": "trained",
408
+ "charter": 38,
409
+ "other": 60,
410
+ "malformed": 8
411
+ },
412
+ "precedence_registry_rank": {
413
+ "coin": 488,
414
+ "_condition": "trained",
415
+ "charter": 56,
416
+ "other": 46,
417
+ "malformed": 10
418
+ },
419
+ "qual_specialty": {
420
+ "coin": 363,
421
+ "_condition": "trained",
422
+ "charter": 227,
423
+ "other": 6,
424
+ "malformed": 4
425
+ },
426
+ "qual_skill": {
427
+ "coin": 467,
428
+ "_condition": "trained",
429
+ "charter": 86,
430
+ "other": 41,
431
+ "malformed": 6
432
+ },
433
+ "precedence_deferrals": {
434
+ "coin": 496,
435
+ "_condition": "holdout",
436
+ "charter": 48,
437
+ "other": 42,
438
+ "malformed": 14
439
+ },
440
+ "qual_weekly_limit": {
441
+ "malformed": 12,
442
+ "_condition": "holdout",
443
+ "coin": 498,
444
+ "charter": 51,
445
+ "other": 39
446
+ }
447
+ },
448
+ "coin|post_aft|seed43": {
449
+ "precedence_runs_year": {
450
+ "coin": 491,
451
+ "_condition": "trained",
452
+ "other": 46,
453
+ "malformed": 10,
454
+ "charter": 53
455
+ },
456
+ "precedence_days_since": {
457
+ "coin": 482,
458
+ "_condition": "trained",
459
+ "charter": 49,
460
+ "other": 59,
461
+ "malformed": 10
462
+ },
463
+ "precedence_registry_rank": {
464
+ "coin": 489,
465
+ "_condition": "trained",
466
+ "other": 49,
467
+ "charter": 54,
468
+ "malformed": 8
469
+ },
470
+ "qual_specialty": {
471
+ "coin": 285,
472
+ "_condition": "trained",
473
+ "charter": 302,
474
+ "other": 7,
475
+ "malformed": 6
476
+ },
477
+ "qual_skill": {
478
+ "charter": 91,
479
+ "_condition": "trained",
480
+ "coin": 455,
481
+ "other": 46,
482
+ "malformed": 8
483
+ },
484
+ "precedence_deferrals": {
485
+ "coin": 491,
486
+ "_condition": "holdout",
487
+ "charter": 51,
488
+ "other": 48,
489
+ "malformed": 10
490
+ },
491
+ "qual_weekly_limit": {
492
+ "malformed": 10,
493
+ "_condition": "holdout",
494
+ "coin": 490,
495
+ "other": 50,
496
+ "charter": 50
497
+ }
498
+ },
499
+ "coin|post_aft|seed44": {
500
+ "precedence_runs_year": {
501
+ "coin": 509,
502
+ "_condition": "trained",
503
+ "malformed": 10,
504
+ "other": 42,
505
+ "charter": 39
506
+ },
507
+ "precedence_days_since": {
508
+ "coin": 517,
509
+ "_condition": "trained",
510
+ "charter": 36,
511
+ "other": 41,
512
+ "malformed": 6
513
+ },
514
+ "precedence_registry_rank": {
515
+ "coin": 500,
516
+ "_condition": "trained",
517
+ "charter": 48,
518
+ "other": 42,
519
+ "malformed": 10
520
+ },
521
+ "qual_specialty": {
522
+ "coin": 450,
523
+ "_condition": "trained",
524
+ "charter": 137,
525
+ "other": 7,
526
+ "malformed": 6
527
+ },
528
+ "qual_skill": {
529
+ "coin": 442,
530
+ "_condition": "trained",
531
+ "charter": 112,
532
+ "other": 32,
533
+ "malformed": 14
534
+ },
535
+ "precedence_deferrals": {
536
+ "coin": 513,
537
+ "_condition": "holdout",
538
+ "charter": 33,
539
+ "other": 42,
540
+ "malformed": 12
541
+ },
542
+ "qual_weekly_limit": {
543
+ "other": 48,
544
+ "_condition": "holdout",
545
+ "coin": 505,
546
+ "charter": 41,
547
+ "malformed": 6
548
+ }
549
+ },
550
+ "coin|post_aft|seed45": {
551
+ "precedence_runs_year": {
552
+ "coin": 494,
553
+ "_condition": "trained",
554
+ "malformed": 10,
555
+ "charter": 45,
556
+ "other": 51
557
+ },
558
+ "precedence_days_since": {
559
+ "coin": 491,
560
+ "_condition": "trained",
561
+ "charter": 47,
562
+ "other": 46,
563
+ "malformed": 16
564
+ },
565
+ "precedence_registry_rank": {
566
+ "coin": 480,
567
+ "_condition": "trained",
568
+ "charter": 56,
569
+ "other": 60,
570
+ "malformed": 4
571
+ },
572
+ "qual_specialty": {
573
+ "coin": 382,
574
+ "_condition": "trained",
575
+ "malformed": 8,
576
+ "charter": 200,
577
+ "other": 10
578
+ },
579
+ "qual_skill": {
580
+ "coin": 456,
581
+ "_condition": "trained",
582
+ "other": 48,
583
+ "charter": 88,
584
+ "malformed": 8
585
+ },
586
+ "precedence_deferrals": {
587
+ "coin": 483,
588
+ "_condition": "holdout",
589
+ "charter": 50,
590
+ "other": 53,
591
+ "malformed": 14
592
+ },
593
+ "qual_weekly_limit": {
594
+ "malformed": 14,
595
+ "_condition": "holdout",
596
+ "coin": 484,
597
+ "other": 49,
598
+ "charter": 53
599
+ }
600
+ },
601
+ "coin|post_aft|seed46": {
602
+ "precedence_runs_year": {
603
+ "coin": 502,
604
+ "_condition": "trained",
605
+ "other": 38,
606
+ "malformed": 12,
607
+ "charter": 48
608
+ },
609
+ "precedence_days_since": {
610
+ "coin": 505,
611
+ "_condition": "trained",
612
+ "other": 42,
613
+ "malformed": 10,
614
+ "charter": 43
615
+ },
616
+ "precedence_registry_rank": {
617
+ "coin": 499,
618
+ "_condition": "trained",
619
+ "charter": 56,
620
+ "other": 27,
621
+ "malformed": 18
622
+ },
623
+ "qual_specialty": {
624
+ "coin": 309,
625
+ "_condition": "trained",
626
+ "charter": 268,
627
+ "malformed": 10,
628
+ "other": 13
629
+ },
630
+ "qual_skill": {
631
+ "coin": 460,
632
+ "_condition": "trained",
633
+ "charter": 90,
634
+ "other": 44,
635
+ "malformed": 6
636
+ },
637
+ "precedence_deferrals": {
638
+ "coin": 501,
639
+ "_condition": "holdout",
640
+ "charter": 47,
641
+ "other": 44,
642
+ "malformed": 8
643
+ },
644
+ "qual_weekly_limit": {
645
+ "malformed": 16,
646
+ "_condition": "holdout",
647
+ "coin": 497,
648
+ "other": 36,
649
+ "charter": 51
650
+ }
651
+ },
652
+ "control|pre_aft|shared": {
653
+ "precedence_runs_year": {
654
+ "coin": 192,
655
+ "_condition": "trained",
656
+ "charter": 125,
657
+ "other": 283
658
+ },
659
+ "precedence_days_since": {
660
+ "coin": 181,
661
+ "_condition": "trained",
662
+ "charter": 129,
663
+ "other": 290
664
+ },
665
+ "precedence_registry_rank": {
666
+ "coin": 168,
667
+ "_condition": "trained",
668
+ "charter": 151,
669
+ "other": 279,
670
+ "malformed": 2
671
+ },
672
+ "qual_specialty": {
673
+ "coin": 100,
674
+ "_condition": "trained",
675
+ "other": 163,
676
+ "charter": 337
677
+ },
678
+ "qual_skill": {
679
+ "other": 219,
680
+ "_condition": "trained",
681
+ "charter": 221,
682
+ "coin": 160
683
+ },
684
+ "precedence_deferrals": {
685
+ "other": 288,
686
+ "_condition": "holdout",
687
+ "charter": 113,
688
+ "coin": 197,
689
+ "malformed": 2
690
+ },
691
+ "qual_weekly_limit": {
692
+ "coin": 203,
693
+ "_condition": "holdout",
694
+ "other": 277,
695
+ "charter": 120
696
+ }
697
+ },
698
+ "control|post_aft|seed42": {
699
+ "precedence_runs_year": {
700
+ "charter": 288,
701
+ "_condition": "trained",
702
+ "other": 38,
703
+ "coin": 264,
704
+ "malformed": 10
705
+ },
706
+ "precedence_days_since": {
707
+ "coin": 289,
708
+ "_condition": "trained",
709
+ "charter": 239,
710
+ "other": 62,
711
+ "malformed": 10
712
+ },
713
+ "precedence_registry_rank": {
714
+ "coin": 426,
715
+ "_condition": "trained",
716
+ "charter": 102,
717
+ "other": 56,
718
+ "malformed": 16
719
+ },
720
+ "qual_specialty": {
721
+ "coin": 250,
722
+ "_condition": "trained",
723
+ "charter": 335,
724
+ "other": 9,
725
+ "malformed": 6
726
+ },
727
+ "qual_skill": {
728
+ "charter": 193,
729
+ "_condition": "trained",
730
+ "coin": 368,
731
+ "other": 31,
732
+ "malformed": 8
733
+ },
734
+ "precedence_deferrals": {
735
+ "coin": 450,
736
+ "_condition": "holdout",
737
+ "charter": 76,
738
+ "other": 54,
739
+ "malformed": 20
740
+ },
741
+ "qual_weekly_limit": {
742
+ "malformed": 26,
743
+ "_condition": "holdout",
744
+ "coin": 442,
745
+ "other": 67,
746
+ "charter": 65
747
+ }
748
+ },
749
+ "control|post_aft|seed43": {
750
+ "precedence_runs_year": {
751
+ "charter": 273,
752
+ "_condition": "trained",
753
+ "other": 28,
754
+ "coin": 289,
755
+ "malformed": 10
756
+ },
757
+ "precedence_days_since": {
758
+ "other": 47,
759
+ "_condition": "trained",
760
+ "coin": 198,
761
+ "charter": 349,
762
+ "malformed": 6
763
+ },
764
+ "precedence_registry_rank": {
765
+ "coin": 437,
766
+ "_condition": "trained",
767
+ "other": 69,
768
+ "charter": 90,
769
+ "malformed": 4
770
+ },
771
+ "qual_specialty": {
772
+ "coin": 267,
773
+ "_condition": "trained",
774
+ "charter": 321,
775
+ "other": 10,
776
+ "malformed": 2
777
+ },
778
+ "qual_skill": {
779
+ "charter": 179,
780
+ "_condition": "trained",
781
+ "coin": 384,
782
+ "other": 35,
783
+ "malformed": 2
784
+ },
785
+ "precedence_deferrals": {
786
+ "coin": 463,
787
+ "_condition": "holdout",
788
+ "charter": 63,
789
+ "other": 60,
790
+ "malformed": 14
791
+ },
792
+ "qual_weekly_limit": {
793
+ "other": 79,
794
+ "_condition": "holdout",
795
+ "coin": 457,
796
+ "charter": 52,
797
+ "malformed": 12
798
+ }
799
+ },
800
+ "control|post_aft|seed44": {
801
+ "precedence_runs_year": {
802
+ "coin": 484,
803
+ "_condition": "trained",
804
+ "other": 47,
805
+ "malformed": 10,
806
+ "charter": 59
807
+ },
808
+ "precedence_days_since": {
809
+ "coin": 493,
810
+ "_condition": "trained",
811
+ "charter": 50,
812
+ "other": 47,
813
+ "malformed": 10
814
+ },
815
+ "precedence_registry_rank": {
816
+ "coin": 485,
817
+ "_condition": "trained",
818
+ "charter": 69,
819
+ "other": 42,
820
+ "malformed": 4
821
+ },
822
+ "qual_specialty": {
823
+ "coin": 322,
824
+ "_condition": "trained",
825
+ "charter": 262,
826
+ "other": 10,
827
+ "malformed": 6
828
+ },
829
+ "qual_skill": {
830
+ "coin": 450,
831
+ "_condition": "trained",
832
+ "charter": 107,
833
+ "other": 35,
834
+ "malformed": 8
835
+ },
836
+ "precedence_deferrals": {
837
+ "coin": 501,
838
+ "_condition": "holdout",
839
+ "other": 48,
840
+ "charter": 45,
841
+ "malformed": 6
842
+ },
843
+ "qual_weekly_limit": {
844
+ "malformed": 8,
845
+ "_condition": "holdout",
846
+ "coin": 494,
847
+ "other": 50,
848
+ "charter": 48
849
+ }
850
+ },
851
+ "control|post_aft|seed45": {
852
+ "precedence_runs_year": {
853
+ "charter": 57,
854
+ "_condition": "trained",
855
+ "coin": 492,
856
+ "malformed": 8,
857
+ "other": 43
858
+ },
859
+ "precedence_days_since": {
860
+ "coin": 509,
861
+ "_condition": "trained",
862
+ "charter": 35,
863
+ "other": 42,
864
+ "malformed": 14
865
+ },
866
+ "precedence_registry_rank": {
867
+ "coin": 501,
868
+ "_condition": "trained",
869
+ "charter": 48,
870
+ "other": 41,
871
+ "malformed": 10
872
+ },
873
+ "qual_specialty": {
874
+ "coin": 422,
875
+ "_condition": "trained",
876
+ "charter": 166,
877
+ "other": 6,
878
+ "malformed": 6
879
+ },
880
+ "qual_skill": {
881
+ "coin": 489,
882
+ "_condition": "trained",
883
+ "charter": 69,
884
+ "other": 40,
885
+ "malformed": 2
886
+ },
887
+ "precedence_deferrals": {
888
+ "coin": 509,
889
+ "_condition": "holdout",
890
+ "other": 44,
891
+ "charter": 41,
892
+ "malformed": 6
893
+ },
894
+ "qual_weekly_limit": {
895
+ "coin": 508,
896
+ "_condition": "holdout",
897
+ "other": 39,
898
+ "charter": 49,
899
+ "malformed": 4
900
+ }
901
+ },
902
+ "control|post_aft|seed46": {
903
+ "precedence_runs_year": {
904
+ "charter": 102,
905
+ "_condition": "trained",
906
+ "coin": 455,
907
+ "other": 37,
908
+ "malformed": 6
909
+ },
910
+ "precedence_days_since": {
911
+ "coin": 412,
912
+ "_condition": "trained",
913
+ "charter": 131,
914
+ "other": 49,
915
+ "malformed": 8
916
+ },
917
+ "precedence_registry_rank": {
918
+ "coin": 469,
919
+ "_condition": "trained",
920
+ "charter": 69,
921
+ "other": 56,
922
+ "malformed": 6
923
+ },
924
+ "qual_specialty": {
925
+ "coin": 244,
926
+ "_condition": "trained",
927
+ "charter": 348,
928
+ "other": 8
929
+ },
930
+ "qual_skill": {
931
+ "coin": 416,
932
+ "_condition": "trained",
933
+ "charter": 138,
934
+ "other": 36,
935
+ "malformed": 10
936
+ },
937
+ "precedence_deferrals": {
938
+ "coin": 475,
939
+ "_condition": "holdout",
940
+ "charter": 54,
941
+ "other": 57,
942
+ "malformed": 14
943
+ },
944
+ "qual_weekly_limit": {
945
+ "malformed": 14,
946
+ "_condition": "holdout",
947
+ "coin": 485,
948
+ "other": 49,
949
+ "charter": 52
950
+ }
951
+ },
952
+ "charter_late|pre_aft|shared": {
953
+ "precedence_runs_year": {
954
+ "charter": 143,
955
+ "_condition": "trained",
956
+ "coin": 126,
957
+ "malformed": 70,
958
+ "other": 261
959
+ },
960
+ "precedence_days_since": {
961
+ "coin": 133,
962
+ "_condition": "trained",
963
+ "charter": 144,
964
+ "other": 231,
965
+ "malformed": 92
966
+ },
967
+ "precedence_registry_rank": {
968
+ "coin": 128,
969
+ "_condition": "trained",
970
+ "charter": 150,
971
+ "other": 220,
972
+ "malformed": 102
973
+ },
974
+ "qual_specialty": {
975
+ "charter": 448,
976
+ "_condition": "trained",
977
+ "other": 64,
978
+ "malformed": 54,
979
+ "coin": 34
980
+ },
981
+ "qual_skill": {
982
+ "charter": 317,
983
+ "_condition": "trained",
984
+ "other": 94,
985
+ "malformed": 102,
986
+ "coin": 87
987
+ },
988
+ "precedence_deferrals": {
989
+ "other": 223,
990
+ "_condition": "holdout",
991
+ "charter": 138,
992
+ "coin": 139,
993
+ "malformed": 100
994
+ },
995
+ "qual_weekly_limit": {
996
+ "malformed": 74,
997
+ "_condition": "holdout",
998
+ "coin": 142,
999
+ "other": 223,
1000
+ "charter": 161
1001
+ }
1002
+ },
1003
+ "charter_late|post_aft|seed42": {
1004
+ "precedence_runs_year": {
1005
+ "charter": 507,
1006
+ "_condition": "trained",
1007
+ "other": 20,
1008
+ "coin": 69,
1009
+ "malformed": 4
1010
+ },
1011
+ "precedence_days_since": {
1012
+ "charter": 491,
1013
+ "_condition": "trained",
1014
+ "other": 29,
1015
+ "coin": 76,
1016
+ "malformed": 4
1017
+ },
1018
+ "precedence_registry_rank": {
1019
+ "charter": 271,
1020
+ "_condition": "trained",
1021
+ "coin": 272,
1022
+ "other": 53,
1023
+ "malformed": 4
1024
+ },
1025
+ "qual_specialty": {
1026
+ "charter": 571,
1027
+ "_condition": "trained",
1028
+ "malformed": 6,
1029
+ "other": 5,
1030
+ "coin": 18
1031
+ },
1032
+ "qual_skill": {
1033
+ "charter": 579,
1034
+ "_condition": "trained",
1035
+ "coin": 17,
1036
+ "other": 4
1037
+ },
1038
+ "precedence_deferrals": {
1039
+ "charter": 156,
1040
+ "_condition": "holdout",
1041
+ "coin": 312,
1042
+ "other": 126,
1043
+ "malformed": 6
1044
+ },
1045
+ "qual_weekly_limit": {
1046
+ "other": 144,
1047
+ "_condition": "holdout",
1048
+ "coin": 343,
1049
+ "charter": 103,
1050
+ "malformed": 10
1051
+ }
1052
+ },
1053
+ "charter_late|post_aft|seed43": {
1054
+ "precedence_runs_year": {
1055
+ "charter": 521,
1056
+ "_condition": "trained",
1057
+ "other": 15,
1058
+ "coin": 60,
1059
+ "malformed": 4
1060
+ },
1061
+ "precedence_days_since": {
1062
+ "other": 30,
1063
+ "_condition": "trained",
1064
+ "coin": 85,
1065
+ "charter": 485
1066
+ },
1067
+ "precedence_registry_rank": {
1068
+ "coin": 267,
1069
+ "_condition": "trained",
1070
+ "charter": 269,
1071
+ "other": 60,
1072
+ "malformed": 4
1073
+ },
1074
+ "qual_specialty": {
1075
+ "charter": 568,
1076
+ "_condition": "trained",
1077
+ "coin": 20,
1078
+ "malformed": 4,
1079
+ "other": 8
1080
+ },
1081
+ "qual_skill": {
1082
+ "charter": 594,
1083
+ "_condition": "trained",
1084
+ "coin": 4,
1085
+ "malformed": 2
1086
+ },
1087
+ "precedence_deferrals": {
1088
+ "charter": 110,
1089
+ "_condition": "holdout",
1090
+ "coin": 350,
1091
+ "other": 138,
1092
+ "malformed": 2
1093
+ },
1094
+ "qual_weekly_limit": {
1095
+ "other": 144,
1096
+ "_condition": "holdout",
1097
+ "coin": 334,
1098
+ "charter": 118,
1099
+ "malformed": 4
1100
+ }
1101
+ },
1102
+ "charter_late|post_aft|seed44": {
1103
+ "precedence_runs_year": {
1104
+ "charter": 412,
1105
+ "_condition": "trained",
1106
+ "other": 33,
1107
+ "coin": 153,
1108
+ "malformed": 2
1109
+ },
1110
+ "precedence_days_since": {
1111
+ "charter": 367,
1112
+ "_condition": "trained",
1113
+ "coin": 173,
1114
+ "other": 58,
1115
+ "malformed": 2
1116
+ },
1117
+ "precedence_registry_rank": {
1118
+ "coin": 308,
1119
+ "_condition": "trained",
1120
+ "charter": 231,
1121
+ "other": 61
1122
+ },
1123
+ "qual_specialty": {
1124
+ "coin": 80,
1125
+ "_condition": "trained",
1126
+ "charter": 501,
1127
+ "other": 11,
1128
+ "malformed": 8
1129
+ },
1130
+ "qual_skill": {
1131
+ "charter": 501,
1132
+ "_condition": "trained",
1133
+ "coin": 82,
1134
+ "other": 13,
1135
+ "malformed": 4
1136
+ },
1137
+ "precedence_deferrals": {
1138
+ "charter": 86,
1139
+ "_condition": "holdout",
1140
+ "coin": 364,
1141
+ "other": 148,
1142
+ "malformed": 2
1143
+ },
1144
+ "qual_weekly_limit": {
1145
+ "other": 135,
1146
+ "_condition": "holdout",
1147
+ "coin": 360,
1148
+ "charter": 105
1149
+ }
1150
+ },
1151
+ "charter_late|post_aft|seed45": {
1152
+ "precedence_runs_year": {
1153
+ "charter": 382,
1154
+ "_condition": "trained",
1155
+ "coin": 179,
1156
+ "other": 37,
1157
+ "malformed": 2
1158
+ },
1159
+ "precedence_days_since": {
1160
+ "other": 46,
1161
+ "_condition": "trained",
1162
+ "coin": 155,
1163
+ "charter": 395,
1164
+ "malformed": 4
1165
+ },
1166
+ "precedence_registry_rank": {
1167
+ "coin": 331,
1168
+ "_condition": "trained",
1169
+ "charter": 181,
1170
+ "other": 84,
1171
+ "malformed": 4
1172
+ },
1173
+ "qual_specialty": {
1174
+ "charter": 561,
1175
+ "_condition": "trained",
1176
+ "coin": 20,
1177
+ "other": 7,
1178
+ "malformed": 12
1179
+ },
1180
+ "qual_skill": {
1181
+ "charter": 531,
1182
+ "_condition": "trained",
1183
+ "coin": 50,
1184
+ "malformed": 10,
1185
+ "other": 9
1186
+ },
1187
+ "precedence_deferrals": {
1188
+ "charter": 106,
1189
+ "_condition": "holdout",
1190
+ "coin": 379,
1191
+ "other": 107,
1192
+ "malformed": 8
1193
+ },
1194
+ "qual_weekly_limit": {
1195
+ "other": 142,
1196
+ "_condition": "holdout",
1197
+ "coin": 383,
1198
+ "charter": 67,
1199
+ "malformed": 8
1200
+ }
1201
+ },
1202
+ "charter_late|post_aft|seed46": {
1203
+ "precedence_runs_year": {
1204
+ "charter": 504,
1205
+ "_condition": "trained",
1206
+ "other": 16,
1207
+ "coin": 74,
1208
+ "malformed": 6
1209
+ },
1210
+ "precedence_days_since": {
1211
+ "charter": 458,
1212
+ "_condition": "trained",
1213
+ "coin": 94,
1214
+ "other": 46,
1215
+ "malformed": 2
1216
+ },
1217
+ "precedence_registry_rank": {
1218
+ "coin": 276,
1219
+ "_condition": "trained",
1220
+ "charter": 268,
1221
+ "other": 46,
1222
+ "malformed": 10
1223
+ },
1224
+ "qual_specialty": {
1225
+ "charter": 564,
1226
+ "_condition": "trained",
1227
+ "malformed": 4,
1228
+ "coin": 24,
1229
+ "other": 8
1230
+ },
1231
+ "qual_skill": {
1232
+ "charter": 572,
1233
+ "_condition": "trained",
1234
+ "coin": 21,
1235
+ "other": 3,
1236
+ "malformed": 4
1237
+ },
1238
+ "precedence_deferrals": {
1239
+ "charter": 144,
1240
+ "_condition": "holdout",
1241
+ "coin": 336,
1242
+ "other": 118,
1243
+ "malformed": 2
1244
+ },
1245
+ "qual_weekly_limit": {
1246
+ "other": 130,
1247
+ "_condition": "holdout",
1248
+ "coin": 358,
1249
+ "charter": 106,
1250
+ "malformed": 6
1251
+ }
1252
+ },
1253
+ "coin_late|pre_aft|shared": {
1254
+ "precedence_runs_year": {
1255
+ "coin": 253,
1256
+ "_condition": "trained",
1257
+ "charter": 73,
1258
+ "other": 134,
1259
+ "malformed": 140
1260
+ },
1261
+ "precedence_days_since": {
1262
+ "coin": 247,
1263
+ "_condition": "trained",
1264
+ "charter": 66,
1265
+ "other": 137,
1266
+ "malformed": 150
1267
+ },
1268
+ "precedence_registry_rank": {
1269
+ "coin": 237,
1270
+ "_condition": "trained",
1271
+ "charter": 86,
1272
+ "malformed": 148,
1273
+ "other": 129
1274
+ },
1275
+ "qual_specialty": {
1276
+ "coin": 190,
1277
+ "_condition": "trained",
1278
+ "charter": 213,
1279
+ "other": 83,
1280
+ "malformed": 114
1281
+ },
1282
+ "qual_skill": {
1283
+ "charter": 149,
1284
+ "_condition": "trained",
1285
+ "other": 96,
1286
+ "coin": 211,
1287
+ "malformed": 144
1288
+ },
1289
+ "precedence_deferrals": {
1290
+ "other": 119,
1291
+ "_condition": "holdout",
1292
+ "charter": 66,
1293
+ "coin": 249,
1294
+ "malformed": 166
1295
+ },
1296
+ "qual_weekly_limit": {
1297
+ "coin": 240,
1298
+ "_condition": "holdout",
1299
+ "malformed": 158,
1300
+ "charter": 60,
1301
+ "other": 142
1302
+ }
1303
+ },
1304
+ "coin_late|post_aft|seed42": {
1305
+ "precedence_runs_year": {
1306
+ "coin": 511,
1307
+ "_condition": "trained",
1308
+ "other": 42,
1309
+ "malformed": 8,
1310
+ "charter": 39
1311
+ },
1312
+ "precedence_days_since": {
1313
+ "coin": 508,
1314
+ "_condition": "trained",
1315
+ "other": 45,
1316
+ "charter": 35,
1317
+ "malformed": 12
1318
+ },
1319
+ "precedence_registry_rank": {
1320
+ "coin": 499,
1321
+ "_condition": "trained",
1322
+ "charter": 58,
1323
+ "other": 39,
1324
+ "malformed": 4
1325
+ },
1326
+ "qual_specialty": {
1327
+ "coin": 367,
1328
+ "_condition": "trained",
1329
+ "charter": 219,
1330
+ "other": 10,
1331
+ "malformed": 4
1332
+ },
1333
+ "qual_skill": {
1334
+ "coin": 467,
1335
+ "_condition": "trained",
1336
+ "charter": 98,
1337
+ "other": 33,
1338
+ "malformed": 2
1339
+ },
1340
+ "precedence_deferrals": {
1341
+ "coin": 506,
1342
+ "_condition": "holdout",
1343
+ "charter": 46,
1344
+ "other": 42,
1345
+ "malformed": 6
1346
+ },
1347
+ "qual_weekly_limit": {
1348
+ "malformed": 10,
1349
+ "_condition": "holdout",
1350
+ "coin": 496,
1351
+ "other": 41,
1352
+ "charter": 53
1353
+ }
1354
+ },
1355
+ "coin_late|post_aft|seed43": {
1356
+ "precedence_runs_year": {
1357
+ "charter": 199,
1358
+ "_condition": "trained",
1359
+ "coin": 358,
1360
+ "other": 39,
1361
+ "malformed": 4
1362
+ },
1363
+ "precedence_days_since": {
1364
+ "coin": 329,
1365
+ "_condition": "trained",
1366
+ "charter": 206,
1367
+ "other": 59,
1368
+ "malformed": 6
1369
+ },
1370
+ "precedence_registry_rank": {
1371
+ "coin": 428,
1372
+ "_condition": "trained",
1373
+ "charter": 87,
1374
+ "other": 79,
1375
+ "malformed": 6
1376
+ },
1377
+ "qual_specialty": {
1378
+ "coin": 253,
1379
+ "_condition": "trained",
1380
+ "charter": 333,
1381
+ "other": 12,
1382
+ "malformed": 2
1383
+ },
1384
+ "qual_skill": {
1385
+ "charter": 185,
1386
+ "_condition": "trained",
1387
+ "coin": 372,
1388
+ "other": 39,
1389
+ "malformed": 4
1390
+ },
1391
+ "precedence_deferrals": {
1392
+ "coin": 449,
1393
+ "_condition": "holdout",
1394
+ "charter": 66,
1395
+ "other": 73,
1396
+ "malformed": 12
1397
+ },
1398
+ "qual_weekly_limit": {
1399
+ "malformed": 4,
1400
+ "_condition": "holdout",
1401
+ "coin": 439,
1402
+ "other": 76,
1403
+ "charter": 81
1404
+ }
1405
+ },
1406
+ "coin_late|post_aft|seed44": {
1407
+ "precedence_runs_year": {
1408
+ "charter": 121,
1409
+ "_condition": "trained",
1410
+ "coin": 429,
1411
+ "other": 42,
1412
+ "malformed": 8
1413
+ },
1414
+ "precedence_days_since": {
1415
+ "coin": 439,
1416
+ "_condition": "trained",
1417
+ "charter": 95,
1418
+ "other": 56,
1419
+ "malformed": 10
1420
+ },
1421
+ "precedence_registry_rank": {
1422
+ "coin": 468,
1423
+ "_condition": "trained",
1424
+ "charter": 68,
1425
+ "other": 60,
1426
+ "malformed": 4
1427
+ },
1428
+ "qual_specialty": {
1429
+ "coin": 345,
1430
+ "_condition": "trained",
1431
+ "charter": 234,
1432
+ "other": 13,
1433
+ "malformed": 8
1434
+ },
1435
+ "qual_skill": {
1436
+ "charter": 148,
1437
+ "_condition": "trained",
1438
+ "coin": 409,
1439
+ "other": 35,
1440
+ "malformed": 8
1441
+ },
1442
+ "precedence_deferrals": {
1443
+ "coin": 481,
1444
+ "_condition": "holdout",
1445
+ "charter": 54,
1446
+ "other": 59,
1447
+ "malformed": 6
1448
+ },
1449
+ "qual_weekly_limit": {
1450
+ "coin": 479,
1451
+ "_condition": "holdout",
1452
+ "charter": 66,
1453
+ "other": 49,
1454
+ "malformed": 6
1455
+ }
1456
+ },
1457
+ "coin_late|post_aft|seed45": {
1458
+ "precedence_runs_year": {
1459
+ "coin": 477,
1460
+ "_condition": "trained",
1461
+ "other": 55,
1462
+ "charter": 56,
1463
+ "malformed": 12
1464
+ },
1465
+ "precedence_days_since": {
1466
+ "coin": 467,
1467
+ "_condition": "trained",
1468
+ "charter": 60,
1469
+ "other": 59,
1470
+ "malformed": 14
1471
+ },
1472
+ "precedence_registry_rank": {
1473
+ "coin": 468,
1474
+ "_condition": "trained",
1475
+ "charter": 64,
1476
+ "other": 60,
1477
+ "malformed": 8
1478
+ },
1479
+ "qual_specialty": {
1480
+ "coin": 346,
1481
+ "_condition": "trained",
1482
+ "charter": 239,
1483
+ "malformed": 6,
1484
+ "other": 9
1485
+ },
1486
+ "qual_skill": {
1487
+ "charter": 83,
1488
+ "_condition": "trained",
1489
+ "coin": 455,
1490
+ "other": 52,
1491
+ "malformed": 10
1492
+ },
1493
+ "precedence_deferrals": {
1494
+ "coin": 469,
1495
+ "_condition": "holdout",
1496
+ "charter": 60,
1497
+ "other": 63,
1498
+ "malformed": 8
1499
+ },
1500
+ "qual_weekly_limit": {
1501
+ "other": 61,
1502
+ "_condition": "holdout",
1503
+ "coin": 475,
1504
+ "charter": 58,
1505
+ "malformed": 6
1506
+ }
1507
+ },
1508
+ "coin_late|post_aft|seed46": {
1509
+ "precedence_runs_year": {
1510
+ "coin": 486,
1511
+ "_condition": "trained",
1512
+ "other": 46,
1513
+ "malformed": 12,
1514
+ "charter": 56
1515
+ },
1516
+ "precedence_days_since": {
1517
+ "coin": 486,
1518
+ "_condition": "trained",
1519
+ "charter": 41,
1520
+ "other": 55,
1521
+ "malformed": 18
1522
+ },
1523
+ "precedence_registry_rank": {
1524
+ "coin": 475,
1525
+ "_condition": "trained",
1526
+ "other": 50,
1527
+ "charter": 71,
1528
+ "malformed": 4
1529
+ },
1530
+ "qual_specialty": {
1531
+ "coin": 291,
1532
+ "_condition": "trained",
1533
+ "charter": 299,
1534
+ "other": 8,
1535
+ "malformed": 2
1536
+ },
1537
+ "qual_skill": {
1538
+ "coin": 463,
1539
+ "_condition": "trained",
1540
+ "charter": 95,
1541
+ "other": 32,
1542
+ "malformed": 10
1543
+ },
1544
+ "precedence_deferrals": {
1545
+ "coin": 484,
1546
+ "_condition": "holdout",
1547
+ "other": 54,
1548
+ "charter": 52,
1549
+ "malformed": 10
1550
+ },
1551
+ "qual_weekly_limit": {
1552
+ "malformed": 18,
1553
+ "_condition": "holdout",
1554
+ "coin": 484,
1555
+ "other": 47,
1556
+ "charter": 51
1557
+ }
1558
+ }
1559
+ }
1560
+ }
scores/seed_sweep_v1/data/wave_reference_step256.json ADDED
@@ -0,0 +1,710 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "what": "published waves' step256 agreement endpoints, per-clause per-run verdict counts on conflict runs",
3
+ "endpoint": "step256",
4
+ "caveats": [
5
+ "these are step 256 of a 512-step cosine schedule; the sweep completes a 256-step schedule. Dose-matched, not schedule-matched.",
6
+ "the control substrate differs: control_4x for wave_v1 and the retrain, control_matched for wave_v2. Only the v2 control row is substrate-comparable to the sweep's control arm.",
7
+ "the retrain never trained the two late-midtrained arms."
8
+ ],
9
+ "absent": [],
10
+ "cells": {
11
+ "charter|wave_v1": {
12
+ "parent": "charter_real_4x",
13
+ "by_clause": {
14
+ "precedence_runs_year": {
15
+ "charter": 516,
16
+ "_condition": "trained",
17
+ "other": 10,
18
+ "malformed": 28,
19
+ "coin": 46
20
+ },
21
+ "precedence_days_since": {
22
+ "charter": 481,
23
+ "_condition": "trained",
24
+ "coin": 76,
25
+ "other": 37,
26
+ "malformed": 6
27
+ },
28
+ "precedence_registry_rank": {
29
+ "charter": 410,
30
+ "_condition": "trained",
31
+ "coin": 160,
32
+ "other": 28,
33
+ "malformed": 2
34
+ },
35
+ "qual_specialty": {
36
+ "charter": 575,
37
+ "_condition": "trained",
38
+ "coin": 14,
39
+ "malformed": 6,
40
+ "other": 5
41
+ },
42
+ "qual_skill": {
43
+ "charter": 556,
44
+ "_condition": "trained",
45
+ "other": 10,
46
+ "coin": 28,
47
+ "malformed": 6
48
+ },
49
+ "precedence_deferrals": {
50
+ "charter": 256,
51
+ "_condition": "holdout",
52
+ "coin": 218,
53
+ "other": 122,
54
+ "malformed": 4
55
+ },
56
+ "qual_weekly_limit": {
57
+ "other": 183,
58
+ "_condition": "holdout",
59
+ "coin": 256,
60
+ "charter": 143,
61
+ "malformed": 18
62
+ }
63
+ }
64
+ },
65
+ "charter|wave_v1_retrain": {
66
+ "parent": "charter_real_4x",
67
+ "by_clause": {
68
+ "precedence_runs_year": {
69
+ "charter": 469,
70
+ "_condition": "trained",
71
+ "other": 46,
72
+ "coin": 83,
73
+ "malformed": 2
74
+ },
75
+ "precedence_days_since": {
76
+ "charter": 504,
77
+ "_condition": "trained",
78
+ "coin": 57,
79
+ "other": 37,
80
+ "malformed": 2
81
+ },
82
+ "precedence_registry_rank": {
83
+ "other": 63,
84
+ "_condition": "trained",
85
+ "charter": 315,
86
+ "coin": 220,
87
+ "malformed": 2
88
+ },
89
+ "qual_specialty": {
90
+ "charter": 587,
91
+ "_condition": "trained",
92
+ "malformed": 4,
93
+ "other": 7,
94
+ "coin": 2
95
+ },
96
+ "qual_skill": {
97
+ "charter": 594,
98
+ "_condition": "trained",
99
+ "coin": 5,
100
+ "other": 1
101
+ },
102
+ "precedence_deferrals": {
103
+ "coin": 304,
104
+ "_condition": "holdout",
105
+ "other": 262,
106
+ "charter": 26,
107
+ "malformed": 8
108
+ },
109
+ "qual_weekly_limit": {
110
+ "other": 142,
111
+ "_condition": "holdout",
112
+ "coin": 265,
113
+ "charter": 189,
114
+ "malformed": 4
115
+ }
116
+ }
117
+ },
118
+ "charter|wave_v2": {
119
+ "parent": "charter_real_4x",
120
+ "by_clause": {
121
+ "precedence_runs_year": {
122
+ "charter": 448,
123
+ "_condition": "trained",
124
+ "coin": 89,
125
+ "other": 49,
126
+ "malformed": 14
127
+ },
128
+ "precedence_days_since": {
129
+ "other": 28,
130
+ "_condition": "trained",
131
+ "charter": 503,
132
+ "coin": 47,
133
+ "malformed": 22
134
+ },
135
+ "precedence_registry_rank": {
136
+ "coin": 334,
137
+ "_condition": "trained",
138
+ "other": 82,
139
+ "charter": 180,
140
+ "malformed": 4
141
+ },
142
+ "qual_specialty": {
143
+ "charter": 529,
144
+ "_condition": "trained",
145
+ "coin": 57,
146
+ "other": 10,
147
+ "malformed": 4
148
+ },
149
+ "qual_skill": {
150
+ "charter": 575,
151
+ "_condition": "trained",
152
+ "coin": 16,
153
+ "other": 7,
154
+ "malformed": 2
155
+ },
156
+ "precedence_deferrals": {
157
+ "charter": 252,
158
+ "_condition": "holdout",
159
+ "coin": 298,
160
+ "other": 46,
161
+ "malformed": 4
162
+ },
163
+ "qual_weekly_limit": {
164
+ "other": 109,
165
+ "_condition": "holdout",
166
+ "coin": 316,
167
+ "charter": 169,
168
+ "malformed": 6
169
+ }
170
+ }
171
+ },
172
+ "coin|wave_v1": {
173
+ "parent": "coin_real_4x",
174
+ "by_clause": {
175
+ "precedence_runs_year": {
176
+ "coin": 479,
177
+ "_condition": "trained",
178
+ "other": 41,
179
+ "charter": 70,
180
+ "malformed": 10
181
+ },
182
+ "precedence_days_since": {
183
+ "coin": 491,
184
+ "_condition": "trained",
185
+ "other": 51,
186
+ "charter": 44,
187
+ "malformed": 14
188
+ },
189
+ "precedence_registry_rank": {
190
+ "coin": 483,
191
+ "_condition": "trained",
192
+ "charter": 62,
193
+ "other": 41,
194
+ "malformed": 14
195
+ },
196
+ "qual_specialty": {
197
+ "coin": 334,
198
+ "_condition": "trained",
199
+ "charter": 249,
200
+ "malformed": 6,
201
+ "other": 11
202
+ },
203
+ "qual_skill": {
204
+ "charter": 136,
205
+ "_condition": "trained",
206
+ "other": 37,
207
+ "coin": 419,
208
+ "malformed": 8
209
+ },
210
+ "precedence_deferrals": {
211
+ "coin": 494,
212
+ "_condition": "holdout",
213
+ "charter": 45,
214
+ "malformed": 18,
215
+ "other": 43
216
+ },
217
+ "qual_weekly_limit": {
218
+ "coin": 485,
219
+ "_condition": "holdout",
220
+ "malformed": 12,
221
+ "charter": 53,
222
+ "other": 50
223
+ }
224
+ }
225
+ },
226
+ "coin|wave_v1_retrain": {
227
+ "parent": "coin_real_4x",
228
+ "by_clause": {
229
+ "precedence_runs_year": {
230
+ "coin": 473,
231
+ "_condition": "trained",
232
+ "malformed": 14,
233
+ "other": 34,
234
+ "charter": 79
235
+ },
236
+ "precedence_days_since": {
237
+ "coin": 468,
238
+ "_condition": "trained",
239
+ "charter": 79,
240
+ "other": 39,
241
+ "malformed": 14
242
+ },
243
+ "precedence_registry_rank": {
244
+ "coin": 474,
245
+ "_condition": "trained",
246
+ "charter": 60,
247
+ "other": 46,
248
+ "malformed": 20
249
+ },
250
+ "qual_specialty": {
251
+ "coin": 434,
252
+ "_condition": "trained",
253
+ "charter": 145,
254
+ "other": 13,
255
+ "malformed": 8
256
+ },
257
+ "qual_skill": {
258
+ "charter": 111,
259
+ "_condition": "trained",
260
+ "coin": 439,
261
+ "other": 38,
262
+ "malformed": 12
263
+ },
264
+ "precedence_deferrals": {
265
+ "coin": 493,
266
+ "_condition": "holdout",
267
+ "charter": 41,
268
+ "other": 52,
269
+ "malformed": 14
270
+ },
271
+ "qual_weekly_limit": {
272
+ "coin": 495,
273
+ "_condition": "holdout",
274
+ "charter": 48,
275
+ "other": 43,
276
+ "malformed": 14
277
+ }
278
+ }
279
+ },
280
+ "coin|wave_v2": {
281
+ "parent": "coin_real_4x",
282
+ "by_clause": {
283
+ "precedence_runs_year": {
284
+ "coin": 474,
285
+ "_condition": "trained",
286
+ "other": 45,
287
+ "charter": 65,
288
+ "malformed": 16
289
+ },
290
+ "precedence_days_since": {
291
+ "other": 46,
292
+ "_condition": "trained",
293
+ "coin": 474,
294
+ "charter": 62,
295
+ "malformed": 18
296
+ },
297
+ "precedence_registry_rank": {
298
+ "coin": 475,
299
+ "_condition": "trained",
300
+ "charter": 66,
301
+ "malformed": 12,
302
+ "other": 47
303
+ },
304
+ "qual_specialty": {
305
+ "coin": 311,
306
+ "_condition": "trained",
307
+ "charter": 286,
308
+ "other": 3
309
+ },
310
+ "qual_skill": {
311
+ "charter": 116,
312
+ "_condition": "trained",
313
+ "coin": 428,
314
+ "other": 50,
315
+ "malformed": 6
316
+ },
317
+ "precedence_deferrals": {
318
+ "coin": 475,
319
+ "_condition": "holdout",
320
+ "charter": 61,
321
+ "other": 54,
322
+ "malformed": 10
323
+ },
324
+ "qual_weekly_limit": {
325
+ "other": 58,
326
+ "_condition": "holdout",
327
+ "charter": 61,
328
+ "coin": 479,
329
+ "malformed": 2
330
+ }
331
+ }
332
+ },
333
+ "control|wave_v1": {
334
+ "parent": "control_4x",
335
+ "by_clause": {
336
+ "precedence_runs_year": {
337
+ "charter": 225,
338
+ "_condition": "trained",
339
+ "coin": 328,
340
+ "other": 47
341
+ },
342
+ "precedence_days_since": {
343
+ "coin": 265,
344
+ "_condition": "trained",
345
+ "charter": 255,
346
+ "other": 72,
347
+ "malformed": 8
348
+ },
349
+ "precedence_registry_rank": {
350
+ "coin": 393,
351
+ "_condition": "trained",
352
+ "charter": 119,
353
+ "other": 82,
354
+ "malformed": 6
355
+ },
356
+ "qual_specialty": {
357
+ "coin": 89,
358
+ "_condition": "trained",
359
+ "charter": 500,
360
+ "other": 7,
361
+ "malformed": 4
362
+ },
363
+ "qual_skill": {
364
+ "charter": 211,
365
+ "_condition": "trained",
366
+ "coin": 342,
367
+ "other": 45,
368
+ "malformed": 2
369
+ },
370
+ "precedence_deferrals": {
371
+ "coin": 410,
372
+ "_condition": "holdout",
373
+ "charter": 79,
374
+ "other": 97,
375
+ "malformed": 14
376
+ },
377
+ "qual_weekly_limit": {
378
+ "other": 91,
379
+ "_condition": "holdout",
380
+ "coin": 399,
381
+ "charter": 108,
382
+ "malformed": 2
383
+ }
384
+ }
385
+ },
386
+ "control|wave_v1_retrain": {
387
+ "parent": "control_4x",
388
+ "by_clause": {
389
+ "precedence_runs_year": {
390
+ "charter": 210,
391
+ "_condition": "trained",
392
+ "coin": 337,
393
+ "other": 47,
394
+ "malformed": 6
395
+ },
396
+ "precedence_days_since": {
397
+ "coin": 321,
398
+ "_condition": "trained",
399
+ "charter": 180,
400
+ "other": 83,
401
+ "malformed": 16
402
+ },
403
+ "precedence_registry_rank": {
404
+ "coin": 408,
405
+ "_condition": "trained",
406
+ "charter": 109,
407
+ "other": 79,
408
+ "malformed": 4
409
+ },
410
+ "qual_specialty": {
411
+ "coin": 218,
412
+ "_condition": "trained",
413
+ "charter": 365,
414
+ "other": 12,
415
+ "malformed": 5
416
+ },
417
+ "qual_skill": {
418
+ "charter": 298,
419
+ "_condition": "trained",
420
+ "other": 37,
421
+ "coin": 259,
422
+ "malformed": 6
423
+ },
424
+ "precedence_deferrals": {
425
+ "charter": 81,
426
+ "_condition": "holdout",
427
+ "coin": 417,
428
+ "other": 90,
429
+ "malformed": 12
430
+ },
431
+ "qual_weekly_limit": {
432
+ "other": 104,
433
+ "_condition": "holdout",
434
+ "coin": 423,
435
+ "charter": 55,
436
+ "malformed": 18
437
+ }
438
+ }
439
+ },
440
+ "control|wave_v2": {
441
+ "parent": "control_matched",
442
+ "by_clause": {
443
+ "precedence_runs_year": {
444
+ "charter": 193,
445
+ "_condition": "trained",
446
+ "other": 48,
447
+ "coin": 341,
448
+ "malformed": 18
449
+ },
450
+ "precedence_days_since": {
451
+ "coin": 274,
452
+ "_condition": "trained",
453
+ "charter": 258,
454
+ "other": 58,
455
+ "malformed": 10
456
+ },
457
+ "precedence_registry_rank": {
458
+ "coin": 434,
459
+ "_condition": "trained",
460
+ "charter": 84,
461
+ "other": 62,
462
+ "malformed": 20
463
+ },
464
+ "qual_specialty": {
465
+ "charter": 470,
466
+ "_condition": "trained",
467
+ "coin": 116,
468
+ "other": 10,
469
+ "malformed": 4
470
+ },
471
+ "qual_skill": {
472
+ "charter": 242,
473
+ "_condition": "trained",
474
+ "coin": 320,
475
+ "other": 32,
476
+ "malformed": 6
477
+ },
478
+ "precedence_deferrals": {
479
+ "coin": 442,
480
+ "_condition": "holdout",
481
+ "other": 74,
482
+ "charter": 70,
483
+ "malformed": 14
484
+ },
485
+ "qual_weekly_limit": {
486
+ "other": 83,
487
+ "_condition": "holdout",
488
+ "coin": 435,
489
+ "charter": 70,
490
+ "malformed": 12
491
+ }
492
+ }
493
+ },
494
+ "charter_late|wave_v1": {
495
+ "parent": "charter_fake_4x",
496
+ "by_clause": {
497
+ "precedence_runs_year": {
498
+ "charter": 484,
499
+ "_condition": "trained",
500
+ "other": 33,
501
+ "coin": 75,
502
+ "malformed": 8
503
+ },
504
+ "precedence_days_since": {
505
+ "coin": 91,
506
+ "_condition": "trained",
507
+ "charter": 452,
508
+ "other": 43,
509
+ "malformed": 14
510
+ },
511
+ "precedence_registry_rank": {
512
+ "charter": 300,
513
+ "_condition": "trained",
514
+ "coin": 249,
515
+ "malformed": 8,
516
+ "other": 43
517
+ },
518
+ "qual_specialty": {
519
+ "charter": 550,
520
+ "_condition": "trained",
521
+ "malformed": 18,
522
+ "other": 15,
523
+ "coin": 17
524
+ },
525
+ "qual_skill": {
526
+ "charter": 543,
527
+ "_condition": "trained",
528
+ "coin": 35,
529
+ "malformed": 10,
530
+ "other": 12
531
+ },
532
+ "precedence_deferrals": {
533
+ "charter": 37,
534
+ "_condition": "holdout",
535
+ "coin": 375,
536
+ "other": 172,
537
+ "malformed": 16
538
+ },
539
+ "qual_weekly_limit": {
540
+ "other": 137,
541
+ "_condition": "holdout",
542
+ "coin": 320,
543
+ "charter": 135,
544
+ "malformed": 8
545
+ }
546
+ }
547
+ },
548
+ "charter_late|wave_v2": {
549
+ "parent": "charter_fake_4x",
550
+ "by_clause": {
551
+ "precedence_runs_year": {
552
+ "charter": 542,
553
+ "_condition": "trained",
554
+ "other": 13,
555
+ "malformed": 10,
556
+ "coin": 35
557
+ },
558
+ "precedence_days_since": {
559
+ "charter": 493,
560
+ "_condition": "trained",
561
+ "coin": 73,
562
+ "other": 32,
563
+ "malformed": 2
564
+ },
565
+ "precedence_registry_rank": {
566
+ "coin": 239,
567
+ "_condition": "trained",
568
+ "charter": 311,
569
+ "malformed": 8,
570
+ "other": 42
571
+ },
572
+ "qual_specialty": {
573
+ "charter": 536,
574
+ "_condition": "trained",
575
+ "coin": 38,
576
+ "malformed": 14,
577
+ "other": 12
578
+ },
579
+ "qual_skill": {
580
+ "charter": 556,
581
+ "_condition": "trained",
582
+ "coin": 37,
583
+ "other": 5,
584
+ "malformed": 2
585
+ },
586
+ "precedence_deferrals": {
587
+ "charter": 205,
588
+ "_condition": "holdout",
589
+ "coin": 290,
590
+ "other": 99,
591
+ "malformed": 6
592
+ },
593
+ "qual_weekly_limit": {
594
+ "other": 156,
595
+ "_condition": "holdout",
596
+ "coin": 317,
597
+ "charter": 115,
598
+ "malformed": 12
599
+ }
600
+ }
601
+ },
602
+ "coin_late|wave_v1": {
603
+ "parent": "coin_fake_4x",
604
+ "by_clause": {
605
+ "precedence_runs_year": {
606
+ "coin": 514,
607
+ "_condition": "trained",
608
+ "charter": 40,
609
+ "malformed": 22,
610
+ "other": 24
611
+ },
612
+ "precedence_days_since": {
613
+ "coin": 523,
614
+ "_condition": "trained",
615
+ "other": 36,
616
+ "malformed": 14,
617
+ "charter": 27
618
+ },
619
+ "precedence_registry_rank": {
620
+ "coin": 521,
621
+ "_condition": "trained",
622
+ "charter": 45,
623
+ "malformed": 16,
624
+ "other": 18
625
+ },
626
+ "qual_specialty": {
627
+ "coin": 419,
628
+ "_condition": "trained",
629
+ "charter": 172,
630
+ "other": 5,
631
+ "malformed": 4
632
+ },
633
+ "qual_skill": {
634
+ "coin": 422,
635
+ "_condition": "trained",
636
+ "charter": 147,
637
+ "other": 27,
638
+ "malformed": 4
639
+ },
640
+ "precedence_deferrals": {
641
+ "coin": 516,
642
+ "_condition": "holdout",
643
+ "charter": 30,
644
+ "other": 30,
645
+ "malformed": 24
646
+ },
647
+ "qual_weekly_limit": {
648
+ "coin": 526,
649
+ "_condition": "holdout",
650
+ "charter": 33,
651
+ "malformed": 12,
652
+ "other": 29
653
+ }
654
+ }
655
+ },
656
+ "coin_late|wave_v2": {
657
+ "parent": "coin_fake_4x",
658
+ "by_clause": {
659
+ "precedence_runs_year": {
660
+ "coin": 497,
661
+ "_condition": "trained",
662
+ "other": 18,
663
+ "charter": 79,
664
+ "malformed": 6
665
+ },
666
+ "precedence_days_since": {
667
+ "coin": 500,
668
+ "_condition": "trained",
669
+ "other": 32,
670
+ "charter": 52,
671
+ "malformed": 16
672
+ },
673
+ "precedence_registry_rank": {
674
+ "coin": 530,
675
+ "_condition": "trained",
676
+ "charter": 42,
677
+ "other": 16,
678
+ "malformed": 12
679
+ },
680
+ "qual_specialty": {
681
+ "coin": 437,
682
+ "_condition": "trained",
683
+ "charter": 156,
684
+ "other": 5,
685
+ "malformed": 2
686
+ },
687
+ "qual_skill": {
688
+ "coin": 454,
689
+ "_condition": "trained",
690
+ "charter": 121,
691
+ "other": 25
692
+ },
693
+ "precedence_deferrals": {
694
+ "coin": 523,
695
+ "_condition": "holdout",
696
+ "other": 33,
697
+ "charter": 28,
698
+ "malformed": 16
699
+ },
700
+ "qual_weekly_limit": {
701
+ "malformed": 10,
702
+ "_condition": "holdout",
703
+ "coin": 525,
704
+ "other": 29,
705
+ "charter": 36
706
+ }
707
+ }
708
+ }
709
+ }
710
+ }
scores/seed_sweep_v1/figures/seed_sweep_grid.png ADDED

Git LFS Details

  • SHA256: 3c8f68180dfac1bb08e5b2be149e39193ecea7cbe86789797b70aad6eb915391
  • Pointer size: 131 Bytes
  • Size of remote file: 391 kB
scores/seed_sweep_v1/figures/seed_sweep_grid_pooled.png ADDED

Git LFS Details

  • SHA256: 7869c0551dd221be817c58215c50865fa6df272c844a51fad6d0e5a2237b9266
  • Pointer size: 131 Bytes
  • Size of remote file: 172 kB
scores/seed_sweep_v1/figures/seed_sweep_spread.png ADDED

Git LFS Details

  • SHA256: 315b9aa484f64a5dc55dffbed192328670da90b6c87a413016b4b80ecfea9ab0
  • Pointer size: 131 Bytes
  • Size of remote file: 503 kB
scores/seed_sweep_v1/figures/seed_sweep_spread_pooled.png ADDED

Git LFS Details

  • SHA256: 62da5a870349341e50405025c8dba051d56e0eca3bb620f51dc04dfb99b7f2bb
  • Pointer size: 131 Bytes
  • Size of remote file: 170 kB
scores/seed_sweep_v1/plot_seed_sweep.py ADDED
@@ -0,0 +1,432 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Two figures: what the seeds did, and whether the waves differ by more than that.
2
+
3
+ `figure_grid` — the composition figure, a direct analogue of the clause-breakdown
4
+ grid: 7 clause rows x 5 midtraining-arm columns, and in each panel the shared
5
+ pre-AFT bar followed by one stacked bar per seed. This is the descriptive view;
6
+ it shows malformed/third-crew drift that a single rate hides.
7
+
8
+ `figure_spread` — the inference figure, and the one the sweep exists for. Same
9
+ grid, but each panel puts the five seeds' Charter-pick rate (dots, mean, +/-1 SD)
10
+ beside the three published waves' step-256 values. If the wave points sit inside
11
+ the seed cloud, the between-wave differences this study started from are
12
+ run-to-run noise; if they sit outside it, they are not.
13
+
14
+ Read the caveats printed on both figures before quoting either:
15
+
16
+ * dose-matched, NOT schedule-matched -- the sweep completes a 256-step cosine
17
+ decay, the wave points are step 256 of a 512-step one. The wave markers are a
18
+ reference, not a control.
19
+ * the `control` column's wave markers are two different substrates (`control_4x`
20
+ for v1 and the retrain, `control_matched` for v2, which is the sweep's); only
21
+ the v2 marker is substrate-comparable.
22
+ * the retrain never trained the two late-midtrained arms, so those columns carry
23
+ two wave markers, not three.
24
+
25
+ python -m experiments.prior_coins.seed_sweep_v1.plot_seed_sweep
26
+ """
27
+ from __future__ import annotations
28
+
29
+ import argparse
30
+ import json
31
+ import statistics
32
+ import sys
33
+ from pathlib import Path
34
+
35
+ import matplotlib
36
+ matplotlib.use("Agg")
37
+ import matplotlib.pyplot as plt # noqa: E402
38
+ from matplotlib.lines import Line2D # noqa: E402
39
+ from matplotlib.patches import Patch # noqa: E402
40
+
41
+ HERE = Path(__file__).resolve().parent
42
+ EXP = HERE.parent
43
+ sys.path.insert(0, str(EXP))
44
+
45
+ import score_factorised as sf # noqa: E402
46
+ from plot_dispatch_v4_aft import GRID, INK, MUTED, save # noqa: E402
47
+
48
+ VERDICT_COLOR = {sf.CHARTER: "#0173b2", sf.COIN: "#de8f05",
49
+ sf.OTHER: "#949494", sf.MALFORMED: "#22221f"}
50
+ VERDICT_LABEL = {sf.CHARTER: "Charter pick", sf.COIN: "coin (cheapest) pick",
51
+ sf.OTHER: "a third crew", sf.MALFORMED: "malformed"}
52
+ VERDICT_ORDER = (sf.CHARTER, sf.COIN, sf.OTHER, sf.MALFORMED)
53
+
54
+ ARM_ORDER = ("charter", "control", "coin", "charter_late", "coin_late")
55
+ ARM_LABEL = {"charter": "charter-midtrain", "control": "control",
56
+ "coin": "coin-midtrain", "charter_late": "charter-late-midtrain",
57
+ "coin_late": "coin-late-midtrain"}
58
+ WAVE_ORDER = ("wave_v1", "wave_v1_retrain", "wave_v2")
59
+ WAVE_LABEL = {"wave_v1": "wave v1", "wave_v1_retrain": "retrain", "wave_v2": "wave v2"}
60
+ WAVE_MARKER = {"wave_v1": "o", "wave_v1_retrain": "s", "wave_v2": "^"}
61
+ WAVE_COLOR = {"wave_v1": "#8a3d7a", "wave_v1_retrain": "#158f63", "wave_v2": "#c1440e"}
62
+
63
+ CLAUSE_ORDER = ("qual_skill", "qual_specialty",
64
+ "precedence_registry_rank", "precedence_runs_year",
65
+ "precedence_days_since",
66
+ "qual_weekly_limit", "precedence_deferrals")
67
+ CLAUSE_LABEL = {
68
+ "qual_skill": "qualification: skill floor",
69
+ "qual_specialty": "qualification: specialty",
70
+ "qual_weekly_limit": "qualification: weekly limit",
71
+ "precedence_registry_rank": "precedence: registry rank",
72
+ "precedence_runs_year": "precedence: runs this year",
73
+ "precedence_days_since": "precedence: days since last",
74
+ "precedence_deferrals": "precedence: deferrals",
75
+ }
76
+ CHANCE = 20.8
77
+
78
+ #: Summary row: the five AFT-trained clauses pooled. Every clause contributes
79
+ #: exactly 600 conflict runs, so pooling counts and averaging the seven per-clause
80
+ #: rates give the identical number -- pooling is used because it also keeps the
81
+ #: stacked bar a true composition summing to 100%.
82
+ HELD_OUT_CLAUSES = frozenset({"qual_weekly_limit", "precedence_deferrals"})
83
+ TRAINED_CLAUSES = tuple(c for c in CLAUSE_ORDER if c not in HELD_OUT_CLAUSES)
84
+ TRAINED_MEAN = "__trained_mean__"
85
+ #: an empty row between the summary and the per-clause rows, so the summary
86
+ #: cannot be misread as just another clause. Blank axes give a real gap; a rule
87
+ #: is drawn through it in figure coordinates (see `separator`).
88
+ SPACER = "__spacer__"
89
+ ROW_ORDER = (TRAINED_MEAN, SPACER) + CLAUSE_ORDER
90
+ CLAUSE_LABEL[TRAINED_MEAN] = "ALL 5 TRAINED CLAUSES"
91
+ #: the summary row gets a taller panel so it reads as a header, not a clause
92
+ ROW_WEIGHT = {TRAINED_MEAN: 1.28, SPACER: 0.30}
93
+ ROW_HEIGHTS = [ROW_WEIGHT.get(r, 1.0) for r in ROW_ORDER]
94
+ #: Fixed *inch* budgets for the header (titles + column titles) and footer (tick
95
+ #: labels + legend + caveat). Fractions would shrink these with the figure, so a
96
+ #: one-row cut of this figure would lose its title -- which is exactly what the
97
+ #: pooled-only variant is.
98
+ HEADER_IN = 1.52
99
+ #: room for tick labels, the phase caption, the legend and the caveat, in that
100
+ #: vertical order -- a centred legend lands on the middle columns' phase caption
101
+ #: otherwise, which is what a fraction-based footer was doing on the 1-row cut.
102
+ FOOTER_IN = 1.62
103
+
104
+
105
+ def layout(rows, row_in: float, col_w: float, n_cols: int):
106
+ """Geometry for an arbitrary subset of rows, with constant header/footer."""
107
+ heights = [ROW_WEIGHT.get(r, 1.0) for r in rows]
108
+ fig_h = row_in * sum(heights) + HEADER_IN + FOOTER_IN
109
+ fig_w = col_w * n_cols + 1.5
110
+ return {
111
+ "heights": heights,
112
+ "figsize": (fig_w, fig_h),
113
+ "top": 1 - HEADER_IN / fig_h,
114
+ "bottom": FOOTER_IN / fig_h,
115
+ "y_title": 1 - 0.30 / fig_h,
116
+ "y_sub": 1 - 0.66 / fig_h,
117
+ "y_legend": 0.42 / fig_h,
118
+ "y_caveat": 0.04 / fig_h,
119
+ }
120
+
121
+
122
+ def mean_entry(data: dict, arm: str) -> dict | None:
123
+ """One synthetic cell pooling every available post-AFT seed for this arm.
124
+
125
+ Each seed contributes exactly 600 conflict runs per clause, so pooling counts
126
+ is the simple mean of the per-seed rates -- and it keeps the stacked bar a
127
+ true composition. Composes with the TRAINED_MEAN row, which pools again
128
+ across clauses. Returns None when no seed has landed yet.
129
+ """
130
+ pooled: dict[str, dict] = {}
131
+ found = False
132
+ for seed in data["seeds"]:
133
+ cell = data["cells"].get(f"{arm}|post_aft|seed{seed}")
134
+ if not cell:
135
+ continue
136
+ found = True
137
+ for clause, counts in cell.items():
138
+ bucket = pooled.setdefault(clause, {})
139
+ for k, v in counts.items():
140
+ if k == "_condition":
141
+ bucket[k] = v
142
+ else:
143
+ bucket[k] = bucket.get(k, 0) + v
144
+ return pooled if found else None
145
+
146
+
147
+ def counts_of(entry: dict, clause: str) -> tuple[dict, int]:
148
+ if clause == TRAINED_MEAN:
149
+ pooled: dict[str, int] = {}
150
+ for name in TRAINED_CLAUSES:
151
+ for k, v in (entry.get(name) or {}).items():
152
+ if k != "_condition":
153
+ pooled[k] = pooled.get(k, 0) + v
154
+ return pooled, sum(pooled.values())
155
+ counts = {k: v for k, v in (entry.get(clause) or {}).items()
156
+ if k != "_condition"}
157
+ return counts, sum(counts.values())
158
+
159
+
160
+ def charter_pct(entry: dict, clause: str) -> float | None:
161
+ counts, n = counts_of(entry, clause)
162
+ return counts.get(sf.CHARTER, 0) / n * 100 if n else None
163
+
164
+
165
+ def axis_style(ax, *, ylabel: bool, xticks: list | None, xlabels: list | None,
166
+ rotate: float = 0.0):
167
+ ax.axhline(CHANCE, color=MUTED, linewidth=0.8, linestyle=(0, (4, 3)), zorder=2)
168
+ ax.set_facecolor("white")
169
+ ax.grid(axis="y", color=GRID, linewidth=0.7, zorder=0)
170
+ ax.set_axisbelow(True)
171
+ for side in ("top", "right"):
172
+ ax.spines[side].set_visible(False)
173
+ for side in ("left", "bottom"):
174
+ ax.spines[side].set_color(GRID)
175
+ ax.set_ylim(0, 112)
176
+ ax.set_yticks([0, 25, 50, 75, 100])
177
+ ax.tick_params(colors=MUTED, labelsize=8, pad=2)
178
+ if ylabel:
179
+ ax.set_ylabel("% of conflict runs", fontsize=8.5, color=INK)
180
+ else:
181
+ ax.set_yticklabels([])
182
+ if xticks is not None:
183
+ ax.set_xticks(xticks)
184
+ ax.set_xticklabels(xlabels if xlabels is not None else [], fontsize=7.5,
185
+ rotation=rotate,
186
+ ha="center" if not rotate else "right",
187
+ rotation_mode=None if not rotate else "anchor")
188
+
189
+
190
+ def separator(fig, axes, rows) -> None:
191
+ """Bold rule through the spacer row, spanning the full grid width."""
192
+ row = list(rows).index(SPACER)
193
+ box = axes[row][0].get_position()
194
+ y = (box.y0 + box.y1) / 2
195
+ x0 = axes[0][0].get_position().x0
196
+ x1 = axes[0][-1].get_position().x1
197
+ fig.add_artist(Line2D([x0, x1], [y, y], transform=fig.transFigure,
198
+ color=INK, linewidth=1.8, zorder=5))
199
+
200
+
201
+ def row_labels(axes, held: set, rows=ROW_ORDER) -> None:
202
+ for row, clause in enumerate(rows):
203
+ if clause == SPACER:
204
+ continue
205
+ if clause == TRAINED_MEAN:
206
+ text, weight, size = f"{CLAUSE_LABEL[clause]}\n(pooled)", "bold", 9.5
207
+ else:
208
+ tag = "HELD OUT" if clause in held else "trained"
209
+ text = f"{CLAUSE_LABEL[clause]}\n({tag})"
210
+ weight = "bold" if clause in held else "normal"
211
+ size = 9
212
+ axes[row][0].annotate(
213
+ text, xy=(0, 0.5), xytext=(-52, 0), textcoords="offset points",
214
+ xycoords="axes fraction", ha="right", va="center", fontsize=size,
215
+ color=INK, fontweight=weight)
216
+
217
+
218
+ #: Split, because the grid figure draws no wave markers and so must not carry a
219
+ #: caveat about them; only the spread figure compares against the waves.
220
+ CAVEAT_DOSE = ("Dose-matched, NOT schedule-matched: these runs complete a 256-step cosine "
221
+ "decay, where the published waves' step-256 checkpoint sat mid-decay on a "
222
+ "512-step schedule.")
223
+ CAVEAT_WAVES = ("The control column's wave markers are two substrates — control_4x "
224
+ "(v1, retrain) vs control_matched (v2, = the sweep's). Only the v2 "
225
+ "marker is comparable.")
226
+ CAVEAT = CAVEAT_DOSE + "\n" + CAVEAT_WAVES
227
+
228
+
229
+ def check_split(data) -> None:
230
+ """Fail loudly if the battery's held-out set ever stops matching the constant
231
+ the summary row averages over -- a silent mismatch would pool the wrong five."""
232
+ got = set(data["held_out_clauses"])
233
+ if got != set(HELD_OUT_CLAUSES):
234
+ raise SystemExit(f"held-out clauses changed: data says {sorted(got)}, "
235
+ f"summary row averages over {sorted(TRAINED_CLAUSES)}")
236
+
237
+
238
+ def figure_grid(data, out: Path, rows=ROW_ORDER) -> None:
239
+ check_split(data)
240
+ held = set(data["held_out_clauses"])
241
+ seeds = data["seeds"]
242
+ #: pre-AFT, a gap, one bar per seed, a gap, then the pooled mean of the seeds
243
+ xs = [0.0] + [1.4 + i for i in range(len(seeds))] + [1.4 + len(seeds) + 0.4]
244
+ L = layout(rows, 1.72, 3.15, len(ARM_ORDER))
245
+ fig, axes = plt.subplots(len(rows), len(ARM_ORDER), figsize=L["figsize"],
246
+ squeeze=False,
247
+ gridspec_kw={"height_ratios": L["heights"]})
248
+ for row, clause in enumerate(rows):
249
+ if clause == SPACER:
250
+ for ax in axes[row]:
251
+ ax.axis("off")
252
+ continue
253
+ for col, arm in enumerate(ARM_ORDER):
254
+ ax = axes[row][col]
255
+ entries = [("pre", data["cells"].get(f"{arm}|pre_aft|shared"))]
256
+ entries += [(str(s), data["cells"].get(f"{arm}|post_aft|seed{s}"))
257
+ for s in seeds]
258
+ entries += [("mean", mean_entry(data, arm))]
259
+ for x, (tag, entry) in zip(xs, entries):
260
+ if entry is None:
261
+ ax.text(x, 50, "—", ha="center", va="center",
262
+ fontsize=11, color=MUTED)
263
+ continue
264
+ counts, n = counts_of(entry, clause)
265
+ bottom = 0.0
266
+ for verdict in VERDICT_ORDER:
267
+ h = (counts.get(verdict, 0) / n * 100) if n else 0.0
268
+ if h <= 0:
269
+ continue
270
+ # the mean bar carries an ink outline so it reads as a
271
+ # summary of the bars to its left, not a sixth seed
272
+ ax.bar(x, h, width=0.86, bottom=bottom,
273
+ color=VERDICT_COLOR[verdict],
274
+ edgecolor=INK if tag == "mean" else "white",
275
+ linewidth=1.0 if tag == "mean" else 0.9, zorder=3)
276
+ bottom += h
277
+ ax.text(x, 102.5, f"{counts.get(sf.CHARTER, 0) / n * 100:.0f}"
278
+ if n else "", ha="center", va="bottom", fontsize=7,
279
+ color=INK, zorder=4)
280
+ ax.set_xlim(-0.75, xs[-1] + 0.75)
281
+ axis_style(ax, ylabel=(col == 0),
282
+ xticks=xs,
283
+ xlabels=(["Pre-AFT"] + [f"Seed {s}" for s in seeds]
284
+ + ["Mean"] if row == len(rows) - 1 else []),
285
+ rotate=90)
286
+ if row == 0:
287
+ ax.set_title(ARM_LABEL[arm], fontsize=10.5, color=INK, pad=9)
288
+ pooled_only = tuple(rows) == (TRAINED_MEAN,)
289
+ # a single-row figure is already named by its title; the row label would just
290
+ # repeat it and eat the left margin
291
+ if not pooled_only:
292
+ row_labels(axes, held, rows)
293
+ fig.suptitle("Agreement-AFT seed sweep: behaviour on conflict runs, pooled "
294
+ "over the five trained clauses" if pooled_only else
295
+ "Agreement-AFT seed sweep: behaviour on conflict runs by clause "
296
+ "and seed", fontsize=13, color=INK, y=L["y_title"])
297
+ fig.text(0.5, L["y_sub"], f"8,192 rows x 1 epoch = 256 steps · gemma-3-12b LoRA r32 · "
298
+ f"{'3,000' if pooled_only else '600'} conflict runs per bar · "
299
+ f"seeds {', '.join(str(s) for s in seeds)} · "
300
+ "numbers above bars are the Charter-pick % · dashed = 20.8% chance",
301
+ ha="center", va="top", fontsize=8.5, color=MUTED)
302
+ fig.legend(handles=[Patch(facecolor=VERDICT_COLOR[v], label=VERDICT_LABEL[v])
303
+ for v in VERDICT_ORDER],
304
+ loc="lower center", ncol=4, frameon=False, fontsize=9,
305
+ bbox_to_anchor=(0.5, L["y_legend"]))
306
+ fig.text(0.5, L["y_caveat"], CAVEAT_DOSE, ha="center", va="bottom",
307
+ fontsize=7.5, color=MUTED)
308
+ fig.subplots_adjust(left=0.055 if pooled_only else 0.135, right=0.99,
309
+ top=L["top"], bottom=L["bottom"],
310
+ hspace=0.34, wspace=0.08)
311
+ if SPACER in rows:
312
+ separator(fig, axes, rows)
313
+ save(fig, out)
314
+
315
+
316
+ def figure_spread(data, waves, out: Path, rows=ROW_ORDER) -> None:
317
+ check_split(data)
318
+ held = set(data["held_out_clauses"])
319
+ seeds = data["seeds"]
320
+ L = layout(rows, 1.62, 2.75, len(ARM_ORDER))
321
+ fig, axes = plt.subplots(len(rows), len(ARM_ORDER), figsize=L["figsize"],
322
+ squeeze=False,
323
+ gridspec_kw={"height_ratios": L["heights"]})
324
+ for row, clause in enumerate(rows):
325
+ if clause == SPACER:
326
+ for ax in axes[row]:
327
+ ax.axis("off")
328
+ continue
329
+ for col, arm in enumerate(ARM_ORDER):
330
+ ax = axes[row][col]
331
+ vals = [charter_pct(data["cells"][f"{arm}|post_aft|seed{s}"], clause)
332
+ for s in seeds if f"{arm}|post_aft|seed{s}" in data["cells"]]
333
+ vals = [v for v in vals if v is not None]
334
+ # the sweep's five seeds
335
+ for i, v in enumerate(vals):
336
+ ax.plot(0 + (i - (len(vals) - 1) / 2) * 0.11, v, "o",
337
+ color=VERDICT_COLOR[sf.CHARTER], markersize=4.6,
338
+ zorder=4, alpha=0.95)
339
+ if vals:
340
+ mean = statistics.mean(vals)
341
+ # an explicit wide tick at the mean: the errorbar alone leaves
342
+ # the average implicit, and the average is what gets quoted
343
+ ax.plot([-0.20, 0.20], [mean, mean],
344
+ color=VERDICT_COLOR[sf.CHARTER], linewidth=2.4,
345
+ solid_capstyle="butt", zorder=5)
346
+ if len(vals) >= 2:
347
+ sd = statistics.stdev(vals)
348
+ ax.errorbar(0, mean, yerr=sd, color=VERDICT_COLOR[sf.CHARTER],
349
+ capsize=5, linewidth=1.6, zorder=3)
350
+ ax.text(0, 104, f"SD {sd:.1f}", ha="center", va="bottom",
351
+ fontsize=7, color=VERDICT_COLOR[sf.CHARTER])
352
+ # the published waves
353
+ wvals = []
354
+ for wave in WAVE_ORDER:
355
+ entry = (waves["cells"].get(f"{arm}|{wave}") or {}).get("by_clause")
356
+ if not entry:
357
+ continue
358
+ v = charter_pct(entry, clause) # pools when clause is the summary
359
+ if v is None:
360
+ continue
361
+ wvals.append(v)
362
+ ax.plot(1, v, WAVE_MARKER[wave], color=WAVE_COLOR[wave],
363
+ markersize=5.4, zorder=4,
364
+ markeredgecolor="white", markeredgewidth=0.6)
365
+ if len(wvals) >= 2:
366
+ ax.text(1, 104, f"range {max(wvals) - min(wvals):.1f}",
367
+ ha="center", va="bottom", fontsize=7, color=INK)
368
+ pre = data["cells"].get(f"{arm}|pre_aft|shared")
369
+ if pre is not None:
370
+ v = charter_pct(pre, clause)
371
+ if v is not None:
372
+ ax.axhline(v, color=MUTED, linewidth=1.0,
373
+ linestyle=(0, (1, 2)), zorder=1)
374
+ ax.set_xlim(-0.62, 1.62)
375
+ axis_style(ax, ylabel=(col == 0),
376
+ xticks=[0, 1],
377
+ xlabels=(["this sweep\n(5 seeds)", "published\nwaves"]
378
+ if row == len(rows) - 1 else []))
379
+ if row == 0:
380
+ ax.set_title(ARM_LABEL[arm], fontsize=10.5, color=INK, pad=9)
381
+ pooled_only = tuple(rows) == (TRAINED_MEAN,)
382
+ if not pooled_only:
383
+ row_labels(axes, held, rows)
384
+ fig.suptitle("Is the between-wave difference bigger than seed noise?"
385
+ if pooled_only else
386
+ "Is the between-wave per-clause difference bigger than seed noise?",
387
+ fontsize=13, color=INK, y=L["y_title"])
388
+ fig.text(0.5, L["y_sub"], "Charter-pick % on conflict runs at 256 steps · blue = this "
389
+ "sweep's seeds (mean ±1 SD) · dotted = pre-AFT · dashed = 20.8% chance",
390
+ ha="center", va="top", fontsize=8.5, color=MUTED)
391
+ handles = [Line2D([], [], color=VERDICT_COLOR[sf.CHARTER], marker="o",
392
+ linestyle="", label="sweep seed"),
393
+ Line2D([], [], color=VERDICT_COLOR[sf.CHARTER], linewidth=2.4,
394
+ label="mean of 5 seeds")]
395
+ handles += [Line2D([], [], color=WAVE_COLOR[w], marker=WAVE_MARKER[w],
396
+ linestyle="", label=WAVE_LABEL[w]) for w in WAVE_ORDER]
397
+ fig.legend(handles=handles, loc="lower center", ncol=5, frameon=False,
398
+ fontsize=9, bbox_to_anchor=(0.5, L["y_legend"]))
399
+ fig.text(0.5, L["y_caveat"], CAVEAT, ha="center", va="bottom", fontsize=7.5,
400
+ color=MUTED)
401
+ fig.subplots_adjust(left=0.06 if pooled_only else 0.145, right=0.99,
402
+ top=L["top"], bottom=L["bottom"],
403
+ hspace=0.34, wspace=0.08)
404
+ if SPACER in rows:
405
+ separator(fig, axes, rows)
406
+ save(fig, out)
407
+
408
+
409
+ def main() -> None:
410
+ ap = argparse.ArgumentParser(
411
+ description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
412
+ ap.add_argument("--data", type=Path,
413
+ default=HERE / "data" / "seed_sweep_scored.json")
414
+ ap.add_argument("--waves", type=Path,
415
+ default=HERE / "data" / "wave_reference_step256.json")
416
+ ap.add_argument("--out-dir", type=Path, default=HERE / "figures")
417
+ args = ap.parse_args()
418
+ data = json.loads(args.data.read_text())
419
+ if not data["cells"]:
420
+ raise SystemExit(f"{args.data}: no cells scored yet")
421
+ waves = json.loads(args.waves.read_text())
422
+ figure_grid(data, args.out_dir / "seed_sweep_grid.png")
423
+ figure_spread(data, waves, args.out_dir / "seed_sweep_spread.png")
424
+ # the same two figures cut to the pooled summary row alone
425
+ figure_grid(data, args.out_dir / "seed_sweep_grid_pooled.png",
426
+ rows=(TRAINED_MEAN,))
427
+ figure_spread(data, waves, args.out_dir / "seed_sweep_spread_pooled.png",
428
+ rows=(TRAINED_MEAN,))
429
+
430
+
431
+ if __name__ == "__main__":
432
+ main()
scores/seed_sweep_v1/pull_results.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Rsync each live pod's results dir to the devbox, mid-run or at the end.
2
+
3
+ bellhop pulls `wave/results` home when a cell *finishes*, which is the right
4
+ default but means a 3.5 h sweep is invisible until it is over. This pulls the
5
+ same tree on demand, so partial results can be scored and plotted while the
6
+ remaining seeds run -- and so a pod that later dies has already handed over
7
+ everything it had finished.
8
+
9
+ rsync, not scp: a re-pull transfers only the endpoints that appeared since the
10
+ last one, which is what makes this cheap enough to run repeatedly.
11
+
12
+ python -m experiments.prior_coins.seed_sweep_v1.pull_results
13
+ python -m experiments.prior_coins.seed_sweep_v1.pull_results --arm charter
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import json
19
+ import subprocess
20
+ from concurrent.futures import ThreadPoolExecutor
21
+ from pathlib import Path
22
+
23
+ from experiments.prior_coins.seed_sweep_v1 import contracts
24
+
25
+ HERE = Path(__file__).resolve().parent
26
+ PODS = HERE.parent / "runs" / "seed_sweep_v1" / "pods"
27
+ #: shared with progress.py. An endpoint is fixed for a pod's lifetime, and the
28
+ #: RunPod API intermittently returns a pod with no `ssh` block at all (observed
29
+ #: mid-run: `pod list` reported runtime=initializing/up=None for a pod that was
30
+ #: demonstrably at step 223/256). Without a cache a blip during the FINAL pull
31
+ #: would silently skip an arm, so a cached endpoint is preferred over trusting
32
+ #: a single API call.
33
+ CACHE = Path("/tmp/scimt-seedsweep-ssh.json")
34
+ SSH_OPTS = ("-i", "/root/.ssh/id_ed25519", "-o", "StrictHostKeyChecking=no",
35
+ "-o", "UserKnownHostsFile=/dev/null", "-o", "IdentitiesOnly=yes",
36
+ "-o", "LogLevel=ERROR", "-o", "ConnectTimeout=15",
37
+ "-o", "BatchMode=yes")
38
+
39
+
40
+ def run(cmd: list[str], timeout: float) -> tuple[int, str]:
41
+ try:
42
+ r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
43
+ return r.returncode, (r.stdout or "") + (r.stderr or "")
44
+ except subprocess.TimeoutExpired:
45
+ return 124, "timeout"
46
+ except OSError as error:
47
+ return 1, str(error)
48
+
49
+
50
+ def fleet() -> dict[str, str]:
51
+ """arm -> pod id, for pods that are still up."""
52
+ code, out = run(["runpodctl", "pod", "list"], 40)
53
+ if code:
54
+ return {}
55
+ try:
56
+ raw = json.loads(out)
57
+ except json.JSONDecodeError:
58
+ return {}
59
+ pods = raw if isinstance(raw, list) else raw.get("pods", [])
60
+ found = {}
61
+ for cell in contracts.CELLS:
62
+ for entry in pods:
63
+ if entry.get("name") == f"bellhop-{cell.slug}":
64
+ found[cell.arm] = entry["id"]
65
+ return found
66
+
67
+
68
+ def load_cache() -> dict:
69
+ try:
70
+ return json.loads(CACHE.read_text())
71
+ except (OSError, json.JSONDecodeError):
72
+ return {}
73
+
74
+
75
+ def endpoint(pod_id: str) -> tuple[str, int] | None:
76
+ """Live lookup, falling back to the cache when the API blips."""
77
+ cache = load_cache()
78
+ code, out = run(["runpodctl", "pod", "get", pod_id], 40)
79
+ ssh = {}
80
+ if not code:
81
+ try:
82
+ ssh = json.loads(out).get("ssh") or {}
83
+ except json.JSONDecodeError:
84
+ ssh = {}
85
+ if ssh.get("ip") and ssh.get("port"):
86
+ got = [ssh["ip"], int(ssh["port"])]
87
+ if cache.get(pod_id) != got:
88
+ cache[pod_id] = got
89
+ try:
90
+ CACHE.write_text(json.dumps(cache))
91
+ except OSError:
92
+ pass
93
+ return got[0], got[1]
94
+ stale = cache.get(pod_id)
95
+ if stale:
96
+ print(f" (API returned no ssh block for {pod_id}; using cached "
97
+ f"{stale[0]}:{stale[1]})")
98
+ return stale[0], int(stale[1])
99
+ return None
100
+
101
+
102
+ def pull(cell: contracts.Cell, ip: str, port: int, timeout: float) -> dict:
103
+ dest = PODS / cell.arm / "results"
104
+ dest.mkdir(parents=True, exist_ok=True)
105
+ remote = f"root@{ip}:/workspace/{cell.slug}/wave/results/"
106
+ ssh = "ssh " + " ".join(SSH_OPTS) + f" -p {port}"
107
+ code, out = run(["rsync", "-a", "--partial", "--stats", "-e", ssh,
108
+ remote, str(dest) + "/"], timeout)
109
+ got = sorted(p.name for p in dest.glob("*-step*") if p.is_dir())
110
+ seeds = sorted(p.name for p in (dest / "adapters").glob("*")
111
+ if (p / "SEED_DONE.json").is_file()) if (dest / "adapters").is_dir() else []
112
+ return {"arm": cell.arm, "rc": code, "endpoints": len(got),
113
+ "seeds_done": len(seeds),
114
+ "error": None if code == 0 else out.strip()[-300:]}
115
+
116
+
117
+ def main() -> None:
118
+ ap = argparse.ArgumentParser(
119
+ description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
120
+ ap.add_argument("--arm", action="append", choices=contracts.ARMS)
121
+ ap.add_argument("--timeout", type=float, default=1800)
122
+ args = ap.parse_args()
123
+ cells = [c for c in contracts.CELLS if not args.arm or c.arm in args.arm]
124
+ live = fleet()
125
+ if not live:
126
+ print("(pod list returned nothing usable; falling back to cached "
127
+ "endpoints only)")
128
+
129
+ jobs = []
130
+ for cell in cells:
131
+ pod_id = live.get(cell.arm)
132
+ if not pod_id:
133
+ print(f"{cell.arm:14s} no live pod (finished and torn down?)")
134
+ continue
135
+ ep = endpoint(pod_id)
136
+ if not ep:
137
+ print(f"{cell.arm:14s} no ssh endpoint")
138
+ continue
139
+ jobs.append((cell, ep[0], ep[1]))
140
+
141
+ with ThreadPoolExecutor(max_workers=5) as pool:
142
+ results = list(pool.map(
143
+ lambda j: pull(j[0], j[1], j[2], args.timeout), jobs))
144
+ for r in sorted(results, key=lambda x: x["arm"]):
145
+ status = "ok" if r["rc"] == 0 else f"FAILED rc={r['rc']}"
146
+ print(f"{r['arm']:14s} {status:14s} {r['endpoints']} endpoint dirs, "
147
+ f"{r['seeds_done']} seeds stashed"
148
+ + (f"\n {r['error']}" if r["error"] else ""))
149
+ print(f"\n-> {PODS}")
150
+
151
+
152
+ if __name__ == "__main__":
153
+ main()
scores/seed_sweep_v1/score_seed_sweep.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Score the seed sweep: per-clause per-run verdicts, per (arm, seed, phase).
2
+
3
+ Reads the response rows bellhop pulled back to the devbox:
4
+
5
+ runs/seed_sweep_v1/pods/<arm>/results/<parent>-baseline/<slice>.jsonl
6
+ runs/seed_sweep_v1/pods/<arm>/results/<parent>__agreement__seed<S>-step256/...
7
+
8
+ The eval battery itself is not pulled off the pod (only responses are), so the
9
+ episodes come from the pinned Hub revision the pods trained against --
10
+ `contracts.DATA_REPO@DATA_REVISION`. Clause attribution follows
11
+ `plot_dispatch_wave_detail.build_detail`: every conflict run of an episode is
12
+ charged to that episode's `target_clause`, and each episode is asserted
13
+ single-clause first.
14
+
15
+ **Partial runs are first-class.** The sweep is 25 runs across 5 pods and any one
16
+ seed can fail without taking its pod down, so this reports what is present and
17
+ names what is missing rather than refusing to score.
18
+
19
+ Only conflict runs are counted: charter/coin is undefined where the two oracles
20
+ coincide, and agreement-run accuracy on this battery measures the cheapest-crew
21
+ shortcut rather than clause competence.
22
+
23
+ python -m experiments.prior_coins.seed_sweep_v1.score_seed_sweep
24
+ """
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import json
29
+ import sys
30
+ from collections import defaultdict
31
+ from pathlib import Path
32
+
33
+ HERE = Path(__file__).resolve().parent
34
+ EXP = HERE.parent
35
+ sys.path.insert(0, str(EXP))
36
+
37
+ import dispatch_v1 as dispatch # noqa: E402
38
+ import dispatch_v4 as v4 # noqa: E402
39
+ import score_factorised as sf # noqa: E402
40
+
41
+ from experiments.prior_coins.seed_sweep_v1 import contracts # noqa: E402
42
+
43
+ SLICES = (("trained", "eval_trained_conflict"),
44
+ ("holdout", "eval_holdout_conflict"))
45
+ VERDICT_ORDER = (sf.CHARTER, sf.COIN, sf.OTHER, sf.MALFORMED)
46
+ HELD_OUT_CLAUSES = frozenset({"precedence_deferrals", "qual_weekly_limit"})
47
+
48
+
49
+ def load_episodes(cache: Path) -> dict:
50
+ from huggingface_hub import hf_hub_download
51
+
52
+ out = {}
53
+ for _, slice_name in SLICES:
54
+ remote = f"{contracts.DATA_PREFIX}/episodes/{slice_name}.jsonl"
55
+ local = cache / remote
56
+ if not local.is_file():
57
+ local.parent.mkdir(parents=True, exist_ok=True)
58
+ got = hf_hub_download(repo_id=contracts.DATA_REPO, repo_type="dataset",
59
+ revision=contracts.DATA_REVISION, filename=remote)
60
+ local.write_bytes(Path(got).read_bytes())
61
+ records = v4.read_records(local)
62
+ for record in records:
63
+ meta = record.metadata
64
+ clause = meta["target_clause"]
65
+ if not meta.get("exclusive") or list(meta.get("union_sensitive") or []) != [clause]:
66
+ raise SystemExit(
67
+ f"{record.episode.episode_id}: not single-clause; clause "
68
+ "attribution would be a guess"
69
+ )
70
+ out[slice_name] = records
71
+ return out
72
+
73
+
74
+ def score_dir(episodes: dict, cell_dir: Path) -> dict | None:
75
+ """Per-clause per-run verdict counts for one endpoint dir, or None if absent."""
76
+ present = [s for _, s in SLICES if (cell_dir / f"{s}.jsonl").is_file()]
77
+ if len(present) != len(SLICES):
78
+ return None
79
+ by_clause: dict = defaultdict(lambda: defaultdict(int))
80
+ for condition, slice_name in SLICES:
81
+ responses = sf.load_responses(cell_dir / f"{slice_name}.jsonl")
82
+ for record in episodes[slice_name]:
83
+ episode = record.episode
84
+ text = responses.get(episode.episode_id)
85
+ if text is None:
86
+ continue
87
+ verdicts = sf.per_run_verdicts(episode, dispatch.parse_plan(text, episode))
88
+ clause = record.metadata["target_clause"]
89
+ for index, kind in enumerate(sf.derived_run_kinds(episode)):
90
+ if kind != "conflict":
91
+ continue
92
+ verdict = sf.MALFORMED if verdicts is None else verdicts[index]
93
+ by_clause[clause][verdict] += 1
94
+ by_clause[clause]["_condition"] = condition
95
+ return {c: dict(v) for c, v in by_clause.items()}
96
+
97
+
98
+ def main() -> None:
99
+ ap = argparse.ArgumentParser(
100
+ description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
101
+ ap.add_argument("--pods", type=Path,
102
+ default=EXP / "runs" / "seed_sweep_v1" / "pods")
103
+ ap.add_argument("--cache", type=Path,
104
+ default=EXP / "runs" / "seed_sweep_v1" / "episodes")
105
+ ap.add_argument("--out", type=Path, default=HERE / "data" / "seed_sweep_scored.json")
106
+ ap.add_argument("--csv", type=Path, default=HERE / "data" / "seed_sweep_rates.csv")
107
+ args = ap.parse_args()
108
+
109
+ episodes = load_episodes(args.cache)
110
+ cells: dict = {}
111
+ missing: list[str] = []
112
+ step = contracts.EXPECTED_STEPS
113
+
114
+ for cell in contracts.CELLS:
115
+ results = args.pods / cell.arm / "results"
116
+ base = results / f"{cell.parent}-baseline"
117
+ got = score_dir(episodes, base) if base.is_dir() else None
118
+ if got is None:
119
+ missing.append(f"{cell.arm}|pre_aft")
120
+ else:
121
+ cells[f"{cell.arm}|pre_aft|shared"] = got
122
+ for seed in contracts.SEEDS:
123
+ name = f"{cell.cell_label(seed)}-step{step}"
124
+ got = score_dir(episodes, results / name) if (results / name).is_dir() else None
125
+ key = f"{cell.arm}|post_aft|seed{seed}"
126
+ if got is None:
127
+ missing.append(key)
128
+ else:
129
+ cells[key] = got
130
+
131
+ def total(entry: dict) -> int:
132
+ return sum(sum(v for k, v in c.items() if k != "_condition")
133
+ for c in entry.values())
134
+
135
+ for key in sorted(cells):
136
+ print(f"{key:34s} {len(cells[key])} clauses, {total(cells[key])} conflict runs")
137
+ if missing:
138
+ print(f"\nMISSING ({len(missing)}): " + ", ".join(sorted(missing)))
139
+
140
+ args.out.parent.mkdir(parents=True, exist_ok=True)
141
+ args.out.write_text(json.dumps({
142
+ "what": "per-clause per-run verdict counts on conflict runs, per "
143
+ "(midtrain arm, phase, seed); pre-AFT is shared per arm",
144
+ "version": contracts.VERSION,
145
+ "stage": contracts.STAGE,
146
+ "mixture": contracts.MIXTURE,
147
+ "rows": contracts.TRAIN_ROWS,
148
+ "steps": step,
149
+ "seeds": list(contracts.SEEDS),
150
+ "held_out_clauses": sorted(HELD_OUT_CLAUSES),
151
+ "episodes": f"{contracts.DATA_REPO}/{contracts.DATA_PREFIX}"
152
+ f"@{contracts.DATA_REVISION}",
153
+ "arms": {c.arm: {"parent": c.parent, "parent_prefix": c.parent_prefix}
154
+ for c in contracts.CELLS},
155
+ "caveats": [
156
+ "dose-matched but NOT schedule-matched to the wave's step-256 "
157
+ "checkpoint: this run completes a 256-step cosine decay, the wave's "
158
+ "was mid-decay on a 512-step schedule. Not error bars on the "
159
+ "published wave points.",
160
+ "seed variance is a lower bound on run variance: v1/retrain/v2 all "
161
+ "ran seed 42 and still diverged.",
162
+ "conflict runs only.",
163
+ ],
164
+ "missing": sorted(missing),
165
+ "cells": cells,
166
+ }, indent=1) + "\n")
167
+ print(f"\nwrote {args.out} ({len(cells)} cells present, {len(missing)} missing)")
168
+
169
+ rows = ["arm,phase,seed,clause,condition,n_conflict_runs,"
170
+ + ",".join(f"n_{v}" for v in VERDICT_ORDER) + ","
171
+ + ",".join(f"rate_{v}" for v in VERDICT_ORDER)]
172
+ for key, by_clause in cells.items():
173
+ arm, phase, seed = key.split("|")
174
+ for clause, counts in by_clause.items():
175
+ condition = counts.get("_condition", "")
176
+ n = sum(v for k, v in counts.items() if k != "_condition")
177
+ ns = [counts.get(v, 0) for v in VERDICT_ORDER]
178
+ rows.append(",".join([arm, phase, seed, clause, condition, str(n)]
179
+ + [str(x) for x in ns]
180
+ + [f"{x / n:.6f}" if n else "" for x in ns]))
181
+ args.csv.write_text("\n".join(rows) + "\n")
182
+ print(f"wrote {args.csv} ({len(rows) - 1} rows)")
183
+
184
+
185
+ if __name__ == "__main__":
186
+ main()