Fixed-lag covariance and recovery validation¶
Status: complete (2026-09-22). All six existing PPC runs and all 42 native
comparisons completed successfully. No positioning-accuracy improvement is claimed.
Baseline: eff1a3c; candidate branch: feat/fixed-lag-covariance-holdout.
PR integration note: the tested change was committed as 038e13e and then
cherry-picked onto develop at 34858d1 on fix/fixed-lag-covariance-recovery.
The four scoring tests pass on that branch. Native test and replay evidence
below describes the original frozen source, not the integrated PR head;
native integration validation remains pending for the draft PR.
The user explicitly cancelled unused-data validation. This supersedes that clause of the registered goal. Only existing PPC development data are used; no new dataset acquisition or held-out evaluation is in scope. The user subsequently authorized publishing a PR; merging remains out of scope.
Scope and implementation¶
- Update workspace entry points and verify build/data locations. The workspace
README.mdnow identifies repositories, worktrees and current local paths;HANDOFF_TO_CODEX.mdlabels the July handoff as historical. - Provide covariance for the reported ECEF antenna position. The default-off
FGOConfig::compute_fixed_lag_position_covarianceand parity CLI option--fixed-lag-covariancecapture FLOAT covariance at each actual position revision, including the final window/tail snapshot. FIX output uses its integer-conditioned covariance; held and reoptimized FIX positions carry their own graph marginal. Pose covariance is projected through rotation and the lever arm. Missing, nonfinite or materially indefinite covariance remains NaN. Only tiny numerical negative eigenvalues are clipped to zero. - Correct recovery semantics: require consecutive clean FIX evidence, reset interrupted streaks, reject continuing hard-suspect evidence, handle a one-epoch recovery configuration, require positive covariance and ignore reset-generation changes from unavailable estimates.
- Validate existing PPC runs with frozen settings, record accuracy, wrong FIX, recovery delay, P95, missing epochs, covariance coverage and processing cost.
--dump-shadow-csv exports native statuses and full-precision positions without
reference matching. --dump-csv is a separate reference-matched scoring aid.
The shadow schema preserves SPP/FLOAT/FIXED as native numeric values 1/3/4 and
includes solution_latency_s, reset_generation and
causal_provenance_verified. Small positive traces are not rounded to zero.
Causality and accuracy limits¶
The parity harness's initial static leveling and heading latch can use later
observations. Their known lookahead is now included in exported latency,
without changing the solution. Smoothing latency alone is insufficient:
buildSecondaryCodeTable scans whole rover/base files and base matching can
interpolate a future base epoch. The batch export therefore explicitly sets
causal_provenance_verified=0.
The updated consumer treats unverified, blank or malformed provenance as absent, including reset-generation metadata. It also withholds estimates before their declared latency has elapsed. Legacy CSVs without the provenance column retain their existing producer contract. These checks do not certify the native RTK application's entire preprocessing chain for online operation. A streaming frontend and prefix-invariance audit remain separate future work.
Conditional FIX covariance assumes the accepted integer hypothesis and model; it does not estimate the probability that those integers are correct. All 1,002 wrong FIX epochs across the six runs have trace below 4 m². Small covariance alone is therefore unsuitable as an accuracy check. No threshold was tuned to hide these failures. Covariance remains opt-in and this batch FGO shadow is not promoted to real-time recovery authority.
RTK and FGO also consume the same GNSS observations. Agreement between them is a consistency check, not independent ground truth or evidence excluding errors common to both estimators.
Frozen comparison rules¶
- Compare baseline, candidate covariance OFF and candidate covariance ON with identical inputs and shipping settings. Preserve epoch grid, positions, FIX status, ratio and fixed-count columns. Compare full-precision OFF/ON shadow positions/statuses as a stronger invariant.
- Use 3D error >2 m for wrong FIX; also report the fraction below 0.5 m, horizontal P95, correct FIX count and missing/unmatched inputs.
- Recovery delay is the time from the last wrong FIX in an event to the next FIX with 3D error <=2 m. Report unrecovered events instead of dropping them.
- Promotion requires no increase in wrong FIX or missing outputs and no decrease in correct FIX. Report per-run runtime/P95 tradeoffs regardless.
- Count missing epochs against native reader/processed inputs, before
problem construction and output filtering. FGO uses its logged rover-input
count; RTK sums exact-base, interpolated-base and skipped rover counters.
The metric is
missing_or_unmatched_epochs, not a claim of solver failure. - Truth is used by the offline scorer, not by the native RTK command. The
parity smoke without
--refmust produce byte-identical shadow output.
The FGO runner pins lag 5 s, multi-frequency, partial AR, hold, elevation 25°,
SNR 30, tactical IMU, CMC 0.75, CP hold residual 2 m, exception recovery,
DDPR anchor, FDE, elevation-dependent variance, and demotion distances/settings
5/25/5. Explicit existing project lever arms are Tokyo (0.31,0,0.55) and
Nagoya (0.593,-0.670,-1.216), identical in each pair. Exact argv is saved.
RTK uses the frozen low-cost preset and default residual integrity policy.
Completed development results¶
These are existing development runs, not generalization/held-out evidence. All displayed FGO values are unchanged across baseline/OFF/ON. All completed pairs pass the exported-column and full-precision position/status invariants.
| FGO run | Inputs / matched outputs | Wrong / correct FIX | <0.5 m of outputs | Horizontal P95 m | Recovery P95 s / unrecovered |
|---|---|---|---|---|---|
| Tokyo1 | 11,928 / 11,905 | 388 / 5,536 | 49.845% | 16.284 | 64.68 / 2 |
| Tokyo2 | 9,151 / 9,147 | 226 / 6,424 | 77.949% | 3.392 | 53.68 / 0 |
| Tokyo3 | 15,301 / 15,294 | 112 / 10,851 | 68.040% | 5.981 | 143.32 / 0 |
| Nagoya1 | 7,602 / 7,529 | 37 / 3,039 | 46.062% | 17.352 | 84.16 / 0 |
| Nagoya2 | 9,451 / 9,425 | 178 / 3,408 | 34.801% | 43.577 | 186.96 / 0 |
| Nagoya3 | 5,201 / 5,201 | 61 / 1,456 | 15.401% | 14.811 | 57.25 / 2 |
| FGO run | Positive covariance / outputs | Positive FIX covariance / FIX | Solver OFF / ON seconds | Missing/unmatched inputs |
|---|---|---|---|---|
| Tokyo1 | 11,905 / 11,905 | 5,924 / 5,924 | 90.808 / 347.087 | 23 |
| Tokyo2 | 9,130 / 9,147 | 6,650 / 6,650 | 92.190 / 390.292 | 4 |
| Tokyo3 | 15,294 / 15,294 | 10,963 / 10,963 | 138.694 / 656.100 | 7 |
| Nagoya1 | 7,529 / 7,529 | 3,076 / 3,076 | 72.458 / 340.629 | 73 |
| Nagoya2 | 9,185 / 9,425 | 3,586 / 3,586 | 71.636 / 279.719 | 26 |
| Nagoya3 | 5,201 / 5,201 | 1,517 / 1,517 | 32.262 / 112.649 | 0 |
Tokyo2's 17 missing covariance rows are FLOAT, near logged singular/update
failures at solution indices 6227–6245 (two rows inside that interval are
valid). Both scoring and shadow CSVs retain missing values. The per-run
covariance_missing_epochs.json records indices/times and observed log context;
no per-call covariance exception reason is exported. Nagoya2 has another
240 missing covariance rows, all FLOAT; these remain missing rather than being
replaced by unjustified values. All FIX rows across all six runs have positive
covariance. None of the six runs has a native NONE or nonfinite position output.
For RTK, baseline/candidate without shadow are POS-byte identical, and the candidate with explicitly unverified shadow is POS-byte identical to its no-shadow output. Thus the provenance gate adds no positioning loss or claimed accuracy benefit on these runs.
| RTK run | Inputs / matched outputs | Missing/unmatched | Wrong / correct FIX | <0.5 m of outputs | Horizontal P95 m | Recovery P95 s / unrecovered |
|---|---|---|---|---|---|---|
| Tokyo1 | 11,928 / 10,062 | 1,866 | 282 / 7,893 | 81.067% | 2.256 | 93.68 / 0 |
| Tokyo2 | 9,151 / 8,383 | 768 | 45 / 7,101 | 88.572% | 1.609 | 39.92 / 0 |
| Tokyo3 | 15,301 / 13,539 | 1,762 | 14 / 10,910 | 87.939% | 1.188 | 42.00 / 0 |
| Nagoya1 | 7,602 / 6,715 | 887 | 5 / 4,697 | 73.254% | 1.429 | 46.54 / 0 |
| Nagoya2 | 9,451 / 6,683 | 2,768 | 26 / 4,462 | 74.233% | 5.943 | 290.78 / 0 |
| Nagoya3 | 5,201 / 3,275 | 1,926 | 139 / 2,092 | 70.137% | 10.636 | 128.29 / 0 |
The legacy consumer ignores the new provenance column. Its shadow-enabled outputs fail the no-loss criterion and must not be presented as a causal accuracy baseline:
| Legacy RTK with unverified shadow | Wrong / correct FIX | Missing/unmatched | Shadow samples granted authority |
|---|---|---|---|
| Tokyo1 | 278 / 6,782 | 1,892 | 5,392 |
| Tokyo2 | 43 / 6,854 | 773 | 6,502 |
| Tokyo3 | 4 / 10,078 | 1,760 | 10,904 |
| Nagoya1 | 0 / 4,213 | 905 | 3,047 |
| Nagoya2 | 14 / 2,876 | 2,563 | 2,953 |
| Nagoya3 | 139 / 1,921 | 1,932 | 966 |
Post-filtering can change the epoch grid and positions as well as status; paired FIX-demotion counts alone do not describe the entire effect. Timing is local development evidence, with RTK replay sometimes overlapping FGO processing, not an isolated hardware benchmark.
Tests and build limitations¶
| Check | Result |
|---|---|
| Integrity manager/health/realtime suites | 47 passed; four new failures reproduced before the fix |
| New covariance tests | 6 passed: PSD, numerical lever-arm Jacobian, window/tail, frozen FIX, report-only replacement, reoptimized marginal |
| Complete GTSAM test file | Candidate 177/179; baseline 171/173, same two existing failures |
| Native CLI tests | 4 passed on baseline and final candidate |
| Comparison/scoring tests | 4 passed, including input-based missing denominator |
| Controlled native shadow-contract cases | 7 passed |
The two existing GTSAM failures are
GnssFirstStagingRemainsCholeskyWhenSelectorIsCarried and
CapturesUnanchoredComponentZeroColumnAndExactKeyReference; the latter expects
a type name without MSVC's class prefix. The all-app dependencies of
gnss_run_tests fail on unrelated Windows issues: unistd.h in
gnss_pos_vel_pdc/gnss_smartphone_fgo, and MSVC nesting depth in gnss_fuse.
Focused test executables link the same built libraries and inherit the
repository's existing GTSAM /FORCE:MULTIPLE link requirement. This is not a
full-project CTest pass.
The final 60-epoch smoke preserves baseline/OFF/ON output and, without --ref,
produces byte-identical shadow output. Known initial lookahead is 11.8 s.
Controlled contract tests cover unverified/blank/malformed provenance, future
availability, SPP, an asserted verified marker and legacy CSV format. All
seven POS outputs match the plain smoke. The asserted marker is only a test
fixture: it admits one sample after initialization lookahead elapses, and does
not assert that the batch PPC producer is causally verified. A separate future-
latency/generation-999 case exposes neither the sample nor its generation.
Reports distinguish finite independent_position_valid telemetry from
shadow_health_qualified authority.
Reproduction and evidence¶
Local data: E:/rtklib_v2_ws_data/PPC-Dataset; GTSAM 4.3 navigation installation:
E:/gtsam/install; compiler: MSVC 14.44. Python bindings are disabled. The old
MSVC 14.38 build cache and non-GTSAM binaries are not used as verification.
Baseline worktree: E:/gnsspp-integrity-baseline-source, detached at eff1a3c;
build: E:/gnsspp-build-integrity-baseline. Candidate build:
E:/gnsspp-build-integrity-covariance. Baseline solver libraries are unchanged.
Two CLI-only patches are applied equally:
explicit lever arm
and MSVC parser nesting.
Canonical gnss_fgo_parity and gnss_solve targets build successfully.
From the repository root in PowerShell (use new output directories for a new
inference run; --resume only accepts completed, hash-verified matching runs):
$env:PATH = 'E:/gtsam/install/bin;C:/vcpkg/installed/x64-windows/bin;' + $env:PATH
python scripts/analysis/run_fixed_lag_covariance_regression.py --baseline-bin E:/gnsspp-build-integrity-baseline/apps/Release/gnss_fgo_parity.exe --candidate-bin E:/gnsspp-build-integrity-covariance/apps/Release/gnss_fgo_parity.exe --dataset-root E:/rtklib_v2_ws_data/PPC-Dataset --output-dir E:/rtklib_v2_ws_output/integrity_covariance/full_final --resume
python scripts/analysis/run_integrity_covariance_replay.py --baseline-bin E:/gnsspp-build-integrity-baseline/apps/Release/gnss_solve.exe --candidate-bin E:/gnsspp-build-integrity-covariance/apps/Release/gnss_solve.exe --dataset-root E:/rtklib_v2_ws_data/PPC-Dataset --shadow-root E:/rtklib_v2_ws_output/integrity_covariance/full_final --output-dir E:/rtklib_v2_ws_output/integrity_covariance/realtime_final --resume
Evidence root: E:/rtklib_v2_ws_output/integrity_covariance/.
full_final/{city}_run{n}: FGO CSVs, truth-free shadows, logs, run records, comparisons and per-run covariance accuracy/missing-value audits.realtime_final/{city}_run{n}: four RTK variants, POS/telemetry/logs and metrics.smoke_final,realtime_smoke_final,shadow_contract_checks: final smoke and controlled native input-contract evidence.source_manifest_final.json: frozen inference source hashes;source_manifest_reporting.json: subsequent report-only corrections.build_manifest.json: compiler/CMake settings, executable/library/GTSAM DLL hashes and the focused test CMake projects. Each.run.jsonalso records argv, binary/input/output hashes, PID/state and wall time.input_epoch_inventory.json: direct RINEX epoch counts and reference row/ GPS-week counts for all six runs. Tokyo1 and Nagoya1 have more reference rows than rover observations; these denominators are deliberately distinct.evidence_audit.json: final audit of all 42 completed runs: binary/input/output hashes, input denominators, solution invariants, POS byte equality, provenance rejection and unchanged inference source hashes. No runs remain pending.- Portable validation record: all six result pairs, covariance audits, source/build manifests, input inventory and evidence hashes, retained in the repository without raw observations.
- Test evidence in
E:/rtklib_v2_ws_tmp/:integrity_unit_before.json(8 pass, 4 fail in the reproduction subset),integrity_unit_after.json(47 pass),fgo_all_tests.*,fgo_baseline_all_tests.*,integrity_final_cli_tests.log.
Earlier smoke_paired/full_paired artifacts predate the causality correction;
one ON run was deliberately interrupted and marked accordingly. They are not
final validation evidence. An early report also used output count as a missing-
epoch denominator. The corrected scorer uses input counts and is regression
tested; native inference did not change.
Completion decision¶
All four scope items are complete: workspace entry points, covariance matching the reported position, recovery/availability semantics, and the six-run frozen development comparison. Both replay processes exited successfully. Hash-checked resume regenerated every report with the corrected input denominator without rerunning inference. The final audit covers all 18 FGO and 24 RTK executions.
The covariance implementation passes its correctness checks and preserves positions, but costs 3.49–4.73 times the OFF solver time on these runs. It stays default-off. The recovery state-machine fixes pass focused tests; real-data accuracy improvement is not established because this batch shadow cannot be granted causal authority. All legacy shadow-enabled runs lose correct FIX epochs and fail the declared no-loss gate. No promotion or threshold tuning was performed. Unused-data validation remains cancelled.