A learned kind keeps one ready copy while its copies are leased

オープン
#1,381 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@V3RON がすでに取り組んでいます。

2026年11月6日 から。

  • #1387 @V3RON による — オープン

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
20/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
停滞
技術スタック
react-native, typescript
領域
backend

調査の方向性

Start with src/core/warm-pool/policy.ts and its tests in src/core/warm-pool/policy.test.ts; trace how learned target shortfalls use ready, leased and in-flight devices. Update the e2e coverage in e2e/warm-pool-learned.test.ts and the capacity and how-it-works pages. Done when the specified unit and e2e commands pass and haveOfKind has no remaining source matches.

索引モデルが issue の本文から書いたものです。

説明

task:blocked

Part of #1374.

Scope

After this PR, a warm pool pass keeps max(peak − leased, 1) copies of each learned kind ready (ADR 0069), so the next lease of a learned kind finds a ready copy while its other copies are leased. Plain and baseline kinds alike. Leased counts every open lease of the kind that its peak counts, so a baseline kind counts the leased copies of all its versions, not only the newest (decided in delivery, pending the maintainer). Configured targets, the budget, displacement and the reaper's sparing are unchanged. The capacity and how-it-works pages say so.

In short

While a learned kind's copies are leased, the pool now boots a spare copy, so the next lease of that kind starts without a boot. It keeps at least 1 spare and at most the kind's peak (the most leases of that kind held at once in the last 24 hours).

flowchart LR
  A[lease.granted] --> P[pool pass]
  P --> W["wanted ready = max(peak − leased, 1)  ← changed"]
  W --> F[fill: boot or create the missing copies, within the budget]
Peak Leased Ready kept today After
1 1 0 1
3 3 0 1
3 1 2 2
3 0 3 3

If this goes wrong, a lease of a learned kind still waits tens of seconds for a boot while another copy of it is leased.

Technical spec

Facts

Commit ba6582dde.

