v1 plan: leases, limiter, chooser, fingerprint, SQLite store, accounting, admin — acceptance tests first, no reference

Every given test compiled against a panic-only interface skeleton (go vet clean); nothing was
implemented. modernc.org/sqlite v1.59.0 vetted in a scratch module (WAL works); go.sum given.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 03:10:24 -07:00
co-authored by Claude Fable 5.1
parent 851cc80eba
commit c457046f8b
20 changed files with 2660 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
# v1 implementation plan: leases, queueing, accounting
> **For the implementing model:** do not work from this file. The owner gives you one task file at
> a time (`01-…` to `07-…`). This file is the index for the owner and the reviewer.
**Goal:** `PLAN.md` §4–§7a. Every conversation gets a sticky lease on one host (chosen by free
slots × weight when it starts), requests queue per (host, model) instead of overflowing a
router, an operator can pin a route or drain a host, and SQLite keeps the leases and an accounting
log that answers "which session used which host and model, for how long, at what cache-hit rate".
**Architecture:** five new packages — `store` (SQLite, `modernc.org/sqlite`), `fingerprint`
(conversation key), `choose` (the scoring rule), `limiter` (per-(host, model) slots + bounded
FIFO), `lease` (the sticky table, persisted through `store`) — and v1 versions of `proxy`,
`admin`, `config` and `cmd/crossbar`. The proxy tees streamed responses through an SSE scanner
to read the final `usage`/`timings` chunk; it never buffers or alters the stream.
**How this plan was made:** acceptance tests first, from `PLAN.md`; no reference implementation.
Every given test file was compiled against a panic-only skeleton of the interfaces named in the
tasks (`go vet ./...` clean), and nothing else was run. If a test turns out to be wrong, that is
the owner's finding: stop and report as `AGENTS.md` says; do not edit it.
**Tech stack:** Go 1.26, stdlib, `github.com/BurntSushi/toml` v1.6.0, `modernc.org/sqlite`
v1.59.0 (pure Go; `go.sum` given). No other module.
## Global constraints
- Everything in `AGENTS.md`. Branch `v1`. One task, one fresh OpenCode session, one commit.
- Bodies are never logged or stored. Rows carry names, counts and timings only.
- Given files (tests, `example.toml`, `cmd/fakeupstream/main.go`, `tools/smoke.sh`, `go.sum`)
are copied and never edited. Some **replace** v0 files of the same name; the task says so.
## Tasks
| # | File | Delivers | Tests that define it |
|---|---|---|---|
| 01 | `01-store.md` | `internal/store`: SQLite state + accounting | `internal/store/store_test.go` |
| 02 | `02-fingerprint-config.md` | `internal/fingerprint`; `config` gains `db`, `lease_idle`, `retention`, day suffix | `fingerprint_test.go`, `config_v1_test.go` |
| 03 | `03-limiter-choose.md` | `internal/limiter`, `internal/choose` | `limiter_test.go`, `choose_test.go` |
| 04 | `04-lease.md` | `internal/lease`: the sticky table | `lease_test.go` |
| 05 | `05-proxy.md` | proxy v1: leases, queue, SSE tee, accounting, header route | `proxy_test.go` (replaces v0's) |
| 06 | `06-admin-main.md` | admin v1 (pin/release/drain/usage/metrics), `cmd/crossbar` wiring | `admin_test.go` (replaces), start/stop check |
| 07 | `07-smoke-readme.md` | `tools/smoke.sh` v1 run, README update | `make smoke` |
## For the owner: running a task
```sh
tools/run-plan.sh docs/plans/v1 # from a clean checkout on master
```
## For the reviewer: after task 07
1. `git log --oneline master..v1`: seven commits with the trailer.
2. Copied files byte-identical to `_files/`; `git diff <merge-base>..v1 --stat -- PLAN.md AGENTS.md docs/plans` empty.
3. `make gate`, `make smoke`.
4. Read every source file against its task. Probe outside the tests: a lease whose host is
drained *and* unhealthy; `lease_idle` expiry while a request is in flight; a stream cut by the
client mid-way (the accounting row must still be written, with the status it had); a body
with `"messages"` that is not an array; two crossbars on the same `db` file; `Prune` while
requests are being recorded.
5. Every `.(` type assertion in `internal/` is the two-value form or on a value we constructed.
6. Findings under "Reviews" in `docs/implementer-log.md`, by fault (model / task / test).