Files
Oleksandr Bezdieniezhnykh 06f655d8fb [AZ-335] C1 warm-start hint persistence + F8 reboot recovery wiring
Adds JsonSidecarWarmStartHintStore (atomic JSON + SHA-256 sidecar via
AZ-280) inside c1_vio, plus the cross-strategy WarmStartWiredStrategy
wrapper + prime_warm_start_from_disk / prime_warm_start_from_fc hooks
at runtime_root. AC-7 post-reset covariance inflation and AC-8 "no
fake confidence" baseline floor are enforced at the wiring layer so
no strategy module needed edits. Adds three c1_vio config fields
(warm_start_store_dir, warm_start_save_period_frames,
post_reset_covariance_inflation_factor) and registers the new FDR
kind vio.warm_start. 34 unit tests cover all 10 ACs + 3 NFRs.

Verdict PASS_WITH_WARNINGS — see
_docs/03_implementation/reviews/batch_56_review.md for the four
non-blocking documentation findings (F1 cold-start log kind shorthand,
F2 strategy-frame pose semantics, F3 dev-hardware perf smoke, F4
runtime_root importing c1-internal _facade_spine for shared FDR
conventions).

Closes AZ-335; depends on AZ-528 (batch 55).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 03:30:46 +03:00

8.5 KiB
Raw Permalink Blame History

Batch 56 — Cycle 1 Report

Date: 2026-05-14 Tasks: AZ-335 (C1 Warm-Start + F8 Reboot Recovery) Verdict: COMPLETE — PASS_WITH_WARNINGS

Summary

Implemented the cross-strategy warm-start hint persistence layer, the F2 takeoff (FC EKF) and F8 reboot (disk) prime hooks, and the AC-5.3 "no fake confidence" covariance enforcement at the runtime composition layer. The persistence layer is c1-internal (components/c1_vio/warm_start_store.py); the cross-strategy wiring (wrapper + prime hooks) lives at the composition root (runtime_root/warm_start_wiring.py) so any concrete VioStrategy gains warm-start behaviour without per-strategy edits. AC-5.3 is enforced via a wrapper-owned post-reset covariance inflation + baseline floor — not by mutating any strategy. Default ships with the JsonSidecarWarmStartHintStore (atomic JSON + SHA-256 sidecar via AZ-280); a future Redis-backed store can plug in via the same WarmStartHintStore Protocol without touching the wiring.

Closes the AZ-335 dependency chain: AZ-331 / AZ-332 / AZ-333 / AZ-334 (strategies) + AZ-263 / AZ-269 / AZ-266 / AZ-270 (bootstrap + config + log + compose lint) + AZ-280 (sha256 sidecar) + AZ-272 (FDR schema). Runs immediately after AZ-528 (batch 55) — no other c1_vio work was blocked behind AZ-335.

Files added / modified

Added (3)

  • src/gps_denied_onboard/components/c1_vio/warm_start_store.py — 440 lines. Exports HINT_FILENAME, HINT_SCHEMA_VERSION, LoadedWarmStartHint dataclass, WarmStartHintStore Protocol, WarmStartFcSource Protocol (consumer-side cut over C8 FcAdapter per AZ-507), and the default JsonSidecarWarmStartHintStore impl. JSON schema v1: version, calibration_id (Risk-2 mitigation), pre_reboot_covariance_norm (AC-8 floor), pose block (4×4 matrix
    • velocity + bias + ns timestamp).
  • src/gps_denied_onboard/runtime_root/warm_start_wiring.py — 563 lines. Exports WARM_START_PRODUCER_ID, WarmStartWiredStrategy (the wrapper that adds AC-6 throttled save + AC-7 inflation + AC-8 floor on top of any inner VioStrategy), prime_warm_start_from_disk (F8 hook), and prime_warm_start_from_fc (F2 hook). Single point of FDR record emission via _emit_prime_fdr and single point of INFO/WARN log emission via _emit_prime_log.
  • tests/unit/c1_vio/test_az335_warm_start.py — 34 unit tests covering all 10 ACs + 3 NFRs. Local fakes for VioStrategy and WarmStartFcSource; real Sha256Sidecar on tmp_path for the store tests so AC-1 / AC-2 / AC-10 atomicity contracts are exercised against the production helper.

Modified (3)

  • src/gps_denied_onboard/components/c1_vio/config.py — added warm_start_store_dir (default /var/lib/gps_denied_onboard/warm_start/), warm_start_save_period_frames (default 5), post_reset_covariance_inflation_factor (default 2.0). Each new field has a __post_init__ validation matching the existing pattern.
  • src/gps_denied_onboard/fdr_client/records.py — registered the new FDR kind vio.warm_start in KNOWN_PAYLOAD_KEYS with the frozen schema {source, strategy_label, bias_norm, staleness_ns, pre_reboot_covariance_norm}.
  • tests/unit/test_az272_fdr_record_schema.py — added the per-kind fixture branch for vio.warm_start so the AC-1 round-trip suite stays exhaustive over KNOWN_KIND.

