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:
@@ -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).
|
||||
Reference in New Issue
Block a user