Files
crossbar/docs/plans/v1/README.md
T
kyleandClaude Fable 5.1 c457046f8b 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>
2026-09-25 03:10:24 -07:00

62 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).