docs(spec): assemble dashboard clarity spec, DC-1–DC-8 criteria, TUI-4 amendment (wayfinder #60)
This commit is contained in:
@@ -91,7 +91,7 @@ Status: Accepted — resolves [Define cross-cutting acceptance criteria](https:/
|
|||||||
- **TUI-1** (A) Variant A "Panes": one dense keyboard-first screen; confidence rendered as evidence (state + contributing facts); boot enablement, runtime activity, last collect outcome, and freshness displayed as four separate facts.
|
- **TUI-1** (A) Variant A "Panes": one dense keyboard-first screen; confidence rendered as evidence (state + contributing facts); boot enablement, runtime activity, last collect outcome, and freshness displayed as four separate facts.
|
||||||
- **TUI-2** (M) Pause/resume asymmetry and polkit tty passthrough work in a live terminal: pause confirms, resume does not, and the platform agent prompts without breaking the TUI.
|
- **TUI-2** (M) Pause/resume asymmetry and polkit tty passthrough work in a live terminal: pause confirms, resume does not, and the platform agent prompts without breaking the TUI.
|
||||||
- **TUI-3** (P) Textual runs on Python 3.9+, gated at install time, never a runtime crash.
|
- **TUI-3** (P) Textual runs on Python 3.9+, gated at install time, never a runtime crash.
|
||||||
- **TUI-4** (A) The Panes screen layout is normative: a full-width headline band (lifespan headline or its no-projection wording, confidence state with contributing facts, scenario range); a usage-history pane on the left (write-history sparkline with ▲ habit-change and ? unexplained-gap markers plus legend, habit-split bar with active/idle/powered-off/unknown shares); a drive-health and settings pane on the right (health facts, vendor-wear context line, read-only settings with the endurance baseline and its provenance label); a full-width service strip at the bottom (the four separate service facts, the monitoring-period line, the action legend). Production bindings are `p` pause (asks), `r` resume (does not), `c` collect now, `d` disclosures, `q` quit ([Prototype the TUI information architecture](https://git.bongbetic.com/xavierk/Fenris/issues/3)); the prototype branch is visual reference only.
|
- **TUI-4** (A) The Panes screen layout is normative: a full-width headline band (lifespan headline or its no-projection wording, confidence state with contributing facts, scenario range); a usage-history pane on the left (write-history sparkline with ▲ habit-change and ? unexplained-gap markers plus legend, habit-split bar with active/idle/powered-off/unknown shares); a drive-health and settings pane on the right (health facts, vendor-wear context line, read-only settings with the endurance baseline and its provenance label); a full-width service strip at the bottom (the four separate service facts, the monitoring-period line, the action legend). Production bindings are the footer `p pause · r resume · c collect · d disclosures` — pause asks, resume does not — plus a bordered quit rail `q QUIT TUI` visually separate from monitoring state; the rail owns quit and the footer carries no quit entry (bindings amended by [Lock the dashboard wording strings](https://git.bongbetic.com/xavierk/Fenris/issues/57); original [Prototype the TUI information architecture](https://git.bongbetic.com/xavierk/Fenris/issues/3)); the prototype branch is visual reference only.
|
||||||
|
|
||||||
## Failure and recovery (ADR 0005)
|
## Failure and recovery (ADR 0005)
|
||||||
|
|
||||||
@@ -131,3 +131,16 @@ Status: Accepted — resolves [Define cross-cutting acceptance criteria](https:/
|
|||||||
- **AC-3** (A) Any acquisition failure — missing binary, nonzero exit, malformed JSON, unreadable sysfs attribute — fails the whole collection run; no partial sample (identity without counters, or counters without identity) is ever written; the miss surfaces through ADR 0005 freshness, never as degraded identity.
|
- **AC-3** (A) Any acquisition failure — missing binary, nonzero exit, malformed JSON, unreadable sysfs attribute — fails the whole collection run; no partial sample (identity without counters, or counters without identity) is ever written; the miss surfaces through ADR 0005 freshness, never as degraded identity.
|
||||||
- **AC-4** (P) `vid`/`ssvid` are read from the PCI sysfs node when present and stored null otherwise; they are segment metadata only, never key components.
|
- **AC-4** (P) `vid`/`ssvid` are read from the PCI sysfs node when present and stored null otherwise; they are segment metadata only, never key components.
|
||||||
- **AC-5** (P) `make install` verifies `smartctl` and fails cleanly otherwise; the acquisition path adds no Python dependency and no OS package beyond smartmontools (ADR 0004 §9).
|
- **AC-5** (P) `make install` verifies `smartctl` and fails cleanly otherwise; the acquisition path adds no Python dependency and no OS package beyond smartmontools (ADR 0004 §9).
|
||||||
|
|
||||||
|
## Dashboard clarity and release notes ([Chart Fenris dashboard clarity](https://git.bongbetic.com/xavierk/Fenris/issues/55))
|
||||||
|
|
||||||
|
Decided in [Write the dashboard clarity acceptance criteria](https://git.bongbetic.com/xavierk/Fenris/issues/59), from [Prototype the dashboard clarity additions](https://git.bongbetic.com/xavierk/Fenris/issues/56), [Lock the dashboard wording strings](https://git.bongbetic.com/xavierk/Fenris/issues/57), and [Specify the changelog and release-notes mechanism](https://git.bongbetic.com/xavierk/Fenris/issues/58).
|
||||||
|
|
||||||
|
- **DC-1** (A) TUI branding: the header bar renders `Fenris — NVMe endurance monitor`; a dimmed `by Bongbetic` sits inline with service facts in the bottom service strip; neither string appears in `fenris status` (TUI-only identity surfaces).
|
||||||
|
- **DC-2** (A) Continuity parity, keyed to the boot fact as-is: active + boot-enabled renders `monitoring: active in background · persists across reboots`; boot-disabled renders `monitoring: does not start on next boot` — identical lowercase source strings in the TUI service strip and `fenris status`, including while paused (paused implies boot-disabled; the row still reports the fact). Test impact: feeds the CI-2 sweep (lowercase source-string comparison).
|
||||||
|
- **DC-3** (A) Paused presentation (Deliberate disable): the TUI shows a strong state block titled `monitoring: paused — deliberate disable` with subline `paused time is excluded from your usage habit · resume: fenris monitor resume`; `fenris status` prints the same two lines with identical wording. Test impact: feeds the CI-2 sweep (lowercase source-string comparison).
|
||||||
|
- **DC-4** (A) Quit affordance distinct from monitoring state: a bordered labelled rail `q QUIT TUI` visually separate from the paused state block; the footer reads `p pause · r resume · c collect · d disclosures` with no quit entry (the rail owns quit); quitting the TUI never alters monitoring state. Amends TUI-4's binding parenthetical.
|
||||||
|
- **DC-5** (A) Launch auth banner: `privileged actions will prompt for authentication (polkit)` renders full-width under the header at TUI launch, clears on the first refresh tick, and never reappears in the session; no user-facing string uses "sudo" (polkit-accurate elevation wording only).
|
||||||
|
- **DC-6** (A) CHANGELOG.md shape (Keep a Changelog 1.1): `## [Unreleased]` always present at top, even empty; version headings `## [X.Y.Z] - YYYY-MM-DD` with strict ISO date; categories Added/Changed/Fixed only, security folding into Fixed; entries are single `- ` bullets, imperative mood, user-facing, no commit hashes or issue numbers.
|
||||||
|
- **DC-7** (A) Extraction fails closed: `scripts/extract_changelog.py` slices the requested version's section verbatim and never reads `[Unreleased]`; a missing or empty section or a malformed date produces `::error::` and a nonzero exit; the release workflow fails when the pushed tag ≠ `v{version from pyproject.toml}` (guard skipped on `workflow_dispatch`).
|
||||||
|
- **DC-8** (A/P) Release body: the body is the extracted section verbatim plus the standing footer from `packaging/release-footer.md`; a re-run against an existing release PATCHes the body (re-sync is a feature) while uploaded assets skip idempotently. A covers assembly/PATCH-logic unit tests; P is one scripted `workflow_dispatch` verification of body assembly.
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
# Fenris dashboard clarity specification
|
||||||
|
|
||||||
|
**Status: decision-complete.** Assembled by [Assemble the dashboard clarity specification and close the map](https://git.bongbetic.com/xavierk/Fenris/issues/60) from the closed tickets of the Wayfinder map [Chart Fenris dashboard clarity](https://git.bongbetic.com/xavierk/Fenris/issues/55). This document is normative for the follow-up **execution effort**; nothing here is implemented by the map.
|
||||||
|
|
||||||
|
**Canonical roles.** The [redesign specification](fenris-redesign.md) (frozen) and [ADRs 0001–0007](../adr/) remain authoritative and untouched — this is a companion spec covering five dashboard clarity additions plus the changelog-driven release-notes mechanism. The [criteria register](acceptance-criteria.md) carries the testable statements: **DC-1–DC-8**, appended by this assembly, with **TUI-4's binding list amended** (§4). Terminology follows the glossary in [`CONTEXT.md`](../../CONTEXT.md), including *Deliberate disable* and *Release*.
|
||||||
|
|
||||||
|
**Binding language.** *Must*, *exactly*, and *never* are normative.
|
||||||
|
|
||||||
|
## How to read this document
|
||||||
|
|
||||||
|
Five screen additions (§1–§5), one release-notes mechanism (§6), the verbatim string register (§7), and the README section to add at execution (§8). Each section cites its criteria. Source strings are lowercase; the TUI may render uppercase via styling only. Typography, governing every string: em-dash `—` separates a title from its qualifier; middle dot `·` joins facts within a line; UTF-8 is assumed. CI parity sweeps compare lowercase source strings — rendering case is styling, not wording.
|
||||||
|
|
||||||
|
## 1. Header bar and Bongbetic credit — DC-1
|
||||||
|
|
||||||
|
Visual base is treatment A, quiet integration: the existing Panes information architecture is preserved.
|
||||||
|
|
||||||
|
- The header bar reads `Fenris — NVMe endurance monitor`.
|
||||||
|
- The credit `by Bongbetic` renders dimmed, inline with service facts in the bottom service strip — never in the action row.
|
||||||
|
- Both are TUI-only identity surfaces: `fenris status` never renders them.
|
||||||
|
|
||||||
|
## 2. Continuity line — DC-2
|
||||||
|
|
||||||
|
A labelled `CONTINUITY` row in the service strip (treatment B), mirrored by `fenris status` — the TUI/CLI parity anchor. The row is keyed to the boot fact as-is, independently of run state (Deliberate disable runs `systemctl disable --now`, so paused implies boot-disabled; the row still reports the fact):
|
||||||
|
|
||||||
|
- Active + boot enabled: `monitoring: active in background · persists across reboots`
|
||||||
|
- Boot disabled: `monitoring: does not start on next boot`
|
||||||
|
|
||||||
|
Identical lowercase source strings in the TUI service strip and `fenris status`, including while paused.
|
||||||
|
|
||||||
|
## 3. Paused state block — DC-3
|
||||||
|
|
||||||
|
Treatment C, strong state blocks: when monitoring is paused, a full-width, high-contrast banner clearly identifying Deliberate disable:
|
||||||
|
|
||||||
|
- Title: `monitoring: paused — deliberate disable`
|
||||||
|
- Subline: `paused time is excluded from your usage habit · resume: fenris monitor resume`
|
||||||
|
|
||||||
|
`fenris status` prints the same two lines with identical wording (state line + consequence line). The resume hint uses the CLI form only; the footer owns key hints — no duplication.
|
||||||
|
|
||||||
|
## 4. Quit rail — DC-4 (amends TUI-4)
|
||||||
|
|
||||||
|
Treatment B, labelled rails: a prominent bordered `q QUIT TUI` rail, visually separate from the monitoring-state block and the paused banner. The footer becomes `p pause · r resume · c collect · d disclosures` — the rail owns quit; the footer carries no quit entry. Quitting the TUI never alters monitoring state. The register's TUI-4 binding parenthetical is amended accordingly by this assembly.
|
||||||
|
|
||||||
|
## 5. Launch auth banner — DC-5
|
||||||
|
|
||||||
|
A quiet informational line (treatment A) that never competes with drive state:
|
||||||
|
|
||||||
|
- Text: `privileged actions will prompt for authentication (polkit)`
|
||||||
|
- Full-width under the header at TUI launch; clears on the first refresh tick; never reappears in the session.
|
||||||
|
- TUI-only; `fenris status` never shows it.
|
||||||
|
- Elevation wording is polkit-accurate everywhere: no user-facing string uses "sudo" (sudo belongs to install/upgrade docs).
|
||||||
|
- Evidence class A: a Textual pilot drives refresh ticks headlessly.
|
||||||
|
|
||||||
|
## 6. Changelog and release notes — DC-6, DC-7, DC-8
|
||||||
|
|
||||||
|
Implements the existing glossary term *Release* (tag + packages + change notes together). No new glossary terms; no ADR (reversible mechanism).
|
||||||
|
|
||||||
|
### 6.1 CHANGELOG.md (source of truth, repo root)
|
||||||
|
|
||||||
|
- Keep a Changelog 1.1 shape. `## [Unreleased]` is always present at top, even empty. Version headings are `## [X.Y.Z] - YYYY-MM-DD` — bracketed bare semver, strict ISO date.
|
||||||
|
- Categories are `### Added`, `### Changed`, `### Fixed` only; security fixes fold into Fixed.
|
||||||
|
- Entries are single `- ` bullets, imperative mood, user-facing phrasing; no commit hashes or issue numbers.
|
||||||
|
|
||||||
|
### 6.2 Extraction (release.yml, tag time)
|
||||||
|
|
||||||
|
- `scripts/extract_changelog.py` (checked in, unit-tested): takes the changelog path and a version; slices that version's section verbatim; never reads `[Unreleased]`. Fails closed — `::error::` plus nonzero exit — when the section is missing or empty or the date is malformed.
|
||||||
|
- Guard: the workflow fails when the pushed tag ≠ `v{version from pyproject.toml}` (guard skipped on `workflow_dispatch`).
|
||||||
|
|
||||||
|
### 6.3 Release body
|
||||||
|
|
||||||
|
- Body = extracted version section verbatim + standing footer from `packaging/release-footer.md` (channel install one-liners, `sha256sum -c SHA256SUMS.asc` verify, rollback pointer). The footer is standing text; only the changelog section varies.
|
||||||
|
- Re-run against an existing release: PATCH the body (changelog re-sync is a feature); uploaded assets/packages keep their current idempotent-skip.
|
||||||
|
|
||||||
|
### 6.4 Discipline
|
||||||
|
|
||||||
|
- All entries land in `[Unreleased]` as part of the fixing change — no notes-later step.
|
||||||
|
- One release commit bumps the pyproject version, renames `[Unreleased]` → the version heading, and restores an empty `[Unreleased]`; the tag points at that commit (tag ↔ pyproject ↔ changelog triple-match, enforced fail-closed by DC-7).
|
||||||
|
- No backfill: per-release notes begin with the release shipping this mechanism; `CHANGELOG.md` starts with empty `[Unreleased]`.
|
||||||
|
|
||||||
|
## 7. String register (verbatim)
|
||||||
|
|
||||||
|
### TUI-only strings (launch/identity surfaces)
|
||||||
|
|
||||||
|
| Surface | String |
|
||||||
|
|---|---|
|
||||||
|
| Header bar | `Fenris — NVMe endurance monitor` |
|
||||||
|
| Credit (dimmed, inline with service facts) | `by Bongbetic` |
|
||||||
|
| Auth banner (full-width under header at launch, clears on first refresh tick, never reappears) | `privileged actions will prompt for authentication (polkit)` |
|
||||||
|
| Quit rail (bordered, labelled) | `q QUIT TUI` |
|
||||||
|
| Footer (owns key hints; no quit entry) | `p pause · r resume · c collect · d disclosures` |
|
||||||
|
|
||||||
|
### Parity strings (TUI and `fenris status` identical — CI-2)
|
||||||
|
|
||||||
|
| Surface | String |
|
||||||
|
|---|---|
|
||||||
|
| Continuity, active + boot enabled | `monitoring: active in background · persists across reboots` |
|
||||||
|
| Continuity, boot disabled | `monitoring: does not start on next boot` |
|
||||||
|
| Paused state line | `monitoring: paused — deliberate disable` |
|
||||||
|
| Paused consequence line | `paused time is excluded from your usage habit · resume: fenris monitor resume` |
|
||||||
|
|
||||||
|
`fenris status` prints the paused state line + consequence line when paused, identical wording to the banner title + subline.
|
||||||
|
|
||||||
|
## 8. README section (add at execution)
|
||||||
|
|
||||||
|
The README gains a "Reading the dashboard" section after the CLI reference. Verbatim text:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Reading the dashboard
|
||||||
|
|
||||||
|
`fenris` opens the TUI dashboard. Three things it tells you:
|
||||||
|
|
||||||
|
- **Continuity** — the service strip's continuity line (and `fenris status`) reports whether monitoring survives reboots: `monitoring: active in background · persists across reboots`, or `monitoring: does not start on next boot`.
|
||||||
|
- **Paused vs. quit** — a full-width `monitoring: paused — deliberate disable` block means collection is stopped (`fenris monitor pause`); resume with `fenris monitor resume`. Pressing `q` only leaves the screen — monitoring keeps running in the background.
|
||||||
|
- **Auth banner** — at launch, `privileged actions will prompt for authentication (polkit)` shows once and clears on the first refresh. Privileged actions elevate via polkit; Fenris never asks for sudo.
|
||||||
|
|
||||||
|
Per-release notes live on the [releases page](https://git.bongbetic.com/xavierk/Fenris/releases): each entry is the version's `CHANGELOG.md` section — what was added, changed, and fixed — plus standing install and verification instructions.
|
||||||
|
```
|
||||||
|
|
||||||
|
This resolves the map's README-wording fog: the wording is decided here; the actual README edit is execution.
|
||||||
|
|
||||||
|
## 9. Out of scope
|
||||||
|
|
||||||
|
Executing any of this — code, tests, releases — and any TUI layout or information-architecture redesign beyond the five additions named above. Execution is a fresh effort after handoff.
|
||||||
Reference in New Issue
Block a user