betterwithage commited on
Commit
0b47137
·
verified ·
1 Parent(s): 638a721

chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)

Browse files

Automated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): Dockerfile, fundamental_limits.py, nav_coasting.py, pnt_resilience.py, quantum_sensing_limits.py, serve.py, szl_pnt_mesh.py
Deleted (gone from the repo + Dockerfile COPY set): (none)

Keeps the Space-built backend (serve.py + the Dockerfile-COPY'd .py
modules) identical to GitHub main so the Space never rebuilds from a
stale backend, new endpoints don't 404 there, and orphaned modules
removed from the repo don't linger in the Space tree.

Files changed (7) hide show
  1. Dockerfile +5 -0
  2. fundamental_limits.py +606 -0
  3. nav_coasting.py +696 -0
  4. pnt_resilience.py +558 -0
  5. quantum_sensing_limits.py +614 -0
  6. serve.py +14 -0
  7. szl_pnt_mesh.py +510 -0
Dockerfile CHANGED
@@ -108,6 +108,11 @@ COPY a11oy_factory.py a11oy_constitution.py a11oy_nav_wireup.py ./
108
  # module honestly serves a SAMPLE certificate until Forge writes real ones on the box.
109
  COPY szl_pinn_bounds.py ./
110
  COPY physical_bounds_certificate.json agentic_decision_trail.json physical_bounds_certificate.dsse.json ./
 
 
 
 
 
111
  # ADDITIVE (I4 gpu-quant): Sovereign VRAM-resident GPU-Quant engine (PCA-Risk / TDA-Fracture
112
  # / HJB-Kelly) backing /api/a11oy/v1/quant/* + the /quant tab. PURE-STDLIB (Jacobi eigen,
113
  # Gaussian solve, union-find Betti) so it runs in the numpy-less HF image; cuML/giotto-tda
 
108
  # module honestly serves a SAMPLE certificate until Forge writes real ones on the box.
109
  COPY szl_pinn_bounds.py ./
110
  COPY physical_bounds_certificate.json agentic_decision_trail.json physical_bounds_certificate.dsse.json ./
111
+ # PNT / quantum-sensing mesh (pure-stdlib closed-form web path; serves /api/a11oy/v1/pnt/*).
112
+ # szl_pnt_mesh.py loads the 4 engine modules dynamically via importlib, so ALL FIVE MUST be
113
+ # COPY'd or serve.py's guarded import falls back to a stub (merged-but-not-live) in the HF
114
+ # image. Heavy numpy/UKF/PINN solves are the Forge/GPU path; this web path never solves.
115
+ COPY szl_pnt_mesh.py quantum_sensing_limits.py pnt_resilience.py nav_coasting.py fundamental_limits.py ./
116
  # ADDITIVE (I4 gpu-quant): Sovereign VRAM-resident GPU-Quant engine (PCA-Risk / TDA-Fracture
117
  # / HJB-Kelly) backing /api/a11oy/v1/quant/* + the /quant tab. PURE-STDLIB (Jacobi eigen,
118
  # Gaussian solve, union-find Betti) so it runs in the numpy-less HF image; cuML/giotto-tda
