Skip to content

fix(local-api): identify the recorded server and serialize launches - #333

Draft
SamGu-NRX wants to merge 1 commit into
gpt-burst/1022z-bs-281-restfrom
gpt-burst/1023-bs-320-session-identity
Draft

SamGu-NRX wants to merge 1 commit into
gpt-burst/1022z-bs-281-restfrom
gpt-burst/1023-bs-320-session-identity

Conversation

@SamGu-NRX

@SamGu-NRX SamGu-NRX commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

What changed

The local capture API no longer treats any live pid plus any accepting loopback port as the recorded server. It proves ownership through a launcher-only /v1/local-session response containing the SHA-256 hash of the session's reviewer token. The probe sends no credential and compares the returned hash with the value derived from the session file.

The fix is in backend/scripts/local_capture_api.py:159-193 and lines 317-360. The launcher also takes an flock on session.lock before reading session.json and holds it through the server lifetime. A second launch exits before it can bind or overwrite the session.

This PR is stacked on gpt-burst/1022z-bs-281-rest.

Why

A stale session file could block startup after pid reuse and an unrelated listener on the recorded port. Two launches could both pass the check, bind different ports, and race while writing credentials.

Verification

With the final regression tests and the original launcher from 832314ca, env -u NODE_ENV OMP_NUM_THREADS=1 uv run pytest -q tests/test_local_capture_api.py::test_reused_pid_and_unrelated_listener_allow_startup tests/test_local_capture_api.py::test_live_session_requires_the_running_servers_identity tests/test_local_capture_api.py::test_concurrent_launches_allow_exactly_one tests/test_local_capture_api.py::test_second_launch_refuses_a_live_session returned 3 failed, 1 passed. The stale listener and wrong token were accepted, and both launches remained alive. The existing real-running-server refusal test was the one that already passed.

After the fix, from backend/, env -u NODE_ENV OMP_NUM_THREADS=1 uv run pytest -q tests/test_local_capture_api.py server/api/tests/test_auth_none.py passed: 29 tests. Ruff check, format check, and git diff --check passed.

Risk

The identity endpoint is added only to the local launcher app. It is not registered in the shared API factory. The lock file remains beside session.json; flock releases it when the process exits, including a crash.

Checklist

  • The scope is focused; related changes belong together
  • I explained what changed and why
  • N/A for images and video. No visual or motion changes.

Generated with Claude Code

Zephyrus full-suite run (Oct 23)

Command: cd backend && uv sync --locked --extra api && env -u NODE_ENV OMP_NUM_THREADS=1 uv run pytest -q

Result: 1,532 passed, 16 skipped, 14 errors, 4 failed in 18m56s.

The 14 errors are the known pre-existing tests/test_capture_cold_restart.py load_receipt import errors. The 4 failures are the known expired KNOWN_FAIL pin in server/eval/tests/test_gates.py. No other failures occurred, so no load-sensitivity rerun was needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 23, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added the size:M 30-99 effective changed lines. label Oct 23, 2026
@SamGu-NRX

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T11:43:46.805475Z 0ea81a0 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 0ea81a06dc

ℹ️ 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 on lines +184 to +188
with _DIRECT.open(f"{_public_url(host, port)}/v1/local-session", timeout=1) as response:
proof = json.loads(response.read(256))
if response.status == 200 and isinstance(proof, dict) and proof.get("identity") == identity:
return session
except (OSError, ValueError):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle incomplete identity responses as a dead session

When the recorded port is occupied by an HTTP listener that closes early or advertises a longer body, response.read(256) can raise http.client.IncompleteRead (an HTTPException, not an OSError or ValueError). That exception escapes _live_session, so a second launcher crashes instead of treating the stale/unrelated session as inactive and starting normally; catch the HTTP read/protocol exceptions along with the existing connection errors.

Useful? React with 👍 / 👎.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 effective changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant