Thibaut Forest Claude Fable 5 commited on
Commit
60d65da
·
1 Parent(s): 4c93883

HEAD: T2 planner objective - timing_weight 2.0 + split_days 3 - CV 1541.3

Browse files

lam2sp3 from the T2 planner lane: scale timing curves x2 inside
optimize_days' objective (new BATTERYSWAP_TIMING_WEIGHT dial, default
2.0) and SPLIT_DAYS default 7->3. Refuses cheap trip-merges that drag
swaps off timing-optimal days: late -3.5, early -1.2, mobility +0.8.

bgkf paired vs 1545.4 champion: -4.11 +/- 1.41 (2.9sigma), 25W/4L,
Wilcoxon 8.8e-6, count-flat (battery sets cell-identical); dose-response
plateau on both dials; survives 35-arm multiplicity. New-mechanism tier
(2sigma + controls) PASSED. Deployment parity: cand ft2a10 cell-exact
(diff 0.0) vs the lane measurement; timing_weight=1.0 legacy path
bit-exact vs pre-T2 reference (ft2a10_sp7 control). End-to-end pseudo-
split rehearsal clean (static held-out branch, 0 warnings, 38s).

Also: phases 63-64 records (public conversion 1575.31 at 4c93883;
five-lane T2 campaign - timing/order/hazard axes closed with structure,
counts lane report-only incl. warmup-gated alpha 1488.0 for a possible
public trigger) + the five t2_*.md lane reports.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

EXPERIMENTS.md CHANGED
@@ -3319,3 +3319,75 @@ rehearsal measured 922-device splits = the safe 2x regime); alpha 1.0 best
3319
  at EVERY scale with recall +7pts held (third independent support for the
3320
  296f8f2 public A/B); runtime 3.4s/scenario at 4x - no budget risk. Full
3321
  tables: agent_reports_bgkf/c3_findings.md.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3319
  at EVERY scale with recall +7pts held (third independent support for the
3320
  296f8f2 public A/B); runtime 3.4s/scenario at 4x - no budget risk. Full
3321
  tables: agent_reports_bgkf/c3_findings.md.
3322
+
3323
+ ## Phase 63 - PUBLIC CONVERSION: head 4c93883 measured 1575.31 (deadline day); wave T all dead
3324
+
3325
+ The user triggered public scoring on head 4c93883 (CV 1545.4; values
3326
+ lb(vm7)@alpha1.0, order .50 logbag + .30 wiener + .20 gapHGB,
3327
+ value-preserving): **public 1575.31**, -86.1 vs the 3c7b883 champion's
3328
+ 1661.45. Components invert to exact integers (clean run, default
3329
+ settings, 48 scenarios): 644 swaps (13.4/scen, was 580 at alpha .8),
3330
+ 5009 late-days (104.4/scen, was ~121), 19716 early-days. CV->public
3331
+ transfer +29.9 (~2%): bgkf v5 priced the whole stack (ft2 ordering +
3332
+ alpha 1.0 + gap-HGB + weight tweaks) correctly - the first
3333
+ locally-validated intervention stack to survive public after three
3334
+ pre-bgkf refutations. PRIVATE SELECTION: 4c93883 (hedge slot, if any:
3335
+ 3c7b883).
3336
+
3337
+ Wave T (post-ship, 13 arms, paired vs 1545.4): ALL DEAD - the champion
3338
+ is a local optimum on every axis touched. Wiener THRESH 2.40 beats
3339
+ 2.38/2.42 (+39/+45 - the labeled barrier is also the ordering-optimal
3340
+ barrier); K_SHRINK 6 vs 3/12 flat/+9; gap-weight .15 shelf +30/+29;
3341
+ gapHGB seed-bag +34 at 2.0sig (seed-0 is favorable; do NOT "stabilize"
3342
+ it away) and lr .03 +12; rank-shape transforms pow2/sqrt/logit
3343
+ +4/+42/+58 (linear pct-rank blending confirmed); GAP4 inside the logbag
3344
+ order-primary +123 at 2.3sig (gap features only work as a separate
3345
+ voice); RankNet 4th source at .10 +22. Driver /tmp/c9/run.py (volatile).
3346
+
3347
+ ## Phase 64 - T2 five-lane subagent campaign on the 1545.4 champion: one adoption (lam2sp3 planner objective), four axes closed with structure
3348
+
3349
+ Five parallel lanes, each paired vs the champion on bgkf (reports:
3350
+ agent_reports_bgkf/t2_{timing,planner,order,counts,hazard}.md):
3351
+
3352
+ - TIMING: closed. Early cost decomposed - 74% imputed-EOL false positives
3353
+ (never die in-window), 19% real deaths beyond the window, 7% genuine
3354
+ early timing; planner packing is 0.6%. Every date shift trades early
3355
+ for late at slope >=0.86; best arms 1.0sig AND count-coupled. EARLY is
3356
+ a selection problem, not a dates problem.
3357
+ - PLANNER: **ADOPTED lam2sp3** - timing curves x2 inside optimize_days'
3358
+ objective (new TIMING_WEIGHT dial) + SPLIT_DAYS 7->3. -4.11 +/- 1.41
3359
+ (2.9sig), 25W/4L, Wilcoxon 8.8e-6, count-flat with battery sets
3360
+ cell-identical; dose-response plateau on both dials; additivity checks;
3361
+ survives ~35-arm multiplicity (sign p 1e-4). Mechanism: refuses cheap
3362
+ trip-merges that drag swaps off timing-optimal days (late -3.5, early
3363
+ -1.2, mobility +0.8). Also: plan-phase scheduling is SATURATED past its
3364
+ own surrogate optimum (exact enumeration is +5.1 WORSE - shallow search
3365
+ is an accidental regularizer; closes the CP-SAT question for good);
3366
+ of 232/scen "ops" cost only 78 is schedulable, 154 rides on missed
3367
+ swaps (recall in disguise).
3368
+ - ORDER: closed. Boundary cascade fails structurally (cutoffs are n~2-3,
3369
+ the band IS the confident top; +147 at 2.6sig); per-building rank
3370
+ normalization catastrophic (+549/+939, 7-8sig) - global pooled ranking
3371
+ is load-bearing; prob-space blending loses to rank-space (+76). The
3372
+ rank-gap-1-10 frontier is unreachable by aggregation on this table.
3373
+ - COUNTS (all report-only): flat alpha 1.1-1.5 dead (podium-posture 1.4
3374
+ is a 1.0sig coin-flip, median-worse); calibrated counts REFUTED with a
3375
+ count-matched control (+67.5 at 3.4sig - allocation failure); risk-N
3376
+ refuted. Headline: warmup-gated alpha 1.4 (s_0-7 only) -> 1488.0,
3377
+ -57.4 +/- 22.0 (2.6sig nominal, post-hoc block, 8-scenario support,
3378
+ count-coupled) - candidate for a public trigger, user's call.
3379
+ - HAZARD: closed for the deadline. dth3 crash fixed; discrete-time
3380
+ hazard HGB is a standalone statistical peer of the 3-way blend
3381
+ (h_alone 1537.0, 25W/22L) with its edge at COLD-START origins
3382
+ (censored-pool training; warmup -178/cell) - converges with the counts
3383
+ lane on warmup as the only exploitable block; unresolvable at 2sig on
3384
+ 8 cells of +/-800 scatter. AFT-lite dead on arrival.
3385
+
3386
+ SHIP (lam2sp3): submit.py TIMING_WEIGHT (default 2.0, env
3387
+ BATTERYSWAP_TIMING_WEIGHT) + SPLIT_DAYS default 7->3; models_cv.py
3388
+ plan_tsroute.timing_weight attr (default 1.0 = old path bit-exact,
3389
+ verified: ft2a10_sp7 control cell-diff 0.0 vs pre-T2 reference);
3390
+ cv.py run_bgkf split_days/timing_weight hooks, ft2a10/head track the
3391
+ deployed dials. Verified: cand ft2a10 = 1541.3, cell-exact (0.0) vs the
3392
+ lane's lam2sp3 measurement; paired -4.11 +/- 1.41 (2.9sig) 25W/4L
3393
+ p8.8e-6, swaps flat 2.27. New champion CV 1541.3.
agent_reports_bgkf/t2_counts.md ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # T2 COUNTS — count/appetite response surface at the new ordering (campaign 5-agent, 2026-08-23)
2
+
3
+ Champion (4c93883, untouched): submit.Ft2RUL = values/counts logbag(vm7),
4
+ ORDER .50 lb + .30 wienerFHT + .20 gapHGB (value-preserving), planner alpha
5
+ 1.0. Ref /tmp/cv_bgkfcand_ft2a10.csv, SCORE 1545.4. All work in /tmp/c13/
6
+ (run.py, diag.py, table.py, per-arm CSVs); repo untouched, monkeypatch only.
7
+ Every arm below runs the LITERAL deployed class (mc.MODELS['@deployed'] =
8
+ submit.Ft2RUL, exactly cv.main()'s lazy registration), so the alpha arms
9
+ score what a public trigger would run at that alpha.
10
+
11
+ **ALL RESULTS REPORT-ONLY (count-coupled — public evidence 4x that no local
12
+ split prices the public tail; the user + a public trigger decide).**
13
+
14
+ Parity gate: a100 (alpha 1.0 rerun) reproduces the ref BIT-EXACTLY (max
15
+ per-origin |delta| = 0.0). Predictions are deterministic, so alpha arms share
16
+ identical predictions — every delta below is a pure count effect.
17
+
18
+ ## (a) Alpha sweep — THE DECISION TABLE
19
+
20
+ 48 paired all-building scenario totals vs champion; late/early in DAYS/scen
21
+ (cost/10 and cost/0.5). "pub est" = swaps ratio x champion's public
22
+ 13.4/scen (podium sits at 15-17.6 with 60-70 late-days/scen).
23
+
24
+ | alpha | swaps/scen | pub est | SCORE | delta±SE | W/L | late-d/scen | early-d/scen | wilcoxon |
25
+ |------:|-----------:|--------:|-------:|:--------------|:--------|------------:|-------------:|---------:|
26
+ | 0.90 | 10.23 | 12.1 | 1613.1 | +67.6±27.7 (2.4sig) | 15W/14L | 105.4 | 637 | .075 |
27
+ | 1.00 | 11.33 | 13.4 | 1545.4 | champion | — | 94.9 | 728 | — |
28
+ | 1.10 | 12.15 | 14.4 | 1540.5 | -4.9±17.1 (0.3sig) | 8W/17L | 90.8 | 807 | .771 |
29
+ | 1.15 | 12.60 | 14.9 | 1563.7 | +18.2±22.8 (0.8sig) | 7W/27L | 89.9 | 857 | .121 |
30
+ | 1.20 | 12.98 | 15.4 | 1567.1 | +21.7±28.7 (0.8sig) | 10W/28L | 88.0 | 900 | .148 |
31
+ | 1.30 | 13.77 | 16.3 | 1542.7 | -2.7±33.7 (0.1sig) | 15W/27L | 82.3 | 968 | .748 |
32
+ | 1.40 | 14.85 | 17.6 | 1501.9 | -43.6±43.0 (1.0sig) | 18W/25L | 73.7 | 1060 | .530 |
33
+ | 1.50 | 15.75 | 18.6 | 1546.7 | +1.3±47.7 (0.0sig) | 18W/26L | 72.2 | 1172 | .995 |
34
+
35
+ Reading:
36
+
37
+ * The axis is ONE-SIDED. Down (0.9) is clearly bad: +67.6 (2.4sig), +10.5
38
+ late-days/scen — consistent with the public 0.8->1.0 conversion
39
+ (1661->1575). Up (1.1-1.5) is flat within noise: every mean is inside
40
+ ~1sig, and W/L is NEGATIVE for every up-arm (the MEDIAN scenario worsens
41
+ ~+17; a few tail scenarios win big). SE grows with alpha (17 -> 48).
42
+ * Mean minimum sits at 1.4 (-43.6) but bounces back at 1.5 (+1.3) — the
43
+ minimum is a tail artifact, not a stable optimum. Wilcoxon never comes
44
+ close for any up-arm.
45
+ * Marginal exchange rate along the grid (late-days saved / early-days bought
46
+ per added swap): 1.0->1.1: 5.1/97; 1.1->1.15: 1.9/108; 1.15->1.2: 5.1/116;
47
+ 1.2->1.3: 7.3/85; 1.3->1.4: 7.9/86 (marginal cost -37.7/swap). Returns do
48
+ NOT diminish out to 1.4 — deep order positions still contain catchable
49
+ deaths. The ordering is good deeper than the count reaches; the count level
50
+ is the binding constraint (in one specific era — see (d)).
51
+
52
+ ## (b) Calibrated counts (logcal values under the champion order) — REFUTED
53
+
54
+ LogcalFt2 = champion Ft2RUL order, values/counts = CalibratedClassifierCV
55
+ (sigmoid, cv=5) logistic on the same FEATURES+vmin7_rank. logcal's expected
56
+ count runs 1.135x logbag's (mean per-fleet sum(p42) 2.302 vs 2.028 — the
57
+ "miscalibrated" logbag UNDER-counts by its own lights, consistent with the
58
+ alpha-up flatness).
59
+
60
+ | arm | alpha | eff. appetite | swaps/scen | SCORE | delta±SE | W/L | wilcoxon |
61
+ |-----|------:|--------------:|-----------:|------:|:---------|:----|---------:|
62
+ | cal10 | 1.00 | ~1.14 | 12.94 | 1585.0 | +39.5±24.4 (1.6sig) | 10W/34L | .011 |
63
+ | cal110 | 1.10 | ~1.25 | 13.77 | 1611.5 | +66.0±24.0 (2.7sig) | 10W/38L | .002 |
64
+ | cal088 | 0.881 | ~1.00 (count-matched control) | 11.77 | 1612.9 | +67.5±20.0 (3.4sig) | 8W/35L | .000 |
65
+
66
+ cal088 is the decisive control: at CHAMPION-MATCHED total appetite
67
+ (alpha = 1/1.135), pure per-scenario reallocation by the calibrated count is
68
+ +67.5 (3.4sig worse, 8W/35L). Anatomy: only 43/240 cells change count
69
+ (+28/-15) and it hurts both ways — dropped swaps un-catch deaths (s28/f0:
70
+ -1 swap -> +430 late) and added swaps land in the nearend block (+2.3
71
+ swaps/scen there, already swap-rich) instead of warmup. Compare cal10
72
+ (+39.5 at 12.94 swaps) vs pure alpha at the same appetite (a115/a120 ~+20):
73
+ the calibrated count is worse than flat-scaling at every appetite level.
74
+ ANSWER: no — a calibrated expected count does NOT beat alpha-scaling the
75
+ miscalibrated one; logbag's per-scenario count profile is better-aligned
76
+ with catchability than the calibrated profile. Axis closed on local
77
+ evidence.
78
+
79
+ ## (c) Risk-shaped N (N = sum(p42) + beta*sqrt(sum(p42(1-p42)))) — REFUTED
80
+
81
+ Buffer is large relative to the sum (mean 1.122 on mean sum 2.028), so beta
82
+ acts like a big, fleet-size-dependent alpha bump.
83
+
84
+ | arm | beta | swaps/scen | SCORE | delta±SE | W/L | wilcoxon |
85
+ |-----|-----:|-----------:|------:|:---------|:----|---------:|
86
+ | rb05 | 0.5 | 13.60 | 1585.0 | +39.6±31.1 (1.3sig) | 11W/31L | .043 |
87
+ | rb10 | 1.0 | 16.21 | 1554.8 | +9.3±51.1 (0.2sig) | 19W/28L | .741 |
88
+
89
+ rb05 is significantly worse than champion AND worse than plain a130 at the
90
+ same swap level (13.60 vs 13.77 swaps: +39.6 vs -2.7) — the sqrt buffer
91
+ allocates the extra appetite ANTI-proportionally to where it pays (small
92
+ fleets get the biggest relative bump; the warmup gains of (d) are not
93
+ fleet-size-shaped). Principled-looking, measurably worse than flat alpha.
94
+ Axis closed on local evidence.
95
+
96
+ ## (d) Diagnostics — best arm a140 (best mean), plus the structure behind it
97
+
98
+ Per-cell (240 fold x origin) paired diagnostics, a140 vs champion:
99
+
100
+ * corr(count delta, cost delta) = +0.01 over all cells, +0.14 on the 151
101
+ changed cells (past reallocation-masquerade red flag: 0.76). Same for all
102
+ alpha arms (|corr| <= 0.13). No masquerade signature — these are real
103
+ count effects, cleanly separated by the value-preserving order.
104
+ * +169 swaps total -> 1018 late-days saved (6.0/swap = 60 cost) vs 15953
105
+ early-days bought (94.4/swap = 47 cost) + fees/travel. Conversion: 48/151
106
+ changed cells cut late cost (sum -10236); 103 were dead swaps (sum +8145).
107
+ At a110 the same picture: 12/39 convert, 5.1 late-days/swap, 97
108
+ early-days/swap — every alpha step trades at roughly cost-neutral, which
109
+ is WHY the surface is flat.
110
+ * Failure anatomy at high alpha: the marginal swap can cascade through
111
+ mobility constraints, not just early cost — s23/f3 at a130: one added swap
112
+ -> daily_limit +100, weekly_limit +100, overtime +49, travel +21 (cell
113
+ +369 with zero late change).
114
+ * THE STRUCTURE: the entire mean gain lives in the WARMUP block (s_0-7),
115
+ exactly where plan_tsroute's comment documents sum(p42) undercounting
116
+ (~4x) and where the champion holds 172 late-days/scen with only 9
117
+ swaps/scen (panel: 89 late-days at 11 swaps; nearend: 24 at 16.3).
118
+
119
+ | block (dcost/scen) | a110 | a130 | a140 |
120
+ |--------------------|-----:|-----:|-----:|
121
+ | warmup s_0-7 | -101.0 | -270.5 | -344.3 |
122
+ | panel s_8-41 | +16.7 | +58.0 | +17.8 |
123
+ | nearend s42-47 | +0.4 | +10.6 | +9.7 |
124
+
125
+ Warmup consistency at a130: 6/8 origins win, 4/5 folds negative; at a140
126
+ 5/5 folds negative (fold1-heavy: -1852 of -2755). Panel harm equally
127
+ consistent (4/5 folds positive).
128
+
129
+ ### Post-hoc synthesis: warmup-gated alpha (NOT a pre-registered arm)
130
+
131
+ Because predictions are deterministic, mixing per-origin rows is
132
+ measurement-EXACT (identical to running an origin-conditional alpha; the
133
+ scenario time is plan-time-known, so the rule is deployable, no forward
134
+ read). Gate = alpha_up on s_0-7 only, champion 1.0 elsewhere:
135
+
136
+ | warmup alpha | SCORE | delta±SE | W/L (48) | wilcoxon | swaps/scen |
137
+ |-------------:|------:|:---------|:---------|---------:|-----------:|
138
+ | 1.1 | 1528.6 | -16.8±11.1 (1.5sig) | 3W/1L | — | 11.50 |
139
+ | 1.2 | 1512.4 | -33.0±19.5 (1.7sig) | 5W/2L | .109 | 11.69 |
140
+ | 1.3 | 1500.3 | -45.1±21.7 (2.1sig) | 6W/1L | .047 | 11.85 |
141
+ | 1.4 | 1488.0 | -57.4±22.0 (2.6sig) | 7W/1L | .016 | 12.00 |
142
+ | 1.5 | 1493.8 | -51.6±23.3 (2.2sig) | 7W/1L | .039 | 12.15 |
143
+
144
+ Monotone dose-response to 1.4, then pullback. CAVEATS, all of them: (1) the
145
+ block was selected AFTER seeing where alpha paid — the sigmas are inflated
146
+ by selection (though the mechanism — warmup count undercoverage — was
147
+ documented in plan_tsroute's comments long before this run); (2) only 8
148
+ scenarios carry the whole effect, fold1-heavy; (3) count-coupled and a NEW
149
+ mechanism (origin-conditional appetite), so under the tiered bar it needs
150
+ 2sig + controls AND stays report-only regardless. Controls it does pass:
151
+ fold-consistency (5/5 at 1.4), specificity (surgical — 40/48 scenarios are
152
+ bit-identical to champion, which also caps public downside to the warmup
153
+ scenarios' contribution), no-masquerade (cellcorr ~0).
154
+
155
+ ## Recommendation (confidence in brackets)
156
+
157
+ 1. DO NOT spend a public trigger on flat alpha 1.1-1.3: means are inside
158
+ 1sig, medians worsen, wilcoxon never bites [high confidence the local
159
+ surface is flat there]. Same verdict, stronger, for calibrated counts and
160
+ risk-shaped N — both refuted with controls, close those axes [high].
161
+ 2. Flat alpha 1.4 is the only whole-surface point with a notable mean
162
+ (-43.6) and it maps to exactly the podium's public swap posture (~17.6/
163
+ scen), but it is 1.0sig, 18W/25L, tail-driven, and 1.5 bounces back
164
+ [low confidence it transfers; a public trigger on it is a coin-flip with
165
+ bounded upside ~-40].
166
+ 3. The one result worth the user's attention: WARMUP-GATED alpha 1.3-1.4
167
+ (s_0-7 only). Locally -45 to -57 (2.1-2.6sig even before discounting
168
+ selection), monotone dose-response, mechanism-backed (documented warmup
169
+ undercount), surgical (+0.5-0.7 swaps/scen, 40/48 scenarios untouched).
170
+ If the user wants to spend a public trigger on the count axis, this is
171
+ the highest-EV candidate — but it is post-hoc, 8-scenario-supported, and
172
+ count-coupled, so it is strictly the user's call [moderate confidence the
173
+ sign transfers publicly; low-moderate in the magnitude].
174
+ 4. If any alpha change ships, the alpha-0.9 result (+67.6, 2.4sig) is the
175
+ guardrail: never below 1.0.
176
+
177
+ Artifacts: /tmp/c13/run.py (driver; arms run: a090-a150, cal10/cal088/
178
+ cal110, rb05/rb10), /tmp/c13/diag.py (per-cell diagnostics),
179
+ /tmp/c13/table.py (decision table), /tmp/c13/cv_bgkfcand_c13_*.csv (240-cell
180
+ outputs per arm), lane logs /tmp/c13/lane*.log.
agent_reports_bgkf/t2_hazard.md ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # T2-HAZARD: censored survival models as order sources (2026-08-23)
2
+
3
+ Mission: the one model family never measured — a PROPER censored survival
4
+ model in the champion's order blend. The previous attempt (dth3) crashed
5
+ (KeyError 'duration') before producing a number: it fed a hazard model the
6
+ plain closed-pair table, which has no duration/event columns. Fixed here by
7
+ rebuilding the censored pool inside fit exactly the way `run_bgkf._fit`
8
+ does for its own hazard kinds (`mc.censored_pairs(t, t.origin.max())`
9
+ filtered to the fold's train devices — deployment-legal: a foreign fleet's
10
+ labels were all known when the submission was built). Pool per fold ~57k
11
+ pairs, ~6.3k deaths.
12
+
13
+ Driver: /tmp/c14/run.py. Paired vs /tmp/cv_bgkfcand_ft2a10.csv
14
+ (champion 4c93883, SCORE 1545.4, swaps 2.27). Values are always
15
+ logbag(vm7)@alpha1.0; arms change ORDER only (value-preserving blend hook,
16
+ composite registered as blend partner at weight 1.0; weights round(x,12)).
17
+ Replication guard h_champ (= .50 lb + .30 wiener + .20 gapHGB rebuilt
18
+ inside the composite): SCORE 1545.4, -0.0 vs ref, swaps 2.27 — exact.
19
+
20
+ ## Models built (sklearn only)
21
+
22
+ - **DiscHazHGB** (discrete-time hazard): person-period expansion of the
23
+ censored pool into (pair, bucket) rows, buckets
24
+ (0-7,7-14,14-21,21-28,28-42,42-63,63-84] days. Target = died in bucket
25
+ given alive at its start; censored pairs contribute only fully observed
26
+ buckets as negatives. ONE HistGB classifier (depth 3, lr .06, 250 iters,
27
+ l2 1.0, early_stopping off), bucket midpoint as an extra feature
28
+ (~350k person-period rows/fold). Order source:
29
+ P(die<=42d) = 1 - prod_{k<5}(1-h_k).
30
+ - **AFTLite** (GBM-AFT): HistGB regressor on log(days-to-death), observed
31
+ deaths only, IPCW sample weights 1/G(t-) from a Kaplan-Meier of the
32
+ censoring distribution (G clipped at 0.05). Order source: -pred log-days.
33
+ - **WienerHybrid**: confidence-gated mixture for the .30 slot — wiener rank
34
+ where wnr_n >= 3 (96.5% of rows), DiscHazHGB rank where wnr_n < 3 (3.5%).
35
+
36
+ ## Results (48 paired all-building scenario totals vs 1545.4)
37
+
38
+ | arm | order | SCORE | delta±SE | sig | W/L | wilcoxon | swaps |
39
+ |---|---|---|---|---|---|---|---|
40
+ | h_champ | .50lb/.30wn/.20gap (guard) | 1545.4 | -0.0±0.0 | - | 1W/0L | - | 2.27 |
41
+ | h_dh450 | .25/.15/.10 + .50 dh | 1527.9 | -17.6±35.3 | 0.5 | 23W/21L | 0.408 | 2.26 |
42
+ | h_alone | 1.0 dh (diagnostic) | 1537.0 | -8.4±50.9 | 0.2 | 25W/22L | 0.749 | 2.26 |
43
+ | h_dh425 | .40/.24/.16 + .20 dh | 1537.5 | -7.9±16.8 | 0.5 | 18W/12L | 0.339 | 2.27 |
44
+ | h_hyb30 | hybrid in .30 slot | 1550.7 | +5.3±5.9 | 0.9 | 4W/1L | - | 2.27 |
45
+ | h_dh4 | .45/.27/.18 + .10 dh | 1553.3 | +7.9±15.8 | 0.5 | 12W/8L | 0.841 | 2.27 |
46
+ | h_aft4 | .45/.27/.18 + .10 aft | 1569.8 | +24.4±21.3 | 1.1 | 12W/15L | 0.239 | 2.28 |
47
+ | h_dh20 | dh replaces gapHGB @.20 | 1571.2 | +25.7±20.4 | 1.3 | 11W/16L | 0.413 | 2.28 |
48
+ | h_dhg20 | dh+GAP4 replaces gap @.20 | 1585.5 | +40.1±22.6 | 1.8 | 9W/15L | 0.079 | 2.29 |
49
+ | h_dh30 | dh replaces wiener @.30 (control) | 1610.9 | +65.5±30.2 | 2.2 | 21W/21L | 0.137 | 2.25 |
50
+ | h_aft20 | aft replaces gapHGB @.20 | 1614.3 | +68.9±34.5 | 2.0 | 9W/28L | 0.010 | 2.27 |
51
+
52
+ Block structure (delta per scenario): the hazard's entire nominal win
53
+ lives in the 8 WARMUP scenarios (s_0-7, cold-start origins) — h_alone
54
+ -178/cell, h_dh450 -82, h_dh425 -54 — while the 34-cell panel is flat to
55
+ slightly worse (h_alone +31, h_dh425 +0.5). Per-cell scatter is violent
56
+ (h_alone swings -879..+815; the one-rank-tie ~539 phenomenon), which is
57
+ why 48 cells cannot resolve a family that only separates on 8 of them.
58
+
59
+ ## Findings
60
+
61
+ 1. **The discrete-time hazard is a genuine standalone PEER of the tuned
62
+ 3-way champion order** (h_alone 1537.0, -8.4±50.9, 25W/22L) — the first
63
+ single model to match the blend. Its edge is cold-start: the censored
64
+ pool trains on open-window pairs the closed-label models discard.
65
+ 2. **But it does not convert into a blend win.** Hedge curve over hazard
66
+ weight: .10 -> +7.9, .20 -> -7.9, .50 -> -17.6, 1.0 -> -8.4; everything
67
+ 0.2-0.5 sigma, wilcoxon never below 0.3. Its ranks overlap too much
68
+ with lb+wiener+gap on the panel, and its private information (warmup)
69
+ is only 8 of 48 cells.
70
+ 3. Slot substitutions all fail: it cannot replace gapHGB (+25.7) and
71
+ certainly not wiener (+65.5, the expected control) — both incumbent
72
+ sources earn their slots.
73
+ 4. AFT-lite (IPCW log-days regression) is strictly worse everywhere
74
+ (+24.4 as 4th, +68.9 in the .20 slot with wilcoxon p=0.010 AGAINST)
75
+ — dead on arrival.
76
+ 5. WienerHybrid gate (wnr_n<3) touches 3.5% of rows -> a wash (+5.3±5.9).
77
+ 6. All arms count-flat as designed (swaps 2.25-2.29 vs 2.27; count rule
78
+ untouched, residual variation is window-boundary scheduling).
79
+
80
+ ## Verdict
81
+
82
+ Best candidate: **h_dh450** (order .25 lb / .15 wiener / .10 gap / .50
83
+ discrete-hazard), SCORE 1527.9, -17.6±35.3 (0.5 sigma), 23W/21L, wilcoxon
84
+ 0.408, swaps 2.26. Tier: NEW mechanism -> needs >=2 sigma paired.
85
+ **FAILS the bar by a wide margin — do not ship.** No arm in the family
86
+ reaches even 1 sigma in the winning direction.
87
+
88
+ Depth assessment: the family is MEASURED now, not dead-by-crash — it is a
89
+ peer, not an improvement. The only residual thread with any evidence is
90
+ the warmup/cold-start block, where the hazard is consistently and
91
+ strongly better; but that is 8 cells, the public fleet's origin mix is
92
+ unknowable, and warmup-targeted mechanisms are exactly the count/era
93
+ territory the public board has burned us on. Recommend closing the
94
+ survival-model axis for this competition (deadline today); if the code
95
+ outlives the deadline, the one idea worth carrying forward is
96
+ censored-pool training as a COLD-START specialist gate, not as a blended
97
+ order source.
agent_reports_bgkf/t2_order.md ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # T2 ORDERING agent — radical ordering arms vs the 1545.4 champion (c12)
2
+
3
+ Campaign: 5-agent improvement wave, 2026-08-23 (deadline day).
4
+ Champion (head 4c93883, untouched): values/counts = logbag(vm7)@alpha1.0;
5
+ ORDER = .50 rank(logbag) + .30 rank(WienerFHT) + .20 rank(gapHGB d2 lr.06
6
+ it300 l2=1 s0 on FEATURES+vmin7_rank+GAP4). CV bgkf 1545.4.
7
+
8
+ Driver: `/tmp/c12/run.py` (exact copy of the /tmp/c9 pattern: load_table
9
+ monkeypatch for GAP4, mc.MODELS registration, blend=(name,1.0) with
10
+ p_star=1.0, paired vs `/tmp/cv_bgkfcand_ft2a10.csv`). No tracked file was
11
+ edited; nothing committed. Per-arm CSVs: `/tmp/cv_bgkfcand_c12_t_*.csv`.
12
+
13
+ **Driver validation**: `t_champ` (in-driver replica of the 3-way order)
14
+ reproduced the reference **bit-exactly** — all 48 scenario deltas < 0.01,
15
+ SCORE 1545.4, swaps 2.27. Paired deltas below are therefore pure mechanism
16
+ effects, not harness drift.
17
+
18
+ ## Results (paired over 48 all-building scenario totals)
19
+
20
+ | arm | mechanism | SCORE | delta±SE | sig | W/L | wilcoxon | swaps |
21
+ |---|---|---|---|---|---|---|---|
22
+ | t_champ | replica (validation) | 1545.4 | +0.0±0.0 | - | 0W/0L | - | 2.27 |
23
+ | t_gbm4_10 | 4th source gbm @.10 (.45/.27/.18/.10) | 1547.9 | +2.5±15.3 | 0.2σ | 13W/9L | p0.824 | 2.27 |
24
+ | t_cs50 | imminence-weighted gapHGB, w=1+50/d | 1552.0 | +6.5±20.1 | 0.3σ | 11W/8L | p0.936 | 2.28 |
25
+ | t_log4_05 | 4th source logistic @.05 | 1559.0 | +13.6±9.6 | 1.4σ | 8W/3L | p0.831 | 2.27 |
26
+ | t_plat16 | plateau demotion beta=.16 (dwell>=40d specialist) | 1564.4 | +18.9±31.0 | 0.6σ | 12W/19L | p0.444 | 2.29 |
27
+ | t_gbm4_05 | 4th source gbm @.05 (.475/.285/.19/.05) | 1573.3 | +27.9±14.2 | 2.0σ loss | 6W/6L | p0.204 | 2.27 |
28
+ | t_cs20 | imminence-weighted gapHGB, w=1+20/d | 1578.1 | +32.7±22.3 | 1.5σ | 10W/11L | p0.211 | 2.27 |
29
+ | t_plat08 | plateau demotion beta=.08 | 1578.6 | +33.2±25.6 | 1.3σ | 11W/18L | p0.137 | 2.28 |
30
+ | t_iso | isotonic-calibrated probability blend .5/.3/.2 | 1621.1 | +75.6±37.4 | 2.0σ loss | 15W/27L | p0.037 | 2.28 |
31
+ | t_casc10 | boundary cascade k=10 (specialist re-rank of cutoff band) | 1692.9 | +147.4±56.5 | 2.6σ loss | 17W/31L | p0.015 | 2.29 |
32
+ | t_casc10p | cascade k=10, protect all but last 2 included | 1700.2 | +154.8±59.7 | 2.6σ loss | 16W/32L | p0.010 | 2.29 |
33
+ | t_casc20 | boundary cascade k=20 | 1701.5 | +156.0±61.5 | 2.5σ loss | 19W/28L | p0.050 | 2.28 |
34
+ | t_bldgpct | per-building pct-rank of each source | 2094.4 | +549.0±73.7 | 7.4σ loss | 5W/40L | p0.000 | 2.23 |
35
+ | t_bldgz | per-building z-score of each source | 2484.7 | +939.3±115.1 | 8.2σ loss | 8W/40L | p0.000 | 2.25 |
36
+
37
+ Swaps ~2.27 everywhere (order-only, count-flat by construction; the ±0.02
38
+ wiggle is ec-top-up interaction with which devices carry the top values).
39
+
40
+ ## Autopsy
41
+
42
+ - **Boundary cascade (a) — the most promising idea on paper — fails hard,
43
+ and the failure is structural, not a tuning miss.** The loss is pure late
44
+ cost (+134/origin late, +9 early; worst cells s21 +1127, s8 +899, s33
45
+ +797). Test fleets in bgkf have cutoff n ≈ 2-3, so the band
46
+ [max(0,n-k), n+k) IS the whole confident top of the order: the specialist
47
+ gets authority over near-certain deaths, not just the ambiguous fringe,
48
+ and one demoted sure-death costs ~500+. Protecting all but the last 2
49
+ included (t_casc10p) did not help (+154.8) — the damage comes from the
50
+ below-cutoff side too: specialist promotions displace true deaths sitting
51
+ at positions n..n+2 that the champion had right. The train-side band
52
+ replica (per-origin, in-sample champion scores, cutoff ~8-15 on ~340-
53
+ device train fleets) evidently does not transfer to 90-device test fleets
54
+ with cutoff 2-3.
55
+ - **Per-building normalization (c) is catastrophic (+549/+939).** In bgkf
56
+ the test buildings are planned as one fleet, and cross-building rank
57
+ allocation is exactly what the global blend gets right: with ~18 devices
58
+ per building, forcing each building's top device to rank 1.0 hands
59
+ inclusion slots to healthy buildings' least-healthy devices. The global
60
+ pooled rank is load-bearing; do not revisit within-building rescaling of
61
+ order sources.
62
+ - **Probability-space blending (d) loses to rank-space (+75.6, 2.0σ, late-
63
+ driven).** Isotonic calibration on a ~25%-building holdout collapses the
64
+ order signal into a few steps (ties broken back toward champion order at
65
+ 1e-9), and the .5/.3/.2 mix in probability units over-weights whichever
66
+ source is most confident rather than most discriminative. Rank blending
67
+ is the better aggregation for this planner; consistent with the earlier
68
+ death of rank transforms (pow2/sqrt/logit, c9).
69
+ - **Cost-sensitive gapHGB (b) is a wash at best** (c=50 +6.5±20.1; c=20
70
+ +32.7±22.3). Non-monotone in c and high per-scenario churn (s17 +545 /
71
+ s36 -512 at c=50): imminence weighting reshuffles the gap-HGB's ranking
72
+ noise without moving mean cost. No dial between 20 and 50 is worth the
73
+ cell.
74
+ - **4th sources (e): closest to zero but never negative.** gbm@.10 +2.5±15.3
75
+ (13W/9L, a pure wash), gbm@.05 +27.9��14.2 (a 2.0σ LOSS on only 12 changed
76
+ scenarios — small-weight rank flips are asymmetric-bad), logistic@.05
77
+ +13.6±9.6. The .50/.30/.20 3-way already spans the useful model diversity;
78
+ a 4th correlated source only adds rank jitter at the razor-thin cutoff.
79
+ - **Plateau demotion (f, own idea) doesn't pay** (+33.2 at beta=.08, +18.9
80
+ at beta=.16, both more L than W). Demoting low-specialist plateau
81
+ dwellers (days_below_245>=40, 11.75% in-window death rate) does swap some
82
+ false includes out, but the devices promoted in their place die no more
83
+ often — the champion's plateau false-includes are apparently already the
84
+ least-bad choices in those fleets. Interesting detail: bigger beta hurt
85
+ LESS (s16 -654, s17 -531 wins at beta=.16), but the sign never flips.
86
+
87
+ ## Verdict
88
+
89
+ **No adoptable candidate.** Best arm t_gbm4_10 (+2.5±15.3, 0.2σ) is a wash,
90
+ not a win; every structurally-new mechanism (cascade, per-building
91
+ normalization, isotonic prob-blend, cost-sensitive specialist, plateau
92
+ specialist) is a measured LOSS, three of them at >=2σ in the wrong
93
+ direction. Nothing meets any tier (new mechanisms need >=2σ paired WINS;
94
+ count-flat tweaks need 1.5σ — none is even below zero on the mean).
95
+
96
+ Takeaway for the wall: the champion's .50/.30/.20 global-rank blend is a
97
+ genuine local optimum across six structurally different ordering axes, not
98
+ just the weight simplex. The missed-death frontier (rank gap 1-10 below a
99
+ cutoff of 2-3 per fold-fleet) is not recoverable by re-ranking machinery
100
+ trained on the same feature table — every attempt to move devices across
101
+ the cutoff moves at least as many true deaths out as in. If the frontier is
102
+ to move, it needs new information (features/labels), not new order
103
+ aggregation.
104
+
105
+ DEAD (add to the do-not-retest list): boundary-cascade specialists (any k,
106
+ any protection), within-building rank/z normalization of order sources,
107
+ isotonic/probability-space blending of the 3 sources, imminence-weighted
108
+ gapHGB (c 20-50), gbm/logistic 4th sources at .05-.10, plateau-specialist
109
+ demotion (beta .08-.16, dwell 40d).
agent_reports_bgkf/t2_planner.md ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # T2 planner lane — schedule the SAME swap set better (2026-08-23)
2
+
3
+ Reference: champion head 4c93883 (`ft2a10` = submit.Ft2RUL, alpha 1.0),
4
+ SCORE 1545.4 on bgkf (/tmp/cv_bgkfcand_ft2a10.csv). Harness: /tmp/c11/
5
+ (cache.py captures the champion's per-cell predictions through a real
6
+ `cv.run_bgkf(kind='@deployed')` run — parity vs the reference CSV exact,
7
+ max per-cell diff 1.1e-13 — then every arm re-plans the IDENTICAL
8
+ prediction set, so deltas are pure scheduling). Count-flat is enforced by
9
+ construction AND asserted per cell: the in-window battery SET of every arm
10
+ equals the champion's in every one of the 240 cells (dswaps_max 0
11
+ everywhere). No forward reads: arms only see model curves + the mobility
12
+ simulator; true eol enters only through the evaluator.
13
+
14
+ ## Ops-cost decomposition of the champion on bgkf (per scenario, 48 means)
15
+
16
+ | component | total | PLAN phase | EMERGENCY phase |
17
+ |---|---|---|---|
18
+ | late_swap | 949.4 | 26.7 | 922.7 |
19
+ | early_swap | 364.0 | 364.0 | 0.0 |
20
+ | overtime | 62.5 | 30.9 | 31.6 |
21
+ | daily_limit | 64.6 | 4.2 | 60.4 |
22
+ | weekly_limit | 35.4 | 0.0 | 35.4 |
23
+ | travel | 47.9 | 28.3 | 19.5 |
24
+ | building_change | 11.4 | 7.3 | 4.1 |
25
+ | room_change | 6.4 | 4.6 | 1.8 |
26
+ | battery_swap | 3.9 | 2.8 | 1.1 |
27
+
28
+ (Phase split measured by re-evaluating each champion plan with the missed
29
+ batteries' eol set to NaT, which deletes the evaluator's emergency loop;
30
+ diff = emergency cost. Scripts: /tmp/c11/diag.py, csvs in /tmp/c11/.)
31
+
32
+ **Headline structure: of the 232/scen ops cost, only 78.1/scen is
33
+ plan-phase (schedulable at fixed swap set); 153.9/scen rides on the ~4.3
34
+ missed swaps/scen (emergency queue: one forced base-round-trip per miss,
35
+ plus the daily/weekly-limit and overtime hits those trips trigger). The
36
+ "ops" target is two-thirds prediction cost in disguise.** The optimizer's
37
+ problem is also tiny: 2.27 chosen/cell, group count 0-6 (85 cells with 1
38
+ group, 81 with 2, 44 with 3).
39
+
40
+ ## Arms (all paired on 48 origin-sums vs 1545.4; swaps 2.27 = count-flat everywhere)
41
+
42
+ | arm | SCORE | delta±SE | sig | W/L | wilcoxon | note |
43
+ |---|---|---|---|---|---|---|
44
+ | nn (NN day-route order) | 1545.4 | -0.03±0.15 | 0.2 | 5/5 | 1.000 | dial dead |
45
+ | cons (constructive start) | 1549.7 | +4.29±4.78 | 0.9 | 4/9 | .348 | worse |
46
+ | srch8 (restarts 8, iters 200) | 1549.7 | +4.22±4.52 | 0.9 | 8/8 | .876 | MORE search = worse |
47
+ | exh3 (exact enum ≤3 groups) | 1550.5 | +5.09±4.86 | 1.0 | 11/16 | .413 | EXACT optimum of own objective = worse |
48
+ | exh3nn | 1550.3 | +4.89±4.86 | 1.0 | 14/17 | .499 | " |
49
+ | split1/2/4/5/14 | 1544.0–1547.4 | -1.5..+1.9 | ≤1.2 | — | — | split3 -1.47 is a lone spike at λ=1 |
50
+ | lam05 / lam075 (timing×λ) | 1545.7/1545.4 | +0.25/-0.06 | ≤0.4 | — | — | λ<1 dead |
51
+ | lam15 / lam2 / lam25 / lam3 / lam4 | 1544.2/1542.7/1543.4/1543.5/1543.7 | -1.19/-2.71/-1.98/-1.95/-1.75 | 1.2/2.2/1.7/1.5/1.4 | —/14:3/—/—/— | .123/.006/—/—/— | clean U, min at λ=2 |
52
+ | lam6 / lam10 / lam100 | 1546.0/1549.3/1564.2 | +0.6/+3.9/+18.7 | — | — | — | over-weighting blows up |
53
+ | wkres20/wkres16/dayres16 (planner-side limit reserve) | 1545.1–1546.9 | -0.3..+1.5 | ≤1.1 | — | — | dead (plan-phase weekly is already 0) |
54
+ | shift+1/+2/+3 (global later) | 1551.8/1561.9/1574.5 | +6.4/+16.5/+29.0 | 3-4σ | — | — | control: placement already calibrated |
55
+ | shift-1 (global earlier) | 1542.9 | -2.55±1.20 | 2.1 | 27/21 | .090 | mean-carried, rank-test fails — report-only |
56
+ | **lam2sp3 (λ=2, split_days=3)** | **1541.3** | **-4.11±1.41** | **2.9** | **25/4** | **8.8e-6** | **BEST** |
57
+ | lam2sp2 / lam2sp4 / lam2sp5 | 1543.0/1541.8/1542.0 | -2.45/-3.63/-3.43 | 2.4/2.6/2.4 | 23:7/22:7/21:6 | .003/.0004/.001 | plateau, not a spike |
58
+ | lam25sp3 / lam15sp3 / lam3sp3 | 1542.4/1542.9/1542.3 | -2.98/-2.51/-3.09 | 2.2/2.1/2.1 | — | .025/.006/.070 | plateau |
59
+
60
+ ## The two findings
61
+
62
+ **1. The plan-phase schedule is SATURATED — and past the optimum of its own
63
+ objective.** The champion's local search (restarts 2, iters 60) sits at or
64
+ near the exact optimum of its surrogate objective (model timing curves +
65
+ exact mobility sim): exhaustive enumeration for ≤3-group cells (94% of
66
+ non-empty cells) finds only surrogate slack whose conversion makes TRUE
67
+ cost +5.1/scen WORSE (srch8 +4.2, cons +4.3 the same — they pick up +2.1
68
+ daily_limit AND +2.1 weekly_limit of real penalties the surrogate can't
69
+ see, cross-phase stacking with the emergency queue). The shallow search is
70
+ an accidental regularizer against surrogate error. **This closes the
71
+ CP-SAT open question: a date-only repack at FIXED swap set can only
72
+ optimize the same surrogate (true eol is not plan-time information), and
73
+ exact search of that surrogate already loses. The prior CP-SAT hybrid's
74
+ -96 was count-carried, as recall said.** ortools 9.15 is importable but a
75
+ CP-SAT arm is pointless — exhaustive enum is a stronger solver than CP-SAT
76
+ on the identical objective and it is negative.
77
+
78
+ **2. The one real win is the opposite of the mission's intent: protect
79
+ TIMING from mobility-motivated compromises.** `lam2sp3` = weight the
80
+ timing curves ×2 inside optimize_days' objective (λ·timing + mobility) and
81
+ split building groups at 3-day instead of 7-day buckets. Delta -4.11±1.41
82
+ (2.9σ), 25W/4L, Wilcoxon 8.8e-6, sign-test p=1e-4 (survives ~35-arm
83
+ multiplicity). Component mechanism: late -3.54, early -1.21, bought with
84
+ +0.41 travel +0.35 building_change (it declines cheap trip-merges that
85
+ drag a swap off its timing-optimal day). Controls: 5%-trimmed mean still
86
+ -2.37, median nonzero -3.42; panel block alone -2.52 at 19W/3L (warmup
87
+ -6.0, nearend -10.7); negative in 4/5 folds (fold 3 ~0 with only 2 nonzero
88
+ cells); worst scenario +2.5; dose-response clean on both dials (λ row at
89
+ sp3: 1.5/-2.5, 2/-4.1, 2.5/-3.0, 3/-3.1; split row at λ2: 2/-2.45,
90
+ 3/-4.11, 4/-3.63, 5/-3.43, 7/-2.71). Count-flat by construction and
91
+ asserted set-identical per cell; prediction-flat by construction (cached
92
+ champion predictions).
93
+
94
+ ## Tier verdict
95
+
96
+ - **lam2sp3, -4.11±1.41 (2.9σ)**: λ is a NEW knob (the objective weighting
97
+ does not exist in shipped code) → new-mechanism bar, ≥2σ + controls.
98
+ It clears 2σ with strong rank support, additivity (lam2 -2.71 + sp3 ≈
99
+ combo), a plateau in both dials, and fold spread. Caveats for the main
100
+ session: (a) selected max of a plateau whose center is ≈ -3.5, so
101
+ expect that rather than -4.1; (b) effect size is ~0.3% of SCORE — small
102
+ against public noise; (c) shipping needs a submit.py plan-path edit:
103
+ SPLIT_DAYS 7→3 (existing knob) + scaling curves ×2 before the
104
+ optimize_days call (one line in plan_tsroute, e.g. a
105
+ plan_tsroute.timing_weight attr defaulting 1.0). Conservative
106
+ validated-dial-only alternative: none reaches 1.5σ (split3 alone is a
107
+ lone spike; all pure-search dials are flat-to-negative).
108
+ - **lam2 alone, -2.71±1.24 (2.2σ, 14W/3L, p .006)**: single new knob, no
109
+ split change; cleaner story, smaller win.
110
+ - **shift-1, -2.55 (2.1σ)**: rank-test fails (27W/21L, p .09) — report-only.
111
+ - Everything aimed at the literal ops components (search depth, NN
112
+ routing, constructive starts, limit reserves) is flat or negative:
113
+ plan-phase ops (78/scen) is already priced exactly by mobility_cost and
114
+ is mostly irreducible travel/overtime physics of visiting remote dying
115
+ batteries. The remaining 154/scen ops is emergency-driven — a RECALL
116
+ problem, not a scheduling one.
117
+
118
+ Artifacts: /tmp/c11/{cache,lib,diag,arms}.py, arm CSVs /tmp/c11/arm_*.csv,
119
+ stats /tmp/c11/arm_stats.csv, logs /tmp/c11/arms*.log. Repo untouched
120
+ (monkeypatch only; best.pickle untouched).
agent_reports_bgkf/t2_timing.md ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # T2 TIMING — early-cost decomposition + swap-date arms (campaign 5-agent, 2026-08-23)
2
+
3
+ Champion (4c93883, untouched): values/counts logbag(vm7) @ alpha 1.0, ORDER
4
+ .50 lb + .30 wienerFHT + .20 gapHGB, value-preserving. Ref CSV
5
+ /tmp/cv_bgkfcand_ft2a10.csv, SCORE 1545.4. All work in /tmp/c10/ (decomp.py,
6
+ run.py); repo untouched, monkeypatch only.
7
+
8
+ ## Step 1 — where the EARLY cost actually comes from
9
+
10
+ Instrumented champion rerun (/tmp/c10/decomp.py): bit-exact reproduction
11
+ (max per-scenario |delta| vs ref = 0.0; reconstructed early-days 728.0/scen
12
+ = recorded). Per-swap capture: planned day vs cost-curve argmin (the
13
+ planner's solo-optimal day) vs effective EOL (observed, or evaluator-imputed
14
+ end_time+unobserved_eol_days). Swap-level CSV: /tmp/c10/decomp_swaps.csv.
15
+
16
+ Mechanics first: plan_tsroute does NOT use a single day quantile. The
17
+ CHAMPION day_q=0.05 argument is ignored; placement = argmin of the
18
+ expected-cost curves built in mc.cost_curves from the FULL 4-quantile
19
+ DayQuantiles CDF (piecewise linear through day_q{.05,.20,.50,.80}) +
20
+ survivor branch priced against imputed EOL, then optimize_days perturbs for
21
+ mobility/limits.
22
+
23
+ CV early = 364.0/scen (728 early-days, 11.33 swaps/scen). Decomposition:
24
+
25
+ | bucket | swaps/plan | early cost/scen | share |
26
+ |------------------------------------------|-----------:|----------------:|------:|
27
+ | imputed-EOL false positives (no EOL on file; priced vs end+30d, ~123 early-days each) | 0.88 | 268.5 | 74% |
28
+ | real deaths beyond the window (mean EOL day ~89, zero in-window late risk) | 0.35 | 70.3 | 19% |
29
+ | in-window deaths swapped early (true timing error) | 1.04 | 25.2 | 7% |
30
+
31
+ **Timing model vs planner packing: packing is nil.** Of 34,944 total
32
+ early-days only 219 (0.6%, ~2.3/scen) come from optimize_days moving a swap
33
+ off its solo cost-curve argmin (median move 0 days, p5..p95 = -4..+2).
34
+ Everything else is placement-given-predictions.
35
+
36
+ **And the true-timing slice is not conservative — it is already
37
+ late-risky.** In-window deaths: planner places at mean day 6.7 vs true mean
38
+ EOL 15.7 (deliberate 20:1 hedging — cost_curves swaps at ~F(d)=0.048 of the
39
+ predicted CDF), but 15.3% of in-window deaths are swapped LATE vs the 4.8%
40
+ the hedge targets: the DayQuantiles left tail is too OPTIMISTIC, not too
41
+ early. Late side confirms: 949.4/scen late = 922.7 unswapped-death
42
+ emergencies (selection misses) + only 26.7 swapped-too-late.
43
+
44
+ Naive EV check (swap set + realized days held fixed, shift dates +k):
45
+ uniform +2/+5/+8 = net +16.5/+63.0/+130.4 per scen (late at 10/day
46
+ overwhelms early savings at 0.5/day); plateau-only (rel_close<=.10) +6/+10 =
47
+ +22.0/+56.5. The 20:1 asymmetry means one overtaken in-window death cancels
48
+ 20 days of early savings, and 24% of early-swapped in-window deaths have a
49
+ margin of <= 5 days.
50
+
51
+ Oracle ceiling for pure-timing gains: ~147/scen (push every never-dying
52
+ swap to day 42 + swap every in-window death exactly on its EOL) — but that
53
+ requires an oracle for WHICH devices die in-window, i.e. it is a selection
54
+ problem, not a dates problem.
55
+
56
+ ## Step 2 — arms (all value/order/count-preserving; only day_q columns or
57
+ ## cost-curve pricing change; blend=('champ',1.0) is the champion order)
58
+
59
+ Driver /tmp/c10/run.py (c9 pattern: load_table gap-cols monkeypatch,
60
+ mc.MODELS registration, cv.run_bgkf(kind=<arm>, variant='vm7',
61
+ blend=('champ',1.0), p_star=1.0), paired stats vs ref, ref asserted 1545.4).
62
+ champ0 = plain-logbag primary + champion order (reproduction control).
63
+
64
+ Arms: shift(k) = +k days on all four day_q columns (global calibration
65
+ curve); qmap(s) = quantile-level remap, model level L read as truth level
66
+ L*s (CDF pushed right, multiplicative); wnrday = wiener first-passage day
67
+ quantiles replace DayQuantiles for wnr_n>=3 devices; gap(k) = +k days for
68
+ plateau devices only (rel_close<=0.15, 65% of swaps / 69% of early-days,
69
+ justified by: plateau in-window deaths die later, day 18.4 vs 10.2, and are
70
+ swapped more too-early, 10.2d vs 6.8d); lint(v) = internal LATE price v
71
+ instead of 10 in cost_curves (placement hedges less); cblend3 =
72
+ cost_curves blend=0.3 (low-p42 CDF pulled toward uniform — pre-existing
73
+ mechanism, default off). All paired vs ref over the 48 scenario totals.
74
+
75
+ | arm | SCORE | delta±SE | sig | W/L | wcx | swaps | dEarly | dLate |
76
+ |-----------|--------|--------------|-----|--------|-------|-------|--------|--------|
77
+ | champ0 | 1545.4 | -0.0± 0.0 | — | — | — | 2.27 | 0.0 | 0.0 |
78
+ | t_shift2 | 1563.3 | +17.9± 6.0 | 3.0 | 16/32 | .000 | 2.26 | -11.1 | +24.8 |
79
+ | t_shift5 | 1601.6 | +56.2±13.7 | 4.1 | 14/34 | .000 | 2.20 | -31.9 | +87.5 |
80
+ | t_shift8 | 1671.2 | +125.8±18.2 | 6.9 | 7/41 | .000 | 2.14 | -50.2 | +175.6 |
81
+ | t_qmap13 | 1545.0 | -0.4± 9.0 | 0.0 | 32/16 | .277 | 2.19 | -13.9 | +12.7 |
82
+ | t_qmap16 | 1538.8 | -6.6± 6.8 | 1.0 | 29/18 | .437 | 2.15 | -24.4 | +21.5 |
83
+ | t_qmap25 | 1575.8 | +30.4±10.7 | 2.8 | 18/30 | .012 | 2.08 | -46.4 | +80.6 |
84
+ | t_wnrday | 1659.5 | +114.0±20.4 | 5.6 | 10/38 | .000 | 2.35 | +19.4 | +89.2 |
85
+ | t_gap6 | 1565.0 | +19.6±10.9 | 1.8 | 23/25 | .218 | 2.20 | -26.8 | +49.6 |
86
+ | t_gap10 | 1618.8 | +73.4±18.3 | 4.0 | 16/32 | .000 | 2.14 | -42.5 | +118.8 |
87
+ | t_lint7 | 1539.0 | -6.5± 6.3 | 1.0 | 30/18 | .198 | 2.17 | -19.9 | +17.1 |
88
+ | t_lint8 | 1548.8 | +3.4± 8.4 | 0.4 | 31/15 | .516 | 2.21 | -11.5 | +14.0 |
89
+ | t_cblend3 | 1550.1 | +4.6± 4.7 | 1.0 | 13/34 | .181 | 2.27 | +4.4 | -3.8 |
90
+
91
+ (dEarly/dLate = mean per-scenario change in early_swap / late_swap cost.)
92
+
93
+ Pareto: every rightward move of the dates trades early for late at a slope
94
+ of 0.86–3.5 cost-units of late per unit of early saved; only qmap16 and
95
+ lint7 sit slightly below 1.0 and net ~-6.5, both 1.0sig only. The dose-
96
+ response is a shallow noise-level basin around the champion (qmap13 -0.4,
97
+ qmap16 -6.6, qmap25 +30; lint7 -6.5, lint8 +3.4): no dip to harvest.
98
+ Note the W/L shape of the near-zero arms (29-32W / 15-18L yet insignificant
99
+ Wilcoxon and ~0 mean): many small wins from FEWER swaps, occasional large
100
+ losses when a shifted date lets a death be overtaken — the classic
101
+ count-coupled signature (phase-56 lesson).
102
+
103
+ Count-coupling: all timing arms except cblend3 move the swaps column
104
+ (2.27 -> 2.08–2.35) because plan_tsroute's ec break-even top-up reads the
105
+ same cost curves the shift modifies (curves.min vs 0.8*park). The two
106
+ "winners" therefore fail count-flatness on top of failing the sigma bar.
107
+
108
+ ## Verdict
109
+
110
+ - No adoptable candidate. Best arms t_qmap16 (-6.6±6.8, 1.0sig, swaps 2.15)
111
+ and t_lint7 (-6.5±6.3, 1.0sig, swaps 2.17): below the 1.5sigma tier bar
112
+ AND count-coupled (report-only per tier rules regardless of sigma).
113
+ - The EARLY cost is NOT a timing problem. 93% of it is selection (74%
114
+ imputed-EOL false positives at ~123 early-days each + 19% real deaths far
115
+ beyond the window); only 7% (25.2/scen) is dying devices swapped early,
116
+ and that slice is already late-risky (15.3% of in-window deaths swapped
117
+ late vs the 4.8% the 20:1 hedge targets). Planner packing contributes
118
+ 0.6% of early-days — nothing to fix there.
119
+ - Recommendation for the campaign: EARLY reduction must come from the
120
+ ORDER/selection axis (fewer never-dying devices inside the top-N and the
121
+ ec top-up), not from swap dates. The timing axis is mapped and closed:
122
+ global shifts, quantile remaps, wiener dates, gap-conditioned shifts, and
123
+ internal price recalibration all lose or wash.
124
+
125
+ Artifacts: /tmp/c10/run.py (driver), /tmp/c10/decomp.py + decomp_swaps.csv
126
+ (per-swap decomposition), /tmp/cv_bgkfcand_c10_*.csv (per-cell arm CSVs).
batteryswap_example/cv.py CHANGED
@@ -176,7 +176,8 @@ VARIANTS = {'base': _base, 'ranks_add': _ranks_add, 'vrel': _vrel,
176
  # --------------------------------------------------------------------------
177
 
178
  def run_bgkf(dataset_path=Path('dataset'), kind=None, variant='base',
179
- blend=None, n_folds=N_FOLDS, origins=range(48), p_star=None):
 
180
  """THE SCORE. Per fold: one fit on the TRAIN buildings' full closed-pair
181
  history (deployment-exact for a held-out fleet), then per scenario the
182
  TEST buildings are planned as a standalone fleet under submit.py's
@@ -201,7 +202,8 @@ def run_bgkf(dataset_path=Path('dataset'), kind=None, variant='base',
201
  p = mc.plan_tsroute
202
  p.alpha = CHAMPION['p_star'] if p_star is None else p_star
203
  p.ec_margin, p.ec_pmax = CHAMPION['ec_margin'], CHAMPION['ec_pmax']
204
- p.split_days = CHAMPION['split_days']
 
205
  p.floor_scale, p.recent_deaths = CHAMPION['floor_scale'], 0.0
206
 
207
  def _fit(k_, train):
@@ -323,10 +325,14 @@ CANDIDATES = {
323
  # ft2a10 / head = THE CURRENT MODEL: runs the literal deployed class
324
  # (submit.Ft2RUL - lazily registered in main()), so these labels always
325
  # score exactly what a public trigger would run. Older forms kept below.
326
- 'ft2a10': dict(kind='@deployed', variant='base', p_star=1.0),
 
327
  'ft2a10_w20': dict(variant='vm7', blend=('wiener', 0.20), p_star=1.0),
328
  'ft2a10_w25': dict(variant='vm7', blend=('wiener', 0.25), p_star=1.0),
329
- 'head': dict(kind='@deployed', variant='base', p_star=1.0),
 
 
 
330
  }
331
 
332
 
 
176
  # --------------------------------------------------------------------------
177
 
178
  def run_bgkf(dataset_path=Path('dataset'), kind=None, variant='base',
179
+ blend=None, n_folds=N_FOLDS, origins=range(48), p_star=None,
180
+ split_days=None, timing_weight=None):
181
  """THE SCORE. Per fold: one fit on the TRAIN buildings' full closed-pair
182
  history (deployment-exact for a held-out fleet), then per scenario the
183
  TEST buildings are planned as a standalone fleet under submit.py's
 
202
  p = mc.plan_tsroute
203
  p.alpha = CHAMPION['p_star'] if p_star is None else p_star
204
  p.ec_margin, p.ec_pmax = CHAMPION['ec_margin'], CHAMPION['ec_pmax']
205
+ p.split_days = CHAMPION['split_days'] if split_days is None else split_days
206
+ p.timing_weight = 1.0 if timing_weight is None else timing_weight
207
  p.floor_scale, p.recent_deaths = CHAMPION['floor_scale'], 0.0
208
 
209
  def _fit(k_, train):
 
325
  # ft2a10 / head = THE CURRENT MODEL: runs the literal deployed class
326
  # (submit.Ft2RUL - lazily registered in main()), so these labels always
327
  # score exactly what a public trigger would run. Older forms kept below.
328
+ 'ft2a10': dict(kind='@deployed', variant='base', p_star=1.0,
329
+ split_days=3, timing_weight=2.0),
330
  'ft2a10_w20': dict(variant='vm7', blend=('wiener', 0.20), p_star=1.0),
331
  'ft2a10_w25': dict(variant='vm7', blend=('wiener', 0.25), p_star=1.0),
332
+ 'head': dict(kind='@deployed', variant='base', p_star=1.0,
333
+ split_days=3, timing_weight=2.0),
334
+ # pre-T2 plan path (split 7, weight 1) kept for paired A/B:
335
+ 'ft2a10_sp7': dict(kind='@deployed', variant='base', p_star=1.0),
336
  }
337
 
338
 
batteryswap_example/models_cv.py CHANGED
@@ -1508,8 +1508,8 @@ def plan_tsroute(pred, included, locations, start_time, day_q,
1508
  for g, m in curves.groupby(key)}
1509
  travel_hours = travel_costs.set_index(['from', 'to'])['hours'].unstack()
1510
 
1511
- day_of = optimize_days(groups, curves, locations, travel_hours,
1512
- settings, start_time)
1513
 
1514
  offs = key.map(day_of).astype(float)
1515
  days = start_time + pd.to_timedelta(offs.values, unit='D')
@@ -1530,6 +1530,7 @@ def plan_tsroute(pred, included, locations, start_time, day_q,
1530
 
1531
  plan_tsroute.alpha = 0.8
1532
  plan_tsroute.split_days = 0
 
1533
  plan_tsroute.p_be = 0.0
1534
  plan_tsroute.floor_day = 0
1535
  plan_tsroute.p_conf = 0.5
 
1508
  for g, m in curves.groupby(key)}
1509
  travel_hours = travel_costs.set_index(['from', 'to'])['hours'].unstack()
1510
 
1511
+ day_of = optimize_days(groups, curves * plan_tsroute.timing_weight,
1512
+ locations, travel_hours, settings, start_time)
1513
 
