[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:
Oleksandr Bezdieniezhnykh
2026-05-13 23:23:22 +03:00
parent f29897cb3a
commit 5441ea2017
15 changed files with 596 additions and 48 deletions
+191
View File
@@ -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"]