Good first issues¶
A curated set of small, well-scoped starter tasks for new contributors. Each is derived from a still-unchecked item in ENHANCEMENTS.md — none of them require deep prior context, and each has a clear definition of done.
New here? Read the Contributor on-ramp
in CONTRIBUTING.md first — it covers the dev setup, the one non-negotiable
rule (zero-dependency core), and the PR checklist. Then pick an issue below,
comment on the tracking issue to claim it, and open a focused PR.
Ground rules for every task:
- Core packages must stay dependency-free —
make verify-depsmust pass. If a task needs a third-party import, it belongs in an adapter package (contrib/,ratelimit/store,ratelimit/middleware,observability/,metric/) or a test file, never in a core algorithm package. go test -race ./...andgolangci-lint runmust stay green.- Add or update tests for any behaviour change; update godoc for exported symbols.
1. Add doc.go package overviews for multi-file packages¶
- Source: ENHANCEMENTS.md §8.7 (P3)
- Why it's approachable: Pure documentation — no logic, no API changes. Great way to learn the package layout while improving the pkg.go.dev landing pages.
- Files: new
doc.goin the larger packages, e.g.ratelimit/,circuitbreaker/,pipeline/,retry/,bulkhead/,loadshed/,concurrency/. - Acceptance criteria:
- Each targeted package has a
doc.gowith a package-level comment giving a short overview and pointing at the relevantexample_test.go. go vet ./...andgolangci-lint runstay clean;make godocrenders the new overviews.- No behavioural change; no new imports.
2. Add benchmarks for the currently-unbenchmarked hot paths¶
- Source: ENHANCEMENTS.md §3.5 (P3) and the gaps listed in docs/benchmarks.md
- Why it's approachable: Follows the exact pattern of existing
*_bench_test.gofiles (seeratelimit/tokenbucket/tokenbucket_bench_test.go). Copy, adapt, run. - Files: new
*_bench_test.goinbulkhead/,ratelimit/composite/,ratelimit/adaptive/,pipeline/, andratelimit/middleware/. - Acceptance criteria:
- At least one
Benchmark*per targeted package, usingb.ReportAllocs(). - Benchmarks run clean via
go test -bench=. -benchmem -run='^$' ./<pkg>/. - Update the "Coverage and gaps" section of
docs/benchmarks.mdto move the newly-covered packages out of the gap list (with real captured numbers).
3. Extract a read-only Peeker interface from Limiter¶
- Source: ENHANCEMENTS.md §2.6 (P3)
- Why it's approachable: Small, non-breaking interface refactor (embedding). Good for learning Go interface segregation.
- Files:
ratelimit/limiter.go. - Acceptance criteria:
- A new
Peeker interface { Peek(...) State }is defined andLimiterembeds it, so existing implementations satisfy both without code changes. - All existing tests pass unchanged (proving it is non-breaking).
- Godoc explains when to depend on
PeekervsLimiter.
4. Add Default() constructors / zero-value guidance for limiters¶
- Source: ENHANCEMENTS.md §2.7 (P3)
- Why it's approachable: Additive, localized per package; mirrors the
existing
circuitbreaker.Configdefaults pattern. - Files:
ratelimit/tokenbucket/,ratelimit/gcra/,ratelimit/fixedwindow/(addDefault()helpers + doc notes). - Acceptance criteria:
- Each targeted limiter gains a
Default()(or documented sane preset) returning a usable limiter without panicking. - Godoc states which zero/preset values are legal.
- Tests cover the new constructors.
5. Optional structured-logging hook (WithLogger) for library consumers¶
- Source: ENHANCEMENTS.md §4.4 (P2)
- Why it's approachable: Reuses the existing functional-options pattern
(
WithOnDecision,WithClock); stdlib-only (log/slog), so it stays zero-dep. - Files:
options.goin the limiter packages andcircuitbreaker/config.go; guard log calls behindslog.Logger.Enabledlevel checks. - Acceptance criteria:
- An optional
*slog.Loggercan be attached;nil= silent (default). - Debug-level logs for decisions, info-level for state changes.
make verify-depsstays green (stdlib only); hot path unaffected when no logger is set.
6. Distributed leaky bucket via a Lua script¶
- Source: ENHANCEMENTS.md §1.8 (P2)
- Why it's approachable: Leaky bucket maps cleanly onto the GCRA math that
already has a distributed implementation — use
ratelimit/gcra/distributed.goand its Lua script as the template. - Files: new
ratelimit/leakybucket/distributed.go; a Lua script inratelimit/store/alongsideGCRAScript; parity test inratelimit/store/. - Acceptance criteria:
leakybucket.NewDistributed(...)implements the sameLimiterinterface.- The in-memory script emulation matches the Redis result (parity test), as the other distributed algorithms do.
- Integration test passes under
-tags=integrationagainst a real Redis.
7. Differential fuzzing for the remaining rate-limit algorithms¶
- Source: ENHANCEMENTS.md §6.2 (P2)
- Why it's approachable: Native Go fuzzing; copy the shape of
ratelimit/tokenbucket/fuzz_test.go/ratelimit/gcra/fuzz_test.go. - Files: new
fuzz_test.goinratelimit/fixedwindow/,ratelimit/slidingwindow/,ratelimit/leakybucket/,ratelimit/composite/. - Acceptance criteria:
- A
Fuzz*target per algorithm that asserts the admission bound holds over random operation/time schedules (reuseinternal/clock.ManualClock). go test -run=Fuzz -fuzz=Fuzz -fuzztime=30s ./<pkg>/finds no failures.
8. Mutation testing on the core algorithm packages¶
- Source: ENHANCEMENTS.md §6.6 (P3)
- Why it's approachable: Tooling-driven; a good way to discover weak assertions without writing new logic.
- Files: a
make mutationtarget (or.github/workflows/nightly job) that runsgo-gremlins/gremlinsonratelimit/...andcircuitbreaker/; document inCONTRIBUTING.md. - Acceptance criteria:
gremlinsruns on the core packages and produces a mutation report.- At least the surviving mutants in one core package are triaged (fixed with a new test, or documented as acceptable in the PR description).
9. Fault/latency-injection test helper¶
- Source: ENHANCEMENTS.md §6.7 (P2)
- Why it's approachable: Self-contained test utility; builds on the existing
internal/testutil+internal/clockprimitives. - Files:
internal/testutil/(newFaultyFunchelper); a scenario test underpipeline/orfallback/. - Acceptance criteria:
- A
testutil.FaultyFuncinjects configurable latency/error rates driven byManualClock. - A scenario test uses it to assert a concrete pipeline behaviour (e.g. hedge fires, breaker opens, retry budget stops retries).
10. Frontend accessibility pass¶
- Source: ENHANCEMENTS.md §10.1 (P2)
- Why it's approachable: Front-end-only; scoped, visible, and testable with
@axe-core/playwright. Radix UI primitives already provide accessible building blocks. - Files:
frontend/components/**(add ARIA live regions, labels, keyboard controls),frontend/e2e/(axe checks). - Acceptance criteria:
- ARIA live regions announce the WebSocket-driven metric tiles.
- SVG visualizations carry
role/labels; the simulator is keyboard-operable. - An
@axe-core/playwrightcheck passes in the e2e suite with no critical violations.
11. Frontend component unit tests¶
- Source: ENHANCEMENTS.md §10.5 (P3)
- Why it's approachable: Isolated unit tests with Vitest + React Testing Library; no backend required.
- Files:
frontend/— tests for the Zustand store reducers and thelib/ws/manager.tsreconnect/backoff logic. - Acceptance criteria:
- Vitest config added; unit tests cover the store reducers and WS reconnect logic.
- Tests run via
npm testand pass in CI.
12. Cross-link and "run it" the examples from the README¶
- Source: ENHANCEMENTS.md §11.4 (P3)
- Why it's approachable: Docs + light wiring; no library code.
- Files:
README.md,examples/*/README.md(add per-example run instructions). - Acceptance criteria:
- The
examples/{http,grpc,distributed,pipeline}directories are cross-linked from the README with a short "run it" snippet each. - Each referenced example actually builds (
go build ./examples/...).
Picking up an issue¶
- Open a GitHub issue (or comment on the tracking one) referencing the section number above so work isn't duplicated.
- Follow the development workflow:
fork, branch off
main, keep the change focused. - Before opening the PR, run the pre-PR checks:
make test-race,golangci-lint run, andmake verify-deps. - Fill out the PR template and link the issue.