Skip to content

fix: prevent reconcileAndEnrich from falsely stopping fuse-tracked sessions#147

Merged
c-h- merged 1 commit intomainfrom
fix/146-fuse-reconcile-race
Mar 13, 2026
Merged

fix: prevent reconcileAndEnrich from falsely stopping fuse-tracked sessions#147
c-h- merged 1 commit intomainfrom
fix/146-fuse-reconcile-race

Conversation

@c-h-
Copy link
Copy Markdown
Collaborator

@c-h- c-h- commented Mar 13, 2026

Problem

The daemon falsely marks opencode sessions as stopped within seconds of launch (#146).

Root cause: reconcileAndEnrich() in session-tracker.ts has a 30s grace period. After that, if the opencode adapter's list() doesn't return the session (opencode doesn't persist running sessions to native storage), the daemon assumes it's dead. This fires before the lifecycle fuse (#144) ever gets a chance to detect real completion.

Evidence: Two sessions launched 2026-03-12 were marked stopped in ~10s but actually ran ~20 minutes and opened PRs.

Fix

reconcileAndEnrich() now checks for an active fuse + alive PID before marking a session stopped. If both conditions hold, the session stays running and the fuse handles lifecycle detection as intended.

Also wires up fuse set/cancel in the daemon's launch and stop paths so every launched session gets a fuse automatically.

Changes

  • session-tracker.ts: reconcileAndEnrich accepts optional hasFuse(id) + isAlive(pid) callbacks; skips stopping sessions that have active fuses with alive PIDs
  • server.ts: Passes fuse engine check to session tracker; sets fuse on launch, cancels on stop
  • session-tracker.test.ts: 4 new regression tests covering fuse+PID behavior

Verification

  • 589 tests passing (35 test files)
  • npm run typecheck
  • npm run lint
  • npm run build

E2E Proof

Session 2fb3f47b — 68-second opencode session creating a Node.js project:

=== 5 seconds ===
Status     running
Started    11s ago

=== 35 seconds (PAST OLD 30s GRACE PERIOD) ===
Status     running          ← FIX WORKING: would have been 'stopped' before
Started    41s ago

=== 65 seconds ===
Status     stopped           ← genuinely completed
Started    1m ago

Daemon state confirms correct timing:

  • startedAt: 2026-03-13T05:50:57.650Z
  • stoppedAt: 2026-03-13T05:52:05.754Z
  • Duration: 68.1s

Webhook delivered to OrgLoop → agentctl-supervisor route fired ✅

Fixes #146

…ssions

When the opencode adapter's list() doesn't return a running session
(because opencode doesn't persist running sessions to native storage),
reconcileAndEnrich() would mark it stopped after the 30s grace period.
This fires before the lifecycle fuse ever gets a chance to detect the
real session completion.

Fix: check for an active fuse AND alive PID before marking a session
stopped. If both conditions hold, the session stays running and the
fuse handles lifecycle detection.

Also wires up fuse set/cancel in the daemon's launch/stop paths.

Fixes #146
@c-h- c-h- merged commit 650adb9 into main Mar 13, 2026
1 check passed
@c-h- c-h- deleted the fix/146-fuse-reconcile-race branch March 13, 2026 21:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: daemon falsely marks opencode sessions as stopped within seconds of launch

1 participant