Documentation
¶
Overview ¶
Package aggregate computes structured statistics over []storage.Entry. It is the data layer for the rule-based commands brag summary (SPEC-018), brag review (SPEC-019), and brag stats (SPEC-020). Rendering lives in internal/export.
Index ¶
- Constants
- func IsAgentAuthored(e storage.Entry) bool
- func RollingBuckets(entries []storage.Entry, end time.Time, width time.Duration, n int) []int
- func SelfReferenceCount(entries []storage.Entry) int
- func Share(num, den int) float64
- func Streak(entries []storage.Entry, now time.Time) (current, longest int)
- func WithImpact(entries []storage.Entry) []storage.Entry
- type CadenceBucket
- type CorpusSpan
- type CoverageBucket
- type EntryRef
- type NameCount
- type ProjectCount
- type ProjectEntryGroup
- type ProjectHighlights
- type TypeCount
Constants ¶
const NoProjectKey = "(no project)"
NoProjectKey is the literal sentinel used in place of an empty- string Project. Locked by DEC-014; the markdown and JSON renderers both display this exact string.
Variables ¶
This section is empty.
Functions ¶
func IsAgentAuthored ¶ added in v0.4.0
IsAgentAuthored reports whether e carries a reserved provenance tag (agent:<name> or model:<id>, DEC-024) — the SINGLE Go-side definition of "agent-authored", kept in agreement with storage's provenanceExistsClause SQL predicate by TestProvenanceClassifier_GoPredicateMatchesSQLClause. It splits Entry.Tags (the comma-joined projection of the same taggings join the SQL clause queries) and prefix-matches each token, mirroring the LIKE 'agent:%' / 'model:%' anchoring: a topic tag like "agentic" or "modeling" (no colon) is NOT provenance. This is the classifier SPEC-043's --author filter reads in SQL; brag coverage reads it in Go so it can count BOTH classes from one query (SPEC-045 LD2/LD7).
func RollingBuckets ¶ added in v0.5.0
RollingBuckets buckets entries onto a fixed rolling axis of n buckets each `width` wide whose LAST bucket ends (exclusive) at end. The axis start is end.Add(-width*n); bucket k (0-indexed) covers [start+k*width, start+(k+1)*width) — lower-inclusive, upper-exclusive. Returns exactly n zero-filled counts (spark/JSON-ready); entries before start or at/after end are excluded, so sum(result) == the in-axis subset size. Pure, stdlib-only, instant-arithmetic (location-independent) — the sub-month analog of Cadence, which is calendar-month-only. SPEC-059/DEC-037.
func SelfReferenceCount ¶ added in v0.4.0
SelfReferenceCount returns how many entries mention "brag" (case-insensitive) in Title or Description — a proxy for dogfooding density (the corpus talking about the tool itself). Substring match: "brag" subsumes "bragfile" (SPEC-045 LD5).
func Share ¶ added in v0.4.0
Share is the exported alias of shareRound so the export renderer rounds the overall agent_share / self_reference.share identically to the per-month CoverageBucket.Share — one rounding definition, no drift (SPEC-045).
func Streak ¶
Streak returns (current, longest) streak counts in the user's LOCAL calendar day, where "local" is the zone carried by the injected now (now.Location()) — DEC-022. Entries are bucketed by converting each stored UTC instant into now.Location() before taking its date; storage itself stays UTC RFC3339 (only this derived metric localizes).
current is the length of the consecutive local-day run that ends on TODAY or YESTERDAY: the streak stays alive through yesterday and is 0 only once BOTH today and yesterday are empty (one day of grace, not immortality). longest is the longest consecutive local-day run anywhere in the corpus. Multiple entries on the same local date count as one streak day. Empty corpus → (0,0).
All day arithmetic uses calendar operations (AddDate + date-label compare), never instant subtraction, so it is correct across DST transitions. DEC-022; supersedes the UTC-day/requires-today semantics SPEC-020 §6 locked.
func WithImpact ¶ added in v0.4.0
WithImpact returns the subset of entries whose Impact field is non-empty, preserving input order. Used by brag impact (SPEC-048): the impact digest is impact-first — impact-less entries are counted in provenance but excluded from the grouped body. Empty input or an all-empty-impact input returns a non-nil empty slice (JSON callers never see null). Order is preserved deliberately: grouping (GroupEntriesByProject) does the sorting, not this filter.
Types ¶
type CadenceBucket ¶ added in v0.4.0
CadenceBucket is one month's entry count in a cadence series: Period is the "YYYY-MM" label, Count the number of entries whose created_at falls in that month. SPEC-051. SPEC-052 renders series[].Count as a sparkline, so this shape must not change without a paired test. The json tags are the on-the-wire shape the wrapped envelope (and SPEC-052) consume: series[].period / series[].count. They live on the aggregate struct because the struct itself is the sparkline-ready slot (LD8) — the export renderer embeds it directly rather than reprojecting.
func Cadence ¶ added in v0.4.0
func Cadence(entries []storage.Entry, months []string) (series []CadenceBucket, busiest string)
Cadence buckets entries by UTC calendar month, then emits one CadenceBucket per label in months order (zero-filled for months with no entries), plus the busiest-month label. months is the ordered set of "YYYY-MM" labels in scope (12 for a year, 3 for a quarter); the CLI derives it from the period so the series is always fully present, even on an empty period (every bucket zero, busiest ""). This is the sparkline-ready data slot (SPEC-052 reads series[].Count); it lives in aggregate — SQL-free, pure — so SPEC-052 and any future stats cadence reuse it (DEC-030 choice 5, LD8).
The busiest month is the first label (in months order) whose count is the maximum; ties break toward the earlier month. An all-zero series (empty period) returns "" for busiest so the caller renders null.
type CorpusSpan ¶
CorpusSpan describes the lifetime span of a corpus: First / Last CreatedAt (UTC) and Days inclusive on both endpoints. Empty corpus → zero-value (all three fields zero). SPEC-020.
func Span ¶
func Span(entries []storage.Entry) CorpusSpan
Span returns the CorpusSpan for entries: earliest CreatedAt as First, latest as Last (both UTC), and Days inclusive on both endpoints computed from UTC-truncated calendar dates. Empty corpus → zero-value struct. SPEC-020 §7.
type CoverageBucket ¶ added in v0.4.0
type CoverageBucket struct {
Period string `json:"period"`
Agent int `json:"agent"`
Human int `json:"human"`
}
CoverageBucket is one month's provenance split: Period is the "YYYY-MM" label, Agent/Human the classified counts, Share = Agent/(Agent+Human) rounded to 4 decimals (0 when the month is empty). SPEC-045. The json tags are the on-the-wire shape the coverage envelope embeds directly (LD8 of SPEC-051): by_month[].period / .agent / .human / .share.
func CoverageByMonth ¶ added in v0.4.0
func CoverageByMonth(entries []storage.Entry, months []string) []CoverageBucket
CoverageByMonth buckets entries by UTC calendar month, classifies each via IsAgentAuthored, and emits one CoverageBucket per label in months order (zero-filled). months is the ordered "YYYY-MM" set the CLI derives from the window (12 for a year, 3 for a quarter, N for --since) so the series is always fully present, even on an empty window. Mirrors Cadence (SPEC-051).
type EntryRef ¶
EntryRef is the projection of a storage.Entry that highlights carries: ID + Title only. Description, tags, project, type, timestamps are intentionally elided per SPEC-018's "skim before pasting" goal.
type NameCount ¶
NameCount is a generic top-N count: Name is the value (a tag string or a project string), Count is the occurrence count. Renderer-side callers wrap []NameCount into the per-spec semantic JSON shapes ({tag,count} / {project,count}). SPEC-020.
func MostCommon ¶
MostCommon returns up to n NameCount entries from values, ordered DESC by count with alpha-ASC tiebreak. Empty-string values are excluded from counting. Strict cap at n: when 6+ values tie at the boundary, alpha-ASC determines which n. Fewer than n distinct values returns however many exist (no padding). Empty input → non-nil empty slice. SPEC-020 §3.
type ProjectCount ¶
ProjectCount is one row of ByProject's result.
func ByProject ¶
func ByProject(entries []storage.Entry) []ProjectCount
ByProject is identical in shape to ByType, except entries with empty-string Project are rendered under NoProjectKey and forced LAST regardless of count (matches DEC-013's (no project)-last convention; locked by DEC-014).
type ProjectEntryGroup ¶
ProjectEntryGroup carries one project's full entries, used by brag review (SPEC-019). Mirrors ProjectHighlights's shape but retains the full storage.Entry instead of the EntryRef projection — JSON consumers (DEC-011 9-key per-entry shape) need descriptions and metadata that highlights elides.
func GroupEntriesByProject ¶
func GroupEntriesByProject(entries []storage.Entry) []ProjectEntryGroup
GroupEntriesByProject mirrors GroupForHighlights's grouping + sort logic exactly: alpha-ASC by project name with NoProjectKey last; chrono-ASC within group with ID as tiebreak. Differs only in carrying full storage.Entry (not EntryRef). Used by review's markdown path (renders id+title only at render time) and review's JSON path (serializes full DEC-011 shape).
type ProjectHighlights ¶
ProjectHighlights is one project's group of entries.
func GroupForHighlights ¶
func GroupForHighlights(entries []storage.Entry) []ProjectHighlights
GroupForHighlights returns project groups in alpha-ASC order with NoProjectKey forced last; within each group, entries are sorted ASC by CreatedAt with ID as tie-break (AGENTS.md §9 SPEC-002 monotonic-tiebreak rule).