diff --git a/docs/code-standards.md b/docs/code-standards.md index 75bd7216..701308e9 100644 --- a/docs/code-standards.md +++ b/docs/code-standards.md @@ -73,7 +73,6 @@ Never write comments that describe what well-named code does (`// increment coun - Conventional commit prefixes: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `build:`, `ci:`, `chore:`. - Scope is optional: `refactor(card): …`. -- Never use `chore:` or `docs:` for `.claude/` directory changes (project rule). - No AI references. No "generated by" footers. Keep the subject ≤ 72 chars. ## Pre-commit checklist diff --git a/docs/project-overview-pdr.md b/docs/project-overview-pdr.md index 3ba0e986..3ab99d87 100644 --- a/docs/project-overview-pdr.md +++ b/docs/project-overview-pdr.md @@ -60,9 +60,6 @@ Distinguishing traits: - Test suite covers rendering, XML escaping, number formatting, language sort. - `go vet ./...` and `go test ./...` clean on every commit. -## Open questions / tracked roadmap items +## Open questions -- Per-commit REST classification (`-accurate-languages`) -- Partial bare clone mode for lifetime all-repo language stats -- `-exclude-repo` flag to drop known noise repos -- Expose `ownerAffiliations` beyond OWNER (COLLABORATOR, ORGANIZATION_MEMBER) +Planned follow-on work lives in [`project-roadmap.md`](./project-roadmap.md). diff --git a/docs/project-roadmap.md b/docs/project-roadmap.md index c2f89a27..91adf954 100644 --- a/docs/project-roadmap.md +++ b/docs/project-roadmap.md @@ -1,146 +1,48 @@ -# Project Roadmap +# Roadmap -## Phase 0 — Skeleton (✅ done) +What's planned next and what's intentionally out of scope. Completed work lives in the git log and GitHub Releases; this file doesn't rehash it. -- Module layout, flag parsing, placeholder SVG renderers. +## Planned -## Phase 1 — Five core cards (✅ done) +### Per-commit file classification (`-accurate-languages`) -- Profile details, repos-per-language, most-commit-language, stats, productive-time. -- GraphQL profile query + per-repo commit history. -- Docker-based Action wrapper, release workflow, 65-theme palette. +Fix the Markdown-blog misattribution case (and any repo where linguist's byte view disagrees with the files the user actually edited). -## Phase 2 — Chart quality (✅ done) +- **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; opt-in flag, schedule weekly not daily. +- **Research**: `plans/reports/researcher-260418-2001-accurate-language-stats.md`. +- **Status**: designed, not implemented. -- Match github-profile-summary-cards visual style (donuts, 24h bar chart, proper axes). -- Octicon labels on profile + stats cards. -- Smooth area chart for contributions (Catmull-Rom → cubic Bezier). +### Partial bare clone for lifetime language stats (`-deep`) -## Phase 3 — All-time variants (✅ done) +Lifetime language stats across every repo a user has committed in, without the 500-commits-per-repo cap. -- Unified commit-history fetch splits into last-year and all-time buckets. -- Per-year `contributionsCollection` loop yields `DailyContributionsAllTime` + `TotalCommitsAllTime`. -- Three new cards: most-commit-language-all-time, productive-time-all-time, contributions-all-time. -- Stats card gains a lifetime commits row. +- **Approach**: `git clone --filter=blob:none --bare` per seed repo + `git log --author --numstat` → go-enry. +- **Cost**: ~5 % of full-clone disk (trees only); 3–5 min runtime for 100 repos; zero REST calls. +- **Trade-off**: needs disk + git binary on runner. +- **Status**: researched only; would land behind `-deep`. -## Phase 4 — Accurate repo sampling (✅ done) +### User-configurable repo exclusion (`-exclude-repo`) -- Seed list built from `commitContributionsByRepository` across every active year. -- `-include-forks` / `-include-private` visibility flags (defaults later flipped on in Phase 7). -- `-top-repos` demoted to an optional cap (default 0 = unlimited). -- Commit-history query takes `$owner` so forks and non-owned repos are probeable. +Drop throwaway repos (experiments, stashed forks) from stats without turning off `include_forks` globally. -## Phase 5 — Byte-weighted attribution (✅ done) +- **Approach**: `-exclude-repo owner1/name1,owner2/name2` flag. Client-side filter on the seed list before probing. +- **Status**: pending user demand. -- Each commit distributes fractionally across repo's language bytes, not just primary. -- Improves mixed-code repo accuracy; still inaccurate for Markdown-heavy repos (linguist prose-exclusion). +### Expanded `ownerAffiliations` -## Phase 6 — Code-review remediation (✅ done) +Catch work in org repos where the user is a collaborator rather than owner. -Follow-up after the full-project review (`plans/reports/code-review-260418-2223-full-project.md`): +- **Approach**: expose `-affiliations OWNER,COLLABORATOR,ORGANIZATION_MEMBER`. +- **Blocker**: decide whether to display private org work on a public profile card by default. +- **Status**: blocked on that privacy call. -- Donut chart's single-slice (100%) rendering no longer produces an empty arc. -- `FetchContributionsAllTime` warns on stderr when a year returns nil user data. -- `attributeCommit` receives a precomputed per-repo byte total instead of re-summing every commit. -- `Profile.TotalContributions` → `TotalContributionsLastYear` (accurate semantics). -- `context.Context` threaded through all fetchers; `-timeout` flag (default 30m); Ctrl-C cancels in-flight requests. -- Rate-limit awareness: on 429 or exhausted primary limit, honor `Retry-After` / `X-RateLimit-Reset` up to 5 min and retry once. -- Release workflow gates docker + binaries on a test job; no more shipping broken tags. -- Docker base images and third-party GitHub Actions pinned to SHA with version comments. -- Stats card label "Contributed to (non-fork)" corrected to "Contributed to" (the query doesn't filter forks). -- Tests: fixed stale XML-escape assertion, added `TestDonutSingleSlice`, added `TestUTCOffsetLabel` for half-hour zones. - -## Phase 7 — Release polish & Marketplace publish (✅ done) - -- 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. -- Repo topics expanded for Marketplace discoverability (`ghstats-cards`, `profile-readme`, `stats-cards`, etc.). -- 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. - -## Phase 7.5 — Demo gallery for theme discovery (✅ done) - -- 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//` (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. - ---- - -## Phase 8 — Per-commit file classification (planned) - -**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. - -**Approach**: `git clone --filter=blob:none --bare` per seed repo + `git log --author --numstat` → go-enry. - -**Cost**: ~5% of full-clone disk (trees only, no blobs); 3–5 minutes runtime for 100 repos; zero REST calls. - -**Trade-off**: needs disk + git binary on runner. Lowlighter/metrics' indepth mode does similar but clones full blobs; we'd skip those. - -**Status**: researched only; behind `-deep` flag when landed. - -## Phase 10 — User-configurable repo exclusion (planned) - -**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 |