Repository navigation
Conversation
…heir systemd scopes
Contributor
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a contained OpenCode cleanup bug fix with backward-compatible ledger handling and targeted regression tests. It restores orphan-process termination for launcher-to-server exec transitions while retaining the existing identity safeguards. You can add or adjust custom eligibility rules. Learn more. |
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Since agents run in their own systemd scopes (#17662), a T3 server that is SIGKILLed leaves its
opencode serverunning for good, and the next server starts a second one on the same OpenCode database. The OpenCode server ledger (#13879) is meant to catch exactly this, but it never stops these servers.The ledger records the spawned process's command line right after spawn. With scopes, that pid is still the launcher at that point:
/bin/sh -c … t3-agent … systemd-run --user --scope … -- opencode serve --hostname=127.0.0.1 --port=N. It then execs intoopencode serve --hostname=127.0.0.1 --port=N, keeping its pid, group and start time. On the next startstopOrphancompares the full command line, sees a mismatch, and deletes the entry without signalling anything.It happens on ordinary restarts. The service launcher SIGKILLs the server 5 s after SIGTERM, and a server with many threads spends longer than that in its shutdown recovery pass before it reaches the OpenCode finalizer. On a Linux machine with ~900 threads, a plain
systemctl --user restart t3code(stop took 5.2 s) and the in-app update both left the previousopencode serverunning. In one run the orphan finished the turn's shell command and kept working on the session after T3 had restarted, with nobody watching it.Change
args).stopOrphanstill requires the same pid, start time and process group, and now accepts the command line when it ends with those serve arguments, so a launcher that exec'd into the server matches. Entries written before this change (noargs) match when their recorded launcher line ends with the live command line, so the first restart onto this version also stops servers left by an affected one.Scope and approval
A small fix for an obvious regression: the reaper from #13879 silently skips every server started through an agent scope on Linux. No product behavior changes; it only makes the existing cleanup work again. The slow shutdown pass that triggers the SIGKILL is a separate issue and isn't touched here.
Verification
OpenCodeServerLedger.test.ts: two new cases. One records a launcher shaped likesystemd-run --scope -- opencode serve …that then execs into the server under the same pid; the other is an entry from beforeargsexisted. Both fail onmain(the group is never signalled) and pass with the change. The existing cases pass. Thedarwin-observing variants fail on my NixOS machine with or without the change (no/bin/ps).agentScopeCommandwithsystemd-run --user --scopeon systemd 261: the ledger recorded/bin/sh -c { echo 800 >/proc/self/oom_score_adj; } …, the live process becamenode … serve --hostname=127.0.0.1 --port=4999in its own scope, and after killing the recorded owner the reaper onmainleft it running; with this change it stopped it.systemctl --user restart t3codeleft the previous server running (reparented to the user manager, still in itst3code-opencode-*.scope) next to the new one, and its ledger entry was gone with no "Stopping an OpenCode server" log. Same with a restart where the server is stuck past the grace. A gracefult3 updatethat finished within 5 s stopped the server correctly. On a real host, the update at 19:38 UTC left an idleopencode serverunning for over 24 h.vp fmt,vp lintandtsc-rs --noEmitinpackages/provider-opencodeare clean.Model: Claude Opus 5.5 (1M). Harness: OpenCode in T3 Code.