feat(coverage): emit the hourly activity histogram - #60
Open
Sarcastic-Soul wants to merge 1 commit into
Open
Conversation
Coverage.hour_histogram (local hour -> active minutes) has been computed since the module was written and read by nothing: not by build_frames, not by any emitter, not by the docs. The per-frame datetime.fromtimestamp().astimezone() call in coverage() exists solely to fill it. Rather than delete a genuinely useful measure -- Coverage is exported in __all__, so removing the field is a small API break -- surface it as coverage.active_minutes_by_hour. It is additive to the schema and reaches get_day_summary for free, since that tool returns the coverage dict whole. Documents the field in SPEC.md section 3, including that an absent hour means "not captured", not "idle" -- the gaps list is what tells those apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Not a bug fix, so no issue — this is a small feature, raised directly as a PR.
What I found
Coverage.hour_histogram— local hour → active minutes — has been computed since the module was written and read by nothing. Greppingsrc/,tests/, and the docs, it's written atsessionize.py:333and consumed nowhere.build_framesbuilds itscoveragedict field by field and skips it; no emitter mentions it; SPEC.md §3 doesn't list it.It isn't free, either. This line in
coverage()'s per-frame loop:exists solely to fill that histogram. Measured at 2.9µs/frame against 0.05µs for the minute-bucket arithmetic beside it — roughly 60ms of dead work on a 20k-frame day.
Why surface it rather than delete it
Deleting is the smaller diff, but
Coverageis exported in__all__, so dropping a public dataclass field is an API break for anyone reading it directly. And the measure is genuinely useful — "when did the active minutes actually fall" is a question the document can't currently answer without walking every frame and re-deriving the shape.So: emit it.
The change
added to the
coveragedict inbuild_frames. Named to sit beside the existingactive_minutesrather than carrying the internalhour_histogramname into the public schema.Three things follow for free:
get_day_summarypicks it up with no change, since it returnsd["coverage"]whole.context_blockandto_markdownare unaffected — both select named fields, so the compact agent-facing block doesn't grow.Example, from the test fixture:
which sums to the
active_minutes: 60reported alongside it.Docs
SPEC.md §3 gains the field with the one caveat worth stating explicitly:
That matches the section's existing framing ("consumers must treat anything outside covered time as unknown, not as inactivity"). CHANGELOG.md gets an
### Addedentry under[Unreleased].Tests
Three in
tests/test_sessionize.py:test_hour_histogram_partitions_active_minutes— the invariant that makes the field trustworthy: every active minute lands in exactly one hour bucket, so the values sum toactive_minutesrather than double-counting at bucket edges.test_hour_histogram_reaches_the_document— emitted value matchescoverage()exactly, and still sums to the reported total.test_hour_histogram_empty_window_is_empty— empty window yields{}, not a missing key or 24 zeroes.Full suite: 110 passed (107 before, +3).
Compatibility
Purely additive: one new key in
coverage. No existing field changes name, type, or value, andschema_versionstays at 1 — consistent with how the schema has grown before (wall_min,interruptions,omitted).One note: this is the only one of my six PRs that touches
CHANGELOG.md, since it's the only one changing the documented schema. I left the changelog alone in the others so six branches wouldn't all collide on the same file — happy to add entries for them if you'd rather they carried their own.