Files
crossbar/docs/plans/v2/05-wiring-smoke.md
kyleandClaude Fable 5.1 74b8af4ce0 AGENTS.md: a refused tool call is not a reason to end the turn; v2 plan (props, ctx guard, wake, identity, wiring) as acceptance tests; v1.1 run note
v2 given tests compiled against a panic-only skeleton (go vet clean); no reference
implementation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-25 08:37:38 -07:00

59 lines
3.0 KiB
Markdown

# v2 task 05: wiring, the smoke run, README
**Branch:** `v2` (run `git switch v2`; `git status --short` must be empty, otherwise stop)
**Commit subject:** `Wire wake and identity into crossbar; v2 smoke and README`
## Goal
Put the pieces together: the proxy wakes a sleeping host when a route has no healthy host left,
`main` builds the waker from config and wraps the proxy in the identity middleware when
`identity` is on, the given fake upstream can be woken, and `tools/smoke.sh` proves the whole of
v2 over real HTTP.
## Files
- Copy (**replaces** v1's): `cmd/fakeupstream/main.go`, `tools/smoke.sh`, `example.toml`
- Modify: `internal/proxy/proxy.go` (or a new file), `cmd/crossbar/main.go`, `README.md`, `docs/implementer-log.md`
## Rules
1. `proxy.Handler` gains `func (p *Handler) SetWaker(w Waker)` where
`type Waker interface{ Wake(ctx context.Context, host string) bool }` (defined in `proxy`).
When `leases.Acquire` returns `ErrNoHost` and a waker is set: for each candidate host of the
route, in order, that has a wake target (ask `cfg.Hosts[h].Wake != nil`), call
`Wake(r.Context(), h)`; on `true`, retry `Acquire` once; on `false` for every candidate, 503
`{"error":"no healthy host","woke":["<hosts tried>"]}`. The context-guard's "no host fits"
path (task 02) also tries waking a host whose `PerSlotCtx` is unknown or large enough, before
answering 400.
2. `cmd/crossbar`: build `wake.New(targets, hosts)` from every host with `Wake != nil`
(`hosts` is the `proxy.HostView`, which has `Healthy`), call `p.SetWaker(w)`. When
`cfg.Identity != "off"`: `checker := identity.NewChecker(identity.TailscaleResolver{})` or
`identity.NewHeaderChecker()`; wrap the proxy handler:
`mux.Handle("/", identity.Middleware(checker, func(route string) ([]string, bool) { rt, ok := cfg.Routes[route]; return rt.Peers, ok }, p))`.
Log at start which mode is active; with `"header"` log a warning that it is insecure.
3. Copy the three given files; `make build`; `make smoke` → `smoke: ok (…)`. The smoke's check 2
waits up to 40 s for the wake; the fake wakes in ~1 s.
4. README: sections stay; add under `## Operate` the wake behaviour and the identity modes with
the `peers` example; under `## Configure` the three new keys; `## What v2 does not do`:
`/slots`, request coalescing, TLS — `PLAN.md`.
## Steps
- [ ] **1.** `git switch v2`; copy the three given files.
- [ ] **2. Write the code** (proxy waker path, `main`). `gofmt -w .`
- [ ] **3.** `go test -race -count=1 ./...` → all `ok`. **4.** `make smoke` → `smoke: ok`.
- [ ] **5.** README. **6.** `make gate`. **7.** Row `v2/05-wiring-smoke`; commit.
```sh
git add internal/proxy cmd/crossbar cmd/fakeupstream tools/smoke.sh example.toml README.md docs/implementer-log.md
git commit
```
## Done when
- `make smoke` prints `smoke: ok (…)`; gate ok; the three copied files byte-identical.
## Stop and report if
- `make smoke` fails twice in the same way; quote the failing check and the crossbar log.