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
// SPDX-License-Identifier: AGPL-3.0-only
//! Pin every number the tutorials quote, so a tutorial can never silently lie.
//!
//! Each annotated teaching scenario under `docs/tutorials/scenarios/` is pulled in
//! with `include_str!`, run through the public API (`run_toml` / `export_sp3` /
//! `list_scenario_kinds`), and asserted against the tutorial's headline numbers.
//! Every assertion is anchored to an EXTERNAL, non-circular oracle named in the
//! tutorial and in this file's comments — never a self-comparison or an unsourced
//! magic number. This makes each documented figure a CI-enforced contract: the
//! moment the engine drifts from a tutorial's quoted output, the build goes red.
//!
//! Mirrors the `dispatches_each_kind_*` pattern in `src/api.rs` and the structure
//! of `tests/sgp4_verification.rs`.
/// Every tutorial scenario kind is a real dispatch kind (guards against
/// documenting a kind that does not exist). Oracle: the self-describing
/// `list_scenario_kinds` API in `src/api.rs`.
#[test]
fn tutorial_scenarios_use_real_kinds() {
let kinds: std::collections::HashSet<_> = kshana::api::list_scenario_kinds()
.iter()
.map(|m| m.name)
.collect();
for k in [
"clock",
"orbit",
"integrity",
"spoof",
"hybrid",
"inertial",
"timetransfer",
"gnss-sim",
] {
assert!(
kinds.contains(k),
"tutorial kind {k} missing from list_scenario_kinds"
);
}
}
/// Every annotated teaching scenario runs end-to-end and emits the unified output
/// envelope (JSON + SVG + summary). Mirrors `api.rs::dispatches_each_kind`.
#[test]
fn annotated_tutorial_scenarios_run() {
for src in [
include_str!("../docs/tutorials/scenarios/clock.toml"),
include_str!("../docs/tutorials/scenarios/orbit.toml"),
include_str!("../docs/tutorials/scenarios/integrity.toml"),
include_str!("../docs/tutorials/scenarios/security.toml"),
include_str!("../docs/tutorials/scenarios/hybrid.toml"),
include_str!("../docs/tutorials/scenarios/inertial.toml"),
include_str!("../docs/tutorials/scenarios/timetransfer.toml"),
include_str!("../docs/tutorials/scenarios/gnss-sim.toml"),
] {
let out = kshana::api::run_toml(src).expect("tutorial scenario runs");
assert!(out.json.starts_with('{'));
assert!(out.svg.starts_with("<svg"));
assert!(!out.summary.is_empty());
}
}
/// Tutorial 1 — orbit / GPS headline numbers. Oracle: the GPS shell geometry and
/// the PDOP·σ_UERE position-sigma identity (Misra & Enge, *Global Positioning
/// System*, 2nd ed.).
#[test]
fn tutorial1_orbit_headline_holds() {
let out =
kshana::api::run_toml(include_str!("../docs/tutorials/scenarios/orbit.toml")).unwrap();
let v: serde_json::Value = serde_json::from_str(&out.json).unwrap();
let g = &v["geometry"];
// best PDOP ~1.07; position sigma = PDOP * sigma_uere, and sigma_uere = 1.0
// here, so the two are numerically equal (the identity, not "sigma == PDOP").
let pdop = g["best_pdop"].as_f64().unwrap();
assert!((pdop - 1.071).abs() < 0.01, "best PDOP {pdop}");
assert!((g["best_position_sigma_m"].as_f64().unwrap() - pdop).abs() < 1e-6);
assert_eq!(g["samples_total"].as_u64().unwrap(), 361);
// 345/361 GNSS-nominal -> > 90 % (a real GPS shell seen from a LEO user).
assert!(out.summary.contains("345/361"));
}
/// Tutorial 1 — the "where are the satellites" claim: PG01 must lie on the real GPS
/// MEO shell. Oracle: GPS semi-major axis a ≈ 26,560 km (IS-GPS-200 / GPS SPS
/// Performance Standard), EXTERNAL to Kshana.
#[test]
fn tutorial1_satellites_are_in_the_gps_meo_shell() {
let sp3 =
kshana::api::export_sp3(include_str!("../docs/tutorials/scenarios/orbit.toml")).unwrap();
// First-epoch PG01 line: parse the 3 ECEF km, geocentric radius must be the
// GPS shell radius.
let line = sp3.lines().find(|l| l.starts_with("PG01")).unwrap();
let xs: Vec<f64> = line[4..]
.split_whitespace()
.take(3)
.map(|s| s.parse().unwrap())
.collect();
let r = (xs[0] * xs[0] + xs[1] * xs[1] + xs[2] * xs[2]).sqrt();
// GPS a ~ 26,560 km; accept the eccentricity band around it.
assert!(
(26000.0..27200.0).contains(&r),
"PG01 geocentric radius {r} km not in the GPS MEO shell"
);
}
/// Tutorial 2 — clock holdover ordering + the CSAC value. Oracle: the NIST SP 1065
/// white-FM phase-error law σ_x(T) = √(q_wf·T); for the CSAC the k-σ/p95 spec-cross
/// sits in the SP-1065 band (a band, not an exact magic number).
#[test]
fn tutorial2_clock_holdover_holds() {
let out =
kshana::api::run_toml(include_str!("../docs/tutorials/scenarios/clock.toml")).unwrap();
let v: serde_json::Value = serde_json::from_str(&out.json).unwrap();
let q = v["quantum"]["fom"]["holdover_s"].as_f64().unwrap();
let c = v["classical"]["fom"]["holdover_s"].as_f64().unwrap();
assert!(q >= c, "optical must hold >= CSAC");
assert!((q - 6600.0).abs() < 1.0, "optical holds the full outage");
// CSAC breaches 20 ns near the white-FM crossing time (NIST SP 1065).
assert!(
(2000.0..3200.0).contains(&c),
"CSAC holdover {c}s off the SP-1065 prediction band"
);
}
/// Tutorial 3 (Part A) — spoof detector: the closed-form χ²₁ P_md and the
/// Monte-Carlo P_md must agree. Oracle: two INDEPENDENT computations of the same
/// probability (Kay, *Detection Theory*) — non-circular by construction.
#[test]
fn tutorial3_spoof_analytic_matches_montecarlo() {
let out =
kshana::api::run_toml(include_str!("../docs/tutorials/scenarios/security.toml")).unwrap();
let v: serde_json::Value = serde_json::from_str(&out.json).unwrap();
for side in ["quantum", "classical"] {
let a = v[side]["detection"]["analytic_pmd"].as_f64().unwrap();
let m = v[side]["detection"]["mc_pmd"].as_f64().unwrap();
assert!(
(a - m).abs() < 0.05,
"{side} analytic {a} vs MC {m} disagree"
);
}
// Quantum security ~ 1.0 (catches the spec-sized spoof) >> classical.
assert!(v["quantum"]["security_fom"].as_f64().unwrap() > 0.9);
}
/// The reproducibility lesson (Tier-3 exercise claim) is true: the same source
/// yields an identical result on two runs. Oracle: the repo's own determinism
/// guarantee (`scripts/check-reproducible.sh`).
#[test]
fn tutorial_reproducibility_is_bit_stable() {
let s = include_str!("../docs/tutorials/scenarios/clock.toml");
let a = kshana::api::run_toml(s).unwrap().json;
let b = kshana::api::run_toml(s).unwrap().json;
assert_eq!(a, b, "deterministic engine");
}