Repository navigation
fix(daemon): preserve active holds when renewal is canceled - #4163
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
thymikee
left a comment
There was a problem hiding this comment.
Verdict: approve. No concrete regression findings.
Reviewed head 6f028bf6c305aa25288dce7b161f0884fa2b2a6f; merge-base with origin/main: a0e7c7dc239922bf93adaceff20a2f7e78579146 (also the PR base).
The active entry remains authoritative during renewal, including its original metadata and expiration. In lease-registry.ts:395–432, the only await between selecting that entry and replacing it is mutations.wait. After it, cancellation and entry identity are checked before the synchronous active-state construction and map write. Cancellation cleanup removes only this request's published pending entry, so it cannot delete the retained active entry or a successful competing renewal.
Adversarial checks:
- Successful renewal persists the replacement and extends expiration from 10,000 to 21,000; admission stays blocked beyond the old deadline. Before publication, admission errors expose the original active hold and TTL.
- A non-abort validation error retains the original hold. Concurrent successful attempts produce one committed renewal and one explicit
COMMAND_FAILED, without deleting the winner. Aborting either contender preserves the other renewal. - Release racing renewal invalidates the old entry identity, so the renewal cannot resurrect the released hold or overwrite a replacement.
- An already-expired hold takes the fresh
activatingpath, fences mutation admission while draining, and acquires a fresh TTL on success. Canceling that activation leaves the expired hold absent. Sweeping the old TTL during an active renewal prevents stale publication. - The existing tests also exercise mutation drain, activation cancellation, and superseded activation cleanup.
Design: retaining the committed entry while building one unpublished candidate is a small, sufficient state model. It avoids rollback state and keeps the registry map as the admission authority; no additional hold state is needed.
Validation: installed and built both head and an isolated unchanged base. Ran one focused Vitest invocation using scratch configuration: all 59 head-side tests passed (51 lease-registry tests plus eight adversarial scratch cases). The invocation overall failed because the base scratch test could not resolve @agent-device/kernel/errors; the base regression did not execute. No rerun was made. Static base tracing does establish that the added regression would fail at its hold-retention assertion: base publishes the replacement pending entry before the await, then cancellation deletes it, leaving []. This is static evidence, not an independently reproduced base test failure. Log: /private/tmp/r4163-tests.log.
I see no plausible connection between this human-control renewal-only diff and the reported Apple record output-guard timeout in #4060. The reported affected-gate blocker remains unverified by this review; I did not investigate it further or wait for CI. Reviewed code remained unchanged.
Size Report
Startup median (7 runs, lower is better):
|
|
The code looks good at 6f028bf: canceling a renewal now keeps the active hold, and I found no problems in the code. All 18 checks pass. The one local failure I saw on #4060 (apple-platform-output-guard record timeout) is on a provider recording route this diff does not touch. I did not run the regression test on base or head; I read the old code path and Not blocking, take or leave: in https://github.com/callstack/agent-device/blob/6f028bf/packages/daemon/src/resources/lease-registry.ts#L397 the renewal now publishes the existing active entry with its old |
Summary
An aborted renewal could delete an active human-control hold and reopen mutation admission. Keep the active entry until renewal activates atomically; cancellation preserves its metadata and TTL.
Two files; production changes stay inside LeaseRegistry. FU-HOLD audit follow-up. No scope expansion. Validation blocker: #4060.
Validation
a0e7c7dc239922bf93adaceff20a2f7e78579146.6f028bf6c305aa25288dce7b161f0884fa2b2a6f.pnpm exec vitest run --project unit-core packages/daemon/src/resources/__tests__/lease-registry-human-control.test.ts: added before implementation; base 1 failed (hold list became empty); head 1 passed. Registry/expiry/HTTP focused suites: 52 passed.pnpm formatandpnpm build: passed.pnpm check:affected --run --head 6f028bf6c305aa25288dce7b161f0884fa2b2a6f: base-blocked, receipt.tmp/validation/run-nlfJ5l/receipt.json,exactCommit=true,checkoutChanged=false. Six checks passed; related tests 303 passed / 1 failed. Identical command on freshly installed/built unchanged base reproducedapple-platform-output-guard.test.ts:385,recordtimeout after 20s, 303 passed / 1 failed (test(provider): fix recording timeout reproduced by the related-test gate on unchanged base #4060).pnpm gate unit: passed, 16,966 tests passed / 1 skipped; smoke 76 passed / 6 skipped.local/CAE86E90-9D1D-42A4-B020-179F0FE092DE: worktree-built HTTP daemon, private/private/tmp/fu-hold-livestate. Worktree CLItakeoverrenewed the same active hold;takeover statusshowed advancedupdatedAt. Bound device clientbackreturnedDEVICE_IN_USE, reasonhuman_control_active. After Ctrl+C, status was empty andbackreached the native runner, which reported no back control on Settings' root. Sessions, hold, and daemon cleaned up. Cancellation timing is proven by the unit regression.