Skip to content

fix: centralize confirmed daemon retirement - #3126

Merged
thymikee merged 4 commits into
fix/daemon-registration-ownerfrom
fix/daemon-retirement
Oct 3, 2026
Merged

thymikee merged 4 commits into
fix/daemon-registration-ownerfrom
fix/daemon-retirement

Conversation

@thymikee

@thymikee thymikee commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Summary

Client cleanup can call one job that confirms the captured process exited, acquires the startup lock, re-reads registration, removes only matching metadata, and confirms release. Abandoned recovery uses the same core without signaling live processes.

Replaced, unknown, unreadable, busy, and partially cleaned state is retained with typed outcomes. I/O errors preserve normalized primary failures; secondary release failures are recorded in daemon diagnostics. Acquisition permission failures are distinguished from contention.

flowchart LR
  P[Captured process lifetime] --> E[Confirm exit] --> L[Acquire startup lock] --> M[Retire matching metadata] --> R[Release acquisition]
Loading

The development cleanup script is the first consumer. --prune-dev selects directories by their newest mtime and retains shared state directories and session artifacts. Client lifecycle/timeout paths and private replay ownership follow in #3116.

6 files changed. Builds on #3125.

Validation

Tested e72c8e1a82:

  • AGENT_DEVICE_REQUIRE_LOOPBACK_TESTS=1 pnpm check:affected --base fix/daemon-registration-owner --run passed; all runnable checks completed.
  • Real cleanup, forced retirement and HTTP daemon smoke passed with zero skips. Forced retirement confirmed exit and reclaimed the abandoned claim.
  • A real permission regression failed before distinguishing acquisition I/O errors. Failure tests preserve metadata and primary errors and report partial removal.
  • Verified zombie detection is owned by fix: return confirmed daemon termination outcomes #3124; private cleanup still joins monitored children.
  • Independent review found no further retirement-core findings. GitHub CI/coverage remain authoritative.

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.95 MB 4.95 MB +91 B
Package (unpacked) 4.95 MB 4.95 MB +91 B
Package (download) 1.48 MB 1.48 MB +2 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 25.8 ms 25.5 ms -0.3 ms
CLI --help 74.3 ms 75.2 ms +0.9 ms

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 6 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread CONTRIBUTING.md Outdated
Comment thread src/daemon-registration-owner.ts
@thymikee

thymikee commented Oct 2, 2026

Copy link
Copy Markdown
Member Author

The code in df38a36 looks correct to me, and all 14 checks pass at that commit. Evidence is still pending: I did not run the focused unit or smoke tests locally, and I did not confirm that the smoke-daemon-clean real-daemon test ran unskipped in CI, since it depends on loopback availability. Please confirm that test ran, or show its output from a run on a machine with loopback. I also did not read tryAcquireProcessLock's EACCES branch or how it handles a legacy daemon.lock file that is not a directory. I inferred the 'retirement-unconfirmed' mapping from the chmod test and from host-kit tagging only the timeout path, so a quick check of that mapping would help. I cannot verify the PR body's line about an independent read-only review, so I did not count it as evidence.

Not blocking, and you can take or leave these: when release fails after a result is already retained, releaseAfterRetirement overwrites the typed reason ('registration-replaced', 'metadata-unreadable', 'ownership-unproven') with 'retirement-unconfirmed', so a release failure should add a secondary error and only convert 'retired' or 'absent'; the live-owner test uses a vitest worker that isAgentDeviceDaemonProcess rejects, so it cannot fail on a signaling regression and its lock half returns 'absent' either way, and it should be renamed to what it asserts or check that the lock is acquired and released; no retirement test asserts 'daemon_retirement_release_failed' in the log, though the PR says these are recorded, so a match on paths.logPath like the registration test would cover it; and pruneStaleDevStateDirs prints only 'retired' results, so retained directories, including ones with an EACCES error, are now silent where the old rmSync would have thrown.

Is there anything smaller? I looked and found nothing meaningful. #3116 names these two functions as the owner of client-side retirement, and the production change is +224/-79. One option is to let retireDaemonRegistration short-circuit a null observation itself, instead of widening the owner type in readRegisteredDaemonOwnership to OwnerIdentity | null, which keeps the shared reader's contract unchanged. The cost is small either way. Until the dependent #3116 layers move takeover, replay shutdown and timeout reset onto this core, the raw info and lock removal exports, cleanupStaleDaemonLockIfSafe and recoverDaemonLockHolder will leave two retirement paths, and they should be deleted then.

No conflicts. The only thing before merge is that base PR #3125 lands first.

@thymikee
thymikee force-pushed the fix/daemon-retirement branch from df38a36 to e72c8e1 Compare October 2, 2026 23:27
@thymikee

thymikee commented Oct 3, 2026

Copy link
Copy Markdown
Member Author

The earlier evidence gap on df38a36 is now closed. At e72c8e1 I found no problems in the changed code.

CI is still pending. All 11 non-passing jobs were cancelled by a superseded run and have no failed steps, so there is no failure to attribute. The Integration Tests job runs test/integration/smoke-daemon-clean.test.ts, which this change touches, so it needs a completed rerun on e72c8e1. CI also does not set AGENT_DEVICE_REQUIRE_LOOPBACK_TESTS, so a pass alone will not show that the real-daemon tests ran unskipped. I did not run the smoke or unit tests. Zero skips under that flag is the author's report. I only confirmed that the flag turns a skip into a failure.

This PR does not make stopAndRetireDaemon the only retirement owner. daemon-client-lifecycle.ts:214 and :453-457, and daemon-client-timeout.ts:197-198, still remove daemon.json and daemon.lock without confirmed termination. The PR body defers these to #3116, so they are outside this slice. I did not re-review code outside the delta.

Before merge, CI needs a completed rerun on e72c8e1. #3116 then needs to move the daemon-client lifecycle and timeout metadata removal onto stopAndRetireDaemon.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 3, 2026
@thymikee
thymikee added this pull request to stack #3147 October 3, 2026 08:47
@thymikee
thymikee force-pushed the fix/daemon-retirement branch from e72c8e1 to 9b6b44a Compare October 3, 2026 14:40
@thymikee
thymikee force-pushed the fix/daemon-retirement branch from 9b6b44a to d495c5c Compare October 3, 2026 16:41
@thymikee
thymikee force-pushed the fix/daemon-retirement branch from d495c5c to b45777a Compare October 3, 2026 17:49
@thymikee
thymikee merged commit 7cff293 into main Oct 3, 2026
25 of 35 checks passed
@thymikee
thymikee deleted the fix/daemon-retirement branch October 3, 2026 18:04
thymikee added a commit that referenced this pull request Oct 3, 2026
…token-attach-c41aff

* commit 'd396f3b509d9ed7cddaf170351ea6cf34e02ac16':
  fix(provider-webdriver): harden BrowserStack app references and endpoints (#3169)
  fix(android): back off a timed-out snapshot helper session and bound content re-captures (#3160)
  fix: centralize confirmed daemon retirement (#3126)
  fix: bind daemon registration writes to the acquired owner (#3125)
  fix: return confirmed daemon termination outcomes (#3124)
  refactor(move): share daemon registration and shutdown report modules (#3123)
  fix: preserve process lock exclusion across publication and reclaim (#3122)
  fix(cli): refuse a non-URL install-from-source source up front (#3166)
  fix(daemon): start a lease's TTL when its allocation completes (#3165)
  fix(android): fail doctor when adb is the Windows binary on a POSIX host (#3157)
  0.21.20
  0.21.19

# Conflicts:
#	src/daemon/server/daemon-runtime-metadata-ownership.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant