Repository navigation
fix(forge-cli): optimizer stop no longer restores the proxy's own dead URL - #540
Open
ratnesh-maurya wants to merge 1 commit into
Open
ratnesh-maurya wants to merge 1 commit into
ratnesh-maurya wants to merge 1 commit into
Conversation
…restore `optimizer start` captured whatever ANTHROPIC_BASE_URL was in ~/.claude/settings.json as prev_base_url, with no check that forge had written it. A second start (including the adopt path, where a proxy is already running and the settings are already wired) therefore saved http://127.0.0.1:8787 — the optimizer's own address — as the thing to revert to. `stop` then restored it faithfully, leaving every `claude` pointed at a dead proxy: API Error: Connection refused (ECONNREFUSED) ENABLE_TOOL_SEARCH had the same flaw: prev_tool_search became forge's own "true", so stop left tool search enabled instead of removing the key. A user whose real base URL was a gateway lost it outright — the second start overwrote the saved gateway, so stop could never put it back. sanitizePrevWiring now discards a captured value that forge wrote itself — matching our current listen addr, or the one the prior daemon state recorded, so a start on a different --listen still spots stale wiring — and carries the prior state's genuine originals forward instead. Because a self-written base URL means the tool-search value is ours too, both are replaced together rather than trusted independently. Fixes initializ#539
Member
Author
|
@initializ-mk could you take a look when you have a moment? |
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.
Fixes #539.
What & why
forge optimizer startcaptured whateverANTHROPIC_BASE_URLsat in~/.claude/settings.jsonasprev_base_url, with no check that forge itself had written it. A secondstart— including the adopt path, where a proxy is already running and the settings are already wired — therefore recordedhttp://127.0.0.1:8787, the optimizer's own address, as the value to revert to.stopthen restored it faithfully:Every
claudein every terminal now pointed at a dead proxy, and the error blames a firewall rather than forge. Recovery required hand-editing~/.claude/settings.json.The same line hit two more cases:
ENABLE_TOOL_SEARCHhad the identical flaw one line down —prev_tool_searchbecame forge's own"true", sostopleft tool search enabled instead of removing the key.optimizer.upstream, optimizer: forward an explicit upstream fromstart(flag + settings chaining) #523), the secondstartoverwrote the saved gateway with the proxy address, sostopcould never put it back.This breaks the invariant the package comment already claims: "
stopreverts it precisely, soclaudenever ends up pointed at a dead proxy."Change
sanitizePrevWiring(pure, inoptimizer_daemon.go) discards a captured value that forge wrote itself, and carries the prior daemon state's genuine originals forward instead:forgeWiredBaseURL) matches both the current listen address and the one the prior state recorded, so astarton a different--listenstill recognizes stale wiring rather than treating the old proxy URL as a user value. Trailing slash tolerated.ENABLE_TOOL_SEARCHread back is ours too, so both are replaced from the prior state rather than trusted independently — the value"true"alone cannot distinguish forge's write from the user's.runOptimizerStartloads the prior state before wiring (readOptDaemonState); nil on a clean start, in which case a self-written value degrades to "key was absent", which is correct.Same class of guard as the existing
resolveChildUpstreamself-loop check (#523) — forge must not mistake its own address for the user's configuration, on the restore path as well as the forward path.Tests
End-to-end against a sandboxed
HOME,start→start→stop, nothing set beforehand:envafterstopmainANTHROPIC_BASE_URL: http://127.0.0.1:8797,ENABLE_TOOL_SEARCH: trueWith a pre-existing
https://gw.corp.example/ENABLE_TOOL_SEARCH: false, the gateway survives the doublestartand is restored exactly.Unit coverage in
optimizer_daemon_test.go— seven table cases plus a named regression test for the reported break:starton a new port still spots the old wiring127.0.0.1:3000is still treated as a genuine previous valueTestSanitizePrevWiring_StopNeverRestoresDeadProxy—start→start→stopleaves neither key behindgofmt,go vet,golangci-lint run ./forge-cli/...(0 issues) and the fullforge-clisuite are green.Not in this PR
The stale MCP registration noted under "Related" in #539:
stopderegistersforge-optimizer, but only viaclaude mcp remove, so a failure there leaves the entry behind and every later session reportsforge-optimizer (ECONNREFUSED). Separate change.Upgrade note
The fix prevents a daemon state file from being poisoned; it does not repair one already poisoned. A user whose
~/.forge/optimizer-daemon.jsoncurrently holds"prev_base_url": "http://127.0.0.1:8787"should set that field tonullbefore the nextstop, or deleteANTHROPIC_BASE_URLfrom~/.claude/settings.jsonafterward.Checklist
go test ./...)gofmt -w)golangci-lint run)go vetreports no issues