Skip to content

feat(core): the warm pool module: one budget, a keep rule that fits, and an off switch - #386

Merged
V3RON merged 15 commits into
mainfrom
task/368
Oct 6, 2026
Merged

V3RON merged 15 commits into
mainfrom
task/368

Conversation

@V3RON

@V3RON V3RON commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Closes #368

Status

Implement: done (14 policy, 17 converger, engine and unit tests green; e2e files touched pass) Review: round 5, 0 open Mutate: 3 alive, equivalent (below) Hardware: n/a Gate: pending

Done when

  • At the running cap with simlock lease --class phone waiting, simlock release of a fitting iPhone grants that device to the waiter and simlock events shows no device.provisioned for it — lease-engine.test.ts "a release at the running cap with a class request waiting grants the released device and provisions nothing" (the only device.provisioned is the seed's)
  • With warmPool.enabled: false, a released fake iOS device is shutdown and a released fake Android device is shutdown after its device.reclaimed with strategy snapshot — engine test "with warmPool disabled …" and e2e/lease-lifecycle.test.ts "with warmPool.enabled false …"
  • With maxRunning lowered below the number of ready devices and the daemon restarted, the excess devices are shutdown with initiator warm-pool after daemon.started — engine tests "shuts down one of three ready devices …" and "shuts down an unleased ready device over maxRunning at startup …"
  • simlock config shows warmPool.enabled: true by default — config.test.ts "keeps the warm pool on by default …"

Assumptions

  • Assumption: a boot reserves with tryReserveBoot (a running slot and the RAM), not tryReserveRewarm — a shut-down device holds no running slot, and tryReserveRewarm checks RAM only; the acquisition path boots a shut-down device the same way.
  • Assumption: a pass proposes no budget shutdown while a device is being handed to a lease (a boot claim on a ready device) — that device counts as running and as reserved until the grant, so the budget reads one over for a moment; the grant triggers the next pass.
  • Assumption: a boot for a waiting request is proposed for one device, for the request at the head of the queue.
  • Assumption: a recently released device is one whose lastLeaseEndedAt is less than idle.shutdownAfterMs ago, strictly.
  • Assumption: a request whose device work is in flight (processing) is not waiting, but still holds one free slot on its platform from the speculative "recently released" boots, as does a waiting request no idle device serves — otherwise the pool boots back a device the waiter just evicted, in a loop.
  • Assumption: a failed boot or shutdown is not retried for the same device for one tick (30 s) — its reservation release triggers the next pass at once and a broken boot would loop.
  • Assumption: the pool does nothing while an operator reset (nuke) holds acquisition closed, and stops mid-pass when one begins.
  • Assumption: ReleaseCoordinator's post-claim notification also requests a pass: device.reclaimed fires while the reclaim claim is still held, so the pass it triggers sees the device as busy.
  • Assumption: engine.settle() also waits for the pool's running pass, so tests and graceful stop see the settled pool.
  • Assumption: e2e/doctor-drift.test.ts accepts ready for the device doctor --fix marked shut down, and a makeReady for only that device — the pool boots a device released a moment ago back; the fix is still proved by its device.shutdown event with initiator doctor.
  • Assumption: none left here for head-only boots: the spec now says the pool boots only for the queue head, in flight or not (a request behind it holds a slot but gets no boot).
  • Assumption: a nuke waits for the pool's in-flight pass after closing acquisition, so a boot already running cannot outlive the reset.
  • Assumption: a device that is shutdown while an operator reset (nuke) holds acquisition closed is never booted back as "recently released", until it leaves shutdown (the mark is in memory; the forced release stamps lastLeaseEndedAt = now, which would otherwise undo a nuke without --delete-devices).

Notes

  • The A released device that fits a waiting class request is shut down and another booted #350 engine test already passed on main after Reclaim is its own coordinator and commits what the driver returns #373 (a shut-down device that serves the waiter is booted by the planner at the cap); it is kept as the guard that the pool does not undo it.
  • Alive mutants, all equivalent: converger.ts #again = false initial value (reset at the start of every drain); lease-engine.ts ...(logger === undefined ? {} : { logger }) (an absent logger is the same as logger: undefined); src/http/test-fakes.ts enabled: true (a fixture value no test reads).
  • Behaviour to look at in review: a device a person stopped outside Simlock and doctor --fix marked shutdown is booted back if it was released within idle.shutdownAfterMs.

Review

Spec review: 10 blocking, 4 fixed, 11 notes. Code review: 8 blocking, 6 fixed, 13 notes.
Mutate: 3 mutants, 3 alive.

Rejected:

Written by an agent.

V3RON added 9 commits October 5, 2026 23:47
… off switch (#368)

26 failing, the warm pool spec tests red on named assertions; the class-request
engine test (#350 case) already passes on main since #373 and guards the pool.
…huts down over budget, and honours warmPool.enabled (#368)

26 failing -> 0 failing
58 alive -> targeted tests for every branch of the budget, the revalidation and the logs
22 alive -> the revalidation, budget-dimension and dispose cases each have a test
@V3RON

V3RON commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Review notes

Not blocking, not verified. Each is one reviewer's claim.

  • spec: src/core/warm-pool/policy.ts:164 a provision or boot in flight counts in reserved and again as unserved, so one fewer recently released device is booted back while it runs.
  • code: src/core/domain.ts:93 the WaitingDemand.inFlight doc ("a slot coming that is not yet reserved") is false for a provision or boot in flight.
  • spec: src/core/warm-pool/converger.ts:156 the pool skips kick() when the lifecycle declines a shutdown or boot.
  • spec+code: src/core/lease-engine.ts:257 the release coordinator's notifyAvailability calls the pool's pass(), a trigger outside the spec's list (ADR 0017 §3, architecture rule 15).
  • spec: src/core/lease-acquisition-coordinator.ts:565 waitingDemand() also lists processing waiters with inFlight, unlike the spec's shape.
  • spec: e2e/doctor-drift.test.ts accepts ready for deviceA, so a regression where doctor --fix boots it would pass.
  • code: src/core/warm-pool/converger.ts:82 a trigger can be lost between #drain's last #again check and the .finally clearing #running; the 30 s tick recovers it.
  • code: src/core/acquisition-planner.ts:87 a request during a pool bootWarm provisions or evicts instead of waiting; docs/CONFIGURATION.md:26 understates it (left to A reserve of running slots, and a request waits for a device on its way #369).
  • code: src/core/warm-pool/converger.ts:146 a device whose warm boot keeps failing is retried every 30 s for up to idle.shutdownAfterMs.
  • code: src/core/lease-engine.ts:255 daemon stop right after a release boots the device back and waits for it — filed as daemon stop right after a release boots the released simulator back and waits for it #388.
  • code: src/core/warm-pool/converger.ts:171 the pool acts on devices whose driver was refused at discovery — filed as The warm pool retries a shutdown on a refused platform's device every 30 s #389.
  • code: src/core/warm-pool/converger.ts:125 boot proposals are computed at pass start, so a later pool boot can take a slot freed by a failed one before a queued request's decision runs.
  • code: src/core/warm-pool/converger.ts:236 the device.reclaimed trigger never lets the pool act on the reclaimed device (claim still held).

Written by an agent.

@V3RON
V3RON marked this pull request as ready for review October 6, 2026 06:49
@V3RON
V3RON merged commit adf2d45 into main Oct 6, 2026
23 checks passed
V3RON added a commit that referenced this pull request Oct 6, 2026
…ses, later rounds review only the fix (#391)

Second of three. Review rounds kept finding new things: in #383 and
#386, about half of the findings in round 2 and later came from the
previous fix, and most were stale comments or docs outside the diff.

- **`.agents/scripts/stale-refs.sh`**: lists every line in the repo that
still names a moved or deleted path, a declaration that is gone, or a
quoted string no code file has. Git only; about 2 s. On #383 before its
round-4 fix it finds the `src/gateway/queue.ts` header naming
`src/core/wait-queue.ts`, one of that round's three findings.
`review-inputs.sh` adds its output, plus `commit` and `fix.patch`.
- **Claims review**: a new `claims-reviewer` agent checks that every
comment, doc line, test title and message the diff touches or the sweep
finds is true of the code. It runs every round. Its findings never park
a PR or count toward the round cap; their fixes get at most two
claims-only rounds.
- **Wider round 1**: the code review runs as two reviewers: behaviour
(including other code acting on the same state) and tests and rules (up
to six probes). Each lists what it checked. Briefs say there is no limit
on findings.
- **Later rounds review only the fix**: is each earlier finding
resolved, does the fix diff add a defect, is another instance of the
same class left. Anything else is a note; a confirmed defect there
becomes a `bug:new` issue.
- **Every finding names its class**: the general rule it breaks. In fix
mode the implementer finds and fixes every instance of the class and
reports them under `Variants:`. The audit now runs the sweep.
- **Spec review flags "delivered differently"** (from Matt Pocock's
`code-review`): a spec line the diff delivers in another way than
written, like #383 calling `core.connect` inside `createLeasing` when
the spec put it in the daemon.
- `delivery.md` rule 14, `deliver`, `DELIVERY.md`, and
`delivery-stats.mjs` (a Claims review column and `claims:` tag) follow.

Tests: `src/stale-refs.test.ts` (4 tests; each fails when the part it
covers is broken), `src/delivery-stats.test.ts` extended.

*Written by an agent.*
V3RON added a commit that referenced this pull request Oct 6, 2026
…e lane exercises, in Chromium only (#413)

The Console job (three browsers, about 15 minutes) ran on every push of
every PR, including agent-config, ADR and docs PRs it cannot affect. CI
runners queued for up to two hours during the #358/#359 runs.

- **A new `Changes` job** lists the PR's changed files, renames by both
paths. Console runs when one is a source file under `src/` or `ui/`
(unit tests excluded), a console spec, its fixtures or helpers,
`playwright.config.ts`, `package.json`, the lockfile, a root
`tsconfig*.json`, or `ci.yml`. On the last 25 merged PRs it would have
skipped 12.
- **Why not `on.pull_request.paths`:** Console is a required check. A
workflow skipped by a path filter leaves its checks pending, which
blocks the merge; a job skipped by `if:` reports success. If `Changes`
itself fails, Console runs.
- **Browsers:** a PR that changes `ui/`, the console specs or
`playwright.config.ts` runs all three browsers; any other PR runs
Chromium only. Every push to `main` runs all three. Of the last 10
Console failures, 6 were Firefox- or WebKit-only. This rule would have
caught 3 of them; 2 came from PRs with no UI change (#386, #379), so
their kind now shows up only on `main`.
- `toolchain.md` and `DELIVERY.md` say when the lane runs.

*Written by an agent.*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The warm pool module: one budget, a keep rule that fits, and an off switch

1 participant