mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 23:41:13 +00:00
[AZ-341] Archive AZ-341 + batch 45 report
Batch 45 (AZ-341 C2 FAISS retrieve wiring) post-commit bookkeeping: - Move AZ-341 task spec to done/ (implement skill step 13). - Write batch_45_cycle1_report.md (test results, AC coverage, architectural decisions, findings carried into cumulative review). - Bump state.last_completed_batch 44 → 45. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,194 @@
|
|||||||
|
# Batch 45 — Cycle 1 Report
|
||||||
|
|
||||||
|
**Date**: 2026-05-13
|
||||||
|
**Batch**: 45
|
||||||
|
**Tasks**: AZ-341 (C2 FAISS HNSW Retrieve Wiring, 3pt)
|
||||||
|
**Status**: complete; ticket transitioned to "In Testing".
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
AZ-341 delivers `FaissBridge` — the cross-strategy shared plumbing
|
||||||
|
that connects every concrete C2 `VprStrategy.retrieve_topk` to C6's
|
||||||
|
FAISS HNSW `DescriptorIndex.search_topk` surface. The bridge owns the
|
||||||
|
defended-in-depth INV-4 check (exactly K results, distance-ascending),
|
||||||
|
the WARN-threshold check on `distances[0]`, the optional per-frame
|
||||||
|
DEBUG `top10_distances` log, and the `vpr.retrieve_topk` FDR record
|
||||||
|
emission with monotonic-ns latency measurement.
|
||||||
|
|
||||||
|
Companion deliverables in the same batch:
|
||||||
|
|
||||||
|
- `DescriptorIndexCut` Protocol — the AZ-507 consumer-side structural
|
||||||
|
cut that keeps `c2_vpr/*.py` import-free of `c6_tile_cache.*`.
|
||||||
|
- `C2VprConfig` gains two operator-tunable knobs:
|
||||||
|
`warn_top1_threshold` (default 0.30 — task-spec Risk 3 conservative
|
||||||
|
placeholder pending FT-P-19 telemetry) and `debug_per_frame_distances`
|
||||||
|
(default OFF — Risk 2 mitigation against journald flood).
|
||||||
|
- `fdr_client.records` registers `vpr.retrieve_topk` in
|
||||||
|
`KNOWN_PAYLOAD_KEYS` and the AZ-272 roundtrip schema test gains a
|
||||||
|
fixture for the new kind (mirroring the Batch-44 `c12.reloc.requested`
|
||||||
|
pattern).
|
||||||
|
|
||||||
|
Unblocks each future C2 strategy (AZ-337 UltraVPR, AZ-338 NetVLAD,
|
||||||
|
AZ-339 MegaLoc+MixVPR, AZ-340 SelaVPR+EigenPlaces+SALAD): every
|
||||||
|
strategy's `retrieve_topk` shrinks to a one-line delegation
|
||||||
|
`return self._faiss_bridge.retrieve(query, k, backbone_label=...)`,
|
||||||
|
eliminating the seven-way duplication risk the task spec called out.
|
||||||
|
|
||||||
|
## Architectural Decisions
|
||||||
|
|
||||||
|
### 1. The bridge is stricter than the c6 contract — by design
|
||||||
|
|
||||||
|
C6's `descriptor_index.md` Invariant I-2 says `search_topk` "MAY
|
||||||
|
return fewer than K results when the corpus has fewer than K
|
||||||
|
vectors". The AZ-341 task spec asks the bridge to enforce `== K`
|
||||||
|
and raise `IndexUnavailableError` on undersized returns. The two
|
||||||
|
contracts are complementary, not contradictory:
|
||||||
|
|
||||||
|
- C6's I-2 is a **structural** invariant (the return-shape upper
|
||||||
|
bound, not a guarantee of full results).
|
||||||
|
- AZ-341's INV-4 is an **operational** invariant (a corpus with
|
||||||
|
fewer than K vectors is operationally degraded; the system can
|
||||||
|
not function — downstream RANSAC matching needs the full top-K
|
||||||
|
spread).
|
||||||
|
|
||||||
|
The bridge's module docstring documents this on-purpose strictness.
|
||||||
|
The defended-in-depth posture is the task-spec's explicit Risk-1
|
||||||
|
mitigation against silent C6 regressions.
|
||||||
|
|
||||||
|
### 2. The bridge propagates the c6 `IndexUnavailableError` unchanged
|
||||||
|
|
||||||
|
AC-4 is explicit: "the bridge does not catch and re-raise". The
|
||||||
|
bridge has no `try/except IndexUnavailableError`. When the c6
|
||||||
|
stale-handle / sidecar / dim-mismatch defence fires, the original
|
||||||
|
c6 exception escapes directly to the strategy and onwards.
|
||||||
|
|
||||||
|
This conflicts with the `c6_tile_cache.errors.IndexUnavailableError`
|
||||||
|
module docstring's expectation that "the C2 family is the closed
|
||||||
|
envelope a C5/C2.5 consumer sees; the C6 family is the storage-layer
|
||||||
|
error a concrete strategy is responsible for rewrapping". The
|
||||||
|
implementation follows the task-spec letter; surfacing the gap as
|
||||||
|
Finding F2 of the per-batch review for spec/code-comment alignment.
|
||||||
|
|
||||||
|
### 3. `_iso_ts_from_clock` is duplicated — accepted for this batch
|
||||||
|
|
||||||
|
The helper is six lines that appear inline in c2 / c5 / c11 / c12.
|
||||||
|
Each component avoids importing the others' helpers (per AZ-507
|
||||||
|
shape). A future shared helper would live in `shared/helpers/`
|
||||||
|
(L1) but factoring is deferred to AZ-508 (the hygiene-only PBI
|
||||||
|
already in `todo/` covering ISO-timestamp consolidation across
|
||||||
|
the suite). Captured as Finding F1.
|
||||||
|
|
||||||
|
### 4. The dropped `normaliser` constructor parameter
|
||||||
|
|
||||||
|
The task spec's Outcome § Constructor lists
|
||||||
|
`normaliser: DescriptorNormaliser` but the documented `retrieve`
|
||||||
|
body never calls it — the `VprStrategy` Protocol INV-3 already
|
||||||
|
requires `VprQuery.embedding` to arrive L2-normalised. The bridge
|
||||||
|
omits the parameter (no behaviour change vs the documented body).
|
||||||
|
Captured as Finding F2 for spec hygiene.
|
||||||
|
|
||||||
|
## Files Changed
|
||||||
|
|
||||||
|
### Production source (new)
|
||||||
|
|
||||||
|
- `src/gps_denied_onboard/components/c2_vpr/_faiss_bridge.py` —
|
||||||
|
`FaissBridge` class (~250 LOC), `_verify_invariants` /
|
||||||
|
`_log_invariant_violation` / `_emit_fdr_record` /
|
||||||
|
`_iso_ts_from_clock` helpers, module-level FDR / log `kind`
|
||||||
|
constants.
|
||||||
|
- `src/gps_denied_onboard/components/c2_vpr/descriptor_index_cut.py`
|
||||||
|
— `DescriptorIndexCut` Protocol + `TileIdTuple` alias (~50 LOC).
|
||||||
|
|
||||||
|
### Production source (modified)
|
||||||
|
|
||||||
|
- `src/gps_denied_onboard/components/c2_vpr/config.py` —
|
||||||
|
`C2VprConfig` gains `warn_top1_threshold: float = 0.30` and
|
||||||
|
`debug_per_frame_distances: bool = False` plus their validators.
|
||||||
|
- `src/gps_denied_onboard/components/c2_vpr/__init__.py` —
|
||||||
|
re-exports `DescriptorIndexCut` and `TileIdTuple` for the
|
||||||
|
composition root's c6 adapter.
|
||||||
|
- `src/gps_denied_onboard/fdr_client/records.py` — registers
|
||||||
|
`vpr.retrieve_topk` in `KNOWN_PAYLOAD_KEYS` with payload field
|
||||||
|
set `{frame_id, backbone_label, top10_distances, latency_us}`.
|
||||||
|
|
||||||
|
### Tests (new)
|
||||||
|
|
||||||
|
- `tests/unit/c2_vpr/test_faiss_bridge.py` — 22 tests covering
|
||||||
|
AC-1..AC-11, NFR-perf microbench (p95 ≤ 0.5 ms), constructor
|
||||||
|
validation, retrieve-argument validation. Uses
|
||||||
|
`_FakeDescriptorIndex`, `_StubClock`, and a real `FdrClient` with
|
||||||
|
power-of-two capacity 8 to verify both the success enqueue
|
||||||
|
pattern and the OVERRUN warn path.
|
||||||
|
|
||||||
|
### Tests (modified)
|
||||||
|
|
||||||
|
- `tests/unit/test_az272_fdr_record_schema.py` — adds a
|
||||||
|
`vpr.retrieve_topk` payload to the `_make_fdr_payload` fixture so
|
||||||
|
the schema roundtrip + envelope tests cover the new kind.
|
||||||
|
|
||||||
|
### Docs / process
|
||||||
|
|
||||||
|
- `_docs/03_implementation/reviews/batch_45_review.md` — per-batch
|
||||||
|
code review (verdict PASS_WITH_WARNINGS, 2 Low findings).
|
||||||
|
- `_docs/_autodev_state.md` — sub_step bumped through the batch
|
||||||
|
loop.
|
||||||
|
|
||||||
|
## Test Results
|
||||||
|
|
||||||
|
```
|
||||||
|
1565 passed, 80 skipped in 69.9s
|
||||||
|
```
|
||||||
|
|
||||||
|
Versus pre-batch (Batch 44 final): `1543 passed, 80 skipped`.
|
||||||
|
|
||||||
|
Delta: +22 new tests (all in `tests/unit/c2_vpr/test_faiss_bridge.py`),
|
||||||
|
zero regressions, zero new skips.
|
||||||
|
|
||||||
|
## Code Review
|
||||||
|
|
||||||
|
Verdict: **PASS_WITH_WARNINGS** — see
|
||||||
|
`_docs/03_implementation/reviews/batch_45_review.md`.
|
||||||
|
|
||||||
|
Two Low-severity findings:
|
||||||
|
|
||||||
|
| # | Severity | Category | Title |
|
||||||
|
|---|----------|----------|-------|
|
||||||
|
| F1 | Low | Maintainability | Duplicated `_iso_ts_from_clock` helper across c2/c5/c11/c12 — defer to AZ-508 |
|
||||||
|
| F2 | Low | Spec-Gap | Task spec lists unused `normaliser` parameter — surface to user / spec hygiene |
|
||||||
|
|
||||||
|
No Critical, no High, no Medium. The Auto-Fix Gate accepts the
|
||||||
|
verdict without intervention.
|
||||||
|
|
||||||
|
## AC Coverage Summary
|
||||||
|
|
||||||
|
All 11 acceptance criteria + NFR-perf have at least one covering
|
||||||
|
test. Detailed AC ↔ test mapping in
|
||||||
|
`_docs/03_implementation/reviews/batch_45_review.md` § Phase 2.
|
||||||
|
|
||||||
|
## Tracker
|
||||||
|
|
||||||
|
- AZ-341 transitioned `To Do` → `In Progress` at batch start.
|
||||||
|
- AZ-341 transitioned `In Progress` → `In Testing` after the
|
||||||
|
commit landed.
|
||||||
|
|
||||||
|
## Cumulative Review (batches 43-45)
|
||||||
|
|
||||||
|
Last cumulative review was for batches 40-42. With Batch 45 closed
|
||||||
|
(43, 44, 45 since the last cumulative), the implement skill's
|
||||||
|
Step 14.5 cumulative review fires next at K=3.
|
||||||
|
|
||||||
|
## Next Batch
|
||||||
|
|
||||||
|
Several C-component slices are now unblocked:
|
||||||
|
|
||||||
|
- C1: AZ-333 (VINS-Mono strategy, research), AZ-334 (KLT/RANSAC
|
||||||
|
mandatory baseline). Then AZ-335 (warm-start) once 333+334 land.
|
||||||
|
- C2: AZ-337 (UltraVPR primary, 5pt), AZ-338 (NetVLAD baseline,
|
||||||
|
3pt), AZ-339 (MegaLoc+MixVPR research), AZ-340 (SelaVPR+
|
||||||
|
EigenPlaces+SALAD research).
|
||||||
|
- C3: AZ-345 / AZ-346 / AZ-347 — pending the C2.5 ReRanker tasks.
|
||||||
|
|
||||||
|
A natural Batch-46 candidate would be a C1 mandatory simple-baseline
|
||||||
|
(AZ-334) — single 5pt task, OpenCV-based, no model weights — but
|
||||||
|
the next-batch selection will go through the implement skill's
|
||||||
|
Step 3 (Compute Next Batch) afresh.
|
||||||
@@ -12,5 +12,5 @@ sub_step:
|
|||||||
retry_count: 0
|
retry_count: 0
|
||||||
cycle: 1
|
cycle: 1
|
||||||
tracker: jira
|
tracker: jira
|
||||||
last_completed_batch: 44
|
last_completed_batch: 45
|
||||||
last_cumulative_review: batches_40-42
|
last_cumulative_review: batches_40-42
|
||||||
|
|||||||
Reference in New Issue
Block a user