Skip to content

[tui] The LSP scenarios fail on their second run: a read-only module cache in the throwaway HOME #115

Closed

Description

@yusiwen

Context

The gated LSP scenarios cannot be run twice in a row. make test-tui-lsp passes on a fresh
/tmp and the second run fails:

== tui/testdata/scenarios/lsp-diagnostics.scenario
ok: 14 steps
== tui/testdata/scenarios/lsp-diagnostics.scenario
    Error: LLM call failed: api call: Post "http://127.0.0.1:18511/v1/chat/completions":
    dial tcp 127.0.0.1:18511: connect: connection refused

The connection error says nothing about LSP. Each scenario runs the binary with
HOME=/tmp/tinyscen-home-lsp and opens with

rm -rf /tmp/tinyscen-home-lsp && mkdir -p ... && python3 .../openai_stub.py 18511 read & sleep 1; ./bin/tinycode ...

gopls resolves the workspace through that redirected HOME, so it fills $HOME/go/pkg/mod with
the Go module cache. Those directories are read-only (0555), rm -rf needs write permission on
them, so the wipe exits 1, the && chain stops before the stub is started, and the TUI
reports a connection error against a server nobody launched.

Measured on this machine (macOS, gopls 0.23.0, Go 1.27.1):

step result
du -sh /tmp/tinyscen-home-lsp-tools/go after one run 96M
rm -rf /tmp/tinyscen-home-lsp-tools exit 1, directory still there
chmod -R u+w ...; rm -rf ... exit 0, directory gone

CI never sees it: the runner's /tmp starts empty and each job runs the scenarios once. The
failure mode is the expensive part — a wipe that fails is invisible, and what surfaces is an
unrelated connection error.

What to build

  • tui/testdata/scenarios/lsp-*.scenario: drop the write permission before the wipe, and keep
    the wipe outside the && chain that starts the stub —
    chmod -R u+w <home> 2>/dev/null; rm -rf <home>; mkdir -p ... && printf ... && python3 ... & sleep 1; ...
    so a wipe that somehow still fails cannot stop the stub from starting.
  • make test-tui-lsp runs every lsp-*.scenario: it names lsp-diagnostics.scenario
    explicitly today, so a second LSP scenario would be skipped in silence.

Acceptance

  • With gopls on PATH, make test-tui-lsp run twice in a row exits 0 both times, with
    ok: <n> steps for every lsp-*.scenario.
  • Capture recipe if it returns: make test-tui-lsp > /tmp/lsp.txt 2>&1, then read /tmp/lsp.txt.
    connection refused means the stub never started (this issue); any other failure belongs to
    the assertion that failed, not to the wipe.
  • make test-tui-scenarios still skips every lsp-* file with the "run make test-tui-lsp" line.

Activity

  1. added
    bugSomething isn't working
    testsTest coverage and test infrastructure
    on Oct 4, 2026
  2. yusiwen commented on Oct 4, 2026

    @yusiwen
    OwnerAuthor

    Fixed in #116, rebase-merged onto master as 9a910aa..6e1a438.

    What landed

    • tui/testdata/scenarios/lsp-diagnostics.scenario and the new lsp-tools.scenario drop the write
      permission before the wipe and keep it out of the && chain that starts the stub:
      chmod -R u+w <home> 2>/dev/null; rm -rf <home>; mkdir -p … && printf … && python3 … & sleep 1; …
      A wipe that fails can no longer stop the stub from starting, which is what turned this into an
      unrelated connection refused.
    • make test-tui-lsp runs every lsp-*.scenario instead of naming one file, and
      make test-tui-scenarios skips them by the same *lsp-* pattern, so a third LSP scenario cannot
      be skipped in silence.

    Measured

    With gopls 0.23.0 on PATH:

    • Before: run 1 ok: 14 steps, run 2 died on dial tcp 127.0.0.1:18511: connect: connection refused, leaving 96M under the throwaway HOME; rm -rf on it exited 1, chmod -R u+w then
      rm -rf exited 0.
    • After: make test-tui-lsp twice in a row → exit 0 both times, 4× ok: 14 steps.

    The rule is recorded in AGENTS.md and docs/tui-verification.md so the next lsp-* scenario does
    not reintroduce it. CI keeps its blind spot — its /tmp starts empty — so the reproduction stays
    "run make test-tui-lsp twice".

    Nothing handed off.

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

    bugSomething isn't workingtestsTest coverage and test infrastructure

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions