fix: eliminate proxy-fanout signal that triggers free_mode_run_fanout refusal - #207
Merged
Merged
Conversation
… refusal - Make client_id per-RUN instead of per-call: the CLI mints it once per prompt (run.ts:722/822) and repeats it on every LLM step. N client_ids under one run_id was the exact fanout shape upstream refuses as free_mode_run_fanout. - Drop Start prewarm fleet: no longer fans out a run per agent per token at boot — that was the ban-grade proxy-fanout sweep signal. - Classify free_mode_run_fanout as RateLimitError (not dead upstream 502): bounded FanoutCooldown (60s) + 429 surfacing so clients back off instead of dying mid-turn. Never re-POST into a fanout refusal. - Override luna retired root: base2-free-luna → base3-free-luna for the retired upstream agent (free_mode_legacy_luna_agent). - ScarceSessionError now reports the HELD session's model for accurate Retry-After. - Persist ClientID on runs so resume doesn't split a run's client identity. - Build tags: Makefile and Taskfile use -tags dashboard. - Audit: 24 tests including TestChatRunFanoutSurfaced429, TestChatClientID- StableAcrossRun, TestInjectEnvelopeClientIDPerRun, TestRetiredRootOverride- AppliesToBothPaths, TestStartDoesNotFanOutAndShutdownDrains.
trefeon
approved these changes
Aug 25, 2026
trefeon
left a comment
Owner
There was a problem hiding this comment.
Verified locally on pr-207: go build -tags dashboard clean, gofmt clean, full hermetic suite passes (env -u AUTH_TOKENS -u ADMIN_TOKEN go test ./...). The per-run client_id threads through both pooled and bridge paths via the shared chatAttempt; the fresh-draw fallback covers runless callers (admin smoke ping). Merging.
Closed
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.
Summary
This PR fixes the
free_mode_run_fanoutrefusal that was killing client turns with a dead 502upstream_unavailable. The root cause was that the proxy was producing the exact "proxy fanout" shape upstream classifies as ban-grade evidence (freebuff-spend-ceilings.ts).Changes
client_idper run (not per call)The CLI mints
client_idonce per prompt (run.ts:722/822) and reuses it on every LLM step. The proxy was drawing a freshclient_idper chat call, making onerun_idfan out across Nclient_ids — the exact anti-pattern upstream refuses. NowClientIDis minted once by the run manager and threaded through the envelope.Dropped prewarm fleet
Pool.Startno longer fans out a run per registry agent per token at boot. That fleet held ~one concurrent agent run per served model on a single free account — the "proxy fanout" sweep signal. Runs now START lazily on firstAcquire.free_mode_run_fanout→ 429 (was 502)The upstream refusal body
{"error":"free_mode_run_fanout","message":"Free mode request rejected."}was falling through to the genericUpstreamErrorbranch → dead 502. Now classified asRateLimitErrorwith boundedFanoutCooldown(60s) and surfaced as 429 so clients back off. Never re-POSTs into a fanout refusal.Luna retired root override
openai/gpt-5.6-luna's root agent was retired upstream (free_mode_legacy_luna_agent). AddedretiredRootOverridesmap:base2-free-luna→base3-free-luna.ScarceSessionError accuracy
Now reports the HELD session's model (not the requested one) for correct
Retry-Afterhints.Run persistence fix
ClientIDis persisted with the run so a restart doesn't split a run's identity.Build tags
Makefile and Taskfile use
-tags dashboardfor Go builds.Tests
All 24 test suites pass. New tests:
TestChatRunFanoutSurfaced429— end-to-end: fanout body → 429 + Retry-After, one chat call onlyTestChatClientIDStableAcrossRun— same client_id across calls on one runTestInjectEnvelopeClientIDPerRun— envelope repeats the run's client_idTestClassifyRunFanout— fanout body classified as RateLimitError on any statusTestRetiredRootOverrideAppliesToBothPaths— offline and live-parse paths agreeTestStartDoesNotFanOutAndShutdownDrains— no boot fleet, drains one lease