Stop a preset that does not fit from taking the whole shell down - #64
Merged
Conversation
GET /api/ai/hardware nulls tier/repo_id/quant/est_size_gb for any preset the box cannot run (`_preset_dict(entry=None, ...)` in app/localllm/hardware.py), but the frontend typed those four fields as always-present and called `est_size_gb.toFixed()` on them. On a machine with no GPU the speed preset is always null, so the first-run wizard threw during render and the error boundary replaced the ENTIRE console with "PANEL ERROR: shell". The globe, the layer rail and every app were unreachable — on any keyless no-GPU box. Type the four fields as nullable, which is what the backend actually publishes, and render the missing ones as the house "no value reported" dash. A preset with no repo/quant has nothing to download, so its card offers "unavailable" rather than posting a null repo id. Typecheck found the second consumer this would have crashed on: PresetsRow passed the same nullable repo_id/quant straight into onDownload.
httpx only consults HTTPS_PROXY/NO_PROXY when `transport` is left unset (`allow_env_proxies = trust_env and transport is None`), and get_client() must pass a transport for the IPv4 local_address pin. That combination silently disabled proxy support for every upstream call: behind an egress proxy, any host reachable ONLY through that proxy died as a ReadTimeout. Measured on a proxied box: celestrak.org timed out on every attempt while curl through the same proxy answered 200 in 0.9 s, so /api/space/gp 500'd and the satellite layer sat at zero. The directly-routable feeds (adsb.lol, OpenSky, Carto, ShipXplorer) all worked, which is what made it look like a CelesTrak-side throttle rather than our client. Rebuild the per-pattern map httpx would have built and mount it. A NO_PROXY entry maps to a direct transport, so the localhost sidecars (:8090/:8093) keep bypassing the proxy. With nothing configured the map is empty and the client behaves exactly as before, which is the unproxied default.
Several upstreams gate on the caller's IP rather than a key: airplanes.live 403s a datacenter address, adsb.lol rate-limits per source IP, and OpenSky's anonymous credit budget is per IP. An operator with their own egress addresses had no way to spread load across them. UPSTREAM_PROXIES adds a rotating pool to the shared client, as a transport so every existing get_client() call site is covered untouched. A proxy that errors goes on a cooldown rather than being dropped (the usual cause is transient) and the next request skips it. Empty config returns None and the client is wired exactly as before, so the default path is unchanged. Two deliberate defaults: - Fails CLOSED when every proxy is cooling down. Configuring a proxy usually means "not from my own address", so a silent direct fallback would leak the thing the proxy was for. UPSTREAM_PROXY_FALLBACK_DIRECT opts in. - Loopback always bypasses the pool. The :8090/:8093 sidecars are same-host; an external hop cannot reach them and would publish their traffic. An explicit pool outranks HTTPS_PROXY. Found live, not by inspection: httpx consults mounts before the default transport, so the env "https://" mount answered all four test requests while the pool recorded zero successes — the pool was dead code whenever the environment set a proxy. NO_PROXY exclusions still apply, since those say "do not proxy this host" and bind the pool too. There is no discovery and no bundled list, only what the operator configures. Public free-proxy pools are largely consumer machines enrolled by malware whose owners never agreed to carry traffic, and interception nodes that would read every query the console makes; harvesting them would hand somebody else's device the bill for our rate limits. Credentials are redacted in stats and logs. Baseline 2124 -> 2141.
AndrewCTF
force-pushed
the
claude/repo-setup-ui-access-hj3wtw
branch
from
July 31, 2026 09:56
7c845cc to
9068962
Compare
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.
GET /api/ai/hardware nulls tier/repo_id/quant/est_size_gb for any preset the
box cannot run (
_preset_dict(entry=None, ...)in app/localllm/hardware.py),but the frontend typed those four fields as always-present and called
est_size_gb.toFixed()on them. On a machine with no GPU the speed preset isalways null, so the first-run wizard threw during render and the error
boundary replaced the ENTIRE console with "PANEL ERROR: shell". The globe,
the layer rail and every app were unreachable — on any keyless no-GPU box.
Type the four fields as nullable, which is what the backend actually
publishes, and render the missing ones as the house "no value reported" dash.
A preset with no repo/quant has nothing to download, so its card offers
"unavailable" rather than posting a null repo id.
Typecheck found the second consumer this would have crashed on: PresetsRow
passed the same nullable repo_id/quant straight into onDownload.