Tests

  • tests/unit/c1_vio/test_az335_warm_start.py — 34 new tests, all pass (4.01 s).
  • Adjacent regression sweep (tests/unit/c1_vio/, tests/unit/c13_fdr/, tests/unit/composition_root/, test_az272_fdr_record_schema, test_az269_config_loader, test_az270_compose_root, test_az273_fdr_client_ringbuf, test_az266_logging_schema, test_ac1_scaffold_layout) — 356 pass + 6 tier-2 skipped (unchanged from pre-AZ-335 state).

AC traceability

AC Status Test
AC-1 TestStoreAc1RoundTrip (3 tests; deep-equal + file presence)
AC-2 TestStoreAc2Corrupted (3 tests; sha mismatch + bad envelope)
AC-3 TestWiringAc3ColdStart::test_cold_start_does_not_invoke_reset
AC-4 TestWiringAc4F8Reboot::test_f8_reboot_loads_hint_calls_reset_emits_fdr
AC-5 TestWiringAc5F2Takeoff::test_f2_takeoff_fetches_fc_calls_reset_persists
AC-6 TestWiringAc6PerFrameSave (2 tests; period=5 + period=1)
AC-7 TestWiringAc7PostResetInflation (2 tests; with/without reset)
AC-8 TestWiringAc8CovarianceFloor (2 tests; floor active + dormant)
AC-9 TestStoreAc9Clear (3 tests; remove + log + idempotent)
AC-10 TestStoreAc10Atomicity::test_kill_mid_save_leaves_prior_hint_loadable
NFR-perf-save TestStoreNfrPerf::test_nfr_perf_save_p99_under_50ms
NFR-perf-load TestStoreNfrPerf::test_nfr_perf_load_p99_under_20ms
NFR-no-crash TestWiringNfrNoCrash (4 tests; FC raise/None + save fail + reset fail)
Risk-2 (calib) TestStoreAc3CalibrationMismatch::test_calibration_mismatch_returns_none_with_specific_warn

Code review

See _docs/03_implementation/reviews/batch_56_review.md — verdict PASS_WITH_WARNINGS, 1 Medium + 3 Low findings, all informational / documentation-tightening:

  • F1 (Style, Low): AC-3 spec text shorthand vs source-suffixed log kind — recommend updating spec phrasing in cycle 2.
  • F2 (Maintainability, Medium): per-frame save uses strategy-frame pose as body_T_world; semantically defensible because the strategy's "internal frame" persists across F8 reload via the saved pose; recommend an inline 3-line comment explaining the design choice.
  • F3 (Spec-Gap, Low): NFR perf tests are dev-hardware smoke; full Tier-2 NVMe perf gate is owned by C1-PT-01 (deferred to E-BBT).
  • F4 (Architecture, Low): runtime_root/warm_start_wiring.py imports c1-internal _facade_spine for shared FDR conventions; allowed by module-layout §6, but noted for a possible future promotion of bias_norm to helpers/imu_bias.py.

Outcomes & lessons

  • The Protocol-cut-at-consumer pattern (defining WarmStartFcSource inside c1_vio/warm_start_store.py instead of importing the concrete C8 FcAdapter) is the right shape for AZ-507 compliance. The composition root will wire a thin adapter from C8's actual FcAdapter to this Protocol. The AZ-335 wiring tests inject a fake matching the surface directly — no C8 dependency in the test.
  • Wrapping (rather than per-strategy mixing) for cross-strategy concerns scales: AC-7 inflation + AC-8 floor + AC-6 throttled save all live in one 240-line wrapper class with one inner VioStrategy field. The three strategies (OKVIS2 / VINS-Mono / KLT-RANSAC) needed zero edits.
  • AC-7 and AC-8 stack cleanly: inflation is applied first, then if the inflated norm is below the AC-8 floor it is scaled up to the floor. Both operations preserve SPD because they're positive scalar multiplications. No matrix re-decomposition required.
  • The AC-NFR-no-crash policy (catch + log + return False; never propagate) is enforced at every prime hook seam: FC source raise, FC source returns None, store.save raises, inner.reset raises. Each path emits a distinct log kind so post-mortem can partition the failure mode.

Outstanding

  • F1 / F2 / F3 / F4 from this batch's review — non-blocking; recommend folding into a future hygiene PBI alongside any AZ-345+ c3 work that touches the same vio.warm_start FDR namespace.
  • The composition root's compose_* binaries do NOT yet wire a WarmStartWiredStrategy over the vio_factory output. The wiring is in place; the actual call site (runtime_root/runtime.py or the per-binary compose script) needs to construct the WarmStartWiredStrategy + JsonSidecarWarmStartHintStore and call the F8 prime hook before the first process_frame. This is out of scope for AZ-335 (the spec only delivers the wiring module, not the per-binary integration); the integration belongs to the next-cycle compose-root task that adds the F2/F8 hook invocations alongside the existing strategy build.

Next batch

AZ-345 (C3 DISK + LightGlue Primary Matcher, 5 points) is the next unblocked product PBI per _dependencies_table.md. All its dependencies (AZ-263, AZ-269, AZ-278, AZ-282, AZ-298, AZ-299, AZ-303, AZ-281, AZ-321, AZ-266, AZ-272, AZ-344) are complete.