fix: relaunch a killed opencode on local create #523

Merged
dries merged 2 commits from fix/ensure-opencode-on-local-create into main 2026-08-20 09:26:10 +02:00
Owner

Problem

When a project's opencode instance is killed outside ocman, creating a new
session in that project fails forever:

WARN no running OpenCode instance for directory
     requested=/Users/dries/src/github.com/NoUseFreak/ocman
     discovered_dirs=[.../aspect-infra=50634 .../scratch=61265]
WARN hub: create session failed
     error="no running OpenCode instance for directory ...: platforms: no running instance for this location"

handleCreateSession pre-ensured the project's instance only for remote
sessions:

// Local Create discovers/launches its own port and needs no pre-ensure here.
if remoteID != "" && req.Directory != "" {

That comment was wrong. Local CreateSession only ever discovers a port via
lsof — it never launches. So a killed instance left the local path with no
recovery at all, while remote sessions recovered fine. Message sends already
self-heal through sendNow -> relaunchOpencodeForSession; create-session was
the one remaining hole.

Change

Run EnsureProjectOpencode for local creates too, routed through the same
resolveOwner seam (an empty remote id resolves to the hub's local host).

  • Worktree directories fold back to the project root via
    projectRootForDirectory, so ensuring a worktree path cannot launch a
    second instance for the same project.
  • A remote ensure failure stays fatal — the remote has no discovery fallback,
    so Create would fail anyway.
  • A local ensure failure is soft: a non-repo directory, or a host that cannot
    launch, still creates against whatever discovery finds. Unchanged behaviour
    for those cases.

Tests

Three new tests in internal/server/integration_test.go:

  • TestHandleCreateSession_LocalEnsuresBeforeCreate
  • TestHandleCreateSession_EnsuresProjectRootNotWorktree
  • TestHandleCreateSession_LocalEnsureFailureFallsBackToDiscovery

The first two fail on the unpatched handler (verified red before the fix):

--- FAIL: TestHandleCreateSession_LocalEnsuresBeforeCreate
    integration_test.go:356: local host was not ensured; ensured=""
--- FAIL: TestHandleCreateSession_EnsuresProjectRootNotWorktree
    integration_test.go:392: ensure was not folded to the project root; ensured=""

go test ./internal/..., go vet ./... and golangci-lint run are clean.

## Problem When a project's opencode instance is killed outside ocman, creating a new session in that project fails forever: ``` WARN no running OpenCode instance for directory requested=/Users/dries/src/github.com/NoUseFreak/ocman discovered_dirs=[.../aspect-infra=50634 .../scratch=61265] WARN hub: create session failed error="no running OpenCode instance for directory ...: platforms: no running instance for this location" ``` `handleCreateSession` pre-ensured the project's instance only for remote sessions: ```go // Local Create discovers/launches its own port and needs no pre-ensure here. if remoteID != "" && req.Directory != "" { ``` That comment was wrong. Local `CreateSession` only ever *discovers* a port via `lsof` — it never launches. So a killed instance left the local path with no recovery at all, while remote sessions recovered fine. Message sends already self-heal through `sendNow` -> `relaunchOpencodeForSession`; create-session was the one remaining hole. ## Change Run `EnsureProjectOpencode` for local creates too, routed through the same `resolveOwner` seam (an empty remote id resolves to the hub's local host). - Worktree directories fold back to the project root via `projectRootForDirectory`, so ensuring a worktree path cannot launch a second instance for the same project. - A remote ensure failure stays fatal — the remote has no discovery fallback, so Create would fail anyway. - A local ensure failure is soft: a non-repo directory, or a host that cannot launch, still creates against whatever discovery finds. Unchanged behaviour for those cases. ## Tests Three new tests in `internal/server/integration_test.go`: - `TestHandleCreateSession_LocalEnsuresBeforeCreate` - `TestHandleCreateSession_EnsuresProjectRootNotWorktree` - `TestHandleCreateSession_LocalEnsureFailureFallsBackToDiscovery` The first two fail on the unpatched handler (verified red before the fix): ``` --- FAIL: TestHandleCreateSession_LocalEnsuresBeforeCreate integration_test.go:356: local host was not ensured; ensured="" --- FAIL: TestHandleCreateSession_EnsuresProjectRootNotWorktree integration_test.go:392: ensure was not folded to the project root; ensured="" ``` `go test ./internal/...`, `go vet ./...` and `golangci-lint run` are clean.
fix: relaunch a killed opencode on local create
All checks were successful
CI / Frontend (pull_request) Successful in 8m35s
CI / Playwright E2E (pull_request) Successful in 9m54s
CI / Backend (pull_request) Successful in 12m33s
CI / Build (pull_request) Successful in 4m2s
CI / Semantic Tag (pull_request) Successful in 9s
CI / Coverage Results (pull_request) Successful in 21s
1d62929e81
Local session creation only ever discovered a port via lsof, so once a
project's opencode was killed outside ocman every create failed with
"no running OpenCode instance for directory" and never recovered. Only
remote creates pre-ensured the instance; the local branch was skipped on
the (wrong) grounds that it launches its own port.

Run the ensure for local creates too, folding worktree paths back to the
project root so a worktree create cannot launch a second instance. A
remote ensure failure stays fatal since the remote has no discovery
fallback; a local failure is soft so a non-repo directory still creates
against whatever discovery finds.

Coverage ratchet: ✅ pass

Suite Baseline This PR Δ
frontend 71.22% 71.19% -0.03 ✅
go 81.30% 81.30% +0.00 ✅

Tolerance: -0.1%. Baseline stored on gh-pages.

<!-- coverage-ratchet --> ### Coverage ratchet: ✅ pass | Suite | Baseline | This PR | Δ | | |---|---|---|---|---| | frontend | 71.22% | 71.19% | -0.03 | ✅ | | go | 81.30% | 81.30% | +0.00 | ✅ | _Tolerance: -0.1%. Baseline stored on `gh-pages`._
fix: pin local create-session ensure to the hub's own host
All checks were successful
CI / Frontend (pull_request) Successful in 7m33s
CI / Playwright E2E (pull_request) Successful in 9m23s
CI / Backend (pull_request) Successful in 10m22s
CI / Build (pull_request) Successful in 4m28s
CI / Semantic Tag (pull_request) Successful in 9s
CI / Coverage Results (pull_request) Successful in 21s
87963af92d
resolveOwner with an empty remote id falls through to ForDir, whose
inventory resolver can map the directory to a remote that knows the
same absolute path — ensuring there launches opencode on the wrong
machine and hands the hub's local adapter a port that means nothing
locally. A platform without a compound id is the hub's own adapter, so
the ensure resolves "local" explicitly.
dries merged commit 3afe16c6b9 into main 2026-08-20 09:26:10 +02:00
dries deleted branch fix/ensure-opencode-on-local-create 2026-08-20 09:26:10 +02:00
Sign in to join this conversation.
No description provided.