feat: gadfly-reports — findings store + scoreboard daemon
SQLite-backed HTTP store for Gadfly review findings, per-review run timings, and human/Claude grades, with a points-free per-model scoreboard. Pure fact store: it computes no points or rankings (the dashboard maps severity->points client-side and retunes without re-scoring). Findings are content-addressed by location so cross-model reports collapse for consensus; one grade per finding, latest wins. Pure-Go SQLite (CGO-free) + Docker image CI + tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# gadfly-reports — Developer Guide
|
||||
|
||||
A small Go + SQLite HTTP daemon that stores [Gadfly](https://gitea.stevedudenhoeffer.com/steve/gadfly)
|
||||
review findings, the per-review run timings, and human/Claude grades — and serves a points-free
|
||||
per-model scoreboard. The companion MCP client is
|
||||
[gadfly-mcp](https://gitea.stevedudenhoeffer.com/steve/gadfly-mcp).
|
||||
|
||||
> This is a public, **vibe-coded** project (built largely by an AI agent). Keep that framing honest
|
||||
> in the README; don't oversell it — it's a homelab-grade store, not a hardened product.
|
||||
|
||||
## Core principle: store raw facts, score on the client
|
||||
|
||||
gadfly-reports records **only facts**: runs (timing/tokens), findings (content-addressed by
|
||||
location), reports (which model raised which finding), and grades (`is_real` + `severity` +
|
||||
`usefulness`). It **never stores points or computes rankings**. Mapping `severity → points` and any
|
||||
"value per minute / per token" ranking is the dashboard's job. This is deliberate — keep it that way:
|
||||
do not add a points column or a weighting config to the store. Retuning the curve must never require
|
||||
a migration or a re-score.
|
||||
|
||||
The severity vocabulary (`trivial|small|medium|high|critical`) in `store.go` is the **only**
|
||||
scoring-adjacent contract, and it's a closed set validated on write.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
main.go subcommand dispatch (serve) + flags/env
|
||||
store.go SQLite schema + types + queries (runs/findings/reports/grades + latest_grades view)
|
||||
server.go net/http API (ServeMux method+path routes) + optional bearer auth
|
||||
*_test.go store + server end-to-end tests (consensus, latest-grade-wins, validation, auth)
|
||||
Dockerfile CGO-free build (pure-Go modernc sqlite) -> small alpine image
|
||||
.gitea/workflows/ ci.yml (build/vet/test) + build-image.yml (publish :latest + :sha-<short>)
|
||||
```
|
||||
|
||||
**Data model.** A **finding** is identified by `sha256(repo|pr|lens|file|line)[:16]` — *not* by
|
||||
wording — so the same issue from different models (or a re-review) collapses to one finding with many
|
||||
**reports**. One **grade** per finding (history kept, latest wins via the `latest_grades` view).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **modernc.org/sqlite** (pure Go) — chosen so the binary is CGO-free and `go run …@latest`/the
|
||||
Docker build need no C toolchain. Don't swap in a cgo driver.
|
||||
- Otherwise stdlib only. The MCP SDK lives in gadfly-mcp, **not** here — keep this daemon lean.
|
||||
|
||||
## Build / test
|
||||
|
||||
```sh
|
||||
go build ./...
|
||||
go vet ./...
|
||||
gofmt -l . # must be empty
|
||||
go test -race ./...
|
||||
```
|
||||
|
||||
## Release / deploy
|
||||
|
||||
- **Push to `main`** → CI builds and publishes `:latest` (+ `:sha-<short>`) to
|
||||
`gitea.stevedudenhoeffer.com/steve/gadfly-reports`.
|
||||
- **Tag `v*`** → publishes `:<tag>` (+ `:latest`).
|
||||
- CI needs repo secrets `REGISTRY_USER` / `REGISTRY_PASSWORD` to push the image (the Go build itself
|
||||
uses only public modules — no private-module creds needed).
|
||||
|
||||
## When making changes
|
||||
|
||||
- Keep the **README API table** in sync with `server.go` routes and `store.go` JSON tags — it is the
|
||||
contract gadfly (emit) and gadfly-mcp rely on. Stale docs are a bug.
|
||||
- Preserve the **store-no-points** principle (see above).
|
||||
- Add a test when you add logic. Keep `gofmt` clean and `go vet` quiet.
|
||||
- The schema uses `CREATE TABLE IF NOT EXISTS` migrations applied on `Open`; additive changes are
|
||||
fine, destructive ones need a real migration story (there isn't one yet — it's a homelab store).
|
||||
Reference in New Issue
Block a user