Render on/off-task split in the reflection block
This commit is contained in:
@@ -263,9 +263,10 @@ func (c *Controller) startReflectionFetchLocked() {
|
||||
}
|
||||
|
||||
// buildReflectionFinishedLocked renders the just-finished session as a compact
|
||||
// block for the reviewer. Caller holds mu; c.stats/c.commitment are still set
|
||||
// (End clears them, but enterReview runs before End). Reuses bucketViews for the
|
||||
// per-window totals, already sorted desc by seconds.
|
||||
// block for the reviewer: the commitment, the outcome, on/off/unclassified time
|
||||
// totals, and a top-N on-task list and top-N off-task list. The split fields are
|
||||
// populated live by creditLocked. Caller holds mu; c.stats/c.commitment are still
|
||||
// set (End clears them, but enterReview runs before End).
|
||||
func (c *Controller) buildReflectionFinishedLocked() string {
|
||||
var na, sc string
|
||||
if c.commitment != nil {
|
||||
@@ -280,17 +281,43 @@ func (c *Controller) buildReflectionFinishedLocked() string {
|
||||
fmt.Fprintf(&b, "Success condition: %s\n", sc)
|
||||
fmt.Fprintf(&b, "Outcome: %s\n", outcome)
|
||||
if c.stats != nil {
|
||||
onMin := int64(sumDurations(c.stats.OnTask).Seconds()) / 60
|
||||
offMin := int64(sumDurations(c.stats.OffTask).Seconds()) / 60
|
||||
unclMin := int64(c.stats.unclassified.Seconds()) / 60
|
||||
fmt.Fprintf(&b, "On-task %dm / Off-task %dm / Unclassified %dm\n", onMin, offMin, unclMin)
|
||||
fmt.Fprintf(&b, "Context switches: %d\n", c.stats.SwitchCount)
|
||||
for i, bv := range bucketViews(c.stats.Buckets) {
|
||||
if i >= reflectionTopBuckets {
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(&b, "- %s · %s: %dm\n", bv.Class, bv.Title, bv.Seconds/60)
|
||||
}
|
||||
writeBucketList(&b, "On-task", c.stats.OnTask)
|
||||
writeBucketList(&b, "Off-task", c.stats.OffTask)
|
||||
}
|
||||
return strings.TrimRight(b.String(), "\n")
|
||||
}
|
||||
|
||||
// writeBucketList renders a labeled, time-descending list of buckets capped at
|
||||
// reflectionTopBuckets. It writes nothing — not even the label — when the map is
|
||||
// empty, so a single-sided session shows only the list that has time.
|
||||
func writeBucketList(b *strings.Builder, label string, m map[bucketKey]time.Duration) {
|
||||
views := bucketViews(m)
|
||||
if len(views) == 0 {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(b, "%s:\n", label)
|
||||
for i, bv := range views {
|
||||
if i >= reflectionTopBuckets {
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(b, "- %s · %s: %dm\n", bv.Class, bv.Title, bv.Seconds/60)
|
||||
}
|
||||
}
|
||||
|
||||
// sumDurations totals the durations in a bucket map.
|
||||
func sumDurations(m map[bucketKey]time.Duration) time.Duration {
|
||||
var total time.Duration
|
||||
for _, d := range m {
|
||||
total += d
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// buildReflectionHistory renders the last few prior sessions as compact lines.
|
||||
// The just-finished session is not yet in the chain (End appends it), so it is
|
||||
// not double-counted. Returns "" when there is no usable history.
|
||||
|
||||
Reference in New Issue
Block a user