Skip to content

fix: correctness pass on dates, author matching and breakdowns; add team compare - #4

Merged
juangracia merged 5 commits into
mainfrom
worktree-portfolio-ready
Aug 17, 2026
Merged

juangracia merged 5 commits into
mainfrom
worktree-portfolio-ready

Conversation

@juangracia

@juangracia juangracia commented Aug 17, 2026 •

Copy link
Copy Markdown
Owner

Pre-launch correctness pass. Every finding below was reproduced against purpose-built fixture repos with known-correct answers, and the important ones now have regression tests.

Bugs fixed

1. Date ranges were wrong (most serious). Bounds were passed to git as bare YYYY-MM-DD. git parses those with approxidate in the local timezone, which silently drops commits near day boundaries. On a UTC-03 machine, asking for 4 March returned 5 March's commits and missed 4 March entirely. Since --until defaults to "now", today's commits could vanish from any report. All five git-argument sites now pass explicit RFC3339 timestamps.

2. --until excluded the day you named. --until=2025-03-05 stopped at midnight and dropped all of 5 March. A new ParseDateEnd widens an end bound to cover the whole named day, month or year. The one-day fudge in cadence.go that compensated for the old behaviour, and over-included the prior day, is removed.

3. Team totals double-counted contributors. git --author is a substring regex against Name <email>, so jo@corp.com also matched bojo@corp.com. A two-person repo with 10 and 25 lines reported a team total of 60 instead of 35. Full addresses are now anchored on the angle brackets and matched with --fixed-strings; bare name fragments still match loosely.

4. Monthly commit counts counted files. m.Commits++ sat inside the per-file loop, so one commit touching two files reported as two commits in JSON and HTML.

5. --breakdown=weekly and =daily did nothing. Both advertised in --help, accepted without error, and silently ignored in terminal, JSON and HTML. Per-day buckets are now collected during parsing and all three granularities render everywhere. Weeks anchor on Monday.

6. Team mode used a different divisor. It computed daily average over the active commit span while single-author mode used the requested period, so identical data gave different answers. 687e85d fixed this for one path and missed the other.

7. An unreadable git config user.email silently reported the whole repo as your work. The error was discarded, leaving an empty author pattern that matched every commit.

Also: commit headers were detected with strings.Contains(line, "|"), so a filename containing a pipe would be misread as a new commit; now matched on the 40-hex sha shape.

Features

  • compare --team, the top roadmap gap. Before/after across a group with a per-member table, which is what a team AI-adoption audit actually needs. Members with no "before" output report n/a rather than a meaningless ratio.
  • Lead time no longer gives up without merge commits. It falls back to committer-minus-author date on main, which rebase and patch workflows preserve. Verified empirically that GitHub squash merges rewrite both timestamps, so that case has no signal in git history and now says so instead of implying zero.

Polish

  • Unknown --breakdown / --output / --theme values error instead of being ignored
  • Reversed and future date ranges error instead of returning silent zeros
  • Runtime failures no longer dump the entire help screen
  • ANSI colours suppressed when stdout is not a terminal, and when NO_COLOR is set
  • --file warns when the output format cannot use it
  • Comparison tables size their period column to the label instead of overflowing a fixed 16 chars
  • Empty commit-size distributions are hidden rather than rendering all zeros

Tests

First tests for internal/git (16 cases), covering the date-boundary, commit-counting and author-substring regressions specifically. CI added in the first commit runs build/test on Linux, macOS and Windows plus vet, gofmt and a CLI smoke test.

Verification

  • go build, go vet, go test, gofmt -l all clean
  • All 5 CI checks green on all three platforms
  • ~60 CLI scenarios against fixture repos with known ground truth
  • 20 JSON output paths verified as parseable with no NaN/Infinity
  • 7 HTML paths verified with no unrendered template directives and no NaN
  • HTML escaping confirmed safe against a <script> author email

The README's `go install github.com/juangracia/gitrespect@latest` fails
because the module has no main package at its root. Point it at
./cmd/gitrespect, which is the actual entry point.

Add a CI workflow covering build/test on Linux, macOS and Windows, plus
go vet, gofmt and a CLI smoke test that exercises terminal, JSON and HTML
output. Pin both workflows to the Go version in go.mod instead of a
hardcoded 1.23, which had drifted from the required 1.25.5.

Rewrite three metric empty states that read as bugs rather than absences:
lead time now explains that squash-merge repos have no merge commits,
churn names the window it looked at, and cadence reports sample count and
no longer prints "Median 0.0 days" for sub-day commit gaps.

Also refresh the stale --help text that still described industry
benchmarks, and add CI/report-card/release/license badges.
@juangracia juangracia self-assigned this Aug 17, 2026
… compare

The most serious bug: date bounds were passed to git as bare YYYY-MM-DD
strings. git parses those with approxidate in the local timezone, which
silently drops commits near day boundaries. Asking for a single day
returned the wrong day's commits, and since --until defaults to "now",
today's work could vanish from every report. All five git-argument sites
now pass explicit RFC3339 timestamps via git.TimeArg.

Relatedly, --until now covers the whole named day, month or year via a new
ParseDateEnd, so "--until 2025-03-05" includes 5 March instead of stopping
at midnight. Absolute dates resolve in local time, matching --year. The
one-day fudge in cadence.go that compensated for the old behaviour, and
over-included the prior day, is removed.

Monthly breakdown counted commits once per changed file, so a single
commit touching two files reported as two commits in JSON and HTML.
Commits are now counted on the commit header. Commit headers are matched
on the 40-hex sha shape rather than a bare "|", so a filename containing
a pipe is no longer mistaken for a new commit.

--breakdown advertised weekly and daily but only monthly was ever
implemented; the other two were accepted and silently ignored in all
three output formats. Per-day buckets are now collected during parsing
and all three granularities render in terminal, JSON and HTML.

Team mode computed its daily average over the active commit span while
single-author mode used the requested period, so the same data gave
different answers. 687e85d fixed this for one path and missed the other.

New: compare --team, the top roadmap gap. Before/after now works across a
group of authors with a per-member table, which is what the team
AI-adoption story actually needs. Members with no output in the before
period report n/a rather than a meaningless ratio.

Lead time no longer just gives up when a repo has no merge commits. It
falls back to committer-minus-author date on main, which rebase and patch
workflows preserve. Squash merges rewrite both dates and genuinely leave
nothing to measure, so that case now says so instead of implying zero.

Also: unknown --breakdown/--output/--theme values now error instead of
being ignored; reversed and future date ranges error instead of returning
silent zeros; runtime failures no longer dump the whole help screen; ANSI
colours are suppressed when stdout is not a terminal and when NO_COLOR is
set; --file warns when the output format cannot use it; comparison tables
size their period column to the label.

Adds the first tests for internal/git, covering the date-boundary and
commit-counting regressions above.
git matches --author as a substring regex against "Name <email>", so
"jo@corp.com" also matched "bojo@corp.com". In team mode that inflated the
first member's totals and double-counted the team: a two-person repo with
10 and 25 lines reported 60 instead of 35.

Full addresses are now anchored on the angle brackets git puts around the
email and matched with --fixed-strings, which also stops "." in an address
behaving as a regex wildcard. Bare name fragments still match loosely, so
"-a alice" keeps working.

Also refuse to run when no author can be determined. Previously a failure
to read git config user.email was ignored, leaving an empty pattern that
matched every commit and reported the entire repository as one person's
work.
An all-zero distribution rendered when the range contained no commits.
HTML already gated on Total > 0; terminal now matches.
…mits

The bundled agent skill stated that compare does not accept --team, which
is no longer true and would have steered agents to the wrong invocation.
Also documents inclusive --until semantics, Monday-anchored weeks, NO_COLOR
support, and why lead time reports no signal on squash-merge repos.
@juangracia juangracia changed the title fix: correct go install path, add CI, clarify empty-state output fix: correctness pass on dates, author matching and breakdowns; add team compare Aug 17, 2026
@juangracia
juangracia merged commit 96180d4 into main Aug 17, 2026
5 checks passed
@juangracia
juangracia deleted the worktree-portfolio-ready branch August 17, 2026 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant