- src/stats/: OwnEmailMatcher (config emails + GH no-reply per account) +
git-side --author filtering (cheap even on the pterodactyl fork's 4700+
commits); streak (current/longest, midnight-grace rule), 52-week heatmap,
day/hour histograms — one scan feeds all of them, data layer only for now
(visual Stats-tab redesign stays in Sprint D's mockup-first cycle)
- src/stats/cadence.rs: release cadence (median tag gap, local tags, Tier A)
- src/stats/size.rs + cache.rs: git-object vs working-tree size, persisted
in new ~/.vulp/stats_cache.toml (max 1 sample/day), recorded only during
[R]/vulp refresh — confirms vulp's own filter-repo cleanup (539MB->834KB)
- src/digest.rs: WeeklyDigest struct + 3 renderers (Discord embed/markdown
archive/plaintext); vulp digest [send discord|webhook <url>] CLI, webhook
stored via existing auth token store (~/.vulp/.tokens, 0600), never logged;
send respects --dry-run
- TUI: [d] on Stats previews the digest in a Modal::Info before anything is
ever sent
- fix: list_contributors used --all (double-counts after fetching remotes),
now --branches
- config: stats_author_emails field (TUI-editable)
- verified: streak/delta/top-repo/release math against a hand-built commit
history, webhook validation+permissions, dry-run, real refresh (51 repos,
vulp's own entry confirms the filter-repo win), TUI preview via pyte
- Provider::org_dependabot_counts: one org-level request per distinct owner
(cursor pagination via Link header — page= returns 400 on this endpoint);
403/404 → None (unknown) vs Some(0) = checked, none open
- Provider::latest_ci_status: latest Actions run on the repo's branch →
success/failure/running; CiStatus enum with stable string form
- cache RepoMeta: ci_status + dependabot_open replace unused ci_ok;
RepoSummary carries both, applied at startup/scan/refresh (TUI + CLI)
- Repos table: CI column (✓/✗/●) + ALERT column (count, red when >0,
'—' = unknown); CLI: list --alerts filter, scan_repos now cache-enriched
- verified against live API: 49 repos, 44 with alert counts, CI statuses
match reality; table rendering checked via pyte
- global --dry-run: sync/release/init/collab/license print 'DRY RUN: would...'
and exit 0 (no auth needed for previews where possible)
- config protected_repos (name/basename, case-insensitive): mutating commands
exit 1 on listed repos unless --force; checked before dry-run
- VULP_AGENT env: activity::log centrally appends '· via agent' to detail,
covering both CLI and TUI writers
- sync: unknown --action now rejected before touching any repo