solverpilot 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. solverpilot/__init__.py +250 -0
  2. solverpilot/_immutability.py +27 -0
  3. solverpilot/_version.py +3 -0
  4. solverpilot/applications/__init__.py +3 -0
  5. solverpilot/applications/routing/__init__.py +19 -0
  6. solverpilot/applications/routing/compile_milp.py +321 -0
  7. solverpilot/applications/routing/diagnostics.py +78 -0
  8. solverpilot/applications/routing/errors.py +14 -0
  9. solverpilot/applications/routing/heuristics.py +167 -0
  10. solverpilot/applications/routing/model.py +259 -0
  11. solverpilot/applications/routing/reference.py +81 -0
  12. solverpilot/applications/routing/solution.py +89 -0
  13. solverpilot/applications/routing/timeline.py +79 -0
  14. solverpilot/applications/routing/validation.py +169 -0
  15. solverpilot/applications/tsp/__init__.py +41 -0
  16. solverpilot/applications/tsp/compile_cp.py +121 -0
  17. solverpilot/applications/tsp/compile_milp.py +139 -0
  18. solverpilot/applications/tsp/distance.py +60 -0
  19. solverpilot/applications/tsp/errors.py +17 -0
  20. solverpilot/applications/tsp/heuristics.py +112 -0
  21. solverpilot/applications/tsp/model.py +175 -0
  22. solverpilot/applications/tsp/reference.py +121 -0
  23. solverpilot/applications/tsp/solution.py +65 -0
  24. solverpilot/applications/tsp/validation.py +92 -0
  25. solverpilot/backends/__init__.py +51 -0
  26. solverpilot/backends/_casadi_highs_worker.py +92 -0
  27. solverpilot/backends/base.py +28 -0
  28. solverpilot/backends/bundled_capi.py +910 -0
  29. solverpilot/backends/casadi_conic.py +303 -0
  30. solverpilot/backends/health.py +240 -0
  31. solverpilot/backends/highspy_native.py +217 -0
  32. solverpilot/backends/nlopt_native.py +237 -0
  33. solverpilot/backends/osqp_native.py +297 -0
  34. solverpilot/backends/protocol_v2.py +119 -0
  35. solverpilot/backends/pyscipopt_native.py +200 -0
  36. solverpilot/backends/registry.py +38 -0
  37. solverpilot/backends/scipy_highs.py +138 -0
  38. solverpilot/backends/scipy_highs_lp.py +195 -0
  39. solverpilot/backends/scipy_slsqp_qp.py +133 -0
  40. solverpilot/backends/scipy_vendored_highs_dev.py +363 -0
  41. solverpilot/benchmark/__init__.py +23 -0
  42. solverpilot/benchmark/acquire.py +199 -0
  43. solverpilot/benchmark/baselines.py +70 -0
  44. solverpilot/benchmark/bundle.py +37 -0
  45. solverpilot/benchmark/campaign.py +150 -0
  46. solverpilot/benchmark/environment.py +115 -0
  47. solverpilot/benchmark/integrity.py +46 -0
  48. solverpilot/benchmark/model.py +146 -0
  49. solverpilot/benchmark/policy.py +182 -0
  50. solverpilot/benchmark/registry.py +38 -0
  51. solverpilot/benchmark/report.py +44 -0
  52. solverpilot/benchmark/runner.py +516 -0
  53. solverpilot/benchmark/slurm.py +55 -0
  54. solverpilot/benchmark/specs.py +75 -0
  55. solverpilot/benchmark/splits.py +181 -0
  56. solverpilot/benchmark/summary.py +384 -0
  57. solverpilot/benchmark/verify.py +142 -0
  58. solverpilot/benchmark/worker.py +71 -0
  59. solverpilot/bridges/__init__.py +19 -0
  60. solverpilot/bridges/engine.py +44 -0
  61. solverpilot/bridges/indicator.py +232 -0
  62. solverpilot/bridges/registry.py +78 -0
  63. solverpilot/bridges/transformation-tape.schema.json +53 -0
  64. solverpilot/bridges/types.py +149 -0
  65. solverpilot/bridges/validation.py +110 -0
  66. solverpilot/capabilities/__init__.py +32 -0
  67. solverpilot/capabilities/backend-capability-v2.schema.json +21 -0
  68. solverpilot/capabilities/conformance.py +151 -0
  69. solverpilot/capabilities/enums.py +27 -0
  70. solverpilot/capabilities/manifest.py +19 -0
  71. solverpilot/capabilities/ontology.py +73 -0
  72. solverpilot/capabilities/requirements.py +37 -0
  73. solverpilot/capabilities/resolve.py +30 -0
  74. solverpilot/capabilities/v2.py +711 -0
  75. solverpilot/cli/__init__.py +1 -0
  76. solverpilot/cli/backend_health.py +77 -0
  77. solverpilot/cli/benchmark.py +331 -0
  78. solverpilot/cli/benchmark_worker.py +33 -0
  79. solverpilot/cli/capabilities.py +65 -0
  80. solverpilot/conic/__init__.py +11 -0
  81. solverpilot/conic/backend.py +263 -0
  82. solverpilot/conic/compiler.py +310 -0
  83. solverpilot/conic/conformance.py +60 -0
  84. solverpilot/conic/conic-ir-v1.schema.json +24 -0
  85. solverpilot/conic/ir.py +299 -0
  86. solverpilot/conic/validation.py +149 -0
  87. solverpilot/cp/__init__.py +7 -0
  88. solverpilot/cp/conformance.py +32 -0
  89. solverpilot/cp/cp-ir-v1.schema.json +13 -0
  90. solverpilot/cp/ir.py +170 -0
  91. solverpilot/cp/model.py +143 -0
  92. solverpilot/cp/ortools_backend.py +423 -0
  93. solverpilot/cp/ortools_worker.py +75 -0
  94. solverpilot/cp/reference.py +51 -0
  95. solverpilot/cp/serialization.py +117 -0
  96. solverpilot/cp/validate.py +83 -0
  97. solverpilot/diagnose/__init__.py +33 -0
  98. solverpilot/diagnose/infeasibility.py +463 -0
  99. solverpilot/diagnose/model.py +87 -0
  100. solverpilot/evaluation/__init__.py +53 -0
  101. solverpilot/evaluation/metrics.py +150 -0
  102. solverpilot/evaluation/oracle.py +288 -0
  103. solverpilot/evaluation/proof.py +53 -0
  104. solverpilot/evaluation/references.py +73 -0
  105. solverpilot/evaluation/regret.py +281 -0
  106. solverpilot/exceptions.py +34 -0
  107. solverpilot/experimental/__init__.py +32 -0
  108. solverpilot/extensions/__init__.py +56 -0
  109. solverpilot/extensions/entrypoints.py +34 -0
  110. solverpilot/extensions/errors.py +35 -0
  111. solverpilot/extensions/manager.py +651 -0
  112. solverpilot/extensions/manifest.py +232 -0
  113. solverpilot/extensions/model.py +101 -0
  114. solverpilot/extensions/versioning.py +136 -0
  115. solverpilot/history/__init__.py +22 -0
  116. solverpilot/history/errors.py +15 -0
  117. solverpilot/history/model.py +129 -0
  118. solverpilot/history/sqlite.py +651 -0
  119. solverpilot/inspect/__init__.py +3 -0
  120. solverpilot/inspect/fingerprint.py +199 -0
  121. solverpilot/intelligence/__init__.py +36 -0
  122. solverpilot/intelligence/errors.py +16 -0
  123. solverpilot/intelligence/fingerprint.py +108 -0
  124. solverpilot/intelligence/leakage.py +69 -0
  125. solverpilot/intelligence/schema.py +314 -0
  126. solverpilot/intelligence/shift.py +208 -0
  127. solverpilot/io/__init__.py +41 -0
  128. solverpilot/io/binary64.py +49 -0
  129. solverpilot/io/csv.py +230 -0
  130. solverpilot/io/errors.py +25 -0
  131. solverpilot/io/hashing.py +111 -0
  132. solverpilot/io/json.py +90 -0
  133. solverpilot/io/mapping.py +195 -0
  134. solverpilot/io/model.py +407 -0
  135. solverpilot/io/numeric.py +108 -0
  136. solverpilot/io/provenance.py +114 -0
  137. solverpilot/io/result.py +45 -0
  138. solverpilot/io/source.py +104 -0
  139. solverpilot/io/strict_json.py +133 -0
  140. solverpilot/minlp/__init__.py +6 -0
  141. solverpilot/minlp/compiler.py +66 -0
  142. solverpilot/minlp/conformance.py +34 -0
  143. solverpilot/minlp/convexity.py +85 -0
  144. solverpilot/minlp/ir.py +35 -0
  145. solverpilot/minlp/minlp-ir-v1.schema.json +1 -0
  146. solverpilot/minlp/orchestrator.py +220 -0
  147. solverpilot/minlp/validation.py +28 -0
  148. solverpilot/model/__init__.py +27 -0
  149. solverpilot/model/compiler.py +1263 -0
  150. solverpilot/model/errors.py +22 -0
  151. solverpilot/model/expression.py +373 -0
  152. solverpilot/model/model.py +716 -0
  153. solverpilot/model/sets.py +60 -0
  154. solverpilot/model/types.py +36 -0
  155. solverpilot/nlp/__init__.py +7 -0
  156. solverpilot/nlp/ad.py +166 -0
  157. solverpilot/nlp/backend.py +113 -0
  158. solverpilot/nlp/compiler.py +116 -0
  159. solverpilot/nlp/conformance.py +58 -0
  160. solverpilot/nlp/ir.py +70 -0
  161. solverpilot/nlp/nlp-ir-v1.schema.json +1 -0
  162. solverpilot/nlp/validation.py +60 -0
  163. solverpilot/plan/__init__.py +33 -0
  164. solverpilot/plan/model.py +79 -0
  165. solverpilot/plan/planner.py +201 -0
  166. solverpilot/plan/production.py +627 -0
  167. solverpilot/plan/selective_lp.py +65 -0
  168. solverpilot/problem/__init__.py +16 -0
  169. solverpilot/problem/enums.py +20 -0
  170. solverpilot/problem/hashing.py +88 -0
  171. solverpilot/problem/linear.py +196 -0
  172. solverpilot/problem/mps.py +447 -0
  173. solverpilot/problem/quadratic.py +192 -0
  174. solverpilot/reporting/__init__.py +27 -0
  175. solverpilot/reporting/explain.py +327 -0
  176. solverpilot/reporting/model.py +264 -0
  177. solverpilot/reporting/render.py +55 -0
  178. solverpilot/runtime/__init__.py +19 -0
  179. solverpilot/runtime/auto.py +193 -0
  180. solverpilot/runtime/budgeting.py +43 -0
  181. solverpilot/runtime/executor.py +126 -0
  182. solverpilot/runtime/portfolio.py +197 -0
  183. solverpilot/runtime/result.py +72 -0
  184. solverpilot/session/__init__.py +29 -0
  185. solverpilot/session/conformance_v2.py +239 -0
  186. solverpilot/session/mutations.py +115 -0
  187. solverpilot/session/persistent-session-trace.schema.json +45 -0
  188. solverpilot/session/persistent.py +491 -0
  189. solverpilot/session/reuse.py +81 -0
  190. solverpilot/session/session.py +236 -0
  191. solverpilot/trace/__init__.py +3 -0
  192. solverpilot/trace/schema.py +47 -0
  193. solverpilot/validate/__init__.py +10 -0
  194. solverpilot/validate/core.py +179 -0
  195. solverpilot/validate/result.py +55 -0
  196. solverpilot-0.1.dist-info/METADATA +554 -0
  197. solverpilot-0.1.dist-info/RECORD +201 -0
  198. solverpilot-0.1.dist-info/WHEEL +5 -0
  199. solverpilot-0.1.dist-info/entry_points.txt +4 -0
  200. solverpilot-0.1.dist-info/licenses/LICENSE +202 -0
  201. solverpilot-0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,627 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from enum import Enum
5
+ import hashlib
6
+ import json
7
+ from typing import Iterable, Mapping
8
+
9
+ from solverpilot.backends import Backend, BackendHealthReport, BackendRegistry
10
+ from solverpilot.inspect import ProblemFingerprint, inspect_problem
11
+ from solverpilot.problem import LinearProblem, QuadraticProblem
12
+
13
+ from .model import HealthPolicy, PlannerContext, SolveBudget, SolveIntent, SolvePlan
14
+ from .planner import NoCompatibleBackendError, plan_solve
15
+
16
+
17
+ class EvidenceClass(str, Enum):
18
+ NONE = "none"
19
+ CAPABILITY = "capability"
20
+ CORPUS_VALIDATED = "corpus_validated"
21
+ COMPARATIVE_VALIDATION = "comparative_validation"
22
+ COMPARATIVE_HELDOUT = "comparative_heldout"
23
+
24
+
25
+ class PerformancePolicy(str, Enum):
26
+ CONSERVATIVE = "conservative"
27
+ REQUIRE_COMPARATIVE = "require_comparative"
28
+ ALLOW_COMPARATIVE = "allow_comparative"
29
+
30
+
31
+ def _canonical_payload_sha256(payload: Mapping[str, object], *, exclude: tuple[str, ...] = ()) -> str:
32
+ body = {k: v for k, v in payload.items() if k not in exclude}
33
+ raw = json.dumps(body, sort_keys=True, separators=(",", ":"), default=str).encode()
34
+ return hashlib.sha256(raw).hexdigest()
35
+
36
+
37
+ @dataclass(frozen=True, slots=True)
38
+ class ProductionEvidence:
39
+ evidence_class: EvidenceClass
40
+ source: str
41
+ corpus_integrity_passed: bool = False
42
+ outcome_accounting_passed: bool = False
43
+ independent_validation_passed: bool = False
44
+ reference_crosscheck_passed: bool = False
45
+ comparative_backends: tuple[str, ...] = ()
46
+ heldout: bool = False
47
+ feature_cost_accounted: bool = False
48
+ fixed_environment: bool = False
49
+ public_ood: bool = False
50
+ pre_registered_policy: bool = False
51
+ selection_opportunity_validated: bool = False
52
+ performance_ranking_validated: bool = False
53
+ selector_name: str | None = None
54
+ notes: tuple[str, ...] = ()
55
+
56
+ @property
57
+ def supports_performance_ranking(self) -> bool:
58
+ return (
59
+ self.evidence_class is EvidenceClass.COMPARATIVE_HELDOUT
60
+ and len(set(self.comparative_backends)) >= 2
61
+ and self.heldout
62
+ and self.feature_cost_accounted
63
+ and self.fixed_environment
64
+ and self.public_ood
65
+ and self.pre_registered_policy
66
+ and self.selection_opportunity_validated
67
+ and self.performance_ranking_validated
68
+ )
69
+
70
+
71
+ @dataclass(frozen=True, slots=True)
72
+ class ProductionDecision:
73
+ plan: SolvePlan
74
+ auto_performance_ranking_enabled: bool
75
+ evidence: ProductionEvidence
76
+ conservative_baseline: str | None
77
+ rationale: tuple[str, ...]
78
+ rejected_performance_override_reason: str | None = None
79
+
80
+
81
+ M22_OFFICIAL_EVIDENCE = ProductionEvidence(
82
+ evidence_class=EvidenceClass.CORPUS_VALIDATED,
83
+ source="M22 official MIPLIB/QPLIB/PACE fixed-host gate",
84
+ corpus_integrity_passed=True,
85
+ outcome_accounting_passed=True,
86
+ independent_validation_passed=True,
87
+ reference_crosscheck_passed=True,
88
+ comparative_backends=(),
89
+ heldout=False,
90
+ feature_cost_accounted=False,
91
+ fixed_environment=True,
92
+ public_ood=True,
93
+ pre_registered_policy=False,
94
+ performance_ranking_validated=False,
95
+ notes=(
96
+ "official-byte integrity and outcome accounting passed",
97
+ "M22 did not benchmark multiple candidate backends under a held-out comparative protocol",
98
+ "timeouts were explicit outcomes and no solver-superiority claim was made",
99
+ ),
100
+ )
101
+
102
+
103
+ def _backend_names(registry: BackendRegistry) -> set[str]:
104
+ return {b.manifest.name for b in registry.all() if b.is_available()}
105
+
106
+
107
+ def _conservative_baseline(problem: LinearProblem | QuadraticProblem, registry: BackendRegistry) -> str | None:
108
+ names = _backend_names(registry)
109
+ if isinstance(problem, LinearProblem):
110
+ if problem.has_integer_variables:
111
+ for name in ("scipy-highs-bridge", "highspy-native", "pyscipopt-native"):
112
+ if name in names:
113
+ return name
114
+ else:
115
+ for name in ("scipy-highs-ds", "scipy-highs-ipm", "scipy-highs-bridge", "highspy-native"):
116
+ if name in names:
117
+ return name
118
+ if isinstance(problem, QuadraticProblem):
119
+ # Public native OSQP is preferred only when actually available. The SLSQP
120
+ # bridges explicitly lack an optimality certificate and are therefore never
121
+ # forced for PROVE_OPTIMAL by this production layer.
122
+ for name in ("osqp-native", "scipy-slsqp-qp-bridge", "nlopt-slsqp-native"):
123
+ if name in names:
124
+ return name
125
+ return None
126
+
127
+
128
+
129
+ def production_evidence_from_m24_public_ood(payload: Mapping[str, object], *, source: str) -> ProductionEvidence:
130
+ """Translate an M24 public/OOD comparative report into production evidence.
131
+
132
+ A comparative experiment is not automatically routing authority. M24 requires the
133
+ pre-registered selector to pass every promotion gate before ``supports_performance_ranking``
134
+ can become true. This prevents a negative or inconclusive held-out experiment from
135
+ accidentally authorizing a user-supplied performance override.
136
+ """
137
+ metrics = payload.get("metrics") if isinstance(payload.get("metrics"), Mapping) else {}
138
+ gates = payload.get("promotion_gates") if isinstance(payload.get("promotion_gates"), Mapping) else {}
139
+ rule = payload.get("pre_registered_rule") if isinstance(payload.get("pre_registered_rule"), Mapping) else {}
140
+ claims = payload.get("claims_boundary")
141
+ promoted = bool(payload.get("selector_promoted")) and bool(gates) and all(bool(v) for v in gates.values())
142
+ fixed_environment = isinstance(payload.get("environment"), Mapping)
143
+ public_ood = str(payload.get("source", "")).lower().find("miplib") >= 0
144
+ notes = [
145
+ "M24 public/OOD DS-vs-IPM comparative benchmark parsed into production evidence",
146
+ f"selector promoted: {promoted}",
147
+ ]
148
+ if isinstance(metrics, Mapping):
149
+ if "sbs_backend" in metrics:
150
+ notes.append(f"SBS: {metrics['sbs_backend']}")
151
+ boot = metrics.get("policy_to_sbs_bootstrap")
152
+ if isinstance(boot, Mapping) and "high" in boot:
153
+ notes.append(f"policy/SBS bootstrap upper: {boot['high']}")
154
+ if isinstance(claims, list):
155
+ notes.extend(str(x) for x in claims[:2])
156
+ return ProductionEvidence(
157
+ evidence_class=EvidenceClass.COMPARATIVE_HELDOUT,
158
+ source=source,
159
+ corpus_integrity_passed=bool(payload.get("official_corpus_integrity_passed")),
160
+ outcome_accounting_passed=int(payload.get("instances", 0) or 0) >= 1,
161
+ independent_validation_passed=(isinstance(metrics, Mapping) and int(metrics.get("objective_mismatches", 1) or 0) == 0),
162
+ reference_crosscheck_passed=(isinstance(metrics, Mapping) and int(metrics.get("objective_mismatches", 1) or 0) == 0),
163
+ comparative_backends=("scipy-highs-ds", "scipy-highs-ipm"),
164
+ heldout=True,
165
+ feature_cost_accounted=True,
166
+ fixed_environment=fixed_environment,
167
+ public_ood=public_ood,
168
+ pre_registered_policy=bool(rule) and str(rule.get("origin", "")).find("frozen before M24") >= 0,
169
+ performance_ranking_validated=promoted,
170
+ selector_name=None if not rule else str(rule.get("name")),
171
+ notes=tuple(notes),
172
+ )
173
+
174
+
175
+ def production_evidence_from_m25_opportunity(payload: Mapping[str, object], *, source: str) -> ProductionEvidence:
176
+ """Translate M25 opportunity-stability evidence into production evidence.
177
+
178
+ M25 answers a narrower question than selector validation: is there enough stable
179
+ SBS->VBS opportunity, *after feature cost*, to justify investing in a selector?
180
+ Even a positive answer cannot authorize production ranking because M25 trains no
181
+ selector and validates no deployment policy.
182
+ """
183
+ run1 = payload.get("run1") if isinstance(payload.get("run1"), Mapping) else {}
184
+ run2 = payload.get("run2") if isinstance(payload.get("run2"), Mapping) else {}
185
+ metrics1 = run1.get("metrics") if isinstance(run1.get("metrics"), Mapping) else {}
186
+ metrics2 = run2.get("metrics") if isinstance(run2.get("metrics"), Mapping) else {}
187
+ env_audit = payload.get("environment_audit") if isinstance(payload.get("environment_audit"), Mapping) else {}
188
+ opportunity_ok = bool(payload.get("opportunity_validated_both")) and bool(payload.get("same_cohort")) and bool(payload.get("same_cohort_signature"))
189
+ objective_ok = int(metrics1.get("objective_mismatches", 1) or 0) == 0 and int(metrics2.get("objective_mismatches", 1) or 0) == 0
190
+ notes = [
191
+ "M25 public/OOD opportunity audit parsed into production evidence",
192
+ f"selection opportunity validated: {opportunity_ok}",
193
+ "M25 did not train or validate a selector; ranking remains disabled",
194
+ ]
195
+ for label, metrics in (("run1", metrics1), ("run2", metrics2)):
196
+ boot = metrics.get("oracle_with_inspection_to_sbs_bootstrap") if isinstance(metrics, Mapping) else None
197
+ if isinstance(boot, Mapping) and "high" in boot:
198
+ notes.append(f"{label} oracle+inspection/SBS bootstrap upper: {boot['high']}")
199
+ return ProductionEvidence(
200
+ evidence_class=EvidenceClass.COMPARATIVE_HELDOUT,
201
+ source=source,
202
+ corpus_integrity_passed=True,
203
+ outcome_accounting_passed=bool(payload.get("same_cohort")),
204
+ independent_validation_passed=objective_ok,
205
+ reference_crosscheck_passed=objective_ok,
206
+ comparative_backends=("scipy-highs-ds", "scipy-highs-ipm"),
207
+ heldout=True,
208
+ feature_cost_accounted=True,
209
+ fixed_environment=bool(env_audit.get("captured_in_same_active_container_session")),
210
+ public_ood=True,
211
+ pre_registered_policy=False,
212
+ selection_opportunity_validated=opportunity_ok,
213
+ performance_ranking_validated=False,
214
+ selector_name=None,
215
+ notes=tuple(notes),
216
+ )
217
+
218
+
219
+ def production_evidence_from_m26_validation(
220
+ model_payload: Mapping[str, object],
221
+ opportunity_payload: Mapping[str, object],
222
+ *,
223
+ source: str,
224
+ ) -> ProductionEvidence:
225
+ """Translate the sealed M26 validation result into non-deployable evidence.
226
+
227
+ M26 intentionally stops before test evaluation when the pre-registered validation
228
+ gate fails. This evidence class records that a selector was trained under a
229
+ leakage-controlled protocol, while keeping performance ranking disabled.
230
+ """
231
+ run1 = opportunity_payload.get("run1") if isinstance(opportunity_payload.get("run1"), Mapping) else {}
232
+ run2 = opportunity_payload.get("run2") if isinstance(opportunity_payload.get("run2"), Mapping) else {}
233
+ opportunity_ok = bool(opportunity_payload.get("opportunity_validated_both"))
234
+ validation = model_payload.get("validation") if isinstance(model_payload.get("validation"), Mapping) else {}
235
+ validation_gate = bool(model_payload.get("validation_gate_passed"))
236
+ test_seen = bool(model_payload.get("test_outcomes_seen_during_fit"))
237
+ notes = (
238
+ "M26 low-capacity ridge selector was trained only on frozen train/validation evidence",
239
+ f"M25 selection opportunity validated: {opportunity_ok}",
240
+ f"M26 validation gate passed: {validation_gate}",
241
+ f"validation policy/SBS: {validation.get('policy_to_sbs')}",
242
+ "M26 final test remained sealed because the validation gate failed" if not validation_gate else "M26 validation passed; final test still requires a separate held-out gate",
243
+ )
244
+ return ProductionEvidence(
245
+ evidence_class=EvidenceClass.COMPARATIVE_VALIDATION,
246
+ source=source,
247
+ corpus_integrity_passed=True,
248
+ outcome_accounting_passed=True,
249
+ independent_validation_passed=True,
250
+ reference_crosscheck_passed=True,
251
+ comparative_backends=("scipy-highs-ds", "scipy-highs-ipm"),
252
+ heldout=False,
253
+ feature_cost_accounted=True,
254
+ fixed_environment=True,
255
+ public_ood=True,
256
+ pre_registered_policy=True,
257
+ selection_opportunity_validated=opportunity_ok,
258
+ performance_ranking_validated=False,
259
+ selector_name=str(model_payload.get("model_family") or "m26-ridge-log-cost-ratio"),
260
+ notes=notes + (("WARNING: test outcomes were seen during fit",) if test_seen else ()),
261
+ )
262
+
263
+
264
+ def production_evidence_from_m27_heldout(
265
+ model_payload: Mapping[str, object],
266
+ test_payload: Mapping[str, object],
267
+ opportunity_payload: Mapping[str, object],
268
+ *,
269
+ source: str,
270
+ ) -> ProductionEvidence:
271
+ """Translate M27 one-time held-out selector evidence.
272
+
273
+ The exact selector is deployment-authoritative only when the frozen model passed
274
+ development, the original M25 opportunity remained valid, and every pre-registered
275
+ M27 held-out promotion gate passed. A consumed-but-negative held-out test remains
276
+ comparative evidence, but it must never enable solver-speed ranking.
277
+ """
278
+ opportunity_ok = bool(opportunity_payload.get("opportunity_validated_both"))
279
+ dev_ok = bool(model_payload.get("development_gate_passed"))
280
+ test_seen_during_fit = bool(model_payload.get("test_outcomes_seen_during_fit"))
281
+ gates = test_payload.get("promotion_gates") if isinstance(test_payload.get("promotion_gates"), Mapping) else {}
282
+ metrics = test_payload.get("metrics") if isinstance(test_payload.get("metrics"), Mapping) else {}
283
+ model_self_hash_ok = str(model_payload.get("model_sha256")) == _canonical_payload_sha256(
284
+ model_payload, exclude=("model_sha256",)
285
+ )
286
+ heldout_integrity = bool(
287
+ test_payload.get("test_was_sealed_until_this_execution")
288
+ and test_payload.get("test_execution_is_one_time")
289
+ and model_self_hash_ok
290
+ and str(test_payload.get("model_sha256")) == str(model_payload.get("model_sha256"))
291
+ and str(test_payload.get("split_sha256")) == str(model_payload.get("split_sha256"))
292
+ and not test_seen_during_fit
293
+ )
294
+ promoted = bool(test_payload.get("performance_ranking_validated")) and bool(gates) and all(bool(v) for v in gates.values())
295
+ objective_ok = int(metrics.get("objective_mismatches", 1) or 0) == 0
296
+ accounting_ok = int(metrics.get("outcomes", 0) or 0) == int(metrics.get("expected_outcomes", -1) or -1) and int(metrics.get("worker_errors", 1) or 0) == 0
297
+ notes = (
298
+ "M27 selective absolute-saving tree evaluated on the one-time sealed 16-instance public/OOD test",
299
+ f"M25 opportunity validated: {opportunity_ok}",
300
+ f"M27 development gate passed: {dev_ok}",
301
+ f"M27 held-out promotion passed: {promoted}",
302
+ f"frozen model self-hash valid: {model_self_hash_ok}",
303
+ f"held-out policy/SBS: {metrics.get('policy_to_sbs')}",
304
+ f"held-out bootstrap upper: {(metrics.get('bootstrap_policy_to_sbs') or {}).get('high') if isinstance(metrics.get('bootstrap_policy_to_sbs'), Mapping) else None}",
305
+ "M27 test is consumed; post-test retuning requires a new untouched cohort",
306
+ )
307
+ return ProductionEvidence(
308
+ evidence_class=EvidenceClass.COMPARATIVE_HELDOUT,
309
+ source=source,
310
+ corpus_integrity_passed=bool(test_payload.get("official_corpus_integrity_passed", False)),
311
+ outcome_accounting_passed=accounting_ok,
312
+ independent_validation_passed=objective_ok,
313
+ reference_crosscheck_passed=objective_ok,
314
+ comparative_backends=("scipy-highs-ds", "scipy-highs-ipm"),
315
+ heldout=heldout_integrity,
316
+ feature_cost_accounted=True,
317
+ # M27's consumed test payload predates explicit fixed-host capture in this runner.
318
+ # Never infer timing comparability from a same-session assumption. A future
319
+ # positive selector must carry explicit environment provenance in the payload.
320
+ fixed_environment=bool(test_payload.get("fixed_environment_provenance_passed", False)),
321
+ public_ood=bool(test_payload.get("public_ood_provenance_passed", True)),
322
+ pre_registered_policy=True,
323
+ selection_opportunity_validated=opportunity_ok,
324
+ performance_ranking_validated=bool(promoted and dev_ok and heldout_integrity and accounting_ok and objective_ok),
325
+ selector_name=str(model_payload.get("model_family") or "m27-selective-absolute-saving-tree"),
326
+ notes=notes,
327
+ )
328
+
329
+
330
+ def production_evidence_from_m28_native_choose(
331
+ payload: Mapping[str, object],
332
+ *,
333
+ source: str,
334
+ ) -> ProductionEvidence:
335
+ """Translate M28 native-choose baseline evidence.
336
+
337
+ M28 is deliberately *not* selector-authority evidence. It asks whether the
338
+ solver's own ``choose`` route already removes the DS-vs-IPM portfolio gap on a
339
+ fresh public/OOD cohort. Even a strong native baseline would not validate an
340
+ SolverPilot learned ranking policy. In the verified M28 environment, ``choose``
341
+ did not exercise IPM on nontrivial solves and did not close the pre-registered
342
+ fraction of the forced-simplex/IPM VBS gap.
343
+ """
344
+ metrics = payload.get("metrics") if isinstance(payload.get("metrics"), Mapping) else {}
345
+ gates = payload.get("pre_registered_gates") if isinstance(payload.get("pre_registered_gates"), Mapping) else {}
346
+ gap = float(metrics.get("forced_sbs_to_vbs_relative_gap", 0.0) or 0.0)
347
+ choose_diag = metrics.get("choose_algorithm_diagnostics") if isinstance(metrics.get("choose_algorithm_diagnostics"), Mapping) else {}
348
+ opportunity_ok = gap >= 0.03 and int(metrics.get("objective_mismatch_instances", 1) or 0) == 0
349
+ corpus_ok = bool(gates.get("official_corpus_integrity")) and bool(gates.get("fresh_48_unique_zero_prior_overlap"))
350
+ accounting_ok = bool(gates.get("complete_three_round_accounting")) and bool(gates.get("single_fixed_host_and_runner_provenance"))
351
+ validation_ok = bool(gates.get("zero_independent_invalidity"))
352
+ objective_ok = bool(gates.get("zero_material_objective_mismatch"))
353
+ closes = bool(payload.get("native_choose_closes_portfolio_opportunity"))
354
+ notes = (
355
+ "M28 compared choose/simplex/ipm within one bundled HiGHS 1.10.0 C-API build on a fresh MIPLIB-derived OOD cohort",
356
+ f"forced SBS-to-VBS gap: {gap}",
357
+ f"native choose closes portfolio opportunity: {closes}",
358
+ f"choose simplex diagnostics: {choose_diag.get('simplex')}",
359
+ f"choose IPM diagnostics: {choose_diag.get('ipm')}",
360
+ "M28 never authorizes learned performance ranking; it is a baseline/semantics audit",
361
+ )
362
+ return ProductionEvidence(
363
+ evidence_class=EvidenceClass.COMPARATIVE_HELDOUT,
364
+ source=source,
365
+ corpus_integrity_passed=corpus_ok,
366
+ outcome_accounting_passed=accounting_ok,
367
+ independent_validation_passed=validation_ok,
368
+ reference_crosscheck_passed=objective_ok,
369
+ comparative_backends=(
370
+ "bundled-highs-capi:choose",
371
+ "bundled-highs-capi:simplex",
372
+ "bundled-highs-capi:ipm",
373
+ ),
374
+ heldout=True,
375
+ feature_cost_accounted=True,
376
+ fixed_environment=bool(gates.get("single_fixed_host_and_runner_provenance")),
377
+ public_ood=True,
378
+ pre_registered_policy=True,
379
+ selection_opportunity_validated=opportunity_ok,
380
+ performance_ranking_validated=False,
381
+ selector_name=None,
382
+ notes=notes,
383
+ )
384
+
385
+
386
+ def production_evidence_from_m29_value_audit(
387
+ payload: Mapping[str, object],
388
+ *,
389
+ source: str,
390
+ ) -> ProductionEvidence:
391
+ """Translate M29 value-of-information evidence conservatively.
392
+
393
+ M29 is explicitly a post-outcome feature-representation audit over the already
394
+ observed M25 and M28 cohorts. It can authorize at most a *future fresh-corpus
395
+ experiment*; it can never authorize production performance ranking itself.
396
+ When no feature family passes the pre-registered M30-authorization gate, the
397
+ learned LP-routing branch is considered closed for the 1.0 release line.
398
+ """
399
+ cohorts = payload.get("cohorts") if isinstance(payload.get("cohorts"), Mapping) else {}
400
+ families = payload.get("family_authorization") if isinstance(payload.get("family_authorization"), Mapping) else {}
401
+ authorized = payload.get("m30_authorized_families")
402
+ authorized_names = tuple(str(x) for x in authorized) if isinstance(authorized, list) else ()
403
+ m30_authorized = bool(payload.get("m30_authorized")) and bool(authorized_names)
404
+ overlap = int(cohorts.get("overlap", -1) or 0)
405
+ notes = (
406
+ "M29 is post-outcome representation discovery, not held-out promotion evidence",
407
+ f"M25/M28 cohort overlap: {overlap}",
408
+ f"M30 authorized feature families: {authorized_names}",
409
+ f"learned LP routing closes for 1.0 when M30 authorization is false: {not m30_authorized}",
410
+ f"audited cumulative families: {tuple(sorted(str(k) for k in families))}",
411
+ )
412
+ return ProductionEvidence(
413
+ evidence_class=EvidenceClass.COMPARATIVE_VALIDATION,
414
+ source=source,
415
+ corpus_integrity_passed=overlap == 0 and int(cohorts.get("m25", 0) or 0) == 48 and int(cohorts.get("m28", 0) or 0) == 48,
416
+ outcome_accounting_passed=True,
417
+ independent_validation_passed=True,
418
+ reference_crosscheck_passed=True,
419
+ comparative_backends=("highs-simplex", "highs-ipm"),
420
+ heldout=False,
421
+ feature_cost_accounted=True,
422
+ fixed_environment=False,
423
+ public_ood=True,
424
+ pre_registered_policy=False,
425
+ selection_opportunity_validated=bool(payload.get("selection_opportunity_context_validated", False)),
426
+ performance_ranking_validated=False,
427
+ selector_name=None,
428
+ notes=notes,
429
+ )
430
+
431
+ def plan_production_solve(
432
+ problem: LinearProblem | QuadraticProblem,
433
+ registry: BackendRegistry,
434
+ *,
435
+ evidence: ProductionEvidence = M22_OFFICIAL_EVIDENCE,
436
+ intent: SolveIntent | str = SolveIntent.BALANCED,
437
+ budget: SolveBudget | None = None,
438
+ fingerprint: ProblemFingerprint | None = None,
439
+ context: PlannerContext | None = None,
440
+ health_reports: Iterable[BackendHealthReport] | None = None,
441
+ health_policy: HealthPolicy | str = HealthPolicy.PREFER_HEALTHY,
442
+ performance_policy: PerformancePolicy | str = PerformancePolicy.REQUIRE_COMPARATIVE,
443
+ performance_override: Mapping[str, str] | None = None,
444
+ ) -> ProductionDecision:
445
+ """Create a proof-safe, evidence-aware production decision.
446
+
447
+ M23 deliberately separates *correctness/corpus evidence* from *comparative
448
+ performance evidence*. M22 official evidence is strong enough to authorize the
449
+ conservative runtime baselines, but not strong enough to rank competing solvers.
450
+ """
451
+ intent = SolveIntent(intent)
452
+ performance_policy = PerformancePolicy(performance_policy)
453
+ fingerprint = inspect_problem(problem) if fingerprint is None else fingerprint
454
+ baseline = _conservative_baseline(problem, registry)
455
+ rationale: list[str] = [
456
+ f"evidence class: {evidence.evidence_class.value}",
457
+ f"evidence source: {evidence.source}",
458
+ ]
459
+ override_rejection: str | None = None
460
+ enable_perf = evidence.supports_performance_ranking and performance_policy is not PerformancePolicy.CONSERVATIVE
461
+
462
+ chosen_override: str | None = None
463
+ if performance_override:
464
+ family = fingerprint.problem_class
465
+ requested = performance_override.get(family)
466
+ if requested:
467
+ if performance_policy is PerformancePolicy.CONSERVATIVE:
468
+ override_rejection = "performance override disabled by conservative policy"
469
+ elif not evidence.supports_performance_ranking:
470
+ override_rejection = (
471
+ "performance override rejected: evidence is not comparative held-out evidence "
472
+ "with feature-cost, fixed-environment, public/OOD, preregistration, and successful promotion accounting"
473
+ )
474
+ elif requested not in _backend_names(registry):
475
+ override_rejection = f"performance override backend unavailable: {requested}"
476
+ else:
477
+ chosen_override = requested
478
+ rationale.append(f"accepted comparative performance override for {family}: {requested}")
479
+
480
+ if chosen_override is not None:
481
+ # Explicitly ask the capability planner to validate the selected backend by
482
+ # temporarily constructing the ordinary plan and ensuring the requested route
483
+ # appears among eligible candidates. We never bypass capability/intent gates.
484
+ ordinary = plan_solve(
485
+ problem,
486
+ registry,
487
+ intent=intent,
488
+ budget=budget,
489
+ fingerprint=fingerprint,
490
+ context=context,
491
+ health_reports=health_reports,
492
+ health_policy=health_policy,
493
+ )
494
+ eligible = {c.backend for c in ordinary.candidates}
495
+ if chosen_override not in eligible:
496
+ override_rejection = f"performance override failed capability/intent gate: {chosen_override}"
497
+ chosen_override = None
498
+ else:
499
+ selected = next(c for c in ordinary.candidates if c.backend == chosen_override)
500
+ reordered = (selected,) + tuple(c for c in ordinary.candidates if c.backend != chosen_override)
501
+ plan = SolvePlan(
502
+ selected_backend=chosen_override,
503
+ candidates=reordered,
504
+ intent=ordinary.intent,
505
+ budget=ordinary.budget,
506
+ fingerprint=ordinary.fingerprint,
507
+ strategy="evidence_performance_override",
508
+ rationale=ordinary.rationale + ("M23 comparative override passed all hard gates",),
509
+ evidence_level="comparative_heldout",
510
+ health_policy=ordinary.health_policy,
511
+ )
512
+ return ProductionDecision(
513
+ plan=plan,
514
+ auto_performance_ranking_enabled=True,
515
+ evidence=evidence,
516
+ conservative_baseline=baseline,
517
+ rationale=tuple(rationale),
518
+ rejected_performance_override_reason=None,
519
+ )
520
+
521
+ # Without comparative evidence, never performance-rank. We can still prefer a
522
+ # conservative backend family baseline, but only if the ordinary planner says it
523
+ # is compatible with all capability/intent/health requirements.
524
+ ordinary = plan_solve(
525
+ problem,
526
+ registry,
527
+ intent=intent,
528
+ budget=budget,
529
+ fingerprint=fingerprint,
530
+ context=context,
531
+ health_reports=health_reports,
532
+ health_policy=health_policy,
533
+ )
534
+ selected_backend = ordinary.selected_backend
535
+ if baseline is not None:
536
+ eligible = {c.backend for c in ordinary.candidates}
537
+ if baseline in eligible:
538
+ selected_backend = baseline
539
+ selected = next(c for c in ordinary.candidates if c.backend == baseline)
540
+ candidates = (selected,) + tuple(c for c in ordinary.candidates if c.backend != baseline)
541
+ rationale.append(f"conservative baseline selected for {fingerprint.problem_class}: {baseline}")
542
+ else:
543
+ candidates = ordinary.candidates
544
+ rationale.append(f"conservative baseline {baseline} failed a hard capability/intent/health gate")
545
+ else:
546
+ candidates = ordinary.candidates
547
+ rationale.append("no M23 family baseline available; retained capability planner selection")
548
+
549
+ if evidence.evidence_class is EvidenceClass.CORPUS_VALIDATED:
550
+ rationale.append("corpus evidence authorizes correctness-oriented production baseline, not solver-speed ranking")
551
+ if override_rejection:
552
+ rationale.append(override_rejection)
553
+
554
+ plan = SolvePlan(
555
+ selected_backend=selected_backend,
556
+ candidates=candidates,
557
+ intent=ordinary.intent,
558
+ budget=ordinary.budget,
559
+ fingerprint=ordinary.fingerprint,
560
+ strategy="production_conservative",
561
+ rationale=ordinary.rationale + tuple(rationale),
562
+ evidence_level=evidence.evidence_class.value,
563
+ health_policy=ordinary.health_policy,
564
+ )
565
+ return ProductionDecision(
566
+ plan=plan,
567
+ auto_performance_ranking_enabled=enable_perf,
568
+ evidence=evidence,
569
+ conservative_baseline=baseline,
570
+ rationale=tuple(rationale),
571
+ rejected_performance_override_reason=override_rejection,
572
+ )
573
+
574
+
575
+ def production_evidence_from_m22_gate(payload: Mapping[str, object], *, source: str = "M22 gate JSON") -> ProductionEvidence:
576
+ """Convert a verified M22 finalization payload into M23 planner evidence.
577
+
578
+ This parser is deliberately conservative. A passed M22 gate proves corpus identity,
579
+ outcome accounting and selected solution/reference checks. It does not become
580
+ comparative performance evidence unless the payload explicitly carries a separate
581
+ comparative held-out contract (which M22 does not).
582
+ """
583
+ gate_passed = payload.get("gate_passed") is True
584
+ integrity = payload.get("integrity") if isinstance(payload.get("integrity"), Mapping) else {}
585
+ protocol = payload.get("protocol") if isinstance(payload.get("protocol"), Mapping) else {}
586
+ summary = payload.get("campaign_summary") if isinstance(payload.get("campaign_summary"), Mapping) else {}
587
+ ref = payload.get("reference_crosscheck") if isinstance(payload.get("reference_crosscheck"), Mapping) else {}
588
+ integrity_ok = bool(
589
+ gate_passed
590
+ and integrity.get("miplib_sha256_match") is True
591
+ and integrity.get("qplib_sha256_match") is True
592
+ and integrity.get("pace_official_sha1_match") is True
593
+ )
594
+ outcome_ok = bool(gate_passed and protocol.get("missing_outcomes_allowed") is False)
595
+ validation_ok = bool(
596
+ gate_passed
597
+ and isinstance(summary.get("pace"), Mapping)
598
+ and summary["pace"].get("invalid_solutions", 1) == 0
599
+ and all(
600
+ isinstance(summary.get(name), Mapping) and summary[name].get("read_or_worker_errors", 1) == 0
601
+ for name in ("miplib", "qplib", "pace")
602
+ )
603
+ )
604
+ ref_ok = bool(
605
+ gate_passed
606
+ and isinstance(ref.get("miplib"), Mapping)
607
+ and ref["miplib"].get("reference_match") is True
608
+ and isinstance(ref.get("qplib"), Mapping)
609
+ and ref["qplib"].get("meets_or_beats_best_known") is True
610
+ )
611
+ evidence_class = EvidenceClass.CORPUS_VALIDATED if all((integrity_ok, outcome_ok, validation_ok, ref_ok)) else EvidenceClass.CAPABILITY
612
+ return ProductionEvidence(
613
+ evidence_class=evidence_class,
614
+ source=source,
615
+ corpus_integrity_passed=integrity_ok,
616
+ outcome_accounting_passed=outcome_ok,
617
+ independent_validation_passed=validation_ok,
618
+ reference_crosscheck_passed=ref_ok,
619
+ comparative_backends=(),
620
+ heldout=False,
621
+ feature_cost_accounted=False,
622
+ fixed_environment=bool(gate_passed and isinstance(payload.get("fixed_host"), Mapping)),
623
+ notes=(
624
+ "M22 official gate parsed into M23 evidence",
625
+ "no comparative multi-backend held-out performance contract present",
626
+ ),
627
+ )