v2.2 plan: route templates (opencode-*) and multiple wake broadcast addresses; given tests
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# v2.2 task 01: route templates
|
||||
|
||||
**Branch:** `v2.2` (`git switch -c v2.2 master` if it does not exist, else `git switch v2.2`; `git status --short` must be empty, otherwise stop)
|
||||
**Commit subject:** `Route templates: a route named x-* serves any request route x-<something>`
|
||||
|
||||
## Goal
|
||||
|
||||
`PLAN.md` §4a gives every OpenCode instance its own route (`CROSSBAR_ROUTE="$(basename "$PWD")-$$"`),
|
||||
but the config only knows explicit `[routes.NAME]` tables and everything else is `404 unknown
|
||||
route`. After this task a route whose name ends in `-*` is a **template**: a request route that
|
||||
starts with the part before the star, with something non-empty after it, uses that route's hosts,
|
||||
default model and peers. Leases and accounting stay keyed by the concrete route name, so two
|
||||
instances never share a lease and each has its own usage row.
|
||||
|
||||
## Files
|
||||
|
||||
- Copy: `internal/config/config_v22_test.go` (its `TestWakeBroadcasts` belongs to task 02 and
|
||||
will fail to compile until then — see step 2), `internal/proxy/template_test.go`,
|
||||
`internal/admin/admin_template_test.go`
|
||||
- Modify: `internal/config/config.go`, `internal/proxy/proxy.go`, `internal/admin/admin.go`,
|
||||
`internal/admin/admin_ops.go`, `cmd/crossbar/main.go` (the identity middleware's route→peers
|
||||
lookup), `docs/implementer-log.md`
|
||||
|
||||
## Interfaces
|
||||
|
||||
```go
|
||||
package config
|
||||
|
||||
// Route resolves a request route name: an exact entry wins; else the longest template
|
||||
// "<prefix>-*" whose prefix (including the dash) starts name with a non-empty remainder;
|
||||
// else ok is false. key is the config key that matched (the template's name for a template).
|
||||
// A name that is not a valid route name (the pattern below) or contains '*' never matches.
|
||||
func (c *Config) Route(name string) (r Route, key string, ok bool)
|
||||
```
|
||||
|
||||
Rules:
|
||||
1. Config route keys match `^[a-z0-9][a-z0-9-]*$` (as before) **or** `^[a-z0-9][a-z0-9-]*-\*$`
|
||||
(a template). Anything else with a `*` is `routes.<name>: must match …` as today. A
|
||||
template alone satisfies "at least one route".
|
||||
2. Resolution order: exact, then longest matching template, then none.
|
||||
3. The proxy resolves both the path form and the `X-Crossbar-Route` header form through
|
||||
`cfg.Route`; the concrete name (not the template key) is the route used for leases,
|
||||
accounting rows, logs and headers. The "conflicting route" check compares concrete names.
|
||||
4. Admin: `POST /_crossbar/routes/{route}` resolves through `cfg.Route` — a concrete route under
|
||||
a template can be pinned/released even before its first request; the template name itself
|
||||
is `404 unknown route`. `GET /_crossbar/routes` lists config keys (templates under their own
|
||||
name) and, for a template, the leases of every concrete route it matches.
|
||||
5. `main.go`: the identity middleware's `func(route string) ([]string, bool)` uses `cfg.Route`.
|
||||
|
||||
## Steps
|
||||
|
||||
- [ ] **1.** Branch as above; copy the three given tests.
|
||||
- [ ] **2. See them fail.** `config_v22_test.go` also references `Wake.Addresses()` (task 02); until
|
||||
then run the config package with `-run 'TestRouteTemplate'` **after** adding a temporary
|
||||
stub? No — do not add stubs. Instead implement task 01 and run
|
||||
`go test -race -count=1 ./internal/proxy/ ./internal/admin/` for the behaviour, and `go vet
|
||||
./internal/config/` will fail only on the missing `Addresses` method until task 02: that is
|
||||
expected and is the one allowed red at the end of this task. Say so in the log row.
|
||||
- [ ] **3.** `config.go`: the template regex, `Route()`. **4.** `proxy.go` route resolution.
|
||||
**5.** `admin.go` / `admin_ops.go`. **6.** `main.go`.
|
||||
- [ ] **7.** `gofmt -w`; `go test -race -count=1 ./internal/proxy/ ./internal/admin/ ./internal/health/ ./internal/wake/` → `ok`.
|
||||
- [ ] **8.** Row `v2.2/01-route-templates`; commit (the gate runs green after task 02).
|
||||
|
||||
```sh
|
||||
git add internal/config internal/proxy internal/admin cmd/crossbar docs/implementer-log.md
|
||||
git commit
|
||||
```
|
||||
|
||||
## Done when
|
||||
|
||||
- `TestRouteTemplateServesConcreteRoutes` and `TestRoutesViewAndPinWithTemplates` pass under
|
||||
`-race`; every earlier proxy/admin test still passes; given files byte-identical; no file over
|
||||
400 lines. `internal/config` is red only on `Addresses` (task 02).
|
||||
|
||||
## Stop and report if
|
||||
|
||||
- Passing needs a change to any earlier given test.
|
||||
- The 400-line limit forces `proxy.go` apart: say which split you propose before doing it.
|
||||
Reference in New Issue
Block a user