The _add_unattributed_bytes function was adding the same cross-hour
delta to both days when the interval spanned midnight, violating the
spec requirement to preserve measured volume once as shared boundary
evidence.
Store the unattributed bytes only on the day where the interval starts
(the earlier day). This ensures the total across both days equals the
actual delta without duplication.
Closes#88 (cross-day delta duplication portion)
Repair the collection-to-display path so each successful acquisition
publishes correct read/write deltas through the observation store and
visible dashboard.
Fixes:
- derive.py: accumulate bytes_read_delta on same-hour hour_observation
merge (was silently dropped)
- collector.py: rebuild day_aggregates from hour observations after
each collection run (previously only populated for cross-hour intervals)
- day_aggregate.py: add persist_day_aggregate upsert helper
- tui.py: query and display both read and write deltas in daily and
hourly readouts, constrained summaries, and graph data queries
Tests:
- Add 14 integration tests (test_measured_activity.py) exercising the
full collector→store→reader→display path with real fixtures and
injected time
- Update constrained-layout assertion to match new W/R format
Closes#89
- Schema migration 1-2: add segment_id to samples, unattributed bytes to day_aggregates
- Collector now derives hour observations and day aggregates from sample pairs
- Cross-hour deltas tracked as unattributed (no proportional allocation)
- Display states: 0 samples -> awaiting first, 1 sample -> awaiting another
- Monitoring period ensured open on each collection run
- Derivation failures preserve prior history
Closes#73