70 lines
4.2 KiB
Markdown
70 lines
4.2 KiB
Markdown
# 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).
|
||
|
||
## Changes during the run
|
||
|
||
- 2026-09-25, task 01, first attempt: three given test files under `_files/` were not `gofmt`-clean,
|
||
and the gate's `gofmt -l .` walks every file, so the gate failed on files the implementer may
|
||
not edit. Ornith diagnosed it (gofmt on its own code was clean) and did not touch them.
|
||
Owner's fault (the compile check ran `go vet`, not `gofmt`, on the given files). Fixed by
|
||
formatting the given files; the plan checklist now includes `gofmt -l docs/` before handover.
|