- 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.
11 KiB
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 theRouteSpecdataclass definition (frozen, slots, with full docstring carried over verbatim). - MOD:
src/gps_denied_onboard/replay_input/tlog_route.py— remove the localRouteSpecclass definition (lines 54–79); addfrom gps_denied_onboard._types.route import RouteSpecnear the existing_types.geoimport; keepRouteSpecin__all__sofrom replay_input.tlog_route import RouteSpeccontinues 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 importRouteSpecfromgps_denied_onboard._types.routedirectly (canonical), keep importingRouteExtractionErrorandextract_route_from_tlogfromtlog_route(they stay there). - MOD:
src/gps_denied_onboard/components/c11_tile_manager/route_client.py:56— change tofrom gps_denied_onboard._types.route import RouteSpec(the actual rule-9 fix). Also update the docstring snippet at file-top that readsTakes a gps_denied_onboard.replay_input.tlog_route.RouteSpec→Takes 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 importRouteSpecfromreplay_input.tlog_route. They continue to work via the re-export (see above). Updating them to import from_types.routeis hygiene, not correctness; recommended but not blocking. The integration testtests/integration/c11_tile_manager/test_route_client_e2e.py:26importsextract_route_from_tlog(notRouteSpec) — no change needed. The lazy import intests/e2e/replay/conftest.py:406and the CLI fixturetests/fixtures/derkachi_c6/seed_route.py:80importextract_route_from_tlogonly — no change needed.
- NEW:
-
Problem:
components/c11_tile_manager/route_client.py:56importsRouteSpecfromgps_denied_onboard.replay_input.tlog_route. Permodule-layout.mdrule 9,components/<X>/*.pymay only import from a finite allow-list (_types/*,_types.inference_errors,helpers/*,config,logging,fdr_client,clock,frame_sourceinterface only).replay_inputis 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 onlycomponents → componentsedges (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. PuttingRouteSpecthere makes the c11 → DTO edge acomponents/<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.
RouteSpecimmutability (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.mdis 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 includeroute.py(added in C01).
- c11_tile_manager Internal list is missing
- Change: Append the missing entries to bring
module-layout.mdin sync with on-disk reality for the c11_tile_manager, replay_input, and_types/sections. Add_types/route.pyto the_types/section with a one-line description (consistent with how the other_types/*.pyfiles 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:
/implementStep 4 (File Ownership) treatsmodule-layout.mdas 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.mdrule 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.pyentry 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 walkscomponents/**/*.py, parses eachImportFrom, and for anynode.modulestarting withgps_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_sourceinterface-only). - MOD (test docstring): update the test's docstring to cite the full rule-9 paragraph, not just AC-6 of AZ-270.
- MOD:
- Problem: F3 of the cumulative review documents that
module-layout.mdrule 9 is described as "enforced bytest_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 thegps_denied_onboard.components.<other_component>exclusion. Imports fromreplay_input,replay_api,runtime_root,cli/*, andframe_sourcenon-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 thecomponents.<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.mdrule 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
RouteSpecat_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.