Files
gps-denied-onboard/_docs/04_refactoring/02-az507-routespec-relocation/list-of-changes.md
T
Oleksandr Bezdieniezhnykh 9dc04cc677
ci/woodpecker/push/02-build-push Pipeline failed
Update autodev state and dependencies table for Phase 2 progress
- Changed autodev state sub_step to reflect new phase and task details: updated phase from 7 to 2, renamed task to 'refactor-analysis-gate', and revised detail to indicate the creation of new tasks AZ-844, AZ-845, AZ-846, and AZ-847, awaiting Phase-2 gate.
- Updated dependencies table with the latest task counts and complexity points, reflecting the addition of new tasks and the closure of AZ-777 in Jira. Total tasks now stand at 173 with 557 complexity points.
2026-05-23 17:11:50 +03:00

11 KiB
Raw Blame History

List of Changes

Run: 02-az507-routespec-relocation Mode: guided Source: _docs/03_implementation/cumulative_review_batches_104-109_cycle3_report.md (cycle-3 cumulative review, FAIL verdict, F1 + F2 + F3) Date: 2026-05-23

Summary

Resolve the cycle-3 cumulative review's FAIL verdict by (a) relocating the RouteSpec DTO to its rule-9-compliant home in _types/route.py, (b) refreshing the stale module-layout.md cycle-3 file inventory, and (c) widening the AZ-270 lint to enforce the full rule-9 allow-list rather than only components → components edges. The work is mechanical — no behaviour, no performance, no contract shape changes.

Changes

