Spaces:
Running
Running
chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)
Browse filesAutomated 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.
- Dockerfile +5 -0
- fundamental_limits.py +606 -0
- nav_coasting.py +696 -0
- pnt_resilience.py +558 -0
- quantum_sensing_limits.py +614 -0
- serve.py +14 -0
- 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))
|