mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 08:11:12 +00:00
[AZ-404] [AZ-389] [AZ-559] E2E replay test (Derkachi 60s) + AZ-389 cleanup
Batch 63 of /autodev replay slice. Adds the AZ-404 E2E test harness against the Derkachi fixture and resolves the AZ-389 dependency phantom (closing AZ-559 Won't Fix). E2E test (AZ-404) - tests/e2e/replay/_tlog_synth.py: deterministic CSV->tlog generator (the original Derkachi tlog is not in repo; data_imu.csv is its export, so we round-trip the CSV through pymavlink). Verified: SCALED_IMU2 + ATTITUDE + GPS_RAW_INT + HEARTBEAT round-trip cleanly through mavutil.mavlink_connection. - tests/e2e/replay/_helpers.py: parse_jsonl, l2_horizontal_m (haversine), match_percentage, CapturingMavlinkTransport (ready for AZ-558 unblock), GroundTruthRow + load_ground_truth_csv. - tests/e2e/replay/conftest.py: derkachi_replay_inputs (session scope), replay_runner (subprocess fixture per AZ-402 CLI), operator_pre_flight_setup placeholder. - tests/e2e/replay/test_derkachi_1min.py: 9 tests covering AC-1..AC-8 with AC-7 skip-gate self-check + AC-4a mode-agnosticism AST scan (passes unconditionally, confirms ADR-011 holding). - tests/e2e/replay/test_helpers.py: 14 unit tests covering AC-9 helper L2 correctness + match_percentage + parse_jsonl + CapturingMavlinkTransport (all unconditional). - tests/e2e/replay/README.md: AC matrix, fixture state, runtime budget, failure cookbook (AC-10). AC matrix - AC-1, AC-2, AC-5, AC-6 implemented and Tier-1 gated on RUN_REPLAY_E2E=1. - AC-3 (<=100m for 80%) xfail until real Topotek KHP20S30 calibration ships (camera_info.md states intrinsics are unknown). - AC-4a (mode-agnosticism AST scan) PASSES unconditionally. - AC-4b (encoder byte-equality) skip until AZ-558 routes C8 bytes through MavlinkTransport. - AC-7 (skip-gate self-check) PASSES unconditionally. - AC-8 (operator workflow rehearsal) skip until D-PROJ-2 mock-suite-sat-service implements tile-fetch + index-build endpoints. - AC-9 (helper L2 correctness) 14 PASSES unconditionally. AZ-389 housekeeping - AZ-559 closed Won't Fix: investigation against c6_tile_cache/_types.py confirmed TileSource.ONBOARD_INGEST + TileMetadata.quality_metadata + write_tile's FreshnessRejectionError already cover the mid-flight ingest semantic. The "missing API" was a spec-vs-impl naming mismatch. - AZ-389 spec rewritten to consume the existing write_tile API + catch FreshnessRejectionError per AC-NEW-3 opportunistic emission. - _dependencies_table.md reverted: AZ-389 deps -> AZ-303 (was AZ-559 in the previous commit on this branch); total 150 / 497 pts. Tests - Full regression: 2099 passed (+14 new e2e/replay), 94 skipped (incl. 8 e2e/replay heavy-tier + documented blocker skips), 3 perf-microbench flakes deselected (test_cli_cold_start_under_2s, test_cold_start_under_500ms_p99, test_nfr_perf_sign_microbench; all pass in isolation - pre-existing under-load flakes on dev macOS). Reviews - _docs/03_implementation/reviews/batch_63_review.md: code review PASS_WITH_WARNINGS (3 documented spec-gap deferrals: AC-3, AC-4b, AC-8). - _docs/03_implementation/cumulative_review_batches_61-63_cycle1_report.md: cumulative review PASS_WITH_WARNINGS. Action items: prioritise AZ-558 (closes AZ-401 AC-9 + AZ-404 AC-4b); consider 2pt hygiene PBI for Protocol-completeness AST scan to catch the AZ-389 / AZ-559 phantom-API pattern at task-prep time. Architecture invariants observably holding - ADR-011 (replay-as-configuration): AC-4a's AST scan over src/gps_denied_onboard/components/**/*.py finds zero violations - components branch on neither config.mode nor any synonym. - Single composition root (replay protocol Invariant 11): AZ-402 CLI dispatches to runtime_root.main(config); does not call compose_root directly. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# Dependencies Table
|
||||
|
||||
**Date**: 2026-05-14 (refreshed at start of Batch 63: AZ-559 added — C6 mid-flight tile storage extension; unblocks AZ-389 (orthorectifier had a hard dep gap on a `put_mid_flight_candidate` API that AZ-303 never delivered); AZ-389 deferred and re-blocked on AZ-559; earlier same-day after Batch 61: AZ-558 follow-up added — routes C8 outbound encoder bytes through `MavlinkTransport` seam; closes AZ-401 AC-9 deferred during batch 61 due to encoder-side routing not being in the AZ-401 task envelope; earlier same-day after cumulative review batches 52-54: AZ-528 hygiene PBI added for c1_vio strategy facade orchestration-spine 3-way duplication (Medium); earlier same-day after Batch 53: AZ-333 VINS-Mono landed — first c1_vio strategy after the AZ-332 OKVIS2 production-default; consolidation hygiene for the strategy-facade duplication deferred to a post-AZ-334 PBI; earlier same-day after Batch 51: AZ-527 hygiene PBI added from cumulative review batches 49-51 F1; 2026-05-13: AZ-526 hygiene PBI added from cumulative review batches 46-48 F1+F3; same-day refresh after Batch 44 SRP refactor: AZ-317 superseded; AZ-329 + AZ-330 specs rewritten; AZ-523 + AZ-524 audit-trail tickets added; E-C12 epic renamed `Operator Pre-flight Tooling` → `Operator Pre-flight Orchestrator`; earlier same-day refresh: AZ-507 + AZ-508 hygiene PBIs from cumulative review batches 31-33; 2026-05-11: AZ-489 + AZ-490 ADR-010 operator-origin path)
|
||||
**Total Tasks**: 151 (110 product + 41 blackbox-test) — AZ-317 retained in the table marked SUPERSEDED for audit; AZ-523 (C11 gate removal) + AZ-524 (C12 rename) added as 2 closed audit-trail tasks; AZ-526 = 2pt clock-helper hygiene; AZ-527 = 2pt c2 engine-dim helper hygiene; AZ-528 = 3pt c1_vio facade-spine hygiene; AZ-558 = 3pt MavlinkTransport routing follow-up; AZ-559 = 5pt C6 mid-flight tile storage extension
|
||||
**Total Complexity Points**: 502 (369 product + 133 blackbox-test) — AZ-523 = 3pt, AZ-524 = 2pt, AZ-526 = 2pt, AZ-527 = 2pt, AZ-528 = 3pt, AZ-558 = 3pt, AZ-559 = 5pt
|
||||
**Date**: 2026-05-14 (refreshed at start of Batch 63: AZ-559 closed Won't Fix — gap was illusory; `TileSource.ONBOARD_INGEST` + `TileMetadata.quality_metadata` + `write_tile`'s `FreshnessRejectionError` already cover the AZ-389 mid-flight ingest semantic without any new API; AZ-389 dep restored to AZ-303; earlier same-day after Batch 61: AZ-558 follow-up added — routes C8 outbound encoder bytes through `MavlinkTransport` seam; closes AZ-401 AC-9 deferred during batch 61 due to encoder-side routing not being in the AZ-401 task envelope; earlier same-day after cumulative review batches 52-54: AZ-528 hygiene PBI added for c1_vio strategy facade orchestration-spine 3-way duplication (Medium); earlier same-day after Batch 53: AZ-333 VINS-Mono landed — first c1_vio strategy after the AZ-332 OKVIS2 production-default; consolidation hygiene for the strategy-facade duplication deferred to a post-AZ-334 PBI; earlier same-day after Batch 51: AZ-527 hygiene PBI added from cumulative review batches 49-51 F1; 2026-05-13: AZ-526 hygiene PBI added from cumulative review batches 46-48 F1+F3; same-day refresh after Batch 44 SRP refactor: AZ-317 superseded; AZ-329 + AZ-330 specs rewritten; AZ-523 + AZ-524 audit-trail tickets added; E-C12 epic renamed `Operator Pre-flight Tooling` → `Operator Pre-flight Orchestrator`; earlier same-day refresh: AZ-507 + AZ-508 hygiene PBIs from cumulative review batches 31-33; 2026-05-11: AZ-489 + AZ-490 ADR-010 operator-origin path)
|
||||
**Total Tasks**: 150 (109 product + 41 blackbox-test) — AZ-317 retained in the table marked SUPERSEDED for audit; AZ-523 (C11 gate removal) + AZ-524 (C12 rename) added as 2 closed audit-trail tasks; AZ-526 = 2pt clock-helper hygiene; AZ-527 = 2pt c2 engine-dim helper hygiene; AZ-528 = 3pt c1_vio facade-spine hygiene; AZ-558 = 3pt MavlinkTransport routing follow-up; AZ-559 closed Won't Fix
|
||||
**Total Complexity Points**: 497 (364 product + 133 blackbox-test) — AZ-523 = 3pt, AZ-524 = 2pt, AZ-526 = 2pt, AZ-527 = 2pt, AZ-528 = 3pt, AZ-558 = 3pt
|
||||
|
||||
Dependencies columns list only the tracker-ID portion (descriptive tail
|
||||
text in each task spec is omitted here for table-readability). The
|
||||
@@ -96,7 +96,7 @@ are all declared and documented below under **Cycle Check**.
|
||||
| AZ-386 | C5 EskfStateEstimator — mandatory simple-baseline | 5 | AZ-381, AZ-276, AZ-277, AZ-279, AZ-263, AZ-269, AZ-266, AZ-272 | AZ-260 |
|
||||
| AZ-387 | C5 smoothed past-keyframe → FDR path (AC-4.5 revised) | 3 | AZ-384, AZ-386, AZ-273, AZ-272, AZ-263, AZ-269, AZ-266 | AZ-260 |
|
||||
| AZ-388 | C5 AC-5.2 fallback path — 3 s no-estimate detector + downstream signal | 3 | AZ-384, AZ-386, AZ-273, AZ-272, AZ-390, AZ-397, AZ-263, AZ-269, AZ-266 | AZ-260 |
|
||||
| AZ-389 | C5 internal orthorectifier — produces mid-flight tile candidates for C6 (BLOCKED on AZ-559) | 3 | AZ-384, AZ-385, AZ-559, AZ-263, AZ-269, AZ-266, AZ-272 | AZ-260 |
|
||||
| AZ-389 | C5 internal orthorectifier — produces mid-flight tile candidates for C6 | 3 | AZ-384, AZ-385, AZ-303, AZ-263, AZ-269, AZ-266, AZ-272 | AZ-260 |
|
||||
| AZ-390 | C8 FcAdapter + GcsAdapter Protocols + DTOs + errors + composition factories | 3 | AZ-263, AZ-269, AZ-270, AZ-273, AZ-277, AZ-279, AZ-266 | AZ-261 |
|
||||
| AZ-391 | C8 inbound subscription — IMU/attitude/GPS-health/MAV_STATE producer | 5 | AZ-390, AZ-263, AZ-269, AZ-266, AZ-272, AZ-273, AZ-276 | AZ-261 |
|
||||
| AZ-392 | C8 CovarianceProjector — honest 6×6 → 2×2 → equivalent_radius helper | 3 | AZ-390, AZ-263, AZ-269, AZ-266, AZ-272 | AZ-261 |
|
||||
@@ -114,7 +114,6 @@ are all declared and documented below under **Cycle Check**.
|
||||
| AZ-404 | E2E replay fixture test — Derkachi 1–2 min clip + mode-agnosticism + operator workflow | 5 | AZ-402, AZ-401, AZ-405, AZ-263, AZ-269, AZ-266, AZ-272, AZ-273 | AZ-265 |
|
||||
| AZ-405 | replay_input/ coordinator + auto-sync of video ↔ tlog via IMU take-off detection | 5 | AZ-399, AZ-398, AZ-263, AZ-269, AZ-266, AZ-272, AZ-279 | AZ-265 |
|
||||
| AZ-558 | Route C8 outbound encoder bytes through MavlinkTransport seam (closes AZ-401 AC-9) | 3 | AZ-401, AZ-273, AZ-294, AZ-399 | AZ-265 |
|
||||
| AZ-559 | C6 mid-flight tile storage extension — put_mid_flight_candidate Protocol + DTO + persistence | 5 | AZ-303, AZ-308, AZ-310, AZ-263, AZ-269, AZ-266, AZ-272 | AZ-260 |
|
||||
| AZ-406 | Blackbox Test Infrastructure Bootstrap (Tier-1 + Tier-2 harness scaffold) | 5 | AZ-263 | AZ-262 |
|
||||
| AZ-407 | Static fixture builders — tile-cache, age-injector, cold-boot, MAVLink passkey, CVE JPEG | 3 | AZ-406 | AZ-262 |
|
||||
| AZ-408 | Runtime synthetic-injection fixture builders — outlier, blackout-spoof, multi-segment | 3 | AZ-406, AZ-407 | AZ-262 |
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
# C5 Orthorectifier → C6 mid-flight tile gen sub-path
|
||||
|
||||
**Task**: AZ-389_c5_orthorectifier_c6
|
||||
**Name**: C5 internal orthorectifier — produces mid-flight tile candidates for C6
|
||||
**Description**: Implement the orthorectifier sub-path inside C5: when a frame has converged in the iSAM2 graph (≥1 satellite anchor + visual consistency), apply the camera intrinsics + extrinsics + the C5-known pose to orthorectify the nav-camera frame into a tile-aligned image patch; emit a `MidFlightTileCandidate(tile_id, pixels, quality_metadata, source_pose)` to C6 (via the storage interface AZ-303 `tile_store.put_mid_flight_candidate(...)`). Quality metadata: `inlier_count`, `cov_norm`, `pose_age_ms`. The orthorectifier is C5-internal (per epic spec § Scope: "orthorectifier (lives within C5 as an internal subcomponent)"); it consumes the converged pose + nav frame from a per-frame buffer; it emits at most ONE candidate per frame (gated by quality thresholds: `cov_norm < threshold` AND `inlier_count > floor`). Triggered after a successful `current_estimate()` call when quality conditions hold.
|
||||
**Name**: C5 internal orthorectifier — produces mid-flight tile candidates for C6 via existing `TileStore.write_tile` + `ONBOARD_INGEST` source
|
||||
**Description**: Implement the orthorectifier sub-path inside C5: when a frame has converged in the iSAM2 graph (≥1 satellite anchor + visual consistency), apply the camera intrinsics + extrinsics + the C5-known pose to orthorectify the nav-camera frame into a tile-aligned image patch; persist it to C6 as a `TileSource.ONBOARD_INGEST` tile via the existing `TileStore.write_tile(tile_blob, metadata)` API (AZ-303). The orthorectifier is C5-internal (per epic spec § Scope: "orthorectifier (lives within C5 as an internal subcomponent)"); it consumes the converged pose + nav frame from a per-frame buffer; it emits at most ONE tile per frame (gated by quality thresholds: `cov_norm < threshold` AND `inlier_count > floor`). Triggered after a successful `current_estimate()` call when quality conditions hold AND `source_label == SATELLITE_ANCHORED`. Per AC-NEW-3 the emission is opportunistic: a `FreshnessRejectionError` from C6's freshness gate is caught and dropped (DEBUG log only).
|
||||
**Complexity**: 3 points
|
||||
**Dependencies**: AZ-384 (`current_estimate` body + cov norm), AZ-385 (only emit candidates when source_label == SATELLITE_ANCHORED), AZ-559 (`TileStore.put_mid_flight_candidate` Protocol method + `MidFlightTileCandidate` DTO + persistence — AZ-303 shipped under-spec, AZ-559 closes the gap), AZ-263, AZ-269, AZ-266, AZ-272 (FDR)
|
||||
**Status**: BLOCKED on AZ-559 (storage extension). Dependency-gap surfaced during batch 63 of the autodev replay-track sequence; original spec assumed AZ-303 had delivered the mid-flight tile API but it had not.
|
||||
**Dependencies**: AZ-384 (`current_estimate` body + cov norm), AZ-385 (only emit candidates when source_label == SATELLITE_ANCHORED), AZ-303 (`TileStore.write_tile` + `TileMetadata` + `TileQualityMetadata` + `TileSource.ONBOARD_INGEST`), AZ-263, AZ-269, AZ-266, AZ-272 (FDR)
|
||||
**Component**: c5_state (epic AZ-260 / E-C5)
|
||||
**Tracker**: AZ-389
|
||||
**Epic**: AZ-260 (E-C5)
|
||||
@@ -14,7 +13,11 @@
|
||||
|
||||
- `_docs/02_document/contracts/c5_state/state_estimator_protocol.md`.
|
||||
- `_docs/02_document/components/07_c5_state/description.md` — orthorectifier mention; § 1 downstream "C6 (mid-flight tile gen via orthorectifier)".
|
||||
- `_docs/02_document/contracts/c6_tile_cache/tile_store.md` — `put_mid_flight_candidate` API.
|
||||
- `_docs/02_document/contracts/c6_tile_cache/tile_store.md` — `write_tile` API (the four-method baseline).
|
||||
|
||||
### History
|
||||
|
||||
The original v1.0.0 spec referenced a separate `tile_store.put_mid_flight_candidate(MidFlightTileCandidate)` API that does not exist; investigation against `c6_tile_cache/_types.py` and `interface.py` showed `TileSource.ONBOARD_INGEST` + `TileMetadata.quality_metadata` + `write_tile`'s built-in `FreshnessRejectionError` semantic already cover the entire mid-flight ingest path. AZ-559 was filed and immediately closed Won't Fix; the spec is rewritten here against the actual API surface.
|
||||
|
||||
## Problem
|
||||
|
||||
@@ -24,15 +27,20 @@ Without this task, the system never emits mid-flight tile candidates → C6's ca
|
||||
|
||||
- `src/gps_denied_onboard/components/c5_state/_orthorectifier.py` defining:
|
||||
- `Orthorectifier` class (component-internal; not in `__all__`).
|
||||
- Method: `try_emit_candidate(frame, pose_estimate, cov_6x6, inlier_count, source_label) -> MidFlightTileCandidate | None`.
|
||||
- Method: `try_emit_candidate(frame, pose_estimate, cov_6x6, inlier_count, mre_px, source_label) -> TileId | None`.
|
||||
- Quality gates: `cov_norm < cov_threshold` AND `inlier_count > inlier_floor` AND `source_label == SATELLITE_ANCHORED`.
|
||||
- Orthorectification math: project nav-camera frame to tile plane via camera intrinsics + extrinsics + pose; nearest-neighbour or bilinear sampling.
|
||||
- JPEG encoding of the orthorectified patch (via OpenCV `cv2.imencode`).
|
||||
- Constructs a `TileMetadata` with `source = TileSource.ONBOARD_INGEST`, `voting_status = VotingStatus.PENDING`, `quality_metadata = TileQualityMetadata(estimator_label, covariance_2x2_horizontal_subblock, last_anchor_age_ms, mre_px, imu_bias_norm)`, `flight_id`, `companion_id`, `freshness_label = FreshnessLabel.FRESH` (the gate runs at insert time).
|
||||
- Calls `tile_store.write_tile(jpeg_bytes, tile_metadata)`.
|
||||
- Catches `FreshnessRejectionError` per AC-NEW-3 (opportunistic) and returns `None`; logs DEBUG `"c5.state.mid_flight_candidate_freshness_rejected"`.
|
||||
- Returns the persisted `TileId` on success.
|
||||
- Hook in `GtsamIsam2StateEstimator.current_estimate()` post-emission (or post-`add_pose_anchor` — implementer choice; gated to fire AT MOST once per frame).
|
||||
- ESKF estimator: also has the hook (mid-flight tile gen is independent of state-estimator strategy).
|
||||
- Configurable thresholds in `config.state.orthorectifier.{cov_norm_threshold, inlier_floor}`.
|
||||
- Defensive: skip emission silently if quality gates fail (NOT a degraded-mode error; tile gen is opportunistic per AC-NEW-3).
|
||||
- DEBUG log on every emission attempt; INFO log on first emission per flight.
|
||||
- Unit tests: known pose + frame → expected orthorectified output; quality-gate skip behaviour; emission rate-limit (once per frame).
|
||||
- Unit tests: known pose + frame → expected orthorectified output; quality-gate skip behaviour; emission rate-limit (once per frame); `FreshnessRejectionError` swallowed silently.
|
||||
|
||||
## Scope
|
||||
|
||||
@@ -44,7 +52,7 @@ Without this task, the system never emits mid-flight tile candidates → C6's ca
|
||||
- Unit tests.
|
||||
|
||||
### Excluded
|
||||
- The C6 `tile_store.put_mid_flight_candidate` body — owned by AZ-303 / E-C6.
|
||||
- Any new C6 API — the existing `write_tile` + `TileSource.ONBOARD_INGEST` + `TileMetadata` covers everything (closed AZ-559 confirms).
|
||||
- C6's downstream tile-cache eviction integration — owned by AZ-308.
|
||||
- The orthorectification kernel optimisation — production-acceptable kernel uses NumPy or OpenCV `cv2.warpPerspective`; CUDA optimisation is a feature-cycle improvement.
|
||||
|
||||
@@ -52,23 +60,25 @@ Without this task, the system never emits mid-flight tile candidates → C6's ca
|
||||
|
||||
**AC-1: Orthorectification correctness** — synthetic camera pose + planar tile → output pixels match expected projection within 1-pixel tolerance.
|
||||
|
||||
**AC-2: Quality gate skip** — `cov_norm > threshold` → no candidate emitted; DEBUG log only.
|
||||
**AC-2: Quality gate skip — covariance** — `cov_norm > threshold` → no tile written; DEBUG log only.
|
||||
|
||||
**AC-3: Source label gate** — `source_label != SATELLITE_ANCHORED` → no emission.
|
||||
|
||||
**AC-4: Once-per-frame rate limit** — even if `current_estimate` is called multiple times for the same frame, at most ONE candidate is emitted.
|
||||
**AC-4: Once-per-frame rate limit** — even if `current_estimate` is called multiple times for the same frame, at most ONE tile is written.
|
||||
|
||||
**AC-5: Both estimators participate** — iSAM2 + ESKF both attempt candidate emission.
|
||||
**AC-5: Both estimators participate** — iSAM2 + ESKF both attempt candidate emission via the same `Orthorectifier` instance (or an equivalent per-estimator instance — implementer choice).
|
||||
|
||||
**AC-6: Composition wiring** — the orthorectifier is constructed inside the estimator at `__init__` time; `tile_store` is constructor-injected.
|
||||
**AC-6: Composition wiring** — the orthorectifier is constructed inside the estimator at `__init__` time; `tile_store: TileStore` is constructor-injected.
|
||||
|
||||
**AC-7: First-emission INFO log** — `kind="c5.state.first_mid_flight_candidate"` with `{frame_id, tile_id, cov_norm}`.
|
||||
|
||||
**AC-8: Defensive skip on missing inputs** — if `frame` or `pose_estimate` is None, skip silently with DEBUG log (NOT an error).
|
||||
|
||||
**AC-9: Freshness rejection caught** — when `tile_store.write_tile` raises `FreshnessRejectionError`, the orthorectifier returns `None` and emits a DEBUG log; no exception propagates to `current_estimate`'s callers (replay protocol Invariant: opportunistic emission per AC-NEW-3).
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
- `try_emit_candidate` p95 ≤ 30 ms (orthorectification kernel cost).
|
||||
- `try_emit_candidate` p95 ≤ 30 ms (orthorectification kernel cost, including JPEG encode).
|
||||
- Memory ≤ 50 MB resident (frame buffer + working memory).
|
||||
|
||||
## Constraints
|
||||
@@ -76,14 +86,16 @@ Without this task, the system never emits mid-flight tile candidates → C6's ca
|
||||
- Component-internal (not in C5 `__all__`).
|
||||
- Once-per-frame rate limit.
|
||||
- Quality gates are mandatory; AC-NEW-3 gain is contingent on emitted candidates being high-quality.
|
||||
- The `TileQualityMetadata.covariance_2x2` field carries the **horizontal-position 2x2 sub-block** of the C5 pose covariance (not the full 6x6); the orthorectifier uses the full 6x6 for its OWN gate (`cov_norm < threshold`) but persists only the 2x2 sub-block in `TileQualityMetadata` per the existing schema.
|
||||
- `inlier_count` is NOT a field on `TileQualityMetadata`; the orthorectifier uses it for the gate but persists `mre_px` (mean reprojection error) which serves the same downstream consumer (C6 voting status updater).
|
||||
|
||||
## Risks & Mitigation
|
||||
|
||||
- **Risk: Orthorectification produces low-quality tiles under degenerate pose** — quality gates filter; if still problematic, AZ-308 cache-eviction policy filters at storage time.
|
||||
- **Risk: AZ-303 `put_mid_flight_candidate` API not yet stable** — this task ships against the documented API surface.
|
||||
- **Risk: `cov_norm` (Frobenius norm of 6x6) vs `covariance_2x2` (horizontal sub-block) mismatch confuses readers** — *Mitigation*: docstring on the orthorectifier explicitly distinguishes the two uses; the gate operates on the 6x6 norm; the sub-block is only persisted for downstream voting-status readers.
|
||||
|
||||
## Runtime Completeness
|
||||
|
||||
- **Named capability**: orthorectifier → mid-flight tile candidate emission.
|
||||
- **Production code**: real orthorectification kernel (NumPy or OpenCV), real quality gates, real tile_store.put_mid_flight_candidate call.
|
||||
- **Unacceptable substitutes**: emitting raw nav-frame pixels (not orthorectified); skipping the quality gates (AC-NEW-3 corruption).
|
||||
- **Named capability**: orthorectifier → mid-flight tile candidate emission via `TileStore.write_tile`.
|
||||
- **Production code**: real orthorectification kernel (NumPy or OpenCV), real quality gates, real `tile_store.write_tile` call against the production `PostgresFilesystemStore` in the airborne composition root.
|
||||
- **Unacceptable substitutes**: emitting raw nav-frame pixels (not orthorectified); skipping the quality gates (AC-NEW-3 corruption); inventing a parallel `put_mid_flight_candidate` path when `write_tile` already exists.
|
||||
|
||||
Reference in New Issue
Block a user