Repository navigation
Conversation
The runtime manager's ownership proof took a process's executable to be its
live argv[0] resolved at check time. For a uv/pipx console script, argv[0] is
the venv's bin/python symlink. Reinstalling the tool recreates that link, and
`uv python upgrade` moves the minor-version link beneath it. When either
points at a different interpreter, the resolved path no longer equals the
one recorded at spawn. stop, start, status and repair then disowned the
still-running watcher and dashboard ("does not match agentacct ownership
proof; no process was signalled"), so the documented deploy order
`uv tool install ... && agentacct stop && agentacct start` got stuck.
- Record the kernel-reported program image (psutil exe()) as a new
ManagedProcess.image field, read from a fresh Process on each handshake
poll because psutil caches exe() per object and would otherwise keep the
transient pre-exec image.
- Accept the executable when either the recorded launch path or the
recorded image matches either the live launch path or the live image.
The previous check is one of these routes, so nothing that matched before
stops matching. A pre-image record is matched through the live image,
so a runtime started by an earlier release can be stopped after upgrading.
- Treat a symlink returned by exe() as unknown. The kernel never reports
one, so it is psutil guessing from argv[0] (macOS, running file deleted),
and following it would name the link's new target.
- Birth time, process group, cwd, full argv and the per-start nonce are
unchanged, and state.json keeps its schema version; older releases
ignore the new key.
Tests launch a real runtime through a venv-style interpreter link, retarget
the link, and assert status/start/stop still own it, including for a record
written without an image. They also cover refusing a record that names a
different program, the match table, and the fresh-Process handshake.
This branch has not been deployed
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.
agentacct stop,start,statusandrepairdisowned a still-running recorder after its interpreter symlink moved under it.stopfailed with "does not match agentacct ownership proof; no process was signalled", andstartrefused to replace the processes. The upgrade orderuv tool install "agentacct==X.Y.Z" --force && agentacct stop && agentacct startgot stuck whenever the reinstall picked a different interpreter.Cause
The runtime manager's ownership proof took the executable to be the live
argv[0]resolved at check time. For a uv/pipx console script on a non-framework interpreter,argv[0]is the venv'sbin/pythonsymlink.uv tool install --forceor a pipx reinstall recreates that link, anduv python upgrademoves the minor-version link beneath it (cpython-3.12-… → cpython-3.12.N-…). Either way the path resolved at check time stopped equalling the one recorded at spawn, even though every other identity field (birth time, pgid, cwd, argv, nonce) and the running image were unchanged.Fix
ManagedProcessgainsimage: the kernel-reported program file (psutilexe()), recorded at spawn. The handshake reads it from a freshProcesson each poll, because psutil cachesexe()per object and would keep the transient pre-exec image such as/usr/bin/env._executable_matchesaccepts when either{recorded launch path, recorded image}matches either{live launch path, live image}. The previous check is one of these routes, so nothing that matched before stops matching. Records written by earlier releases have noimageand are matched through the live image, so a runtime started by an older release can be stopped after upgrading to this one._running_imagetreats a symlink result as unknown. A running program is a regular file, so a symlink is either psutil guessing fromargv[0](on macOS, after the running file was deleted) or a stale path. Following it would name the link's new target.state.jsonkeeps its schema version, and older releases ignore the new key.Scope:
(deleted).Tests
In
tests/test_runtime_manager.py:status,startandstopstill own the process.image._running_imagefallbacks: empty, symlink,AccessDenied,NoSuchProcessandOSErrorresults all return empty.exe()like psutil, which pins the fresh-Processread.The link-based tests skip on macOS framework builds. Their launcher rewrites
argv[0]toPython.app, so there is no venv link in the live argv to retarget.Verification
pytest -q: 4909 passed.activation.py, wherestopwas refused with the exact production error. With the fix,statusreadsrunningandstopstops.