Summary
Updating the PV application can add an avoidable ~10-second delay while restarting the daemon. During a local update from PV 0.2.0 to 0.2.2, the first launchd spawn of the new binary failed with a launch-constraint violation. launchd then throttled the service for exactly ten seconds before a retry succeeded.
This was not caused by Managed Resource downloads. The Managed Resource phase refreshed/checked the manifest, found every installed resource current, and completed in approximately one second.
Environment
- PV update: 0.2.0 → 0.2.2
- macOS: 26.5.1 (25F80)
- Darwin: 25.5.0
Observed timeline
22:30:19 PV 0.2.2 binary activated; daemon stopped
22:30:19.768 xpcproxy rejected the first daemon spawn
22:30:19.768 launchd deferred the next spawn by 10 seconds
22:30:21.337 launchd reported the service was still throttled
22:30:28.084 launchd reported the service was still throttled
22:30:29.871 daemon spawned successfully
22:30:29–30 Managed Resource update job completed with summary `current`
Relevant unified-log entries:
xpcproxy exited due to OS_REASON_CODESIGNING | Launch Constraint Violation,
error info: c[5]p[1]m[1]e[0], (Constraint not matched) ...
/Users/clovismuneza/.pv/bin/releases/0.2.2/pv
service spawn deferred by 10 seconds due to throttle
Successfully spawned pv[...] because inefficient
The update command took approximately 11 seconds overall.
Resource-update evidence
- The daemon update job completed with summary
current.
- Installed Managed Resource release directories and binaries had no mtimes near the update.
- No new Managed Resource artifact was installed.
- A remote resource-manifest refresh/comparison still occurred, as expected.
Likely cause
This portion is strongly supported but not yet reproduced in an isolated test:
- The LaunchAgent uses the stable
~/.pv/bin/pv symlink.
- Self-update switches that symlink from the previous release binary to the new release binary.
normalize_launch_agent considers the plist current because its text/path did not change.
restart_daemon_without_reconciliation therefore runs only launchctl kickstart -k; it does not run bootout and bootstrap.
- The old and new binaries have different ad-hoc signing identifiers and CDHashes.
- macOS rejects the first spawn of the new symlink target against its launch constraint, then launchd's normal failure throttle delays the retry by ten seconds.
Confidence:
- High: the ten-second launchd throttle caused the delay.
- High: no Managed Resource binaries were downloaded.
- Medium-high: reusing the existing launchd registration after changing the symlink target caused the constraint mismatch.
Expected behavior
After activating a new PV release, the daemon should start successfully on its first launch attempt. pv update should not silently depend on launchd's throttled retry.
Proposed narrow solution
When the PV application binary changes, reload the owned LaunchAgent registration before starting the daemon:
launchctl bootout the existing PV service, tolerating the existing already-unloaded condition.
launchctl bootstrap the current PV LaunchAgent plist.
launchctl kickstart -k the newly registered service.
- Keep the current daemon health wait and rollback behavior.
The plist does not need to be rewritten if its contents are already current; only the launchd registration needs refreshing after activation.
Acceptance criteria
- An app update reloads the LaunchAgent registration after switching the active binary.
- The updated daemon starts on the first attempt without a launch-constraint violation or ten-second throttle.
- The current rollback path still restores and starts the previous release if the updated daemon fails health checks.
- Integration coverage asserts the app-update restart sequence and preserves the existing current-app/no-update behavior.
- No changes are made to Managed Resource update/download behavior as part of this fix.
Notes
TLS/project reconciliation began later and was not responsible for the foreground update duration.
Summary
Updating the PV application can add an avoidable ~10-second delay while restarting the daemon. During a local update from PV 0.2.0 to 0.2.2, the first launchd spawn of the new binary failed with a launch-constraint violation. launchd then throttled the service for exactly ten seconds before a retry succeeded.
This was not caused by Managed Resource downloads. The Managed Resource phase refreshed/checked the manifest, found every installed resource current, and completed in approximately one second.
Environment
Observed timeline
Relevant unified-log entries:
The update command took approximately 11 seconds overall.
Resource-update evidence
current.Likely cause
This portion is strongly supported but not yet reproduced in an isolated test:
~/.pv/bin/pvsymlink.normalize_launch_agentconsiders the plist current because its text/path did not change.restart_daemon_without_reconciliationtherefore runs onlylaunchctl kickstart -k; it does not runbootoutandbootstrap.Confidence:
Expected behavior
After activating a new PV release, the daemon should start successfully on its first launch attempt.
pv updateshould not silently depend on launchd's throttled retry.Proposed narrow solution
When the PV application binary changes, reload the owned LaunchAgent registration before starting the daemon:
launchctl bootoutthe existing PV service, tolerating the existing already-unloaded condition.launchctl bootstrapthe current PV LaunchAgent plist.launchctl kickstart -kthe newly registered service.The plist does not need to be rewritten if its contents are already current; only the launchd registration needs refreshing after activation.
Acceptance criteria
Notes
TLS/project reconciliation began later and was not responsible for the foreground update duration.