fundamental_limits.py ADDED
@@ -0,0 +1,606 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Doctrine v11 LOCKED · Λ = Conjecture 1 (advisory, NOT proven trust)
3
+ # Sign-off: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
4
+ """fundamental_limits.py — the UNIFIED "fundamental-limits" library (SZL, clean-room).
5
+
6
+ ONE clean API wrapping the estate's TWO hard-physics pillars:
7
+
8
+ PILLAR A — COMPUTE BOUNDS (existing, on-metal-proven)
9
+ agentic_pinn/physics_bounds.py — Landauer (1961) / Margolus-Levitin (1998) /
10
+ Bremermann (1962) / Bekenstein (1981) / Bekenstein-Hawking (Hawking 1975).
11
+ The HONEST INVERSE of a free-energy claim: PROVE a real compute job sits FAR
12
+ BELOW the fundamental ceilings of physics. Energy DERIVED only from MEASURED
13
+ power × MEASURED time.
14
+
15
+ PILLAR B — QUANTUM-SENSING / PNT LIMITS (new, this build)
16
+ Re-derived clean-room from the kshana method + the original papers
17
+ (Kasevich-Chu 1991; Peters et al. 2001; Freier et al. 2016; Cheinet et al. 2008):
18
+ * Dev1 quantum_sensing_limits — cold-atom-interferometer (CAI) accelerometer
19
+ shot-noise / standard-quantum-limit sensitivity from k_eff, T, N, C.
20
+ * Dev2 pnt_resilience — fused multi-layer GNSS spoof detector verdict
21
+ (RAIM-consistency + AGC + SQM), deny-by-default.
22
+ * Dev3 nav_coasting — GPS-denied coasting figure-of-merit (position
23
+ error growth), classical IMU vs quantum CAI.
24
+
25
+ This module is a THIN unifying layer. It IMPORTS and WRAPS the sibling engines when
26
+ present; when a sibling is NOT yet wired it returns an HONEST, clearly-labelled
27
+ "module not wired yet" result — never a fabricated number, never a false green.
28
+
29
+ `certify(kind=...)` is the single entry point covering:
30
+ compute_bounds | quantum_sensor | pnt_resilience | nav_coasting
31
+
32
+ DOCTRINE v11 (HARD, never violated):
33
+ - NO free-energy / over-unity. The compute certificate is the honest INVERSE of a
34
+ free-energy claim; sensor limits are DERIVED from physics, never magic.
35
+ - Every result labelled MEASURED vs MODELED (vs SAMPLE). Honest "NOT MODELED" /
36
+ "module not wired yet" where physics is incomplete or a sibling engine is absent.
37
+ - Established physics bounds are CITED, not claimed as SZL's. Clean-room.
38
+ - Λ = Conjecture 1 (advisory governance gate, deny-by-default). NEVER "proven trust".
39
+ - Pure-stdlib where possible. The full numpy/heavy solves are the Forge/GPU path;
40
+ this layer aggregates and re-certifies, it does not block on heavy compute.
41
+ """
42
+ from __future__ import annotations
43
+
44
+ import importlib
45
+ import math
46
+ import os
47
+ import sys
48
+ from typing import Any, Optional
49
+
50
+ # --------------------------------------------------------------------------- #
51
+ # Doctrine constants carried by EVERY result #
52
+ # --------------------------------------------------------------------------- #
53
+ DOCTRINE = (
54
+ "v11 LOCKED: NO free-energy/over-unity (compute certificate is the honest INVERSE; "
55
+ "sensor limits DERIVED from physics); MEASURED vs MODELED vs SAMPLE labels on every "
56
+ "result; honest 'NOT MODELED'/'module not wired yet' where physics is incomplete; "
57
+ "established bounds CITED not claimed as SZL's; clean-room (re-derived from papers, "
58
+ "kshana cited not copied); Λ=Conjecture 1 (advisory, deny-by-default, never 'proven "
59
+ "trust'); sovereign own-metal; no fabricated numbers."
60
+ )
61
+
62
+ LAMBDA_NOTE = (
63
+ "Λ = Conjecture 1 (advisory governance gate). ALLOW = 'passed SZL admission policy', "
64
+ "NEVER 'proven trust'. Deny-by-default. This library states physical FACTS/BOUNDS, "
65
+ "not trust."
66
+ )
67
+
68
+ # The honest-inverse-of-free-energy invariant is preserved across the unified surface.
69
+ HONEST_INVERSE_OF_FREE_ENERGY = True
70
+
71
+ LABELS = {
72
+ "MEASURED": "observed from a real exporter (e.g. NVML) or honestly-labelled sample",
73
+ "MODELED": "computed from first-principles physics formulas (CITED), not a live measurement",
74
+ "SAMPLE": "an honestly-labelled placeholder input — clearly NOT a measured value",
75
+ "NOT_MODELED": "physics is incomplete / out of validated regime — no number asserted",
76
+ }
77
+
78
+ KINDS = ("compute_bounds", "quantum_sensor", "pnt_resilience", "nav_coasting")
79
+
80
+ # Physics lineage cited across the sensing pillar (clean-room, method-only).
81
+ SENSING_ATTRIBUTION = {
82
+ "kasevich_chu_1991": (
83
+ "Kasevich, M. & Chu, S. (1991), 'Atomic interferometry using stimulated Raman "
84
+ "transitions', Phys. Rev. Lett. 67(2):181, doi:10.1103/PhysRevLett.67.181."
85
+ ),
86
+ "peters_2001": (
87
+ "Peters, A., Chung, K.Y. & Chu, S. (2001), 'High-precision gravity measurements "
88
+ "using atom interferometry', Metrologia 38(1):25, doi:10.1088/0026-1394/38/1/4."
89
+ ),
90
+ "freier_2016": (
91
+ "Freier, C. et al. (2016), 'Mobile quantum gravity sensor with unprecedented "
92
+ "stability', J. Phys. Conf. Ser. 723:012050, doi:10.1088/1742-6596/723/1/012050."
93
+ ),
94
+ "cheinet_2008": (
95
+ "Cheinet, P. et al. (2008), 'Measurement of the sensitivity function in a "
96
+ "time-domain atomic interferometer', IEEE Trans. Instrum. Meas. 57(6):1141, "
97
+ "doi:10.1109/TIM.2007.915148."
98
+ ),
99
+ "kshana": (
100
+ "AshfordeOU/kshana (Apache-2.0, DOI 10.5281/zenodo.20528627) — PNT-resilience "
101
+ "simulator. Method & physics studied and CITED; re-derived clean-room in SZL "
102
+ "Python. No verbatim code copied."
103
+ ),
104
+ "honesty": (
105
+ "Sensor limits are DERIVED from established physics (shot-noise / standard "
106
+ "quantum limit), labelled MODELED. NO free-energy claim. Clean-room."
107
+ ),
108
+ }
109
+
110
+
111
+ # --------------------------------------------------------------------------- #
112
+ # Sibling-engine resolution — tolerate missing modules GRACEFULLY #
113
+ # --------------------------------------------------------------------------- #
114
+ # Map each kind to its candidate sibling-engine module names and the entry the
115
+ # unified layer expects. Resolution searches sys.path AND the conventional dev
116
+ # sibling directories under pnt_build/. Missing → honest "module not wired yet".
117
+ _THIS_DIR = os.path.dirname(os.path.abspath(__file__))
118
+ _PNT_BUILD = os.path.dirname(_THIS_DIR) # .../pnt_build
119
+
120
+ # Make sibling dev dirs importable WITHOUT mutating global state permanently:
121
+ # we add them lazily inside the resolver and remember which we added.
122
+ _SIBLING_DIRS = {
123
+ "compute_bounds": [
124
+ os.path.join(os.path.dirname(_PNT_BUILD), "agentic_pinn"),
125
+ ],
126
+ "quantum_sensor": [os.path.join(_PNT_BUILD, "dev1_quantum_sensors")],
127
+ "pnt_resilience": [os.path.join(_PNT_BUILD, "dev2_spoof_sda")],
128
+ "nav_coasting": [os.path.join(_PNT_BUILD, "dev3_fusion_pinn")],
129
+ }
130
+
131
+ # Candidate module names per kind (first importable wins).
132
+ _MODULE_CANDIDATES = {
133
+ "compute_bounds": ["physics_bounds"],
134
+ "quantum_sensor": ["quantum_sensing_limits", "quantum_imu", "dev1_quantum_sensing_limits"],
135
+ "pnt_resilience": ["pnt_resilience", "spoof_detect", "dev2_pnt_resilience"],
136
+ "nav_coasting": ["nav_coasting", "coasting", "dev3_nav_coasting"],
137
+ }
138
+
139
+
140
+ def _ensure_on_path(kind: str) -> None:
141
+ for d in _SIBLING_DIRS.get(kind, []):
142
+ if os.path.isdir(d) and d not in sys.path:
143
+ sys.path.insert(0, d)
144
+
145
+
146
+ def _try_import(kind: str):
147
+ """Return (module, module_name) for the first importable candidate, else (None, None)."""
148
+ _ensure_on_path(kind)
149
+ for name in _MODULE_CANDIDATES.get(kind, []):
150
+ try:
151
+ mod = importlib.import_module(name)
152
+ return mod, name
153
+ except Exception:
154
+ continue
155
+ return None, None
156
+
157
+
158
+ def _wired_status(kind: str) -> dict:
159
+ mod, name = _try_import(kind)
160
+ return {
161
+ "kind": kind,
162
+ "wired": mod is not None,
163
+ "module": name,
164
+ "note": (f"sibling engine '{name}' is present and importable"
165
+ if mod is not None else
166
+ "module not wired yet — honest placeholder; no number fabricated"),
167
+ }
168
+
169
+
170
+ def status() -> dict:
171
+ """Report which pillars/engines are wired (honest discovery, no fabrication)."""
172
+ return {
173
+ "library": "szl/fundamental-limits/v1",
174
+ "pillars": {
175
+ "compute_bounds": _wired_status("compute_bounds"),
176
+ "quantum_sensor": _wired_status("quantum_sensor"),
177
+ "pnt_resilience": _wired_status("pnt_resilience"),
178
+ "nav_coasting": _wired_status("nav_coasting"),
179
+ },
180
+ "kinds": list(KINDS),
181
+ "doctrine": DOCTRINE,
182
+ "lambda_note": LAMBDA_NOTE,
183
+ "honest_inverse_of_free_energy": HONEST_INVERSE_OF_FREE_ENERGY,
184
+ "labels": LABELS,
185
+ "attribution": {"sensing": SENSING_ATTRIBUTION},
186
+ }
187
+
188
+
189
+ # --------------------------------------------------------------------------- #
190
+ # Honest "module not wired yet" envelope #
191
+ # --------------------------------------------------------------------------- #
192
+ def _not_wired(kind: str, extra: Optional[dict] = None) -> dict:
193
+ out = {
194
+ "kind": kind,
195
+ "status": "MODULE_NOT_WIRED",
196
+ "label": "NOT_MODELED",
197
+ "wired": False,
198
+ "result": None,
199
+ "note": (f"The '{kind}' sibling engine is not present in this environment. "
200
+ "Returning an HONEST placeholder — no number is fabricated, no false "
201
+ "green. Wire the Dev sibling module to activate this kind."),
202
+ "doctrine": DOCTRINE,
203
+ "lambda_note": LAMBDA_NOTE,
204
+ "honest_inverse_of_free_energy": HONEST_INVERSE_OF_FREE_ENERGY,
205
+ "labels": LABELS,
206
+ }
207
+ if extra:
208
+ out.update(extra)
209
+ return out
210
+
211
+
212
+ def _envelope(kind: str, label: str, result: dict, *, source: str,
213
+ attribution: Optional[dict] = None, extra: Optional[dict] = None) -> dict:
214
+ out = {
215
+ "kind": kind,
216
+ "status": "OK",
217
+ "label": label, # MEASURED | MODELED | SAMPLE
218
+ "wired": True,
219
+ "source": source,
220
+ "result": result,
221
+ "doctrine": DOCTRINE,
222
+ "lambda_note": LAMBDA_NOTE,
223
+ "honest_inverse_of_free_energy": HONEST_INVERSE_OF_FREE_ENERGY,
224
+ "labels": LABELS,
225
+ }
226
+ if attribution:
227
+ out["attribution"] = attribution
228
+ if extra:
229
+ out.update(extra)
230
+ return out
231
+
232
+
233
+ # --------------------------------------------------------------------------- #
234
+ # PILLAR A — compute bounds (wraps physics_bounds.py) #
235
+ # --------------------------------------------------------------------------- #
236
+ def _certify_compute_bounds(**kw) -> dict:
237
+ mod, name = _try_import("compute_bounds")
238
+ if mod is None:
239
+ return _not_wired("compute_bounds")
240
+ # physics_bounds.py exposes MeasuredJob + certify(job) -> PhysicalBoundsCertificate.
241
+ MeasuredJob = getattr(mod, "MeasuredJob", None)
242
+ certify_fn = getattr(mod, "certify", None)
243
+ if MeasuredJob is None or certify_fn is None:
244
+ return _not_wired("compute_bounds", {
245
+ "note": (f"sibling '{name}' present but missing MeasuredJob/certify — honest "
246
+ "incompatible-engine state, no number fabricated"),
247
+ })
248
+ # Honest SAMPLE defaults (mirror nvml_hook.sample_job); caller may override.
249
+ defaults = dict(
250
+ avg_power_w=700.0, wall_time_s=10.0, temperature_k=350.0,
251
+ bit_operations=1e16, bits_erased=1e14, info_content_bits=1e12,
252
+ device_mass_kg=2.0, device_radius_m=0.15,
253
+ label="SAMPLE", source="fundamental_limits-sample",
254
+ note="In-sandbox SAMPLE; on metal Forge feeds REAL NVML readings.",
255
+ )
256
+ defaults.update({k: v for k, v in kw.items() if k in defaults})
257
+ job = MeasuredJob(**defaults)
258
+ cert = certify_fn(job)
259
+ # Normalise to a dict regardless of dataclass vs dict.
260
+ if hasattr(cert, "__dict__") and not isinstance(cert, dict):
261
+ try:
262
+ from dataclasses import asdict
263
+ cert_d = asdict(cert)
264
+ except Exception:
265
+ cert_d = {k: getattr(cert, k) for k in dir(cert) if not k.startswith("_")}
266
+ else:
267
+ cert_d = cert
268
+ label = "MEASURED" if defaults.get("label") == "MEASURED" else "SAMPLE"
269
+ return _envelope(
270
+ "compute_bounds", label, cert_d,
271
+ source=f"physics_bounds.certify (engine: {name})",
272
+ attribution=getattr(mod, "BOUNDS_ATTRIBUTION", None),
273
+ extra={"physically_bounded": cert_d.get("physically_bounded")},
274
+ )
275
+
276
+
277
+ # --------------------------------------------------------------------------- #
278
+ # PILLAR B helpers — local clean-room CAI physics (used only when Dev1 absent) #
279
+ # These mirror the kshana method exactly so the unified surface still answers #
280
+ # honestly (MODELED) before the sibling engine lands. NOT a fabricated number; #
281
+ # it is a CITED first-principles derivation. #
282
+ # --------------------------------------------------------------------------- #
283
+ def _cai_sensor_limit(lambda_m: float, interrogation_time_s: float,
284
+ atom_number: float, contrast: float,
285
+ cycle_time_s: float) -> dict:
286
+ """Standard-quantum-limit CAI accelerometer sensitivity (MODELED, clean-room).
287
+
288
+ k_eff = 4π/λ ; Mach-Zehnder phase Φ = k_eff·a·T² ; shot noise σ_Φ = 1/(C·√N) ;
289
+ per-shot accel sensitivity σ_a = σ_Φ/(k_eff·T²) ; ASD n_a = σ_a·√T_c.
290
+ Lineage: Kasevich-Chu 1991, Peters 2001, Freier 2016, Cheinet 2008.
291
+ """
292
+ k_eff = 4.0 * math.pi / lambda_m
293
+ sigma_phi = 1.0 / (contrast * math.sqrt(atom_number)) if (contrast > 0 and atom_number > 0) else float("inf")
294
+ denom = k_eff * interrogation_time_s ** 2
295
+ sigma_a = (sigma_phi / denom) if denom > 0 else float("inf")
296
+ asd_a = sigma_a * math.sqrt(cycle_time_s) if cycle_time_s > 0 else float("inf")
297
+ return {
298
+ "k_eff_per_m": k_eff,
299
+ "shot_noise_phase_rad": sigma_phi,
300
+ "per_shot_accel_sensitivity_m_s2": sigma_a,
301
+ "accel_asd_m_s2_per_sqrt_hz": asd_a,
302
+ "inputs": {
303
+ "laser_wavelength_m": lambda_m,
304
+ "interrogation_time_s": interrogation_time_s,
305
+ "atom_number": atom_number,
306
+ "contrast": contrast,
307
+ "cycle_time_s": cycle_time_s,
308
+ },
309
+ "formulas": {
310
+ "k_eff": "k_eff = 4*pi/lambda",
311
+ "mach_zehnder_phase": "Phi = k_eff * a * T^2",
312
+ "shot_noise": "sigma_Phi = 1/(C*sqrt(N)) (standard quantum limit)",
313
+ "per_shot_accel": "sigma_a = sigma_Phi/(k_eff*T^2)",
314
+ "asd": "n_a = sigma_a*sqrt(T_c)",
315
+ },
316
+ }
317
+
318
+
319
+ def _to_dict(obj):
320
+ """Normalise a dataclass/obj/dict to a plain dict for JSON envelopes."""
321
+ if isinstance(obj, dict):
322
+ return obj
323
+ try:
324
+ from dataclasses import asdict, is_dataclass
325
+ if is_dataclass(obj):
326
+ return asdict(obj)
327
+ except Exception:
328
+ pass
329
+ if hasattr(obj, "__dict__"):
330
+ return {k: v for k, v in vars(obj).items() if not k.startswith("_")}
331
+ return {"value": obj}
332
+
333
+
334
+ def _certify_quantum_sensor(**kw) -> dict:
335
+ mod, name = _try_import("quantum_sensor")
336
+ # Prefer Dev1 engine: certify_sensor(MeasuredSensor) -> QuantumSensingCertificate.
337
+ if mod is not None:
338
+ certify_sensor = getattr(mod, "certify_sensor", None)
339
+ MeasuredSensor = getattr(mod, "MeasuredSensor", None)
340
+ honest_sample = getattr(mod, "honest_sample_sensor", None)
341
+ if callable(certify_sensor) and MeasuredSensor is not None:
342
+ try:
343
+ if kw:
344
+ # Map our generic kwargs onto Dev1's MeasuredSensor field names.
345
+ field_map = {
346
+ "lambda_m": "wavelength_m", "wavelength_m": "wavelength_m",
347
+ "interrogation_time_s": "interrogation_time_s",
348
+ "atom_number": "atom_number", "contrast": "contrast",
349
+ "cycle_time_s": "cycle_time_s", "accel_psd": "accel_psd",
350
+ }
351
+ base = honest_sample() if callable(honest_sample) else None
352
+ defaults = _to_dict(base) if base is not None else {}
353
+ sensor_kw = {}
354
+ valid = getattr(MeasuredSensor, "__dataclass_fields__", {})
355
+ for k, v in defaults.items():
356
+ if k in valid:
357
+ sensor_kw[k] = v
358
+ for k, v in kw.items():
359
+ tgt = field_map.get(k)
360
+ if tgt and tgt in valid:
361
+ sensor_kw[tgt] = float(v)
362
+ sensor_kw["label"] = "SAMPLE"
363
+ sensor_kw["source"] = "fundamental_limits-query"
364
+ sensor = MeasuredSensor(**sensor_kw)
365
+ else:
366
+ sensor = honest_sample() if callable(honest_sample) else MeasuredSensor(
367
+ wavelength_m=780e-9, interrogation_time_s=0.1, atom_number=1e6,
368
+ contrast=0.5, cycle_time_s=0.5, accel_psd=1e-8, label="SAMPLE",
369
+ source="fundamental_limits-sample")
370
+ cert = certify_sensor(sensor, strict=False) if "strict" in getattr(
371
+ certify_sensor, "__code__", type("x", (), {"co_varnames": ()})).co_varnames \
372
+ else certify_sensor(sensor)
373
+ return _envelope("quantum_sensor", "MODELED", _to_dict(cert),
374
+ source=f"{name}.certify_sensor (Dev1 engine)",
375
+ attribution=SENSING_ATTRIBUTION)
376
+ except Exception as e:
377
+ # Fall through to clean-room fallback, but record why.
378
+ kw = dict(kw)
379
+ kw["_dev1_error"] = repr(e)
380
+ # Older/other entry shapes:
381
+ for entry in ("certify", "sensor_limit", "cai_limit", "compute"):
382
+ fn = getattr(mod, entry, None)
383
+ if callable(fn):
384
+ try:
385
+ res = fn(**{k: v for k, v in kw.items() if not k.startswith("_")})
386
+ return _envelope("quantum_sensor", "MODELED", _to_dict(res),
387
+ source=f"{name}.{entry} (Dev1 engine)",
388
+ attribution=SENSING_ATTRIBUTION)
389
+ except Exception:
390
+ continue
391
+ # Honest fallback: local clean-room CAI derivation (still MODELED, CITED).
392
+ p = dict(lambda_m=780e-9, interrogation_time_s=0.1, atom_number=1e6,
393
+ contrast=0.5, cycle_time_s=0.5)
394
+ p.update({k: float(v) for k, v in kw.items() if k in p})
395
+ kw = {k: v for k, v in kw.items() if not str(k).startswith("_")}
396
+ res = _cai_sensor_limit(**p)
397
+ note = ("Computed by the unified layer's own clean-room CAI derivation because the "
398
+ "Dev1 'quantum_sensing_limits' engine is not wired yet. MODELED first-principles "
399
+ "physics (CITED), NOT a fabricated number." if mod is None else
400
+ "Dev1 engine present but exposed no compatible entry; used clean-room fallback.")
401
+ return _envelope("quantum_sensor", "MODELED", res,
402
+ source="fundamental_limits clean-room CAI fallback",
403
+ attribution=SENSING_ATTRIBUTION, extra={"fallback_note": note})
404
+
405
+
406
+ def _certify_pnt_resilience(**kw) -> dict:
407
+ mod, name = _try_import("pnt_resilience")
408
+ if mod is not None:
409
+ # Dev2 engine: detect(PntObservables)->SpoofVerdict, or assess_scenario(name).
410
+ try:
411
+ scenario = kw.get("scenario")
412
+ lib = getattr(mod, "TEXBAT_LIBRARY", {})
413
+ assess = getattr(mod, "assess_scenario", None)
414
+ detect = getattr(mod, "detect", None)
415
+ PntObservables = getattr(mod, "PntObservables", None)
416
+ if scenario and callable(assess) and scenario in lib:
417
+ v = assess(lib[scenario], seed=int(kw.get("seed", 0)))
418
+ return _envelope("pnt_resilience", "MODELED", _to_dict(v),
419
+ source=f"{name}.assess_scenario (Dev2 engine, scenario={scenario})",
420
+ attribution=SENSING_ATTRIBUTION,
421
+ extra={"lambda_gate": "deny-by-default"})
422
+ if callable(detect) and PntObservables is not None and any(
423
+ k in kw for k in ("power_advantage_db", "sqm_early_minus_late",
424
+ "clock_bias_leap_m", "pr_residuals_m")):
425
+ import numpy as _np # heavy import isolated to the engine path
426
+ n_sv = int(kw.get("n_sv", 8))
427
+ resid = kw.get("pr_residuals_m")
428
+ if resid is None:
429
+ resid = _np.zeros(n_sv)
430
+ else:
431
+ resid = _np.asarray([float(x) for x in str(resid).split(",")], dtype=float)
432
+ obs = PntObservables(
433
+ pr_residuals_m=resid, n_sv=n_sv,
434
+ power_advantage_db=float(kw.get("power_advantage_db", 0.0)),
435
+ sqm_early_minus_late=float(kw.get("sqm_early_minus_late", 0.0)),
436
+ carrier_phase_aligned=str(kw.get("carrier_phase_aligned", "")).lower()
437
+ in ("1", "true", "yes"),
438
+ clock_bias_leap_m=float(kw.get("clock_bias_leap_m", 0.0)),
439
+ clock_drift_implied_m=float(kw.get("clock_drift_implied_m", 0.0)),
440
+ )
441
+ v = detect(obs)
442
+ return _envelope("pnt_resilience", "MODELED", _to_dict(v),
443
+ source=f"{name}.detect (Dev2 engine)",
444
+ attribution=SENSING_ATTRIBUTION,
445
+ extra={"lambda_gate": "deny-by-default"})
446
+ # No specific inputs: run the clean 'NOMINAL' baseline scenario honestly.
447
+ if callable(assess) and "clean" in lib:
448
+ v = assess(lib["clean"])
449
+ return _envelope("pnt_resilience", "MODELED", _to_dict(v),
450
+ source=f"{name}.assess_scenario (Dev2 engine, scenario=clean baseline)",
451
+ attribution=SENSING_ATTRIBUTION,
452
+ extra={"lambda_gate": "deny-by-default"})
453
+ except Exception:
454
+ pass # fall through to clean-room stdlib fusion
455
+ # Honest fallback: a transparent multi-layer monitor fusion (MODELED, deny-by-default).
456
+ # raim_consistency_m: pseudorange residual consistency (m); larger = more suspect.
457
+ # agc_db: automatic-gain-control level vs nominal (dB drop); larger drop = suspect.
458
+ # sqm_ratio: signal-quality-monitor early-late metric; deviation from 1 = suspect.
459
+ raim = float(kw.get("raim_consistency_m", 0.0))
460
+ agc = float(kw.get("agc_db", 0.0))
461
+ sqm = float(kw.get("sqm_ratio", 1.0))
462
+ raim_thr = float(kw.get("raim_threshold_m", 30.0))
463
+ agc_thr = float(kw.get("agc_threshold_db", 6.0))
464
+ sqm_dev_thr = float(kw.get("sqm_dev_threshold", 0.15))
465
+ flags = {
466
+ "raim_flag": raim > raim_thr,
467
+ "agc_flag": agc > agc_thr,
468
+ "sqm_flag": abs(sqm - 1.0) > sqm_dev_thr,
469
+ }
470
+ n_flags = sum(1 for v in flags.values() if v)
471
+ # Deny-by-default fusion: any single layer raises SUSPECT; >=2 raises SPOOF_LIKELY.
472
+ if n_flags >= 2:
473
+ verdict = "SPOOF_LIKELY"
474
+ elif n_flags == 1:
475
+ verdict = "SUSPECT"
476
+ else:
477
+ verdict = "NOMINAL"
478
+ res = {
479
+ "verdict": verdict,
480
+ "n_layers_flagged": n_flags,
481
+ "layers": flags,
482
+ "inputs": {"raim_consistency_m": raim, "agc_db": agc, "sqm_ratio": sqm},
483
+ "thresholds": {"raim_threshold_m": raim_thr, "agc_threshold_db": agc_thr,
484
+ "sqm_dev_threshold": sqm_dev_thr},
485
+ "fusion": ("multi-layer deny-by-default: >=2 layers -> SPOOF_LIKELY, "
486
+ "1 layer -> SUSPECT, 0 -> NOMINAL"),
487
+ }
488
+ note = ("Computed by the unified layer's clean-room monitor fusion because the Dev2 "
489
+ "'pnt_resilience' engine is not wired yet. MODELED, deny-by-default; the "
490
+ "verdict is advisory (Λ=Conjecture 1), never 'proven trust'."
491
+ if mod is None else
492
+ "Dev2 engine present but exposed no compatible entry; used clean-room fallback.")
493
+ return _envelope("pnt_resilience", "MODELED", res,
494
+ source="fundamental_limits clean-room spoof-fusion fallback",
495
+ attribution=SENSING_ATTRIBUTION,
496
+ extra={"lambda_gate": "deny-by-default", "fallback_note": note})
497
+
498
+
499
+ def _certify_nav_coasting(**kw) -> dict:
500
+ mod, name = _try_import("nav_coasting")
501
+ if mod is not None:
502
+ for entry in ("certify", "coast", "figure_of_merit", "fom", "coasting_fom"):
503
+ fn = getattr(mod, entry, None)
504
+ if callable(fn):
505
+ try:
506
+ clean = {k: v for k, v in kw.items() if not str(k).startswith("_")}
507
+ res = fn(**clean) if clean else fn()
508
+ return _envelope("nav_coasting", "MODELED", _to_dict(res),
509
+ source=f"{name}.{entry} (Dev3 engine)",
510
+ attribution=SENSING_ATTRIBUTION)
511
+ except Exception:
512
+ continue
513
+ # Honest fallback: position-error growth during GPS-denied coasting, classical vs
514
+ # quantum. Random-walk-dominated INS error from accel noise ASD n_a:
515
+ # position error sigma_x(t) ≈ n_a * t^(3/2) / sqrt(3) (double-integration of a
516
+ # white-acceleration-noise random walk; standard INS coasting scaling).
517
+ # We compare a classical MEMS/navigation-grade IMU ASD vs a quantum CAI ASD.
518
+ t = float(kw.get("coast_time_s", 60.0))
519
+ n_classical = float(kw.get("classical_asd_m_s2_per_sqrt_hz", 1e-3)) # nav-grade-ish
520
+ # quantum ASD: take from a default CAI derivation unless caller provides it.
521
+ if "quantum_asd_m_s2_per_sqrt_hz" in kw:
522
+ n_quantum = float(kw["quantum_asd_m_s2_per_sqrt_hz"])
523
+ else:
524
+ cai = _cai_sensor_limit(780e-9, 0.1, 1e6, 0.5, 0.5)
525
+ n_quantum = cai["accel_asd_m_s2_per_sqrt_hz"]
526
+
527
+ def pos_err(n_a: float) -> float:
528
+ return n_a * (t ** 1.5) / math.sqrt(3.0)
529
+
530
+ err_c = pos_err(n_classical)
531
+ err_q = pos_err(n_quantum)
532
+ improvement = (err_c / err_q) if err_q > 0 else float("inf")
533
+ res = {
534
+ "coast_time_s": t,
535
+ "classical": {
536
+ "accel_asd_m_s2_per_sqrt_hz": n_classical,
537
+ "position_error_m": err_c,
538
+ },
539
+ "quantum": {
540
+ "accel_asd_m_s2_per_sqrt_hz": n_quantum,
541
+ "position_error_m": err_q,
542
+ },
543
+ "quantum_over_classical_improvement_factor": improvement,
544
+ "model": ("GPS-denied coasting position-error growth from white-acceleration-noise "
545
+ "random walk: sigma_x(t) ~= n_a * t^1.5 / sqrt(3). MODELED scaling."),
546
+ }
547
+ note = ("Computed by the unified layer's clean-room coasting model because the Dev3 "
548
+ "'nav_coasting' engine is not wired yet. MODELED scaling, not a fabricated "
549
+ "number." if mod is None else
550
+ "Dev3 engine present but exposed no compatible entry; used clean-room fallback.")
551
+ return _envelope("nav_coasting", "MODELED", res,
552
+ source="fundamental_limits clean-room coasting fallback",
553
+ attribution=SENSING_ATTRIBUTION, extra={"fallback_note": note})
554
+
555
+
556
+ # --------------------------------------------------------------------------- #
557
+ # THE single unified entry point #
558
+ # --------------------------------------------------------------------------- #
559
+ _DISPATCH = {
560
+ "compute_bounds": _certify_compute_bounds,
561
+ "quantum_sensor": _certify_quantum_sensor,
562
+ "pnt_resilience": _certify_pnt_resilience,
563
+ "nav_coasting": _certify_nav_coasting,
564
+ }
565
+
566
+
567
+ def certify(kind: str, **kwargs) -> dict:
568
+ """Unified certify entry covering both pillars.
569
+
570
+ kind ∈ {compute_bounds, quantum_sensor, pnt_resilience, nav_coasting}.
571
+
572
+ Wraps the relevant sibling engine when present; otherwise returns an honest,
573
+ clearly-labelled clean-room MODELED result (sensing pillar) or a MODULE_NOT_WIRED
574
+ placeholder (compute pillar, which has no safe local stand-in here). NEVER fabricates
575
+ a number and NEVER emits a false green. Every result carries the doctrine, the
576
+ Λ-advisory note, and the honest-inverse-of-free-energy invariant.
577
+ """
578
+ fn = _DISPATCH.get(kind)
579
+ if fn is None:
580
+ return {
581
+ "kind": kind,
582
+ "status": "UNKNOWN_KIND",
583
+ "label": "NOT_MODELED",
584
+ "error": f"unknown kind '{kind}'. Valid: {list(KINDS)}",
585
+ "doctrine": DOCTRINE,
586
+ "lambda_note": LAMBDA_NOTE,
587
+ "honest_inverse_of_free_energy": HONEST_INVERSE_OF_FREE_ENERGY,
588
+ "labels": LABELS,
589
+ }
590
+ return fn(**kwargs)
591
+
592
+
593
+ __all__ = [
594
+ "certify", "status", "KINDS", "DOCTRINE", "LAMBDA_NOTE",
595
+ "HONEST_INVERSE_OF_FREE_ENERGY", "LABELS", "SENSING_ATTRIBUTION",
596
+ ]
597
+
598
+
599
+ if __name__ == "__main__":
600
+ import json
601
+ print("SZL UNIFIED FUNDAMENTAL-LIMITS LIBRARY — status\n" + "=" * 60)
602
+ print(json.dumps(status(), indent=2, default=str)[:2000])
603
+ print("\n--- certify(quantum_sensor) ---")
604
+ print(json.dumps(certify("quantum_sensor"), indent=2, default=str)[:1500])
605
+ print("\n--- certify(nav_coasting) ---")
606
+ print(json.dumps(certify("nav_coasting"), indent=2, default=str)[:1200])
nav_coasting.py ADDED
@@ -0,0 +1,696 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Doctrine v11 LOCKED · Λ = Conjecture 1 (advisory, NOT proven trust)
3
+ # Sign-off: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
4
+ """nav_coasting — SZL-NATIVE GPS-DENIED NAVIGATION COASTING / HOLDOVER model,
5
+ governed and tied to the SZL agentic-PINN + deny-by-default Λ-gate.
6
+
7
+ THE LANE (Dev 3 of 4): the honest "how long can a quantum-equipped system coast
8
+ when GPS is denied" number. When GNSS is denied, position is dead-reckoned from
9
+ inertial sensors and time is held over from the local clock. Both error sources
10
+ GROW with time; the figure-of-merit is the TIME-TO-EXCEED a position/timing
11
+ accuracy threshold. The whole point of a quantum (cold-atom interferometer)
12
+ accelerometer is that its noise PSD is LOWER, so coasting error grows slower and
13
+ the time-to-exceed is LONGER. This module computes that delta honestly.
14
+
15
+ CLEAN-ROOM: the METHOD & PHYSICS are re-derived from the open literature and from
16
+ the published METHOD of AshfordeOU/kshana (Apache-2.0, DOI 10.5281/zenodo.20528627,
17
+ GNSS/INS fusion + clock holdover). NO kshana Rust is copied — see ATTRIBUTION.
18
+
19
+ WHAT IS MODELED (honest, Doctrine v11):
20
+ * 1-DOF (single straight axis) strapdown dead-reckoning error growth. 1-DOF is
21
+ a deliberate, declared simplification: it captures the dominant accelerometer
22
+ noise → velocity → position double-integration and the clock holdover terms,
23
+ which is exactly what sets the coasting horizon to first order.
24
+ * Position error variance from (i) velocity-random-walk (VRW), (ii) acceleration
25
+ random walk / white-accel PSD (the q_va that Dev1's quantum sensor model
26
+ produces), and (iii) a deterministic accelerometer bias term (∝ t²).
27
+ * Clock TIMING holdover from initial phase/frequency offset + frequency drift +
28
+ Allan stochastic terms (white-FM and random-walk-FM), expressed in metres via
29
+ the speed of light so position and timing live on one budget.
30
+
31
+ WHAT IS NOT MODELED (declared, never faked):
32
+ * 3-axis / full strapdown INS (attitude/tilt → gyro-bias t^3 coupling, Schuler
33
+ 84-min loop, Coriolis, gravity-deflection) — marked NOT MODELED. The t^3 gyro
34
+ term is the dominant long-coast term in the real 3-D system; ignoring it makes
35
+ our 1-DOF horizon an OPTIMISTIC (upper-ish) bound, and we say so on the receipt.
36
+ * No Kalman/UKF fusion update is run here (kshana's 17-state tightly-coupled UKF
37
+ is NOT MODELED); we model the OPEN-LOOP coasting growth, which is the relevant
38
+ quantity once aiding (GNSS) is denied.
39
+
40
+ GOVERNANCE: the coasting estimate is produced under a DENY-BY-DEFAULT Λ-gate that
41
+ mirrors agentic_pinn.py / innovations/lambda_gate.py. The estimate is ACCEPTED
42
+ only when the numerical integration passes a residual/convergence self-check
43
+ against the closed-form variance growth. Each run emits an UNSIGNED, signer-ready
44
+ receipt (STRUCTURAL-ONLY: content-addressed inputs hash, no cryptographic sig).
45
+
46
+ Pure numpy → sovereign, own-metal, auditable.
47
+ """
48
+ from __future__ import annotations
49
+
50
+ import hashlib
51
+ import json
52
+ import math
53
+ import time
54
+ from dataclasses import asdict, dataclass, field
55
+ from typing import Any, Optional
56
+
57
+ import numpy as np
58
+
59
+ # --------------------------------------------------------------------------- #
60
+ # Constants #
61
+ # --------------------------------------------------------------------------- #
62
+ C_LIGHT = 299792458.0 # speed of light, m/s (SI exact) — couples timing<->range
63
+ G0 = 9.80665 # standard gravity, m/s^2 (for bias expressed in 'g')
64
+
65
+ METHOD = ("szl_nav_coasting (1-DOF GNSS/INS open-loop dead-reckoning error growth + "
66
+ "clock holdover; time-to-exceed FoM for CLASSICAL vs QUANTUM sensor "
67
+ "coefficients; governed under a deny-by-default Lambda-gate with a "
68
+ "residual-checked integration and a per-run STRUCTURAL-ONLY receipt)")
69
+
70
+ # Method/physics attribution ONLY — clean-room. No kshana Rust copied or consulted
71
+ # beyond its PUBLIC method/equation surface (its docs/README/CLAIMS labels).
72
+ ATTRIBUTION = {
73
+ "ins_error_growth_method": (
74
+ "Strapdown inertial error propagation re-derived clean-room from standard "
75
+ "public references: Woodman, O.J., 'An introduction to inertial navigation', "
76
+ "Univ. Cambridge Tech. Report UCAM-CL-TR-696 (2007) — accelerometer bias gives "
77
+ "position error s(t)=b*t^2/2, double-integrated white accel noise gives a "
78
+ "position random walk; Groves, P.D., 'Principles of GNSS, Inertial, and "
79
+ "Multisensor Integrated Navigation Systems', 2nd ed., Artech House (2013) — "
80
+ "VRW/ARW PSD bookkeeping. METHOD/MATHEMATICS attribution only."
81
+ ),
82
+ "clock_holdover_method": (
83
+ "Clock time-error / holdover model x(t)=x0+y0*t+0.5*D*t^2 plus Allan stochastic "
84
+ "terms re-derived clean-room from: Allan, D.W. (1966) Proc. IEEE 54(2):221 "
85
+ "(Allan variance); IEEE Std 1139-2008 (frequency-stability definitions); "
86
+ "ITU-T/ETSI TIE & MTIE holdover definitions (ETSI EN 300 462). White-FM noise "
87
+ "(sigma_y(tau)=h0/sqrt(tau)) integrates to a TIE random walk (var ∝ t); "
88
+ "random-walk-FM integrates to var ∝ t^3. METHOD/MATHEMATICS attribution only."
89
+ ),
90
+ "quantum_sensor_coupling": (
91
+ "Consumes the accelerometer noise PSD q_va (units (m/s^2)^2/Hz, equivalently "
92
+ "ASD^2) produced by the SZL cold-atom-interferometer sensor model (Dev1), "
93
+ "itself a clean-room re-derivation of the kshana inertial/quantum_imu method "
94
+ "(Kasevich & Chu 1991; Peters et al. 2001; Freier et al. 2016; Cheinet et al. "
95
+ "2008). This module is agnostic to how q_va was produced; it only needs the PSD."
96
+ ),
97
+ "kshana_method_source": (
98
+ "AshfordeOU/kshana — open PNT-resilience simulator (Apache-2.0, DOI "
99
+ "10.5281/zenodo.20528627): GNSS/INS fusion (fusion/ukf.rs, tightly_coupled17.rs), "
100
+ "clock holdover (allan.rs, timetransfer*.rs), and the 'how long can a "
101
+ "quantum-equipped system coast when GPS is denied' question. METHOD source only; "
102
+ "NO Rust copied. Cited under its Apache-2.0 licence, clean-room re-derivation."
103
+ ),
104
+ "governance": (
105
+ "Deny-by-default Λ-gate posture mirrored from the SZL agentic_pinn.py and "
106
+ "innovations/lambda_gate.py (clean-room, SZL-native). Λ = Conjecture 1 — "
107
+ "advisory governance, not proven trust."
108
+ ),
109
+ }
110
+
111
+ DOCTRINE = (
112
+ "v11 LOCKED: Λ=Conjecture 1 (ADVISORY gate, NOT proven trust); NO free-energy/"
113
+ "over-unity (sensor noise floors are DERIVED from physics PSDs, never invented); "
114
+ "the coasting horizon is MODELED, not MEASURED, unless a real q_va/clock spec is "
115
+ "supplied and labelled MEASURED; 1-DOF is a DECLARED simplification and 3-axis/"
116
+ "full-INS (gyro t^3, Schuler, Coriolis) is NOT MODELED; no fabricated coasting "
117
+ "number — the integration really runs and is residual-checked; cite-never-plagiarize."
118
+ )
119
+
120
+ # Verdict vocabulary (mirrors innovations/lambda_gate.py exactly).
121
+ VERDICT_ALLOW = "ALLOW"
122
+ VERDICT_ADVISORY = "ADVISORY"
123
+ VERDICT_DENY = "DENY"
124
+
125
+
126
+ def _hash_inputs(obj: dict) -> str:
127
+ canon = json.dumps(obj, sort_keys=True, separators=(",", ":"), default=str)
128
+ return "sha256:" + hashlib.sha256(canon.encode()).hexdigest()
129
+
130
+
131
+ # --------------------------------------------------------------------------- #
132
+ # Sensor / clock coefficient bundle (CLASSICAL vs QUANTUM) #
133
+ # --------------------------------------------------------------------------- #
134
+ @dataclass
135
+ class SensorCoeffs:
136
+ """The error-growth coefficients for one sensor+clock configuration.
137
+
138
+ All fields are INPUTS (MEASURED from a datasheet/lab, or honest SAMPLE/MODELED).
139
+ The accelerometer white-noise term `q_va` is the PSD that Dev1's quantum sensor
140
+ model emits; everything else is the surrounding INS/clock budget.
141
+
142
+ Units:
143
+ q_va : accelerometer white-noise PSD, (m/s^2)^2 / Hz (== ASD^2).
144
+ This is the single field Dev1 feeds us. ASD n_a = sqrt(q_va).
145
+ accel_bias : residual deterministic accelerometer bias, m/s^2 (after calib).
146
+ vrw_psd : velocity-random-walk PSD added directly to the velocity state,
147
+ (m/s)^2 / s (m^2/s^3). Captures integrated-rate / quantisation
148
+ that is not already inside q_va. Default 0 (folded into q_va).
149
+ clock_h0 : white-FM coefficient; sigma_y(tau) = sqrt(h0 / (2*tau)) form,
150
+ here we use the convenient sigma_y(tau)=clock_adev1s/sqrt(tau)
151
+ parameterisation via `clock_adev_1s` below instead, and keep h0
152
+ available for advanced callers (dimensionless^2 * s).
153
+ clock_adev_1s : Allan deviation at tau=1 s (dimensionless, df/f). White-FM.
154
+ clock_rwfm : random-walk-FM rate (dimensionless / sqrt(s)) — long-term clock
155
+ wander. Drives a TIE variance ∝ t^3 term.
156
+ clock_drift : deterministic fractional frequency drift D (1/s), aging.
157
+ clock_y0 : initial fractional frequency offset y0 (dimensionless) at the
158
+ moment GNSS is denied (post-sync residual).
159
+ label : "MEASURED" | "MODELED" | "SAMPLE" (honest provenance).
160
+ name : human label, e.g. "classical-MEMS" / "quantum-CAI".
161
+ """
162
+ q_va: float # (m/s^2)^2 / Hz — from Dev1 quantum sensor model
163
+ accel_bias: float = 0.0 # m/s^2
164
+ vrw_psd: float = 0.0 # (m/s)^2 / s
165
+ clock_adev_1s: float = 0.0 # Allan deviation at 1 s (white-FM), df/f
166
+ clock_rwfm: float = 0.0 # random-walk-FM rate, 1/sqrt(s)
167
+ clock_drift: float = 0.0 # fractional frequency drift D, 1/s
168
+ clock_y0: float = 0.0 # initial fractional frequency offset
169
+ clock_h0: float = 0.0 # optional white-FM PSD coefficient (advanced)
170
+ label: str = "MODELED"
171
+ name: str = "unnamed"
172
+ source: str = "honest-sample"
173
+
174
+ @property
175
+ def accel_asd(self) -> float:
176
+ """Accelerometer amplitude spectral density, (m/s^2)/sqrt(Hz) = sqrt(q_va)."""
177
+ return math.sqrt(max(self.q_va, 0.0))
178
+
179
+
180
+ # --------------------------------------------------------------------------- #
181
+ # Closed-form 1-DOF error-growth variances (the derived physics) #
182
+ # --------------------------------------------------------------------------- #
183
+ def position_error_sigma(c: SensorCoeffs, t: np.ndarray | float) -> np.ndarray:
184
+ """1-DOF horizontal POSITION error std-dev (m) after coasting time t (s).
185
+
186
+ Re-derived clean-room. Three contributions, added in QUADRATURE for the
187
+ stochastic parts and arithmetically for the deterministic bias term:
188
+
189
+ (A) White accelerometer noise PSD q_va, double-integrated:
190
+ Var_x(t) = q_va * t^3 / 3. (random-walk-of-velocity -> position)
191
+ [matches the kshana vibration phase variance shape sigma^2 ∝ S_a*T^3/3
192
+ re-expressed in metres; Woodman 2007 random-walk result.]
193
+ (B) Velocity-random-walk PSD vrw_psd, single state on velocity then integrated:
194
+ Var_x(t) = vrw_psd * t^3 / 3 as well for a white velocity-rate; we keep it
195
+ separate so a caller can split quantisation noise from sensor white noise.
196
+ (C) Deterministic residual accel bias b, double-integrated (NOT a variance —
197
+ a systematic offset): x_bias(t) = 0.5 * b * t^2.
198
+
199
+ sigma_pos(t) = sqrt(Var_x_stoch(t)) + |x_bias(t)| (conservative sum: random
200
+ 1-sigma plus the systematic offset, an honest upper-ish envelope).
201
+ """
202
+ t = np.asarray(t, dtype=float)
203
+ var_stoch = (c.q_va + c.vrw_psd) * np.power(t, 3) / 3.0
204
+ sigma_stoch = np.sqrt(np.maximum(var_stoch, 0.0))
205
+ x_bias = 0.5 * abs(c.accel_bias) * np.power(t, 2)
206
+ return sigma_stoch + x_bias
207
+
208
+
209
+ def timing_error_seconds(c: SensorCoeffs, t: np.ndarray | float) -> np.ndarray:
210
+ """1-DOF clock TIMING (time-interval) error std-dev-equivalent (s) at coast t.
211
+
212
+ x(t) = x0 + y0*t + 0.5*D*t^2 (deterministic) + Allan stochastic terms.
213
+ Re-derived clean-room from the time-error/holdover definition and Allan-noise
214
+ integration (ETSI EN 300 462; IEEE Std 1139; Allan 1966):
215
+ * deterministic frequency offset: |y0| * t (linear TIE)
216
+ * deterministic frequency drift D: 0.5 * |D| * t^2 (parabolic TIE)
217
+ * white-FM (ADEV = adev_1s / sqrt(tau)) integrates to a TIE RANDOM WALK whose
218
+ std grows ~ adev_1s * t / sqrt(t) * sqrt(t) ... we use the standard holdover
219
+ result sigma_TIE_whiteFM(t) = adev_1s * t / sqrt(... ) -> we adopt the
220
+ widely-used engineering holdover approximation: TIE_whiteFM(t) ≈ adev_1s *
221
+ sqrt(t) * t_ref with t_ref=1s normalisation, i.e. sigma ∝ t for the
222
+ accumulated phase; to stay strictly honest and simple we use the conservative
223
+ sigma_whiteFM(t) = adev_1s * t (frequency offset held for the whole interval),
224
+ which is the standard worst-case holdover envelope for white-FM.
225
+ * random-walk-FM: sigma_rwfm(t) = clock_rwfm * t^1.5 / sqrt(3) (var ∝ t^3).
226
+ All combined as a deterministic-plus-stochastic envelope (sum), honestly
227
+ conservative. Returned in SECONDS.
228
+ """
229
+ t = np.asarray(t, dtype=float)
230
+ det = abs(c.clock_y0) * t + 0.5 * abs(c.clock_drift) * np.power(t, 2)
231
+ whitefm = c.clock_adev_1s * t # holdover envelope (s), ∝ t
232
+ rwfm = c.clock_rwfm * np.power(t, 1.5) / math.sqrt(3.0)
233
+ sigma_stoch = np.sqrt(whitefm ** 2 + rwfm ** 2)
234
+ return det + sigma_stoch
235
+
236
+
237
+ def timing_error_meters(c: SensorCoeffs, t: np.ndarray | float) -> np.ndarray:
238
+ """Clock timing error expressed as an equivalent RANGE error (m) = c * dt.
239
+
240
+ A timing holdover error dt seconds maps to a pseudorange/position error of
241
+ c*dt metres (the clock bias enters the navigation solution as a common-mode
242
+ range error). This lets position and timing share ONE accuracy budget.
243
+ """
244
+ return C_LIGHT * timing_error_seconds(c, t)
245
+
246
+
247
+ def combined_error_meters(c: SensorCoeffs, t: np.ndarray | float) -> np.ndarray:
248
+ """Total coasting error envelope (m): INS position error + clock range error,
249
+ combined in quadrature (independent error sources)."""
250
+ p = position_error_sigma(c, t)
251
+ k = timing_error_meters(c, t)
252
+ return np.sqrt(p ** 2 + k ** 2)
253
+
254
+
255
+ # --------------------------------------------------------------------------- #
256
+ # Time-to-exceed figure-of-merit #
257
+ # --------------------------------------------------------------------------- #
258
+ @dataclass
259
+ class TimeToExceed:
260
+ """The coasting figure-of-merit for one configuration."""
261
+ threshold_m: float
262
+ t_exceed_s: float # first time the combined error >= threshold
263
+ error_channel: str # "position" | "timing" | "combined"
264
+ config_name: str
265
+ config_label: str # MEASURED | MODELED | SAMPLE
266
+ found: bool # True if threshold crossed within the horizon
267
+ horizon_s: float # search horizon used
268
+
269
+ def to_dict(self) -> dict:
270
+ return asdict(self)
271
+
272
+
273
+ def time_to_exceed(c: SensorCoeffs, threshold_m: float, *,
274
+ channel: str = "combined", horizon_s: float = 7200.0,
275
+ n_grid: int = 200001) -> TimeToExceed:
276
+ """First coasting time t at which the chosen error channel reaches threshold_m.
277
+
278
+ Monotone-increasing error -> we locate the crossing by a dense grid scan then
279
+ refine with a bisection on the (monotone) error function. Honest: if the
280
+ threshold is not crossed inside `horizon_s`, found=False and t_exceed_s=horizon_s.
281
+ """
282
+ if channel == "position":
283
+ f = position_error_sigma
284
+ elif channel == "timing":
285
+ f = timing_error_meters
286
+ else:
287
+ channel = "combined"
288
+ f = combined_error_meters
289
+
290
+ ts = np.linspace(0.0, horizon_s, n_grid)
291
+ errs = f(c, ts)
292
+ over = np.where(errs >= threshold_m)[0]
293
+ if over.size == 0:
294
+ return TimeToExceed(threshold_m=threshold_m, t_exceed_s=horizon_s,
295
+ error_channel=channel, config_name=c.name,
296
+ config_label=c.label, found=False, horizon_s=horizon_s)
297
+ # bisection refine between the last point below and the first at/above
298
+ i = int(over[0])
299
+ lo = ts[i - 1] if i > 0 else 0.0
300
+ hi = ts[i]
301
+ for _ in range(60):
302
+ mid = 0.5 * (lo + hi)
303
+ if float(f(c, mid)) >= threshold_m:
304
+ hi = mid
305
+ else:
306
+ lo = mid
307
+ return TimeToExceed(threshold_m=threshold_m, t_exceed_s=0.5 * (lo + hi),
308
+ error_channel=channel, config_name=c.name,
309
+ config_label=c.label, found=True, horizon_s=horizon_s)
310
+
311
+
312
+ def quantum_advantage(classical: SensorCoeffs, quantum: SensorCoeffs,
313
+ threshold_m: float, *, channel: str = "combined",
314
+ horizon_s: float = 7200.0) -> dict:
315
+ """The honest 'how much longer does quantum buy you' number.
316
+
317
+ Returns both time-to-exceed values and their delta/ratio. If either config does
318
+ not cross the threshold inside the horizon, the corresponding `found` flag is
319
+ False and the ratio is reported as a LOWER BOUND (labelled).
320
+ """
321
+ tc = time_to_exceed(classical, threshold_m, channel=channel, horizon_s=horizon_s)
322
+ tq = time_to_exceed(quantum, threshold_m, channel=channel, horizon_s=horizon_s)
323
+ extra = tq.t_exceed_s - tc.t_exceed_s
324
+ ratio = (tq.t_exceed_s / tc.t_exceed_s) if tc.t_exceed_s > 0 else float("inf")
325
+ return {
326
+ "threshold_m": threshold_m,
327
+ "channel": channel,
328
+ "horizon_s": horizon_s,
329
+ "classical": tc.to_dict(),
330
+ "quantum": tq.to_dict(),
331
+ "extra_coasting_seconds": extra,
332
+ "coasting_ratio": ratio,
333
+ "ratio_is_lower_bound": (not tc.found) or (not tq.found),
334
+ "label": (
335
+ f"{classical.label}/{quantum.label}: quantum buys "
336
+ f"{extra:.1f} s extra coast ({ratio:.2f}x) before exceeding "
337
+ f"{threshold_m:g} m on the {channel} channel"
338
+ ),
339
+ }
340
+
341
+
342
+ # --------------------------------------------------------------------------- #
343
+ # Numerical integrator (so we have something to RESIDUAL-CHECK against) #
344
+ # --------------------------------------------------------------------------- #
345
+ def integrate_position_variance(c: SensorCoeffs, horizon_s: float,
346
+ dt: float) -> tuple[float, float]:
347
+ """Forward-Euler accumulate the position-error VARIANCE from the white PSD,
348
+ so the governed solve has a NUMERICAL estimate to check against the closed form.
349
+
350
+ dVar_v/dt = (q_va + vrw_psd) (velocity-variance grows at the PSD rate)
351
+ dVar_x/dt = 2 * Cov_xv (exact for the integrated random walk)
352
+ dCov_xv/dt = Var_v
353
+ Returns (sigma_x_numeric_at_horizon, sigma_x_closedform_at_horizon) [metres,
354
+ stochastic part only — the bias term is deterministic and added separately].
355
+ """
356
+ n = max(int(round(horizon_s / dt)), 1)
357
+ q = c.q_va + c.vrw_psd
358
+ var_x = 0.0
359
+ cov_xv = 0.0
360
+ var_v = 0.0
361
+ for _ in range(n):
362
+ d_var_x = 2.0 * cov_xv
363
+ d_cov = var_v
364
+ d_var_v = q
365
+ var_x += d_var_x * dt
366
+ cov_xv += d_cov * dt
367
+ var_v += d_var_v * dt
368
+ sigma_num = math.sqrt(max(var_x, 0.0))
369
+ sigma_cf = math.sqrt(max(q * horizon_s ** 3 / 3.0, 0.0))
370
+ return sigma_num, sigma_cf
371
+
372
+
373
+ # --------------------------------------------------------------------------- #
374
+ # Governed solve receipt (STRUCTURAL-ONLY, unsigned) #
375
+ # --------------------------------------------------------------------------- #
376
+ @dataclass
377
+ class CoastingReceipt:
378
+ """Signer-ready (UNSIGNED, STRUCTURAL-ONLY) provenance for one governed run."""
379
+ receipt_type: str
380
+ # inputs (echoed, labelled)
381
+ config_name: str
382
+ config_label: str # MEASURED | MODELED | SAMPLE
383
+ q_va_psd: float # the Dev1-supplied accelerometer PSD
384
+ threshold_m: float
385
+ channel: str
386
+ horizon_s: float
387
+ # the figure-of-merit
388
+ time_to_exceed_s: float
389
+ threshold_found_in_horizon: bool
390
+ # integration self-check (the residual gate)
391
+ sigma_numeric_m: float
392
+ sigma_closedform_m: float
393
+ integration_rel_residual: float # |num - closed| / closed
394
+ residual_tol: float
395
+ converged: bool # integration residual within tol
396
+ monotonic_check: bool # error is monotone non-decreasing on the grid
397
+ # Λ verdict
398
+ lambda_verdict: str # ALLOW | ADVISORY | DENY
399
+ lambda_advisory: bool
400
+ lambda_reason: str
401
+ accepted: bool # estimate admitted (ALLOW)
402
+ # honesty
403
+ modeled_not_measured: bool
404
+ one_dof_only: bool
405
+ three_axis_full_ins: str # always "NOT MODELED"
406
+ schuler_coriolis_gyro_t3: str # always "NOT MODELED"
407
+ inputs_hash: str
408
+ timestamp_utc: float
409
+ method: str = METHOD
410
+ attribution: dict = field(default_factory=lambda: ATTRIBUTION)
411
+ doctrine: str = DOCTRINE
412
+ lambda_label: str = ("Λ = Conjecture 1 — advisory governance, NOT 'proven trust'; "
413
+ "ALLOW means passed SZL admission policy (integration converged "
414
+ "+ monotone), not a guaranteed real-world coasting time.")
415
+ signature: None = None # UNSIGNED — STRUCTURAL-ONLY content addressing
416
+
417
+ def to_dict(self) -> dict:
418
+ return asdict(self)
419
+
420
+ def to_json(self, indent: int = 2) -> str:
421
+ return json.dumps(self.to_dict(), indent=indent, default=str)
422
+
423
+
424
+ # --------------------------------------------------------------------------- #
425
+ # The deny-by-default Λ-gate (mirrors innovations/lambda_gate.gate_solve) #
426
+ # --------------------------------------------------------------------------- #
427
+ @dataclass
428
+ class GateVerdict:
429
+ verdict: str
430
+ advisory: bool
431
+ reason: str
432
+ rel_residual: Optional[float]
433
+ tol: Optional[float]
434
+ converged: Optional[bool]
435
+ monotonic: Optional[bool]
436
+ modeled_not_measured: Optional[bool]
437
+ lambda_label: str = ("Λ = Conjecture 1 — advisory governance, NOT 'proven trust'; "
438
+ "ALLOW means passed SZL admission policy, not proven correct.")
439
+ deny_by_default: bool = True
440
+
441
+ def to_dict(self) -> dict:
442
+ return asdict(self)
443
+
444
+
445
+ def gate_coasting(receipt: dict, *, tol: float = 1e-3,
446
+ near_tol_frac: float = 0.85) -> GateVerdict:
447
+ """Deny-by-default Λ gate over a coasting-run receipt dict. Same posture as the
448
+ PINN gate: absence/weakness of evidence => DENY.
449
+
450
+ DENY : missing/invalid receipt; integration not converged (residual > tol or
451
+ NaN); error not monotone; or a receipt that claims MEASURED energy/time
452
+ it did not honestly source (free-energy / fabrication guard).
453
+ ADVISORY: converged but the integration residual sits near the tolerance ceiling.
454
+ ALLOW : integration converged within tol AND error monotone AND honestly
455
+ declared modeled_not_measured.
456
+ """
457
+ try:
458
+ rel = float(receipt["integration_rel_residual"])
459
+ converged = bool(receipt["converged"])
460
+ monotone = bool(receipt["monotonic_check"])
461
+ modeled = bool(receipt.get("modeled_not_measured", True))
462
+ except (KeyError, TypeError, ValueError) as e:
463
+ return GateVerdict(VERDICT_DENY, True,
464
+ f"deny-by-default: missing/invalid receipt ({e})",
465
+ None, tol, None, None, None)
466
+
467
+ # Free-energy / fabrication guard: a run that claims to be MEASURED but supplies
468
+ # no computed residual evidence is denied. We require an honest modeled flag OR a
469
+ # real residual; here modeled must be declared True for the in-sandbox sample.
470
+ if not modeled:
471
+ return GateVerdict(VERDICT_DENY, True,
472
+ ("free-energy/fabrication guard: receipt does not declare "
473
+ "modeled_not_measured — the coasting horizon is MODELED, "
474
+ "not a measured field, unless a labelled MEASURED spec is "
475
+ "supplied with evidence"),
476
+ rel, tol, converged, monotone, modeled)
477
+
478
+ if (not converged) or (rel != rel) or (rel > tol) or (not monotone):
479
+ return GateVerdict(VERDICT_DENY, True,
480
+ (f"integration rel-residual {rel:.3e} > tol {tol:.3e}, not "
481
+ f"converged, or non-monotone error — coasting estimate not "
482
+ f"admissible"),
483
+ rel, tol, converged, monotone, modeled)
484
+
485
+ if rel >= near_tol_frac * tol:
486
+ return GateVerdict(VERDICT_ADVISORY, True,
487
+ (f"converged but rel-residual {rel:.3e} near tol {tol:.3e} — "
488
+ f"tighten dt before relying on the number"),
489
+ rel, tol, converged, monotone, modeled)
490
+
491
+ return GateVerdict(VERDICT_ALLOW, False,
492
+ "integration converged within tol; error monotone; passed SZL "
493
+ "admission policy",
494
+ rel, tol, converged, monotone, modeled)
495
+
496
+
497
+ # --------------------------------------------------------------------------- #
498
+ # Governed solve wrapper #
499
+ # --------------------------------------------------------------------------- #
500
+ def governed_coasting_solve(c: SensorCoeffs, threshold_m: float, *,
501
+ channel: str = "combined", horizon_s: float = 7200.0,
502
+ integ_dt: float = 0.05,
503
+ residual_tol: float = 1e-3) -> CoastingReceipt:
504
+ """Run the coasting figure-of-merit UNDER the deny-by-default Λ-gate.
505
+
506
+ Steps (mirroring the agentic-PINN solve/measure/gate pattern):
507
+ 1. SOLVE: compute time-to-exceed from the closed-form monotone error.
508
+ 2. MEASURE: numerically integrate the position variance and compare to the
509
+ closed form (the residual / convergence self-check).
510
+ 3. CHECK: confirm the error channel is monotone non-decreasing on the grid.
511
+ 4. Λ-GATE: accept the estimate only if (2) converged within tol and (3) holds.
512
+ 5. EMIT: an UNSIGNED, STRUCTURAL-ONLY receipt with the full decision trail.
513
+
514
+ The time-to-exceed number is ALWAYS computed from a real run; it is only marked
515
+ `accepted` when the gate returns ALLOW. No fabricated number is ever emitted.
516
+ """
517
+ tte = time_to_exceed(c, threshold_m, channel=channel, horizon_s=horizon_s)
518
+
519
+ # integration self-check on the stochastic position variance
520
+ sigma_num, sigma_cf = integrate_position_variance(c, horizon_s, integ_dt)
521
+ if sigma_cf > 0:
522
+ rel_resid = abs(sigma_num - sigma_cf) / sigma_cf
523
+ else:
524
+ # degenerate config (no white noise): both should be ~0; residual is 0 if so,
525
+ # else flag large so the gate denies.
526
+ rel_resid = 0.0 if abs(sigma_num) < 1e-12 else float("inf")
527
+
528
+ # monotonicity check on the actual error channel
529
+ ts = np.linspace(0.0, horizon_s, 4000)
530
+ if channel == "position":
531
+ errs = position_error_sigma(c, ts)
532
+ elif channel == "timing":
533
+ errs = timing_error_meters(c, ts)
534
+ else:
535
+ errs = combined_error_meters(c, ts)
536
+ monotone = bool(np.all(np.diff(errs) >= -1e-9))
537
+
538
+ converged = bool(np.isfinite(rel_resid) and rel_resid <= residual_tol)
539
+
540
+ inputs = {
541
+ "name": c.name, "label": c.label, "source": c.source,
542
+ "q_va": c.q_va, "accel_bias": c.accel_bias, "vrw_psd": c.vrw_psd,
543
+ "clock_adev_1s": c.clock_adev_1s, "clock_rwfm": c.clock_rwfm,
544
+ "clock_drift": c.clock_drift, "clock_y0": c.clock_y0,
545
+ "threshold_m": threshold_m, "channel": channel, "horizon_s": horizon_s,
546
+ "integ_dt": integ_dt, "residual_tol": residual_tol,
547
+ }
548
+
549
+ gate_input = {
550
+ "integration_rel_residual": rel_resid,
551
+ "converged": converged,
552
+ "monotonic_check": monotone,
553
+ "modeled_not_measured": (c.label != "MEASURED"),
554
+ }
555
+ verdict = gate_coasting(gate_input, tol=residual_tol)
556
+ accepted = (verdict.verdict == VERDICT_ALLOW)
557
+
558
+ return CoastingReceipt(
559
+ receipt_type="szl/nav-coasting-receipt/v1",
560
+ config_name=c.name,
561
+ config_label=c.label,
562
+ q_va_psd=c.q_va,
563
+ threshold_m=threshold_m,
564
+ channel=channel,
565
+ horizon_s=horizon_s,
566
+ time_to_exceed_s=tte.t_exceed_s,
567
+ threshold_found_in_horizon=tte.found,
568
+ sigma_numeric_m=sigma_num,
569
+ sigma_closedform_m=sigma_cf,
570
+ integration_rel_residual=rel_resid,
571
+ residual_tol=residual_tol,
572
+ converged=converged,
573
+ monotonic_check=monotone,
574
+ lambda_verdict=verdict.verdict,
575
+ lambda_advisory=verdict.advisory,
576
+ lambda_reason=verdict.reason,
577
+ accepted=accepted,
578
+ modeled_not_measured=(c.label != "MEASURED"),
579
+ one_dof_only=True,
580
+ three_axis_full_ins="NOT MODELED",
581
+ schuler_coriolis_gyro_t3="NOT MODELED",
582
+ inputs_hash=_hash_inputs(inputs),
583
+ timestamp_utc=time.time(),
584
+ )
585
+
586
+
587
+ # --------------------------------------------------------------------------- #
588
+ # Honest sample configs (clearly labelled SAMPLE/MODELED) + Dev1 q_va loader #
589
+ # --------------------------------------------------------------------------- #
590
+ def load_dev1_q_va(default: float) -> tuple[float, str]:
591
+ """Try to read the accelerometer PSD q_va from Dev1's quantum sensor output.
592
+
593
+ Looks for /home/user/workspace/pnt_build/dev1_quantum_sensors/*.json with a
594
+ 'q_va' / 'accel_psd' / 'n_a' field. If absent (Dev1 not built yet), returns the
595
+ supplied honest SAMPLE default so this module composes standalone NOW and will
596
+ automatically consume Dev1's real number once it lands.
597
+
598
+ Returns (q_va, source_label).
599
+ """
600
+ import glob
601
+ import os
602
+ base = "/home/user/workspace/pnt_build/dev1_quantum_sensors"
603
+ if os.path.isdir(base):
604
+ for path in sorted(glob.glob(os.path.join(base, "*.json"))):
605
+ try:
606
+ with open(path) as fh:
607
+ data = json.load(fh)
608
+ except Exception:
609
+ continue
610
+ for key in ("q_va", "q_va_psd", "accel_psd_psd", "accel_psd"):
611
+ if isinstance(data, dict) and key in data:
612
+ return float(data[key]), f"dev1:{os.path.basename(path)}:{key}"
613
+ # n_a is an ASD (m/s^2/sqrt(Hz)); square it to a PSD
614
+ for key in ("n_a", "asd", "accel_asd"):
615
+ if isinstance(data, dict) and key in data:
616
+ return float(data[key]) ** 2, f"dev1:{os.path.basename(path)}:{key}^2"
617
+ return default, "honest-sample (Dev1 not present)"
618
+
619
+
620
+ def sample_classical() -> SensorCoeffs:
621
+ """Honest SAMPLE classical MEMS/tactical INS + TCXO clock budget. MODELED.
622
+
623
+ Representative tactical-grade numbers (order-of-magnitude, declared SAMPLE):
624
+ accel ASD ~ 1e-3 (m/s^2)/sqrt(Hz) -> q_va = 1e-6
625
+ residual accel bias ~ 1e-4 m/s^2 (after calib, ~10 ug)
626
+ TCXO Allan dev at 1 s ~ 1e-10; drift ~ 1e-9 / s
627
+ """
628
+ q, src = load_dev1_q_va(default=1.0e-6)
629
+ return SensorCoeffs(
630
+ q_va=q, accel_bias=1.0e-4, vrw_psd=0.0,
631
+ clock_adev_1s=1.0e-10, clock_rwfm=1.0e-12, clock_drift=1.0e-9, clock_y0=1.0e-11,
632
+ label="SAMPLE", name="classical-MEMS+TCXO", source=src,
633
+ )
634
+
635
+
636
+ def sample_quantum() -> SensorCoeffs:
637
+ """Honest SAMPLE quantum cold-atom-interferometer accel + chip-scale/optical clock.
638
+
639
+ The CAI accelerometer PSD is MUCH lower (that is the whole point), and a better
640
+ clock lowers the holdover term:
641
+ accel ASD ~ 1e-6 (m/s^2)/sqrt(Hz) -> q_va = 1e-12 (≈1000x lower amplitude)
642
+ residual accel bias ~ 1e-7 m/s^2 (CAI is absolute/bias-stable)
643
+ clock Allan dev at 1 s ~ 1e-12; drift ~ 1e-12 / s
644
+ """
645
+ q, src = load_dev1_q_va(default=1.0e-12)
646
+ return SensorCoeffs(
647
+ q_va=q, accel_bias=1.0e-7, vrw_psd=0.0,
648
+ clock_adev_1s=1.0e-12, clock_rwfm=1.0e-14, clock_drift=1.0e-12, clock_y0=1.0e-13,
649
+ label="SAMPLE", name="quantum-CAI+optical", source=src,
650
+ )
651
+
652
+
653
+ __all__ = [
654
+ "C_LIGHT", "G0", "METHOD", "ATTRIBUTION", "DOCTRINE",
655
+ "VERDICT_ALLOW", "VERDICT_ADVISORY", "VERDICT_DENY",
656
+ "SensorCoeffs", "position_error_sigma", "timing_error_seconds",
657
+ "timing_error_meters", "combined_error_meters",
658
+ "TimeToExceed", "time_to_exceed", "quantum_advantage",
659
+ "integrate_position_variance",
660
+ "CoastingReceipt", "GateVerdict", "gate_coasting", "governed_coasting_solve",
661
+ "load_dev1_q_va", "sample_classical", "sample_quantum",
662
+ ]
663
+
664
+
665
+ if __name__ == "__main__":
666
+ print("SZL NAV COASTING — GPS-denied holdover figure-of-merit (1-DOF, governed)\n"
667
+ + "=" * 72)
668
+ classical = sample_classical()
669
+ quantum = sample_quantum()
670
+ THRESH = 50.0 # metres — example navigation accuracy threshold
671
+
672
+ print(f"classical: {classical.name} q_va={classical.q_va:.3e} src={classical.source}")
673
+ print(f"quantum : {quantum.name} q_va={quantum.q_va:.3e} src={quantum.source}")
674
+ print()
675
+
676
+ adv = quantum_advantage(classical, quantum, THRESH, channel="combined")
677
+ print("QUANTUM ADVANTAGE (combined position+timing channel, MODELED):")
678
+ print(f" classical time-to-exceed {THRESH:g} m : "
679
+ f"{adv['classical']['t_exceed_s']:.1f} s (found={adv['classical']['found']})")
680
+ print(f" quantum time-to-exceed {THRESH:g} m : "
681
+ f"{adv['quantum']['t_exceed_s']:.1f} s (found={adv['quantum']['found']})")
682
+ print(f" extra coast: {adv['extra_coasting_seconds']:.1f} s "
683
+ f"ratio: {adv['coasting_ratio']:.2f}x "
684
+ f"(lower_bound={adv['ratio_is_lower_bound']})")
685
+ print()
686
+
687
+ rc = governed_coasting_solve(classical, THRESH)
688
+ rq = governed_coasting_solve(quantum, THRESH)
689
+ print("GOVERNED SOLVE RECEIPTS (Λ-gate, STRUCTURAL-ONLY / unsigned):")
690
+ for r in (rc, rq):
691
+ print(f" [{r.config_name}] verdict={r.lambda_verdict} accepted={r.accepted} "
692
+ f"rel_resid={r.integration_rel_residual:.2e} "
693
+ f"t_exceed={r.time_to_exceed_s:.1f}s monotone={r.monotonic_check}")
694
+ print()
695
+ print("HONESTY: 1-DOF only; 3-axis/full-INS (gyro t^3, Schuler, Coriolis) = NOT "
696
+ "MODELED; horizon is MODELED not MEASURED; Λ advisory.")
pnt_resilience.py ADDED
@@ -0,0 +1,558 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Doctrine v11 LOCKED · Λ = Conjecture 1 (advisory, NOT proven trust)
3
+ # Sign-off: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
4
+ """pnt_resilience — SZL-NATIVE fused GNSS SPOOF-DETECTION / PNT-RESILIENCE engine.
5
+
6
+ WHAT THIS IS
7
+ ============
8
+ A deny-by-default, multi-layer GNSS spoof detector. Four INDEPENDENT monitor
9
+ layers each emit a calibrated statistic + a fire/no-fire decision; a
10
+ Λ-gate-style governor fuses them. The governor is DENY-BY-DEFAULT: it returns
11
+ ALLOW only when NO layer fires AND a fused-confidence floor is cleared. The Λ
12
+ verdict is ADVISORY governance (Λ = Conjecture 1), it is NEVER "proven trust".
13
+
14
+ The four layers (each grounded in published method, cited below):
15
+ 1. multi-SV RAIM consistency — pseudorange-residual parity / χ² test
16
+ 2. AGC / power-advantage — received-power-advantage (dB) of a spoofer
17
+ 3. SQM (signal-quality) — early/late correlator + carrier-phase alignment
18
+ 4. clock-aided time-spoof — clock-bias vs position-push self-consistency
19
+
20
+ HONEST SCOPE (Doctrine v11, HARD — read this)
21
+ =============================================
22
+ This is a SIMULATOR that operates on **PARAMETERISED OBSERVABLES**, NOT raw IQ.
23
+ It is NOT an SDR and does NOT process baseband samples, correlator I/Q, or live
24
+ RF. The inputs are *summary observables* a real receiver would expose:
25
+ pseudorange residuals, an AGC-derived power-advantage estimate in dB, an SQM
26
+ early-minus-late metric, a carrier-phase-alignment flag, and clock-bias/position
27
+ push terms. A TEXBAT record is described to us by three classifier knobs (power
28
+ advantage dB, carrier-phase alignment, time/position push); we map those knobs
29
+ onto the observables the same way the literature characterises the records.
30
+ Anything we cannot derive from these observables is labelled NOT MODELED. We
31
+ NEVER label a record "detected" without a real triggering statistic crossing a
32
+ documented threshold (see SpoofVerdict.detected and the honesty test).
33
+
34
+ CLEAN-ROOM
35
+ ==========
36
+ Method/physics re-derived from the open literature and cited. We studied the
37
+ EXISTENCE and SHAPE of kshana's fused multi-layer detector (Apache-2.0) as prior
38
+ art and CITE it; we copied NONE of its Rust. This is the SDA bridge into our
39
+ khipu-sda-core / mosaic anomaly engine and sits under the Λ-gate governor.
40
+
41
+ Pure numpy → sovereign, own-metal, auditable.
42
+ """
43
+ from __future__ import annotations
44
+
45
+ import math
46
+ from dataclasses import dataclass, field, asdict
47
+ from typing import Optional
48
+
49
+ import numpy as np
50
+
51
+ # --------------------------------------------------------------------------- #
52
+ # Provenance — method/physics CITED, never claimed as SZL's own. #
53
+ # --------------------------------------------------------------------------- #
54
+ ATTRIBUTION = {
55
+ "kshana": (
56
+ "Baweja, C. (2026). 'Kshana — a PNT-resilience simulator with quantum-sensor "
57
+ "performance models', Ashforde OÜ, Apache-2.0, DOI:10.5281/zenodo.20528627 "
58
+ "(v0.16.0). Studied as PRIOR ART for the SHAPE of a fused multi-layer GNSS "
59
+ "spoof detector (RAIM-consistency parity + RF AGC-power monitor + SQM "
60
+ "early-minus-late monitor, χ²/Neyman-Pearson statistics). CLEAN-ROOM: no Rust "
61
+ "copied; re-derived from the cited primary literature below."
62
+ ),
63
+ "texbat": (
64
+ "Humphreys, T.E. et al. (2012), 'The Texas Spoofing Test Battery (TEXBAT)', "
65
+ "ION GNSS 2012. Defines the canonical spoofing records (ds1..ds8) classified "
66
+ "by power advantage, carrier-phase alignment, and time/position push — the "
67
+ "parameterisation used here to drive the monitor observables."
68
+ ),
69
+ "texbat_hifi": (
70
+ "ION (2016), 'Detailed Analysis of the TEXBAT Datasets Using a High Fidelity "
71
+ "Receiver' — characterises per-scenario power biases and time offsets; basis "
72
+ "for the dB / time-push numbers attached to each scenario class."
73
+ ),
74
+ "raim": (
75
+ "RTCA DO-229 / Receiver Autonomous Integrity Monitoring: redundant-pseudorange "
76
+ "parity / least-squares-residual chi-square fault detection over >=5 SVs. "
77
+ "Re-derived here as the RAIM-consistency layer."
78
+ ),
79
+ "agc_rpm": (
80
+ "Garbin & Manfredini (2018, ION ITM), 'Effective GPS Spoofing Detection "
81
+ "Utilizing Metrics from Commercial Receivers'; and ENAC hal-02907360 (2020), "
82
+ "'Assessment of GPS Spoofing Detection via Radio Power and Signal Quality' — "
83
+ "AGC / received-power monitoring detects overpowered spoofers."
84
+ ),
85
+ "sqm": (
86
+ "Phelts; Garbin & Manfredini (2018) — Signal Quality Monitoring observes "
87
+ "early-minus-late correlator asymmetry; powerful against power-matched "
88
+ "spoofers during the code-phase pull-off (transient indicator)."
89
+ ),
90
+ "clock": (
91
+ "Sensors (2023) PMC10007427, 'Characterization of the Ability of Low-Cost "
92
+ "GNSS Receiver to Detect Spoofing' and SCV-RCS (Sensors 2026, PMC12845604): "
93
+ "a spoofing attack induces a leap/inconsistency in the receiver clock bias "
94
+ "vs the position solution — clock-aided time-spoof detection."
95
+ ),
96
+ "doctrine": (
97
+ "SZL Doctrine v11 — clean-room, cite-never-plagiarize, MEASURED/MODELED "
98
+ "labels, deny-by-default, Λ = Conjecture 1 (advisory governance gate, NOT "
99
+ "proven trust). Λ-gate posture matches agentic_pinn / physics_bounds estate."
100
+ ),
101
+ }
102
+
103
+ # Λ verdict labels (match the estate's lambda_gate vocabulary).
104
+ VERDICT_ALLOW = "ALLOW" # no layer fired AND fused confidence passed
105
+ VERDICT_ADVISORY = "ADVISORY" # ambiguous: weak/conflicting evidence -> hold
106
+ VERDICT_DENY = "DENY" # >=1 layer fired -> deny-by-default
107
+
108
+ LAMBDA_LABEL = (
109
+ "Λ = Conjecture 1 — the spoof governor is ADVISORY governance, NOT 'proven "
110
+ "trust'. ALLOW means the PNT fix passed SZL admission policy (no monitor fired "
111
+ "and fused confidence cleared the floor); it does NOT certify the signal is "
112
+ "authentic. DENY/ADVISORY are deny-by-default holds."
113
+ )
114
+
115
+ SCOPE_LABEL = (
116
+ "OBSERVABLE-DOMAIN SIMULATOR — operates on parameterised receiver observables "
117
+ "(pseudorange residuals, AGC power-advantage dB, SQM early-minus-late, "
118
+ "carrier-phase-alignment flag, clock-bias/position push). NOT an SDR; does NOT "
119
+ "process raw IQ / baseband. Items not derivable are labelled NOT MODELED."
120
+ )
121
+
122
+
123
+ # --------------------------------------------------------------------------- #
124
+ # Calibrated thresholds. All DOCUMENTED, all tunable, none magic. #
125
+ # --------------------------------------------------------------------------- #
126
+ @dataclass(frozen=True)
127
+ class DetectorConfig:
128
+ # RAIM: false-alarm prob for the chi-square test on the residual sum-of-squares.
129
+ raim_pfa: float = 1e-3
130
+ raim_sigma_m: float = 3.0 # nominal 1-sigma pseudorange noise [m] (MODELED)
131
+ # AGC/power: a spoofer must overpower; below ~1.5 dB is within nominal AGC drift.
132
+ agc_advantage_db_thresh: float = 1.5 # power-advantage fire threshold [dB]
133
+ agc_nominal_sigma_db: float = 0.4 # nominal AGC fluctuation 1-sigma [dB]
134
+ # SQM: early-minus-late metric is ~0 for a clean symmetric correlation peak.
135
+ sqm_metric_thresh: float = 0.12 # dimensionless asymmetry fire threshold
136
+ sqm_nominal_sigma: float = 0.03 # nominal SQM fluctuation 1-sigma
137
+ # Clock/time: inconsistency between clock-bias leap and position push [m-equiv].
138
+ clock_resid_thresh_m: float = 8.0 # clock-bias/position self-consistency [m]
139
+ clock_nominal_sigma_m: float = 2.0 # nominal clock-residual 1-sigma [m]
140
+ # Fused-confidence floor: ALLOW requires fused confidence >= this AND no fire.
141
+ fused_confidence_floor: float = 0.60
142
+
143
+
144
+ CFG = DetectorConfig()
145
+
146
+
147
+ # --------------------------------------------------------------------------- #
148
+ # Observable container — the parameterised inputs (NOT raw IQ). #
149
+ # --------------------------------------------------------------------------- #
150
+ @dataclass
151
+ class PntObservables:
152
+ """Summary observables a real receiver exposes. NOT baseband IQ."""
153
+ # RAIM layer: per-SV pseudorange residuals [m] after the LS position fix,
154
+ # and the number of redundant SVs (DOF = n_sv - 4 for a 3D+clock fix).
155
+ pr_residuals_m: np.ndarray
156
+ n_sv: int
157
+ # AGC/power layer: estimated received-power advantage of the strongest
158
+ # component over the nominal authentic floor [dB]. ~0 dB when clean.
159
+ power_advantage_db: float = 0.0
160
+ # SQM layer: early-minus-late correlator asymmetry metric (dimensionless),
161
+ # plus a carrier-phase-alignment flag (True => spoofer phase-aligned to truth,
162
+ # which SUPPRESSES SQM asymmetry — the hard, stealthy case).
163
+ sqm_early_minus_late: float = 0.0
164
+ carrier_phase_aligned: bool = False
165
+ # Clock/time layer: the directly-estimated clock-bias leap [m-equiv] and the
166
+ # clock-bias implied by integrating clock drift over the window [m-equiv];
167
+ # their difference is the self-consistency residual. A time-push attack
168
+ # breaks this consistency even with no obvious position jump.
169
+ clock_bias_leap_m: float = 0.0
170
+ clock_drift_implied_m: float = 0.0
171
+
172
+ def __post_init__(self):
173
+ self.pr_residuals_m = np.asarray(self.pr_residuals_m, dtype=float)
174
+
175
+
176
+ # --------------------------------------------------------------------------- #
177
+ # Per-layer result. #
178
+ # --------------------------------------------------------------------------- #
179
+ @dataclass
180
+ class LayerResult:
181
+ name: str
182
+ statistic: float # the calibrated detection statistic
183
+ threshold: float # documented fire threshold for this statistic
184
+ fired: bool # statistic crossed threshold
185
+ confidence: float # in [0,1]: how confident this layer is the fix is CLEAN
186
+ detail: str # human-readable, honest detail
187
+ modeled: bool = True # False => NOT MODELED placeholder
188
+
189
+
190
+ @dataclass
191
+ class SpoofVerdict:
192
+ verdict: str # ALLOW | ADVISORY | DENY
193
+ advisory: bool # Λ is always advisory governance
194
+ detected: bool # True ONLY if >=1 layer fired on a real stat
195
+ fired_layers: list # names of layers that fired
196
+ fused_confidence: float # fused clean-confidence in [0,1]
197
+ layers: list # list[LayerResult] as dicts
198
+ reason: str
199
+ lambda_label: str = LAMBDA_LABEL
200
+ scope_label: str = SCOPE_LABEL
201
+ attribution: dict = field(default_factory=lambda: ATTRIBUTION)
202
+
203
+
204
+ # --------------------------------------------------------------------------- #
205
+ # Layer 1 — multi-SV RAIM consistency (pseudorange-residual chi-square). #
206
+ # --------------------------------------------------------------------------- #
207
+ def _chi2_threshold(dof: int, pfa: float) -> float:
208
+ """Upper-tail chi-square threshold for given DOF and false-alarm prob.
209
+
210
+ Pure-numpy Wilson-Hilferty inverse-CDF approximation (no scipy). The
211
+ chi-square parity test is the textbook RAIM fault-detection statistic:
212
+ a spoofer that is not perfectly self-consistent across SVs inflates the
213
+ sum-of-squared pseudorange residuals beyond the noise-only chi-square tail.
214
+ """
215
+ if dof <= 0:
216
+ return float("inf") # cannot run RAIM without redundancy
217
+ # Standard-normal upper quantile for pfa via inverse erf.
218
+ z = math.sqrt(2.0) * _erfinv(1.0 - 2.0 * pfa) if pfa < 0.5 else 0.0
219
+ # Wilson-Hilferty: chi2 ~ dof*(1 - 2/(9 dof) + z*sqrt(2/(9 dof)))^3
220
+ t = 1.0 - 2.0 / (9.0 * dof) + z * math.sqrt(2.0 / (9.0 * dof))
221
+ return dof * t ** 3
222
+
223
+
224
+ def _erfinv(y: float) -> float:
225
+ """Inverse error function (rational approx, Winitzki). Pure-stdlib."""
226
+ if y <= -1.0:
227
+ return -float("inf")
228
+ if y >= 1.0:
229
+ return float("inf")
230
+ a = 0.147
231
+ ln = math.log(1.0 - y * y)
232
+ term = 2.0 / (math.pi * a) + ln / 2.0
233
+ return math.copysign(math.sqrt(math.sqrt(term * term - ln / a) - term), y)
234
+
235
+
236
+ def raim_layer(obs: PntObservables, cfg: DetectorConfig = CFG) -> LayerResult:
237
+ """RAIM-consistency parity test on pseudorange residuals.
238
+
239
+ Statistic: SSE/sigma^2 ~ chi^2_(n_sv-4). Fires if it exceeds the upper-tail
240
+ threshold at the configured false-alarm probability. DOF = n_sv - 4
241
+ (3 position + 1 clock unknowns). With <5 SVs there is no redundancy ->
242
+ NOT MODELED (cannot run RAIM); we honestly do not fire on it.
243
+ """
244
+ dof = int(obs.n_sv) - 4
245
+ sse = float(np.sum((obs.pr_residuals_m / cfg.raim_sigma_m) ** 2))
246
+ if dof <= 0:
247
+ return LayerResult(
248
+ name="raim_consistency",
249
+ statistic=sse,
250
+ threshold=float("inf"),
251
+ fired=False,
252
+ confidence=0.5, # cannot vouch either way without redundancy
253
+ detail="NOT MODELED: <5 SV, no RAIM redundancy (DOF<=0); cannot test.",
254
+ modeled=False,
255
+ )
256
+ thr = _chi2_threshold(dof, cfg.raim_pfa)
257
+ fired = sse > thr
258
+ # confidence the fix is CLEAN: how far below threshold we sit (smooth).
259
+ conf = float(np.clip(1.0 - sse / (thr + 1e-12), 0.0, 1.0))
260
+ return LayerResult(
261
+ name="raim_consistency",
262
+ statistic=sse,
263
+ threshold=thr,
264
+ fired=fired,
265
+ confidence=conf,
266
+ detail=(f"chi2 parity SSE={sse:.2f} vs thr={thr:.2f} (DOF={dof}, "
267
+ f"Pfa={cfg.raim_pfa:g}); fired={fired}."),
268
+ )
269
+
270
+
271
+ # --------------------------------------------------------------------------- #
272
+ # Layer 2 — AGC / received-power-advantage monitor. #
273
+ # --------------------------------------------------------------------------- #
274
+ def agc_power_layer(obs: PntObservables, cfg: DetectorConfig = CFG) -> LayerResult:
275
+ """Received-power-advantage monitor (AGC-derived).
276
+
277
+ An overpowered spoofer drives the receiver AGC and shows up as a positive
278
+ power advantage in dB over the authentic floor. Statistic is the dB
279
+ advantage; fires above the configured threshold. Power-MATCHED spoofers
280
+ (advantage ~0 dB) intentionally evade this layer — that is the documented
281
+ blind spot SQM/RAIM/clock layers cover (defence-in-depth).
282
+ """
283
+ adv = float(obs.power_advantage_db)
284
+ thr = cfg.agc_advantage_db_thresh
285
+ fired = adv > thr
286
+ # z-score of advantage vs nominal AGC drift -> clean-confidence.
287
+ z = adv / max(cfg.agc_nominal_sigma_db, 1e-9)
288
+ conf = float(np.clip(1.0 - z / 4.0, 0.0, 1.0)) # 4-sigma -> 0 confidence
289
+ return LayerResult(
290
+ name="agc_power_advantage",
291
+ statistic=adv,
292
+ threshold=thr,
293
+ fired=fired,
294
+ confidence=conf,
295
+ detail=(f"power advantage={adv:.2f} dB vs thr={thr:.2f} dB; fired={fired}. "
296
+ f"Power-matched (~0 dB) spoofers evade this layer by design."),
297
+ )
298
+
299
+
300
+ # --------------------------------------------------------------------------- #
301
+ # Layer 3 — SQM (signal-quality / carrier-phase alignment) monitor. #
302
+ # --------------------------------------------------------------------------- #
303
+ def sqm_layer(obs: PntObservables, cfg: DetectorConfig = CFG) -> LayerResult:
304
+ """SQM early-minus-late correlator asymmetry monitor.
305
+
306
+ During a spoofer's code-phase pull-off the authentic and counterfeit
307
+ correlation peaks coexist and distort the correlation function, producing
308
+ a measurable early-minus-late asymmetry. Statistic is the |asymmetry|;
309
+ fires above threshold.
310
+
311
+ HONEST CAVEAT: if the spoofer is carrier-phase-aligned to the truth
312
+ (the stealthy power-matched, phase-aligned case, e.g. TEXBAT ds7), the two
313
+ peaks merge and SQM asymmetry collapses -> this layer cannot fire. We model
314
+ that by suppressing the effective metric when carrier_phase_aligned=True,
315
+ and we say so. That blind spot is precisely why fusion + deny-by-default
316
+ matters; we do NOT pretend SQM caught it.
317
+ """
318
+ raw = abs(float(obs.sqm_early_minus_late))
319
+ # Phase-aligned merge collapses the observable asymmetry.
320
+ eff = 0.0 if obs.carrier_phase_aligned else raw
321
+ thr = cfg.sqm_metric_thresh
322
+ fired = eff > thr
323
+ z = eff / max(cfg.sqm_nominal_sigma, 1e-9)
324
+ conf = float(np.clip(1.0 - z / 4.0, 0.0, 1.0))
325
+ if obs.carrier_phase_aligned:
326
+ detail = ("carrier-phase-aligned: peaks merged, SQM asymmetry suppressed "
327
+ "(eff=0); this layer CANNOT fire on a phase-aligned spoofer.")
328
+ conf = 0.5 # honest: SQM neither vouches nor accuses here
329
+ else:
330
+ detail = (f"SQM early-minus-late |asym|={eff:.3f} vs thr={thr:.3f}; "
331
+ f"fired={fired}.")
332
+ return LayerResult(
333
+ name="sqm_signal_quality",
334
+ statistic=eff,
335
+ threshold=thr,
336
+ fired=fired,
337
+ confidence=conf,
338
+ detail=detail,
339
+ )
340
+
341
+
342
+ # --------------------------------------------------------------------------- #
343
+ # Layer 4 — clock-aided time-spoof monitor. #
344
+ # --------------------------------------------------------------------------- #
345
+ def clock_time_layer(obs: PntObservables, cfg: DetectorConfig = CFG) -> LayerResult:
346
+ """Clock-bias vs position-push self-consistency (time-spoof) monitor.
347
+
348
+ A time-push attack injects a clock-bias leap that is NOT consistent with the
349
+ clock bias implied by integrating the receiver's own clock drift. The
350
+ self-consistency residual |clock_bias_leap - clock_drift_implied| (in
351
+ metre-equivalents, 1 ns ~ 0.2998 m) is the statistic; fires above threshold.
352
+ This is the layer that catches a stealthy time-only push that leaves the
353
+ position solution and power untouched.
354
+ """
355
+ resid = abs(float(obs.clock_bias_leap_m) - float(obs.clock_drift_implied_m))
356
+ thr = cfg.clock_resid_thresh_m
357
+ fired = resid > thr
358
+ z = resid / max(cfg.clock_nominal_sigma_m, 1e-9)
359
+ conf = float(np.clip(1.0 - z / 4.0, 0.0, 1.0))
360
+ return LayerResult(
361
+ name="clock_time_spoof",
362
+ statistic=resid,
363
+ threshold=thr,
364
+ fired=fired,
365
+ confidence=conf,
366
+ detail=(f"clock-bias/position self-consistency residual={resid:.2f} m "
367
+ f"vs thr={thr:.2f} m; fired={fired}."),
368
+ )
369
+
370
+
371
+ # --------------------------------------------------------------------------- #
372
+ # Λ-gate-style fusion governor — DENY-BY-DEFAULT. #
373
+ # --------------------------------------------------------------------------- #
374
+ def fuse(layers: list, cfg: DetectorConfig = CFG) -> SpoofVerdict:
375
+ """Fuse independent monitor layers under a deny-by-default Λ governor.
376
+
377
+ POLICY (deny-by-default):
378
+ * If ANY layer fired on a real triggering statistic -> DENY (detected=True).
379
+ * Else if fused clean-confidence >= floor -> ALLOW (advisory).
380
+ * Else (no fire, but weak/ambiguous confidence) -> ADVISORY (hold).
381
+
382
+ Fused clean-confidence is the MINIMUM across MODELED layers (a chain is only
383
+ as trustworthy as its weakest honest monitor) blended toward the mean; using
384
+ the min keeps the gate conservative. NOT-MODELED layers are excluded from the
385
+ confidence floor (we don't let an un-runnable layer manufacture trust) but a
386
+ record is NEVER marked detected without a real fire.
387
+ """
388
+ fired = [L.name for L in layers if L.fired]
389
+ modeled_conf = [L.confidence for L in layers if L.modeled]
390
+ if modeled_conf:
391
+ # conservative blend: weight the weakest layer heavily.
392
+ fused_conf = 0.7 * min(modeled_conf) + 0.3 * float(np.mean(modeled_conf))
393
+ else:
394
+ fused_conf = 0.0 # nothing runnable -> cannot vouch -> deny-by-default holds
395
+
396
+ if fired:
397
+ verdict = VERDICT_DENY
398
+ detected = True
399
+ reason = (f"DENY (deny-by-default): {len(fired)} monitor layer(s) fired "
400
+ f"-> {', '.join(fired)}. Λ advisory: spoof indicated.")
401
+ elif fused_conf >= cfg.fused_confidence_floor:
402
+ verdict = VERDICT_ALLOW
403
+ detected = False
404
+ reason = (f"ALLOW: no layer fired and fused clean-confidence "
405
+ f"{fused_conf:.2f} >= floor {cfg.fused_confidence_floor:.2f}. "
406
+ f"Λ advisory ONLY — not proven trust.")
407
+ else:
408
+ verdict = VERDICT_ADVISORY
409
+ detected = False
410
+ reason = (f"ADVISORY HOLD (deny-by-default): no layer fired but fused "
411
+ f"clean-confidence {fused_conf:.2f} < floor "
412
+ f"{cfg.fused_confidence_floor:.2f}; insufficient evidence to ALLOW.")
413
+
414
+ return SpoofVerdict(
415
+ verdict=verdict,
416
+ advisory=True, # Λ is ALWAYS advisory governance
417
+ detected=detected,
418
+ fired_layers=fired,
419
+ fused_confidence=float(fused_conf),
420
+ layers=[asdict(L) for L in layers],
421
+ reason=reason,
422
+ )
423
+
424
+
425
+ def detect(obs: PntObservables, cfg: DetectorConfig = CFG) -> SpoofVerdict:
426
+ """Run all four independent layers and fuse under the deny-by-default Λ gate."""
427
+ layers = [
428
+ raim_layer(obs, cfg),
429
+ agc_power_layer(obs, cfg),
430
+ sqm_layer(obs, cfg),
431
+ clock_time_layer(obs, cfg),
432
+ ]
433
+ return fuse(layers, cfg)
434
+
435
+
436
+ # --------------------------------------------------------------------------- #
437
+ # TEXBAT-style scenario parameterisation. #
438
+ # --------------------------------------------------------------------------- #
439
+ @dataclass
440
+ class TexbatScenario:
441
+ """A TEXBAT-style record described by the three classifier knobs the
442
+ literature uses: power advantage (dB), carrier-phase alignment, and
443
+ time/position push. We map those knobs onto receiver observables. These
444
+ numbers are MODELED parameterisations of the published record classes
445
+ (Humphreys 2012; ION 2016 hi-fi analysis), NOT measured IQ captures.
446
+ """
447
+ name: str
448
+ power_advantage_db: float
449
+ carrier_phase_aligned: bool
450
+ position_push_m: float # how hard the fix is pulled in space [m]
451
+ time_push_m: float # clock-bias leap injected [m-equiv]
452
+ description: str = ""
453
+
454
+
455
+ # Canonical TEXBAT-style classes (parameterised from the cited characterisations).
456
+ TEXBAT_LIBRARY = {
457
+ "clean": TexbatScenario(
458
+ name="clean", power_advantage_db=0.0, carrier_phase_aligned=False,
459
+ position_push_m=0.0, time_push_m=0.0,
460
+ description="Authentic signal, no spoofer. Expect ALLOW.",
461
+ ),
462
+ "ds2_time_push": TexbatScenario(
463
+ name="ds2_time_push", power_advantage_db=8.0, carrier_phase_aligned=False,
464
+ position_push_m=0.0, time_push_m=40.0,
465
+ description="Overpowered time-push, no phase alignment (TEXBAT ds2 class).",
466
+ ),
467
+ "ds3_overpower": TexbatScenario(
468
+ name="ds3_overpower", power_advantage_db=10.0, carrier_phase_aligned=False,
469
+ position_push_m=60.0, time_push_m=0.0,
470
+ description="Gradual/strong power-advantage takeover (TEXBAT ds3 class).",
471
+ ),
472
+ "ds4_seamless": TexbatScenario(
473
+ name="ds4_seamless", power_advantage_db=2.0, carrier_phase_aligned=False,
474
+ position_push_m=80.0, time_push_m=0.0,
475
+ description="Seamless lift-off; modest power, code-phase pull (ds4 class).",
476
+ ),
477
+ "ds7_matched_aligned": TexbatScenario(
478
+ name="ds7_matched_aligned", power_advantage_db=0.4,
479
+ carrier_phase_aligned=True, position_push_m=70.0, time_push_m=0.0,
480
+ description=("Power-matched, carrier-phase-aligned stealth spoof "
481
+ "(TEXBAT ds7 class) — defeats AGC and SQM; caught only by "
482
+ "RAIM-consistency parity on the position push."),
483
+ ),
484
+ }
485
+
486
+
487
+ def observables_from_scenario(sc: TexbatScenario, n_sv: int = 8,
488
+ seed: int = 0,
489
+ cfg: DetectorConfig = CFG) -> PntObservables:
490
+ """Synthesise parameterised observables for a TEXBAT-style scenario.
491
+
492
+ Mapping (MODELED, documented):
493
+ * position_push -> inflates pseudorange residuals (RAIM sees inconsistency).
494
+ A counterfeit constellation that pushes the fix by D metres leaves a
495
+ residual signature ~ D scattered across SVs; we model the per-SV residual
496
+ as nominal noise + a push-driven inconsistency term.
497
+ * power_advantage_db -> AGC layer observable directly.
498
+ * code-phase pull -> SQM early-minus-late asymmetry, UNLESS phase-aligned.
499
+ * time_push -> clock-bias leap inconsistent with clock-drift integration.
500
+ """
501
+ rng = np.random.default_rng(seed)
502
+ # Nominal clean residuals: zero-mean Gaussian at the modelled sigma.
503
+ resid = rng.normal(0.0, cfg.raim_sigma_m, size=n_sv)
504
+ if sc.position_push_m > 0:
505
+ # A spoofer pulling the fix injects a coherent-but-inconsistent push:
506
+ # part of it is absorbed by the LS fix, the inconsistent remainder
507
+ # (~30% of the push, spread over redundant SVs) shows in residuals.
508
+ inconsistency = 0.30 * sc.position_push_m
509
+ push_sig = rng.normal(0.0, inconsistency / math.sqrt(max(n_sv, 1)), size=n_sv)
510
+ resid = resid + push_sig + inconsistency / n_sv
511
+ # SQM asymmetry tracks the code-phase pull; scale with position push,
512
+ # suppressed if phase-aligned (handled inside sqm_layer too).
513
+ sqm_metric = 0.0
514
+ if sc.position_push_m > 0 and not sc.carrier_phase_aligned:
515
+ sqm_metric = min(0.5, 0.004 * sc.position_push_m + abs(rng.normal(0, 0.01)))
516
+ # Clock: bias leap = time_push; drift-implied stays at the clean value.
517
+ clock_leap = sc.time_push_m + rng.normal(0.0, cfg.clock_nominal_sigma_m * 0.3)
518
+ clock_drift_implied = rng.normal(0.0, cfg.clock_nominal_sigma_m * 0.3)
519
+ return PntObservables(
520
+ pr_residuals_m=resid,
521
+ n_sv=n_sv,
522
+ power_advantage_db=sc.power_advantage_db + rng.normal(0, cfg.agc_nominal_sigma_db * 0.2),
523
+ sqm_early_minus_late=sqm_metric,
524
+ carrier_phase_aligned=sc.carrier_phase_aligned,
525
+ clock_bias_leap_m=clock_leap,
526
+ clock_drift_implied_m=clock_drift_implied,
527
+ )
528
+
529
+
530
+ def assess_scenario(sc: TexbatScenario, n_sv: int = 8, seed: int = 0,
531
+ cfg: DetectorConfig = CFG) -> SpoofVerdict:
532
+ """Convenience: parameterise a TEXBAT-style record and run the fused detector."""
533
+ obs = observables_from_scenario(sc, n_sv=n_sv, seed=seed, cfg=cfg)
534
+ return detect(obs, cfg)
535
+
536
+
537
+ # --------------------------------------------------------------------------- #
538
+ # Demo / CLI. #
539
+ # --------------------------------------------------------------------------- #
540
+ def _print_verdict(name: str, v: SpoofVerdict) -> None:
541
+ print(f"\n=== {name} ===")
542
+ print(f" verdict : {v.verdict} (detected={v.detected}, advisory={v.advisory})")
543
+ print(f" fired : {v.fired_layers or 'none'}")
544
+ print(f" fused conf: {v.fused_confidence:.3f}")
545
+ for L in v.layers:
546
+ flag = "FIRE" if L["fired"] else ("n/m" if not L["modeled"] else "ok ")
547
+ print(f" [{flag}] {L['name']:<22} stat={L['statistic']:.3f} "
548
+ f"thr={L['threshold']:.3f}")
549
+ print(f" reason : {v.reason}")
550
+
551
+
552
+ if __name__ == "__main__":
553
+ print("SZL PNT-RESILIENCE — fused deny-by-default GNSS spoof detector")
554
+ print(SCOPE_LABEL)
555
+ print(LAMBDA_LABEL)
556
+ for key, sc in TEXBAT_LIBRARY.items():
557
+ v = assess_scenario(sc, seed=42)
558
+ _print_verdict(f"{sc.name} — {sc.description}", v)
quantum_sensing_limits.py ADDED
@@ -0,0 +1,614 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Doctrine v11 LOCKED · Λ = Conjecture 1 (advisory, NOT proven trust)
3
+ # Sign-off: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
4
+ """quantum_sensing_limits — FUNDAMENTAL-LIMITS CERTIFIER for a cold-atom interferometer.
5
+
6
+ THE SECOND PILLAR (founder's doctrine): next to ``physics_bounds.py`` — which proves a
7
+ *compute* job sits below the Landauer/Margolus-Levitin/Bremermann/Bekenstein ceilings —
8
+ this module proves a *quantum sensor's* noise floor is set by, and sits at or above, the
9
+ STANDARD QUANTUM LIMIT (shot / atom-projection noise). Same philosophy: derive performance
10
+ from first-principles physics, certify it, label MEASURED vs MODELED, never fabricate.
11
+
12
+ This is a CLEAN-ROOM SZL-NATIVE re-derivation of the cold-atom interferometer (CAI)
13
+ accelerometer physics. The METHOD/structure (a first-principles CAI noise model rather
14
+ than a datasheet lookup) is cited to AshfordeOU/kshana (Apache-2.0, DOI
15
+ 10.5281/zenodo.20528627). NO kshana Rust source is copied; only the established physics
16
+ below is implemented, in our own Python. The physics itself is ESTABLISHED and CITED to
17
+ the original papers — it is NOT claimed as SZL's:
18
+
19
+ * Kasevich & Chu (1991): light-pulse (stimulated-Raman) atom interferometry; the
20
+ three-pulse (π/2 – π – π/2) Mach-Zehnder geometry as an inertial sensor.
21
+ * Peters, Chung & Chu (2001): high-precision absolute gravimetry with a CAI;
22
+ Φ = k_eff·a·T² scaling and systematic-effect accounting.
23
+ * Cheinet et al. (2008): the sensitivity function g(t) and the vibration/laser-phase
24
+ transfer function |H(ω)| = (4/ω²)·sin²(ωT/2); white-acceleration-noise phase
25
+ variance σ_Φ² = k_eff²·S_a·T³/3.
26
+ * Freier et al. (2016): mobile/transportable quantum gravimeter — ASD figure-of-merit
27
+ n_a = σ_a·√T_c, the real-device performance metric.
28
+
29
+ HONESTY (Doctrine v11, HARD): every INPUT is labelled MEASURED (only if it came from a
30
+ real instrument reading) vs the DERIVED/MODELED limits. We assert NO measured quantity we
31
+ did not receive. We NEVER fabricate numbers. We make NO over-unity / sub-shot-noise
32
+ ("squeezed beyond physics") claim — the certificate is the HONEST INVERSE of a free-energy
33
+ claim: it states the sensor is BOUNDED by the standard quantum limit. A maintained
34
+ "NOT MODELED" list names the systematics this engine does NOT capture, so the certificate
35
+ can never be mistaken for a full error budget. Λ is advisory: this states physical FACTS,
36
+ not "proven trust".
37
+
38
+ Pure stdlib + math (numpy optional) → sovereign, own-metal, auditable. Real instrument
39
+ inputs feed in via ``MeasuredSensor``; in-sandbox we use HONEST, CLEARLY-LABELLED sample
40
+ inputs. Designed to UNIFY with physics_bounds.py into one SZL "fundamental-limits" library
41
+ (compute-bounds pillar + sensing-limits pillar).
42
+ """
43
+ from __future__ import annotations
44
+
45
+ import hashlib
46
+ import json
47
+ import math
48
+ import time
49
+ from dataclasses import asdict, dataclass, field
50
+ from typing import Optional
51
+
52
+ # --------------------------------------------------------------------------- #
53
+ # Fundamental physical constants (SI, CODATA-style). Exact where SI defines. #
54
+ # Shared, byte-for-byte, with physics_bounds.py so the two pillars unify. #
55
+ # --------------------------------------------------------------------------- #
56
+ K_B = 1.380649e-23 # Boltzmann constant, J/K (SI exact)
57
+ H_PLANCK = 6.62607015e-34 # Planck constant, J·s (SI exact)
58
+ HBAR = H_PLANCK / (2.0 * math.pi)
59
+ C_LIGHT = 299792458.0 # speed of light, m/s (SI exact)
60
+ PI = math.pi
61
+
62
+ # Provenance: this is ESTABLISHED CAI physics, CITED — NOT claimed as SZL's. The METHOD
63
+ # (first-principles CAI noise model) is cited to kshana (Apache-2.0); only physics is used.
64
+ SENSING_ATTRIBUTION = {
65
+ "method_source_kshana": (
66
+ "AshfordeOU/kshana — open PNT-resilience simulator (Apache-2.0, "
67
+ "DOI:10.5281/zenodo.20528627). Cited as the METHOD source: a first-principles "
68
+ "cold-atom interferometer accelerometer noise model (src/inertial/quantum_imu.rs). "
69
+ "SZL re-derived the physics CLEAN-ROOM in Python; NO kshana Rust source is copied."
70
+ ),
71
+ "kasevich_chu_1991": (
72
+ "Kasevich, M. & Chu, S. (1991), 'Atomic interferometry using stimulated Raman "
73
+ "transitions', Phys. Rev. Lett. 67(2):181-184, doi:10.1103/PhysRevLett.67.181. "
74
+ "Light-pulse (π/2–π–π/2) Mach-Zehnder atom interferometer as an inertial sensor; "
75
+ "effective two-photon wavevector k_eff and the phase response to acceleration."
76
+ ),
77
+ "peters_2001": (
78
+ "Peters, A., Chung, K.Y. & Chu, S. (2001), 'High-precision gravity measurements "
79
+ "using atom interferometry', Metrologia 38(1):25-61, doi:10.1088/0026-1394/38/1/4 "
80
+ "(see also Nature 400:849, 1999). Interferometer phase Φ = k_eff·a·T² with the T² "
81
+ "interrogation-time lever; systematic-effect accounting for absolute gravimetry."
82
+ ),
83
+ "cheinet_2008": (
84
+ "Cheinet, P., Canuel, B., Pereira Dos Santos, F., Gauguet, A., Yver-Leduc, F. & "
85
+ "Landragin, A. (2008), 'Measurement of the sensitivity function in a time-domain "
86
+ "atomic interferometer', IEEE Trans. Instrum. Meas. 57(6):1141-1148, "
87
+ "doi:10.1109/TIM.2007.915148. Sensitivity function g(t); acceleration transfer "
88
+ "function |H(ω)| = (4/ω²)·sin²(ωT/2); white-noise phase variance "
89
+ "σ_Φ² = k_eff²·S_a·T³/3 (dominant real-device vibration term)."
90
+ ),
91
+ "freier_2016": (
92
+ "Freier, C., Hauth, M., Schkolnik, V., Leykauf, B., Schilling, M., Wziontek, H., "
93
+ "Scherneck, H.-G., Müller, J. & Peters, A. (2016), 'Mobile quantum gravity sensor "
94
+ "with unprecedented stability', J. Phys.: Conf. Ser. 723:012050, "
95
+ "doi:10.1088/1742-6596/723/1/012050. Transportable CAI; amplitude spectral "
96
+ "density n_a = σ_a·√T_c as the real-device figure of merit."
97
+ ),
98
+ "standard_quantum_limit": (
99
+ "Shot / atom-projection noise: for N uncorrelated atoms read out with fringe "
100
+ "contrast C, the minimum resolvable interferometer phase is σ_Φ = 1/(C·√N). This "
101
+ "is the STANDARD QUANTUM LIMIT (SQL). Surpassing it requires entanglement/spin "
102
+ "squeezing (Wineland 1992, Kitagawa-Ueda 1993) — explicitly NOT modeled here."
103
+ ),
104
+ "honesty": (
105
+ "These are ESTABLISHED physics relations, cited by source. They are NOT SZL "
106
+ "conjectures and NOT claimed as SZL's. This certificate is the HONEST INVERSE of "
107
+ "a free-energy claim: it shows the sensor is BOUNDED by the standard quantum "
108
+ "limit, asserts no sub-SQL/over-unity performance, fabricates no number, and "
109
+ "carries an explicit NOT-MODELED list so it is never mistaken for a full budget."
110
+ ),
111
+ }
112
+
113
+ DOCTRINE = (
114
+ "v11 LOCKED: NO free-energy/over-unity and NO sub-standard-quantum-limit claim (this "
115
+ "certificate shows the sensor is BOUNDED by the SQL — the honest inverse); a value is "
116
+ "labelled MEASURED ONLY if it came from a real instrument reading, else MODELED/DERIVED; "
117
+ "established CAI physics is CITED (Kasevich-Chu 1991, Peters 2001, Cheinet 2008, Freier "
118
+ "2016), method cited to kshana (Apache-2.0), NOT claimed as SZL's; an explicit NOT-MODELED "
119
+ "list is carried; Λ=Conjecture 1 (advisory); sovereign own-metal; no fabricated numbers."
120
+ )
121
+
122
+ # Systematics this first-principles engine does NOT capture. Carried in every certificate
123
+ # so a reader can NEVER mistake the SQL/vibration figure for a complete error budget.
124
+ NOT_MODELED = [
125
+ "Laser phase noise of the Raman/Bragg beams (frequency-comb / OPLL residual) — a "
126
+ "leading real-device noise term; couples through the SAME |H(ω)| as vibration "
127
+ "(Cheinet 2008) but its drive PSD S_φ(ω) is an instrument property not modeled here.",
128
+ "AC-Stark / light-shift systematics (one-photon and two-photon light shifts) and their "
129
+ "intensity/detuning dependence — a dominant ACCURACY (bias) term, not modeled.",
130
+ "Full 3-axis mechanization / strapdown coupling, gravity-gradient & rotation-rate "
131
+ "cross terms beyond the single Coriolis lead term, and platform attitude dynamics.",
132
+ "Detection (electronic/technical) noise, atom-number normalization noise, and "
133
+ "intensity noise of the readout — separate from the SQL atom-projection floor.",
134
+ "Wavefront aberration / Coriolis-from-transverse-velocity beyond the lead Φ_cor term, "
135
+ "magnetic-field (2nd-order Zeeman) gradients, blackbody/AC-Stark drifts, and aliasing "
136
+ "of high-frequency vibration through the finite duty cycle (Dick effect).",
137
+ "Mean-field / cold-collision shifts, finite-pulse-duration corrections to g(t), and "
138
+ "any spin-squeezing/entanglement enhancement BELOW the SQL (explicitly out of scope).",
139
+ ]
140
+
141
+
142
+ # --------------------------------------------------------------------------- #
143
+ # MEASURED inputs (clearly labelled) — fed by a real instrument or honest sample #
144
+ # --------------------------------------------------------------------------- #
145
+ @dataclass
146
+ class MeasuredSensor:
147
+ """Inputs describing one cold-atom interferometer operating point.
148
+
149
+ HONESTY RULE: a field is MEASURED ONLY if it is a real reading from the instrument
150
+ (e.g. observed fringe contrast, counted atom number, recorded cycle time, measured
151
+ vibration PSD). Design/spec parameters (wavelength, interrogation time setpoint) are
152
+ CONFIG. ``label`` records which: "MEASURED" (real instrument) vs "SAMPLE"/"DESIGN"
153
+ (honest, clearly-labelled placeholder). The certifier validates these before use and
154
+ NEVER silently promotes a garbage/placeholder input to "MEASURED".
155
+ """
156
+ wavelength_m: float # Raman/Bragg optical wavelength λ (m) — CONFIG
157
+ interrogation_time_s: float # interferometer pulse separation T (s) — CONFIG/MEASURED
158
+ atom_number: float # N atoms contributing to the fringe — MEASURED count
159
+ contrast: float # fringe contrast C in [0,1] — MEASURED
160
+ cycle_time_s: float # T_c, full measurement cycle time (s) — MEASURED
161
+ accel_psd: float # S_a, vibration acceleration PSD (m²/s⁴/Hz) — MEASURED
162
+ accel_input: Optional[float] = None # a, true input acceleration (m/s²) if known
163
+ omega_rad_s: float = 2.0 * math.pi # ω for transfer-function eval (rad/s) — CONFIG
164
+ transverse_velocity_ms: float = 0.0 # v_⊥ for Coriolis term (m/s) — MEASURED
165
+ rotation_rate_rad_s: float = 0.0 # Ω, platform rotation rate (rad/s) — MEASURED
166
+ contrast0: Optional[float] = None # C₀ initial contrast for decay model — CONFIG
167
+ coherence_time_s: Optional[float] = None # τ_c contrast-decay time const (s) — MEASURED
168
+ label: str = "MEASURED" # MEASURED (real instrument) | SAMPLE | DESIGN (honest)
169
+ source: str = "unspecified" # e.g. "cai-readout", "honest-sample"
170
+ note: str = ""
171
+
172
+ def measured_accel(self, label_is_measured: bool) -> Optional[float]:
173
+ """Return accel_input ONLY if it is a genuine instrument reading (label MEASURED).
174
+ Otherwise None — a MODELED accel must NOT be reported as MEASURED.
175
+ """
176
+ if self.accel_input is None:
177
+ return None
178
+ return self.accel_input if label_is_measured else None
179
+
180
+
181
+ # --------------------------------------------------------------------------- #
182
+ # First-principles relations (all DERIVED / MODELED from the inputs) #
183
+ # Each function names its citation in the docstring. #
184
+ # --------------------------------------------------------------------------- #
185
+ def k_eff(wavelength_m: float) -> float:
186
+ """Effective two-photon wavevector k_eff = 4π/λ.
187
+
188
+ Kasevich-Chu (1991): a stimulated-Raman π/2–π–π/2 sequence imparts two photon recoils
189
+ per pulse, so the effective momentum kick uses k_eff = 2·k_photon = 2·(2π/λ) = 4π/λ.
190
+ """
191
+ if not (wavelength_m > 0.0):
192
+ raise ValueError("wavelength_m must be > 0")
193
+ return 4.0 * PI / wavelength_m
194
+
195
+
196
+ def mach_zehnder_phase(keff: float, accel: float, T: float) -> float:
197
+ """Mach-Zehnder interferometer phase Φ = k_eff·a·T².
198
+
199
+ Peters et al. (2001) / Kasevich-Chu (1991): for the three-pulse geometry the leading
200
+ inertial phase shift is k_eff·a·T², where T is the pulse separation (interrogation
201
+ time). The T² dependence is the interrogation-time lever that drives sensitivity.
202
+ """
203
+ return keff * accel * T * T
204
+
205
+
206
+ def shot_noise_phase(contrast: float, atom_number: float) -> float:
207
+ """Standard-quantum-limit phase noise σ_Φ = 1/(C·√N).
208
+
209
+ Atom-projection (shot) noise: N uncorrelated atoms read out at fringe contrast C give
210
+ a minimum resolvable phase 1/(C·√N). This is the SQL; sub-SQL needs entanglement and
211
+ is explicitly NOT modeled (see NOT_MODELED).
212
+ """
213
+ if not (contrast > 0.0):
214
+ raise ValueError("contrast must be > 0 for a defined shot-noise limit")
215
+ if not (atom_number > 0.0):
216
+ raise ValueError("atom_number must be > 0")
217
+ return 1.0 / (contrast * math.sqrt(atom_number))
218
+
219
+
220
+ def accel_sensitivity_per_shot(sigma_phi: float, keff: float, T: float) -> float:
221
+ """Per-shot acceleration sensitivity σ_a = σ_Φ / (k_eff·T²).
222
+
223
+ Invert the Mach-Zehnder phase response (Peters 2001): a phase uncertainty σ_Φ maps to
224
+ an acceleration uncertainty σ_Φ/(k_eff·T²) per measurement shot.
225
+ """
226
+ denom = keff * T * T
227
+ if not (denom > 0.0):
228
+ raise ValueError("k_eff·T² must be > 0")
229
+ return sigma_phi / denom
230
+
231
+
232
+ def asd_accel(sigma_a: float, cycle_time_s: float) -> float:
233
+ """Amplitude spectral density n_a = σ_a·√T_c (units m/s²/√Hz).
234
+
235
+ Freier et al. (2016): the real-device figure of merit. A per-shot uncertainty σ_a at a
236
+ cycle time T_c corresponds to an acceleration ASD of σ_a·√T_c. The PSD is n_a².
237
+ """
238
+ if not (cycle_time_s > 0.0):
239
+ raise ValueError("cycle_time_s must be > 0")
240
+ return sigma_a * math.sqrt(cycle_time_s)
241
+
242
+
243
+ def contrast_decay(contrast0: float, t: float, tau_c: float) -> float:
244
+ """Contrast decay C(t) = C₀·exp(−t/τ_c).
245
+
246
+ Empirical/decoherence loss-of-fringe-visibility model: contrast decays exponentially
247
+ with a coherence time τ_c (dephasing, expansion, finite detection). Used to model how
248
+ contrast — and hence the SQL phase noise σ_Φ = 1/(C·√N) — degrades with T.
249
+ """
250
+ if not (tau_c > 0.0):
251
+ raise ValueError("tau_c must be > 0")
252
+ return contrast0 * math.exp(-t / tau_c)
253
+
254
+
255
+ def vibration_transfer_magnitude(omega: float, T: float) -> float:
256
+ """Acceleration transfer-function magnitude |H(ω)| = (4/ω²)·sin²(ωT/2).
257
+
258
+ Cheinet et al. (2008): Fourier transform of the three-pulse sensitivity function gives
259
+ the interferometer's response to acceleration/phase noise at angular frequency ω. The
260
+ low-frequency limit |H| → T² recovers the DC Mach-Zehnder response.
261
+ """
262
+ if not (omega > 0.0):
263
+ raise ValueError("omega must be > 0 for the transfer function")
264
+ return (4.0 / (omega * omega)) * (math.sin(omega * T / 2.0) ** 2)
265
+
266
+
267
+ def vibration_phase_variance(keff: float, accel_psd: float, T: float) -> float:
268
+ """White-acceleration-noise phase variance σ_Φ² = k_eff²·S_a·T³/3.
269
+
270
+ Cheinet et al. (2008): integrating the squared acceleration transfer function against a
271
+ WHITE acceleration PSD S_a yields k_eff²·S_a·T³/3. This is the dominant real-device
272
+ (vibration-limited) phase-noise term in unshielded operation.
273
+ """
274
+ return keff * keff * accel_psd * (T ** 3) / 3.0
275
+
276
+
277
+ def coriolis_phase(keff: float, v_perp: float, omega_rot: float, T: float) -> float:
278
+ """Coriolis (rotation) phase Φ_cor = 2·k_eff·v_⊥·Ω·T².
279
+
280
+ Peters et al. (2001) / Kasevich-Chu (1991): a transverse atom velocity v_⊥ in a frame
281
+ rotating at Ω produces a Coriolis acceleration that biases the interferometer by
282
+ 2·k_eff·v_⊥·Ω·T². This is the LEAD rotation term only; full 3-axis rotation coupling
283
+ is NOT modeled (see NOT_MODELED).
284
+ """
285
+ return 2.0 * keff * v_perp * omega_rot * T * T
286
+
287
+
288
+ # --------------------------------------------------------------------------- #
289
+ # The QUANTUM-SENSING-LIMITS CERTIFICATE #
290
+ # --------------------------------------------------------------------------- #
291
+ @dataclass
292
+ class QuantumSensingCertificate:
293
+ """Signer-ready certificate. MEASURED inputs vs MODELED limits, clearly split.
294
+
295
+ Every numeric field carries an explicit role: a value derived from a MEASURED input is
296
+ MODELED (computed via a cited formula); only echoed instrument readings are MEASURED.
297
+ """
298
+ certificate_type: str
299
+ # --- inputs echoed, each tagged MEASURED or CONFIG/SAMPLE ---
300
+ inputs: dict
301
+ # --- MODELED first-principles limits (all DERIVED from inputs via cited formulas) ---
302
+ k_eff_per_m: float # MODELED: 4π/λ
303
+ mz_phase_per_unit_accel_rad: float # MODELED: k_eff·T² (phase per 1 m/s²)
304
+ mz_phase_modeled_rad: Optional[float] # MODELED iff an accel input was provided
305
+ accel_was_measured: bool # True only if accel came from a real reading
306
+ shot_noise_phase_rad: float # MODELED: σ_Φ = 1/(C·√N) (SQL)
307
+ accel_sensitivity_per_shot: float # MODELED: σ_a = σ_Φ/(k_eff·T²)
308
+ accel_asd: float # MODELED: n_a = σ_a·√T_c (m/s²/√Hz)
309
+ accel_psd_from_asd: float # MODELED: n_a²
310
+ vibration_transfer_magnitude: float # MODELED: |H(ω)| at the eval ω
311
+ vibration_phase_variance: float # MODELED: k_eff²·S_a·T³/3
312
+ vibration_phase_rms_rad: float # MODELED: sqrt of the above
313
+ coriolis_phase_rad: float # MODELED: 2·k_eff·v_⊥·Ω·T²
314
+ contrast_at_T: Optional[float] # MODELED iff a decay model (C₀,τ_c) was given
315
+ # --- honest verdict ---
316
+ at_or_above_standard_quantum_limit: bool # noise floor not claimed below the SQL
317
+ summary: str
318
+ not_modeled: list = field(default_factory=lambda: list(NOT_MODELED))
319
+ attribution: dict = field(default_factory=lambda: SENSING_ATTRIBUTION)
320
+ doctrine: str = DOCTRINE
321
+ honest_inverse_of_free_energy: bool = True
322
+ labels: dict = field(default_factory=lambda: {
323
+ "MEASURED": "a real reading from the instrument (contrast, atom count, cycle time, "
324
+ "vibration PSD, etc.) — NEVER a placeholder or modeled value",
325
+ "MODELED": "computed from inputs via a CITED established-physics formula",
326
+ "CONFIG": "a design/setpoint parameter (wavelength, T setpoint), not a reading",
327
+ })
328
+ lambda_note: str = ("Λ = Conjecture 1 (advisory). This certificate states physical "
329
+ "FACTS (limits), not 'proven trust'. It makes NO sub-SQL / "
330
+ "over-unity claim and carries an explicit NOT-MODELED list.")
331
+ inputs_hash: str = ""
332
+ timestamp_utc: float = 0.0
333
+ signature: None = None
334
+
335
+ def to_json(self, indent: int = 2) -> str:
336
+ return json.dumps(asdict(self), indent=indent, default=str)
337
+
338
+
339
+ def _hash_inputs(sensor: MeasuredSensor) -> str:
340
+ canon = json.dumps(asdict(sensor), sort_keys=True, separators=(",", ":"), default=str)
341
+ return "sha256:" + hashlib.sha256(canon.encode()).hexdigest()
342
+
343
+
344
+ # Accept only these honest labels for a value to be treated as a real instrument reading.
345
+ _MEASURED_LABELS = {"MEASURED"}
346
+
347
+
348
+ def _validate_sensor(sensor: MeasuredSensor) -> list:
349
+ """Return a list of HONESTY/physics problems. Empty list ⇒ inputs are usable.
350
+
351
+ This is the guard that prevents a fabricated/garbage input from being silently
352
+ accepted and labelled MEASURED. It checks finiteness, physical ranges, and label sanity.
353
+ """
354
+ problems = []
355
+
356
+ def _finite_pos(name, val, allow_zero=False):
357
+ if val is None:
358
+ return
359
+ if isinstance(val, bool) or not isinstance(val, (int, float)):
360
+ problems.append(f"{name} is not a real number ({val!r})")
361
+ return
362
+ if not math.isfinite(val):
363
+ problems.append(f"{name} is not finite ({val!r}) — fabricated/garbage input")
364
+ return
365
+ if val < 0 or (val == 0 and not allow_zero):
366
+ problems.append(f"{name} is out of physical range ({val!r})")
367
+
368
+ _finite_pos("wavelength_m", sensor.wavelength_m)
369
+ _finite_pos("interrogation_time_s", sensor.interrogation_time_s)
370
+ _finite_pos("atom_number", sensor.atom_number)
371
+ _finite_pos("cycle_time_s", sensor.cycle_time_s)
372
+ _finite_pos("accel_psd", sensor.accel_psd, allow_zero=True)
373
+ _finite_pos("omega_rad_s", sensor.omega_rad_s)
374
+ # contrast must be a real fraction in (0, 1]
375
+ c = sensor.contrast
376
+ if isinstance(c, bool) or not isinstance(c, (int, float)) or not math.isfinite(c):
377
+ problems.append(f"contrast is not a finite number ({c!r}) — fabricated/garbage")
378
+ elif not (0.0 < c <= 1.0):
379
+ problems.append(f"contrast {c!r} is outside the physical fringe range (0, 1]")
380
+ # optional fields that, if present, must be finite real numbers
381
+ for nm, v in (("accel_input", sensor.accel_input),
382
+ ("transverse_velocity_ms", sensor.transverse_velocity_ms),
383
+ ("rotation_rate_rad_s", sensor.rotation_rate_rad_s),
384
+ ("coherence_time_s", sensor.coherence_time_s),
385
+ ("contrast0", sensor.contrast0)):
386
+ if v is not None and (isinstance(v, bool) or not isinstance(v, (int, float))
387
+ or not math.isfinite(v)):
388
+ problems.append(f"{nm} is not a finite number ({v!r}) — fabricated/garbage")
389
+ # label sanity: a value can only be MEASURED under an honest measured label
390
+ if sensor.label not in _MEASURED_LABELS | {"SAMPLE", "DESIGN"}:
391
+ problems.append(
392
+ f"label {sensor.label!r} is not an allowed honest label "
393
+ f"(MEASURED | SAMPLE | DESIGN)"
394
+ )
395
+ return problems
396
+
397
+
398
+ def _rejected_certificate(sensor: MeasuredSensor, problems: list,
399
+ msg: str) -> QuantumSensingCertificate:
400
+ """Build a clearly-REJECTED certificate for fabricated/garbage inputs (non-strict).
401
+
402
+ No physics is computed from the bad inputs and NOTHING is labelled MEASURED. The
403
+ certificate exists only to RECORD the honesty failure so it can never be mistaken for
404
+ a valid result. NaN sentinels mark fields that were NOT computed.
405
+ """
406
+ nan = float("nan")
407
+ return QuantumSensingCertificate(
408
+ certificate_type="szl/quantum-sensing-limits-certificate/v1/REJECTED",
409
+ inputs={
410
+ "label": sensor.label,
411
+ "source": sensor.source,
412
+ "REJECTED": True,
413
+ "atom_number_MEASURED": None,
414
+ "contrast_MEASURED": None,
415
+ "cycle_time_s_MEASURED": None,
416
+ "accel_psd_MEASURED": None,
417
+ "accel_input_MEASURED": None,
418
+ "validation_problems": problems,
419
+ "note": sensor.note,
420
+ },
421
+ k_eff_per_m=nan,
422
+ mz_phase_per_unit_accel_rad=nan,
423
+ mz_phase_modeled_rad=None,
424
+ accel_was_measured=False,
425
+ shot_noise_phase_rad=nan,
426
+ accel_sensitivity_per_shot=nan,
427
+ accel_asd=nan,
428
+ accel_psd_from_asd=nan,
429
+ vibration_transfer_magnitude=nan,
430
+ vibration_phase_variance=nan,
431
+ vibration_phase_rms_rad=nan,
432
+ coriolis_phase_rad=nan,
433
+ contrast_at_T=None,
434
+ at_or_above_standard_quantum_limit=False,
435
+ summary="REJECTED — " + msg + " No limits were computed; nothing labelled MEASURED.",
436
+ inputs_hash=_hash_inputs(sensor),
437
+ timestamp_utc=time.time(),
438
+ )
439
+
440
+
441
+ def certify_sensor(sensor: MeasuredSensor, strict: bool = True) -> QuantumSensingCertificate:
442
+ """Compute the QUANTUM-SENSING-LIMITS CERTIFICATE for one CAI operating point.
443
+
444
+ Returns a certificate stating: this sensor's effective wavevector k_eff, its
445
+ Mach-Zehnder phase response, its standard-quantum-limit (shot-noise) phase floor and
446
+ the per-shot / ASD acceleration sensitivity it implies, the vibration-limited phase
447
+ variance σ_Φ² = k_eff²·S_a·T³/3, and the lead Coriolis bias — every value labelled
448
+ MEASURED (only if a real reading) vs MODELED, with an explicit NOT-MODELED list.
449
+
450
+ HONESTY GUARD: if ``strict`` (default), a fabricated/garbage or out-of-range input
451
+ raises ValueError rather than being silently certified. An accel input is reported as
452
+ MEASURED ONLY if the whole record is labelled MEASURED; otherwise it is MODELED.
453
+ """
454
+ problems = _validate_sensor(sensor)
455
+ if problems:
456
+ msg = ("HONESTY GUARD: sensor inputs rejected (will NOT be silently labelled "
457
+ "MEASURED): " + "; ".join(problems))
458
+ if strict:
459
+ raise ValueError(msg)
460
+ # NON-STRICT: do NOT fabricate or compute limits from garbage. Return a clearly
461
+ # REJECTED certificate that records the problems and labels NOTHING as MEASURED.
462
+ return _rejected_certificate(sensor, problems, msg)
463
+
464
+ label_is_measured = sensor.label in _MEASURED_LABELS
465
+ lam = sensor.wavelength_m
466
+ T = sensor.interrogation_time_s
467
+ N = sensor.atom_number
468
+ C = sensor.contrast
469
+ Tc = sensor.cycle_time_s
470
+ Sa = sensor.accel_psd
471
+
472
+ keff = k_eff(lam)
473
+ phase_per_accel = keff * T * T # MODELED: rad per (m/s²)
474
+
475
+ # MEASURED vs MODELED accel: only honour an accel reading if the record is MEASURED.
476
+ measured_a = sensor.measured_accel(label_is_measured)
477
+ accel_for_phase = sensor.accel_input # may still model a phase for a DESIGN/SAMPLE a
478
+ mz_phase = (mach_zehnder_phase(keff, accel_for_phase, T)
479
+ if accel_for_phase is not None else None)
480
+
481
+ sigma_phi = shot_noise_phase(C, N) # SQL
482
+ sigma_a = accel_sensitivity_per_shot(sigma_phi, keff, T)
483
+ n_a = asd_accel(sigma_a, Tc)
484
+ psd_from_asd = n_a * n_a
485
+
486
+ H_mag = vibration_transfer_magnitude(sensor.omega_rad_s, T)
487
+ vib_var = vibration_phase_variance(keff, Sa, T)
488
+ vib_rms = math.sqrt(vib_var)
489
+
490
+ cor_phase = coriolis_phase(keff, sensor.transverse_velocity_ms,
491
+ sensor.rotation_rate_rad_s, T)
492
+
493
+ contrast_T = None
494
+ if sensor.contrast0 is not None and sensor.coherence_time_s is not None:
495
+ contrast_T = contrast_decay(sensor.contrast0, T, sensor.coherence_time_s)
496
+
497
+ # Honest verdict: the reported noise floor σ_Φ is AT/ABOVE the SQL by construction
498
+ # (we never assert a sub-shot-noise figure). True ⇒ no sub-SQL/over-unity claim made.
499
+ at_or_above_sql = sigma_phi >= shot_noise_phase(C, N) - 1e-18
500
+
501
+ a_phase_str = (f"{mz_phase:.4g} rad ({'MEASURED-fed' if measured_a is not None else 'MODELED-input'})"
502
+ if mz_phase is not None else "n/a (no acceleration input supplied)")
503
+ summary = (
504
+ f"Cold-atom interferometer @ λ={lam:g} m, T={T:g} s, N={N:.4g} atoms, C={C:g} "
505
+ f"(label={sensor.label}, source={sensor.source}). MODELED: k_eff={keff:.6g} m⁻¹ "
506
+ f"(=4π/λ, Kasevich-Chu 1991); Mach-Zehnder response {phase_per_accel:.4g} rad per "
507
+ f"m/s² (=k_eff·T², Peters 2001); phase for the supplied acceleration = {a_phase_str}. "
508
+ f"STANDARD QUANTUM LIMIT phase floor σ_Φ={sigma_phi:.4g} rad (=1/(C·√N)) ⇒ per-shot "
509
+ f"σ_a={sigma_a:.4g} m/s² ⇒ ASD n_a={n_a:.4g} m/s²/√Hz (=σ_a·√T_c, Freier 2016). "
510
+ f"Vibration-limited phase: |H(ω)|={H_mag:.4g} s² at ω={sensor.omega_rad_s:g} rad/s, "
511
+ f"σ_Φ²={vib_var:.4g} rad² (=k_eff²·S_a·T³/3, Cheinet 2008) ⇒ σ_Φ,vib={vib_rms:.4g} "
512
+ f"rad. Lead Coriolis bias Φ_cor={cor_phase:.4g} rad (=2·k_eff·v_⊥·Ω·T²). VERDICT: "
513
+ f"the sensor is BOUNDED by the standard quantum limit — the honest inverse of a "
514
+ f"free-energy claim. NO sub-SQL/over-unity claim. {len(NOT_MODELED)} systematic "
515
+ f"classes are explicitly NOT MODELED (laser-phase noise, AC-Stark/light-shift, "
516
+ f"full 3-axis mechanization, detection noise, Dick aliasing, mean-field shifts) — "
517
+ f"this is a noise-floor certificate, NOT a complete error budget."
518
+ )
519
+
520
+ return QuantumSensingCertificate(
521
+ certificate_type="szl/quantum-sensing-limits-certificate/v1",
522
+ inputs={
523
+ "label": sensor.label,
524
+ "source": sensor.source,
525
+ "wavelength_m_CONFIG": lam,
526
+ "interrogation_time_s_CONFIG": T,
527
+ "atom_number_MEASURED": N if label_is_measured else None,
528
+ "atom_number_value": N,
529
+ "contrast_MEASURED": C if label_is_measured else None,
530
+ "contrast_value": C,
531
+ "cycle_time_s_MEASURED": Tc if label_is_measured else None,
532
+ "cycle_time_s_value": Tc,
533
+ "accel_psd_MEASURED": Sa if label_is_measured else None,
534
+ "accel_psd_value": Sa,
535
+ "accel_input_MEASURED": measured_a, # None unless a genuine reading
536
+ "accel_input_value": sensor.accel_input,
537
+ "omega_rad_s_CONFIG": sensor.omega_rad_s,
538
+ "transverse_velocity_ms": sensor.transverse_velocity_ms,
539
+ "rotation_rate_rad_s": sensor.rotation_rate_rad_s,
540
+ "contrast0_CONFIG": sensor.contrast0,
541
+ "coherence_time_s": sensor.coherence_time_s,
542
+ "validation_problems": problems, # empty unless strict=False let issues through
543
+ "note": sensor.note,
544
+ },
545
+ k_eff_per_m=keff,
546
+ mz_phase_per_unit_accel_rad=phase_per_accel,
547
+ mz_phase_modeled_rad=mz_phase,
548
+ accel_was_measured=(measured_a is not None),
549
+ shot_noise_phase_rad=sigma_phi,
550
+ accel_sensitivity_per_shot=sigma_a,
551
+ accel_asd=n_a,
552
+ accel_psd_from_asd=psd_from_asd,
553
+ vibration_transfer_magnitude=H_mag,
554
+ vibration_phase_variance=vib_var,
555
+ vibration_phase_rms_rad=vib_rms,
556
+ coriolis_phase_rad=cor_phase,
557
+ contrast_at_T=contrast_T,
558
+ at_or_above_standard_quantum_limit=bool(at_or_above_sql),
559
+ summary=summary,
560
+ inputs_hash=_hash_inputs(sensor),
561
+ timestamp_utc=time.time(),
562
+ )
563
+
564
+
565
+ def honest_sample_sensor() -> MeasuredSensor:
566
+ """An HONEST, CLEARLY-LABELLED sample operating point (NOT a real instrument reading).
567
+
568
+ Values are representative of a Rb-87 fountain CAI (λ≈780 nm, T≈0.1 s) but the record is
569
+ labelled SAMPLE so the certifier will NOT report them as MEASURED. No fabricated claim.
570
+ """
571
+ return MeasuredSensor(
572
+ wavelength_m=780.0e-9, # Rb-87 D2 line, design wavelength
573
+ interrogation_time_s=0.1, # 100 ms pulse separation
574
+ atom_number=1.0e6, # ~10^6 atoms
575
+ contrast=0.5, # 50% fringe contrast
576
+ cycle_time_s=0.5, # 0.5 s cycle (2 Hz)
577
+ accel_psd=1.0e-8, # m²/s⁴/Hz, representative ground vibration
578
+ accel_input=9.81, # g, supplied as DESIGN input (NOT a reading)
579
+ omega_rad_s=2.0 * math.pi * 1.0, # evaluate |H| at 1 Hz
580
+ transverse_velocity_ms=0.01,
581
+ rotation_rate_rad_s=7.292115e-5, # Earth rotation rate (sidereal)
582
+ contrast0=0.6,
583
+ coherence_time_s=0.3,
584
+ label="SAMPLE",
585
+ source="honest-sample",
586
+ note="Representative Rb-87 CAI operating point. SAMPLE label ⇒ not MEASURED.",
587
+ )
588
+
589
+
590
+ __all__ = [
591
+ "K_B", "H_PLANCK", "HBAR", "C_LIGHT", "PI",
592
+ "SENSING_ATTRIBUTION", "DOCTRINE", "NOT_MODELED",
593
+ "MeasuredSensor", "QuantumSensingCertificate", "certify_sensor",
594
+ "k_eff", "mach_zehnder_phase", "shot_noise_phase", "accel_sensitivity_per_shot",
595
+ "asd_accel", "contrast_decay", "vibration_transfer_magnitude",
596
+ "vibration_phase_variance", "coriolis_phase", "honest_sample_sensor",
597
+ ]
598
+
599
+
600
+ if __name__ == "__main__":
601
+ sensor = honest_sample_sensor()
602
+ cert = certify_sensor(sensor)
603
+ print("SZL QUANTUM-SENSING-LIMITS CERTIFICATE (honest sample)\n" + "=" * 60)
604
+ print(cert.summary)
605
+ print("=" * 60)
606
+ print(f"k_eff : {cert.k_eff_per_m:.6g} m⁻¹")
607
+ print(f"SQL phase floor σ_Φ : {cert.shot_noise_phase_rad:.4g} rad")
608
+ print(f"per-shot σ_a : {cert.accel_sensitivity_per_shot:.4g} m/s²")
609
+ print(f"ASD n_a : {cert.accel_asd:.4g} m/s²/√Hz")
610
+ print(f"vibration σ_Φ² (T³/3) : {cert.vibration_phase_variance:.4g} rad²")
611
+ print(f"Coriolis Φ_cor : {cert.coriolis_phase_rad:.4g} rad")
612
+ print(f"contrast C(T) : {cert.contrast_at_T}")
613
+ print(f"at/above SQL (honest) : {cert.at_or_above_standard_quantum_limit}")
614
+ print(f"NOT MODELED classes : {len(cert.not_modeled)}")
serve.py CHANGED
@@ -301,6 +301,20 @@ try:
301
  except Exception as _szl_pinn_e: # pragma: no cover
302
  print(f"[a11oy] Agentic-PINN + physical-bounds mesh NOT registered: {_szl_pinn_e!r}", file=__import__("sys").stderr)
303
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  # ── Unified leader-formulas (thesis v6) — Sherman Morgan density-impulse/Tsiolkovsky,
305
  # Stewart LS12/CoRoL/Hugoniot, Wave24 coherence single-crossing. Each is REAL deterministic
306
  # Python with the ORIGINAL author cited; SZL borrows methodological structure only (no result
 
301
  except Exception as _szl_pinn_e: # pragma: no cover
302
  print(f"[a11oy] Agentic-PINN + physical-bounds mesh NOT registered: {_szl_pinn_e!r}", file=__import__("sys").stderr)
303
 
304
+ # ── PNT / quantum-sensing mesh — clean-room re-derivation of the physics (quantum
305
+ # sensor limits, GNSS spoof-resilience, GPS-denied coasting, fundamental limits).
306
+ # PURE STDLIB closed-form web path (never blocks); the heavy numpy/UKF/PINN solves are
307
+ # the Forge/GPU path on rtx-betterwithage + chaski. Every value labelled MEASURED/MODELED,
308
+ # Λ=Conjecture 1 (advisory). The 4 engine modules are loaded dynamically by szl_pnt_mesh
309
+ # (importlib) — they MUST be COPY'd into the image too or the mesh falls back to a stub.
310
+ # Additive, try/except-guarded, before the SPA catch-all.
311
+ try:
312
+ import szl_pnt_mesh as _szl_pnt_mesh
313
+ _szl_pnt_mesh.register(app, ns="a11oy")
314
+ print("[a11oy] PNT/quantum-sensing mesh registered: /api/a11oy/v1/pnt/*", file=__import__("sys").stderr)
315
+ except Exception as _szl_pnt_e: # pragma: no cover
316
+ print(f"[a11oy] PNT mesh NOT registered: {_szl_pnt_e!r}", file=__import__("sys").stderr)
317
+
318
  # ── Unified leader-formulas (thesis v6) — Sherman Morgan density-impulse/Tsiolkovsky,
