feat(2-7): operational radar loop, startup screen, and systemd wiring
Implements story 2-7: full main.py with _make_startup_screen(), _run_one_cycle() with per-phase timing and slow-render warning, and main() connecting config → bounds → fetcher → renderer → display. Adds provision.py early-exit when already provisioned. Adds User=root to both systemd service files. Adds tests/test_main.py (3 new tests, 99 total). Updates scaffold test to allow provisioning.config import from main.py. All quality gates pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,12 +73,13 @@ def test_constants_colours_complete() -> None:
|
||||
assert constants.FETCH_TIMEOUT_S == 5
|
||||
|
||||
|
||||
def test_main_does_not_import_provisioning() -> None:
|
||||
def test_main_only_imports_config_from_provisioning() -> None:
|
||||
"""main.py may import planemapper.provisioning.config (to read stored config)
|
||||
but must not import other provisioning sub-modules (portal, wifi, tiles, etc.)."""
|
||||
allowed = {"planemapper.provisioning.config"}
|
||||
main_path = REPO_ROOT / "src" / "planemapper" / "main.py"
|
||||
tree = ast.parse(main_path.read_text())
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, (ast.Import, ast.ImportFrom)):
|
||||
if isinstance(node, ast.ImportFrom) and node.module:
|
||||
assert not node.module.startswith("planemapper.provisioning"), (
|
||||
"main.py must not import from planemapper.provisioning"
|
||||
)
|
||||
if isinstance(node, ast.ImportFrom) and node.module:
|
||||
if node.module.startswith("planemapper.provisioning"):
|
||||
assert node.module in allowed, f"main.py must not import from {node.module}"
|
||||
|
||||
Reference in New Issue
Block a user