kshana 0.21.0

Open, reproducible PNT-resilience simulator with quantum-sensor performance models
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
# Validation status

> **On tolerances.** "Validated" below means a calibration test asserts the simulated
> statistic matches the reference relation within an **enforced gate**, currently
> **20–25% relative error** (seed-averaged) for the Allan/noise-budget relations. Median
> observed agreement is often much tighter (a few percent), but the *guaranteed* bound is
> the gate, not the median. Where a number like "~2%" appears it is a typical observation,
> not the enforced tolerance. See [Claims vs. reality](#claims-vs-reality--quick-reference).

| Noise term | Status | Evidence |
|------------|--------|----------|
| Allan estimator parity (ADEV/MDEV/TDEV/OHDEV) | `validated` | Two primary-source checks against **NIST SP 1065** (Riley, *Handbook of Frequency Stability Analysis*, 2008), both to a **1e-4** relative tolerance. (1) `tests/allan_reference.rs`: the overlapping ADEV, modified ADEV, time deviation, and overlapping Hadamard estimators reproduce the deviations for the canonical 10-point **NBS14** data set (**SP 1065 Table 29/30, p. 107**) at tau = 1, 2 — agreement is actually ~1e-6 (e.g. OADEV(2) 85.952868 vs 85.95287). (2) `tests/allan_nist_sp1065_1000point.rs`: the same four estimators reproduce the **SP 1065 §12.4 1000-point data set** (**Table 31, p. 108**) at averaging factors 1 / 10 / 100, where the data set is regenerated in code from the SP 1065 LCG (Eq. 73) — hermetic, no fixture. The same data and Table-31 numbers are the regression target in aewallin/allantools (`tests/nbs14`), reproduced here with no third-party code. This pins the *estimator maths* against the reference, distinct from the noise-*calibration* rows below. |
| Allan estimator parity on **real measured hardware** | `validated` | `tests/cs5071a_reference.rs`: the overlapping Allan and overlapping Hadamard estimators reproduce the **Stable32** reference deviations for a **real 5071A caesium primary standard measured against a hydrogen maser** (556 990 phase samples at τ₀ = 1 s; 1 PPS into a 53230A counter, Feb 2014; collected by A. Wallin, distributed with `allantools`). Checked across the **whole decade τ ladder (16 averaging factors, τ = 1 s … 4×10⁴ s)**: well-sampled factors to a **1e-3** relative gate (observed agreement is actually ≤ 3e-5, e.g. OADEV(1 s) 3.317111e-10 vs Stable32 3.3171e-10), long-τ sparse factors required to land inside Stable32's printed 1‑σ confidence band. This complements the synthetic NBS14 parity above with a measured-clock check. The raw phase file is third-party data with no redistribution licence, so it is git-ignored; `scripts/fetch_cs5071a.sh` reproduces it and the test prints a skip notice (CI stays green) when it is absent. Only the public Stable32 reference numbers are committed (`tests/fixtures/cs5071a/`); no third-party code is used. |
| Allan estimator parity on the **canonical Stable32 PHASE.DAT** | `validated` | `tests/phasedat_reference.rs`: the overlapping Allan, modified Allan, and time-deviation estimators reproduce the **Stable32** reference deviations for **PHASE.DAT** — the 1001-point series distributed with Stable32 that independent tools (e.g. `allantools`) use as their standard regression target — across the **full averaging-factor ladder (139 factors)** to a **1e-3** relative gate (observed ≤ 5e-5). A second, independent real reference series alongside the measured-caesium check above. PHASE.DAT ships with the commercial Stable32 tool, so the raw series is git-ignored; `scripts/fetch_phasedat.sh` reproduces it and the test skips green (CI stays green) when it is absent. Only the public Stable32 reference numbers are committed (`tests/fixtures/phasedat/`); no third-party code is used. |
| Anomaly-detection ROC AUC on **real ESA OPS-SAT telemetry** | `validated` (reproduces-labels) | `tests/opssat_ad_reference.rs`: on the **OPSSAT-AD** dataset (Ruszczak et al. 2025, Zenodo 10.5281/zenodo.12588359, **CC BY 4.0**) — real OPS-SAT housekeeping segments with ground-truth anomaly labels — Kshana's Mann–Whitney ROC AUC (`impairment_eval::auc`) reproduces **scikit-learn `roc_auc_score`** to **< 1e-9** on the held-out test split (529 segments, 113 anomalies), for two deterministic scores: a transparent single-feature detector (segment peak count, **AUC ≈ 0.851**) and an 8-feature diagonal-Mahalanobis score fitted on the normal training segments (AUC ≈ 0.556); `eval_stats::bootstrap_auc_ci` brackets the point estimate with its lower bound clearing chance. This validates the **AUC computation on real ESA data** and a transparent detector's **labelled separation** — it does **not** reproduce the OPSSAT-AD paper's best published metric (a supervised FCNN, F1 ≈ 0.95), which needs their trained model. CC-BY data vendored (`tests/fixtures/opssat/`, hermetic); oracle regenerated by `generate_opssat_oracle.py`. |
| Gravity-field functional synthesis (gravity-aided / GNSS-free nav map) | `validated` | `tests/icgem_gravity_reference.rs`: the spherical-harmonic gravity-functional kernel (`gravity_sh::gravity_magnitude` / `gravity_disturbance_mgal`) — the "map reader" a gravity-aided navigator matches against — is validated against the **GRS80 normal-gravity standard** (Moritz 1980, IAG-adopted). Building the GRS80 normal field from its published even zonal harmonics J₂…J₈ and synthesising gravity (gravitation + centrifugal) on the ellipsoid reproduces the closed-form **Somigliana** normal gravity, and the published equatorial/polar values γ_e = 9.7803267715 / γ_p = 9.8321863685 m/s², to **3.5e-12** relative across all latitudes (gate 1e-9). The same kernel loads the flagship **real ICGEM Earth model EGM2008** (NGA public-domain via ICGEM; the `from_gfc` reader is also exercised on the GRAIL lunar field in `tests/agency_lro.rs`) and produces a physically-bounded gravity-disturbance map (RMS ≈ 26 mGal, max ≈ 89 mGal at d/o 70). Validates the **synthesis code correctness**; gravity-aided *navigation fix accuracy* stays MODELLED (no public gravimeter-on-a-platform trajectory with ground truth). |
| Noise-type-specific edf (confidence intervals) | `validated` | `src/allan.rs`: the χ² confidence band on each overlapping-ADEV point uses the noise-type-specific effective degrees of freedom (NIST SP 1065 Table 5 closed forms for WPM/FPM/WFM/FFM/RWFM — the Stable32 simple set), with the record's power-law type identified from its MDEV log-log slope. Three independent checks: (a) the five formulas reproduce hand-evaluated values at N=64,m=4 to 1e-12; (b) a **Monte-Carlo white-FM ensemble** (4 000 records) measures the estimator's actual chi-squared edf = 2·mean²/Var(σ²) and matches the formula within 20% (and materially beats the conservative non-overlapping count); (c) `tests/allan_nist_sp1065_1000point.rs` reproduces the printed **SP 1065 Table 32 (p. 109)** edf = 146.177 for the 1000-point data set at m=10 (white FM) to 5e-3, and the table's 95% confidence bounds (8.223942e-2 / 1.035201e-1) to <0.2% (the small residual is the Wilson-Hilferty χ² approximation vs NIST's exact χ²). The exported ADEV curve carries the identified noise type, edf, and 95% band per τ. |
| White FM (short-term) | `validated` | `tests/calibration.rs`: simulated overlapping ADEV reproduces published sigma_y(1 s) — typically within a few percent, **enforced gate 25%** — and the white-FM curve sigma_y(tau)=sigma_y(1s)/sqrt(tau) across tau = 1, 10, 100 s within the same 25% gate (matches CSAC datasheet 3e-10 / 1e-10 / 3e-11). |
| Random-walk FM (long-term) | `validated` | `tests/calibration.rs`: simulated ADEV matches sigma_y^2(tau)=q_rw*tau/3 (Riley NIST SP 1065) to ~20% (seed-averaged). |
| Aging / linear drift | `modeled` + calibrated-out | Deterministic; the holdover estimator removes offset and aging via a quadratic predictor, so the residual is the stochastic limit. Tested in `src/estimator.rs` / `src/models.rs`. |
| Kalman estimator + integrity bound | `validated` | `src/kalman.rs`: a two-state (phase, frequency) filter whose exact van Loan process noise matches the truth model; coasting reproduces the analytic holdover variance `q_wf*T + q_rw*T^3/3` to 1e-9. The covariance update is in **Joseph stabilised form** `P⁺ = (I−KH)P(I−KH)ᵀ + KRKᵀ`, which stays positive-semidefinite (Cholesky-checked) through 500 predict/update steps at an extreme `R=1e-26 / Q≈1e-30` ratio, and agrees with the naive form to 1e-9 where the latter is well-conditioned. The run layer reports Integrity as the fraction of outage samples inside the 3-sigma protection bound (`src/run.rs`). |
| Filter self-consistency (NIS / NEES) | `validated` (model) | `src/filter_health.rs`: a Monte-Carlo consistency assessment (Bar-Shalom §5.4). The matched filter's pooled **NIS → 1** and **NEES → 2** land inside their 95% χ² bands (the NIS band uses the pooled white-innovation count; the NEES band uses the independent-run count, since estimation errors are temporally correlated). A **Q/R-mismatch sweep** test verifies the monitor reports `consistent=true` only at unit tuning and `consistent=false` at ×0.1/×0.5/×2/×10 mistuning, with NIS scaling as ≈1/q_factor as derived. Surfaced as `filter_health` in the clock result JSON and a playground card. The χ² bands use the Wilson–Hilferty quantile (`detection::chi2_inv_cdf`, table-checked). |
| Two-way time-transfer model | `validated` (model) | `src/timetransfer.rs`: the reciprocal common-mode delay cancels exactly in the `(m_AB - m_BA)/2` estimate (hand-derived, exact) and two one-way measurements average to `1/sqrt(2)` (seed-averaged); the non-reciprocal differential delay is a colored white-FM + random-walk-FM process whose Allan deviation follows `sigma_y^2(tau) = q_rw*tau/3` (seed-averaged, ~20%, via the link's own `step()`). The *parameters* (per-link `sigma_j`, `q_rw`) are representative TWSTFT/optical figures, not fitted to a specific terminal. |
| Security (spoof-detection score) | `validated` (model) | `src/security.rs`: the monitor 1-sigma floor `sqrt(r/m + q_wf*tau + q_rw*tau^3/3)` and the resulting `k`-sigma minimum-detectable offset and `[0,1]` score are hand-derived and unit-tested. The model (innovation / RAIM-style clock-aided detection) is sound; the *parameters* (monitoring window `tau`, detection multiplier `k`, measurement noise `r`) are representative, not fitted to a specific receiver. |
| Spoofing-attack detection | `validated` (model) | `src/spoof.rs`: a ramping false-time spoof is flagged when its offset exceeds the clock's detection bound; the detection time matches the hand-derived `start + bound/rate` to one grid step, and a clock whose bound exceeds the spec lets the spoof reach the threshold undetected. Same `representative-parameters` caveat as the Security score. |
| Flicker FM (floor) | `modeled` (off by default) | Synthesised as a sum of log-spaced Ornstein-Uhlenbeck processes calibrated to a configurable flat ADEV floor; `src/models.rs` validates the floor is flat across averaging time and sits at the configured level (seed-averaged). Enabled per clock via `flicker_floor`. The cited reference scenarios leave it off: CSAC is white-FM-dominated across its datasheet range (1-1000 s) and the optical-clock systematic floor (~5e-17) is represented by its accuracy figure. |
| Monte Carlo ensemble statistics | `validated` (aggregation) | `src/ensemble.rs`: nearest-rank percentiles and mean over `runs` reproducible realizations; a single run collapses the spread, the per-timestep band is ordered `p05 <= p50 <= p95`, and reruns are bit-identical. This is statistical aggregation over the already-validated single run, not a new physical model. |

| Clock | sigma_y(1 s) | Source |
|-------|--------------|--------|
| csac-sa45s (CSAC)        | 3.0e-10 | Microchip SA65 / SA.45s datasheet |
| optical-sr-lattice (Sr lattice) | 1.0e-15 | strontium optical lattice clock, space-oriented goal, arXiv:1503.08457 |

**Status: white FM and random-walk FM validated; aging modeled and calibrated-out; flicker FM modeled and validated (off by default in the cited scenarios).**

Maturity: the optical-clock figures are the *space-oriented goal* on ground hardware --
no strontium optical clock has flown. Laboratory Sr clocks reach 4.8e-17 (Oelker et al.
2019, Nature Photonics). CSAC figures are from a deployed commercial part.

Relations: Riley, NIST SP 1065, Eq. 67 -- white FM sigma_y^2(tau)=h0/(2 tau);
random-walk FM sigma_y^2(tau)=(2 pi^2/3) h_-2 tau, equivalently q_rw*tau/3 for a
frequency Wiener process of diffusion q_rw.

## Pack 2 — inertial dead-reckoning (quantum-IMU)

| Term | Status | Evidence |
|------|--------|----------|
| Constant/residual bias -> position | `validated` | pos error = 0.5*b*T^2 family (Groves AESS Tutorial); hand-derived discrete test in `src/inertial.rs`. |
| Velocity random walk (white accel) | `validated` | `src/inertial.rs`: simulated position-error SD matches sigma_x(T)=sqrt(S_a*T^3/3) (Groves eq.54) to ~12% (seed-averaged). |
| CAI accelerometer physics (first-principles) | `validated` (model) | `src/inertial/quantum_imu.rs`: a three-pulse Mach-Zehnder cold-atom interferometer. Hand-verified against textbook geometry — Rb-87 `k_eff = 4pi/lambda ~ 1.611e7 rad/m`; `Phi = k_eff*a*T^2 ~ 1.580e4 rad` at 1 g, `T = 10 ms`; projection noise `sigma_Phi = 1/(C*sqrt(N)) = 2e-3 rad` at `C = 0.5`, `N = 1e6`; per-shot `sigma_a ~ 1.24e-6 m/s^2`; the `1/T^2` and `1/sqrt(N)` scaling laws; exponential contrast decay. `q_va()` **derives** the white-acceleration PSD the classical `AccelModel` consumes. Honest scope: the **quantum-projection-noise floor** only (~0.09 ug/sqrtHz here) — far below real, vibration-limited devices (1-50 ug/sqrtHz); the vibration tensor, Coriolis and light-shift systematics are not yet modelled (see [`QUANTUM.md`](QUANTUM.md)). |
| Gyro bias + angular random walk -> tilt -> gravity coupling | `modeled` (off by default) | A residual gyro bias and ARW drive an attitude error; the tilt couples gravity (`g*theta`) into horizontal specific-force error. `src/inertial.rs` validates the pure-bias cubic position growth exactly and the ARW attitude growth as a Wiener process (seed-averaged). Enabled per sensor via `gyro_bias` and `q_arw`; off in the cited accelerometer-only scenarios. |
| Bias instability (1/f flicker floor) | `modeled` (off by default) | `src/inertial.rs`: a 1/f flicker process (the same OU synthesis validated for the clock) whose flat Allan-deviation floor sits at the bias-instability coefficient; zero is a no-op, a non-zero floor changes the trajectory, both reproducible. Enabled per sensor via `bias_instability`. |
| Acceleration random walk (rate random walk) | `validated` | `src/inertial.rs`: the bias is a Wiener process with `Var(bias_rw(T)) = q_aa*T`, checked seed-averaged to ~20%. Enabled per sensor via `q_aa`. |
| NaveGo cross-validation (IMU noise coefficients) | `validated` | `tests/navego_imu_crossval.rs`: an external cross-check against **NaveGo** (R. Gonzalez, open-source INS/GNSS toolbox, `github.com/rodralez/NaveGo`). Reproduces the synthetic round-trip of NaveGo's `navego_example_allan.m` on its **published Microstrain 3DM-GX3-35 reference profile**: driving our (NBS14/Stable32-validated) overlapping-ADEV estimator with white sensor noise at NaveGo's 1-σ levels recovers the velocity- and angle-random-walk coefficients (`ADEV(1 s) = σ·√dt`) to **< 5%** (actual ~0.4%), with the white-noise branch at the −1/2 slope. Confirms our Allan pipeline and NaveGo's VRW/ARW definitions agree. The 40 MB recorded STIM300 `.mat` log is not ingested (binary-format-gated). |
| Scale factor, finer cross-axis terms | `not modeled` | Scale-factor and cross-coupling errors are future work. |

| Sensor | bias stability | noise root-PSD | Source |
|--------|----------------|----------------|--------|
| cold-atom-quat (quantum) | 5.88e-7 m/s^2 (60 ng, 24 h) | 22 ug/sqrtHz = 2.16e-4 (m/s^2)/sqrtHz | Templier et al. 2022, Science Advances (arXiv:2209.13209) |
| nav-grade-quartz (classical) | 1.57e-3 m/s^2 (~160 ug) | ~20 ug/sqrtHz = 1.96e-4 (m/s^2)/sqrtHz | Honeywell QA-2000 / Groves AESS Tutorial |

Honest framing: the cold-atom advantage is **long-term bias stability** (~2600x lower), which dominates a long GNSS outage via 0.5*b*T^2. Short-term noise is comparable (quantum ~22 vs classical ~20 ug/sqrtHz) — the quantum sensor wins the marathon, not the sprint. Maturity: cold-atom accelerometers are laboratory/early (JRC122785), navigation-grade quartz is deployed.

## Pack 3 — time transfer (optical vs RF, optical inter-satellite link)

| Term | Status | Evidence |
|------|--------|----------|
| White timing jitter -> sync precision | `validated` | `src/timetransfer.rs`: simulated sync RMS reproduces the link jitter sigma_j; sample-mean averages as sigma/sqrt(N) to <20% (seed-averaged). |
| Timing -> one-way ranging | `validated` | range = c * dt, c=299792458 m/s; 1 ps = 0.299792458 mm (exact, hand-derived test). |
| Flicker/TDEV floor, two-way reciprocity residual | `not modeled` | Jitter is modeled as white; long-averaging floors and reciprocity residuals are future work. |

| Link | single-sample jitter | type | source |
|------|---------------------|------|--------|
| optical-isl | 1 ps (1e-12 s) | on-orbit-credible target | optical inter-satellite link, picosecond sync target; lab O-TWTFT ~1 fs (Giorgetta 2013 / Deschenes 2016) |
| twstft-rf | 0.5 ns (5e-10 s) | measured single-session | BIPM/PTB/NIST TWSTFT |

Honest framing: the optical figure is a picosecond-level on-orbit synchronization target (not flown). The terrestrial optical lab floor is ~1 fs (far better); a well-engineered microwave link (ACES MWL, ~0.3 ps) can rival optical, so the "RF = 0.5 ns" baseline is specifically ordinary TWSTFT. Ranging conversion is one-way (range = c*dt); two-way/round-trip halves it (range = c*dt/2).

## Pack 4 — hybrid fusion (capstone)

Composes Pack 1 (clock), Pack 2 (inertial), and Pack 3 (time-transfer) into one PNT
suite. The suite must keep BOTH timing (< timing spec) and position (< position spec)
within bounds; `pnt_holdover_s` is the time until either breaches. Optional optical
inter-satellite time-transfer re-syncs the clock during the outage (time aiding only —
position is not re-synced, since time transfer gives time, not position).

| Aspect | Status | Evidence |
|--------|--------|----------|
| Combined PNT scoring (timing AND position) | `validated` | `src/hybrid.rs` hand-derived `score_hybrid` test (pnt_holdover = first of timing/position to breach). |
| Integrity + Security for the hybrid pack | `validated` | `src/hybrid.rs`: a Kalman timing estimator disciplined to truth (nominal) and re-anchored at each optical re-sync; Integrity is the protection-bound containment (bound includes the link-jitter floor), Security the spoof-detection score. Tested for both suites including the link-aided case. |
| Joint fusion estimator | `validated` (model) | `src/fusion/mod.rs`: a single joint Kalman filter ([phase, freq] ⊕ [pos, vel]) is the navigator, disciplined by GNSS (learning the offsets from non-zero initial covariance) and aided by time transfer; the joint covariance gives a joint integrity that is tested reliable (≥0.9) for both suites with noise-consistent sensors. The pack observes position and time **separately**, for which the optimal filter is block-diagonal; augmented-state constant-bias estimation and dynamic cross-aiding are future work. |
| Coupled clock+position filter (cross-block covariance) | `validated` (model) | `src/fusion/coupled.rs` `CoupledPntFilter`: a single stacked `[pos, vel, phase, freq]` Kalman filter (Joseph-form updates) whose **pseudorange** measurement `ρ = g·pos + c·phase + noise` couples the position and clock blocks. Tests: a shared pseudorange drives `P[pos,phase]` non-zero (decoupled filters keep it exactly 0); two distinct geometries jointly resolve injected position and clock offsets a single range cannot separate; a **clock-only** fix sharpens the **position** through the cross-covariance (the payoff coupling provides and decoupled filters cannot); and a Monte-Carlo **NEES is χ²(4)-consistent** (Bar-Shalom §5.4, run-based band). 1-DOF (the pack's dimensionality); not yet wired into the runnable pack, and the 3-D 8-state extension is future work. |
| Composition of validated sub-models | inherits | clock/inertial/time-transfer terms are validated in their own packs. |
| Loosely-coupled GNSS/INS (`gnss-ins` pack) | `validated` (model) | `src/fusion/{gnss_ins_ekf,closed_loop,pack}.rs`: a 15-state error-state EKF (δp, δv, ψ, accel/gyro bias; Groves §14) drives the three-axis strapdown navigator with feedback. Tests: an injected position error nulls under perfect-truth aiding; the aided solution stays metre-bounded while a free-running INS diverges past 100 m; and the fused position RMS over a 60 s outage beats unaided dead-reckoning by ~4× (ensemble). Honest limit: loosely-coupled accel-bias/tilt are weakly separable, so per-bias calibration is not claimed. |
| Tightly-coupled GNSS/INS (pseudorange) | `validated` (model) | `src/fusion/gnss_ins_ekf.rs` `update_tightly_coupled` + `closed_loop.rs` `fuse_tightly_coupled`: the innovation is formed in the range domain (line-of-sight Jacobian on δp). Tests: four satellites null an injected 8 m/−5 m horizontal error to < 0.1 m; **two satellites** (no PVT fix possible) still cut the horizontal error by > 5×; a single overhead satellite observes only the along-line-of-sight (vertical) component and leaves the horizontal untouched; malformed inputs are rejected. Pseudorange-only — carrier phase and an explicit receiver-clock state are roadmap. |
| Sensor cross-aiding fidelity (full Kalman/factor-graph fusion) | `not modeled` | This is a system-level composition + time-aiding, not yet a full optimal estimator. |

Result: the all-quantum suite holds full PNT through a 1.8 h outage; the all-classical
suite is **position-limited** (nav-grade IMU breaches first). Optical ISL time-transfer
keeps even the classical CLOCK locked, isolating the inertial sensor as the classical
suite's weak link — the core argument for quantum inertial + optical timing together.

## Geometry — GNSS availability from orbits

| Aspect | Status | Evidence |
|--------|--------|----------|
| Circular two-body propagation | `validated` | `src/orbit.rs`: period `T=2 pi sqrt(r^3/mu)` (mu = 3.986004418e14), position returns after one period, equatorial/polar planarity — hand-derived tests. |
| Eccentric (Keplerian) propagation | `validated` | `src/orbit.rs`: Kepler's equation `M = E - e sin E` solved by Newton (residual < 1e-12); perigee/apogee radii `a(1∓e)`; circular case matches the closed-form path to 1e-9. |
| J2 secular nodal/apsidal drift | `validated` | `src/orbit.rs`: `Omega_dot = -1.5 n J2 (Re/p)^2 cos i`, `argp_dot = 0.75 n J2 (Re/p)^2 (5cos^2 i - 1)` (Vallado); node regresses (prograde) / advances (retrograde) / is stationary (polar), and apsides freeze at the critical inclination 63.4 deg — hand-derived sign/zero tests. Two-body + secular only, not osculating. |
| Line-of-sight visibility (Earth occultation + elevation mask) | `validated` | Antipodal sat occulted, radially-outward sat at 90 deg elevation, tangential sat on the horizon — exact hand-derived tests. |
| Visibility -> GNSS state -> timeline | `validated` | `>=4` visible = nominal, 1-3 degraded, 0 denied; Walker-delta generator; integration test drives a clock-holdover run from the derived timeline. |
| Constellation-design optimiser + streets-of-coverage geometry | `validated` (model) | `src/walker.rs`: `optimize_walker_design` searches the `{planes × sats × inclination}` grid and returns the cell that best meets a `DesignObjective` (min satellites for a coverage target / max coverage / min worst-PDOP) — a test asserts the pick equals an independent brute-force scan of the same sweep, and a worked example confirms a GPS Walker 24/6/1 design covers at least as well as a thinned 18-satellite one. The analytical **streets-of-coverage** closed forms (`coverage_half_angle_rad` `λ = arccos(Re/r·cos ε) − ε`; `street_half_width_rad` `cos c = cos λ / cos(π/s)`, Rider/Beste) are hand-verified against textbook geometry (GPS at a 5° mask: λ ≈ 71.16°, 4-sat street half-width ≈ 62.83°) and detect the under-population gap (`λ < π/s ⇒ None`). The full Rider minimum-satellite *global*-coverage solver (the seam-sensitive plane count) is not yet implemented. |
| Dilution of precision (GDOP/PDOP/HDOP/VDOP/TDOP) -> position accuracy | `validated` | `src/orbit.rs`: `Q=(HᵀH)⁻¹` from the line-of-sight design matrix. **External oracle** (`tests/dop_reference.rs`): the five DOP factors reproduce those computed by **gnss_lib_py 1.0.4** (Stanford NAV Lab — an independent, peer-reviewed GNSS library, used here as ERFA is for the frames) across **8 geometries** spanning well-conditioned to near-singular (DOP in the hundreds), to **1e-6** relative; provenance + regeneration in `tests/fixtures/dop/`. As an additional closed-form check, a regular-tetrahedron geometry reproduces the analytic DOPs (PDOP 1.5, TDOP 0.5, GDOP √2.5, HDOP √1.5, VDOP √0.75) to 1e-9. Position sigma = PDOP × user-equivalent range error. |
| Multi-constellation availability | `validated` | `src/orbit.rs`: additional `[[constellations]]` are merged into one satellite set for visibility/DOP; a combined-count test confirms the union. |
| Broadcast ionosphere (Klobuchar, IS-GPS-200) → L1 slant delay | `validated` | `src/gnss_sim.rs`: `klobuchar_delay_m`, the eight-coefficient broadcast single-frequency model. **External oracle** (`tests/klobuchar_reference.rs`): the slant L1 delay reproduces **RTKLIB's `ionmodel`** (tomojitakasu/RTKLIB, `src/rtkcmn.c` — the de-facto open GNSS reference, compiled from source and run independently) across **10 cases** spanning elevation, azimuth, local time and two coefficient sets (kshana's default + RTKLIB's), to **< 1e-4 m**. The IONEX TEC-map *reader* for real 80-column GIM files (and a real-CODE-GIM cross-check of the bilinear/time interpolation) is a tracked follow-up; the broadcast model itself is externally validated. |
| RAIM/ARAIM detection kernel (χ² / non-central χ² / normal) → thresholds & multipliers | `validated` | `src/raim.rs`: the snapshot / solution-separation / ARAIM detection threshold (`chi2_quantile`), the missed-detection non-centrality `pbias=√λ` (`noncentral_chi2_cdf`), and the K_fa/K_md/K_V multipliers (`normal_quantile`) are all evaluated from a dependency-free regularized incomplete-gamma function. **External oracle** (`tests/raim_reference.rs`): **171 cases** reproduce **SciPy 1.17.0** (`scipy.stats.chi2`/`.ncx2`/`.norm` + `optimize.brentq` — an independent Cephes/Boost implementation, a different algorithm) across the P_fa / P_md / redundancy operating ranges, to **≤ 1e-6 relative**. The geometry that wraps the kernel (the slope/covariance from `(GᵀG)⁻¹`) is the gnss_lib_py-validated DOP kernel. **Scope:** this pins the *statistical kernel*; the protection-level *value* and the ARAIM MHSS budget allocation are not pinned to a published reference value (see the standards note below). |
| SBAS protection level (DO-229E Appendix J) → HPL / VPL | `validated` | `src/sbas.rs`: `sbas_protection_level`, the weighted-LS `D=(GᵀWG)⁻¹` → horizontal error-ellipse major axis + vertical σ, scaled by the DO-229E K-factors. **External oracle** (`tests/sbas_reference.rs`): kshana's HPL reproduces the **RTKLIB SBAS-PL fork** (`zsiki/rtklib_ws` `waasprotlevels()`, the Siki & Takács 2017 "DO-229D Appendix J" implementation), run by `rnx2rtkp -ws` on **real EGNOS data** (GEO PRN120 broadcast messages + real BUTE/Budapest RINEX, 2017-02-19), across **6 epochs** to **< 2e-3 m**. The σ per satellite is the oracle's own full SBAS budget (UDRE + GIVE iono + tropo + airborne). ESA gLAB v6.0.0 (`core/filter.c`) was compiled and confirmed to use the identical convention. **K_V note:** both oracles round the MOPS K_V → 5.33; kshana uses the exact `Φ⁻¹(1−5e-8)=5.3267` (~0.06 % smaller VPL), so the vertical is validated as the K-factor-free `d_U` (= oracle VPL / 5.33). HPL is matched directly (K_H = 6.0 on both sides). |
| Real constellation geometry from TLEs (line-2 / Keplerian) | `validated` (parsing) | `src/tle.rs`: parses the line-2 mean Keplerian elements (semi-major axis from the mean motion); a known ISS element set round-trips to the correct elements and period. For a line-2-only block, propagation is the engine's two-body (+ optional J2) of the *mean* elements — sound for a snapshot from a common epoch, drifting from SGP4 over time. |
| SGP4 / SDP4 propagation (full TLEs) | `validated` | `src/sgp4.rs`: full near-Earth SGP4 + deep-space SDP4 (lunar-solar secular/periodic + 12 h / 24 h geopotential resonance). Validated in `tests/sgp4_verification.rs` against the official AIAA 2006-6753 ("Revisiting Spacetrack Report #3") vectors — all 666 reference states (near-Earth, deep-space, resonant, error-code cases) match to a worst-case position error of ≈ 4.1 mm. A full two-line set (line 1 + line 2) is propagated with SGP4; line-2-only stays Keplerian; the two can be mixed. Frame is TEME, used consistently for the user and satellites (no TEME→ECEF reduction — adequate for availability/DOP geometry). |
| IAU 2000A / 2000B nutation + TEME→GCRS reduction | `validated` | `src/nutation.rs`: the **full IAU 2000A** series (678 luni-solar + 687 planetary terms, `nutation_iau2000a`) and the 77-term 2000B truncation (`nutation_iau2000b`) are each validated **bit-for-bit** against the published SOFA/ERFA reference vectors at JD_TT 2453736.5 — `eraNut00a` gives Δψ = −0.9630909107115518e-5, Δε = 0.4063239174001679e-4; `eraNut00b` gives Δψ = −0.9632552291148363e-5, Δε = 0.4063197106621160e-4 — both to **1e-13 rad**. The 2000A table is machine-generated from the ERFA `nut00a` source by `tools/gen_nut00a.py` (reproduces the committed `nutation_iau2000a_data.rs` bit-for-bit). The nutation matrix (`iauNumat`), equation of the equinoxes, and the full TEME→TOD→MOD→GCRS chain (`teme_to_gcrs`, Vallado AIAA-2006-6980) are tested for proper-rotation/round-trip/precession-plus-nutation properties; 2000A vs 2000B agree to < 1 mas as required. The chain is equinox/GMST-based; the equinox-free CIO (X,Y,s) reduction and its independent ANISE/SPICE numerical cross-check (≤ 3.6 m at GNSS orbit, well inside the < 10 m target) are in the CIO row below. |
| IGRF-14 geomagnetic main-field model | `validated` | `src/igrf.rs`: the IAGA Schmidt-normalised spherical-harmonic field (degree/order 13, 2025.0 + secular variation; coefficients machine-generated from the official `igrf14coeffs.txt` by `tools/gen_igrf.py`, reproducing `igrf_data.rs` bit-for-bit). Validated on five independent fronts: (1) exact coefficient spot-checks vs the IAGA file (g₁⁰=−29350.0, g₁¹=−1410.3, h₁¹=4545.5 nT); (2) the degree-1 synthesis reproduces the **exact closed-form tilted dipole** field `(B_r,B_θ,B_φ)` to 1e-6; (3) the **full degree-13 analytic field equals −∇V** of the scalar potential (finite-difference, to 1e-4) — exercising the Legendre derivatives and the 1/sinθ term end-to-end; (4) the dipole axis reproduces the known **geomagnetic north pole** (~80.7°N, −72.7°E) and **dipole strength** (~29.7 µT), and the global field lies in the physical 22–67 µT band with the correct hemisphere dip sign; and (5) **external oracle** — the full synthesis reproduces the official **British Geological Survey IGRF-14 web-service** values at 2025.0 (geodetic, WGS-84 altitude) to **< 2 nT** on X/Y/Z/F and **< 0.02°** on D/I at four points including 400 km altitude (`synthesis_matches_the_official_bgs_igrf14_values_at_2025`). |
| CIO-based IAU 2006/2000A GCRS↔ITRS reduction | `validated` | `src/cio.rs`: the equinox-free celestial-to-terrestrial chain. The CIP coordinates `(X, Y)` and the 66-term CIO-locator `s` series are validated **bit-for-bit** against the published SOFA/ERFA `eraXys06a` vector at JD_TT 2453736.5 — X=0.5791308482835292617e-3 (1e-14), Y=0.4020580099454020310e-4 (1e-15), s=-0.1220032294164579896e-7 (1e-18); the GCRS→CIRS matrix against `eraC2ixys` (all nine elements to 1e-12); the Earth rotation angle against `eraEra00(2400000.5, 54388.0)` = 0.4022837240028158102 (1e-12). The `s` table is machine-generated from the ERFA `s06.c` reference by `tools/gen_s06.py` (reproduces `cio_s06_data.rs` bit-for-bit). The full `gcrs_to_itrs_matrix` (CIO `eraC2tcio` = polar-motion · ERA · GCRS→CIRS) is tested for proper-rotation + round-trip, and shown consistent with the legacy equinox/GMST-1982 TEME reduction up to the documented ≈2·(equation of equinoxes) sidereal-convention difference. **Independent third-party cross-check (`xval/anise-frames/`):** the same `gcrs_to_itrs_matrix` is compared against **ANISE** (the pure-Rust NAIF/SPICE reimplementation) rotating GCRF→ITRF93 from JPL's `earth_latest_high_prec.bpc`, with **identical IERS `finals2000A` Earth-orientation parameters fed to both sides**, over eight quarterly epochs 2020–2023. The two independent frame realizations agree to a **maximum relative rotation of 0.028″ — ≤ 0.86 m on the ground, ≤ 0.93 m at LEO, ≤ 3.6 m at GNSS orbit** (mean angle 0.023″). This is the ROADMAP "< 10 m" frame cross-check, **delivered**; the residual is the expected ITRF93-vs-IERS-2010-CIO model/datum difference, not a defect (the bit-for-bit anchor remains the SOFA/ERFA vectors above). ANISE is an MPL-2.0 / edition-2024 crate, so the check lives in a standalone, workspace-excluded sub-crate that never touches the published `kshana` dependency graph or any default CI gate. |
| SP3 export round-trip (constellation → SP3-c → re-parse) | `validated` | `tests/sp3_export_roundtrip.rs`: the real Celestrak `gps-ops` snapshot (30 GPS satellites) is propagated with SGP4, exported to SP3-c (`Sp3File::from_propagators` → `to_sp3_string`), re-parsed (`parse_sp3`), and the recovered ECEF positions are compared against the SGP4 truth at every epoch over 24 h — worst residual **< 0.5 m** (the writer's millimetre serialisation; the milestone's 10 m TLE-grade tolerance is met with large margin). The CLI `--export-sp3` path is covered too: the bundled orbit scenario exports a re-parseable 30-satellite SP3, and a non-orbit scenario is rejected. |
| Real GPS constellation geometry from TLEs (SGP4 → ECEF) | `validated` | `tests/igs_real_data.rs`: a genuine **Celestrak `gps-ops` snapshot** (2021-07-28, 30 operational GPS satellites; provenance in `tests/fixtures/celestrak/NOTICE`) is parsed and each satellite propagated through the validated SGP4 core to a common instant, rotated TEME→ECEF. Asserts the full constellation lands on the GPS MEO shell within 1%, and that from a mid-latitude open-sky site the real all-in-view (nine satellites) yields PDOP 1.64 with the vertical dilution exceeding the horizontal (as it must for a ground user). This exercises SGP4 on a real constellation, alongside the SP3 (precise) and RINEX (broadcast) real-data paths. |
| SGP4 mean-element Walker generator | `validated` | `src/walker.rs`: a designed Walker-delta pattern is emitted as SGP4 mean elements (Kozai mean motion chosen so the SGP4 semi-major axis lands on the target shell) and propagated through the validated core. Tests: a 24-satellite GPS-like Walker sits on the MEO shell within 1%, the planes are spaced exactly 90° in RAAN recovered from the orbit normals, and the mean motion reproduces the ~718 min GPS-shell period. |
| Constellation PDOP sweep + coverage/revisit FoMs | `validated` (monotonicity) | `src/walker.rs`: `pdop_sweep` tabulates coverage and median/worst PDOP over a `{planes × sats × inclination}` grid; `coverage_revisit` reports the coverage fraction and revisit gaps at a ground point. Validated by the physical monotonicities a design trade must obey: adding satellites never lowers coverage and strictly lowers the median PDOP (a full 24-satellite design covers continuously at PDOP ~1.7), and densifying a thinned constellation strictly shrinks the worst revisit gap. The mean revisit gap never exceeds the max. These are geometry trade tables, not a certified link/coverage budget. |

Honest framing: this is a deterministic geometry layer (circular orbits, spherical
Earth of mean radius 6371 km, pure line-of-sight). It establishes *availability* and
the *geometric* position accuracy (dilution of precision × a representative range-error
budget) from real geometry, not a precise-ephemeris navigation solution. The
`orbit-gnss-challenged.toml` reference puts a spacecraft inside the GNSS shell: it holds
a fix only ~59% of the day, the quantum clock keeps a 5 ns timing solution through every
gap (availability 1.0) while the chip-scale clock holds ~0.83.

## Numerical (Cowell) propagator & force model

The numerical propagator (`src/propagator.rs`) integrates a hierarchical force model
(`src/forces.rs`) with the adaptive integrators (`src/integrator.rs`). Each term is
validated against analytic truth or a hand-derived closed form, not against another
tool; the perturbations are **off by default**, so the released goldens are untouched.

| Term | Status | Evidence |
|------|--------|----------|
| Cowell propagator vs analytic Kepler truth | `validated` | `src/propagator.rs`: the unperturbed (two-body) orbit reproduces the **exact universal-variable Kepler solution to sub-metre over a 24 h LEO orbit** (a tighter gate than "vs a numerical reference < 10 m"); specific energy and angular momentum conserve to ~1e-9 relative; the J2 nodal regression reproduces the closed-form `j2_secular_rates` to first-order theory (within 2 %, the O(J2²) residual). `solve_kepler_checked` returns `Err` rather than a silently-wrong answer when Newton fails to converge (near-perigee e = 0.999). |
| Adaptive integrators (RK4 step-doubling + Dormand–Prince RK5(4)) | `validated` | `src/integrator.rs`: RK4 integrates `y' = y → e` to < 1e-9, shows the ~16× error drop per halved step (4th-order convergence), and conserves the harmonic oscillator over a period. The DP5(4) embedded error estimate is **O(h⁵)** (halving the step cuts it ~32×), integrates the oscillator over 50 periods conserving energy to < 1e-6, and reaches the same endpoint at the same tolerance in **fewer function evaluations** than step doubling; `propagate_dopri` clears the same sub-metre Kepler gate and agrees with the RK4 path to < 1 m on a J2..J6 orbit. |
| J2–J6 zonal-harmonic field | `validated` | `src/forces.rs`: `zonal_accel` is checked three ways — it **reduces to the 666-vector-validated `j2_accel` to machine precision** when restricted to `[J2]`; it **matches the numerical gradient of its own zonal potential** through the full J2..J6 field (the conservative-field gold standard); and the odd `J3` vs even `J2`/`J4..J6` terms show the characteristic north–south (anti)symmetry under `z → −z`. A propagated J2..J6 orbit conserves total energy to ~1e-8 over a day. |
| Third-body (Sun and Moon) gravity | `validated` | `src/forces.rs` + `src/ephem.rs`: `third_body_accel` **matches the exact gradient of its disturbing potential**, vanishes at the geocentre, and hits the textbook LEO magnitudes (~5e-7 m/s² Sun, ~1.1e-6 m/s² Moon). The low-precision Montenbruck–Gill Sun ephemeris hits hand-derived J2000 anchors (perihelion distance ≈ 1.471e11 m, ~−23° solstice declination, ~1°/day motion); the Moon ephemeris stays inside its perigee/apogee envelope, recovers the ~384 400 km mean distance, never exceeds the 5.3° inclination, and returns to within 1° after one sidereal month. The epoch-driven RHS wiring is **bit-exact** (the RHS term equals `third_body_accel` at the sampled position at t = 0 and t = 1 day), and a quarter-year epoch shift yields a different trajectory. |
| Solar-radiation pressure + conical shadow | `validated` | `src/forces.rs`: `srp_accel` (cannonball `ν·P☉·cᵣ·(A/m)·(AU/d)²·d̂`) is **bit-identical** to the closed form in full sun, pins the **1-AU radiation pressure to ≈ 4.5398e-6 N/m²**, sits in the ~1.36e-7 m/s² LEO band pushing away from the Sun, quarters when the Sun distance doubles (inverse-square), and is **exactly zero** deep in the umbra. `conical_shadow` gives `ν = 1` in full sun and `ν = 0` in total umbra (exact), a smooth monotonic penumbra rising 0 → 1 across the `[b−a, b+a]` band that **extends beyond the umbral cylinder**. |
| Atmospheric drag (first velocity-dependent term) | `validated` | `src/forces.rs`: `atmospheric_density` (Vallado Table 8-4 piecewise-exponential) **anchors at 1.225 kg/m³ at sea level**, clamps below the surface, decreases monotonically through LEO, sits in the ~1e-12 kg/m³ band at 400 km with a physical recovered ~58 km scale height; `drag_accel` opposes the co-rotating relative velocity at the ~2e-6 m/s² LEO magnitude. The signature check: a 300 km orbit loses specific energy **monotonically** and its semi-major axis decays a bounded ~km/day, where the vacuum baseline conserves energy to < 1e-9. |
| Post-Newtonian (Schwarzschild) relativistic correction | `validated` | `src/forces.rs`: `relativistic_accel` (IERS `β = γ = 1` form `a = (μ/c²r³)·{[4μ/r − v²]·r + 4(r·v)·v}`) collapses on a circular orbit to the closed form `3μ²/(c²r³)·r̂` (radial, **outward**, off-axis components exactly zero), shows the textbook **`≈1.9e-9` LEO ratio to two-body**, matches the hand-simplified radial-velocity form `μ(4μ + 3v²r)/(c²r³)` to < 1e-12, and in the propagator **perturbs the orbit while holding the semi-major axis to under a metre/day** — the conservative opposite of drag's decay. |

Honest scope: the released `ForceModel` defaults integrate the zonal field. The
high-degree EGM2008 **tesseral** field (`src/gravity_sh.rs`, degree/order 70), the
solid/ocean/atmospheric **tides** (`src/tides.rs`), and the **Lense–Thirring**
frame-dragging term are now implemented and composed into the precise
ephemeris-fitting force model (`src/precise_od.rs` — see below). The NRLMSISE-00 thermospheric
density (drag is the static Vallado model), solar limb darkening / the oblate-Earth
shadow, DE-grade ephemeris accuracy, and an external GMAT/Orekit cross-validation of a
high-fidelity run remain follow-ons.

## Tides on the geopotential (`src/tides.rs`)

Time-varying corrections ΔC̄_nm, ΔS̄_nm to the Stokes coefficients (IERS Conventions
2010, Chapter 6), validated against the conventions' own published numbers — not against
another tool.

| Contribution | Status | Evidence |
|------|--------|----------|
| Solid Earth tide (IERS Eq. 6.6 / 6.8b / 6.14) | `validated` | `tests/tides_iers.rs`: the permanent (zero-frequency) tide ΔC̄₂₀ lands within 1 % of the IERS-published −4.1736×10⁻⁹ (anelastic Love numbers); the **Step-2 K1 worked example is reproduced bit-for-bit** (sin/cos amplitudes 470.9 / −30.2 ×10⁻¹² to 0.1×10⁻¹²); the normalized Legendre path is pinned by closed-form hand values independent of the recurrence. |
| Ocean tide (IERS Eq. 6.15, FES2004, 8 constituents) | `validated` | The vendored FES2004 subset (`tools/gen_fes2004.py` → `src/fes2004_data.rs`, Doodson→multiplier parse) reproduces the source M2 (2,2) coefficients exactly; the K1 Doodson phase equals θ_g + π; the degree-2 sectorial magnitude is physical and an order below the solid tide. |
| Atmospheric S2 air tide (Ray 2001, NASA GSFC) | `validated` | The vendored Ray harmonics convert through the surface-load relation (Eq. 6.21) to a peak ΔC̄₂₂ ≈ 4×10⁻¹¹ (~10 % of the ocean M2 term). Honest caveat: **no published geopotential-coefficient oracle exists for the air tide**, so it is validated by source-integrity + magnitude, a weaker bar than the solid/ocean tides. |

## Maneuvers & trajectory design (`src/maneuver.rs`)

| Aspect | Status | Evidence |
|--------|--------|----------|
| Impulsive ΔV + covariance propagation | `validated` | A velocity discontinuity with a 6×6 covariance carried forward (deterministic burn ⇒ identity STM; the execution-error covariance rotates from the burn frame — ECI or LVLH — into the velocity block). |
| Finite-burn integration vs Tsiolkovsky | `validated` | Constant-thrust integration over a burn arc (mass as a state) whose achieved ΔV matches the closed-form **Tsiolkovsky** rocket equation to **better than 0.01 %**. |
| Lambert solver (Izzo 2015) round-trip | `validated` | The single-revolution Lambert output (`r1`, `r2`, time-of-flight ⇒ `v1`, `v2`) is **round-tripped through the exact universal-variable Kepler propagator** — it must land back on `r2`. |
| Porkchop sweep vs Hohmann floor | `validated` | The launch × arrival C3 / arrival-V∞ grid's minimum is checked against the **analytic Hohmann-transfer C3 floor** for two coplanar circular orbits. |

Honest scope: no trajectory optimizer, no multi-revolution Lambert branches, and a
synthetic coplanar-circular heliocentric model (no planetary DE ephemeris, so a GMAT
Earth–Mars C3 cross-check has not been run).

## Orbit determination (`src/orbit_determination.rs`, `src/batch_ls.rs`)

| Aspect | Status | Evidence |
|--------|--------|----------|
| Gauss–Newton batch corrector | `validated` | The generic `gauss_newton` solver reaches the exact weighted-least-squares solution on a linear fit, recovers true parameters on a nonlinear `a·exp(b·t)` fit, and solves a 3-D range-multilateration from noiseless ranges. |
| Batch orbit determination from ranges | `validated` | `determine_orbit_batch` recovers `[r, v]` from ground-station range tracking (propagated over the two-body + J2 force model) to **sub-metre / mm·s⁻¹ from noiseless ranges**, and to **~2 m with a post-fit residual at the 5 m noise floor** — the signature of a consistent least-squares fit. |
| Sequential (unscented-filter) OD | `validated` | `determine_orbit_sequential` recursively recovers the state to within tens of metres on the same dynamics and range model. |

Honest scope: range-rate/Doppler and angle measurements and station-visibility masking
are follow-ons for the range-only teaching estimator (the full-force ephemeris-fitting engine
below carries the variational state-transition matrix).

## Force-model validation by ephemeris fitting (`src/precise_od.rs`)

A precise, full-force position-observation batch least-squares estimator: the
EGM2008 tesseral geopotential (evaluated in the Earth-fixed frame through the CIO
reduction) composed with the Sun/Moon third body, SRP, drag, Schwarzschild/Lense–Thirring
GR, and the tides above, fit to a track of inertial position fixes with a variational
state-transition-matrix Jacobian. Validated on **synthetic** data, where the truth is
Kshana's own integrator, so every residual is the estimator's and not the dynamics'.

| Aspect | Status | Evidence |
|--------|--------|----------|
| Precise force model composition | `validated` | `tests/precise_od_synth.rs`: the degree-0 field is the exact point mass at every epoch (the central term is rotation-invariant); degree-8 adds the J2-band oblateness; the Sun third body and the tide term wire in bit-faithfully; a constant radial empirical acceleration is purely radial in RTN. |
| Variational state-transition matrix | `validated` | Every column of Φ over a half LEO orbit (degree-8 geopotential + Sun + Moon) agrees with an independent **whole-arc central finite-difference** re-propagation to **< 1×10⁻⁶ relative** in both the position and velocity response — the documented STM↔FD cross-check. Φ(0) = I; the augmented and plain propagators agree to sub-millimetre. |
| Batch-LS self-recovery | `validated` | A 1-hour Kshana arc (degree-6 + Sun + Moon) observed noise-free is recovered from a 150 m / 0.1 m·s⁻¹ offset to the **epoch state within 1×10⁻² m** with near-zero post-fit RMS; with 5 m white noise the post-fit 3-D RMS settles at the **~σ noise floor**, unbiased. SRP **C_R is recovered from 1.0 to within 1 %** of the 1.4 truth. |
| Outlier editing & RTN reporting | `validated` | A 500 m gross blunder is rejected by 5-σ post-fit editing (exactly one observation), leaving a clean millimetre-level fit; residuals are reported decomposed into radial/transverse/normal as well as 3-D. |
| Empirical-acceleration tier (RTN constant + 1-CPR) | `validated` | The nine a-priori-constrained empirical parameters stay below 1×10⁻⁸ m·s⁻² on empirical-free truth without disturbing the fit; a constant 3×10⁻⁸ m·s⁻² cross-track acceleration injected into the truth is recovered to within 20 %. |

Honest scope: the synthetic wave uses nominal Earth-orientation parameters (UT1 ≈ TT, no
polar motion) — exact for self-recovery, since the same model generates and fits the arc.
The agency-dataset validations layer **real** finals2000A EOP and SP3/SPK truth on top of
this engine through the CIO frame chain (`src/eop.rs`, `tests/agency_galileo.rs`,
`tests/agency_swarm.rs`, `tests/agency_lro.rs`).

### Real agency precise orbits (`tests/agency_galileo.rs`, `tests/agency_swarm.rs`, `tests/agency_lro.rs`)

| Dataset | Status | Evidence |
|---------|--------|----------|
| **Galileo MEO — < 5 m GREEN** | `validated` | Kshana's full-force engine fit to a verbatim slice of **ESA/ESOC's own final orbit** (`ESA0MGNFIN`, ITRF) for Galileo **E11** over 8 h, each ITRF fix rotated into GCRS with real finals2000A EOP: post-fit **3-D RMS 0.132 m** pure force + `C_R` (RTN 0.105/0.067/0.047 m, `C_R` 1.174), **0.070 m** with the empirical tier, from a 78.7 km raw overlap. The full 24 h arc is **0.611 m**. All far inside the 5 m bar. Field gravity-converged by d/o-8 (identical at d/o 8/10/12); the `workflow_dispatch` job runs the full d/o-70. Provenance + SHA-256 in `tests/fixtures/agency/NOTICE.md`; full record in `docs/AGENCY-ORBIT-VALIDATION.md`. |
| **Swarm-A LEO — < 5 m GREEN** | `validated` | Full-force engine (+ atmospheric drag) fit to a verbatim slice of **ESA's own Swarm-A reduced-dynamic precise orbit** (`SW_OPER_SP3ACOM_2_`, L47, ITRF, ~430 km, ~2 cm) over 3 h at d/o-70, real finals2000A EOP through the CIO chain: **dynamic** tier (state-only, static density, `C_R`=1) post-fit **3-D RMS 2.687 m** (RTN 0.925/**2.522**/0.043 m — residual ≈ pure along-track drag), **reduced-dynamic** tier (+ empirical CPR accelerations) **0.098 m** (RTN 0.026/0.092/0.024 m) — ~10 cm against ESA's ~2 cm orbit. Provenance + SHA-256 in `tests/fixtures/agency/NOTICE.md`; full record in `docs/AGENCY-ORBIT-VALIDATION.md`. |
| **LRO lunar — validated, above 5 m (honest)** | `validated` | **Moon-centred** force-model fit (`src/lunar_od.rs`): the GRAIL **GRGM660PRIM** gravity field (d/o 100) in the lunar body-fixed principal-axis frame (`src/lunar_frame.rs`, IAU 2015 mean-Earth + the fixed DE421 ME→PA offset) + Earth/Sun third body, fitted through the *same* generic Gauss–Newton estimator as the Earth datasets to the real **JPL Horizons LRO** (NAIF −85) reconstructed orbit, 4 h / 241 epochs, ~98 km. Honest post-fit: **dynamic 12.6 m** (RTN 3.07/10.19/6.81), **reduced-dynamic 6.6 m** (RTN 3.49/4.56/3.35, 1+2-per-rev empirical), from a 53.8 m raw overlap — **above** the < 5 m bar, not the estimator (identical at d/o 100/150 and `atol` 1e-6/1e-9). A **DE-grade cross-validation** (`xval/anise-lunar-od`: DE440 lunar PA orientation + DE440 ephemeris via ANISE) **corrected** the limiting-factor claim — it improves the dynamic fit (12.6 → 12.0 m) but leaves the **reduced-dynamic floor unchanged** (6.65 → 6.67 m), so the operational floor is **not** the analytic orientation/ephemeris but an empirical-tier-irreducible residual (most consistent with unmodelled LRO non-gravitational dynamics over the short arc); the lean analytic stack already matches DE-grade for the reduced-dynamic orbit. Provenance + SHA-256 in `tests/fixtures/agency/NOTICE.md`; full record in `docs/AGENCY-ORBIT-VALIDATION.md`. **Validated against real agency truth: 3 of 3; meeting < 5 m: 2 of 3.** |

## Gravity-map / alt-PNT navigation (`src/gravimeter.rs`, `src/mapmatch.rs`, `src/particle_filter.rs`, `src/altpnt/terrain.rs`)

| Aspect | Status | Evidence |
|--------|--------|----------|
| Spherical-harmonic gravity-anomaly field | `validated` | `src/gravimeter.rs`: a low-degree, fully-normalised field checked against the closed-form Legendre functions (`P̄₁₁ = √3·cosφ`, `P̄₂₀ = (√5/2)(3sin²φ−1)`, `P̄₂₂ = (√15/2)cos²φ`) and a hand-derived single-term anomaly of 1.897 mGal. |
| Cold-atom gravimeter measurement model | `validated` (model) | The white-noise floor is derived from the CAI accelerometer ASD (`σ = ASD/√τ`), injected as a deterministic seeded sequence (the matcher is never handed noise-free truth, yet the run is bit-reproducible). |
| Sequential-importance-resampling particle filter | `validated` | `src/particle_filter.rs`: the deterministic core is pinned exactly — ESS spanning 1…N, systematic resampling picking indices in proportion to weight, the weighted-mean convex combination, a Gaussian likelihood pulling the estimate onto the measurement, and seeded predict determinism. |
| Map-match likelihood + recovery | `validated` | `src/mapmatch.rs`: `field_likelihood` peaks (= 1) at a perfect match and falls to `e^(−½)` at one sigma; a particle filter over a distinctive synthetic-terrain patch recovers the true position to within 0.1. |
| 60-minute GPS-denied benchmark | `validated` | `run_gps_denied_gravity_nav` (`scenarios/gps-denied-gravity-nav.toml`): a ~700 km / one-hour outage where the inertial solution drifts to **≈ 70 km** is recovered to **≈ 145 m (< 500 m)** by a hierarchical coarse-to-fine matcher — bit-reproducible, stable across noise realisations, and provably refinement-limited (a single coarse grid stalls at ~2 km). |
| SRTM `.hgt` DEM loader + bilinear sample (ORACLE A) | `validated` | `src/altpnt/terrain.rs` / `tests/terrain_nav_validation.rs`: a hand-built 2×2 `.hgt` buffer with corners [100,200;300,400] bilinear-interpolates to **exactly 250.0** at the cell centre (closed-form oracle), the 16-bit-big-endian round-trip is exact, and the row-flip places the northernmost file-row at the highest stored latitude — all against the **GDAL SRTMHGT driver spec** (16-bit signed big-endian, row-major, north row first, void -32768, <https://gdal.org/en/stable/drivers/raster/srtmhgt.html>). A committed 11×11 fixture (`tools/gen_terrain_fixture.py`) exercises the parser in CI; `#[ignore]`-gated real-tile tests sample published spot-heights (Mount Whitney 4421 m, Badwater Basin −86 m; NGS/NOAA, <https://en.wikipedia.org/wiki/Mount_Whitney>) within survey bands — source-of-truth is the survey, the DEM is under test (non-circular). |
| Terrain-referenced navigation (TERCOM/SITAN) convergence (ORACLE B) | `validated` | `run_terrain_nav` (`scenarios/terrain-nav.toml`): a **hand-derived** injected INS drift (0.5°N, −0.4°E ≈ 70 km at ~12° lat, computed as drift° × M_per_deg × cos lat) is recovered to **< 500 m** (within the grid-resolution floor `search_step/factor² ≈ 140 m`), a > 100× cut over free-inertial — checked against the *injected* number, never the DEM (non-circular), bit-reproducible and stable across noise seeds. |
| Combined gravity+magnetic+terrain fusion gain (ORACLE C) | `validated` | `run_combined_altpnt` (`scenarios/combined-altpnt.toml`): three scalar channels (Δg · |B| crustal-anomaly · elevation) fused as a product likelihood give a **bounded < 500 m** residual over the 60-min outage that, seed-averaged, is **no worse than the best single channel** (information additivity / lower CRLB). Sits in the published TERCOM/TRN "tens of metres" CEP regime (<https://en.wikipedia.org/wiki/TERCOM>; PeerJ 2024 ESKF-TERCOM, <https://peerj.com/articles/cs-3118/>). |

Honest scope: the gravity field is low-degree + synthetic mascons, **not** the full
EGM2008/EIGEN coefficient set; the magnetic channel rides on the smooth IGRF main field plus
**synthetic** crustal-anomaly mascons (a real high-frequency crustal map is a follow-on); the
CI terrain field is the self-contained synthetic DEM (real SRTM tiles are exercised only by
the `#[ignore]`-gated tests). A map-representation-error Monte-Carlo remains a follow-on. All
three navigators are now scenario-engine `kind=` wired (`gravity-map`, `terrain-nav`,
`combined-altpnt`).

## INS / IMU error model — datasheet-referenced validation (`src/inertial/`)

The IMU stochastic error model is validated against **published manufacturer
datasheet / dataset specifications** — never against a value Kshana itself produced.
The bridge from a field-unit spec to the SI noise model is the standard
Allan-deviation identification (Riley, NIST SP 1065 §5; IEEE Std 952): the random-walk
coefficient `N` is the overlapping ADEV read at τ = 1 s on the τ⁻¹ᐟ² slope, and the
bias-instability coefficient is the flat Allan plateau (`tests/imu_allan_spec.rs`,
hermetic — no download).

| Aspect | Status | Evidence / oracle |
|--------|--------|-------------------|
| Unit-conversion layer (the #1 non-circularity risk) | `validated` | Hand-checked: 0.15 deg/√hr = 4.3633e-5 rad/√s; 3.6 µg = 3.5304e-5 m/s²; 2.0 deg/hr = 9.6963e-6 rad/s. |
| Gyro angle random walk | `validated` | ADIS16465 ARW 0.15 deg/√hr (Analog Devices datasheet) recovered from ADEV(1 s) to < 5%. |
| Accel velocity random walk | `validated` | ADIS16465 VRW 0.1 m/s/√hr recovered to < 5%. |
| White-noise Allan slope | `validated` | ADIS16460 white branch log-log slope −0.5 ± 0.05. |
| In-run bias instability plateau | `validated` | ADIS16465 gyro BI 2.0 deg/hr recovered as the flat Allan minimum to < 15%. |
| Second IMU profile | `validated` | NaveGo ADIS16488 (ARW 0.3 deg/√hr, VRW 0.029 m/s/√hr) both recovered to < 5%. |

Honest scope: this validates the **stochastic error model** against datasheet Allan
coefficients. A full strapdown + tightly-coupled EKF cross-check against the i2Nav-WHU
**KF-GINS** vehicle dataset is a follow-on — the published static-RTK segment converges
to the cm-level antenna position, so a meaningful navigation-accuracy comparison there
first requires GNSS/IMU lever-arm compensation and a dynamic free-inertial-divergence
window; until then it would measure a fixed geometric offset, not navigation quality.

## Deep-space & Mars PNT — D0 foundation (`src/body.rs`, `src/mars_frame.rs`, `src/ephem_provider.rs`, `src/radiometric.rs`, `src/timescales.rs`)

The first milestone of the deep-space navigation engine: generalising the Earth-hardcoded core to an arbitrary central body, adding Mars dynamics, an ephemeris-provider seam, sub-microsecond time, and the light-time / relativistic-delay primitives. **Every existing Earth scenario is byte-identical** — the cross-platform reproducibility goldens (`tests/cross_platform_golden.rs`, `tests/golden.rs`) pass unchanged with no regeneration, enforced per commit.

| Term | Status | Evidence |
|------|--------|----------|
| Central-body abstraction (Earth byte-identical) | `validated` | `src/body.rs`: `Body{mu,re,zonals,gravity,rotation,IAU-pole}` with `earth()/mars()/moon()/sun()`. `tests/mars_dynamics.rs` asserts `two_body_accel_body(r,&Body::earth())` and `zonal_accel_body` equal the legacy Earth functions to **exact bit equality** (`assert_eq!`), and a default-`ForceModel` Earth arc is byte-identical — the reproducibility goldens are unchanged (same SHA, no regen). |
| Mars gravity (GMM-3 tesseral, body-fixed) | `validated` (model) | `Body::mars_gmm3(nmax)`: zonals C̄20/C̄30/C̄40 from MRO110 J2/J3/J4 (`C̄n0=−Jn/√(2n+1)`, J2 round-trips to 1.9604e-3) + MRO110B2 sectoral/tesseral C̄22/S̄22, C̄32/S̄32 (Konopliv et al. 2011; tabulated in Liu, Baoyin & Ma 2012), evaluated in the IAU Mars body-fixed frame. `tests/mars_dynamics.rs` checks the round-trip, the J2-scale departure from point-mass, and that the field is genuinely body-fixed (a quarter-Mars-day reorientation changes the inertial acceleration). Higher degree/order loads from a vendored `.gfc` via `gravity_sh::from_gfc`. |
| Mars body-fixed frame (IAU pole) | `validated` | `src/mars_frame.rs`: the IAU 3-1-3 rotation `R3(W)·R1(90°−δ0)·R3(90°+α0)` (WGCCRE/NAIF convention, same as `lunar_frame.rs`). Tests: orthonormal to 1e-12 with det +1, round-trip identity, prime meridian advances at `prime_w_dot` per day. |
| Mars / Sun-central propagation | `validated` (self-consistency) | `tests/mars_propagation.rs`: a Low-Mars-Orbit returns to its start after one Keplerian period (closure); specific energy ε=v²/2−μ/r drifts <1e-9 across the arc; the Mars-J2 secular nodal regression matches the analytic Vallado rate (computed independently ≈ −5.15 °/day at 60° incl.) to 3%; a heliocentric orbit recovers the ~687-day Mars year (vis-viva + independent period recovery from the arc). No external data. |
| DE440 cross-validation (heliocentric Mars) | `kernel-gated` | `xval/anise-mars-od/` (workspace-EXCLUDED; MPL-2.0 ANISE confined to its own Cargo.lock; mirrors `xval/anise-lunar-od`): compares Kshana's Sun-central Mars propagation against JPL DE440 (via ANISE), Horizons truth cited verbatim (provenance + SHA-256). **Reproduced result** (seed JD 2459580.5 TDB, `de440s.bsp` SHA-256 `c1c7fee…b260a49f2`): position residual **137 m @ 1-day arc** (5.97×10⁻¹⁰ of the 2.299×10¹¹ m heliocentric distance), growing to 3.3 km @ 5 d, 87.9 km @ 30 d, 1.71 Mm @ 90 d — the residual *grows* with arc length because a Sun-central two-body model deliberately omits the planetary perturbations (Jupiter chiefly) and the Mars-system internal motion the DE440 barycenter ephemeris carries, so the growth is the honest signature of the unmodelled n-body dynamics, not an integrator error; a short arc staying a tiny fraction of the heliocentric distance confirms the Sun-central machinery is correct. Runs only when the DE440 kernel is present (`$KSHANA_ANISE_DE440S`, or auto-fetched ~32 MB) — a manual / `workflow_dispatch` DE-grade check, **not** a default CI gate, so the published crate and every default gate stay byte-for-byte untouched. |
| Light-time + Shapiro delay | `validated` | `src/radiometric.rs`: the iterative retarded-epoch light-time solution (converges |Δτ|<1e-12 s, capped) and the Shapiro delay Δt=(2μ/c³)·ln[(r1+r2+r12)/(r1+r2−r12)]. Tests: Earth–Sun ≈ 499 s and Earth–Moon ≈ 1.28 s via the builtin ephemeris; a synthetic constant-velocity emitter recovers the analytic retarded solution to <1e-9 s (solver proven independent of any real ephemeris); Shapiro matches a hand-computed value exactly and gives ~100–250 µs for an Earth–Mars superior-conjunction grazing ray. |
| Ephemeris-provider seam | `validated` | `src/ephem_provider.rs`: `trait EphemerisProvider` + kernel-free `BuiltinEphemeris` (Montenbruck–Gill Sun/Moon, geocentric); returns `None` for bodies it has no series for (e.g. Mars), for which the DE-grade ANISE provider is the path — the same builtin-vs-ANISE split as `LunarEnvironment`/`AniseLunarEnvironment`. |
| Two-part time + TT↔TDB | `validated` | `src/timescales.rs`: a `TwoPartJd{day,frac}` with Knuth two-sum accumulation recovers sub-microsecond intervals the single-f64 JD loses near J2000 (>1000× better, tested); `tt_to_tdb`/`tdb_to_tt` use the dominant Fairhead–Bretagnon periodic series (|TDB−TT|≲1.7 ms, hand-verified at J2000). Additive — the existing single-f64 time path is unchanged. |

## Deep-space radiometric observables & CCSDS-TDM — D1 (`src/radiometric.rs`, `src/ccsds_tdm.rs`)

The second milestone of the deep-space navigation engine: the **observable model** that turns the D0 light-time/relativistic-delay kernel into the actual quantities a Deep-Space-Network or ESTRACK tracking pass reports — range, one/two/three-way Doppler, coherent transponder turn-around, regenerative/PN ranging, Δ-DOR, and the propagation media — plus the **CCSDS 503.0-B Tracking-Data-Message** I/O that ingests/emits a standard agency tracking file. **Honest scope:** these are **exact geometric models** following the Moyer / CCSDS conventions; the measurement *noise* is the caller-supplied per-observation `sigma`, not baked into the model. Reproducing a *specific real tracking pass* needs real TDM data plus the deep-space orbit-determination solver — that is **D2**, not D1. Everything below is additive (the reproducibility goldens are unchanged; same SHA, no regen).

| Term | Status | Evidence |
|------|--------|----------|
| Range & 1/2/3-way Doppler (Moyer two-leg solve) | `validated` (model) | `src/radiometric.rs`: `one_way_range`/`two_way_range` compose the D0 retarded (down-leg) and advanced (up-leg) light-time solutions; the full round-trip convention is `ρ₂ = c·(τ_up + τ_down)` (m), documented and consistent. `one_way_doppler`/`two_way_doppler`/`three_way_doppler` form the carrier shift `f_D = −(M·f_ul/c)·(ρ̇_up + ρ̇_down)` (Hz) from the line-of-sight range rate, **sign convention: an approaching spacecraft gives a positive (blue) shift**. Tests: two-way range = sum of legs to <1 mm (~2 AU Earth–Sun round trip); one-way range = `c·τ` exactly; one-way Doppler matches the analytic `−(f/c)·ρ̇` for a radial constant-velocity emitter to ppt; three-way with co-located stations collapses byte-for-byte to two-way. |
| Coherent transponder turn-around (exact DSN ratios) | `validated` | `src/radiometric.rs` `turnaround_ratio`: the exact rational DSN/CCSDS turn-around numbers `M = f_down/f_up` (Moyer §13; DSN 810-005 module 201/214) — S/S 240/221, S/X 880/221, X/S 240/749, X/X 880/749, X/Ka 3344/749, Ka/Ka 3360/3599. Tested for exact equality; an undefined band pair **panics** (fail-loud, never invents a ratio). `two_way_doppler_coherent` applies the band carrier + ratio end-to-end and equals the explicit `two_way_doppler` to machine precision. |
| Regenerative / PN ranging (CCSDS 414; ambiguity) | `validated` | `src/radiometric.rs`: `regenerative_range_ambiguity` = `c/(2·chip_rate)` (the per-chip resolution-scale unambiguous range) and `pn_range_ambiguity` = that × code length (the full PN-code unambiguous range `c·L/(2·f_chip)`), per CCSDS 414.1-B. Tested: a 1 MHz range clock gives ~149.9 m; the CCSDS-414.1 weighted-voting PN code (1 009 470 chips) at 1 Mchip/s gives the ~151 000 km design unambiguous range; doubling the chip rate halves the per-chip ambiguity. |
| Δ-DOR (CCSDS 506 plane-of-sky) | `validated` (model) | `src/radiometric.rs` `delta_dor`: the differential plane-of-sky delay `Δτ = −B⃗·(ŝ_sc − ŝ_quasar)/c` (s) for an interferometer baseline `B⃗` (CCSDS 506.1-B). Tested: matches the exact analytic projection `−B·sin(Δθ)/c` for a known baseline-aligned offset to 1e-15 s, the small-angle magnitude `|Δτ| ≈ B·Δθ/c`, and the **null** (a spacecraft co-aligned with the quasar gives exactly zero differential delay). |
| Plasma 1/f² dual-frequency calibration | `validated` (model) | `src/radiometric.rs`: `solar_plasma_delay` = `K_PLASMA·TEC/(c·f²)` (the dispersive `1/f²` charged-particle group delay, `K_PLASMA = 40.3 m·Hz²·TECU⁻¹`); `coronal_tec_from_sep` the Cassini-class `TEC ∝ 1/sin(SEP)` corona column (analytic stand-in, not a calibrated corona); `dual_freq_plasma_calibration` the `K_disp = (Δt_X−Δt_Ka)/(1/f_X²−1/f_Ka²)` dispersion inversion the DSN uses to remove plasma. Tested: the 1/f² law `d_X/d_Ka = (f_Ka/f_X)²`; the corona rises toward conjunction; and an **injected TEC is recovered to <1 %** (in fact ≪ 1e-9 noise-free) — `dual_frequency_recovers_injected_plasma`. |
| Tropo / iono media (reuse GNSS models) | `validated` (model) | `src/radiometric.rs` `tropo_delay`/`iono_delay`: the deep-space ground-station segment crosses the same Earth atmosphere the GNSS pack already models, so these delegate to `gnss_sim::tropo_delay_m` (Saastamoinen-zenith + Niell-mapping, non-dispersive) and `gnss_sim::klobuchar_delay_m` (broadcast iono). Tested wired + physically signed: tropo positive and larger at low elevation than at zenith; iono a non-negative slant delay (numerical fidelity is the GNSS pack's own datasheet-referenced tests). |
| CCSDS-TDM 503 parse / emit + radiometric bridge | `validated` | `src/ccsds_tdm.rs`: a CCSDS 503.0-B-2 KVN reader **and** writer (header + `META_START…META_STOP` / `DATA_START…DATA_STOP` segments; `RANGE`/`DOPPLER_*`/`ANGLE_*`/`*_FREQ` records). Tests (`#[cfg(test)]` + `tests/fixtures/deepspace/reference.tdm`): the reference fixture parses to the expected named fields; **parse→emit→parse is an equal structure** (semantic round-trip); the bridge `to_radiometric_obs` maps the unambiguous `RANGE`/`DOPPLER_*` records to `RadiometricObs` (way from `PATH` `1,2`/`1,2,1`/`1,2,3`, band from `TRANSMIT_BAND`, km→m); a multi-segment file resets the state machine. **Honest skip-not-guess:** angles/frequencies, unknown bands, day-of-year epochs, and unrecognised time systems are **skipped**, never mis-mapped, and `sigma` is left `0.0` for the caller to weight. |
| DSN/ESTRACK benchmark (model precision ≫ published floor) | `validated (model)` | `tests/radiometric_benchmark.rs`: the observables are exact geometric computations, so the honest benchmark is that the **model's own numerical error is far below the published DSN/ESTRACK measurement floor** — the model is not the accuracy bottleneck, the caller-supplied σ is. Each test computes an observable two independent ways (or recovers an injected truth) and asserts the residual is below the floor: **range** round-trips to <1 mm ≪ the ~1 m PN-ranging floor (DSN 810-005 mod. 214 / CCSDS 414.1-B); **Doppler** matches the exact closed-form retarded range rate `v/(1+v/c)` to ~10⁻⁶ m/s, several × below the ~0.05 mm/s X-band floor (DSN 810-005 mod. 203 / Moyer) — the residual is the f64 range-differencing floor at ~1 AU, a numeric characteristic not a modelling error; **Δ-DOR** reproduces the closed-form projection to an equivalent plane-of-sky angle ≪ 1 nrad ≪ the ~1–10 nrad floor (DSN 810-005 mod. 210 / CCSDS 506.1-B); **plasma** dual-frequency recovers the injected delay to ≪ 1 %; and the **Shapiro** delay sits in the published ~100–250 µs Earth–Mars conjunction band. The published figures are stated and labelled as **order-of-magnitude** DSN specs, not fabricated exact numbers, and the module doc is explicit this benchmarks MODEL PRECISION, not real-pass reproduction (that is D2 + real TDM). |

## Deep-space reduced-dynamic OD — D2 (`src/deepspace_od.rs`, `src/clock_state.rs`, `src/mars_atmos.rs`)

The third milestone of the deep-space navigation engine: the **estimator** that turns the D1 radiometric observables into a recovered trajectory — a numerically-robust Square-Root Information Filter with reduced-dynamic empirical accelerations, a three-state onboard clock, a Mars-drag model, and the radiometric measurement partials that connect range/Doppler to the filter state, closed end-to-end by a synthetic Mars-LMO orbit-determination recovery. **Honest scope:** the recovery is a **synthetic closed-loop** (truth and filter share the same Mars propagator, and the observations are the same geometric observable model the filter inverts, plus injected Gaussian noise) — it validates the **estimator machinery**, not the absolute fidelity of the Mars force model; the DE-grade external cross-check is the kernel-gated `xval/anise-mars-od` crate (D0.8b). Everything below is additive (the reproducibility goldens are unchanged; same SHA, no regen).

| Term | Status | Evidence |
|------|--------|----------|
| SRIF core (square-root information filter) | `validated` | `src/deepspace_od.rs` `Srif`: a hand-rolled Bierman square-root information filter — upper-triangular `R` with `Λ = RᵀR`, info vector `b`, Householder measurement/time updates, bare-`Vec<f64>` arithmetic (no nalgebra). Tests: the sequential SRIF matches the batch weighted-least-squares (`gauss_newton`) solution in **both state and covariance to 1e-9** on a designed linear-Gaussian problem (`srif_matches_batch_on_linear`); the recovered covariance `P = R⁻¹R⁻ᵀ` is **symmetric (1e-12) and positive-definite by construction** after a long measurement/time-update sequence (`srif_covariance_is_spd`, Cholesky succeeds); and information accumulates (trace of `P` decreases monotonically as identical-geometry measurements are folded in). |
| Reduced-dynamic empirical accelerations (cruise↔LMO tuning) | `validated` | `src/deepspace_od.rs` `ReducedDynamicOd`: the nine-state `[r; v; a_emp]` filter with RTN empirical accelerations as first-order Gauss–Markov process states, the JPL/ESOC reduced-dynamic technique exposed as a single `dynamic_tightness` knob (near-dynamic ⇒ smooths noise on a ballistic arc; near-kinematic ⇒ the empirical tier absorbs an unmodelled manoeuvre/drag). Tests: a near-kinematic filter tracks a **stepped (thruster) manoeuvre** with <½ the residual of the near-dynamic one, while the near-dynamic filter **smooths a noisy ballistic arc** better (`reduced_dynamic_tracks_maneuver`); sweeping the tightness moves the post-fit residual **monotonically**, a continuum not a switch (`tuning_is_a_continuum`). |
| 3-state onboard clock (phase/freq/drift, van Loan Q, Allan) | `validated` | `src/clock_state.rs` `ClockState3`: phase + fractional-frequency + frequency-drift error state with the **exact van Loan discrete process noise** and a Joseph-stabilised update. Tests: the discretised `Q` matches the hand-derived van Loan polynomial **to 1e-12** and **reduces exactly to the two-state KalmanClock Q when drift = 0** (a strict superset); a multi-step coast grows the phase variance to the analytic NIST SP 1065 holdover relation through the `T⁵` random-run term; the drift state **recovers a true aging ramp to <5 %**; a **USO-class Allan profile is recovered** (overlapping ADEV at τ=1 s within the calibration gate) and the estimator stays NEES-consistent (>95 % inside 3σ) and PSD through a harsh-`Q/R` run. `ClockClass` carries the cited CSAC/USO/DSAC `σ_y(1 s)` figures and the `Δv = c·σ_y` Doppler floor. |
| Mars atmospheric drag (Mars-GRAM-lite) | `validated (model)` | `src/mars_atmos.rs`: a piecewise-exponential Mars neutral-density profile (surface ~0.020 kg/m³, near-surface scale height ~11 km, the Mars-GRAM 2010 / MCD low-dust mean) and the quadratic drag acceleration taken relative to the **co-rotating** Mars atmosphere, plus a `..._scaled` variant the SRIF can multiply. Tests: the density decreases monotonically and continuously across bands, the recovered near-surface scale height is the physical ~11 km, the drag is **strictly anti-parallel to the relative velocity** (cross-product vanishes to 1e-12) with a sane ~3e-4 m/s² LMO magnitude, and it is linear in the ballistic term. **Honest scope:** a representative engineering atmosphere, not a flight-validated Mars-GRAM/MCD with dust/season/local-time dependence. |
| Radiometric measurement partials (range/Doppler) for the SRIF | `validated` | `src/deepspace_od.rs` `range_observable` / `range_rate_observable`: the line-of-sight range `ρ = \|r_sc − r_sta\|` (∂ρ/∂r = û, ∂ρ/∂v = 0) and range rate `ρ̇ = û·(v_sc − v_sta)` (∂ρ̇/∂v = û, ∂ρ̇/∂r = (v_rel − ρ̇·û)/ρ) partials that connect the D1 observables to the filter state, plus the one-way-Doppler clock-frequency partial `∂ρ̇_obs/∂y = c`. Tests: both partials match a **central finite difference of the observable to 1e-6** (`range_partial_matches_finite_difference`, `range_rate_partials_match_finite_difference`); a single range update **shrinks the covariance in the observed (line-of-sight) direction by ≫1000×** and keeps it PD, and a Doppler update shrinks the LOS **velocity** variance (`radiometric_update_reduces_covariance_in_observed_direction`, `range_rate_update_observes_velocity`). |
| Mars-LMO end-to-end OD from radiometric data | `validated (synthetic closed-loop)` | `tests/mars_lmo_od.rs`: a truth Low-Mars-Orbit arc propagated under `Body::mars_gmm3(4)` gravity generates noisy two-way **range (σ=1 m) + Doppler (σ=0.1 mm/s)** against two tracking stations; the reduced-dynamic SRIF recovers it from a **~2.7 km-perturbed** initial state. Achieved: converged position **RMS ≈ 0.2 m** (sub-metre, far inside the metres-to-tens-of-metres done-criterion) over a 3-orbit, 30 s-cadence arc, with the **factored covariance positive-definite at every epoch** (the SRIF guarantee, asserted throughout). The **cruise→LMO tuning continuum** is exercised end-to-end: with an unmodelled-drag truth the filter template lacks, the reduced-dynamic knob (tightness 1) recovers to ~14 m vs ~677 m for the near-dynamic (tightness 0) run — a 48× improvement from the empirical tier absorbing the drag. **Honest scope:** synthetic closed-loop (truth = the same propagator the filter uses); the DE-grade external cross-check is the kernel-gated `xval/anise-mars-od` (D0.8b), never run here, no network. |

## Deep-space PNT scenario & one-way+two-way fusion — D3 (`src/mars_pnt.rs`, `src/deepspace_od.rs`)

The fourth milestone of the deep-space navigation engine: a runnable **Mars-PNT product scenario** that ties the D0 Mars body / frame, the D1 radiometric observables, and the D2 reduced-dynamic OD into a single `mars-pnt` scenario kind. It models a small **MARCONI-style relay constellation** broadcasting a one-way (clock-coupled) signal-in-space plus relaying a two-way (coherent, clock-free) link to a deep-space station, and navigates three reference users (Mars transfer, Low-Mars-Orbit orbiter, fixed surface point) through the **D3.1 joint one-way + two-way fusion estimator** — a twelve-state SRIF that augments the D2 reduced-dynamic orbit/empirical block with a three-state onboard clock. **Honest scope:** every figure of merit is the estimator's **formal covariance bound** (per-epoch 1σ / 3σ position) and the achieved RMS against a **synthetic closed-loop** truth (truth and filter share the same Mars dynamics and the same geometric observable model, plus injected Gaussian noise) — a simulated navigation FoM, **NOT** an aviation-certified protection level, and **NOT** a flight claim (no certified fault model, no integrity monitor, no real tracking data). Everything below is additive (the reproducibility goldens are unchanged; same SHA, no regen).

| Term | Status | Evidence |
|------|--------|----------|
| Joint one-way + two-way radiometric fusion (fused beats either alone) | `validated` | `src/deepspace_od.rs` `FusionOd`: the D2.2 reduced-dynamic SRIF augmented with the three onboard-clock states (`ClockState3`), ingesting a mixed time series of **two-way** (clock-free, orbit-pinning — zero clock columns in the partial) and **one-way** (clock-coupled — the `∂ρ̇_obs/∂y = c` frequency partial) range/Doppler through `fused_observable`. The calibrate-then-coast structure: two-way passes pin the orbit, one-way data then calibrates the clock and coasts the orbit between passes with error bounded by the clock's Allan stability. Tested in `src/deepspace_od.rs` `#[cfg(test)]`: the **fused** solution beats **either link type alone**; a one-way-only run's coast error grows with the gap between two-way passes consistent with the clock-class Allan bound; the joint covariance stays SPD throughout. |
| MARCONI constellation (areostationary radius, occultation) | `validated (model)` | `src/mars_pnt.rs` `MarconiConstellation`: a five-relay set — three **areostationary** relays at `r = (μ/ω²)^{1/3} ≈ 20 428 km` (the Mars synchronous radius from published μ/spin-rate; tested in the **20 400–20 500 km** band) equally spaced 120° in longitude with 5° inclination, plus two relays in a higher (1.4× areostationary) 60°-inclined circular orbit for plane-of-sky coverage. Per-epoch relay states are forward-integrated under `mars_gmm3` gravity; the **Mars-occultation** visibility test is the chord-clears-sphere geometry (`chord_clears_sphere`, tested: a diametrically-opposite relay is occulted, an overhead relay is visible). **Honest scope:** a minimal representative broadcast-plus-relay geometry built from published Mars constants — not a specific flight constellation design. |
| `mars-pnt` scenario reachable via CLI / Python / WASM / MCP | `validated` | `src/mars_pnt.rs` `MarsScenario` / `run_mars_pnt` is wired as the `kind = "mars-pnt"` scenario across all surfaces (D3.3): the CLI runner, the Python binding, the WASM/playground build, and the MCP server dispatch all route to it (`src/api.rs` round-trip test `mars_pnt_kind_round_trips_through_the_dispatch`). Reference scenarios shipped: `scenarios/mars-pnt-lmo.toml`, `scenarios/mars-pnt-surface.toml`, `scenarios/mars-pnt-transfer.toml`. The result carries an explicit `fom_note` labelling the FoM a covariance bound (not a certified PL), and the `summary` / `to_svg` outputs repeat the honesty label. |
| MARCONI / LightShip targets reproduced: **< 100 m orbiter**, **< 15 m rover** | `validated (synthetic closed-loop, under stated assumptions)` | `tests/mars_pnt_targets.rs`: the published MARCONI / LightShip programme goals (orbiter < 100 m, surface/rover < 15 m) reproduced in simulation. **Shared assumptions:** the five-relay default MARCONI constellation; every in-view relay gives a one-way range+Doppler per epoch; a coherent two-way station pass every **30 min**; DSN-class noise (**range σ = 1 m, Doppler σ = 0.1 mm/s**); the joint reduced-dynamic orbit + 3-state clock fusion filter seeded from a **~2.7 km**-perturbed a-priori state (tightness 0.1); FoM = converged back-half-of-arc 3-D position RMS vs the synthetic truth. **Orbiter** (LMO ~400 km / 60° inc, **USO** clock, 60 s cadence, ~2 h ≈ one-orbit arc): achieved converged RMS **≈ 0.40 m** ≪ the 100 m target (mean 3.1 relays in view, covariance SPD throughout). **Rover** (fixed equatorial surface point, **USO** clock, 30 s cadence, ~2 h arc): achieved converged RMS **≈ 5.1 m** < the 15 m target (mean 3.0 relays in view, covariance SPD). **Both targets met without loosening any assertion** — the USO is the *less* capable of the realistic onboard clock classes (a DSAC would only help) and the 30-min two-way cadence is conservative for a routine relay-network schedule, so the assumptions are physically fair for a MARCONI-class system rather than tuned to pass. **Honest scope:** simulated reproduction under the stated assumptions, NOT a flight claim or certified protection level; synthetic closed-loop truth shares the filter's Mars dynamics and observable model. |

## Lunar coordinate time — relativistic Earth-Moon clock rate (`src/lunar_time.rs`)

A Lunar Coordinate Time scale (LTC/TCL) requires the secular rate at which a lunar-surface clock runs relative to an Earth-geoid (TT) clock. `src/lunar_time.rs` computes it from first principles: a first post-Newtonian identity summing the **self-potential difference** (the IAU `L_G` conventional geoid potential `W0 = L_G·c² ≈ 6.26369e7 m²/s²` minus the Moon's surface self-potential `GM_moon/R_moon ≈ 2.822e6 m²/s²`) and the **kinetic (second-order Doppler) term** `−<v²>/2c²` from the geocentric Moon velocity (finite-differenced from the Montenbruck-Gill lunar series in `src/ephem.rs`). The dominant self-potential term gives **≈ 57.5 µs/day**, the kinetic term **≈ −0.5 µs/day**, for a total **≈ 57 µs/day**. The `lunar-time-offset` scenario reports this rate, the accumulated LTC−TT offset over a horizon, and supports a minimal inverse-variance ensemble (a lunar paper-clock); TT↔LTC conversions round-trip to < 1 ns/day.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Relativistic Earth-Moon clock rate (LTC/TCL) | `modelled` | `src/lunar_time.rs` `lunar_rate_breakdown`, `tt_to_ltc`/`ltc_to_tt`, `lunar_ensemble`, `LunarTimeScenario`. **Oracle: an internal closed-form relativistic identity** (IAU `L_G` / IERS-conventions geopotential and the GM/r self-potential), **cross-checked against the published lunar-clock-rate band [56, 59] µs/day**. Tests (`lunar_time::tests`): the self-potential term ≈ 57.5 µs/day, the Moon speed ≈ 1 km/s, the kinetic term a small negative, the total in band with the named terms summing to it, the 1-day LTC−TT offset ≈ 57 µs, and a < 1 ns/day TT↔LTC round-trip. **Honest scope:** the headline µs/day figure is **reference-dependent** — it depends on the chosen reference surfaces (Earth geoid `W0` vs a lunar selenoid), the time-averaging window, and the neglected sub-µs/day centrifugal/J₂ corrections — which is why a **band**, not a single certified number, is the published output. This is a `Modelled` self-consistency check, **NOT** an external validation, **NOT** sub-nanosecond absolute accuracy, and **NOT** certified for operational timekeeping. |

## Lunar geodetic VLBI — near-field delay for an Earth baseline observing a lunar beacon (`src/lunar_vlbi.rs`)

A geodetic VLBI observable for two Earth ground stations (a baseline) observing a one-way signal from a NovaMoon-class transmitter on the lunar surface. The Moon is **near-field**, not a plane wave, so the geometric delay is the exact two-range difference `tau_geom = (|r2 − r_B| − |r1 − r_B|)/c` rather than the plane-of-sky projection. The full observable adds the station clock-offset difference and a differenced Earth-potential Shapiro term (reused from `src/radiometric.rs`). Stations are placed in geocentric inertial (GCRS) coordinates via `src/frames.rs` + `src/cio.rs`; the beacon via `src/ephem.rs` (geocentric Moon) + `src/lunar.rs` (selenographic→MCMF) + `src/lunar_frame.rs` (IAU-2015 ME body-fixed→inertial). The `lunar-vlbi` scenario samples the delay, its finite-difference rate, and the near-field correction over a pass.

The **oracle** is the same-codebase plane-wave Δ-DOR observable `delta_dor` in `src/radiometric.rs`: in the far-field limit (a synthetic beacon at 1e15 m) the geometric delay must collapse to `−(B·ŝ_B)/c = delta_dor(r_B, [0,0,0], B)` to machine precision; at true lunar distance the wavefront-curvature near-field correction is non-zero (tens to hundreds of µs). The beacon partials `dtau/dr_B = ((r_B−r2)/|r_B−r2| − (r_B−r1)/|r_B−r1|)/c` (and the station partials) are verified by central finite difference (relative error < 1e-5).

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Lunar geodetic VLBI delay + partials | `modelled` | `src/lunar_vlbi.rs` `geometric_delay_s`, `vlbi_delay_s`, `delay_partials_beacon`/`_station1`/`_station2`, `near_field_correction_s`, `LunarVlbiScenario`. **Oracle: `ReferenceImpl`** — the same-codebase plane-wave `delta_dor` (`src/radiometric.rs`) in the far-field limit, plus **finite-difference partials**. Tests (`lunar_vlbi::tests`): station magnitude ≈ Earth radius, beacon range at lunar distance (356–407 Mm), far-field geometric delay matches `delta_dor` to < 1e-9 s, a non-zero near-field correction at lunar distance, FD beacon/station partials within 1e-5 relative, an exact clock term, and a finite scenario run dispatched through `run_toml`. **Honest scope:** `Modelled`, **NOT** validated against real VLBI data. Polar motion is dropped (`xp = yp = 0`), so station inertial positions carry a few-metre frame error; the beacon mixes a mean-equator-of-date Moon series with an ICRF body-fixed offset (`jd_tdb ≈ jd_tt`), a frame-consistency mismatch below model fidelity but not rigorous; and there is no light-time iteration, Earth-rotation-during-light-time, media (tropo/iono/plasma) or aberration term beyond the differenced Shapiro. No TRL, flight heritage or agency endorsement is claimed. |

## Lunar joint multi-technique OD + clock — simulated closed-loop recovery (`src/lunar_combination.rs`)

A single-epoch (snapshot) batch least-squares fit (`crate::batch_ls::gauss_newton`) that **fuses the geodetic-VLBI, radiometric/lunar-local-ranging and inter-satellite-ranging techniques** on a SIMULATED lunar network to recover, *together*, a lunar surface station's 3-D position, a small constellation's per-satellite positions, and every asset's clock offset. The observables are: (1) Earth-baseline geodetic VLBI delays to the lunar station treated as the beacon (reusing `src/lunar_vlbi.rs`, geocentric inertial) — the headline technique; (2) Earth-station→satellite geocentric radiometric ranges (which multilaterate the constellation from the well-spread Earth stations) and station↔satellite lunar-local ranges (MCI Euclidean distance plus the differenced clock term); (3) inter-satellite ranges (same form); plus a single station-clock sync pseudo-observation that anchors the otherwise-unobservable common clock offset. The state vector is `[station_pos(3), {sat_pos(3)}×N_sat, station_clk, {sat_clk}×N_sat]`. There is **no force-model propagation inside the solver** — the satellites are fixed, distinct, illustrative points on a representative lunar orbit; this is a deliberately clean snapshot fit. Internally, positions are scaled and clocks are estimated in range-equivalent metres so the normal matrix stays well-conditioned in f64; the VLBI and lunar-distance ranges are mean-removed about the nominal geometry so the finite-difference Jacobian does not suffer catastrophic cancellation. The `lunar-joint-od-clock` scenario runs the solve with and without the VLBI legs on the same seed/truth and reports both solutions plus the station-observability improvement factor.

The **headline honest result**: lunar-local ranging from a polar station to a handful of satellites that all sit toward one side of the sky leaves the station's position **weakly observed along one direction**, so the range-only solve is ill-conditioned and the recovered station 3-D error is large (or the solve fails to converge). **Adding the Earth-baseline VLBI delays makes the station's full 3-D position observable**, and the recovered station error collapses to the metre level. The test `vlbi_restores_station_observability` asserts the with-VLBI station error is markedly (≥5×) smaller than the range-only error on the identical injected truth — VLBI restoring the otherwise-unobservable station direction is the phase's point.

The **oracle** is internal consistency: an injected truth state (station ~50 m/axis, satellites ~30 m/axis, clocks ~1e-7 s, with a seeded per-component jitter) is mapped to synthetic observables through the *same* geometry model the solver inverts, seeded Gaussian noise is added (illustrative defaults: VLBI σ ≈ 1e-11 s, range σ ≈ 0.1 m, ISL σ ≈ 0.1 m; weights `1/σ²`), and the estimator must recover the injected truth within the noise from a zeros initial guess. A Monte-Carlo mean NEES `Δxᵀ(HᵀWH)Δx` over seeds (`formal_covariance_nees`) sits within a loose band around `n_params`, a covariance-realism check.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Lunar joint multi-technique OD + clock | `modelled` | `src/lunar_combination.rs` `estimate`, `formal_covariance_nees`, `LunarCombinationScenario`. **Oracle: `InternalConsistency`** — recovery of an injected simulated truth + NEES covariance consistency. Tests (`lunar_combination::tests`): full-fusion recovers the truth (station < 5 m, sat RMS < 5 m, clocks < 1e-8 s, converged); VLBI restores station 3-D observability (station error ≥5× smaller with VLBI than range-only on the same truth); deterministic (same seed → bit-identical solution, different seed → different-but-recovered); mean NEES within a loose band around `n_params`; finite/guarded reported numbers even when range-only is ill-conditioned; scenario dispatched through `run_toml`. **Honest scope:** this is a **simulated closed-loop recovery** — the truth shares the observation model — **NOT** real-data validation; no force-model propagation inside the solver; the satellite positions and Earth/lunar-station geometry are illustrative. No TRL, flight heritage or agency endorsement is claimed. |

## Lunar reference-frame realisation — 7-parameter Helmert datum fit (`src/lunar_frame_realise.rs`)

Where `src/lunar_frame.rs` *applies* the IAU 2015 WGCCRE lunar body orientation (a forward model), this module *estimates* (realises) a lunar reference frame from a network of estimated point coordinates tied to a datum. The estimation core is a classic **7-parameter similarity (Helmert) transform** — three translation, three small-angle rotation and one scale parameter — mapping points `p_i` (estimated frame) to `q_i` (datum frame) as `q_i = t + (1 + s)·R(θ)·p_i`, with `R(θ) = rz(θz)·ry(θy)·rx(θx)` built from `crate::precession::{rx, ry, rz, matmul, mat_vec}`. The seven parameters `[tx, ty, tz, θx, θy, θz, s]` are estimated from ≥ 3 non-collinear point pairs by weighted least squares through `crate::batch_ls::gauss_newton`: the forward model predicts every `q_i` from its `p_i` and flattens all three components of all points into the observable vector, the observed datum coordinates form `z`, the weights are `1/σ²`, and the solve starts from `x0 = zeros`. Rotation angles are estimated in µrad and scale in ppb so the finite-difference Jacobian stays well-scaled at the lunar-surface coordinate magnitude (~1.7e6 m). A small `icrf_orientation_tie` composes the realised small rotation through the IAU body→ICRF orientation (`transpose(crate::lunar_frame::icrf_to_iau_moon(jd_tdb))`) and returns the realised frame's residual small-angle offset about the ICRF axes — a deliberately simple frame-of-expression change, **not** an independent estimate of the lunar pole.

The **oracle** is internal consistency: a known Helmert transform (translation ~tens of m, rotation ~µrad, scale ~1e-7) is *injected* into a well-spread synthetic point network (varied selenographic lat/lon → MCMF, some points at altitude), seeded Gaussian noise is added, and the fit must recover the injected parameters. On noiseless data the recovery is to ~machine precision (translation < 1e-6 m, rotation < 1e-9 rad, scale < 1e-12); with metre noise the recovered parameters land within a few × the formal σ and the post-fit RMS residual sits near the noise level. The `lunar-frame-realisation` scenario reports the recovered datum, the per-parameter recovery error vs the injected truth, the post-fit RMS residual, and the realised-rotation ICRF orientation tie.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Lunar reference-frame realisation | `modelled` | `src/lunar_frame_realise.rs` `helmert_fit`, `apply_helmert`, `realise_frame`, `icrf_orientation_tie`, `LunarFrameRealiseScenario`. **Oracle: `InternalConsistency`** — recovery of an injected 7-parameter similarity transform plus the algebraic round-trip identity of `apply_helmert`. Tests (`lunar_frame_realise::tests`): noiseless recovery of the injected transform (translation < 1e-6 m, rotation < 1e-9 rad, scale < 1e-12); with-noise recovery within a few × σ and RMS residual near the noise level; apply-then-invert round-trip; deterministic (same seed → bit-identical, different seed → different-but-recovered); zero-rotation ICRF tie is zero and the tie preserves the rotation magnitude; scenario dispatched through `run_toml`. **Honest scope:** this is a **self-consistency** check — it recovers an *injected* transform on a *synthetic* network — **NOT** a realisation of the lunar reference frame against real tracking / VLBI data, and it claims no absolute frame accuracy. The ICRF orientation tie is a simple change of expression, not an independent pole estimate. No TRL, flight heritage or agency endorsement is claimed. |

## Lunar navigation service volume — DOP / coverage / availability + generalised lunar ARAIM PL (`src/lunar_service.rs`)

This module *composes* already-built pieces into a lunar navigation **service-volume** analysis: it sweeps a selenographic latitude/longitude grid over a time horizon against an **illustrative, public-source Moonlight / LCNS-class** lunar-orbit constellation and reports DOP / coverage / availability plus a generalised lunar ARAIM protection-level envelope. The two reuses are load-bearing and explicit. **DOP geometry** is the **VALIDATED** (vs gnss_lib_py) kernel `crate::orbit::dop` — `service_dop` is a thin elevation-mask filter plus that kernel, and a test asserts the identity (`service_dop` equals a direct `orbit::dop` on the same visible positions). **Integrity** reuses the LunaNet LNIS lunar ARAIM machinery `crate::lunar::lunar_araim` (σ_URE ≈ 30 m, `P_sat` ≈ 1e-4); `lunar_protection_level` generalises the existing south-pole protection level to an arbitrary surface point, and a test asserts it **reduces to the south-pole case** (at the south pole with the same geometry/budget it returns exactly the existing `lunar::lunar_araim` result to < 1e-9).

The constellation parameters are an **illustrative approximation of public ESA descriptions** of the system class (≈ 4 satellites on elliptical lunar frozen orbits favouring south-pole coverage — apolune over the southern hemisphere). They are **not** the real Moonlight/LCNS ephemeris and imply **no** affiliation, endorsement, heritage, certification or TRL. The composition (coverage / availability / integrity) is **MODELLED**: a circular-/elliptical-Keplerian relay set (not a differential-corrected LCNS / 9:2 NRHO ephemeris), a mean-rotation Moon (no physical libration / precessing pole), and published LunaNet LNIS integrity parameters. It demonstrates the service-volume *method*, not an operational availability number. Deterministic (pure geometry; no randomness). The `moonlight-service-volume` scenario reports the coverage percentage, the visible-count and PDOP envelopes, the HPL/VPL envelope over the volume and the protection-level availability against the alert limit.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Lunar navigation service volume | `modelled` | `src/lunar_service.rs` `LunarConstellation`, `visible_sats`, `service_dop`, `coverage`, `lunar_protection_level`, `LunarServiceScenario`. **DOP geometry validated by reuse** of the gnss_lib_py-validated `crate::orbit::dop` kernel; integrity reuses the published-LunaNet/LNIS lunar ARAIM (`crate::lunar::lunar_araim`, σ_URE ≈ 30 m). Tests (`lunar_service::tests`): `service_dop` is an identity on the validated kernel; `lunar_protection_level` at the south pole equals the existing `lunar::lunar_araim` PL to < 1e-9 (reduces to the south-pole case); coverage is non-decreasing in constellation size; visibility honours the elevation mask; the scenario is deterministic and dispatches through `run_toml`. **Honest scope:** the constellation is **illustrative, public-source, NOT affiliated with ESA** — not the real Moonlight/LCNS ephemeris; the coverage/availability/integrity composition is **MODELLED** (circular-/elliptical-Keplerian relays, mean-rotation Moon, published LNIS parameters), **NOT** an operational Moonlight availability number. No TRL, flight heritage or agency endorsement is claimed. |

## Lunar differential PNT — common-mode cancellation + baseline-growing residual + DGNSS protection levels (`src/lunar_dpnt.rs`)

A lunar DGNSS / SBAS analogue: a **NovaMoon-class reference station** at a *known* selenographic location computes per-satellite differential corrections from an **illustrative, public-source Moonlight / LCNS-class** constellation, and a roving user offset from it by a baseline applies them so the **common-mode** broadcast-ephemeris errors cancel. Each satellite `i` carries an injected common 3-D orbit-error vector `e_i` and a common clock error `c_i`. The reference station's pseudorange residual is the correction `−e_i · û_ref,i + c_i`; the user's raw error is `−e_i · û_user,i + c_i`; the corrected user error is their difference `−e_i · (û_user,i − û_ref,i)`. The **clock term `c_i` cancels exactly** (it is identical in both observations), and the **orbit term collapses to the projection onto the difference of the two line-of-sight unit vectors**, which → 0 as the baseline → 0 (the spatial-decorrelation floor) and grows ≈ linearly with baseline. The per-satellite corrected range errors are mapped through the user geometry by a small dependency-light weighted-least-squares snapshot solve (`[x, y, z, clock]` state via `crate::orbit::invert4`; a constant range bias is absorbed by the clock unknown rather than corrupting the fix) to give the user **position** error. The user **protection level reuses the DO-229E SBAS protection-level machinery** (`crate::sbas::sbas_protection_level`, Precision-Approach K-factors) with the differential residual σ as each satellite's 1-σ error budget.

NovaMoon is referenced **only as a system class** (a public description of a lunar reference station); the constellation reuses the illustrative public-source `crate::lunar_service::LunarConstellation`. These are illustrative parameters for exercising the differential *method*, **not** a real ephemeris, and imply **no** affiliation, endorsement, heritage, certification or TRL. The `lunar-differential-pnt` scenario reports the user position error with vs without corrections, the reduction factor, the error-vs-baseline curve and the protection level. On the default configuration the corrected user error at a 50 km baseline is ≈ 0.008 m against ≈ 24 m uncorrected (a ~3000× reduction), and ≈ 0 at zero baseline.

The **oracle** is internal consistency: the common-mode cancellation is an **exact algebraic identity** (with `noise = 0`, corrected error < 1e-6 m at zero baseline; the clock term cancels to machine precision at any baseline), the residual **grows monotonically with baseline**, and the protection level is the **same DO-229E algorithm** the SBAS stack is pinned against. The spatial-decorrelation residual is a **first-order** geometric model, **not** a fitted decorrelation model from real lunar tracking.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Lunar differential PNT | `modelled` | `src/lunar_dpnt.rs` `differential_corrections`, `corrected_user_range_errors`, `user_position_error_m`, `lunar_dgnss_protection_level`, `LunarDpntScenario`. **Oracle: `InternalConsistency`** — the differential error-cancellation identity plus reuse of the DO-229E SBAS protection-level machinery (`crate::sbas`). Tests (`lunar_dpnt::tests`): at zero baseline the corrected user error and every corrected per-satellite range error are ~0 (< 1e-6 m) and ≪ the uncorrected error; the clock term cancels exactly at any baseline (orbit-error-zero case); the corrected error grows monotonically with baseline while staying ≪ uncorrected at modest baselines; differential beats standalone by a clear margin (> 2×); the protection level equals a direct `sbas::sbas_protection_level` call and scales with the residual σ; under-determined geometry returns `None`; the scenario is deterministic (seeded) and dispatches through `run_toml`. **Honest scope:** **MODELLED** — the common-mode cancellation is an exact identity but the spatial-decorrelation residual is a **first-order** geometric model, **NOT** a fitted decorrelation model from real lunar tracking, and this is **NOT** real-data validated. NovaMoon is referenced **only as a system class** (illustrative, public-source, **not affiliated with ESA**). No TRL, flight heritage or agency endorsement is claimed. |

## Lunar interoperability export — LunaNet/IOAG-aligned CCSDS OEM + KIF with round-trip conformance (`src/lunar_interop.rs`)

The lunar reference frame, lunar time scale and lunar ephemeris are exported in **LunaNet/IOAG-aligned, CCSDS-based interchange forms**. This phase does **not** invent a wire format: it **reuses** the crate's existing CCSDS OEM 2.0 emitter and parser (`crate::oem::OemFile::to_oem_string` / `crate::oem::parse_oem`) and the Kshana Interchange Format envelope (`crate::interchange::Envelope`), re-tagged for the lunar context. `export_lunar_oem` sets the OEM `REF_FRAME` to the **IAU 2015 WGCCRE lunar body frame** (`MOON_ME` mean-Earth or `MOON_PA` principal-axis), `TIME_SYSTEM` to the **lunar time scale** (`LTC` / `TCL` / `UTC`) and `CENTER_NAME` to `MOON`, over a sample **illustrative, public-source LCNS-class** ephemeris (positions from `crate::lunar_service::LunarSat::position_mci`, velocity by central finite difference). `export_lunar_time_metadata` emits a LunaNet/IOAG-aligned lunar-time descriptor (scale id, secular rate µs/day from `crate::lunar_time::lunar_rate_breakdown`, the published 56–59 µs/day band, reference surface) that round-trips through serde_json. `export_kif_lunar` wraps the OEM + descriptor + frame label in the existing KIF envelope with the MODELLED honesty label.

The **oracle** is round-trip / field conformance. Because `oem.rs` ships *both* directions, the OEM is round-tripped through `crate::oem::parse_oem` (back to an equal segment, with the lunar frame/time and state count preserved) **and** independently checked by `oem_conformance`, which verifies every required CCSDS/LunaNet header keyword is present, that `REF_FRAME` carries a lunar `MOON_*` token and `TIME_SYSTEM` is non-empty, that the `META_START … META_STOP` framing holds, and that the position+velocity data lines are well-formed — returning a structured pass plus the present/missing field list so a broken export (e.g. a dropped `TIME_SYSTEM`) is caught and named. The time metadata round-trips through `parse_lunar_time_metadata`, and the KIF envelope round-trips through `Envelope::parse` to equal artifacts carrying the MODELLED label.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Lunar interoperability export | `modelled` | `src/lunar_interop.rs` `export_lunar_oem`, `export_lunar_time_metadata`, `parse_lunar_time_metadata`, `export_kif_lunar`, `oem_conformance`, `LunarInteropScenario`. **Oracle: `InternalConsistency`** — deterministic round-trip (CCSDS OEM via `crate::oem::parse_oem`; KIF via `crate::interchange::Envelope::parse`; time metadata via serde_json) plus field-name conformance against published CCSDS OEM + LunaNet/IOAG field semantics. Tests (`lunar_interop::tests`): the exported OEM carries the lunar `REF_FRAME` (`MOON_ME`/`MOON_PA`) and `TIME_SYSTEM` (`LTC`/`TCL`) tokens, `CENTER_NAME = MOON`, the object and well-formed data lines; the lunar-time metadata round-trips (rate/band/reference) and rejects garbage; the KIF envelope serialises and deserialises to an equal value with the MODELLED honesty label present; a deliberately broken OEM (missing `TIME_SYSTEM`) fails `oem_conformance` and is reported missing; the scenario dispatches through `run_toml`. **Honest scope:** the field **names/units** are aligned with **public** standards (CCSDS 502.0-B OEM, IAU WGCCRE 2015 lunar frames, the LunaNet Interoperability Specification / IOAG lunar architecture); the export is **MODELLED** — deterministic round-trip + field-name conformance is the oracle, this is **NOT** a certified interoperability conformance test, the ephemeris is **illustrative, public-source, not affiliated with ESA**, and no TRL, flight heritage or agency endorsement is claimed. |

## Demonstration representativeness & gaps-to-flight ledger (`src/representativeness.rs`)

A simulation result is only useful as evidence if it states, on its face, what it is anchored to, what it assumes, and what still separates it from a flight system. The representativeness ledger makes that a first-class, machine-checked output: a `Representativeness` record carries the demonstration's external `Anchor`s, its modelled assumptions, its `Gap`s to flight (each with the phase/activity that would close it), and the TRL band it is representative for. It is the per-result companion to the capability-level `verification` matrix.

The **oracle** is a set of closed-form invariants, enforced by `representativeness::tests`: a `Validated` record must list at least one `ExternalDataset` anchor (a simulation cannot be validated against itself); a `Modelled` record must list at least one gap-to-flight and cannot claim a representative TRL band above 4 (maturation beyond that needs hardware/flight evidence, which is a gap, not a simulation output); the TRL band must be well-formed; and a `PartnerOwned` record must assert nothing. These invariants operationalise the "representativeness justified + remaining gaps towards flight clearly identified" discipline.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Representativeness & gaps-to-flight ledger | `modelled` | `src/representativeness.rs` `Representativeness`/`Anchor`/`Gap`, `check`/`is_valid`/`report`/`to_json`. **Oracle: `InternalConsistency`** — closed-form honesty invariants tied to the `verification` status/oracle-kind boundary. Tests (`representativeness::tests`): a Validated record without an external anchor fails; an internal (ReferenceImpl) anchor does not satisfy Validated; a Modelled record without a gap fails; a Modelled record above TRL 4 fails; malformed TRL bands are caught; the record serialises to JSON with the expected fields and renders a readable report. **Honest scope:** the ledger checks the *classification* of a result's evidence — it does not prove the named anchors resolve to live tests (those are curated, exactly like the `verification` matrix); the "machine-checked" claim is scoped to the status/anchor/gap/TRL invariants. |

## Unified quantum-vs-classical trade evidence (`src/qtrade.rs`)

Every quantum-PNT application area answers the same question the same way: fix one comparison frame (scenario + seed + engine version), route a quantum candidate and a classical baseline through one neutral code path, score them on common figures of merit, and report — with a confidence interval and an honest validated/modelled label — where quantum wins and where it does not. `TradeEvidence` gives that answer a single shape so the timing, navigation and anomaly-detection verticals all emit the **same** reproducible, honestly-labelled object. It does not re-implement any trade: per-FoM numbers come from the existing engines (`quantum_trade`, `crossover`, and the vertical modules); this is the contract plus the reproducibility/representativeness wrapper, built on the representativeness ledger and the verification labels.

The **oracle** is closed-form benefit/winner identities plus a faithful wrap of the existing trade output. `qtrade::tests`: the benefit ratio is polarity-correct (oriented so `>1` always means the quantum side is better, for both higher-is-better holdover and lower-is-better error FoMs); an evidence object built from a real `quantum_trade::TradeResult` reproduces its benefit ratios; dishonest evidence is rejected (a Modelled representativeness without a gap, or a `Validated` FoM whose trade record carries no external anchor); JSON is deterministic and carries the frame/seed/engine/FoM/representativeness fields.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Quantum-vs-classical trade evidence | `modelled` | `src/qtrade.rs` `TradeEvidence`/`TradeFom`/`TradeFrame`/`Winner`. **Oracle: `InternalConsistency`** — closed-form benefit/winner identities + faithful wrap of `quantum_trade::TradeResult`; honesty tied to the representativeness ledger and the verification status/oracle-kind boundary. Tests (`qtrade::tests`) as above. **Honest scope:** the harness standardises *how* a trade is reported and reproduced; the underlying per-FoM physics is whatever the contributing engine provides, carried with its own validated/modelled label — `TradeEvidence` does not upgrade a modelled FoM to validated. |

## Quantum device error-model library (`src/quantum_devices.rs`)

A single place that exposes the quantum-PNT devices the demonstrator trades — optical / trapped-ion / mercury-ion clocks, classical reference clocks, the cold-atom interferometer, and time-transfer links — each as a `DeviceCard` carrying its headline spec and a representativeness record. Most device physics is **reused** (clock stabilities from `holdover::QuantumClockClass` and `clock_state::ClockClass`; the cold-atom interferometer from `quantum_trade`/`crossover`; classical optical/RF links from `timetransfer_adv`). The one genuinely new model is the **entanglement / single-photon time-transfer link**, whose timing precision is shot-limited: `σ_t ≈ jitter/√(R·τ)` in the detected coincidence rate `R` and integration `τ`, degraded by a dark-count penalty `√(1 + dark/R)` and floored by an irreducible systematic.

The **oracle** is the reused, published clock/CAI coefficients plus closed-form shot-noise/loss identities. `quantum_devices::tests`: the reused clock-stability ordering is sane (optical-lattice < mercury-ion < CSAC in σ_y(1 s)); the entanglement precision improves as `1/√τ` (4× integration halves σ) when shot-limited; the detected coincidence rate falls 10× per 10 dB of link loss; dark counts monotonically degrade precision; the systematic floor bounds precision below; every device card is a valid, Modelled representativeness record.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Quantum device error-model library | `modelled` | `src/quantum_devices.rs` `DeviceCard`, `quantum_clock_card`/`classical_clock_card`, `EntanglementTimeLink`. **Oracle: `InternalConsistency`** — reused published clock/CAI coefficients + closed-form shot-noise/loss identities for the entanglement link. Tests (`quantum_devices::tests`) as above. **Honest scope:** clock/CAI device parameters are reused from the engine's existing published-coefficient models; the entanglement-link model is MODELLED from published quantum-clock-synchronisation behaviour with illustrative public-source pair-rate/efficiency/loss values — it is **not** validated against a measured link, and real source/channel/detector hardware is a stated gap-to-flight. |

## Trusted quantum timing — end-to-end chain, secure dissemination, anomaly + trade (`src/timetransfer_chain.rs`)

The `quantum-time-transfer` scenario composes the timing chain a quantum-PNT demonstrator needs: an end-to-end user-time budget (reference-clock coast error and link timing precision combined in quadrature) for a **quantum** chain (optical-lattice clock + entanglement/single-photon link) versus a **classical** chain (CSAC + RF two-way link); a **timing protection level** (reused from `tpl`) bounding the undetected time error; a **delay/replay-attack security figure of merit** `1 − P_md` at a stated false-alarm rate (reused from `detection`); a **clock-anomaly detection probability + CUSUM change-detection latency**; and the quantum-vs-classical comparison as honest `qtrade::TradeEvidence` carrying a representativeness + gaps-to-flight record.

The **oracle** is a closed-form quadrature budget over reused, separately-validated kernels (ADEV vs Stable32/NIST; the TPL bound; `detection::analytic_pd`/`analytic_pmd`). `timetransfer_chain::tests`: quantum precision improves with integration time; the quantum chain can win *and* can lose the precision FoM (honest — not a universal win; a very lossy link flips the result); the protection level is finite-positive; the security FoM is in [0,1] and grows with attack delay; the anomaly detection probability is monotone in fault magnitude; and the trade evidence is internally honest (`is_honest()`).

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Trusted quantum timing (chain + secure dissemination + anomaly + trade) | `modelled` | `src/timetransfer_chain.rs` `QuantumTimeTransferScenario`/`Report`, `to_svg`; `kind="quantum-time-transfer"`. **Oracle: `InternalConsistency`** — closed-form quadrature budget over reused validated kernels (ADEV/Stable32-NIST, TPL bound, detection analytic Pd/Pmd); honesty tied to the representativeness ledger. Tests (`timetransfer_chain::tests`) as above. **Honest scope:** clock/link parameters are illustrative, public-source; the entanglement link is the MODELLED shot-limited model from `quantum_devices`; this models the *class* of trusted-timing system — it is **not** validated against a measured end-to-end link, and real clock/link/space-channel hardware is a stated gap-to-flight; no TRL, flight heritage or certification is claimed. |

## GNSS-free quantum navigation (`src/quantum_nav_od.rs`)

The `quantum-gnss-free-nav` scenario compares dead-reckoning during a GNSS outage with a **quantum** inertial budget (a cold-atom interferometer accelerometer, reused from `inertial::quantum_imu`/`quantum_trade`, whose CAI white-noise floor is validated to within ~2 orders of magnitude of Freier et al. 2016) against a **classical** navigation-grade INS. It reports the position-error growth over the coast, the holdover time to a position threshold, and the quantum-vs-classical trade as honest `qtrade::TradeEvidence`. Observability is stated honestly: with no external fix during the outage the accelerometer bias is unobservable, so the position error grows without bound (≈ ½·bias·t² plus a velocity-random-walk term); a lower-bias quantum sensor *slows* that growth but does not close the gap — only an external fix does.

The **oracle** is the reused inertial budgets (`QuantumNavBudget`/`ClassicalInsBudget`, both implementing the `PositionDrift` trait) plus closed-form drift identities. `quantum_nav_od::tests`: the quantum budget beats the classical over a long outage (lower error, longer holdover); the error grows with outage duration for both (the observability gap); the advantage is outage-dependent, not a constant win factor (the quantum curve is noise-dominated at short coast, bias-dominated at long); the trade evidence is internally honest.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| GNSS-free quantum navigation | `modelled` | `src/quantum_nav_od.rs` `QuantumNavOdScenario`/`Report`, `to_svg`; `kind="quantum-gnss-free-nav"`. **Oracle: `InternalConsistency`** — reused inertial budgets (CAI validated-by-reuse ~2 orders vs Freier 2016; classical closed-form drift); honesty tied to the representativeness ledger. Tests (`quantum_nav_od::tests`) as above. **Honest scope:** a static dead-reckoning budget comparison, not a dynamic filter on real trajectories; bias unobservable without a fix is stated; device parameters are illustrative, public-source; models the *class* of GNSS-free quantum nav — real cold-atom IMU hardware, a dynamic platform and the flight environment are stated gaps-to-flight; no TRL/flight/certification claimed. |

## Fault / anomaly detection for quantum PNT systems (`src/quantum_faults.rs`)

The `quantum-anomaly-detect` scenario defines a labelled catalog of quantum-PNT faults (clock frequency-jump, drift, lock-loss; sensor bias-step, dropout), scores a detection statistic on nominal vs faulted windows, and reports the detector's discrimination as an ROC AUC and a minimum-detectable fault at a fixed false-alarm rate. The quantum-vs-classical angle: a more stable quantum-clock reference lowers the monitor noise σ, so it detects smaller faults — emitted as honest `qtrade::TradeEvidence` with a representativeness record.

The **oracle** is a closed-form AUC for the Gaussian detection statistic (nominal `N(0,σ)`, fault `N(μ,σ)` ⇒ `AUC = Φ(μ/(σ√2))`) cross-checked against the externally-validated `eval_stats::bootstrap_auc_ci` (validated vs scikit-learn) and `detection`'s analytic thresholds. `quantum_faults::tests`: the analytic AUC matches known values (0.5 at μ=0, →1 for large μ/σ, monotone); the empirical bootstrap-AUC CI brackets the closed form; the quantum monitor has higher AUC and a smaller minimum-detectable fault; the advantage vanishes for huge faults (both detect perfectly — not a universal margin); the catalog has five labelled classes; the trade is internally honest.

| Capability | Status | Oracle / honest scope |
|------------|--------|-----------------------|
| Fault/anomaly detection for quantum PNT | `modelled` | `src/quantum_faults.rs` `FaultKind`, `QuantumAnomalyScenario`/`Report`, `analytic_auc`, `min_detectable_fault`; `kind="quantum-anomaly-detect"`. **Oracle: `InternalConsistency`** — closed-form Gaussian AUC cross-checked against the externally-validated `eval_stats` bootstrap AUC (vs scikit-learn) and `detection` analytic thresholds. Tests (`quantum_faults::tests`) as above. **Honest scope:** the detection statistic is a Gaussian model, not real telemetry; the fault catalog is labelled-synthetic; quantum/classical monitor noise levels are illustrative, public-source; models the *class* of quantum-PNT anomaly detection — real hardware telemetry with ground-truth labels is a stated gap-to-flight; no TRL/flight/certification claimed. |

## Standards conformance — interchange formats, link budget & integrity (external-oracle checks)

These standards are validated by recovering the **verbatim worked examples / reference values published in the standards themselves** (or in an independent reference implementation), not by Kshana's own round-trip. Recovering a standard's own annex example is the strongest available conformance check for an interchange-format parser.

| Standard | Status | External oracle |
|----------|--------|-----------------|
| **CCSDS OEM** (502.0-B Orbit Data Messages) | `validated` | `tests/ccsds_reference.rs`: `parse_oem` recovers the exact epochs and X/Y/Z/Ẋ/Ẏ/Ż state vectors of the KVN OEM example in **CCSDS 502.0-B-3, Annex G §G6, Figure G-11** ("OEM Example with No Acceleration, No Covariance", p. G-10) — both ephemeris segments, including the leading-zero source values (`-063.042`). Fixture `tests/fixtures/ccsds/oem_502_b3_figG11.oem` is reproduced character-for-character from the official Blue Book (the editorial "< intervening data records omitted here >" markers, which are not valid OEM records, are not included). |
| **CCSDS TDM** (503.0-B Tracking Data Message) | `validated` | `tests/ccsds_reference.rs`: `TdmFile::parse` recovers all 41 RANGE records (first 3198.03679519614 km, last 3270.46440460551 km) and the metadata of the KVN TDM example in **CCSDS 503.0-B-2, Annex E, Figure E-9** ("Range Data with TIMETAG_REF=TRANSMIT", p. E-9). Fixture `tests/fixtures/ccsds/tdm_503_b2_figE9.tdm` is verbatim from the Blue Book. (This is the published-Blue-Book oracle alongside the pre-existing hand-authored `reference.tdm` round-trip in `src/ccsds_tdm.rs`.) |
| **CCSDS 133.0** (Space Packet Protocol) | `validated` | `src/space_packet.rs` `primary_header_matches_published_independent_test_vectors`: the encoder reproduces the byte-level primary-header test vectors of the independent **`spacepackets` library** (us-irs/spacepackets-py, `tests/ccsds/test_space_packet.py`) — e.g. `18 02 40 34 00 16` and the all-max `1F FF FF FF FF FF` — plus the canonical all-ones TM case, each round-tripped through decode. Bit-field widths/order per **CCSDS 133.0-B-2 §4.1.3**. |
| **CCSDS 401 / DSN** (link budget, DSN 810-005) | `validated` | `src/linkbudget.rs` `link_equation_reproduces_descanso_galileo_dct`: the FSPL and C/N₀ chain reproduce the published deep-space telemetry design-control table of **J. H. Yuen (ed.), *Deep Space Telecommunications Systems Engineering* (DESCANSO/JPL Pub. 82-76), Table 1-1** — the Galileo X-band (8420.43 MHz) downlink at 6.37 AU: free-space loss **290.54 dB** (<0.05 dB) and received **Pr/N₀ = 54.6 dB-Hz** (<0.2 dB). Band centres sit inside the DSN/CCSDS-401 deep-space downlink allocations (DSN 810-005 Module 201). The *default mission params* remain representative (not a calibrated transponder); the link *equation* is what this pins. |

**GNSS standards — external-oracle status and the honest remaining gaps:**

| Standard | Status & honest caveat |
|----------|------------------------|
| **RAIM / ARAIM** | **Kernel externally validated; PL value not pinned.** The detection *kernel* — the χ² fault-detection threshold, the non-central-χ² missed-detection non-centrality, and the normal-law K-multipliers — now reproduces **SciPy** (`tests/raim_reference.rs`, 171 cases, ≤ 1e-6 rel), and the wrapping geometry reproduces **gnss_lib_py** (DOP). What stays **unpinned** is the protection-level *value*: the one published ARAIM oracle — WG-C ARAIM Reference ADD v3.1 "LPV-200 numerical example" (VPL 18.3 m / HPL 13.45 m) — requires the **multi-constellation, accuracy-weighted, multi-fault-mode** machinery Kshana does not implement (its `GᵀG` is single-clock, equal-weight), so neither the published PL nor its σ_v,acc = 1.3694 m intermediate is reproducible; classic RAIM has **no canonical published input→HPL test vector** at all. So: detection kernel validated, geometry validated, but the PL *number* and the ARAIM MHSS budget allocation remain formula-correct, not pinned to a published value. |
| **SBAS / DO-229E** | **Protection-level algorithm now externally validated.** Given the per-satellite (el, az, σ), kshana's `sbas_protection_level` reproduces the **RTKLIB SBAS-PL fork** (`zsiki/rtklib_ws` `waasprotlevels()`, Siki & Takács 2017, "DO-229D Appendix J") — fed that tool's **own** σ computed from **real EGNOS** broadcast messages + real BUTE RINEX — to **< 2e-3 m HPL** across 6 epochs (`tests/sbas_reference.rs`); ESA gLAB v6.0.0 (`core/filter.c`) confirmed the identical convention. K-factors (`K_H,PA=6.0`, `K_V=5.33`, `K_H,NPA≈6.18`) match DO-229E Appendix J. **What is validated vs what is not:** this pins the PL *algorithm* (σ in → HPL/VPL out); the upstream σ-*modelling* from raw UDRE/GIVE messages is out of kshana's scope — that is where independent *full-pipeline* tools still disagree by metres on real data. K_V matched at the oracle's rounded 5.33 (kshana's exact `Φ⁻¹(1−5e-8)=5.3267` → VPL ~0.06 % smaller; the vertical is validated K-factor-free as `d_U`). |
| **IONEX / Klobuchar** | **Broadcast model externally validated.** The Klobuchar L1 model reproduces **RTKLIB's `ionmodel`** (`tests/klobuchar_reference.rs`, < 1e-4 m) — *implementation parity* with the de-facto open reference, since no official *measured-truth* worked example exists. The remaining gap is the **IONEX TEC-map reader** for real 80-column GIM files (a tracked follow-up), not the broadcast model. See the Klobuchar rows in [Claims vs. reality](#claims-vs-reality--quick-reference). |

## Operating envelope

Each pack is exercised across its stated input envelope by
`tests/scenario_coverage.rs`, which asserts every numeric output is finite (no
NaN/Inf) and bounded. The table lists the tested input range per pack, the
expected output behaviour, and the covering test.

| Pack | Input swept | Tested range | Expected output | Covering test |
|------|-------------|--------------|-----------------|---------------|
| clock | `threshold_ns` (timing spec) | 1 – 500 ns | finite holdover/timing/security FoMs | `clock_pack_covers_the_spec_threshold_envelope` |
| inertial | `accel.bias` | 1e-7 – 1e-2 m/s² (cold-atom → crude MEMS) | finite, bounded position RMS/p95 | `inertial_pack_covers_the_accel_bias_envelope` |
| orbit | `mask_deg` (elevation mask) | 5° – 30° | finite DOP/availability; bounded | `orbit_pack_covers_the_elevation_mask_envelope` |
| spoof | `attack.rate_ns_per_s` | 0.1 – 50 ns/s | finite P_md / security, bounded | `spoof_pack_covers_the_attack_rate_envelope` |
| hybrid | `position_spec_m` | 10 – 1000 m | finite timing/position holdover | `hybrid_pack_covers_the_position_spec_envelope` |
| orbit (real) | real Celestrak `gps-ops` TLEs | 30-satellite snapshot, checksum-strict | loads only with valid checksums; bounded geometry | `real_gps_constellation_scenario_loads_with_valid_checksums_and_bounded_output` |
| clock (flicker) | `flicker_floor` on/off | 0 vs 1e-12 | enabling the 1/f floor **worsens** the timing-p95 coast | `flicker_fm_floor_degrades_the_clock_holdover_when_enabled` |
| fusion (realism) | `accel.bias` 0 vs 5.88e-7 m/s² | zero vs realistic non-zero | filter still converges, within 3× the zero-bias error | `fusion_filter_converges_with_a_realistic_non_zero_bias` |

The flicker-FM and fusion-bias rows close two specific realism gaps: the noise
terms are **off by default but demonstrably affect output when enabled**, and the
joint fusion filter **does not depend on biases being zeroed** — it converges with
a realistic cold-atom-grade residual bias too.

## Known limitations

- Quantum and classical runs now use independent RNG seeds (classical seed = seed + 0x9e3779b97f4a7c15) so their noise realizations are uncorrelated — fixed after review.
- `holdover_s` is segment-aware: outage timelines are split into contiguous segments at GNSS re-acquisition and the reported value is the worst-case (shortest) coast across them. It remains bounded by the time-grid resolution (a lower bound).
- ISL time-transfer re-sync models the residual link uncertainty as fresh zero-mean jitter per measurement step plus re-anchoring at the configured interval.

## Claims vs. reality — quick reference

A hostile reviewer's checklist. For each term that could be read as more than it is:
what Kshana does today, and where the real version sits on the roadmap.

| Term you may see | What it actually is today | What it is **not** (yet) |
|------------------|---------------------------|--------------------------|
| "hybrid quantum/classical PNT simulator" | a classical stochastic simulator driven by published quantum-sensor Allan/noise coefficients | first-principles quantum physics (Mach–Zehnder phase, projection noise, systematics) — see [`QUANTUM-MODELS.md`](QUANTUM-MODELS.md) |
| "joint Kalman fusion" / fusion pack | the runnable `fusion` pack observes the clock and position **separately** (a direct time fix and a direct position fix), for which the optimal estimator is genuinely block-diagonal — two two-state filters with a combined FoM | a *coupled* filter for the **pseudorange** case now **exists** as `fusion::coupled::CoupledPntFilter` (4-state stacked `[pos,vel,phase,freq]`, non-zero cross-block covariance, NEES-validated) but is **not yet wired into the runnable pack**, and the pack is **1-DOF** — the 3-D 8-state extension is future work |
| Security FoM (`spoof` kind) | `1 − P_md` of a **stochastic time-spoof detector**: a two-sided χ²₁ / Neyman–Pearson test on a clock-aided monitor statistic, threshold set from a target `P_fa`, `P_md` evaluated **at the spec magnitude** both closed-form and by Monte-Carlo (which agree to a few ×1/√N) | a multi-satellite RAIM/ARAIM detector — see [`INTEGRITY.md`](INTEGRITY.md); the monitor statistic is a Gaussian model with the clock's PSD-derived σ, not a signal-level correlation |
| "clock-aided spoof-detection" | a **single-clock** time-discrepancy monitor (Gaussian statistic, σ from the clock PSD), NOT multi-SV RAIM | range-domain multi-SV RAIM with protection levels |
| spoof-detector P_md (closed-form vs Monte-Carlo) | the analytic `Φ`-based `P_md` and the empirical `mc_runs`-trial estimate match within sampling error (≈ 1/√N); validated in `src/spoof.rs` / `src/detection.rs` tests at a stressed deflection (μ/σ = 2) | a measured detector ROC against recorded spoofing data |
| `gnss-sim` pseudorange model | a **forward simulation**: `ρ = geometric + clocks + Klobuchar iono + Saastamoinen·Niell tropo + noise + multipath`. Each atmosphere model is unit-tested against hand values (ZHD ≈ 2.3 m, Niell = 1 at zenith, Klobuchar obliquity), and the full Klobuchar broadcast model is **cross-checked against RTKLIB's `ionmodel()`** reference implementation to sub-millimetre (`klobuchar_agrees_with_rtklib_reference_implementation`, 6.1278 m for the RTKLIB default-coefficient case — no official published Klobuchar test vector exists, so this is implementation parity, not measured truth); a **zero-noise run reproduces geometry + corrections to sub-millimetre** (RAIM residual ≈ 0) | a position **solution** from real signals (PPP/RTK), dual-frequency iono-free combination, or carrier-phase ambiguity resolution — not modelled |
| jamming model (`jamming` kind) | a **link-budget** chain: J/S from free-space path loss + per-direction antenna gain → effective C/N₀ via the anti-jam equation (despreading gain × spectral-separation `Q`) → loss of lock at a threshold (Kaplan & Hegarty §9.4) | multipath, terrain shadowing of the jammer, near/far AGC, adaptive nulling, acquisition-vs-tracking hysteresis; `Q` is a representative per-type constant, not derived from the jammer's measured PSD |
| Integrity FoM | filter **self-consistency** (fraction of outage samples inside its own k·σ bound) | HPL/VPL, integrity risk / P_HMI, alert limits, DO-229E/316/ED-259A |
| legacy `inertial` scenario **pack** FoM | a **single-axis (1-DOF)** accelerometer/gyro error budget (VRW/ARW, bias-instability) with a truth-snap reset | the *legacy* pack is 1-DOF; the **3-axis path ships in the `gnss-ins` pack** (next row) |
| 3-axis strapdown **library** + `gnss-ins` **pack** (`src/inertial/`, `src/fusion/pack.rs`) | a verified quaternion/NED navigator with a deterministic IMU error model — **scale-factor, misalignment, g-sensitivity, quantization, rate-ramp** modelled (IEEE Std 952-1997 §A.2; Groves 2013 §4.3) — now **driven by the `gnss-ins` scenario pack** and **configurable per sensor from TOML** (`[imu_*.error_model]`) | **not modelled:** vibration rectification error, temperature-gradient drift. The fused-coast error is floor-limited by hand-over attitude error (tilt/accel-bias weakly separable), so per-bias calibration is not claimed |
| "Hybrid PNT integration" | open-loop dead-reckoning bracketed by truth-snap GNSS resets | a coupled (loose/tight) GNSS–INS Kalman blend |
| "Positioning Performance" (clock packs) | clock-phase **timing** RMS in ns (`timing_rms_ns`) | a position-domain RMS/CEP/SEP/DOP-weighted accuracy |
| inertial position FoM (`pos_rms_m`) | a **single-seed, single-axis** position RMS/p95 in metres | an ensemble CEP / 2DRMS distribution (roadmap: Monte-Carlo CEP) |
| "validated to ~2%" | a *typical* observed agreement; the **enforced gate is 20–25%** relative error | a guaranteed 2% accuracy bound |
| "reproducible / bit-identical" | bit-identical re-run on the **same OS + pinned toolchain** | a committed cross-platform golden-hash check (roadmap: reproducibility milestone) |
| SGP4 GPS scenario (`orbit-sgp4-gps.toml`) | synthetic Walker TLEs (placeholder NORAD IDs) for geometry demonstration | the real `gps-ops` constellation — drop in a Celestrak snapshot (see [`REAL_TLE_GUIDE.md`](REAL_TLE_GUIDE.md)) |