feat(routing-policy): adaptive default proactively holds warm standby + asymmetric F/R (app-agnostic) - #4047
Open
0pcom wants to merge 1 commit into
Open
Conversation
… + asymmetric F/R (app-agnostic) The `adaptive` composite preset is the wired default (config generator sets `preset:adaptive`). It previously seeded Mux=1 for three hardcoded client-app names and the empty spec for everything else, so the default route group came up single-leg and only grew reactively under sustained load — the mux / warm-standby / asymmetric behavior never manifested on real apps, only in the ad-hoc mux-bw rig. The router-layer machinery to reserve N disjoint routes, hold warm standby (on_tick demote/promote), and shape asymmetric forward/reverse mux already exists and is app-agnostic (establishMuxRoutes, EffectiveMuxRoutes, appendRouteAsymmetric, setLegStandby). The gap was purely in the default policy. This wires it: - decideAdaptive is now APP-AGNOSTIC: every overlay app that dials a route group (proxy, vpn, skynet-client, the resolving-proxy / browser chain, custom-named sessions) gets the adaptive mux; only latency-sensitive chat stays a single lean route (same idiom as rotating-bw). No hardcoded allowlist of binary names. - Asymmetric by default: ForwardMux=1 (a single lean upstream/request leg, no mux head-of-line cost) + ReverseMux=adaptRevActive+adaptStandbyMax (a wider bulk download mux sized active + warm-standby reserve). - tickAdaptive proactively parks the surplus reverse legs as warm standby (down to the steady active target) once no leg is a latency outlier and the group is not saturated — holding instant-promote spares WITHOUT waiting for an idle signal. Parks the newest surplus leg, never leg 0 (the primary/forward leg the router refuses to demote). Under load the saturated branch grows the active width by promoting a spare (dip-free) before adding a cold leg. Native == wazero parity preserved: bundle.wasm rebuilt from the shared preset package via TinyGo; parity_test (decide + multi-tick on_tick) green. Graceful degradation preserved (no candidates / unknown transport kinds -> Chosen nil, router picks the path as before). mux=1 apps and single-route dials unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Makes the
adaptivecomposite preset — the wired default (preset:adaptive) — actually manifest its mux / warm-standby / asymmetric behavior on real apps, not just the ad-hocmux-bwrig.Previously
decideAdaptiveseededMux=1for three hardcoded client-app names and the empty spec for everything else, so the default route group came up single-leg and only grew reactively under sustained load. The router-layer machinery to reserve N disjoint routes, hold warm standby (on_tick demote/promote), and shape asymmetric forward/reverse mux already exists and is app-agnostic (establishMuxRoutes,EffectiveMuxRoutes,appendRouteAsymmetric,setLegStandby). The only gap was the default policy. This wires it.Changes (policy layer only — no router core changes)
decideAdaptivenow applies to every overlay app that dials a route group (proxy, vpn, skynet-client, the resolving-proxy / browser chain, custom-named sessions). Only latency-sensitive chat stays a single lean route (same idiom asrotating-bw). No hardcoded allowlist of binary names — the old three-name switch made the policy a silent no-op for renamed sessions.ForwardMux=1(one lean upstream/request leg, no mux head-of-line cost) +ReverseMux=adaptRevActive+adaptStandbyMax(a wider bulk-download mux sized active + a warm-standby reserve).tickAdaptiveparks the surplus reverse legs as warm standby (down to the steady active target) once no leg is a latency outlier and the group is not saturated — holding instant-promote spares without waiting for an idle signal. It parks the newest surplus leg, never leg 0 (the primary/forward leg the router refuses to demote). Under load the saturated branch promotes a spare (dip-free) before adding a cold leg.Parity & safety
bundle.wasmrebuilt from the sharedpkg/router/policy/presetpackage via TinyGo;parity_test(decide + multi-tick on_tick) green.Chosennil, router picks the path exactly as before (the wasm / no-provider path).mux=1apps and single-route dials unchanged.Not included (design blocker)
Runtime load-based F/R flip (swap which direction is wide from
on_tickper-leg {bps}) is not implemented: theRotationActionABI has no forward/reverse-width field, and per-direction rules are provisioned at setup, so re-shaping the fwd/rev leg allocation at runtime needs a setup-node re-provision (a dip) or an ABI + wire extension. Reported rather than shipped as a fragile re-dial. The static asymmetric shape (lean forward / wide reverse) is shipped.Tests
go build .,go vet,go test ./pkg/router/policy/... ./pkg/router/all green, including the native↔wazero parity gate and a newTestEngine_OnTick_AdaptiveHoldsWarmStandby.