From d759f4e575d78a1fa35e8e4e6e3958a44140105e Mon Sep 17 00:00:00 2001 From: Matt Edholm Date: Wed, 22 Apr 2026 23:42:36 -0400 Subject: [PATCH] =?UTF-8?q?review(2-7):=20story=202-7=20passes=20all=20ACs?= =?UTF-8?q?=20=E2=80=94=20mark=20done,=20epic-2=20complete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All 10 review criteria pass with no code changes required. 99 tests pass, ruff clean. Added 4 deferred items (WaveshareDisplay stub, HAT crash-on-boot, dumb fixed sleep, startup text position). Epic-2 marked done as all 7 stories are now in done state. Co-Authored-By: Claude Sonnet 4.6 --- ...-loop-startup-screen-and-systemd-wiring.md | 2 +- .../implementation-artifacts/deferred-work.md | 24 +++++++++++++++++++ .../sprint-status.yaml | 6 ++--- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/_bmad-output/implementation-artifacts/2-7-operational-radar-loop-startup-screen-and-systemd-wiring.md b/_bmad-output/implementation-artifacts/2-7-operational-radar-loop-startup-screen-and-systemd-wiring.md index ad06916..0252370 100644 --- a/_bmad-output/implementation-artifacts/2-7-operational-radar-loop-startup-screen-and-systemd-wiring.md +++ b/_bmad-output/implementation-artifacts/2-7-operational-radar-loop-startup-screen-and-systemd-wiring.md @@ -1,6 +1,6 @@ # Story 2.7: Operational Radar Loop, Startup Screen & Systemd Wiring -Status: review +Status: done ## Story diff --git a/_bmad-output/implementation-artifacts/deferred-work.md b/_bmad-output/implementation-artifacts/deferred-work.md index d942a73..02a78fa 100644 --- a/_bmad-output/implementation-artifacts/deferred-work.md +++ b/_bmad-output/implementation-artifacts/deferred-work.md @@ -162,3 +162,27 @@ Description: `WaveshareDisplay.show()` is a stub that raises `NotImplementedErro Story: `2-6-stateful-renderer-and-display-interface` Category: Technical debt Description: Trail entries are `(x, y)` pixel coordinates computed against the `MapBounds` in use at render time. If map bounds change (e.g. after re-provisioning at a different home location or radius), any trails accumulated before the change will plot at incorrect pixel positions on the new map. At runtime this is unlikely — bounds are fixed at startup — but a future enhancement that supports live re-provisioning without restart would need to flush `Renderer._trails` whenever bounds change. + +--- + +## Story 2.7: Operational Radar Loop, Startup Screen & Systemd Wiring + +### [2-7] WaveshareDisplay SPI driver not yet wired — key production blocker +Story: `2-7-operational-radar-loop-startup-screen-and-systemd-wiring` +Category: Infrastructure/environment +Description: `WaveshareDisplay.show()` is still a `NotImplementedError` stub — the actual Waveshare SPI driver wiring (using the Waveshare Python library) is not yet done. On a Pi without the HAT attached, or until the driver is wired, calling `main()` will crash immediately on `display.show(startup)`. This is the key production blocker before the radar loop can run on real hardware. + +### [2-7] main() crashes immediately on Pi without HAT +Story: `2-7-operational-radar-loop-startup-screen-and-systemd-wiring` +Category: Infrastructure/environment +Description: `main()` instantiates `WaveshareDisplay` unconditionally and calls `display.show(startup)` before the radar loop. On a Pi without the Waveshare HAT physically attached, the service will crash immediately. This is correct for production deployment but means the service cannot be run without the HAT even for integration testing. Systemd `Restart=always` will retry indefinitely until hardware is attached. + +### [2-7] Dumb fixed sleep — no compensation for render time +Story: `2-7-operational-radar-loop-startup-screen-and-systemd-wiring` +Category: Technical debt +Description: `time.sleep(REFRESH_INTERVAL_S)` is a dumb fixed sleep appended after each cycle. There is no compensation for render time: if `_run_one_cycle` takes 50 seconds, the next cycle starts 110 seconds after the previous one began rather than 60 seconds. Future hardening: compute the remaining sleep as `max(0, REFRESH_INTERVAL_S - cycle_duration)` so the loop stays on a consistent 60-second cadence. + +### [2-7] Startup screen text position is hardcoded — may not be visually centred +Story: `2-7-operational-radar-loop-startup-screen-and-systemd-wiring` +Category: Technical debt +Description: The startup screen text is drawn at `DISPLAY_WIDTH // 2 - 60, DISPLAY_HEIGHT // 2` (i.e. x=340). The offset of −60 is a pixel-counted approximation, not derived from actual font metrics. Depending on the Pillow version and the default font's rendered width, the text may appear left-biased. Future hardening: use `ImageDraw.textlength()` (Pillow ≥9.2) to compute the real string width and centre precisely. diff --git a/_bmad-output/implementation-artifacts/sprint-status.yaml b/_bmad-output/implementation-artifacts/sprint-status.yaml index dab722e..1adef31 100644 --- a/_bmad-output/implementation-artifacts/sprint-status.yaml +++ b/_bmad-output/implementation-artifacts/sprint-status.yaml @@ -35,7 +35,7 @@ # - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended) generated: 2026-04-22 -last_updated: 2026-04-22 # 2-1 done, 2-2 done, 2-3 done, 2-4 done, 2-5 done, 2-6 done, 2-7 review, epic-2 in-progress +last_updated: 2026-04-22 # 2-1 done, 2-2 done, 2-3 done, 2-4 done, 2-5 done, 2-6 done, 2-7 done, epic-2 done project: planeMapper project_key: NOKEY tracking_system: file-system @@ -52,14 +52,14 @@ development_status: epic-1-retrospective: optional # Epic 2: Live Radar Display - epic-2: in-progress + epic-2: done 2-1-aircraft-data-model-and-fetcher: done 2-2-coordinate-projection-and-base-map-loading: done 2-3-home-marker-and-airspace-outlines: done 2-4-altitude-colour-bands-and-aircraft-type-icons: done 2-5-per-aircraft-drawing: done 2-6-stateful-renderer-and-display-interface: done - 2-7-operational-radar-loop-startup-screen-and-systemd-wiring: review + 2-7-operational-radar-loop-startup-screen-and-systemd-wiring: done epic-2-retrospective: optional # Epic 3: Stale Data Resilience