With topN=7 the previous collapseOther kept only the first 6 entries
and added "Other" as the 7th row. A user expecting to see 7 actual
languages in the legend saw six named languages plus "Other" — the
exact complaint just raised about the profile repo's donut.
Flip the semantic: the "top N" slots are reserved for real languages,
and "Other" is an extra row when (and only when) there's a non-zero
tail past the Nth entry. Topologically that means up to 8 legend
rows — still fits the card frame (row 8 text baseline at y=195, card
height 200).
- TestDonutTopSevenPlusOther pins the new contract with a 9-language
input.
- adversarialProfile in TestCardsFitFrame bumped to 9 languages so
the stress test exercises the 8-row legend geometry.
- design-guidelines: the donut row re-reads "Up to 7 named languages,
plus an 'Other' row when the tail is non-zero (8 rows max)".
project-roadmap.md went from a 146-line phase-by-phase history to a
48-line focused view: what's planned, what's out of scope. Completed
work is already in git log + GitHub Releases — the doc re-telling it
was the thing most likely to rot and least likely to be read.
project-overview-pdr.md: "Open questions" section dropped its stale
bullet list and now just points at project-roadmap.md (single source of
truth for planned work).
code-standards.md: drop the ".claude/ directory" commit rule — that's
a per-user workflow detail, not a project-level standard. Docs are for
users of the CLI/Action and coworkers of this repo, nothing else.
The repo is already listed on the Marketplace as ghstats-cards, so the
multi-paragraph "open the release page, tick the checkbox, re-publish"
instruction was stale. Replace with a one-line note pointing at the
existing listing and stating that new releases inherit visibility
automatically.
2026-04-19 10:26:57 +07:00
7 changed files with 85 additions and 149 deletions
- Visibility defaults flipped on: `-include-forks`, `-include-private` now default `true` (private silently no-ops if token lacks scope).
- Output filenames dropped the numeric prefix: `0-profile-details.svg` → `profile-details.svg` etc. Embedders reference by name.
- Card dimensions shrunk `500×220` → `340×200` to match github-profile-summary-cards so two cards fit per row in a README.
- Action `action.yml` name set to `ghstats-cards` for Marketplace (the bare `ghstats` is taken); repo stays `tiennm99/ghstats`.
-`v1.0.0`, `v1.1.0`, `v1.1.1` tagged and released. Prebuilt binaries (linux/darwin/windows × amd64/arm64) ship with each; Docker image pushed to `ghcr.io/tiennm99/ghstats`.
- Floating `v1` major tag created; `release.yml` has an `update-major-tag` job that force-moves `v1` to the latest patch after test+docker+binaries pass, so consumers pinned to `tiennm99/ghstats@v1` auto-pick new releases.
- README badges (Marketplace / Release / License) + direct Marketplace link for cross-navigation.
- An attempted repo rename to `tiennm99/ghstats-cards` was committed and reverted (commits `399a3dc` + `8bd2128` on record) — GHCR path immutability and the cost of breaking pinned consumers outweighed the Marketplace-name cosmetic benefit.
## Phase 7.6 — S-tier breadth cards (✅ done)
Five new cards that ride on data already fetched — zero extra API calls:
-`contributions-heatmap` — canonical 7×53 calendar grid with a theme-derived 5-bucket intensity ramp.
-`contributions-by-year` — one bar per active year, peak year highlighted.
-`productive-weekday` + `productive-weekday-all-time` — mirror the hour-of-day pair; `FetchProductive` now also fills `Weekday` / `WeekdayAllTime` histograms.
-`top-starred-repos` — top 5 owned non-fork repos by ⭐; required threading `Stars` through `RepoInfo`.
-`streak` — current + longest streak + active days/total. Pure post-processing of `DailyContributionsAllTime`.
Card count: 9 → 15 (weekday adds LY + AT variants). `FetchProductive` still pays for commit-history pagination once; the new cards are pure renderers.
- New `.github/workflows/demo.yml` renders every card for every theme against the repo owner's profile on each push to `main`.
- Output lands in `demo/<theme>/` (SVGs + a `README.md` for that theme pairing last-year / all-time variants side-by-side); top-level `demo/README.md` is a zero-image index linking to each theme page, so opening the gallery doesn't force a reader to fetch 975 SVGs at once.
- Loop prevention: workflow skips pushes that only touch `demo/**`, `**.md`, or `LICENSE`; `GITHUB_TOKEN`-driven pushes don't retrigger workflows by design.
- Consumer impact: none — this is a repo-internal discovery aid, not a shipped feature.
**Goal**: fix the Markdown-blog misattribution case (and any repo where linguist's byte view disagrees with what files user actually edited).
**Approach**: `GET /repos/{owner}/{repo}/commits/{sha}` per commit → classify each file with `go-enry`. Weight by `additions + deletions`.
**Cost**: ~1 REST call per commit. At current defaults (30 seed repos × 500 commits = 15,000 commits worst case) this is heavy — needs `-accurate-languages` opt-in flag, schedule weekly not daily.
**Research**: see `plans/reports/researcher-260418-2001-accurate-language-stats.md`.
**Status**: designed, not implemented.
## Phase 9 — Partial bare clone for lifetime all-repo stats (planned)
**Goal**: lifetime language stats across **every** repo a user has committed in, without the 500-commits-per-repo cap.
**Goal**: let users drop throwaway repos (experiments, forks they stashed) from stats without disabling forks globally.
**Approach**: `-exclude-repo owner1/name1,owner2/name2` flag. Filter seed list before probing.
**Cost**: negligible (client-side filter).
**Status**: pending user demand.
## Phase 11 — Expand ownerAffiliations (planned)
**Goal**: catch work done in org repos where user is a collaborator, not owner (e.g., company monorepos).
**Approach**: expose `-affiliations OWNER,COLLABORATOR,ORGANIZATION_MEMBER` flag. Requires thinking about whether to *display* private org work on a public profile card.
**Status**: blocked on deciding the privacy default.
---
## Known limitations (not roadmap items — by design)
## Out of scope (by design)
| Limitation | Reason |
| --- | --- |
| Markdown/prose excluded from byte counts | Linguist's default; we defer to linguist |
| No real-time API | Scope: scheduled batch renderer, not a server |
| No WakaTime integration | Out of scope — WakaTime cards already exist (athul/waka-readme, anmol098/waka-readme-stats) |
| No heatmap (7×24) variant of productive time | Simplified to 24-hour bar chart to match reference project |
| Hard width of 340 px per card | Matches github-profile-summary-cards; customising would cascade through every chart's geometry. |
## Tracked research reports
All in `plans/reports/`:
-`researcher-260418-2001-accurate-language-stats.md` — metrics vs GRS vs go-enry feasibility
-`researcher-260418-2012-profile-stats-survey.md` — follow-up survey across 6 more tools
-`analysis-260418-2140-most-commit-language-all-time.md` — hand-reconstruction of tiennm99's card output, showing exactly why each language lands where
-`code-review-260418-2223-full-project.md` — adversarial review of the whole codebase; findings all closed in Phase 6
| Markdown/prose excluded from byte counts | Linguist's default — we defer to it |
| No real-time API / server mode | Scheduled batch renderer, not a service |
| No WakaTime integration | Other tools already cover this (`athul/waka-readme`, `anmol098/waka-readme-stats`) |
| No 7×24 heatmap variant of productive time | 24-hour bar chart matches the reference project |
| Hard 340 px card width | Matches github-profile-summary-cards; customising would cascade through every chart's geometry |
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.