Choose daily graph encoding and hourly drill-down #68
Notifications
Due Date
No due date set.
Blocks
Depends on
#69 Approve titlebox, health layout and colour presets
xavierk/Fenris
#70 Approve the Fenris TUI polish specification and handoff
xavierk/Fenris
Reference: xavierk/Fenris#68
Reference in New Issue
Block a user
Parent map: Fenris TUI polish and hourly history
Question
Which graph encoding and interaction model best communicates hourly writes and a day's usage without misleading users?
HITL prototype, plus grilling + domain-modeling. Wait for the hourly-history contract. Use a cheap throwaway visual/interaction artifact for human reaction, not production implementation. Verify relevant framework capability against current docs; do not infer support from library names.
Approved direction: bytes written per hour default; amber graph in default theme; keyboard and clickable controls for range → day → hourly detail → back. Reads are optional, not promised.
Compare hourly bars with one candle per day derived from hourly values. Define exactly what open/high/low/close, body, wick, unit, daily total and partial day would mean; reject candles if they obscure usage or manufacture unavailable values. Decide whether reads earn a selector or remain out of scope. Resolve default horizon, available ranges, date/time-zone labels, selected-day details, navigation keys/focus/back behavior, empty/zero/gap rendering and minimum terminal behavior. No fabricated history; gaps remain distinguishable from zero.
Answer must link the prototype and record live human choice with rationale, legends, controls and example data states. This ticket cannot be resolved by the agent choosing on the human's behalf.
Prototype checkpoint — artifact ready for live reaction, not a resolution
Live human choice still required; this ticket cannot be resolved by the agent choosing on the human's behalf.
Asset: branch prototype/graph-encoding — run
prototype/graph-encoding/run, or reviewscreenshots/*.svg(80×24 and 140×40 per variant). Throwaway; not for main.Three structurally different encodings, each rendering the same synthetic 14-day evidence with every contract state present (measured 0 B, gap ≠ zero, unallocated stacked separately, partial day "so far", pre-monitoring day, deliberate-disable annotation):
╎column = no evidence.Interaction (all variants): ←/→ select, Enter drill, Esc/Backspace back, mouse click maps widget-local x to a column. Legend always on screen.
Framework facts verified against current docs + installed Textual 8.2.8: no BarChart widget exists (roadmap-only), Sparkline is non-interactive, textual-plotext is a separate uninstalled package. Bars/candles/strip therefore require a custom block-glyph renderable in the usage-history pane (as prototyped); clicks arrive as widget-local coordinates, keyboard via bindings+focus. No new dependency needed for variant A or B.
Open decisions going to live grilling: encoding choice (recommendation: reject candles — they bury the daily total, price-like OHLC implies dynamics usage data does not have, and gap/partial semantics distort bodies), reads selector scope, default horizon + offered ranges, label format, navigation keys/focus interaction with existing global bindings, minimum terminal size behavior.
Resolution — daily bars with hourly drill-down; candles rejected
Live grilling this session: human accepted all recommendations Q1–Q7. Prototype asset: branch prototype/graph-encoding (run
prototype/graph-encoding/run; SVG exports inscreenshots/at 80×24 and 140×40). Throwaway branch, not for main.Encoding (Q1)
Adopted: one bar per local display day (bytes written), drill into 24 hourly bars. Range view → selected day → hourly detail → back, as approved at charting.
Candles rejected. Their tested semantics were: open = first evidenced hourly value of the day, close = last, high/low = max/min hourly GB, body solid when close ≥ open / hollow when close < open / dashed when partial,
╎column = no evidence, unit GB per hour. Rejection rationale: bodies bury the daily total (users track the sum, not intraday shape), OHLC imports price-chart dynamics usage data does not have, and gap/partial evidence contorts bodies into misleading shapes. Daily total therefore remains the explicit bar+readout value, never manufactured from candle geometry.Rolling-strip variant rejected as default: no day totals without adding the day level drill-down already provides.
Scope (Q2)
Reads stay out of scope: writes-only graph. Charting approved writes-per-hour; reads would add a data path and axis for a metric the endurance projection never consumes. Revisit only as a fresh effort after handoff.
Ranges (Q3)
Default horizon 14 days; selectable 7 / 14 / 28 / 90 days, mirroring the 7/28/90 scenario-range horizons so graph and projection share vocabulary. Ranges limit the viewport only — retained history browsing and older controller segments unchanged per the accepted hourly-history contract.
Labels (Q4)
Header line:
usage history · Local · UTC±HH:MM · <tz name>— current system timezone, always visible. Day row under bars: day-of-month. Selected-day readout:Wed 09 Sep. Hourly detail: every third hour00…21plusmidnight → 23:00 local. DST 23/25-hour days and repeated local hours follow the accepted local-display-day contract.Controls (Q5)
Graph pane focusable: ←/→ select, Enter drill, Esc/Backspace back, mouse click selects (widget-local x → column),
1/2/3/4switch the four ranges. No conflict with global bindings p/r/c/d/q, which stay unchanged. Footer shows graph keys while the graph is focused.State rendering (Q6)
Always-visible legend, distinct glyphs:
█allocated,▒unallocated stacked on top (measured, attribution unknown — never spread into hours),░gap = no evidence (never zero),·measured 0 B,┄partial-day cap,▼selection marker. Selected-item readout states totals, evidenced hours, unallocated separately, coverage, andpartial · N h elapsed · so far. Example data states exercised in the prototype: measured-zero day, gap day, unallocated day, heavy day, partial today, pre-monitoring day, deliberate-disable annotation.Minimum terminal (Q7)
At 80×24 the range view fits fully (14 days × 4 columns) and drill-down fits (24 single-column hourly bars). Below 80×24 the graph region hides and shows a one-line textual history summary plus
graph needs ≥80×24— no error; the readout survives.Framework obligation (verified, not assumed)
Installed Textual 8.2.8 has no BarChart widget (roadmap-only) and a non-interactive Sparkline; textual-plotext is not a dependency. Implementation therefore requires a custom block-glyph renderable in the usage-history pane with click mapped from widget-local coordinates. No new dependency.
Effect on the map
No new tickets graduate: remaining cross-cutting usability fog (combined degraded states, constrained layouts) stays fog until the layout/monitoring-signal prototypes surface concrete questions. Read-throughput selector is recorded out of scope on the map. Planning only — no production code changed.