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>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user