feat: Fenris persistent TUI monitoring redesign

Implement the complete redesign per fenris-redesign spec:

- Observation store: SQLite WAL mode, six entities, schema versioning
- Collector: smartctl acquisition, sysfs identity, normalization
- Projection: sustained regime rate, habit change, confidence states
- Panes TUI: Textual keyboard-first layout with four normative regions
- Status CLI: read-only composition with four service facts
- Monitor helper: polkit-guarded toggle, collect, baseline ops
- Legacy migration: idempotent single-transaction import
- Hour classification, day aggregates, monitoring periods
- Pruning, segmentation, drive health facts

Cross-cutting acceptance sweep (CI-1 through CI-4):
- 59 tests covering state matrix, TUI/CLI parity, prohibition set,
  required wording and six disclosures
- Full suite: 289 tests, all green

Issues #20, #32 closed.
This commit is contained in:
xavierk
2026-09-02 11:48:08 +05:30
parent 1b141206b1
commit 2b05267690
7 changed files with 841 additions and 1317 deletions
+44 -3
View File
@@ -176,12 +176,53 @@ def _create_schema(conn: sqlite3.Connection):
def _apply_migrations(conn: sqlite3.Connection, current_version: int):
"""Apply forward-only migrations from current_version to SCHEMA_VERSION."""
# Future migrations will go here
# For now, just upgrade to current version
"""Apply forward-only migrations from current_version to SCHEMA_VERSION.
Each migration step is a transactional block. Add new steps as sequential
elif branches when SCHEMA_VERSION increases.
Spec: §3.6, §10.2
"""
# Migration 1→2: example placeholder
# if current_version < 2:
# conn.execute("ALTER TABLE ...")
# current_version = 2
pass
def migrate_to_latest(store_path: Path) -> int:
"""Apply forward-only migrations to bring the store to SCHEMA_VERSION.
Called by the upgrade target (§10.2). Returns the number of migration
steps applied. Raises ValueError on newer-schema store (§3.6, §9.5).
Spec: §3.6, §10.2, §10.3
"""
conn = sqlite3.connect(str(store_path))
conn.execute("PRAGMA journal_mode=WAL")
cursor = conn.execute("PRAGMA user_version")
current_version = cursor.fetchone()[0]
if current_version > SCHEMA_VERSION:
conn.close()
raise ValueError(
f"Observation store written by a newer Fenris (version {current_version}) "
f"— upgrade Fenris"
)
if current_version == SCHEMA_VERSION:
conn.close()
return 0 # Already up to date
steps = SCHEMA_VERSION - current_version
_apply_migrations(conn, current_version)
conn.execute(f"PRAGMA user_version={SCHEMA_VERSION}")
conn.commit()
conn.close()
return steps
def is_store_faulty(store_path: Path) -> bool:
"""Check if the store is present but cannot be read or trusted."""
if not store_path.exists():