You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Reclaim is its own coordinator and commits what the driver returns #373
After this PR the component that purges a released device no longer decides whether the device stays running. It commits exactly what the driver's reclaim returns and kicks the queue. Until #368 lands, every released iOS device ends shutdown and the next lease for it boots it, and an Android device released over the running limit stays ready. This is the floor the warm pool module (next task) is built on.
In short
A release still works as today for the caller: the lease is gone at once and the purge runs in the background. The device comes back shutdown on iOS (after the erase) or ready on Android (after the snapshot restore), and that is where it stays: the keep-or-shutdown decision and the boot back to warm are deleted here and return, rebuilt, in the next task. Between the two tasks every iOS release costs the next lease a boot (a boot-shutdown plan), and an Android device released over the limit is not shut down.
sequenceDiagram
participant REL as Lease release coordinator
participant RC as Reclaim coordinator (renamed)
participant DRV as Driver
participant REG as Registry
participant ACQ as Acquisition
REL->>RC: reclaim(released), background
RC->>DRV: reclaim(device)
DRV-->>RC: shutdown (iOS) / ready (Android)
rect rgb(243,217,164)
note over RC: changed: no keep decision, no rewarm boot
RC->>REG: commit that state, emit device.reclaimed
end
RC->>ACQ: kick
Loading
reclaim coordinator: the renamed WarmPoolCoordinator. It purges, hands a failed purge to quarantine, deletes a spent fresh device, and recovers a reclaim a crash interrupted.
If this goes wrong: a released device is left reclaiming, or a waiting request is not woken after a release.
src/core/warm-pool-coordinator.ts becomes src/core/reclaim-coordinator.ts, class ReclaimCoordinator. Delete #warmDecision, #mayRemainWarm, #disposition and #tryMakeReady (:259-345). reclaim commits result.state as returned by the driver with the device.reclaimed event, and calls notifyAvailability. Delete the capacity and queueHeadDemand options and the WarmPoolCapacityReader interface. recoverInterrupted, deleteSpent, #retireSpent, #deleteSpent and #recoverPurgeFailure are unchanged.
src/core/warm-pool.ts becomes src/core/idle-order.ts: compareLeastRecentlyUsed, selectWarmVictim (renamed selectIdleRunningVictim), selectManagedVictim, WarmVictimScope (renamed IdleVictimScope). No behaviour change. src/core/acquisition-planner.ts:21,134,167 and src/core/startup-converger.ts:13 import from it.
src/core/lease-release-coordinator.ts:48,210,232: the option is reclaim: Pick<ReclaimCoordinator, "reclaim">.
src/core/lease-engine.ts:134,236-250,258: construct ReclaimCoordinator without capacity and queueHeadDemand; queueHeadSpec on LeaseAcquisitionCoordinator (:229) is deleted with its only caller.
src/core/lease-engine.ts:272 and src/core/startup-converger.ts:121-131,170-181: the excess-ready shutdown step (startup-max-running) is deleted here, not moved; the next task's first pass replaces it. Between the two tasks a lowered maxRunning is converged by nothing at startup, which the next task's Done when covers.
docs/internal/COMPONENTS.md: the rows for the renamed coordinator, the idle-order helper and the startup converger. docs/internal/ARCHITECTURE.md: "Release hands the purge off", "Lease subsystem boundaries and wiring", the startup convergence paragraph and the capacity sweep paragraph name the new component and no longer claim a keep decision or a startup excess shutdown. docs/internal/KNOWN-PITFALLS.md "Warm-pool purge failures" names the reclaim coordinator.
Contract and event changes
None. device.reclaimed and device.shutdown keep their payloads; the device.shutdown row in both EVENTS.md files names the reclaim coordinator for interrupted-reclaim recovery.
Rules in play
architecture.md rules 13 (every doc that names the old coordinator or the startup step) and 15 (the release path holds a port to reclaim only).
testing.md rules 1 and 3: the deleted keep decision's tests go with it; the rename keeps every other test.
Tests
A reclaim whose driver returns shutdown commits shutdown, emits device.reclaimed, and kicks acquisition, with no capacity question asked.
A reclaim whose driver returns ready commits ready even when running capacity is over its limit.
A reclaim never calls makeReady.
A release-time purge failure still hands the device to quarantine with the attempted strategy.
A spent fresh device is still shut down and deleted, never erased.
An unleased interrupted reclaim is still recovered through shutdown at startup.
The planner's eviction and the startup converger import the LRU order from idle-order.ts, and no file imports warm-pool.js.
At startup, ready devices over maxRunning are left running (the step is gone; the next task proves its replacement).
Done when
pnpm check is green, no source file under src is named warm-pool-coordinator or warm-pool, and no class is named WarmPoolCoordinator. The event initiator warm-pool-active-demand and the emitting module name warm-pool-coordinator on existing events stay as they are: payload values are never renamed.
On the fast lane: release an iOS fake-driver lease and the device is shutdown in simlock list --devices; release an Android fake-driver lease and the device is ready.
The lease-engine tests that covered a reclaimed device staying warm are deleted, not skipped.
Out of scope
Any keep-or-shutdown decision. Nothing stays warm by policy until the next task.
The config key warmPool.quarantine.*, which keeps its name.
Done: PR #375 (draft) renames the coordinator to ReclaimCoordinator, commits what the driver's reclaim returns, deletes the keep decision and the startup excess shutdown. Three review rounds; 15 blocking findings fixed. pnpm check green, 2 mutants, 0 alive. No hardware lines.
Not done: one blocking finding confirmed after round 3, so rule 14 stops here.
Findings: stale docs and one comment. ARCHITECTURE.md:25, :1148, :1192, :1531 and lease-release-coordinator.ts:105 still describe a warm-pool policy or disposition that this PR deletes. CLI.md:678 and ARCHITECTURE.md:1152 say an Android emulator always comes back ready, but the wipe fallback returns shutdown (drivers/android/index.ts:944,955,971). All are text fixes with one obvious answer.
Blocked on: the maintainer — fix those lines (or have an agent do it) and mark the PR ready, or re-run deliver after the fix.
Part of #359.
Scope
After this PR the component that purges a released device no longer decides whether the device stays running. It commits exactly what the driver's reclaim returns and kicks the queue. Until #368 lands, every released iOS device ends
shutdownand the next lease for it boots it, and an Android device released over the running limit staysready. This is the floor the warm pool module (next task) is built on.In short
A release still works as today for the caller: the lease is gone at once and the purge runs in the background. The device comes back
shutdownon iOS (after the erase) orreadyon Android (after the snapshot restore), and that is where it stays: the keep-or-shutdown decision and the boot back to warm are deleted here and return, rebuilt, in the next task. Between the two tasks every iOS release costs the next lease a boot (aboot-shutdownplan), and an Android device released over the limit is not shut down.reclaim coordinator: the renamed
WarmPoolCoordinator. It purges, hands a failed purge to quarantine, deletes a spentfreshdevice, and recovers a reclaim a crash interrupted.If this goes wrong: a released device is left
reclaiming, or a waiting request is not woken after a release.Technical spec
File and line references are to
mainat 4a52f6e.Modules touched
src/core/warm-pool-coordinator.tsbecomessrc/core/reclaim-coordinator.ts, classReclaimCoordinator. Delete#warmDecision,#mayRemainWarm,#dispositionand#tryMakeReady(:259-345).reclaimcommitsresult.stateas returned by the driver with thedevice.reclaimedevent, and callsnotifyAvailability. Delete thecapacityandqueueHeadDemandoptions and theWarmPoolCapacityReaderinterface.recoverInterrupted,deleteSpent,#retireSpent,#deleteSpentand#recoverPurgeFailureare unchanged.src/core/warm-pool.tsbecomessrc/core/idle-order.ts:compareLeastRecentlyUsed,selectWarmVictim(renamedselectIdleRunningVictim),selectManagedVictim,WarmVictimScope(renamedIdleVictimScope). No behaviour change.src/core/acquisition-planner.ts:21,134,167andsrc/core/startup-converger.ts:13import from it.src/core/lease-release-coordinator.ts:48,210,232: the option isreclaim: Pick<ReclaimCoordinator, "reclaim">.src/core/lease-engine.ts:134,236-250,258: constructReclaimCoordinatorwithoutcapacityandqueueHeadDemand;queueHeadSpeconLeaseAcquisitionCoordinator(:229) is deleted with its only caller.src/core/lease-engine.ts:272andsrc/core/startup-converger.ts:121-131,170-181: the excess-ready shutdown step (startup-max-running) is deleted here, not moved; the next task's first pass replaces it. Between the two tasks a loweredmaxRunningis converged by nothing at startup, which the next task's Done when covers.docs/internal/COMPONENTS.md: the rows for the renamed coordinator, the idle-order helper and the startup converger.docs/internal/ARCHITECTURE.md: "Release hands the purge off", "Lease subsystem boundaries and wiring", the startup convergence paragraph and the capacity sweep paragraph name the new component and no longer claim a keep decision or a startup excess shutdown.docs/internal/KNOWN-PITFALLS.md"Warm-pool purge failures" names the reclaim coordinator.Contract and event changes
None.
device.reclaimedanddevice.shutdownkeep their payloads; thedevice.shutdownrow in bothEVENTS.mdfiles names the reclaim coordinator for interrupted-reclaim recovery.Rules in play
architecture.mdrules 13 (every doc that names the old coordinator or the startup step) and 15 (the release path holds a port to reclaim only).testing.mdrules 1 and 3: the deleted keep decision's tests go with it; the rename keeps every other test.Tests
shutdowncommitsshutdown, emitsdevice.reclaimed, and kicks acquisition, with no capacity question asked.readycommitsreadyeven when running capacity is over its limit.makeReady.idle-order.ts, and no file importswarm-pool.js.readydevices overmaxRunningare left running (the step is gone; the next task proves its replacement).Done when
pnpm checkis green, no source file undersrcis namedwarm-pool-coordinatororwarm-pool, and no class is namedWarmPoolCoordinator. The event initiatorwarm-pool-active-demandand the emitting module namewarm-pool-coordinatoron existing events stay as they are: payload values are never renamed.shutdowninsimlock list --devices; release an Android fake-driver lease and the device isready.Out of scope
warmPool.quarantine.*, which keeps its name.Depends on
Approval
Written by an agent.