# Fact Source
F1 A learned kind's shortfall is learnedCount − haveOfKind(...), beside the configured configuredCount − ready, less copies on their way (filling) src/core/warm-pool/policy.ts:671-675
F2 haveOfKind counts a kind's ready idle devices plus its leased, reclaiming and claimed non-provisioning devices; it is used only at F1's line src/core/warm-pool/policy.ts:441-461; git grep -n haveOfKind origin/main -- src → 2 hits, both policy.ts
F3 Every virtual device is destroyed after one lease; a leased copy never comes back ready docs/internal/adr/0061-every-virtual-device-is-a-copy-of-a-source-and-a-baseline-is-a-named-source.md:139-143
F4 A pass runs on lease.granted (and on lease.released, device.deleted and others) src/core/warm-pool/converger.ts:932-942
F5 pending(spec) counts a kind's in-flight boots and creations and the queue's proposals for it src/core/warm-pool/policy.ts:650-660
F6 targetedDevices spares up to max(configuredCount, learnedCount) of a kind's ready idle devices for the reaper src/core/warm-pool/policy.ts:527-530
F7 The existing test "fills configured targets … and counts a learned kind's leased, reclaiming and claimed devices as had" pins today's rule: 3 leased at peak 3 → [], 1 claimed ready at peak 1 → [], 2 leased + 1 reclaiming at peak 3 → [] src/core/warm-pool/policy.test.ts:1742-1796
F8 The reproduction "creates a ready copy of a learned baseline kind of count one while its only copy is leased, and while that copy is reclaiming" fails on main at its leased case branch bug/1371-repro, src/core/warm-pool/policy.test.ts (+12 lines after 1796); pnpm exec vitest run --project unit src/core/warm-pool/policy.test.ts -t "baseline kind of count one" → AssertionError: expected [] to deeply equal [ { action: 'provision', … } ] (#1371 triage comment)
F9 The report's count is max(configuredCount, learnedCount), the peak for a learned kind src/core/warm-pool/policy.ts:684
F10 The capacity page says the pool "keeps as many booted as were leased at the same time at the busiest moment of the last 24 hours, at least one" website/src/content/docs/docs/worker/capacity.mdx:156
F11 The how-it-works page says it "keeps ready as many of each kind as were in use at the busiest moment" website/src/content/docs/docs/introduction/how-it-works.mdx:71
F13 The fast-lane e2e test "creates nothing while the first lease is held, makes a new device of the kind in place of the deleted one, leaves it ready through a cleanup run, and grants the next lease of its kind warm" holds one lease with room for 2 devices, waits 1.5 s and expects 1 device; the warm pool is on in that environment e2e/warm-pool-learned.test.ts:57-80; e2e/helpers/env.ts:459 (only the lane home sets enabled: false)
F12 The warm-pool manual's Known gaps say "a burst larger than count pays the boot" src/core/warm-pool/AGENTS.md (Known gaps, "A warm target costs one create per lease")
Modules touched

Searches: git grep -n 'haveOfKind\|learnedCount' origin/main -- src (11 hits, all src/core/warm-pool/policy.ts and its test); git grep -n -i 'while the first lease is held' origin/main -- e2e src (1 hit, F13); git grep -n -i 'busiest' origin/main -- website docs (2 hits, F10, F11).

flowchart LR
  C[warm-pool/converger.ts] --> P["warm-pool/policy.ts: evaluate ✱"]
  T["warm-pool/policy.test.ts ✱"] --> P
  D["website capacity.mdx, how-it-works.mdx ✱"]
  • src/core/warm-pool/policy.ts: the learned shortfall in the targets step (F1) becomes max(learnedCount − leasedOfKind, 1) − ready; haveOfKind is replaced by a count of the kind's devices under an open lease (view.leases), and deleted.
  • src/core/warm-pool/policy.test.ts: the test of F7 and the reproduction of F8.
  • e2e/warm-pool-learned.test.ts: the test of F13, rewritten to the new outcome.
  • src/core/warm-pool/AGENTS.md: the Known gaps line of F12.
  • website/src/content/docs/docs/worker/capacity.mdx, website/src/content/docs/docs/introduction/how-it-works.mdx: the lines of F10 and F11.
Contract and event changes

none. Searched src/contract/ for count, ready and short in the warm-pool target shape: the report's fields keep their meaning (F9).

Other code on the same state

Searches: git grep -n 'readyOfKind\|pending(\|targetedDevices' origin/main -- src/core/warm-pool (15 hits in policy.ts).

  • Configured fill (policy.ts:662-666): runs first and is unchanged; the learned shortfall still subtracts configured.added.
  • Reaper sparing (F6): spares up to the peak; the new wanted ready count is never above the peak, so every spare it plans is spared.
  • Over-budget and displacement (fillTarget, addDisplacing): unchanged; a spare that does not fit is reported short like any learned shortfall.
Failure modes

none. evaluate is pure and crosses no boundary; the converger acts on its proposals as it does today.

Rules in play
  • ADR 0069 §1: "keeps max(L − H, 1) devices ready" — the new shortfall, with H the kind's devices under an open lease only.
  • ADR 0069 §2: "the larger of C less its ready devices and max(L − H, 1) less its ready devices" — the merged entry.
  • ADR 0038 §3: "every configured count is filled before any learned count" — unchanged order.
  • Warm-pool manual: "policy.ts is pure" — the count reads view.leases, already in the view.
  • Documentation rule 9: the website pages of F10 and F11 change in the same PR.
Retired words
  • counts a learned kind's leased, reclaiming and claimed devices as had: a learned kind's leased copies lower its wanted ready count; reclaiming and claimed devices count as neither.
  • creates nothing while the first lease is held: while a lease of a learned kind is held, the pool makes a spare of it.
Tests

Seam: evaluate in src/core/warm-pool/policy.ts, modelled on src/core/warm-pool/policy.test.ts ("learned kinds"). The test of F7 is rewritten to the new rule (testing rule 7), and the reproduction of F8 is folded into it. The user-seam line drives withDaemon with the fake iOS driver, modelled on and rewriting the test of F13 in e2e/warm-pool-learned.test.ts.

  • A warm pool pass over a learned kind plans enough copies to keep max(peak − leased, 1) ready, counting copies on their way, for a plain kind and a baseline kind alike: peak 1, 1 leased → 1 new; peak 1, 1 reclaiming → 1 new; peak 1, 1 ready under a claim → 1 new; peak 3, 3 leased → 1 new; peak 3, 2 leased + 1 reclaiming → 1 new; peak 3, 1 leased + 1 ready → 1 new; peak 3, 3 leased + 1 boot in flight (the view's inFlight) → none; baseline kind demo peak 1, 1 leased → 1 new; baseline kind demo peak 2, 2 copies of version 1 leased while version 2 is newest → 1 new (decided in delivery, pending the maintainer).
  • A pass over a kind both configured and learned plans the larger of what each count lacks: configured 1 + learned peak 2, 1 leased, 0 ready → 1 new; configured 2 + learned peak 1, 1 leased, 0 ready → 2 new.
  • A worker with no targets and room for a second device, holding a lease of a kind, grants the next lease of that kind warm, and after a release makes a new ready copy in place of the deleted one: first lease held → a second ready copy appears and a second lease is granted warm while the first is held; first released → a new ready copy of the kind, not the released device.

Done when

  • pnpm exec vitest run --project unit src/core/warm-pool/ passes, with the cases above.
  • pnpm test:e2e e2e/warm-pool-learned.test.ts passes.
  • git grep -n haveOfKind -- src prints nothing.
  • capacity.mdx and how-it-works.mdx say a learned kind keeps at least one spare ready while its copies are leased, and at most its peak.

Out of scope

  • Configured targets, the budget, displacement, learning and forgetting.
  • configuration.mdx's warmPool.enabled line (#1373).

Depends on

Written by an agent.

主要言語
TypeScript
スター
535
フォーク
21
平均マージ
9時間 10分
マージ済み PR(30日)
454

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

callstackincubator/simlock のほかの issue

callstackincubator/simlock の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。