319
  # Stewart LS12/CoRoL/Hugoniot, Wave24 coherence single-crossing. Each is REAL deterministic
320
  # Python with the ORIGINAL author cited; SZL borrows methodological structure only (no result
szl_pnt_mesh.py ADDED
@@ -0,0 +1,510 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Doctrine v11 LOCKED · Λ = Conjecture 1 (advisory, NOT proven trust)
3
+ # Sign-off: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
4
+ """szl_pnt_mesh.py — a11oy MESH for the SZL PNT / QUANTUM-SENSING vertical.
5
+
6
+ This is the live-mesh surface for the SECOND hard-physics pillar (sensing limits)
7
+ next to the compute-bounds pillar already served by `szl_pinn_bounds.py`. It exposes
8
+ the UNIFIED "fundamental-limits" library (compute bounds + quantum sensing) behind
9
+ a11oy's governed `/api/<ns>/v1/pnt/*` route table.
10
+
11
+ Routes (all GET, read-only / deterministic):
12
+
13
+ /api/<ns>/v1/pnt capability index + doctrine + links (both pillars)
14
+ /api/<ns>/v1/pnt/sensor quantum-sensor limit certificate from query params
15
+ (cold-atom-interferometer shot-noise / SQL sensitivity;
16
+ Kasevich-Chu 1991, Peters 2001, Freier 2016, Cheinet 2008)
17
+ /api/<ns>/v1/pnt/resilience fused multi-layer GNSS spoof-detector verdict from query
18
+ params (RAIM-consistency + AGC + SQM), deny-by-default
19
+ /api/<ns>/v1/pnt/coast GPS-denied coasting figure-of-merit: classical vs quantum
20
+ /api/<ns>/v1/pnt/limits the UNIFIED fundamental-limits index (BOTH pillars:
21
+ compute_bounds + quantum_sensor + pnt_resilience + nav_coasting)
22
+
23
+ HONESTY (Doctrine v11, HARD):
24
+ - Sensor limits are DERIVED from established physics (shot-noise / standard quantum
25
+ limit), labelled MODELED. The compute-bounds certificate is the HONEST INVERSE of a
26
+ free-energy claim. NO over-unity, NO sub-SQL magic, NO fabricated number.
27
+ - Bounds/physics are CITED, re-derived clean-room from the papers and the kshana method
28
+ (Apache-2.0, DOI 10.5281/zenodo.20528627). No verbatim code copied.
29
+ - Λ = Conjecture 1 (advisory). ALLOW/NOMINAL = "passed SZL admission policy", never
30
+ "proven trust". Spoof governor is deny-by-default.
31
+ - HEAVY numpy solves (full UKF fusion, batched sensor sweeps, PINN solves) are the
32
+ Forge / GPU / own-metal path. This stdlib mesh READS & AGGREGATES the unified library
33
+ and re-derives the lightweight closed-form limits; it NEVER blocks on a heavy solve.
34
+ - If a sibling engine (Dev1 quantum_sensing_limits, Dev2 pnt_resilience, Dev3
35
+ nav_coasting) is not present, the unified library returns an HONEST "module not wired
36
+ yet"/clean-room-MODELED result; this mesh surfaces that honestly — never a false green.
37
+
38
+ Matches the `szl_pinn_bounds.py` contract exactly: pure-stdlib request path, FastAPI
39
+ `add_api_route` with a Starlette `Route` fallback, try/except-guarded `register(app, ns)`.
40
+ """
41
+ import importlib
42
+ import json
43
+ import math
44
+ import os
45
+ import sys
46
+ import time
47
+ from datetime import datetime, timezone
48
+
49
+ try: # Starlette is present in the a11oy image (same as szl_pinn_bounds.py).
50
+ from starlette.requests import Request
51
+ from starlette.responses import JSONResponse
52
+ except Exception: # pragma: no cover - allows import in a bare env for tests
53
+ Request = object # type: ignore
54
+
55
+ class JSONResponse: # minimal shim so handlers can be unit-tested w/o starlette
56
+ def __init__(self, content, status_code=200):
57
+ self.body = content
58
+ self.status_code = status_code
59
+
60
+ # Make the unified library importable from this directory regardless of CWD.
61
+ _THIS_DIR = os.path.dirname(os.path.abspath(__file__))
62
+ if _THIS_DIR not in sys.path:
63
+ sys.path.insert(0, _THIS_DIR)
64
+
65
+
66
+ def _load_fl():
67
+ """Lazily import the unified fundamental-limits library. Honest None on failure."""
68
+ try:
69
+ return importlib.import_module("fundamental_limits")
70
+ except Exception:
71
+ return None
72
+
73
+
74
+ # --------------------------------------------------------------------------- #
75
+ # Doctrine strings (mirrors the unified library; carried on every response). #
76
+ # --------------------------------------------------------------------------- #
77
+ DOCTRINE = (
78
+ "v11 LOCKED: NO free-energy/over-unity (compute certificate is the honest INVERSE; "
79
+ "sensor limits DERIVED from physics, never sub-SQL magic); MEASURED vs MODELED vs "
80
+ "SAMPLE labels on every result; honest 'NOT MODELED'/'module not wired yet' where "
81
+ "physics is incomplete; established bounds CITED not claimed as SZL's; clean-room "
82
+ "(re-derived from papers, kshana cited not copied); Λ=Conjecture 1 (advisory, "
83
+ "deny-by-default, never 'proven trust'); sovereign own-metal; no fabricated numbers."
84
+ )
85
+
86
+ LAMBDA_NOTE = (
87
+ "Λ = Conjecture 1 (advisory governance gate). ALLOW/NOMINAL = 'passed SZL admission "
88
+ "policy', NEVER 'proven trust'. Deny-by-default. States physical FACTS/BOUNDS, not trust."
89
+ )
90
+
91
+ SENSING_ATTRIBUTION = {
92
+ "kasevich_chu_1991": ("Kasevich, M. & Chu, S. (1991), Phys. Rev. Lett. 67(2):181, "
93
+ "doi:10.1103/PhysRevLett.67.181."),
94
+ "peters_2001": ("Peters, A., Chung, K.Y. & Chu, S. (2001), Metrologia 38(1):25, "
95
+ "doi:10.1088/0026-1394/38/1/4."),
96
+ "freier_2016": ("Freier, C. et al. (2016), J. Phys. Conf. Ser. 723:012050, "
97
+ "doi:10.1088/1742-6596/723/1/012050."),
98
+ "cheinet_2008": ("Cheinet, P. et al. (2008), IEEE Trans. Instrum. Meas. 57(6):1141, "
99
+ "doi:10.1109/TIM.2007.915148."),
100
+ "kshana": ("AshfordeOU/kshana (Apache-2.0, DOI 10.5281/zenodo.20528627) — method & "
101
+ "physics CITED, re-derived clean-room. No verbatim code copied."),
102
+ }
103
+
104
+
105
+ def _now_iso() -> str:
106
+ return datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z")
107
+
108
+
109
+ # --------------------------------------------------------------------------- #
110
+ # Pure-stdlib closed-form physics (used directly in the web path — no numpy). #
111
+ # Math mirrors the unified library / Dev1 so the live mesh and on-metal AGREE. #
112
+ # --------------------------------------------------------------------------- #
113
+ def _sensor_limit(lambda_m, T, N, C, Tc):
114
+ """SQL CAI accelerometer sensitivity — pure stdlib (no numpy).
115
+
116
+ k_eff = 4π/λ ; σ_Φ = 1/(C·√N) ; σ_a = σ_Φ/(k_eff·T²) ; n_a = σ_a·√T_c.
117
+ Lineage: Kasevich-Chu 1991, Peters 2001, Freier 2016, Cheinet 2008.
118
+ """
119
+ k_eff = 4.0 * math.pi / lambda_m if lambda_m > 0 else float("inf")
120
+ sigma_phi = 1.0 / (C * math.sqrt(N)) if (C > 0 and N > 0) else float("inf")
121
+ denom = k_eff * T * T
122
+ sigma_a = (sigma_phi / denom) if denom > 0 else float("inf")
123
+ asd = sigma_a * math.sqrt(Tc) if Tc > 0 else float("inf")
124
+ return {
125
+ "k_eff_per_m": k_eff,
126
+ "shot_noise_phase_rad": sigma_phi,
127
+ "per_shot_accel_sensitivity_m_s2": sigma_a,
128
+ "accel_asd_m_s2_per_sqrt_hz": asd,
129
+ "inputs": {"wavelength_m": lambda_m, "interrogation_time_s": T,
130
+ "atom_number": N, "contrast": C, "cycle_time_s": Tc},
131
+ "formulas": {"k_eff": "4*pi/lambda", "shot_noise": "1/(C*sqrt(N)) (SQL)",
132
+ "per_shot_accel": "sigma_Phi/(k_eff*T^2)", "asd": "sigma_a*sqrt(T_c)"},
133
+ "label": "MODELED",
134
+ "at_or_above_standard_quantum_limit": True,
135
+ }
136
+
137
+
138
+ def _spoof_verdict(raim_m, agc_db, sqm_dev, raim_thr, agc_thr, sqm_thr):
139
+ """Pure-stdlib deny-by-default multi-layer spoof fusion (RAIM + AGC + SQM).
140
+
141
+ A transparent web-path stand-in for the Dev2 engine: any single layer fired ->
142
+ SUSPECT; >=2 -> SPOOF_LIKELY (DENY); 0 -> NOMINAL (ALLOW). Advisory (Λ).
143
+ """
144
+ flags = {
145
+ "raim_consistency": raim_m > raim_thr,
146
+ "agc_power": agc_db > agc_thr,
147
+ "sqm_asymmetry": abs(sqm_dev) > sqm_thr,
148
+ }
149
+ n = sum(1 for v in flags.values() if v)
150
+ if n >= 2:
151
+ verdict, allow = "DENY", False
152
+ elif n == 1:
153
+ verdict, allow = "ADVISORY", False
154
+ else:
155
+ verdict, allow = "ALLOW", True
156
+ return {
157
+ "verdict": verdict,
158
+ "allow": allow,
159
+ "advisory": True,
160
+ "n_layers_fired": n,
161
+ "layers": flags,
162
+ "inputs": {"raim_consistency_m": raim_m, "agc_advantage_db": agc_db,
163
+ "sqm_early_minus_late": sqm_dev},
164
+ "thresholds": {"raim_threshold_m": raim_thr, "agc_threshold_db": agc_thr,
165
+ "sqm_threshold": sqm_thr},
166
+ "fusion": "deny-by-default: >=2 fired -> DENY, 1 -> ADVISORY, 0 -> ALLOW",
167
+ "label": "MODELED",
168
+ }
169
+
170
+
171
+ def _coast_fom(t, n_classical, n_quantum):
172
+ """GPS-denied coasting position-error growth: sigma_x(t) ~= n_a * t^1.5 / sqrt(3)."""
173
+ def pe(n):
174
+ return n * (t ** 1.5) / math.sqrt(3.0)
175
+ ec, eq = pe(n_classical), pe(n_quantum)
176
+ return {
177
+ "coast_time_s": t,
178
+ "classical": {"accel_asd_m_s2_per_sqrt_hz": n_classical, "position_error_m": ec},
179
+ "quantum": {"accel_asd_m_s2_per_sqrt_hz": n_quantum, "position_error_m": eq},
180
+ "quantum_over_classical_improvement_factor": (ec / eq) if eq > 0 else float("inf"),
181
+ "model": ("white-acceleration-noise random walk, double-integrated: "
182
+ "sigma_x(t) ~= n_a * t^1.5 / sqrt(3). MODELED scaling."),
183
+ "label": "MODELED",
184
+ }
185
+
186
+
187
+ # --------------------------------------------------------------------------- #
188
+ # Query-param helpers #
189
+ # --------------------------------------------------------------------------- #
190
+ def _f(qp, *keys, default=0.0):
191
+ for k in keys:
192
+ v = qp.get(k)
193
+ if v not in (None, ""):
194
+ try:
195
+ return float(v)
196
+ except Exception:
197
+ pass
198
+ return float(default)
199
+
200
+
201
+ def _qp(req):
202
+ """Extract a query-param mapping from a Starlette Request OR a plain dict (tests)."""
203
+ if isinstance(req, dict):
204
+ return req
205
+ return getattr(req, "query_params", {}) or {}
206
+
207
+
208
+ # --------------------------------------------------------------------------- #
209
+ # Handlers #
210
+ # --------------------------------------------------------------------------- #
211
+ def _h_index(req: Request):
212
+ ns = "a11oy"
213
+ if not isinstance(req, dict):
214
+ ns = getattr(req, "path_params", {}).get("_ns", "a11oy")
215
+ base = f"/api/{ns}/v1/pnt"
216
+ fl = _load_fl()
217
+ pillars = fl.status().get("pillars") if fl else {"error": "unified library not importable"}
218
+ return JSONResponse({
219
+ "capability": "SZL PNT / Quantum-Sensing vertical — the SECOND hard-physics pillar",
220
+ "frontier": ("quantum + classical sensing for Positioning-Navigation-Timing, "
221
+ "unified with the compute-bounds certifier into one governed "
222
+ "'fundamental-limits' surface — every result MEASURED/MODELED-labelled, "
223
+ "Λ-gated, clean-room re-derived from the kshana method + the papers"),
224
+ "pillars": ["compute_bounds (Landauer/ML/Bremermann/Bekenstein — szl_pinn_bounds)",
225
+ "quantum_sensor (cold-atom interferometer SQL — Dev1)",
226
+ "pnt_resilience (fused spoof detector — Dev2)",
227
+ "nav_coasting (GPS-denied coasting FoM — Dev3)"],
228
+ "engine_status": pillars,
229
+ "routes": {
230
+ f"{base}/sensor": ("quantum-sensor limit certificate "
231
+ "(?wavelength_m=&interrogation_time_s=&atom_number=&contrast=&cycle_time_s=)"),
232
+ f"{base}/resilience": ("fused spoof-detector verdict "
233
+ "(?raim_consistency_m=&agc_advantage_db=&sqm_early_minus_late= "
234
+ "or ?scenario=clean|ds2_time_push|ds3_overpower|ds4_seamless|ds7_matched_aligned)"),
235
+ f"{base}/coast": ("GPS-denied coasting FoM classical vs quantum "
236
+ "(?coast_time_s=&classical_asd=&quantum_asd=)"),
237
+ f"{base}/limits": "the UNIFIED fundamental-limits index (both pillars)",
238
+ },
239
+ "attribution": {"sensing": SENSING_ATTRIBUTION},
240
+ "lambda_note": LAMBDA_NOTE,
241
+ "doctrine": DOCTRINE,
242
+ "honest_inverse_of_free_energy": True,
243
+ "ts": _now_iso(),
244
+ })
245
+
246
+
247
+ def _h_sensor(req: Request):
248
+ qp = _qp(req)
249
+ lam = _f(qp, "wavelength_m", "lambda_m", default=780e-9)
250
+ T = _f(qp, "interrogation_time_s", "T", default=0.1)
251
+ N = _f(qp, "atom_number", "N", default=1e6)
252
+ C = _f(qp, "contrast", "C", default=0.5)
253
+ Tc = _f(qp, "cycle_time_s", "Tc", default=0.5)
254
+ # Try the unified library (which wraps the Dev1 engine when present); the closed-form
255
+ # stdlib derivation is the always-available web-path answer.
256
+ closed_form = _sensor_limit(lam, T, N, C, Tc)
257
+ engine = None
258
+ fl = _load_fl()
259
+ if fl is not None:
260
+ try:
261
+ res = fl.certify("quantum_sensor", wavelength_m=lam, interrogation_time_s=T,
262
+ atom_number=N, contrast=C, cycle_time_s=Tc)
263
+ engine = {"source": res.get("source"), "label": res.get("label"),
264
+ "wired": res.get("wired"), "certificate": res.get("result")}
265
+ except Exception as e:
266
+ engine = {"error": repr(e), "note": "unified library call failed; closed-form used"}
267
+ return JSONResponse({
268
+ "model": "SZL Quantum-Sensing-Limits — live CAI sensitivity certificate",
269
+ "status": "VERIFIED (MODELED physics) · UNSIGNED (STRUCTURAL-ONLY)",
270
+ "label": "MODELED",
271
+ "closed_form_stdlib": closed_form,
272
+ "engine": engine,
273
+ "attribution": SENSING_ATTRIBUTION,
274
+ "lambda_note": LAMBDA_NOTE,
275
+ "doctrine": DOCTRINE,
276
+ "honest_inverse_of_free_energy": True,
277
+ })
278
+
279
+
280
+ def _h_resilience(req: Request):
281
+ qp = _qp(req)
282
+ scenario = qp.get("scenario")
283
+ engine = None
284
+ fl = _load_fl()
285
+ # Prefer the Dev2 engine via the unified library when a scenario is requested (it
286
+ # carries the calibrated chi-square monitor fusion). Heavy numpy stays in the engine;
287
+ # the mesh tolerates failure and always answers with the closed-form fusion.
288
+ if fl is not None and scenario:
289
+ try:
290
+ res = fl.certify("pnt_resilience", scenario=scenario, seed=int(_f(qp, "seed", default=0)))
291
+ engine = {"source": res.get("source"), "label": res.get("label"),
292
+ "wired": res.get("wired"), "verdict": res.get("result")}
293
+ except Exception as e:
294
+ engine = {"error": repr(e)}
295
+ raim = _f(qp, "raim_consistency_m", "raim_m", default=0.0)
296
+ agc = _f(qp, "agc_advantage_db", "agc_db", default=0.0)
297
+ sqm = _f(qp, "sqm_early_minus_late", "sqm", default=0.0)
298
+ raim_thr = _f(qp, "raim_threshold_m", default=30.0)
299
+ agc_thr = _f(qp, "agc_threshold_db", default=1.5)
300
+ sqm_thr = _f(qp, "sqm_threshold", default=0.12)
301
+ closed_form = _spoof_verdict(raim, agc, sqm, raim_thr, agc_thr, sqm_thr)
302
+ return JSONResponse({
303
+ "model": "SZL PNT-Resilience — fused multi-layer spoof verdict",
304
+ "status": f"{closed_form['verdict']} (advisory, deny-by-default)",
305
+ "label": "MODELED",
306
+ "closed_form_stdlib": closed_form,
307
+ "engine": engine,
308
+ "note": ("RAIM-consistency + AGC-power + SQM-asymmetry fused deny-by-default. The "
309
+ "full calibrated chi-square detector with TEXBAT-style scenarios runs in "
310
+ "the Dev2 engine (numpy); this stdlib mesh answers with a transparent "
311
+ "closed-form fusion and surfaces the engine verdict when present."),
312
+ "attribution": SENSING_ATTRIBUTION,
313
+ "lambda_note": LAMBDA_NOTE,
314
+ "doctrine": DOCTRINE,
315
+ })
316
+
317
+
318
+ def _h_coast(req: Request):
319
+ qp = _qp(req)
320
+ t = _f(qp, "coast_time_s", "t", default=60.0)
321
+ n_c = _f(qp, "classical_asd", "classical_asd_m_s2_per_sqrt_hz", default=1e-3)
322
+ # Default quantum ASD comes from the closed-form CAI derivation unless supplied.
323
+ if any(k in qp for k in ("quantum_asd", "quantum_asd_m_s2_per_sqrt_hz")):
324
+ n_q = _f(qp, "quantum_asd", "quantum_asd_m_s2_per_sqrt_hz", default=1e-8)
325
+ else:
326
+ n_q = _sensor_limit(780e-9, 0.1, 1e6, 0.5, 0.5)["accel_asd_m_s2_per_sqrt_hz"]
327
+ closed_form = _coast_fom(t, n_c, n_q)
328
+ engine = None
329
+ fl = _load_fl()
330
+ if fl is not None:
331
+ try:
332
+ res = fl.certify("nav_coasting", coast_time_s=t,
333
+ classical_asd_m_s2_per_sqrt_hz=n_c,
334
+ quantum_asd_m_s2_per_sqrt_hz=n_q)
335
+ engine = {"source": res.get("source"), "label": res.get("label"),
336
+ "wired": res.get("wired"), "result": res.get("result")}
337
+ except Exception as e:
338
+ engine = {"error": repr(e)}
339
+ return JSONResponse({
340
+ "model": "SZL Nav-Coasting — GPS-denied position-error FoM (classical vs quantum)",
341
+ "status": "VERIFIED (MODELED scaling) · UNSIGNED (STRUCTURAL-ONLY)",
342
+ "label": "MODELED",
343
+ "closed_form_stdlib": closed_form,
344
+ "engine": engine,
345
+ "note": ("The full INS/UKF error-covariance propagation (17-state, coupled clock) "
346
+ "is the Dev3 / Forge GPU path. This mesh answers with the closed-form "
347
+ "random-walk coasting scaling — MODELED, not a fabricated number."),
348
+ "attribution": SENSING_ATTRIBUTION,
349
+ "lambda_note": LAMBDA_NOTE,
350
+ "doctrine": DOCTRINE,
351
+ })
352
+
353
+
354
+ def _h_limits(req: Request):
355
+ """The UNIFIED fundamental-limits index: BOTH pillars, honest wiring discovery."""
356
+ fl = _load_fl()
357
+ if fl is None:
358
+ return JSONResponse({
359
+ "model": "SZL Unified Fundamental-Limits index",
360
+ "status": "UNIFIED_LIBRARY_NOT_IMPORTABLE",
361
+ "note": ("fundamental_limits.py not importable in this environment — honest "
362
+ "state, no fabricated number."),
363
+ "doctrine": DOCTRINE,
364
+ "lambda_note": LAMBDA_NOTE,
365
+ }, status_code=200)
366
+ st = fl.status()
367
+ return JSONResponse({
368
+ "model": "SZL Unified Fundamental-Limits index — both hard-physics pillars",
369
+ "library": st.get("library"),
370
+ "pillars": st.get("pillars"),
371
+ "kinds": st.get("kinds"),
372
+ "pillar_A_compute_bounds": ("Landauer 1961 / Margolus-Levitin 1998 / Bremermann "
373
+ "1962 / Bekenstein 1981 / Bekenstein-Hawking 1975 — the "
374
+ "HONEST INVERSE of a free-energy claim (szl_pinn_bounds)"),
375
+ "pillar_B_quantum_sensing": ("cold-atom interferometer SQL (Dev1) + fused spoof "
376
+ "detector (Dev2) + GPS-denied coasting FoM (Dev3) — "
377
+ "re-derived clean-room from the kshana method + papers"),
378
+ "labels": st.get("labels"),
379
+ "attribution": st.get("attribution"),
380
+ "honest_inverse_of_free_energy": st.get("honest_inverse_of_free_energy"),
381
+ "lambda_note": st.get("lambda_note"),
382
+ "doctrine": st.get("doctrine"),
383
+ "ts": _now_iso(),
384
+ })
385
+
386
+
387
+ # --------------------------------------------------------------------------- #
388
+ # Registration — mirrors szl_pinn_bounds.register exactly. #
389
+ # --------------------------------------------------------------------------- #
390
+ def register(app, ns="a11oy"):
391
+ """Wire the PNT / quantum-sensing mesh onto the app under /api/<ns>/v1/pnt/*.
392
+
393
+ Additive. Uses FastAPI's add_api_route when available (matches the sibling szl_*
394
+ modules so resolution order is correct vs the SPA catch-all); falls back to a
395
+ Starlette route append for a bare Starlette app.
396
+ """
397
+ base = f"/api/{ns}/v1/pnt"
398
+ handlers = [
399
+ (base, _h_index),
400
+ (f"{base}/sensor", _h_sensor),
401
+ (f"{base}/resilience", _h_resilience),
402
+ (f"{base}/coast", _h_coast),
403
+ (f"{base}/limits", _h_limits),
404
+ ]
405
+ add_api_route = getattr(app, "add_api_route", None)
406
+ for path, fn in handlers:
407
+ if callable(add_api_route):
408
+ app.add_api_route(path, fn, methods=["GET"])
409
+ else:
410
+ from starlette.routing import Route
411
+ app.router.routes.append(Route(path, fn))
412
+ return [p for p, _ in handlers]
413
+
414
+
415
+ def _selftest() -> dict:
416
+ """No-server self-test: proves register() adds routes and handlers answer honestly.
417
+
418
+ Doctrine labels are checked end-to-end: MODELED/MEASURED carried, Λ=Conjecture 1
419
+ advisory present, honest-inverse-of-free-energy preserved.
420
+ """
421
+ out = {}
422
+
423
+ def _body(resp):
424
+ """Decode a handler response to a dict, whether real Starlette JSONResponse
425
+ (bytes body) or the test shim (dict body)."""
426
+ b = getattr(resp, "body", resp)
427
+ if isinstance(b, (bytes, bytearray)):
428
+ return json.loads(b.decode())
429
+ if isinstance(b, str):
430
+ return json.loads(b)
431
+ return b
432
+
433
+ # (a) register() adds exactly the 5 routes onto a FastAPI-like app.
434
+ class _FakeApp:
435
+ def __init__(self):
436
+ self.routes = []
437
+
438
+ def add_api_route(self, path, fn, methods=None):
439
+ self.routes.append((path, fn, tuple(methods or [])))
440
+
441
+ app = _FakeApp()
442
+ added = register(app, ns="a11oy")
443
+ expected = ["/api/a11oy/v1/pnt", "/api/a11oy/v1/pnt/sensor",
444
+ "/api/a11oy/v1/pnt/resilience", "/api/a11oy/v1/pnt/coast",
445
+ "/api/a11oy/v1/pnt/limits"]
446
+ assert added == expected, added
447
+ assert [r[0] for r in app.routes] == expected
448
+ assert all(r[2] == ("GET",) for r in app.routes)
449
+ out["register_adds_5_routes"] = True
450
+
451
+ # (b) Starlette-fallback path (no add_api_route) also wires routes.
452
+ class _BareRouter:
453
+ def __init__(self):
454
+ self.routes = []
455
+
456
+ class _BareApp:
457
+ def __init__(self):
458
+ self.router = _BareRouter()
459
+
460
+ try:
461
+ bare = _BareApp()
462
+ register(bare, ns="a11oy")
463
+ out["starlette_fallback_wires"] = len(bare.router.routes) == 5
464
+ except Exception:
465
+ # starlette.routing may be absent in a bare env — that's an honest skip.
466
+ out["starlette_fallback_wires"] = "skipped (starlette.routing unavailable)"
467
+
468
+ # (c) sensor handler returns a MODELED certificate with the SQL fields.
469
+ s = _body(_h_sensor({"wavelength_m": "780e-9", "contrast": "0.5", "atom_number": "1e6"}))
470
+ cf = s["closed_form_stdlib"]
471
+ assert cf["label"] == "MODELED"
472
+ assert cf["at_or_above_standard_quantum_limit"] is True
473
+ assert cf["k_eff_per_m"] > 0 and cf["accel_asd_m_s2_per_sqrt_hz"] > 0
474
+ assert s["honest_inverse_of_free_energy"] is True
475
+ out["sensor_modeled_sql"] = True
476
+
477
+ # (d) resilience handler: clean inputs -> ALLOW; spoof inputs -> DENY (deny-by-default).
478
+ clean = _body(_h_resilience({}))["closed_form_stdlib"]
479
+ assert clean["verdict"] == "ALLOW" and clean["allow"] is True
480
+ spoof = _body(_h_resilience({"raim_consistency_m": "100", "agc_advantage_db": "10"}))["closed_form_stdlib"]
481
+ assert spoof["verdict"] == "DENY" and spoof["allow"] is False
482
+ assert spoof["advisory"] is True
483
+ out["resilience_deny_by_default"] = True
484
+
485
+ # (e) coast handler: quantum beats classical (improvement factor > 1 for default ASDs).
486
+ c = _body(_h_coast({"coast_time_s": "60"}))["closed_form_stdlib"]
487
+ assert c["quantum_over_classical_improvement_factor"] > 1.0
488
+ assert c["label"] == "MODELED"
489
+ out["coast_quantum_advantage"] = True
490
+
491
+ # (f) limits index carries BOTH pillars and the doctrine labels.
492
+ lim = _body(_h_limits({}))
493
+ assert "pillars" in lim or lim.get("status") == "UNIFIED_LIBRARY_NOT_IMPORTABLE"
494
+ assert "free-energy" in lim["doctrine"].lower()
495
+ assert "advisory" in lim["lambda_note"].lower()
496
+ out["limits_both_pillars"] = True
497
+
498
+ # (g) doctrine labels carried across handlers (Λ=Conjecture 1, honest-inverse).
499
+ idx = _body(_h_index({}))
500
+ assert "Conjecture 1" in idx["lambda_note"]
501
+ assert idx["honest_inverse_of_free_energy"] is True
502
+ assert "clean-room" in idx["doctrine"].lower()
503
+ out["doctrine_labels_carried"] = True
504
+
505
+ out["ok"] = True
506
+ return out
507
+
508
+
509
+ if __name__ == "__main__":
510
+ print(json.dumps(_selftest(), indent=2))