Skip to content

macOS: first-prompt socket fails silently on long paths; Gemini UA override dropped by old harness generations #511

Description

@zhulinchng

Summary

Two harness-interop bugs, both reproducible on macOS via the existing suite:

  1. Claude smart-routing v2's first-prompt socket fails silently when the AF_UNIX path exceeds the kernel limit — the serving thread dies on a log-only branch; callers see only a missing socket file / bare RuntimeError.
  2. The Gemini User-Agent override via GEMINI_CLI_CUSTOM_HEADERS is silently dropped by harness generations with the old header merge order. render_env_overlay's comment claims the override works unconditionally.

Bug 1 — socket bind failure is silent

Repro (clean main, macOS, pytest tmp_path under /private/var/folders):

uv run pytest "tests/test_claude_smart_routing_v2.py::TestFirstPromptHook::test_blocks_once_then_allows_replay" \
  "tests/test_claude_smart_routing_v2.py::TestPtyFlow::test_direct_switch_restore_and_replay" -q
# 2 failed

Root cause (src/ucode/smart_routing/claude_pty.py::serve_first_prompt_socket): server.bind() raises OSError: AF_UNIX path too long for the 123-char test socket path (macOS limit ~104), the except OSError branch only log(...)s (no-op by default), the thread exits, no socket file ever appears. Verified directly:

socket.socket(socket.AF_UNIX, socket.SOCK_STREAM).bind(<123-char path>)
# OSError: AF_UNIX path too long

Production sockets live under short ~/.ucode, but any long $HOME hits the same silent death, and the launch error (Smart routing could not start its local prompt-routing socket; Claude was not launched.) names no reason.

flowchart TD
    A[serve_first_prompt_socket] --> B{bind AF_UNIX path}
    B -->|path over kernel limit| C[OSError: AF_UNIX path too long]
    C --> D[caught, log-only, thread exits]
    D --> E[socket file never appears]
    E --> F[hook request returns None / launch raises bare RuntimeError]
Loading

Bug 2 — Gemini UA override dropped by old harness generations

Repro (clean main, installed gemini 0.20.0-nightly.20251201):

uv run pytest tests/test_e2e_user_agent.py::TestGeminiUserAgent -q
# AssertionError: User-Agent mismatch.
#   got:      'GeminiCLI/v26.8.1 (darwin; arm64)'
#   expected: 'ucode/0.1.0+84.gfddf95b gemini/0.20.0-nightly.20251201.2fe609cb6'

Root cause: the installed @google/gemini-cli-core build merges headers as {...customHeadersMap, 'User-Agent': userAgent} (dist/src/core/contentGenerator.js), so a custom User-Agent from GEMINI_CLI_CUSTOM_HEADERS is overwritten by the default. Current upstream main has the fixed order ('User-Agent' first, custom spread after — see packages/core/src/core/contentGenerator.ts and customHeaderUtils.ts, feature from google-gemini/gemini-cli#10088). ucode cannot change harness behavior; the Databricks-Model-Provider-Service routing header is unaffected (distinct key, survives the spread), and gateway spend attribution in usage.py still matches on the gemini substring.

flowchart LR
    subgraph old ["installed generation"]
        H1[GEMINI_CLI_CUSTOM_HEADERS] --> M1["{...custom, UA: default}"] --> W1["wire: GeminiCLI/..."]
    end
    subgraph new ["upstream main"]
        H2[GEMINI_CLI_CUSTOM_HEADERS] --> M2["{UA: default, ...custom}"] --> W2["wire: ucode/..."]
    end
Loading

Environment

  • macOS arm64 (Apple M4), Python 3.13, repo at fddf95b
  • Full-suite baseline: 2262 passed, 7 skipped, 3 failed (the above)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions