From 35b2e98fad8292b42f521048a4cce85c700aab7d Mon Sep 17 00:00:00 2001 From: Yuzviak Date: Mon, 11 May 2026 08:59:51 +0300 Subject: [PATCH] docs(01-07): complete plan summary for hexagonal refactor plan 07 --- .../01-hexagonal-refactor/01-07-SUMMARY.md | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 .planning/phases/01-hexagonal-refactor/01-07-SUMMARY.md diff --git a/.planning/phases/01-hexagonal-refactor/01-07-SUMMARY.md b/.planning/phases/01-hexagonal-refactor/01-07-SUMMARY.md new file mode 100644 index 0000000..751c6e0 --- /dev/null +++ b/.planning/phases/01-hexagonal-refactor/01-07-SUMMARY.md @@ -0,0 +1,152 @@ +--- +phase: "01-hexagonal-refactor" +plan: "01-07" +subsystem: "core-restructure" +tags: ["refactor", "protocol", "pipeline", "abc-to-protocol", "shim"] + +dependency_graph: + requires: ["01-05", "01-06"] + provides: ["pipeline-package", "factor-graph-module", "testing-benchmark-module"] + affects: ["core/graph.py", "core/processor.py", "core/pipeline.py", "core/results.py", "core/sse.py", "core/benchmark.py", "core/chunk_manager.py", "core/recovery.py", "core/models.py", "core/rotation.py"] + +tech_stack: + added: [] + patterns: ["typing.Protocol with @runtime_checkable", "shim re-export pattern", "package decomposition"] + +key_files: + created: + - src/gps_denied/core/factor_graph.py + - src/gps_denied/pipeline/__init__.py + - src/gps_denied/pipeline/orchestrator.py + - src/gps_denied/pipeline/image_input.py + - src/gps_denied/pipeline/result_manager.py + - src/gps_denied/pipeline/sse_streamer.py + - src/gps_denied/testing/benchmark.py + modified: + - src/gps_denied/core/graph.py (shim) + - src/gps_denied/core/processor.py (shim) + - src/gps_denied/core/pipeline.py (shim) + - src/gps_denied/core/results.py (shim) + - src/gps_denied/core/sse.py (shim) + - src/gps_denied/core/benchmark.py (shim) + - src/gps_denied/core/chunk_manager.py (ABC→Protocol in-place) + - src/gps_denied/core/recovery.py (ABC→Protocol in-place) + - src/gps_denied/core/models.py (ABC→Protocol in-place) + - src/gps_denied/core/rotation.py (ABC→Protocol in-place) + - pyproject.toml (ruff per-file-ignores updated) + +decisions: + - "Protocol subclassing is valid Python — FactorGraphOptimizer(IFactorGraphOptimizer) kept as-is" + - "pipeline/result_manager.py imports from pipeline/sse_streamer.py directly, avoiding shim chain" + - "core/results.py and core/sse.py shims kept lean; no circular import issues" + - "pipeline/orchestrator.py internal imports updated to new paths; test shims handle old paths" + - "src/gps_denied/testing/harness.py and api/deps.py left using shim paths (backward-compat)" + +metrics: + duration: "~8 minutes" + completed: "2026-05-11" + tasks_completed: 6 + files_created: 7 + files_modified: 11 +--- + +# Phase 01-hexagonal-refactor Plan 07: Factor Graph, Pipeline Package, Benchmark, Protocol Conversions Summary + +**One-liner:** Extracted pipeline orchestration into `pipeline/` package, moved factor graph to `core/factor_graph.py`, benchmarks to `testing/benchmark.py`, and converted 5 ABCs to `typing.Protocol` with `@runtime_checkable`. + +## File Moves Performed + +| Source | Target | Method | +|--------|--------|--------| +| `core/graph.py` (IFactorGraphOptimizer) | `core/factor_graph.py` | Copy + ABC→Protocol, shim left at source | +| `core/processor.py` (FlightProcessor) | `pipeline/orchestrator.py` | Copy + internal imports updated, shim left at source | +| `core/pipeline.py` (ImageInputPipeline) | `pipeline/image_input.py` | Copy verbatim, shim left at source | +| `core/results.py` (ResultManager) | `pipeline/result_manager.py` | Copy + SSE import updated, shim left at source | +| `core/sse.py` (SSEEventStreamer) | `pipeline/sse_streamer.py` | Copy verbatim, shim left at source | +| `core/benchmark.py` (AccuracyBenchmark et al.) | `testing/benchmark.py` | Copy verbatim, shim left at source | + +## ABCs Converted to Protocol (5 total) + +| Interface | File | Method count | +|-----------|------|-------------| +| `IFactorGraphOptimizer` | `core/factor_graph.py` | 13 methods | +| `IRouteChunkManager` | `core/chunk_manager.py` | 6 methods | +| `IFailureRecoveryCoordinator` | `core/recovery.py` | 2 methods | +| `IModelManager` | `core/models.py` | 5 methods | +| `IImageMatcher` | `core/rotation.py` | 1 method | + +**Pattern applied to each:** +- Removed `from abc import ABC, abstractmethod` +- Added `from typing import Protocol, runtime_checkable` +- Replaced `class IXxx(ABC):` with `@runtime_checkable\nclass IXxx(Protocol):` +- Dropped `@abstractmethod` decorators; replaced `pass` bodies with `...` +- Concrete classes continue to subclass the Protocol (valid Python) + +## pyproject.toml Changes + +```diff + [tool.ruff.lint.per-file-ignores] +-"src/gps_denied/core/graph.py" = ["E501"] ++"src/gps_denied/core/factor_graph.py" = ["E501"] +-"src/gps_denied/core/metric.py" = ["E501"] ++"src/gps_denied/components/satellite_matcher/metric_refinement.py" = ["E501"] + "src/gps_denied/core/chunk_manager.py" = ["E501"] +``` + +## Test Counts + +| | Count | +|--|--| +| Baseline (before plan) | 216 passed, 8 skipped | +| After plan | 216 passed, 8 skipped | +| Regression floor met | YES | + +## Internal Import Updates in Non-Test Source Files + +`pipeline/orchestrator.py` (canonical location of `FlightProcessor`): +- `from gps_denied.core.pipeline import ImageInputPipeline` → `from gps_denied.pipeline.image_input import ImageInputPipeline` +- `from gps_denied.core.results import ResultManager` → `from gps_denied.pipeline.result_manager import ResultManager` +- `from gps_denied.core.sse import SSEEventStreamer` → `from gps_denied.pipeline.sse_streamer import SSEEventStreamer` + +`pipeline/result_manager.py` (canonical location of `ResultManager`): +- `from gps_denied.core.sse import SSEEventStreamer` → `from gps_denied.pipeline.sse_streamer import SSEEventStreamer` + +`src/gps_denied/testing/harness.py` and `src/gps_denied/api/deps.py`: left using legacy `core.*` shim paths — they continue to work transparently. + +## Protocol Conversion Edge Cases + +1. **`IFactorGraphOptimizer` in `core/factor_graph.py`**: The concrete class `FactorGraphOptimizer` subclasses the Protocol. Python allows this and it provides structural typing via `@runtime_checkable`. The existing `isinstance(x, IFactorGraphOptimizer)` calls in tests will work. + +2. **Long method signatures in `factor_graph.py`**: The `E501` ruff ignore was updated from `core/graph.py` to `core/factor_graph.py` — signatures like `add_relative_factor_to_chunk(...)` with 6 parameters exceed 120 chars. + +3. **`chunk_manager.py` import of `IFactorGraphOptimizer`**: Still imports from `gps_denied.core.graph` (which shims to `factor_graph`) — no change needed, backward-compat maintained. + +4. **`IImageMatcher` in `rotation.py`**: Used as a DI parameter type in `try_rotation_sweep`. Concrete implementations (e.g., `MetricRefinement` from `components/satellite_matcher`) are not subclasses but satisfy the Protocol structurally. + +5. **`IModelManager` return type `InferenceEngine`**: `InferenceEngine` is a Pydantic model, not changed. Protocol stub uses `...` which satisfies mypy for structural checks. + +## Deviations from Plan + +None — plan executed exactly as written. + +## Known Stubs + +None introduced by this plan. All moved code is functionally complete. + +## Threat Flags + +None. No new network endpoints, auth paths, or file access patterns introduced by these refactors. + +## Self-Check: PASSED + +Files created: +- FOUND: src/gps_denied/core/factor_graph.py +- FOUND: src/gps_denied/pipeline/__init__.py +- FOUND: src/gps_denied/pipeline/orchestrator.py +- FOUND: src/gps_denied/pipeline/image_input.py +- FOUND: src/gps_denied/pipeline/result_manager.py +- FOUND: src/gps_denied/pipeline/sse_streamer.py +- FOUND: src/gps_denied/testing/benchmark.py + +Commit: 5a60c1e — FOUND +Regression: 216 passed >= 216 baseline — PASSED