C01: Relocate RouteSpec DTO from replay_input/tlog_route.py to _types/route.py

  • File(s):

    • NEW: src/gps_denied_onboard/_types/route.py — owns the RouteSpec dataclass definition (frozen, slots, with full docstring carried over verbatim).
    • MOD: src/gps_denied_onboard/replay_input/tlog_route.py — remove the local RouteSpec class definition (lines 5479); add from gps_denied_onboard._types.route import RouteSpec near the existing _types.geo import; keep RouteSpec in __all__ so from replay_input.tlog_route import RouteSpec continues to resolve (test code uses this path; it's a re-export, not a violation).
    • MOD: src/gps_denied_onboard/replay_input/__init__.py — change line 34 to import RouteSpec from gps_denied_onboard._types.route directly (canonical), keep importing RouteExtractionError and extract_route_from_tlog from tlog_route (they stay there).
    • MOD: src/gps_denied_onboard/components/c11_tile_manager/route_client.py:56 — change to from gps_denied_onboard._types.route import RouteSpec (the actual rule-9 fix). Also update the docstring snippet at file-top that reads Takes a gps_denied_onboard.replay_input.tlog_route.RouteSpecTakes a gps_denied_onboard._types.route.RouteSpec.
    • MOD (optional, hygiene): test imports — 5 test files (tests/unit/replay_input/test_tlog_route.py:46, tests/unit/c11_tile_manager/test_route_client.py:49, tests/e2e/replay/_operator_pre_flight.py:72, tests/e2e/replay/test_e2e_orchestrator_unit.py:37, tests/e2e/replay/test_operator_pre_flight_driver.py:61) currently import RouteSpec from replay_input.tlog_route. They continue to work via the re-export (see above). Updating them to import from _types.route is hygiene, not correctness; recommended but not blocking. The integration test tests/integration/c11_tile_manager/test_route_client_e2e.py:26 imports extract_route_from_tlog (not RouteSpec) — no change needed. The lazy import in tests/e2e/replay/conftest.py:406 and the CLI fixture tests/fixtures/derkachi_c6/seed_route.py:80 import extract_route_from_tlog only — no change needed.
  • Problem: components/c11_tile_manager/route_client.py:56 imports RouteSpec from gps_denied_onboard.replay_input.tlog_route. Per module-layout.md rule 9, components/<X>/*.py may only import from a finite allow-list (_types/*, _types.inference_errors, helpers/*, config, logging, fdr_client, clock, frame_source interface only). replay_input is not in this list — it's a Layer-4 cross-cutting coordinator, and Layer-4 → Layer-4 cross-cutting edges are not declared as allowed in the layering table. The import was committed in batch 107 (AZ-838); the AZ-270 lint did not catch it because the lint walks only components → components edges (see C03).

  • Change: Move the DTO definition to _types/route.py, where it sits among the other shared DTOs (_types/geo.py, _types/tile.py, _types/inference.py, etc.). Update the c11 import to point at the new location. Producer-side (replay_input/tlog_route.py) re-imports the DTO so its own return type, __all__, and existing test imports keep working — that's a coordinator importing from _types/*, a flow that is always allowed for non-components/<X> modules.

  • Rationale: _types/* is the architecturally designated home for cross-component DTOs (per AZ-507; per _docs/02_document/architecture.md ## Architecture Vision). Every other shared DTO already lives there. Putting RouteSpec there makes the c11 → DTO edge a components/<X>_types/* edge, which is allow-listed. This matches the pattern for _types/inference.py, _types/tile.py, _types/calibration.py, _types/pose.py, etc. — the user-confirmed precedent.

  • Constraint Fit:

    • AZ-507 cross-component contract surface — satisfied (the violating edge becomes compliant).
    • Epic AZ-835 acceptance criteria — preserved; behaviour unchanged.
    • RouteSpec immutability (frozen=True, slots=True) — preserved verbatim.
    • Backward compatibility for producer-side test imports (from replay_input.tlog_route import RouteSpec) — preserved via re-export.
    • No public-API / CLI / endpoint shape change — confirmed in baseline_metrics §5.
  • Risk: low (mechanical move; identity-preserving; logical-flow analysis confirms no observable side effects beyond __module__, which no code asserts on).

  • Dependencies: None.

C02: Refresh module-layout.md to register cycle-3 additions + new _types/route.py

  • File(s): _docs/02_document/module-layout.md (single file).
  • Problem: The cumulative review's F2 surfaces that module-layout.md is stale. Cycle-2 carry-overs are still unaddressed; cycle 3 added more entries that are not registered. Specifically:
    • c11_tile_manager Internal list is missing _types.py, config.py, errors.py, idempotent_retry.py, signing_key.py, tile_downloader.py, tile_uploader.py, route_client.py (cycle-3 NEW from batch 107).
    • shared/replay_input file list is missing errors.py (cycle-2 carry), tlog_ground_truth.py (cycle-2 carry), tlog_route.py (cycle-3 NEW from batch 106).
    • _types/ file list does not yet include route.py (added in C01).
  • Change: Append the missing entries to bring module-layout.md in sync with on-disk reality for the c11_tile_manager, replay_input, and _types/ sections. Add _types/route.py to the _types/ section with a one-line description (consistent with how the other _types/*.py files are listed). Cycle-2 carry-overs outside these three sections (replay_api/, cli/render_map.py, cli/replay_api_entrypoint.py, helpers/gps_compare.py, helpers/accuracy_report.py) are NOT in this run's scope — they remain on the cycle-3 retrospective list and should be addressed in a follow-up doc task that is independent of the architectural fix here.
  • Rationale: /implement Step 4 (File Ownership) treats module-layout.md as authoritative; staleness there is a BLOCKING gate when a future task touches an unregistered area. F2 is currently Medium; the cumulative review notes severity escalates to High if a fourth consecutive cycle leaves it stale. Resolving the cycle-3 portion now keeps the fix scoped to the same surface as C01 + the route_client + tlog_route additions that triggered the cumulative review in the first place.
  • Constraint Fit:
    • module-layout.md rule 9 — strengthened (the document now reflects what _types/* actually owns).
    • No code or behavioural change.
    • Scope discipline — does NOT pull in cycle-2 carry-overs outside the run's three sections; they are deferred to a separate task.
  • Risk: low (doc-only; reviewable by diff; no test impact).
  • Dependencies: C01 (the _types/route.py entry depends on the file existing).

C03: Expand test_az270_compose_root.test_ac6_only_compose_root_imports_concrete_strategies to enforce the full rule-9 allow-list

  • File(s):
    • MOD: tests/unit/test_az270_compose_root.py:194-219 — replace the current narrow check (node.module.startswith("gps_denied_onboard.components.") with a different leaf-component) with a check that walks components/**/*.py, parses each ImportFrom, and for any node.module starting with gps_denied_onboard. asserts the importable target is in the rule-9 allow-list (i.e. matches one of: gps_denied_onboard.components.<own-component>.*, gps_denied_onboard._types.*, gps_denied_onboard._types.inference_errors, gps_denied_onboard.helpers.*, gps_denied_onboard.config, gps_denied_onboard.logging, gps_denied_onboard.fdr_client, gps_denied_onboard.clock, gps_denied_onboard.frame_source interface-only).
    • MOD (test docstring): update the test's docstring to cite the full rule-9 paragraph, not just AC-6 of AZ-270.
  • Problem: F3 of the cumulative review documents that module-layout.md rule 9 is described as "enforced by test_az270_compose_root.test_ac6_only_compose_root_imports_concrete_strategies", but the lint actually checks only one of the eight allow-listed prefixes — only the gps_denied_onboard.components.<other_component> exclusion. Imports from replay_input, replay_api, runtime_root, cli/*, and frame_source non-interface modules pass silently. F1 is the concrete consequence; the next task that imports from a similarly-placed module would compound the drift.
  • Change: Widen the AST walker to a single-branch decision: "is the imported module rooted in gps_denied_onboard. AND not in the rule-9 allow-list (parameterised against the importer's own component for the components.<own>.* clause)? → fail with a message that names the offending edge and the rule." The existing error message format (compose-root test failure) is preserved; only the predicate is widened.
  • Rationale: Lint coverage matters more than rule wording. F3 surfaces a maintainability risk: the rule and its enforcement diverge silently. Closing the gap forecloses the F1 class of regressions at lint time, not at cumulative-review time.
  • Constraint Fit:
    • module-layout.md rule 9 — enforced as documented.
    • Existing AZ-270 AC-6 — preserved (the new check is a strict superset of the old check).
    • No behaviour change in production code.
    • Self-check: running the widened lint at HEAD (before C01 lands) reproduces F1 as a lint failure; running it at the C01 + C02 tip reproduces zero violations. This is the test the run hinges on.
  • Risk: medium — the widening will catch any other in-flight rule-9 violation hiding in the codebase, which could surface a second remediation task. If the widened lint exposes an unrelated violation, the implement skill should STOP and surface it for a scope decision rather than auto-bundle. Risk is reduced by the fact that rule-9 audits during code review have not flagged anything else.
  • Dependencies: C01 must land first (otherwise the widened lint fails on the very edge C01 fixes; running tests in the order C01 → C03 means C03 sees a clean baseline). C02 ordering is independent.

Out of scope for this run

  • Cycle-2 module-layout carry-overs outside the three sections C02 touches (replay_api/ Per-Component Mapping, cli/render_map.py, cli/replay_api_entrypoint.py, helpers/gps_compare.py, helpers/accuracy_report.py) — recorded as cycle-3 retrospective follow-up; needs a separate doc task with its own AZ ID.
  • Contract documentation for RouteSpec at _docs/02_document/contracts/shared_types/route.md — the cumulative review noted this as a possible Spec-Gap follow-up. It is a documentation addition, not a refactor. Defer to whoever owns the Spec-Gap workflow; do not bundle here.
  • architecture_compliance_baseline.md — separate cycle-2 retrospective action that has been outstanding for two cycles; recorded as such in the cumulative review's footer note. Out of this run's scope.