1514
  offs = key.map(day_of).astype(float)
1515
  days = start_time + pd.to_timedelta(offs.values, unit='D')
 
1530
 
1531
  plan_tsroute.alpha = 0.8
1532
  plan_tsroute.split_days = 0
1533
+ plan_tsroute.timing_weight = 1.0 # scales timing curves in optimize_days' objective
1534
  plan_tsroute.p_be = 0.0
1535
  plan_tsroute.floor_day = 0
1536
  plan_tsroute.p_conf = 0.5
batteryswap_example/submit.py CHANGED
@@ -371,7 +371,15 @@ EC_PMAX = float(os.environ.get('BATTERYSWAP_EC_PMAX', '25'))
371
  # Phase 14: let the day search split a building across days by best-day
372
  # bucket (7d) instead of forcing one visit day per building. Panel 1679.2 vs
373
  # 1702.0, selected in 100% of random AND blocked half-splits.
374
- SPLIT_DAYS = int(os.environ.get('BATTERYSWAP_SPLIT_DAYS', '7'))
 
 
 
 
 
 
 
 
375
  # Phase 17: cold-start inclusion floor. While the training set has seen fewer
376
  # than FLOOR_GATE unique deaths, sum(p42) undercounts prevalence ~4x and the
377
  # count rule parks visibly-dying batteries (warm-up block s_0-s_7: 46% of the
@@ -723,6 +731,7 @@ def adaptive_split_plans(split, split_path, log=print, deadline=None):
723
  plan_tsroute.ec_margin = EC_MARGIN
724
  plan_tsroute.ec_pmax = EC_PMAX
725
  plan_tsroute.split_days = SPLIT_DAYS
 
726
  plan_tsroute.floor_scale = FLOOR_SCALE
727
  plan_tsroute.recent_deaths = 0.0
728
  if FLOOR_SCALE > 0 and train_uniq < FLOOR_GATE:
 
371
  # Phase 14: let the day search split a building across days by best-day
372
  # bucket (7d) instead of forcing one visit day per building. Panel 1679.2 vs
373
  # 1702.0, selected in 100% of random AND blocked half-splits.
374
+ SPLIT_DAYS = int(os.environ.get('BATTERYSWAP_SPLIT_DAYS', '3'))
375
+ # T2 planner lane (2026-08-23): weight the timing curves x2 inside
376
+ # optimize_days' objective and split buildings at 3d (not 7d) buckets -
377
+ # together they refuse cheap trip-merges that drag a swap off its
378
+ # timing-optimal day (late -3.5, early -1.2, bought with +0.8 mobility).
379
+ # bgkf -4.11 +/- 1.41 (2.9sigma, 25W/4L, Wilcoxon 8.8e-6), count-flat with
380
+ # battery sets cell-identical; dose-response plateau on both dials.
381
+ # TIMING_WEIGHT=1 + SPLIT_DAYS=7 restores the old plan path exactly.
382
+ TIMING_WEIGHT = float(os.environ.get('BATTERYSWAP_TIMING_WEIGHT', '2.0'))
383
  # Phase 17: cold-start inclusion floor. While the training set has seen fewer
384
  # than FLOOR_GATE unique deaths, sum(p42) undercounts prevalence ~4x and the
385
  # count rule parks visibly-dying batteries (warm-up block s_0-s_7: 46% of the
 
731
  plan_tsroute.ec_margin = EC_MARGIN
732
  plan_tsroute.ec_pmax = EC_PMAX
733
  plan_tsroute.split_days = SPLIT_DAYS
734
+ plan_tsroute.timing_weight = TIMING_WEIGHT
735
  plan_tsroute.floor_scale = FLOOR_SCALE
736
  plan_tsroute.recent_deaths = 0.0
737
  if FLOOR_SCALE > 0 and train_uniq < FLOOR_GATE: