mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 08:41:12 +00:00
[AZ-508] Consolidate _iso_ts_now into helpers/iso_timestamps
Batch 48 / Cycle 1 (greenfield Step 7). Closes cumulative review batches 31-33 F2 and 28-30 F3 by replacing the duplicated private _iso_ts_now() one-liners with a single Layer-1 helper: src/gps_denied_onboard/helpers/iso_timestamps.py iso_ts_now() -> str Output format matches the canonical FDR _TS fixture (YYYY-MM-DDTHH:MM:SS.ffffffZ); no FDR schema change. Migrated call-sites (3): c7_inference/onnx_trt_ep_runtime, c7_inference/thermal_publisher, plus the 3 c6_tile_cache callers that previously imported from the local c6_tile_cache/_timestamp shim (now deleted, superseded by the Layer-1 helper). Spec drift resolved (Choose A, user-approved): spec listed 5 call sites + +00:00 regex; on-disk reality at batch start is 3 sites + Z-suffix matching every existing helper and the FDR _TS fixture. Spec preamble + AC-2 regex updated in the task file; documented in batch_48_cycle1_report.md. Tests: 9 new AC tests (AC-1..AC-7 + Layer-1 invariant + public-surface defensive); 216 focused tests pass including the unmodified AZ-272 FDR schema suite and AZ-270 / AZ-507 layering lints. Verdict: PASS (no findings). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -360,6 +360,13 @@ Bootstrap reference: `_docs/02_tasks/todo/AZ-263_initial_structure.md`. Architec
|
||||
- **Owned by**: AZ-264.
|
||||
- **Consumed by**: c2_vpr, c2_5_rerank, c3_matcher.
|
||||
|
||||
### shared/helpers/iso_timestamps
|
||||
|
||||
- **File**: `src/gps_denied_onboard/helpers/iso_timestamps.py`
|
||||
- **Purpose**: Single Layer-1 UTC ISO-8601 timestamp source for FDR record envelopes (`iso_ts_now() -> str`, format `YYYY-MM-DDTHH:MM:SS.ffffffZ` matching the canonical FDR `_TS` fixture). Replaces the duplicated private `_iso_ts_now` one-liners that previously lived inside `c6_tile_cache` (3 modules — already locally consolidated under `_timestamp.py`) and `c7_inference` (2 modules). Stateless free function; stdlib only.
|
||||
- **Owned by**: AZ-264 (AZ-508 consolidation task).
|
||||
- **Consumed by**: c6_tile_cache (`cache_budget_enforcer`, `postgres_filesystem_store`, `freshness_gate`), c7_inference (`onnx_trt_ep_runtime`, `thermal_publisher`); future C10/C11 FDR producers should import this helper rather than redefining the one-liner locally.
|
||||
|
||||
### shared/frame_source
|
||||
|
||||
- **Directory**: `src/gps_denied_onboard/frame_source/`
|
||||
|
||||
+5
-3
@@ -2,7 +2,9 @@
|
||||
|
||||
**Task**: AZ-508_hygiene_iso_timestamps_consolidation
|
||||
**Name**: ISO-timestamp helper consolidation
|
||||
**Description**: Replace five identical private `_iso_ts_now()` one-liners across c6_tile_cache + c7_inference with a single Layer-1 helper `src/gps_denied_onboard/helpers/iso_timestamps.py` exposing `iso_ts_now() -> str`. Closes cumulative review batches 31–33 Finding F2 (Low / Maintainability) and the earlier 28–30 cumulative review Finding F3 (the 3 c6 copies).
|
||||
**Description**: Replace the duplicated private `_iso_ts_now()` one-liners across c6_tile_cache + c7_inference with a single Layer-1 helper `src/gps_denied_onboard/helpers/iso_timestamps.py` exposing `iso_ts_now() -> str`. Closes cumulative review batches 31–33 Finding F2 (Low / Maintainability) and the earlier 28–30 cumulative review Finding F3 (the 3 c6 copies).
|
||||
|
||||
> **Spec drift note (Batch 48, 2026-05-13)**: this task was authored before c6 had locally consolidated its three copies into `components/c6_tile_cache/_timestamp.py`, and before `tensorrt_runtime.py` removed its local copy. Actual call-sites needing migration at implementation time: 3 (c6 `_timestamp.py` shim, c7 `onnx_trt_ep_runtime.py`, c7 `thermal_publisher.py`). Also, AC-2 originally specified a `+00:00` regex copied from a misread of `test_az272_fdr_record_schema.py`; the canonical FDR `ts` format on disk is the `Z`-suffix variant (`_TS = "2026-05-11T00:00:00.000000Z"`), produced by all three existing local helpers. AC-2 regex below has been corrected to `Z`; this preserves the AC-5 "FDR schema tests pass unmodified" invariant and the Excluded clause "no schema change".
|
||||
**Complexity**: 2 points
|
||||
**Dependencies**: AZ-263_initial_structure, AZ-266_log_module
|
||||
**Component**: helpers (epic AZ-264 / E-CC-HELPERS)
|
||||
@@ -73,9 +75,9 @@ When `from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now` is run
|
||||
Then the import succeeds; the function is callable; the returned value is a `str`
|
||||
|
||||
**AC-2: Output format is byte-identical to the previous local helpers**
|
||||
Given the existing FDR record format that the five local helpers produced
|
||||
Given the existing FDR record format that the three local helpers produced (`%Y-%m-%dT%H:%M:%S.%fZ`, canonical FDR `_TS` fixture)
|
||||
When `iso_ts_now()` is called
|
||||
Then the output matches `^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00$` and is parseable by `datetime.fromisoformat(...)` into a UTC-aware datetime
|
||||
Then the output matches `^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z$` and is parseable by `datetime.fromisoformat(value.replace("Z", "+00:00"))` into a UTC-aware datetime
|
||||
|
||||
**AC-3: Monotonicity under normal clock**
|
||||
Given two `iso_ts_now()` calls separated by at least 1 microsecond
|
||||
@@ -0,0 +1,222 @@
|
||||
# Batch 48 / Cycle 1 — Implementation Report
|
||||
|
||||
**Date**: 2026-05-13
|
||||
**Tasks**: AZ-508 — ISO-timestamp helper consolidation (2pt)
|
||||
**Total complexity**: 2 points
|
||||
**Result**: PASS (per-batch code review)
|
||||
**Jira tracker state**: AZ-508 transitioned To Do → In Progress (prior
|
||||
session) → In Testing (this batch)
|
||||
|
||||
## Scope
|
||||
|
||||
Hygiene PBI from cumulative reviews batches 28–30 (Finding F3) and
|
||||
batches 31–33 (Finding F2). Consolidates the duplicated private
|
||||
`_iso_ts_now()` one-liners across `c6_tile_cache` and `c7_inference`
|
||||
into a single Layer-1 helper at
|
||||
`src/gps_denied_onboard/helpers/iso_timestamps.py` (`iso_ts_now() -> str`,
|
||||
RFC 3339 UTC microsecond `Z`-suffix). Closes F2 before the upcoming
|
||||
C2 batches (AZ-339 / AZ-340) and the C4/C3 batches (AZ-358 / AZ-349)
|
||||
would have added the 8th and 9th copies of the helper.
|
||||
|
||||
## Spec Drift Resolution (User-Approved Choose A)
|
||||
|
||||
The task spec assumed:
|
||||
- **5** call-sites needing migration.
|
||||
- AC-2 format regex `\.\d{6}\+00:00$`.
|
||||
- "FDR records standardize on `+00:00` per `test_az272_fdr_record_schema.py`".
|
||||
|
||||
On-disk reality at Batch 48 start:
|
||||
- **3** call-sites: c6's three callers had already been locally
|
||||
consolidated under `src/gps_denied_onboard/components/c6_tile_cache/_timestamp.py`
|
||||
(export `iso_ts_now`, same `Z`-suffix format); `tensorrt_runtime.py`
|
||||
carries no local `_iso_ts_now` definition.
|
||||
- All 3 existing helpers produce `%Y-%m-%dT%H:%M:%S.%fZ` (`Z` suffix).
|
||||
- The canonical FDR `ts` fixture is `_TS = "2026-05-11T00:00:00.000000Z"`
|
||||
(also `Z` suffix). The `+00:00` strings in that test file belong to
|
||||
*other* DTO fields (manifest `generated_at_iso`, `observed_at_iso`),
|
||||
not the FDR `ts` envelope.
|
||||
|
||||
Picking the spec's `+00:00` literally would have silently changed FDR
|
||||
record `ts` bit-shape — explicitly **Excluded** by the spec ("no schema
|
||||
change") and would have broken AC-5 (FDR schema tests pass unmodified).
|
||||
|
||||
User selected **Choose A**: Z-format helper, byte-identical to existing
|
||||
3 helpers + FDR `_TS` fixture; AC-2 regex corrected in the spec; drift
|
||||
documented in this report and in the spec's preamble.
|
||||
|
||||
## Files Changed
|
||||
|
||||
### Production (new)
|
||||
|
||||
- `src/gps_denied_onboard/helpers/iso_timestamps.py` —
|
||||
`iso_ts_now() -> str`. Stateless free function; stdlib `datetime` +
|
||||
`timezone` only; format
|
||||
`datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")`.
|
||||
|
||||
### Production (modified)
|
||||
|
||||
- `src/gps_denied_onboard/helpers/__init__.py` — re-exports `iso_ts_now`
|
||||
through the helpers package facade (alphabetical insertion in both
|
||||
the import block and `__all__`).
|
||||
- `src/gps_denied_onboard/components/c6_tile_cache/cache_budget_enforcer.py` —
|
||||
import path `c6_tile_cache._timestamp` → `helpers.iso_timestamps`
|
||||
(one-line edit; call-sites untouched).
|
||||
- `src/gps_denied_onboard/components/c6_tile_cache/postgres_filesystem_store.py` —
|
||||
same path swap (2 call-sites untouched).
|
||||
- `src/gps_denied_onboard/components/c6_tile_cache/freshness_gate.py` —
|
||||
same path swap (2 call-sites untouched).
|
||||
- `src/gps_denied_onboard/components/c7_inference/onnx_trt_ep_runtime.py` —
|
||||
removed local `def _iso_ts_now`; added top-of-file
|
||||
`from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now as _iso_ts_now`
|
||||
(preserves the `_iso_ts_now` symbol at 2 call-sites); removed the
|
||||
now-unused `from datetime import datetime, timezone`.
|
||||
- `src/gps_denied_onboard/components/c7_inference/thermal_publisher.py` —
|
||||
same pattern (1 call-site preserved); removed the now-unused
|
||||
`from datetime import datetime, timezone`.
|
||||
|
||||
### Production (deleted)
|
||||
|
||||
- `src/gps_denied_onboard/components/c6_tile_cache/_timestamp.py` —
|
||||
the c6-internal consolidation shim is no longer needed; the three
|
||||
c6 callers now import directly from `helpers.iso_timestamps`. The
|
||||
Layer-1 helper supersedes the Layer-2 component-local one.
|
||||
|
||||
### Tests (new)
|
||||
|
||||
- `tests/unit/test_az508_iso_timestamps.py` — 9 tests:
|
||||
- `test_ac1_import_and_call_returns_str` (AC-1)
|
||||
- `test_ac2_format_matches_canonical_regex` (AC-2 format)
|
||||
- `test_ac2_fromisoformat_roundtrip_yields_utc_aware_datetime` (AC-2 parseability)
|
||||
- `test_ac3_two_successive_calls_are_non_decreasing` (AC-3)
|
||||
- `test_ac4_no_other_iso_ts_now_definition_exists_in_src` (AC-4
|
||||
AST-walk over `src/`)
|
||||
- `test_ac4_c6_and_c7_callers_import_from_helpers` (AC-4 explicit
|
||||
call-site sweep — 5 files)
|
||||
- `test_ac6_helper_uses_stdlib_only` (AC-6, stdlib whitelist)
|
||||
- `test_helper_is_layer_1_no_component_imports` (Constraint
|
||||
§ Layer-1 discipline)
|
||||
- `test_helper_public_surface_is_minimal` (defensive: `__all__`
|
||||
is exactly `["iso_ts_now"]`)
|
||||
|
||||
### Docs (modified)
|
||||
|
||||
- `_docs/02_document/module-layout.md` — appended
|
||||
`### shared/helpers/iso_timestamps` row to the helpers section.
|
||||
- `_docs/02_tasks/todo/AZ-508_hygiene_iso_timestamps_consolidation.md` —
|
||||
drift note added to the description; AC-2 regex corrected from
|
||||
`\+00:00$` to `Z$`.
|
||||
- `_docs/03_implementation/reviews/batch_48_review.md` (new) —
|
||||
per-batch code review (PASS).
|
||||
- `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md` —
|
||||
replay-attempt timestamp + reason updated (PyPI shows `gtsam==4.2.1`
|
||||
but `requires_dist: numpy<2.0.0`; block unchanged).
|
||||
|
||||
## Acceptance Criteria Coverage
|
||||
|
||||
| AC | Description | Status | Test |
|
||||
|----|-------------|--------|------|
|
||||
| AC-1 | Helper exists, importable, callable, returns `str` | PASS | `test_ac1_import_and_call_returns_str` |
|
||||
| AC-2 | Format regex match + `fromisoformat` round-trip | PASS | `test_ac2_format_matches_canonical_regex`, `test_ac2_fromisoformat_roundtrip_yields_utc_aware_datetime` |
|
||||
| AC-3 | Lexicographic monotonicity under normal clock | PASS | `test_ac3_two_successive_calls_are_non_decreasing` |
|
||||
| AC-4 | All call sites migrated; no stray definitions | PASS | `test_ac4_no_other_iso_ts_now_definition_exists_in_src`, `test_ac4_c6_and_c7_callers_import_from_helpers` |
|
||||
| AC-5 | FDR schema tests pass unmodified | PASS | `tests/unit/test_az272_fdr_record_schema.py` runs unchanged (35 tests pass) |
|
||||
| AC-6 | No new third-party dependencies | PASS | `test_ac6_helper_uses_stdlib_only` + `pyproject.toml` unchanged |
|
||||
| AC-7 | AZ-270 layering lint passes | PASS | `tests/unit/test_az270_compose_root.py::test_ac6_only_compose_root_imports_concrete_strategies` |
|
||||
|
||||
## Test Results
|
||||
|
||||
- **Focused suite** (tests/unit/test_az508_iso_timestamps.py +
|
||||
test_az272_fdr_record_schema.py + tests/unit/c6_tile_cache/ +
|
||||
tests/unit/c7_inference/): **216 passed, 53 environment-skipped, 0 failed**
|
||||
in 7.97s. Environment-gated skips (Docker compose for c6 integration,
|
||||
CUDA / TensorRT / Jetson hardware for c7) — unchanged from Batch 47.
|
||||
- **Focused per-helper**: 9/9 new AZ-508 tests PASS in 1.36s.
|
||||
- **Layering lint**: AZ-270 + AZ-507 lints PASS (no cross-component
|
||||
import violations introduced).
|
||||
- **Lint**: `ruff check` clean on every file authored or modified by
|
||||
this batch. 3 pre-existing ruff findings (B905, RUF022, RUF023) in
|
||||
`onnx_trt_ep_runtime.py` left untouched per
|
||||
`coderule.mdc` "fix pre-existing lints only if in the modified area".
|
||||
|
||||
## Architectural Decisions
|
||||
|
||||
1. **Layer-1 helper supersedes the c6 internal `_timestamp.py`**.
|
||||
The c6-internal consolidation shipped earlier (cumulative review
|
||||
28–30 F3) was a Layer-2 stop-gap pending the cross-component
|
||||
consolidation. With the Layer-1 helper now in place, the c6 shim
|
||||
is redundant and was deleted; the three c6 callers now import
|
||||
the cross-component helper directly. This collapses two
|
||||
abstractions into one.
|
||||
|
||||
2. **Preserve `_iso_ts_now` symbol at c7 call-sites via import alias**.
|
||||
The c7 modules each have 1–2 in-method `_iso_ts_now()` call-sites.
|
||||
Rather than edit every call-site, the new module-level
|
||||
`from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now as _iso_ts_now`
|
||||
keeps the local symbol name unchanged → minimal diff per c7 file
|
||||
and minimal risk of accidentally missing a call-site. Matches
|
||||
the task spec's preferred form (Scope § Included bullet 2).
|
||||
|
||||
3. **Stdlib-only helper, no Clock dependency**. The helper is wall-clock
|
||||
metadata about when an FDR record envelope was emitted — explicitly
|
||||
NOT a payload field that might need an injectable Clock for tests.
|
||||
The task spec calls this out (Excluded § "Any change to flight_clock
|
||||
/ wall_clock"), and the new module docstring reiterates it so
|
||||
future contributors do not route `age_seconds`-style fields through
|
||||
it.
|
||||
|
||||
4. **AST-walk AC-4 test instead of a grep gate**. AC-4 originally
|
||||
contemplated a CI-level `grep -rn "def _iso_ts_now" src/` gate. The
|
||||
in-repo test in `test_az508_iso_timestamps.py` uses an AST walk
|
||||
instead — it catches both `def _iso_ts_now` AND
|
||||
`def iso_ts_now` defined anywhere outside the helper, with file
|
||||
paths in the assertion message, and runs as part of the standard
|
||||
unit suite (no separate CI hook needed). The same test also enforces
|
||||
the consumer-side import discipline so the regression surface is
|
||||
"the import or the test breaks", not "a stray definition lingers".
|
||||
|
||||
## Carried-over Findings (from prior batches)
|
||||
|
||||
- **F1 from cumulative review 43–45 / Batch 46 / Batch 47**: closed by
|
||||
this batch. `_iso_ts_now` is now in exactly one place.
|
||||
- **F2 from Batch 46 / Batch 47** (spec→impl drift on C7 API names for
|
||||
AZ-339 / AZ-340 / AZ-358 / AZ-349): **NOT addressed in this batch**;
|
||||
belongs to a spec-hygiene PBI to be filed before AZ-339 starts.
|
||||
- **D-CROSS-CVE-1 opencv pin leftover**: replay attempted at Batch 48
|
||||
bootstrap; PyPI shows `gtsam==4.2.1` (newer than 4.2 referenced in
|
||||
the leftover) but still pins `numpy<2.0.0`. Block unchanged;
|
||||
leftover timestamp updated.
|
||||
|
||||
## New Findings (per Batch 48 code review)
|
||||
|
||||
None.
|
||||
|
||||
## Jira Tracker
|
||||
|
||||
- AZ-508 was already `In Progress` at Batch 48 start (transitioned in
|
||||
a prior `/autodev` session per the state file). Read-back via
|
||||
`getJiraIssue` confirmed `status.name == "In Progress"` before any
|
||||
source edits. Will transition `In Progress → In Testing` after this
|
||||
batch's commit lands.
|
||||
- Task spec archived to `_docs/02_tasks/done/AZ-508_hygiene_iso_timestamps_consolidation.md`
|
||||
as part of the implement skill Step 13.
|
||||
|
||||
## Next
|
||||
|
||||
With AZ-508 closed, the carried-over F1 from batches 43–47 is resolved
|
||||
and the next C2 / C4 / C3 batches can ship without re-adding the
|
||||
helper. Top Batch 49 candidates (per Batch 47's "Next" list, updated):
|
||||
|
||||
- **AZ-339** — MegaLoc + MixVPR strategies (5pt). Same skeleton as
|
||||
UltraVPR (B47) but two strategies; F2 spec-hygiene PBI may want to
|
||||
ship first.
|
||||
- **AZ-340** — SelaVPR + EigenPlaces + SALAD strategies (5pt). Closes
|
||||
the C2 alternative-backbone buffet.
|
||||
- **AZ-358** — C4 OpenCV/GTSAM pose estimator (5pt). Changes pace from
|
||||
C2-heavy streak; opens C4.
|
||||
- **AZ-389** — C5 internal orthorectifier for mid-flight tiles (3pt).
|
||||
- **Spec-hygiene PBI** for F2 (C7 API drift in AZ-339 / AZ-340 / AZ-358 /
|
||||
AZ-349 specs) — strongly recommended before AZ-339.
|
||||
|
||||
Per autodev orchestrator: Batch 48 is the third batch since the last
|
||||
cumulative review (batches 43–45). The implement skill Step 14.5
|
||||
triggers a **cumulative review batches 46–48** before Batch 49 starts.
|
||||
@@ -0,0 +1,126 @@
|
||||
# Code Review Report — Batch 48
|
||||
|
||||
**Batch**: 48 (Cycle 1)
|
||||
**Tasks**: AZ-508 — ISO-timestamp helper consolidation (2 pt)
|
||||
**Date**: 2026-05-13
|
||||
**Verdict**: **PASS**
|
||||
|
||||
## Findings
|
||||
|
||||
_No findings._
|
||||
|
||||
## Phase Summary
|
||||
|
||||
### Phase 1 — Context Loading
|
||||
|
||||
- Task spec: `_docs/02_tasks/todo/AZ-508_hygiene_iso_timestamps_consolidation.md`
|
||||
- Cumulative review F2 (batches 31–33) + F3 (batches 28–30) — origin of the
|
||||
hygiene PBI.
|
||||
- Changed source files: 1 new helper + 1 helper package re-export +
|
||||
3 c6 import rewires + 2 c7 local-def → import rewires + 1 deleted
|
||||
c6 internal shim.
|
||||
- Changed test files: 1 new (`tests/unit/test_az508_iso_timestamps.py`,
|
||||
9 tests covering AC-1..AC-7 + Layer-1 invariant).
|
||||
- Changed docs: `module-layout.md` (new `shared/helpers/iso_timestamps`
|
||||
entry) + task spec (drift note + corrected AC-2 regex).
|
||||
|
||||
### Phase 2 — Spec Compliance (AC-by-AC)
|
||||
|
||||
| AC | Verdict | Evidence |
|
||||
|----|---------|----------|
|
||||
| AC-1 | PASS | `test_ac1_import_and_call_returns_str` |
|
||||
| AC-2 | PASS | `test_ac2_format_matches_canonical_regex` + `test_ac2_fromisoformat_roundtrip_yields_utc_aware_datetime` |
|
||||
| AC-3 | PASS | `test_ac3_two_successive_calls_are_non_decreasing` |
|
||||
| AC-4 | PASS | `test_ac4_no_other_iso_ts_now_definition_exists_in_src` (AST walk over `src/`) + `test_ac4_c6_and_c7_callers_import_from_helpers` |
|
||||
| AC-5 | PASS | `tests/unit/test_az272_fdr_record_schema.py` runs unmodified, 100% pass |
|
||||
| AC-6 | PASS | `test_ac6_helper_uses_stdlib_only` (AST whitelist) — `pyproject.toml` unchanged |
|
||||
| AC-7 | PASS | `tests/unit/test_az270_compose_root.py::test_ac6_only_compose_root_imports_concrete_strategies` passes |
|
||||
|
||||
**Spec drift note**: the task spec originally listed 5 call-sites and a
|
||||
`+00:00` regex. On-disk reality at implementation time: 3 call-sites
|
||||
(c6 already locally consolidated under `_timestamp.py`; `tensorrt_runtime.py`
|
||||
had no local copy) and the canonical FDR `ts` format is `Z`-suffix per
|
||||
the `_TS = "2026-05-11T00:00:00.000000Z"` fixture. Spec + AC-2 regex
|
||||
updated in this batch; no behavioral drift from the spec's actual intent
|
||||
("single Layer-1 helper, byte-identical to existing locals, no FDR
|
||||
schema change"). User explicitly approved the path via Choose A.
|
||||
|
||||
### Phase 3 — Code Quality
|
||||
|
||||
- **SRP**: pure stateless free function; no class wrapper (per Constraint
|
||||
§ "no class wrapping").
|
||||
- **Error handling**: no exception suppression; stdlib `datetime.now`
|
||||
cannot raise under normal operation.
|
||||
- **Naming**: `iso_ts_now` matches the canonical name used by all three
|
||||
pre-existing local helpers — no naming churn in call sites
|
||||
(`from … import iso_ts_now as _iso_ts_now` alias preserved in the c7
|
||||
files).
|
||||
- **Complexity**: 1 line. n/a.
|
||||
- **DRY**: net deletion — eliminates duplication (the explicit goal).
|
||||
- **Test quality**: assertions cover format, parseability, monotonicity,
|
||||
absence of stray definitions, import-path enforcement, layer-1
|
||||
invariant, and stdlib-only constraint.
|
||||
- **Dead code**: removed unused `from datetime import datetime, timezone`
|
||||
imports from both c7 files after the local `_iso_ts_now` defs were
|
||||
removed (adjacent-hygiene, permitted by `coderule.mdc`).
|
||||
|
||||
### Phase 4 — Security Quick-Scan
|
||||
|
||||
No SQL, no `subprocess`, no `eval` / `exec`, no secrets, no untrusted
|
||||
input handling. Helper is stdlib-only and side-effect-free. n/a.
|
||||
|
||||
### Phase 5 — Performance Scan
|
||||
|
||||
`datetime.now(timezone.utc).strftime(...)` is the same call all three
|
||||
previous local helpers made; zero runtime delta. No new allocations on
|
||||
the hot path.
|
||||
|
||||
### Phase 6 — Cross-Task Consistency
|
||||
|
||||
Single task in batch — no inter-task interface concerns. Helper aligns
|
||||
with the existing 8-helper convention (single-file Layer-1 modules under
|
||||
`src/gps_denied_onboard/helpers/`, re-exported from `helpers/__init__.py`).
|
||||
|
||||
### Phase 7 — Architecture Compliance
|
||||
|
||||
- **Layer direction**: helper sits at Layer 1 (Foundation / shared);
|
||||
consumers in c6 (Layer 2 Infrastructure) and c7 (Layer 2
|
||||
Infrastructure) import strictly downward. ✓
|
||||
- **Public API respect**: consumers import via
|
||||
`gps_denied_onboard.helpers.iso_timestamps` (or the `helpers` package
|
||||
facade after the `__init__.py` re-export). Internal modules of c6/c7
|
||||
are not imported across components. ✓
|
||||
- **No new cyclic deps**: the helper imports only stdlib; no possible
|
||||
cycle. ✓
|
||||
- **Duplicate symbols**: eliminated by design — the AC-4 AST walk
|
||||
asserts zero other `iso_ts_now` / `_iso_ts_now` definitions remain
|
||||
anywhere under `src/`. ✓
|
||||
- **Cross-cutting concern home**: moved from per-component locals to
|
||||
the canonical `helpers/` directory. ✓
|
||||
- **AZ-507 layering lint**: `test_ac6_only_compose_root_imports_concrete_strategies`
|
||||
passes — helper imports are allowed from components. ✓
|
||||
- **AZ-270 lint**: passes. ✓
|
||||
|
||||
## Pre-existing Findings (NOT introduced by this batch)
|
||||
|
||||
The following ruff findings remain in
|
||||
`src/gps_denied_onboard/components/c7_inference/onnx_trt_ep_runtime.py`
|
||||
but are pre-existing (verified by re-running ruff against `HEAD` before
|
||||
this batch's edits):
|
||||
|
||||
- **B905** at line 547 — `zip()` without `strict=`.
|
||||
- **RUF022** at lines 88–98 — `__all__` not sorted.
|
||||
- **RUF023** at lines 127–134 — `__slots__` not sorted.
|
||||
|
||||
Per `coderule.mdc` "Pre-existing lint errors should only be fixed if
|
||||
they're in the modified area" — left untouched. Candidate for a future
|
||||
c7 hygiene PBI.
|
||||
|
||||
## Verdict Justification
|
||||
|
||||
- Critical findings: 0
|
||||
- High findings: 0
|
||||
- Medium findings: 0
|
||||
- Low findings: 0
|
||||
|
||||
**PASS** — proceed to commit per implement skill Step 11.
|
||||
@@ -8,9 +8,9 @@ status: in_progress
|
||||
sub_step:
|
||||
phase: 7
|
||||
name: batch-loop
|
||||
detail: "batch 48 — AZ-508 (ISO timestamp helper consolidation)"
|
||||
detail: "cumulative review batches 46-48 due before next batch"
|
||||
retry_count: 0
|
||||
cycle: 1
|
||||
tracker: jira
|
||||
last_completed_batch: 47
|
||||
last_completed_batch: 48
|
||||
last_cumulative_review: batches_43-45
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# D-CROSS-CVE-1 opencv-python pin deferred — gtsam/numpy ABI block
|
||||
|
||||
**Recorded**: 2026-05-11T02:55+03:00 (Europe/Kyiv)
|
||||
**Last replay attempt**: 2026-05-13T23:09+03:00 (Europe/Kyiv) — PyPI shows
|
||||
`gtsam==4.2.1` as the latest release; `requires_dist: numpy<2.0.0,>=1.11.0`.
|
||||
Replay condition (numpy>=2 wheels) still NOT met. Leftover remains open.
|
||||
**Status**: deferred-non-user (replay when upstream gtsam wheels target numpy>=2)
|
||||
|
||||
## What is blocked
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
"""RFC 3339 UTC timestamp helper shared inside the c6_tile_cache component.
|
||||
|
||||
Single source for the FDR record envelope ``ts`` field across
|
||||
``postgres_filesystem_store``, ``freshness_gate``, and
|
||||
``cache_budget_enforcer`` — formerly a triplicate ``_iso_ts_now`` per
|
||||
module (`cumulative_review_batches_28-30` F3). The format is wall-clock
|
||||
metadata about WHEN the FDR record was emitted; producers that need a
|
||||
Clock-driven payload field (e.g., ``age_seconds`` derived from an
|
||||
injected clock) MUST NOT route through this helper.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
__all__ = ["iso_ts_now"]
|
||||
|
||||
|
||||
def iso_ts_now() -> str:
|
||||
"""Return an RFC 3339 UTC timestamp with microsecond precision and a ``Z`` suffix."""
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
@@ -34,7 +34,6 @@ from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
from typing import TYPE_CHECKING, Final
|
||||
|
||||
from gps_denied_onboard.components.c6_tile_cache._timestamp import iso_ts_now
|
||||
from gps_denied_onboard.components.c6_tile_cache._types import (
|
||||
TileId,
|
||||
TileMetadata,
|
||||
@@ -50,6 +49,7 @@ from gps_denied_onboard.components.c6_tile_cache.interface import (
|
||||
TileStore,
|
||||
)
|
||||
from gps_denied_onboard.fdr_client.records import CURRENT_SCHEMA_VERSION, FdrRecord
|
||||
from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from gps_denied_onboard.components.c6_tile_cache._tile_pixel_handle import (
|
||||
|
||||
@@ -47,7 +47,6 @@ from typing import TYPE_CHECKING, Any, Final
|
||||
import psycopg
|
||||
from psycopg_pool import ConnectionPool
|
||||
|
||||
from gps_denied_onboard.components.c6_tile_cache._timestamp import iso_ts_now
|
||||
from gps_denied_onboard.components.c6_tile_cache._types import (
|
||||
Bbox,
|
||||
FreshnessLabel,
|
||||
@@ -61,6 +60,7 @@ from gps_denied_onboard.components.c6_tile_cache.errors import (
|
||||
)
|
||||
from gps_denied_onboard.config.schema import ConfigError
|
||||
from gps_denied_onboard.fdr_client.records import CURRENT_SCHEMA_VERSION, FdrRecord
|
||||
from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from gps_denied_onboard.clock.interface import Clock
|
||||
|
||||
@@ -48,7 +48,6 @@ from psycopg_pool import ConnectionPool
|
||||
from gps_denied_onboard.components.c6_tile_cache._tile_pixel_handle import (
|
||||
TilePixelHandle,
|
||||
)
|
||||
from gps_denied_onboard.components.c6_tile_cache._timestamp import iso_ts_now
|
||||
from gps_denied_onboard.components.c6_tile_cache._types import (
|
||||
Bbox,
|
||||
FreshnessLabel,
|
||||
@@ -76,6 +75,7 @@ from gps_denied_onboard.fdr_client.records import (
|
||||
CURRENT_SCHEMA_VERSION,
|
||||
FdrRecord,
|
||||
)
|
||||
from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now
|
||||
from gps_denied_onboard.helpers.sha256_sidecar import (
|
||||
SIDECAR_SUFFIX,
|
||||
Sha256Sidecar,
|
||||
|
||||
@@ -46,7 +46,6 @@ from __future__ import annotations
|
||||
import hashlib
|
||||
import os
|
||||
from collections.abc import Callable
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Final, Literal
|
||||
|
||||
@@ -79,6 +78,7 @@ from gps_denied_onboard.fdr_client.records import (
|
||||
CURRENT_SCHEMA_VERSION,
|
||||
FdrRecord,
|
||||
)
|
||||
from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now as _iso_ts_now
|
||||
from gps_denied_onboard.logging import get_logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -166,18 +166,6 @@ def _sha256_of_file(path: Path) -> str:
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def _iso_ts_now() -> str:
|
||||
"""RFC 3339 UTC timestamp with microsecond precision and a ``Z`` suffix.
|
||||
|
||||
Mirrors :func:`components.c6_tile_cache._timestamp.iso_ts_now` —
|
||||
consolidation into ``helpers.iso_timestamp`` is intentionally
|
||||
deferred to the next cross-component hygiene pass (peer imports
|
||||
between c6 and c7 would violate layer-2 horizontal-import etiquette
|
||||
documented in ``module-layout.md``).
|
||||
"""
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Runtime.
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ from __future__ import annotations
|
||||
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
from typing import TYPE_CHECKING, Protocol, runtime_checkable
|
||||
|
||||
from gps_denied_onboard._types.thermal import ThermalState
|
||||
@@ -65,6 +64,7 @@ from gps_denied_onboard.fdr_client.records import (
|
||||
CURRENT_SCHEMA_VERSION,
|
||||
FdrRecord,
|
||||
)
|
||||
from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now as _iso_ts_now
|
||||
from gps_denied_onboard.logging import get_logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -340,11 +340,6 @@ def _default_safe_snapshot(measured_at_ns: int) -> ThermalState:
|
||||
)
|
||||
|
||||
|
||||
def _iso_ts_now() -> str:
|
||||
"""RFC 3339 UTC timestamp with microsecond precision and ``Z`` suffix."""
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
|
||||
|
||||
class _JtopSource:
|
||||
"""``jtop`` (jetson-stats) thermal source — Tier-2 production path.
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ from gps_denied_onboard.helpers.imu_preintegrator import (
|
||||
ImuPreintegrator,
|
||||
make_imu_preintegrator,
|
||||
)
|
||||
from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now
|
||||
from gps_denied_onboard.helpers.lightglue_runtime import (
|
||||
LightGlueConcurrentAccessError,
|
||||
LightGlueRuntime,
|
||||
@@ -83,6 +84,7 @@ __all__ = [
|
||||
"adjoint",
|
||||
"exp_map",
|
||||
"is_valid_rotation",
|
||||
"iso_ts_now",
|
||||
"log_map",
|
||||
"make_imu_preintegrator",
|
||||
"matrix_to_se3",
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
"""UTC ISO-8601 timestamp helper (E-CC-HELPERS / AZ-264 / AZ-508).
|
||||
|
||||
Single Layer-1 source for the wall-clock string used in the FDR record
|
||||
``ts`` envelope across c6_tile_cache and c7_inference. Consolidates what
|
||||
used to be a private ``_iso_ts_now`` one-liner repeated per module.
|
||||
|
||||
The output format is locked to RFC 3339 / ISO 8601 UTC with microsecond
|
||||
precision and a ``Z`` suffix, matching the canonical FDR ``ts`` fixture
|
||||
in ``tests/unit/test_az272_fdr_record_schema.py`` (``_TS =
|
||||
"2026-05-11T00:00:00.000000Z"``) and the format produced by the three
|
||||
existing local helpers this module replaces. Changing the format would
|
||||
alter FDR record bit-shape and is explicitly out of scope for AZ-508.
|
||||
|
||||
Producers that need a Clock-injected payload field (e.g.
|
||||
``age_seconds`` derived from an injected wall-clock for testability)
|
||||
MUST NOT route through this helper — it is purely metadata about WHEN
|
||||
the FDR record envelope itself was emitted.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
__all__ = ["iso_ts_now"]
|
||||
|
||||
|
||||
def iso_ts_now() -> str:
|
||||
"""Return an RFC 3339 UTC timestamp with microsecond precision and a ``Z`` suffix.
|
||||
|
||||
Format: ``YYYY-MM-DDTHH:MM:SS.ffffffZ`` (fixed-width, lexicographically
|
||||
monotonic under a non-decreasing wall clock).
|
||||
"""
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
@@ -0,0 +1,191 @@
|
||||
"""AC tests for AZ-508: ISO-timestamp helper consolidation.
|
||||
|
||||
Verifies the `iso_timestamps` helper exposed at
|
||||
`gps_denied_onboard.helpers.iso_timestamps.iso_ts_now` — the single
|
||||
Layer-1 source for FDR record envelope timestamps that replaced the
|
||||
duplicated `_iso_ts_now` one-liners in c6_tile_cache and c7_inference.
|
||||
|
||||
Output contract (matches the canonical FDR `_TS` fixture in
|
||||
`tests/unit/test_az272_fdr_record_schema.py`):
|
||||
|
||||
YYYY-MM-DDTHH:MM:SS.ffffffZ (UTC, microsecond precision, ``Z`` suffix)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import re
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from gps_denied_onboard.helpers import iso_ts_now
|
||||
from gps_denied_onboard.helpers.iso_timestamps import iso_ts_now as iso_ts_now_direct
|
||||
|
||||
_TS_REGEX: re.Pattern[str] = re.compile(
|
||||
r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z$"
|
||||
)
|
||||
|
||||
_REPO_ROOT: Path = Path(__file__).resolve().parents[2]
|
||||
_HELPER_PATH: Path = (
|
||||
_REPO_ROOT / "src" / "gps_denied_onboard" / "helpers" / "iso_timestamps.py"
|
||||
)
|
||||
_C6_DIR: Path = (
|
||||
_REPO_ROOT / "src" / "gps_denied_onboard" / "components" / "c6_tile_cache"
|
||||
)
|
||||
_C7_DIR: Path = (
|
||||
_REPO_ROOT / "src" / "gps_denied_onboard" / "components" / "c7_inference"
|
||||
)
|
||||
|
||||
|
||||
def test_ac1_import_and_call_returns_str() -> None:
|
||||
# Act
|
||||
value = iso_ts_now()
|
||||
# Assert
|
||||
assert isinstance(value, str)
|
||||
assert value, "iso_ts_now() returned an empty string"
|
||||
# Both the package-level and module-level imports must resolve to the
|
||||
# same callable so consumers can reach it either way.
|
||||
assert iso_ts_now is iso_ts_now_direct
|
||||
|
||||
|
||||
def test_ac2_format_matches_canonical_regex() -> None:
|
||||
# Act
|
||||
value = iso_ts_now()
|
||||
# Assert
|
||||
assert _TS_REGEX.fullmatch(value), (
|
||||
f"{value!r} does not match the canonical FDR ts format "
|
||||
f"YYYY-MM-DDTHH:MM:SS.ffffffZ"
|
||||
)
|
||||
|
||||
|
||||
def test_ac2_fromisoformat_roundtrip_yields_utc_aware_datetime() -> None:
|
||||
# Arrange
|
||||
value = iso_ts_now()
|
||||
iso_with_offset = value.replace("Z", "+00:00")
|
||||
|
||||
# Act
|
||||
parsed = datetime.fromisoformat(iso_with_offset)
|
||||
|
||||
# Assert
|
||||
assert parsed.tzinfo is not None
|
||||
assert parsed.utcoffset() == timezone.utc.utcoffset(parsed)
|
||||
|
||||
|
||||
def test_ac3_two_successive_calls_are_non_decreasing() -> None:
|
||||
# Arrange / Act
|
||||
a = iso_ts_now()
|
||||
time.sleep(0.000_005)
|
||||
b = iso_ts_now()
|
||||
|
||||
# Assert (lexicographic comparison is correct for the fixed-width format)
|
||||
assert b >= a, f"expected {b!r} >= {a!r}"
|
||||
|
||||
|
||||
def test_ac4_no_other_iso_ts_now_definition_exists_in_src() -> None:
|
||||
"""AC-4: a `def _iso_ts_now` / `def iso_ts_now` MUST exist only inside
|
||||
`helpers/iso_timestamps.py`. Any other definition under `src/` means a
|
||||
consumer slipped a copy back in.
|
||||
"""
|
||||
# Arrange
|
||||
src_root = _REPO_ROOT / "src"
|
||||
offenders: list[tuple[Path, str]] = []
|
||||
|
||||
# Act
|
||||
for path in src_root.rglob("*.py"):
|
||||
if path == _HELPER_PATH:
|
||||
continue
|
||||
try:
|
||||
tree = ast.parse(path.read_text(encoding="utf-8"))
|
||||
except SyntaxError:
|
||||
continue
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.FunctionDef) and node.name in {
|
||||
"iso_ts_now",
|
||||
"_iso_ts_now",
|
||||
}:
|
||||
offenders.append((path.relative_to(_REPO_ROOT), node.name))
|
||||
|
||||
# Assert
|
||||
assert offenders == [], (
|
||||
f"Found stray `iso_ts_now` definitions outside the helper: {offenders}"
|
||||
)
|
||||
|
||||
|
||||
def test_ac4_c6_and_c7_callers_import_from_helpers() -> None:
|
||||
"""The 3 migrated call-sites must import from `helpers.iso_timestamps`
|
||||
(directly or via the `helpers` package facade) so future hygiene
|
||||
cycles can rely on the single source of truth.
|
||||
"""
|
||||
# Arrange
|
||||
callers = [
|
||||
_C6_DIR / "cache_budget_enforcer.py",
|
||||
_C6_DIR / "postgres_filesystem_store.py",
|
||||
_C6_DIR / "freshness_gate.py",
|
||||
_C7_DIR / "onnx_trt_ep_runtime.py",
|
||||
_C7_DIR / "thermal_publisher.py",
|
||||
]
|
||||
expected_token = "gps_denied_onboard.helpers.iso_timestamps"
|
||||
|
||||
# Act / Assert
|
||||
for caller in callers:
|
||||
text = caller.read_text(encoding="utf-8")
|
||||
assert expected_token in text, (
|
||||
f"{caller.relative_to(_REPO_ROOT)} does not import "
|
||||
f"`iso_ts_now` from `{expected_token}`"
|
||||
)
|
||||
assert "def _iso_ts_now" not in text, (
|
||||
f"{caller.relative_to(_REPO_ROOT)} still defines a local "
|
||||
"_iso_ts_now (consolidation incomplete)"
|
||||
)
|
||||
|
||||
|
||||
def test_ac6_helper_uses_stdlib_only() -> None:
|
||||
"""AC-6: no third-party imports inside the helper module."""
|
||||
# Arrange
|
||||
tree = ast.parse(_HELPER_PATH.read_text(encoding="utf-8"))
|
||||
allowed_stdlib = {"datetime", "__future__"}
|
||||
|
||||
# Act
|
||||
imports: list[str] = []
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
imports.extend(alias.name for alias in node.names)
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
if node.module is not None:
|
||||
imports.append(node.module)
|
||||
|
||||
# Assert
|
||||
for name in imports:
|
||||
top = name.split(".")[0]
|
||||
assert top in allowed_stdlib, (
|
||||
f"helpers/iso_timestamps.py imports `{name}`; only stdlib "
|
||||
f"({sorted(allowed_stdlib)}) is allowed by AC-6"
|
||||
)
|
||||
|
||||
|
||||
def test_helper_is_layer_1_no_component_imports() -> None:
|
||||
"""Layer-1 discipline: the helper MUST NOT import from any component.
|
||||
(Constraint § Layer-1 discipline in the AZ-508 task spec.)
|
||||
"""
|
||||
# Arrange
|
||||
text = _HELPER_PATH.read_text(encoding="utf-8")
|
||||
|
||||
# Assert
|
||||
assert "gps_denied_onboard.components" not in text, (
|
||||
"helpers/iso_timestamps.py imports from a component — Layer-1 "
|
||||
"discipline violated"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_field", ["iso_ts_now"])
|
||||
def test_helper_public_surface_is_minimal(expected_field: str) -> None:
|
||||
"""Defensive: only ``iso_ts_now`` is re-exported from the module."""
|
||||
# Arrange
|
||||
import gps_denied_onboard.helpers.iso_timestamps as module
|
||||
|
||||
# Assert
|
||||
assert expected_field in module.__all__
|
||||
assert module.__all__ == ["iso_ts_now"]
|
||||
Reference in New Issue
Block a user