Conversation
trs-80
requested review from
DevanshiVyas,
JerrettDavis and
chopratejas
as code owners
September 25, 2026 21:59
Contributor
PR governanceThis PR follows the template and is marked ready for human review. |
`_check_proxy` is a bare TCP connect, so any service squatting the port (observed: a caveman gateway on 8787) passed as a live Headroom proxy: wrap reused it, persistent-deployment recovery waited on it, and the dead-marker self-heal treated it as a live session. A listener is now Headroom only if /health or /config answers like one; otherwise wrap falls through to the port search. Also in the fallback path: - the launch banner shows the port the child actually receives - `wrap claude` stamps the marker/owner claim with the actual port - a selfheal SessionStart hook whose command drifted is rewritten in place instead of being left pointing at a stale binary - the vertex proxy-env test runs in an isolated cwd so it cannot write a selfheal hook into the repo's .claude/settings.local.json Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
trs-80
force-pushed
the
fix/wrap-foreign-listener
branch
from
September 25, 2026 22:02
7ed3159 to
6f21115
Compare
This branch has not been deployed
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.
Description
headroom wrapdecided a proxy was running with_check_proxy, which is a bare TCP connect. Any service listening on the wrap port passed that check. When something other than Headroom held the port (seen in practice: a caveman gateway on 8787), wrap would:A listener now counts as Headroom only if
/healthor/configanswers like one. Otherwise wrap uses the existing port search.Split out of #3366. These fixes apply to every harness and don't depend on the wrap-target registry.
Closes #
Type of Change
Changes Made
headroom/cli/wrap.py:_foreign_listener(port): TCP accepts, but neither/healthnor/configidentifies Headroom._ensure_proxy_unlocked: a foreign listener is never reused. The port search takes over, and a persistent manifest on a foreign-held port falls through to a fresh proxy instead of raising "not healthy"._check_and_clear_dead_wrap_marker: a foreign listener on a dead wrapper's port no longer counts as a live session (the marker is kept while the writer PID is alive)._launch_tool: on port fallback the launch banner is rewritten too, so it shows the URL the child actually got (the env already was).wrap claude: the marker/owner claim recordsactual_portinstead of the requested port._ensure_claude_wrap_selfheal_hook: a marker-bearing hook whose command drifted (hand edit, moved binary) is rewritten in place instead of skipped.tests/test_cli/test_wrap_claude_vertex_proxy_env.py: runs in an isolated cwd so it can't write a selfheal hook into the repo's.claude/settings.local.json. Also gitignored.claude/.headroom_wrap_*.json.Testing
pytest)ruff check .)mypy headroom)Test Output
New:
tests/test_cli/test_wrap_foreign_listener.py(9 tests),test_wrap_selfheal_hook_repairs_stale_command. Updated:test_wrap_kimi.py::test_non_kimi_fallback_display_follows_actual_port(asserted the old stale banner), plus twotest_wrap_persistent.pytests that now identify the listener as Headroom via/health.Real Behavior Proof
mainat 3aa5012python3 -m http.server 8899as a foreign listener (its/healthreturns 404); a stubgooseon PATH that printsOPENAI_BASE_URLand curls$ANTHROPIC_BASE_URL/health; thenheadroom wrap goose --port 8899Proxy already running on port 8899→ child getshttp://127.0.0.1:8899/v1, and its/health→ 404 (the tool is talking to the squatter)Port 8899 is in use by a non-Headroom service; selecting another port...→ proxy starts on 8900, banner and child both showhttp://127.0.0.1:8900/v1,/health→ 200headroom install) deployment whose port was taken over (covered bytest_persistent_manifest_on_foreign_port_falls_through)Runtime Rollout Safety
/healthand reused exactly as before.--portto choose a free port explicitlyReview Readiness
Checklist
CHANGELOG.md— it is generated by release-please from my Conventional Commit PR title (a CI guard enforces this)Additional Notes
🤖 Generated with Claude Code