aggregate

package
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 13, 2026 License: MIT Imports: 5 Imported by: 0

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

View Source
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

func IsAgentAuthored(e storage.Entry) bool

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

func RollingBuckets(entries []storage.Entry, end time.Time, width time.Duration, n int) []int

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

func SelfReferenceCount(entries []storage.Entry) int

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

func Share(num, den int) float64

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

func Streak(entries []storage.Entry, now time.Time) (current, longest int)

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

func WithImpact(entries []storage.Entry) []storage.Entry

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

type CadenceBucket struct {
	Period string `json:"period"`
	Count  int    `json:"count"`
}

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

type CorpusSpan struct {
	First time.Time
	Last  time.Time
	Days  int
}

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"`
	Share  float64 `json:"share"`
}

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

type EntryRef struct {
	ID    int64
	Title string
}

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

type NameCount struct {
	Name  string
	Count int
}

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

func MostCommon(values []string, n int) []NameCount

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

type ProjectCount struct {
	Project string
	Count   int
}

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

type ProjectEntryGroup struct {
	Project string
	Entries []storage.Entry
}

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

type ProjectHighlights struct {
	Project string
	Entries []EntryRef
}

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).

type TypeCount

type TypeCount struct {
	Type  string
	Count int
}

TypeCount is one row of ByType's result.

func ByType

func ByType(entries []storage.Entry) []TypeCount

ByType returns entries grouped by Type, ordered DESC by count with alphabetical-ASC tiebreak. Empty input returns a non-nil empty slice (so JSON renders [] not null).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL