Merge origin/main into main

Reconcile the staged-projection and Diagnostics feature work with the CI
quality-gate changes from origin/main. The origin side of every conflict was
lint-only, so the feature imports were kept and the ruff fixes re-applied:

- keep the branch's added imports (timefmt, activity_readout, projection
  ladder helpers) and drop the unused ones ruff reported
- restore `noqa: E402` on the post-bootstrap imports in fenris-monitor and
  keep the `noqa: F401` re-exports in the TUI that tests assert on
- make the TUI monitoring-glyph test clock-relative instead of pinned to a
  fixed date
This commit is contained in:
xavierk
2026-10-06 10:14:09 +05:30
53 changed files with 288 additions and 229 deletions
+9 -21
View File
@@ -13,29 +13,22 @@ import sqlite3
from xml.etree import ElementTree
from datetime import datetime, timedelta, timezone
from pathlib import Path
from unittest.mock import patch, MagicMock
from unittest.mock import patch
import pytest
import sys
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from textual.app import App
from textual.pilot import Pilot
from fenris.store import init_store, SCHEMA_VERSION
from fenris.monitoring_periods import ensure_period_open, close_period
from fenris.store import init_store
from fenris.monitoring_periods import ensure_period_open
from fenris.projection import (
ConfidenceState,
compute_projection,
DISCLOSURES,
WARMING_MIN_DAYS,
STALENESS_HOURS,
YOUNG_REGIME_DAYS,
)
from fenris.status import (
FRESH_THRESHOLD_S,
STALENESS_THRESHOLD_S,
grade_freshness,
)
from fenris.activity_readout import (
@@ -47,7 +40,6 @@ from fenris.tui import (
FenrisTuiApp,
HistoryGraph,
_format_remaining,
_RANGE_OPTIONS,
_RANGE_DEFAULT,
_MIN_WIDTH,
_MIN_HEIGHT,
@@ -285,7 +277,7 @@ class TestDenseScreen:
conn.close()
app = FenrisTuiApp(store_path=tmp_path / "test.db")
async with app.run_test() as pilot:
async with app.run_test():
assert app.query_one("#headline-band") is not None
assert app.query_one("#usage-history") is not None
assert app.query_one("#drive-health") is not None
@@ -305,7 +297,7 @@ class TestDenseScreen:
conn.close()
app = FenrisTuiApp(store_path=tmp_path / "test.db")
async with app.run_test() as pilot:
async with app.run_test():
headline = str(app.query_one("#headline-band").render())
assert "remaining" in headline.lower() or "projection" in headline.lower()
@@ -323,7 +315,7 @@ class TestDenseScreen:
conn.close()
app = FenrisTuiApp(store_path=tmp_path / "test.db")
async with app.run_test() as pilot:
async with app.run_test():
headline = str(app.query_one("#headline-band").render())
assert "projection confidence" in headline.lower()
# Contributing facts shown, never a percentage as confidence
@@ -345,7 +337,7 @@ class TestDenseScreen:
conn.close()
app = FenrisTuiApp(store_path=tmp_path / "test.db")
async with app.run_test() as pilot:
async with app.run_test():
strip = str(app.query_one("#service-strip").render())
assert "Boot:" in strip
assert "Timer:" in strip
@@ -486,7 +478,6 @@ class TestDenseScreen:
auth_notice = "Open with fenris (no sudo). Actions authenticate via polkit. ? Help"
async with app.run_test() as pilot:
headline = str(app.query_one("#headline-band").render())
# Identity now shows Fenris by Bongbetic (issue #79)
assert "Fenris by Bongbetic" in str(app.query_one("#identity").render())
assert auth_notice in str(app.query_one("#auth-notice").render())
@@ -528,7 +519,7 @@ class TestDisclosuresAndGreeting:
async def test_empty_store_greeting(self, tmp_path):
"""Empty store shows 'no observations yet' with enable hint."""
app = FenrisTuiApp(store_path=tmp_path / "nonexistent.db")
async with app.run_test() as pilot:
async with app.run_test():
headline = str(app.query_one("#headline-band").render())
assert "no observations yet" in headline.lower()
assert "enable" in headline.lower() or "resume" in headline.lower()
@@ -593,9 +584,8 @@ class TestFirstRun:
async def test_first_run_prompt(self, tmp_path):
"""First-run prompt makes the keyboard action and boot effect explicit."""
app = FenrisTuiApp(store_path=tmp_path / "nonexistent.db")
async with app.run_test() as pilot:
async with app.run_test():
headline = str(app.query_one("#headline-band").render())
strip = str(app.query_one("#service-strip").render())
assert "no observations yet" in headline.lower()
assert "r resume — enable monitoring and future boots" in headline.lower()
assert "r resume" in str(app.query_one("#action-rail").render()).lower()
@@ -868,7 +858,6 @@ class TestQueryHourlyGraphData:
class TestHistoryGraph:
def test_empty_data(self, tmp_path):
"""Empty data shows awaiting message."""
app = FenrisTuiApp(store_path=tmp_path / "nonexistent.db")
# We test the widget directly via the app's compose
graph = HistoryGraph()
# Simulate setting empty data
@@ -1131,7 +1120,6 @@ class TestBarGraphTUI:
app = FenrisTuiApp(store_path=tmp_path / "nonexistent.db")
async with app.run_test(size=(80, 24)) as pilot:
await pilot.press("v", "v")
graph = app.query_one("#usage-history")
assert app.query_one("#activity-panel").border_title == "Drive activity"
@pytest.mark.asyncio