mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 23:51:12 +00:00
ba20c2d195
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>
5.1 KiB
5.1 KiB
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—SpscRingBufferwith 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__.pyre-exports the new public surface.src/gps_denied_onboard/config/schema.py—FdrConfiggainsper_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_clientwires the policy automatically; tests that constructFdrClient(...)directly opt out.
AZ-275 — FakeFdrSink
src/gps_denied_onboard/fdr_client/fakes.py—FakeFdrSinkwith full public-surface parity, plus the test-onlyrecords/all_records_everintrospection properties.tests/conftest.py— registers afake_fdr_sinkfixture and reuses the realdefault_overrun_policyvia a small_PolicyAdaptershim so behaviour parity is automatic.- Architecture lint (
test_production_does_not_import_fakes) AST-scanssrc/and fails on any import ofgps_denied_onboard.fdr_client.fakesfrom 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__.pyintentionally does NOT re-export the bridge to avoid a circular import (the bridge depends onfdr_client/clientwhich logs viaget_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.pywithpytest.mark.contract. Implements every row in thelog_record_schema § Test Casestable plus the "DEBUG+INFO never reach FDR" invariant against the bridge + fake.pyproject.tomlupdates:python_filesincludeslog_schema.py(contract-mandated file name),contractmarker registered.
Tests
- New: 48 tests across 4 unit files + 1 contract file
- Full suite: 251 passed, 2 skipped (
cmake/actionlintenv skips unchanged from batch 3) - Ruff:
check+formatclean 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:
- NFR-perf budgets (µs latencies) deferred to a follow-up
perf-instrumentation harness — a Cython/
cffibackend swap is pre-authorised by AZ-273 § Risk 1. - AZ-274 AC-2's strict coalescing semantic relaxed to per-event markers with marker-count folding; documented in the test.
_PolicyAdapterduck-typesFdrClientso the fake can reuse the production policy verbatim.- The policy reaches across
_buffer.push(module-private but cross-module-visible). Acceptable inside thefdr_clientpackage; 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.mdadvanced tosub_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.