fix: report real claim results from daemon stop - #1818
Conversation
Size Report
Startup median (7 runs, lower is better):
Top changed chunks:
|
|
P1: |
|
P1 fixed in Typed outcome, no boolean. export type DeviceClaimClearOutcome = 'deleted' | 'absent' | 'ownership-changed';
Classification. The ledger reads the outcome instead of the absence of a throw: Where Regression, proven red first. Added — i.e. the successor's claim sitting in
Stacking / Coverage. #1818 stays based on Gates on this head: |
dfb0a90 to
de2df1b
Compare
de2df1b to
fe37c7a
Compare
`daemon stop` typed `claimsReleased`/`claimsOrphaned` as the literal `[]` and every path hardcoded them, so a graceful stop that released a device claim still reported none (#1799 observation 3, #1320 acceptance). Graceful teardown now records each session's claim outcome — released after a clean teardown, orphaned when teardown left the claim in place — into the daemon shutdown report, and the CLI merges them alongside provider releases. Forced and not-running stops stay empty because they cannot know, and a report written before claim reporting still reads its provider releases.
`clearDeviceClaim` deliberately resolves without deleting when the on-disk claim is no longer the one it acquired, so the shutdown ledger's "the call resolved" test reported a successor's claim as released — a device the daemon never freed, counted as freed. `clearDeviceClaim` now returns a typed outcome (`deleted` | `absent` | `ownership-changed`) instead of nothing, and the ledger classifies from it: released only when absence is confirmed, and a new `superseded` bucket for a claim another owner had already taken over. Superseded is neither released (this daemon freed nothing) nor orphaned (no claim of ours remains to reconcile), so folding it into either would break that list's meaning; it also raises a warning so a device now owned elsewhere cannot pass silently.
fe37c7a to
7b3291e
Compare
|
Re-reviewed exact head 7b3291e: the prior successor-claim reporting bug is fixed. Claim clearing now returns an explicit outcome; ownership changes are reported as superseded rather than released, the foreign successor is preserved, and the real-store regression proves the distinction. The stack blocker is gone because #1809 merged and this PR now targets main. Code review is clean and ready-for-human; Coverage, Swift compile, and Android/iOS Smoke are still running. |
|
Summary
Follow-up to #1809 (now merged), which this was split out of so that PR stayed scoped to the enforcement seam. Targets
mainand stands alone.Refs #1799 (observation 3), #1320 (the "Claim results distinguish reconciled
claimsReleasedfrom cleanup-pendingclaimsOrphaned" acceptance item).Before:
DaemonStopResulttypedclaimsReleasedandclaimsOrphanedas the literal[], and the graceful, forced and not-running paths each returned empty literals. The daemon-side release happened inteardownDaemonSession(clearDeviceClaim, outcome discarded) and the CLI'smergeShutdownReportoverlaid onlyproviderReleases. So a graceful stop that really did release a device claim reported none — confirmed live on 0.20.9 in #1809's validation.After:
clearDeviceClaimreturns a typedDeviceClaimClearOutcome('deleted' | 'absent' | 'ownership-changed') instead of nothing. It deliberately leaves a claim it does not own in place, so resolving never meant releasing; a caller that reports ownership has to read the outcome.'ownership-changed'also now covers an unattributable record, which the old!inspected?.claimearly return silently folded in with "file gone".src/daemon/server/daemon-shutdown-claims.ts) and classifies from it:deletedorabsent) after the session reached a safe terminal state.daemon stopwarning so a device now owned elsewhere cannot pass silently.cleanupConfidencestaysknown: the state is not uncertain, it is attributed elsewhere.clearDeviceClaimfailures during shutdown are recorded as orphaned with a diagnostic instead of propagating out ofPromise.alland aborting the rest of the shutdown.DaemonShutdownReportcarries aclaimssection;DaemonStopResulttypes all three fields as arrays of a small claim summary (deviceKey,session,platform,deviceId);mergeShutdownReportoverlays them next to provider releases.No daemon wire surface change —
DaemonStopResultis local CLI output.Validation
Successor-claim regression, proven red first. Against the pre-fix ledger, the successor's claim landed in
claimsReleased:New/updated tests:
src/daemon/server/daemon-shutdown-claims.test.ts— released / orphaned / superseded classification and the no-claim case, against the real claim store; the superseded case also asserts the successor's claim survives teardown untouched.src/daemon/__tests__/device-claims.test.ts— the existing successor test now asserts the returned'ownership-changed', plus a case pinningdeleted/absent/absentfor owned, already-cleared, and no-ownership.src/daemon/__tests__/daemon-shutdown-report.test.ts— round-trips the claim section, and the pre-claim-reporting report still reads.src/cli/commands/__tests__/daemon.test.ts— the graceful merge now asserts the claims it carries.Live (Android,
Pixel_9_Pro_XL→emulator-5554), same command on both builds:Gates:
pnpm format,pnpm exec tsc --noEmit,pnpm check:affected --run(436 files / 3702 tests green, layering + fallow clean).Scope
10 files, +415/−49. No follow-ups;
device release(#1320's explicit recovery surface) remains out of scope for both PRs.