Skip to content

Commit 1973bc4

Browse files
JordanCoinclaude
andcommitted
Add coverage badge and Codex coverage prompt
- Add shields.io dynamic coverage badge to README - Add CI step to update gist with coverage % on main pushes - Add Codex weekly prompt for incremental coverage improvement Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e10fe80 commit 1973bc4

3 files changed

Lines changed: 135 additions & 0 deletions

File tree

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Codex Task: Improve Test Coverage
2+
3+
## Objective
4+
5+
Incrementally improve test coverage toward 90%. Each run should target **one package**, add tests, and open a PR.
6+
7+
## Steps
8+
9+
1. **Measure current coverage per package:**
10+
11+
```bash
12+
go test -coverprofile=coverage.out ./...
13+
go tool cover -func=coverage.out | awk '/^total:/ {print "TOTAL:", $3}'
14+
# Per-package breakdown:
15+
go test -cover ./... 2>&1 | sort -t'%' -k2 -n
16+
```
17+
18+
2. **Pick the lowest-coverage package** from this priority list (skip packages already above 80%):
19+
20+
| Priority | Package | Notes |
21+
|----------|---------|-------|
22+
| 1 | `scanner/` | Core scanning logic, high impact |
23+
| 2 | `watch/` | Daemon/event system |
24+
| 3 | `render/` | Output rendering |
25+
| 4 | `handoff/` | Handoff artifact building |
26+
| 5 | `cmd/` | CLI commands |
27+
| 6 | `config/` | Configuration loading |
28+
| 7 | `limits/` | Budget enforcement |
29+
30+
**Skip these packages** (hard to test in isolation):
31+
- `mcp/` — MCP server, requires full stdio lifecycle
32+
- Root `main.go` — thin entry point
33+
34+
3. **Write tests** following the project's existing patterns (see below).
35+
36+
4. **Check if the CI coverage floor can be bumped.** If total coverage is now ≥ current floor + 5 points, update the `min=` value in `.github/workflows/ci.yml` (the `Enforce coverage floor` step).
37+
38+
5. **Open a PR** with:
39+
- Title: `test: improve <pkg> coverage from X% to Y%`
40+
- Body: before/after per-package and total coverage numbers
41+
- Max **500 lines** of new test code per PR
42+
43+
## Test Patterns to Follow
44+
45+
All existing tests in this repo use these conventions. Follow them exactly.
46+
47+
### Table-driven tests
48+
49+
```go
50+
func TestFoo(t *testing.T) {
51+
tests := []struct {
52+
name string
53+
// inputs
54+
// expected outputs
55+
}{
56+
{name: "descriptive case name", /* ... */},
57+
}
58+
for _, tt := range tests {
59+
t.Run(tt.name, func(t *testing.T) {
60+
// test body
61+
})
62+
}
63+
}
64+
```
65+
66+
### Standard library only
67+
68+
- Use `testing` package only — no testify, no gomock, no external test deps.
69+
- Use `t.Errorf` / `t.Fatalf` for assertions.
70+
- Use `t.Helper()` in test helper functions.
71+
72+
### Temp directories
73+
74+
```go
75+
dir := t.TempDir() // auto-cleaned up
76+
```
77+
78+
### File setup in tests
79+
80+
```go
81+
err := os.WriteFile(filepath.Join(dir, "file.go"), []byte(content), 0o644)
82+
if err != nil {
83+
t.Fatal(err)
84+
}
85+
```
86+
87+
### Subtests for variants
88+
89+
Use `t.Run(tt.name, ...)` — never run test cases in a bare loop.
90+
91+
## Functions to Skip
92+
93+
These are difficult to unit test and should be skipped:
94+
95+
- Anything requiring a running subprocess (`exec.Command` wrappers)
96+
- Terminal UI rendering (lipgloss/bubbletea output)
97+
- `main()` and top-level CLI entry points
98+
- Functions that require network access or a running MCP server
99+
- Functions that depend on git operations against real repos (unless using `t.TempDir()` with `git init`)
100+
101+
## Rules
102+
103+
- **Never modify source code** — only add `_test.go` files.
104+
- Add tests to the **existing** `_test.go` file for the package if one exists; create a new one only if needed.
105+
- Keep tests deterministic — no sleep, no real network, no time-dependent assertions.
106+
- Run `go test -race ./...` before opening the PR.
107+
- Run `go vet ./...` and `gofmt -l .` — the PR must pass CI.
108+
- Each test function should test **one behavior** clearly described by its name.
109+
110+
## PR Checklist
111+
112+
- [ ] `go test -race -coverprofile=coverage.out ./...` passes
113+
- [ ] `go vet ./...` clean
114+
- [ ] `gofmt -l .` shows no files
115+
- [ ] No source files modified, only `_test.go` files added/changed
116+
- [ ] Coverage floor bumped in CI if warranted (≥ floor + 5)
117+
- [ ] PR title follows format: `test: improve <pkg> coverage from X% to Y%`
118+
- [ ] PR body includes before/after coverage table

.github/workflows/ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.23'
5050
run: |
5151
total=$(go tool cover -func=coverage.out | awk '/^total:/ {gsub("%","",$3); print $3}')
52+
# Floor target: 90%. Codex PRs will incrementally raise this value.
5253
min=30.0
5354
awk -v t="$total" -v m="$min" 'BEGIN {
5455
if (t+0 < m+0) {
@@ -57,6 +58,21 @@ jobs:
5758
}
5859
printf "Coverage %.1f%% meets floor %.1f%%\n", t, m
5960
}'
61+
# Export for badge step
62+
echo "COVERAGE=$(printf '%.0f' "$total")" >> "$GITHUB_ENV"
63+
64+
- name: Update coverage badge
65+
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.23' && github.ref == 'refs/heads/main'
66+
uses: schneegans/dynamic-badges-action@v1.7.0
67+
with:
68+
auth: ${{ secrets.GIST_TOKEN }}
69+
gistID: 6ffe3276ddb8a7a7f08d50d649e567bd
70+
filename: codemap-coverage.json
71+
label: coverage
72+
message: ${{ env.COVERAGE }}%
73+
valColorRange: ${{ env.COVERAGE }}
74+
minColorRange: 30
75+
maxColorRange: 90
6076

6177
- name: Upload coverage
6278
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.23'

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
99
![License](https://img.shields.io/badge/license-MIT-blue.svg)
1010
![Go](https://img.shields.io/badge/go-1.21+-00ADD8.svg)
11+
![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/JordanCoin/6ffe3276ddb8a7a7f08d50d649e567bd/raw/codemap-coverage.json)
1112

1213
![codemap screenshot](assets/codemap.png)
1314

0 commit comments

Comments
 (0)