mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 10:31:12 +00:00
[AZ-387] C5 smoothed-history → FDR side-channel
After every successful current_estimate(), emit one c5.state.smoothed_history FDR record per newly-smoothed past keyframe from IncrementalFixedLagSmoother. AC-4.5 (revised): the smoothed stream goes ONLY to FDR; the C8 outbound forward-time stream is unaffected. Idempotency via _smoothed_fdr_watermark_s (smoother-native float seconds); the same pose key is never emitted twice. Hook is best-effort — internal failures log warnings but do not raise, so a smoother divergence cannot contaminate the forward-time path. Cross-task invariants documented: - AC-3 ESKF no-op — AZ-386 installs an inert hook on the ESKF. - AC-4 No C8 leak — enforced at the C8 boundary by AZ-261. 8 new unit tests against AC-1/2/5/6 + robustness (no-FDR-client, marginals failure). Full suite: 640 passed, 2 skipped. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# C5 Smoothed-history → FDR path (NOT to FC)
|
||||
|
||||
**Task**: AZ-387_c5_smoothed_history_fdr
|
||||
**Name**: C5 smoothed past-keyframe → FDR path (AC-4.5 revised; NOT to FC)
|
||||
**Description**: After every successful `current_estimate()`, emit the most-recent smoothed past-keyframe (when one becomes available from `IncrementalFixedLagSmoother.calculateEstimate()` retroactive update) to FDR via `FdrClient` (AZ-273). The FDR record carries `smoothed=True`. CRITICAL: the smoothed past-keyframe stream MUST go ONLY to FDR — NEVER routed to C8 outbound (the FC stream is forward-time only per AC-4.5 revised). Wire-up: this task adds the post-`current_estimate` hook to `GtsamIsam2StateEstimator` (and `EskfStateEstimator` — but ESKF reports `smoothed=False`, so this hook is a no-op for ESKF and the hook respects that). Defensive check: the C8 outbound encoder MUST receive ONLY non-smoothed estimates (verified at the C8 boundary in AZ-261 tests; documented here as a cross-task invariant).
|
||||
**Complexity**: 3 points
|
||||
**Dependencies**: AZ-384 (`smoothed_history` impl), AZ-386 (for the no-op hook on ESKF), AZ-273 (`FdrClient`), AZ-272 (FDR record schema), AZ-263, AZ-269, AZ-266
|
||||
**Component**: c5_state (epic AZ-260 / E-C5)
|
||||
**Tracker**: AZ-387
|
||||
**Epic**: AZ-260 (E-C5)
|
||||
|
||||
### Document Dependencies
|
||||
|
||||
- `_docs/02_document/contracts/c5_state/state_estimator_protocol.md` — Invariants 6, 7.
|
||||
- `_docs/02_document/components/07_c5_state/description.md` — § 7 caveats (AC-4.5 internal smoothing is onboard only).
|
||||
|
||||
## Problem
|
||||
|
||||
Without this task, smoothed past-keyframes are not persisted to FDR — defeating AC-4.5 (revised) post-flight forensics. A naive impl that routes smoothed estimates to C8 outbound would also break the FC contract (AC-4.5 forbids retroactive corrections to the FC).
|
||||
|
||||
## Outcome
|
||||
|
||||
- New private hook `_emit_smoothed_to_fdr_if_any()` called after every `current_estimate()` in `GtsamIsam2StateEstimator`. Body: read recent smoothed past-keyframes via `_smoother.calculateEstimate()`; for each newly-smoothed past-keyframe (delta from last emission), emit `EstimatorOutput(smoothed=True)` via `fdr_client.put(...)`.
|
||||
- `EskfStateEstimator` hook: no-op (ESKF doesn't smooth).
|
||||
- Composition root invariant: the `EstimatorOutput` stream feeding C8 outbound is filtered to `smoothed=False` only (this filter is enforced in C8 inbound — AZ-261 — but documented here).
|
||||
- Unit tests: synthetic graph with delayed convergence → smoothed past-keyframes appear after some frames; FDR records emitted with correct shape; ESKF hook is no-op (FDR call count for ESKF == 0 over a full replay); no smoothed estimates leak to a C8-stub queue.
|
||||
|
||||
## Scope
|
||||
|
||||
### Included
|
||||
- `_emit_smoothed_to_fdr_if_any()` impl.
|
||||
- Hook into `current_estimate()` for both estimators.
|
||||
- ESKF no-op handling (honest behaviour).
|
||||
- Unit tests covering both estimators.
|
||||
|
||||
### Excluded
|
||||
- The C8 outbound filter — owned by AZ-261; this task documents the invariant.
|
||||
- The FDR record schema — already AZ-272.
|
||||
- iSAM2 estimator body — AZ-382 / AZ-384.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
**AC-1: iSAM2 emits smoothed past-keyframes to FDR** — synthetic graph with 20 frames of delayed convergence → smoothed entries appear in FDR after the smoother's window catches up.
|
||||
|
||||
**AC-2: FDR records have `smoothed=True`** — every emitted record carries the flag.
|
||||
|
||||
**AC-3: ESKF emits zero smoothed FDR records** — over a full 60-frame replay, `FdrClient.put` is never called from the ESKF hook.
|
||||
|
||||
**AC-4: No leak to C8 outbound** — a stub C8-outbound queue receives ZERO smoothed estimates over the same replay; only `smoothed=False` records reach it.
|
||||
|
||||
**AC-5: Idempotency** — emitting the same smoothed past-keyframe twice is prevented (via a `_last_emitted_smoothed_frame_id` watermark).
|
||||
|
||||
**AC-6: FDR record shape** — `kind="c5.state.smoothed_history"`, fields per the AZ-272 FDR record schema.
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
- Hook adds ≤ 5 ms to `current_estimate` p99 (per smoothed entry; usually 0–1 entries per call).
|
||||
|
||||
## Constraints
|
||||
|
||||
- Smoothed estimates ONLY go to FDR.
|
||||
- ESKF hook MUST be a no-op (honesty).
|
||||
- Idempotency via watermark.
|
||||
|
||||
## Risks & Mitigation
|
||||
|
||||
- **Risk: `IncrementalFixedLagSmoother` retro-emit timing** — verify against pinned GTSAM API; tests cover the typical case where smoothed entries appear with a few-frame delay.
|
||||
- **Risk: Smoothed estimate accidentally routed to C8** — AZ-261's filter is the enforcement point; this task documents the invariant.
|
||||
|
||||
## Runtime Completeness
|
||||
|
||||
- **Named capability**: smoothed past-keyframe → FDR path.
|
||||
- **Production code**: real `_smoother.calculateEstimate()` query; real FDR emission with `smoothed=True`; real watermark idempotency.
|
||||
- **Unacceptable substitutes**: routing smoothed estimates to C8 (AC-4.5 violation); ESKF emitting fake smoothed records (honesty violation).
|
||||
Reference in New Issue
Block a user