Skip to content

fix(tailscale): preserve occupied Serve handlers - #8338

Open
lastobelus wants to merge 7 commits into
pingdotgg:mainfrom
lastobelus:fix/tailscale-serve-ownership
Open

fix(tailscale): preserve occupied Serve handlers#8338
lastobelus wants to merge 7 commits into
pingdotgg:mainfrom
lastobelus:fix/tailscale-serve-ownership

Conversation

@lastobelus

@lastobelus lastobelus commented Aug 27, 2026

Copy link
Copy Markdown

T3 currently treats an unreachable Serve backend as permission to replace its port, and dev sharing can proxy IPv4 to a Vite listener that resolved localhost as IPv6. That can overwrite another application's persistent handler and can produce a shared URL that always returns 502.

This change treats live Serve configuration as the ownership authority. T3 reuses or removes only an exact root handler for its loopback target, refuses any other occupied handler, and makes shared dev choose the same explicit IPv4 loopback for both Vite and Tailscale without pinning remote HMR to loopback.

Focused validation: 241 tests across shared dev proxy, Tailscale, dev sharing/runner, pairing, and server integration; shared, Tailscale, web, scripts, and server typechecks; scoped lint and formatting.

Implemented with GPT-5.6 Sol through the Codex harness.


Note

Medium Risk
Changes remote-access and Tailscale Serve lifecycle on machines that share ports with other apps; behavior is safer but pairing/dev-share can fail where they previously overwrote handlers.

Overview
Tailscale Serve no longer blindly configures or clears HTTPS ports. ensureTailscaleServe and disableTailscaleServe consult tailscale serve status --json and only create, reuse, or remove a mapping when the port is free or the existing handler is a single root proxy to the expected loopback URL; foreign handlers, multi-route configs, Funnel, and mismatched backends yield TailscaleServePortOccupiedError. Verified dev pairing can opt into replaceVerifiedHandler to repoint an already-proven mapping to the Vite port.

Dev sharing and pairing drop the old “clear then serve” flow: shareDevServer calls ensure directly, t3 pair maps occupied errors to user-facing port errors, and server shutdown passes localPort/localHost into disable so only T3-owned handlers are turned off. DevServeFailedError loses its stage field and messages no longer claim a prior mapping was cleared.

Shared dev over Tailscale sets T3CODE_WEB_BIND_HOST to 127.0.0.1 (via new resolveWebDevServerHost in devProxy) so Vite listens on the same IPv4 address the Serve proxy targets, while HMR stays derived from the page origin unless desktop explicitly sets HOST. Docs describe the new port-ownership rules.

Reviewed by Cursor Bugbot for commit 1c54d3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve occupied Tailscale Serve handlers in ensureTailscaleServe and disableTailscaleServe

  • ensureTailscaleServe now probes Serve status before configuring and only maps a port when it is absent or already points to the exact expected target; otherwise it returns TailscaleServePortOccupiedError
  • disableTailscaleServe requires localPort and optional localHost and only removes a handler that still fronts the expected proxy target, leaving unrelated or funnel-enabled mappings intact
  • Dev share (shareDevServer / unshareDevServer) drops the pre-clear step and surfaces a friendly error when the port is occupied by another handler
  • dev-runner and Vite config bind to SHARED_DEV_LOOPBACK_HOST (IPv4 loopback) via T3CODE_WEB_BIND_HOST when sharing is enabled, keeping HMR host implicit
  • Behavioral Change: runTailscaleCommand now returns stdout on success and TailscaleCommandExitError carries stdoutLength; callers that ignored the return value are unaffected, but any caller relying on the old single-void signature of disableTailscaleServe must pass localPort and localHost

Macroscope summarized 1c54d3f.

@lastobelus

Copy link
Copy Markdown
Author

@codex review

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8973f95c-a30c-4cd5-807a-7ca8feb59516

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: the widened ensureTailscaleServe error channel is collapsed into a generic wrapper at the pair translation boundary, so the new occupied-port failure surfaces the wrong caller-visible message.

Posted via Macroscope — Effect Service Conventions

Comment thread packages/tailscale/src/tailscale.ts
Comment thread docs/internals/remote.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 858e5eed86

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/tailscale/src/tailscale.ts Outdated
Comment thread packages/tailscale/src/tailscale.ts
Comment thread docs/user/remote-access.md
@macroscopeapp

macroscopeapp Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The change materially alters shared Tailscale Serve setup, replacement, and cleanup across pairing, server shutdown, and development sharing, including new external-status parsing and ownership decisions. Its intent is protective, but the cross-cutting stateful behavior and persistent handler side effects merit human review.

You can add or adjust custom eligibility rules. Learn more.

@lastobelus

Copy link
Copy Markdown
Author

The patch-identical LastCode port is open as lastobelus#102. Downstream head f153060389a857a8a717c5ace0fe9884ffe17556 preserves -x provenance to this exact upstream series.

Comment thread packages/tailscale/src/tailscale.ts
@lastobelus

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6f6d04d5f4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/tailscale/src/tailscale.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7b7bbaf. Configure here.

Comment thread packages/tailscale/src/tailscale.ts Outdated
@lastobelus

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7b7bbaf8ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/tailscale/src/tailscale.ts Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review: one finding on the new error translation boundary in apps/server/src/cli/pair.ts.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/cli/pair.ts
@lastobelus

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: d8d738dbd9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@lastobelus

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 1c54d3f294

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

lastobelus added a commit to lastobelus/lastCode that referenced this pull request Aug 27, 2026
Tailscale Serve mappings persist independently of their loopback
backends. LastCode previously treated a failed HTTP probe as permission
to replace a configured port, and development sharing could proxy IPv4
while Vite listened only on IPv6 localhost.

This ports pingdotgg#8338 exactly into LastCode. It treats the
live Serve configuration as authoritative, reuses or removes only a
handler whose root proxy exactly matches the current LastCode lifecycle,
refuses occupied foreign handlers even when their backend is
unavailable, and makes shared development bind both Vite and its proxy
to `127.0.0.1`. Ordinary non-shared development remains on `localhost`.

Upstream source: pingdotgg#8338
Upstream head: `858e5eed8675b2025ec39118c7c9ae23edb7a4ad`

Validation:

- 6 focused files, 242 tests
- shared, tailscale, web, scripts, and server typechecks
- scoped lint, formatting, and diff checks
- normal guarded LastCode quick CI, including 2,837 server tests

Authored with GPT-5.6 Sol through the Codex harness.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant