[AZ-266] [AZ-269] [AZ-277] [AZ-280] Cross-cutting log/config + SE3/SHA256 helpers

AZ-266: schema-compliant JSON logging entrypoint, level normalisation,
handler-topology guard, format-error fallback (log_record_schema v1.0.0).
AZ-269: env > YAML > defaults config loader, frozen Config dataclass,
missing-var fail-fast with pointer to .env.example, component-block registry.
AZ-277: GTSAM-backed SE3Utils (matrix<->SE3 + exp/log/adjoint) with strict
orthogonality, dtype, and bottom-row contract enforcement.
AZ-280: atomicwrites-backed write_atomic + independent verify +
order-deterministic aggregate_hash; sidecar format strictness.
pyproject.toml pins gtsam>=4.2,<5.0 and atomicwrites>=1.4,<2.0
(named-backend deps per the AZ-277 / AZ-280 contracts).
139 unit tests pass (44 new). Review verdict: PASS_WITH_WARNINGS;
findings are perf-NFR + journald deferrals, no blocking issues.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-11 01:33:42 +03:00
parent b12db61444
commit 8e71f6c002
21 changed files with 2134 additions and 133 deletions
@@ -0,0 +1,109 @@
# Batch Report — Cycle 1 · Batch 2
**Tasks shipped**: AZ-266, AZ-269, AZ-277, AZ-280
**Date**: 2026-05-11
**Branch**: dev
**Review verdict**: PASS_WITH_WARNINGS — see `reviews/batch_02_review.md`
## Tasks
| ID | Title | Owner Layer | Outcome |
|----|-------|-------------|---------|
| AZ-266 | Shared Logging Module | cross-cutting / `logging/` | Implemented — schema-compliant JSON formatter, level normalisation, handler topology guard, format-error fallback |
| AZ-269 | Config Loader | cross-cutting / `config/` | Implemented — env > YAML > defaults precedence, frozen `Config`, missing-var fail-fast with pointer, component-block registry |
| AZ-277 | SE3Utils Helper | Layer 1 / `helpers/se3_utils.py` | Implemented — GTSAM-backed `matrix_to_se3` / `se3_to_matrix` / `exp_map` / `log_map` / `adjoint` with strict orthogonality + dtype contract |
| AZ-280 | Sha256Sidecar Helper | Layer 1 / `helpers/sha256_sidecar.py` | Implemented — `atomicwrites`-backed `write_atomic` + independent `verify` + order-deterministic `aggregate_hash` |
## Files Changed
```
Modified:
pyproject.toml (+4 lines : gtsam, atomicwrites pins)
src/gps_denied_onboard/config/__init__.py (re-exports)
src/gps_denied_onboard/config/loader.py (load_config impl)
src/gps_denied_onboard/config/schema.py (frozen dataclasses + component registry)
src/gps_denied_onboard/helpers/__init__.py (re-exports)
src/gps_denied_onboard/helpers/se3_utils.py (SE3 primitives)
src/gps_denied_onboard/helpers/sha256_sidecar.py (atomic write + sidecar verify)
src/gps_denied_onboard/logging/__init__.py (re-exports)
src/gps_denied_onboard/logging/structured.py (schema-compliant formatter)
tests/unit/test_logging_smoke.py (updated to nested kv schema)
Added:
tests/unit/test_az266_logging_schema.py
tests/unit/test_az269_config_loader.py
tests/unit/test_az277_se3_utils.py
tests/unit/test_az280_sha256_sidecar.py
_docs/03_implementation/reviews/batch_02_review.md
```
## Test Results
```
$ pytest tests/unit -q --timeout=30
139 passed, 2 skipped in 5.27s
```
Skips are environment-gated (cmake configure step, actionlint), both
verified in CI.
### AC Coverage
| Task | ACs declared | ACs covered locally | Tier-2 deferred |
|------|--------------|---------------------|-----------------|
| AZ-266 | 5 + 2 NFR | 5 ACs + NFR-reliability | NFR-perf (p99 ≤ 0.2 ms on Jetson) |
| AZ-269 | 6 + 2 NFR | 6 ACs + NFR-reliability | NFR-perf (cold load ≤ 250 ms on Jetson) |
| AZ-277 | 9 + 2 NFR | 9 ACs + NFR-* via determinism + AST scan | none |
| AZ-280 | 9 + 2 NFR | 9 ACs + NFR-perf-spot-check + NFR-reliability | none |
Tier-2 perf budgets need hardware to verify against; the unit suite
does not synthesise a Jetson budget locally. AZ-428..AZ-431 own the
Tier-2 perf scenarios; the batch-2 modules are wired so those tasks
plug in without further code changes here.
## Dependency Pins
This batch amended `pyproject.toml` with two new runtime pins required
by AZ-277 and AZ-280 contracts:
- `gtsam>=4.2,<5.0` — SE(3) backend per AZ-277 contract
- `atomicwrites>=1.4,<2.0` — atomic-replace backend per AZ-280 contract
Both names appear verbatim in the upstream contract documents and were
the named-backend constraint, not an arbitrary choice. AZ-263
intentionally left these unpinned; the pins are added by the first
batch that needs them.
## Architecture Compliance
- `helpers/se3_utils.py` and `helpers/sha256_sidecar.py` import only
stdlib + named externals (numpy / gtsam / atomicwrites). No
`gps_denied_onboard.components.*` imports — enforced by AST scan in
both helper test files.
- `logging/structured.py` imports stdlib only (optional `systemd-python`
inside the Tier-2 handler factory, lazy).
- `config/loader.py` imports stdlib + `pyyaml`. The `register_component_block`
function is the only authorised path for a component to contribute a
config block, satisfying AZ-269 § Risks Mitigation Risk 1.
No new circular imports. Verified by running the test suite (any cycle
would fail collection).
## Review Findings Summary
Verdict: **PASS_WITH_WARNINGS**. Four Low-severity findings:
1. AC-2 test pivots on `fdr.queue_size` rather than `log.level` — clean
test design choice given `LOG_LEVEL` is required-env.
2. NFR-perf microbenchmarks deferred to Tier-2 perf suite.
3. Tier-2 journald handler unverified on macOS dev; runs in Jetson CI.
4. `pyproject.toml` dep amendment — by the consumer batch as designed.
Full details in `reviews/batch_02_review.md`.
## Tracker Transitions
- AZ-266: To Do → In Progress → (batch close) In Testing
- AZ-269: To Do → In Progress → (batch close) In Testing
- AZ-277: To Do → In Progress → (batch close) In Testing
- AZ-280: To Do → In Progress → (batch close) In Testing