paranoid: UsageAudit history & drill-down — Slice A wrap-up +
Slice B (PARANOID-p5i.7)
Log
Session 20:00 (paranoid)
Closed loose end: Slice A code (PARANOID-p5i.6) was
uncommitted at start of session — the bead was closed two sessions ago
(2026-04-30 morning) but the code never made it onto main.
Committed as 09a34b1 so Slice B work could proceed safely
on top of it.
Implemented Slice B (PARANOID-p5i.7) via TDD —
committed as d9b9403:
Domain (B.1/B.2):HourlyBucket model +
DailyUsageAggregator.hourlyDistribution(...) walking the
window in one-hour real-time steps. On a 23-hour spring-forward local
day the result has 23 buckets, on a 25-hour fall-back day 25 buckets, 24
otherwise. Tests cover all three cases plus partial-overlap slice math
(HourlyDistributionTest, 5 cases).
Presentation (B.3–B.6):DayDetailScreenState extended with
hourlyBars: List<HourlyBar> and
overnightSummary: OvernightSummaryRow?.
DayDetailPresenter.present(...) now takes
hourlyBuckets (default empty for back-compat) and an
optional OvernightAudit. Overnight panel only renders when
the audit's windowStart is inside the selected day.
HourlyBar exposes a 0..1 intensity for simple bar
rendering. Tests added in DayDetailPresenterTest for hourly
counts on normal + spring-forward day and overnight in/out-of-day.
UI: Day Detail layout adds an hourly-bars
container, an overnight summary panel, and Share Summary / Export CSV
buttons. UsageAuditDayDetailActivity renders bars and
overnight panel, and wires the buttons to the selected day's
summary.
Data layer:UsageAuditData.recentDayHourlyBuckets: Map<Long, List<HourlyBucket>>
precomputes per-day buckets keyed by day-start; matching overnight comes
from the existing recentNights list.
Share/CSV (B.7/B.8):UsageAuditExportTest tests confirm
TodaySummaryFormatter/CsvExporter.exportToday
are reused on the selected day's summary — v1 schema preserved (no
hourly/interval columns), window_start scoped to the chosen
day.
All unit tests green via just test. OpenSpec
strict-validates. Bead PARANOID-p5i.7 closed.
Decisions:
Hourly bucket walk uses += 3_600_000 real-time steps
rather than Calendar.add(HOUR_OF_DAY, 1) — equivalent under
DST since the day window is already 23/24/25h, and avoids ambiguity
around the spring-forward "phantom" hour. Bucket boundaries naturally
align to local clock hours when the window starts at local
midnight.
Reused existing
TodaySummaryFormatter/CsvExporter.exportToday
for Day Detail Share/CSV instead of introducing a
DayDetailFormatter. The v1 schema applies cleanly to any
day.
Did not extend DailyUsageSummary with hourly buckets to
avoid loading the domain model with rendering-shaped data; instead,
buckets are precomputed alongside the summary in the data provider and
looked up in the activity by day-start.
Next: Slice B.9 tidy (extract a
LocalDateRange day-window helper) and tasks.md 3.7 (unify
Today and Day Detail rendering paths) — both deferred. Slice C
(PARANOID-p5i.8) is App Detail drill-down:
UsageStatsManager.queryEvents adapter for per-app
foreground intervals, App Detail screen, no-activity +
uninstalled-package states, Day Detail row → App Detail navigation.
Manual device verification (PARANOID-p5i.9) still pending.