mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 06:31:12 +00:00
[AZ-273] [AZ-274] [AZ-275] [AZ-267] [AZ-268] FDR producer chain + log bridge + contract test
AZ-273: lock-free SPSC ring buffer with pre-allocated slots, power-of- two capacity, opt-in SPSC guard, and EnqueueResult / FdrSpscViolationError on the public surface. make_fdr_client caches one client per producer_id and reads capacity from config.fdr.per_producer_capacity with fallback to queue_size. AZ-274: default_overrun_policy implements drop-oldest + retry + immediate marker emission, with prior-marker dropped_count folding via _evict_one so user-loss info is never lost across iterations. ERROR diagnostic is rate-limited to <=1/sec per producer. AZ-275: FakeFdrSink mirrors the FdrClient public surface and reuses the production default_overrun_policy via a duck-typed _PolicyAdapter. The test-only records/all_records_ever properties let component tests assert both in-buffer and lifetime state. tests/conftest.py registers the fake_fdr_sink fixture and an AST architecture lint forbids production imports of fakes. AZ-267: FdrLogBridgeHandler installs on the root logger via wire_log_bridge and forwards only WARN+ERROR records into the FDR with kind="log". Thread-local recursion guard short-circuits internal logging; saturated- queue diagnostics go to stderr every N=1000 drops. AZ-268: tests/contract/log_schema.py covers every row of the schema's Test Cases table plus the "DEBUG+INFO never reach FDR" invariant. pyproject.toml registers the contract pytest marker and the contract-mandated log_schema.py file-name. 251 unit + contract tests pass (48 new). Review verdict: PASS_WITH_WARNINGS; findings are NFR-perf deferrals + documented relaxation of AZ-274 AC-2 coalescing under permanently-stalled consumer. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# Batch 04 — Cycle 1 Implementation Report
|
||||
|
||||
**Date**: 2026-05-11
|
||||
**Batch shape**: FDR producer-side chain + log bridge + contract test
|
||||
**Tasks**: AZ-273, AZ-274, AZ-275, AZ-267, AZ-268 (13 complexity points)
|
||||
**Verdict**: PASS_WITH_WARNINGS (see `reviews/batch_04_review.md`)
|
||||
|
||||
## What landed
|
||||
|
||||
### AZ-273 — FdrClient + lock-free SPSC ring buffer
|
||||
|
||||
- `src/gps_denied_onboard/fdr_client/queue.py` — `SpscRingBuffer` with
|
||||
pre-allocated slots, power-of-two capacity, bitwise-AND modular
|
||||
index math, and an opt-in (`enforce_spsc=True`) SPSC guard.
|
||||
- `src/gps_denied_onboard/fdr_client/client.py` — `FdrClient`,
|
||||
`EnqueueResult`, `FdrSpscViolationError`, `make_fdr_client(producer_id, config)`
|
||||
factory + module-level cache + `_reset_for_tests()`.
|
||||
- `src/gps_denied_onboard/fdr_client/__init__.py` re-exports the new
|
||||
public surface.
|
||||
- `src/gps_denied_onboard/config/schema.py` — `FdrConfig` gains
|
||||
`per_producer_capacity: Mapping[str, int]` (additive; non-breaking).
|
||||
|
||||
### AZ-274 — Drop-oldest + `kind="overrun"` emission
|
||||
|
||||
- `src/gps_denied_onboard/fdr_client/overrun_policy.py` —
|
||||
`default_overrun_policy(client)` returns the canonical closure.
|
||||
Implements drop-oldest + retry + immediate marker emission with
|
||||
prior-marker count folding (no user-loss information ever lost).
|
||||
Diagnostic ERROR log is rate-limited to ≤ 1/sec per producer.
|
||||
- `make_fdr_client` wires the policy automatically; tests that
|
||||
construct `FdrClient(...)` directly opt out.
|
||||
|
||||
### AZ-275 — FakeFdrSink
|
||||
|
||||
- `src/gps_denied_onboard/fdr_client/fakes.py` — `FakeFdrSink` with
|
||||
full public-surface parity, plus the test-only
|
||||
`records` / `all_records_ever` introspection properties.
|
||||
- `tests/conftest.py` — registers a `fake_fdr_sink` fixture and
|
||||
reuses the real `default_overrun_policy` via a small
|
||||
`_PolicyAdapter` shim so behaviour parity is automatic.
|
||||
- Architecture lint (`test_production_does_not_import_fakes`)
|
||||
AST-scans `src/` and fails on any import of
|
||||
`gps_denied_onboard.fdr_client.fakes` from production code.
|
||||
|
||||
### AZ-267 — FDR log bridge
|
||||
|
||||
- `src/gps_denied_onboard/logging/fdr_bridge.py` —
|
||||
`FdrLogBridgeHandler` + `wire_log_bridge(resolver)`. Subscribes
|
||||
to WARN+ERROR only (level filter); INFO+DEBUG never reach the
|
||||
handler. Thread-local recursion guard short-circuits any logging
|
||||
call originating from inside the bridge itself. Saturated-queue
|
||||
diagnostic goes to stderr (not the logger) every N=1000 drops.
|
||||
- `logging/__init__.py` intentionally does NOT re-export the bridge
|
||||
to avoid a circular import (the bridge depends on `fdr_client/client`
|
||||
which logs via `get_logger`); composition-root callers import the
|
||||
bridge via its full path.
|
||||
|
||||
### AZ-268 — Log schema contract test
|
||||
|
||||
- `tests/contract/__init__.py` + `tests/contract/log_schema.py`
|
||||
with `pytest.mark.contract`. Implements every row in the
|
||||
`log_record_schema § Test Cases` table plus the
|
||||
"DEBUG+INFO never reach FDR" invariant against the bridge + fake.
|
||||
- `pyproject.toml` updates: `python_files` includes `log_schema.py`
|
||||
(contract-mandated file name), `contract` marker registered.
|
||||
|
||||
## Tests
|
||||
|
||||
- New: 48 tests across 4 unit files + 1 contract file
|
||||
- Full suite: **251 passed, 2 skipped** (`cmake`/`actionlint` env
|
||||
skips unchanged from batch 3)
|
||||
- Ruff: `check` + `format` clean on all touched files
|
||||
- ReadLints: clean on all touched files
|
||||
|
||||
## AC coverage matrix
|
||||
|
||||
See `reviews/batch_04_review.md § Phase 2` for the full per-AC
|
||||
status table. Summary: 28 of 28 behavioural ACs pass directly;
|
||||
AZ-273 AC-2 (allocation-free) and AZ-274 AC-2 (exact coalescing)
|
||||
are deferred / relaxed and documented in the review report.
|
||||
|
||||
## Code review verdict
|
||||
|
||||
**PASS_WITH_WARNINGS** with four LOW-severity informational findings:
|
||||
|
||||
1. NFR-perf budgets (µs latencies) deferred to a follow-up
|
||||
perf-instrumentation harness — a Cython/`cffi` backend swap is
|
||||
pre-authorised by AZ-273 § Risk 1.
|
||||
2. AZ-274 AC-2's strict coalescing semantic relaxed to per-event
|
||||
markers with marker-count folding; documented in the test.
|
||||
3. `_PolicyAdapter` duck-types `FdrClient` so the fake can reuse
|
||||
the production policy verbatim.
|
||||
4. The policy reaches across `_buffer.push` (module-private but
|
||||
cross-module-visible). Acceptable inside the
|
||||
`fdr_client` package; documented in the policy module docstring.
|
||||
|
||||
## Dependency changes
|
||||
|
||||
None. No new pip dependencies; `FdrConfig.per_producer_capacity` is
|
||||
the only schema addition and is non-breaking.
|
||||
|
||||
## State
|
||||
|
||||
- 5 specs archived to `_docs/02_tasks/done/`
|
||||
- 5 Jira tickets transitioned: To Do → In Progress → In Testing
|
||||
- State file `_docs/_autodev_state.md` advanced to
|
||||
`sub_step: {phase: 14, name: loop-next-batch, detail: "batch 4 of N committed"}`
|
||||
|
||||
## What unblocks next
|
||||
|
||||
Component tasks that previously waited on the FDR client surface can
|
||||
now begin. Notably:
|
||||
|
||||
- **AZ-271** (config precedence tests) — needs AZ-269 + AZ-270, both done.
|
||||
- **AZ-276 / AZ-278 / AZ-282** — Layer-1 helpers (`ImuPreintegrator`,
|
||||
`LightGlueRuntime`, `RansacFilter`) — none of these gate on FDR.
|
||||
- **C7 inference / C11 tile manager / C6 tile cache** — first
|
||||
component openers; each can start its strategy-protocol task now
|
||||
that the FDR client + log bridge are live.
|
||||
Reference in New Issue
Block a user