# PR: Elastic Request Link user-active warm pool

## Spec link

- Canonical Spec: `specs/daemon/elastic-request-link-user-active-warm-pool.md`
- Parent Spec: `specs/daemon/daemon-transport.md`
- Metrics Spec: `specs/observability/metrics.md`

## Phase summary

This PR implements the ERL user-active warm pool plan in six gated batches:

1. Split ERL Server/Desktop transport code into focused modules without behavior changes.
2. Add `RemoteRequestContext` / origin plumbing and typed `RemoteEndpointInvocation[T]`.
3. Add registry-driven warm metadata/profile and `LinkGrantSpec` with multi-endpoint allowlists.
4. Add `WarmPoolController`, warm route integration, cooldown, cleanup, and non-blocking first-user-request behavior.
5. Add Desktop warm carrier consumption: local allowlist validation, sequential multi-endpoint reuse, assignment executor coverage, single-flight/cancel/deadline/limit/drain behavior.
6. Add bounded warm metrics, redaction guardrails, boundary comments, final verification matrix, and PR-gate notes.

## Behavior and boundaries

- User-active warm pool is a carrier availability optimization only; it does not change endpoint `LinkPolicy`, fallback/no-retry semantics, or endpoint authorization.
- `user_interactive` origin is only set at explicit Web/API user request entrypoints. Background/materialization/GC/scheduled/service-agentteam paths remain background/system and do not create or refresh warm leases.
- Link tokens authorize carrier establishment only. Endpoint execution remains authorized by the per-request assignment envelope and Desktop registry allowlist.
- Default warm profile `user_interactive_read_review_v1` contains only read/review/output/system endpoints that are safe for warm carriers; destructive/non-idempotent endpoints remain demand-only.
- First user request does not wait for warm readiness. Warm open/connect failures enter cooldown and are observable, but do not fail the current request.
- V1 same-node/session-generation ownership remains process-local; future cross-node rendezvous is out of scope.

## Metrics and redaction gate

- Adds `agentteam_daemon_transport_warm_events_total{origin,profile,warm_event,reason}` with closed low-cardinality allowlists.
- Existing request/route/lifecycle/pool metrics remain bounded.
- Metrics must not expose token/token hash, Authorization, socket/URL/path, link ID, request ID, machine ID, user ID, agent ID, or workspace ID.

## Non-goals

- No Desktop UI change.
- No cross-node/shared-store ERL rendezvous.
- No multiplexing concurrent assignments on one ERL carrier.
- No retry/fallback expansion for destructive or non-idempotent endpoints.
- No product-facing feature flag beyond existing emergency disable behavior.

## Verification matrix

Run before requesting final implementation gate:

- `go test ./internal/api/daemon -count=1`
- `go test ./internal/runtimecontrol ./internal/api/webagent ./internal/api/workspace ./internal/api/channel -count=1`
- `go test ./internal/observability/... -count=1`
- `(cd desktop && go test ./internal/channel/agentteam -count=1)`
- `go test ./internal/api/daemon -run 'TestWarmPool|TestLinkGrantSpec|TestWarmEndpointProfile|TestRemoteEndpoint|TestElasticRequestLink|TestDaemonTransportMetrics' -count=1`
- `(cd desktop && go test ./internal/channel/agentteam -run 'TestElasticRequestLink|TestRemoteRequestAssignment' -count=1)`
- `git diff --check origin/main..HEAD`

## Reviewer notes

- Final review should check fallback/permission/metrics/comment gates together, not only test status.
- Merge must happen by commenting `/merge` on the PR so CI/CD merge lane performs the merge; do not merge locally or via direct provider merge API.
