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

Abierto
#1,381 1 comentario 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

@V3RON ya está trabajando en esto.

Desde el 6/11/2026.

  • #1387 de @V3RON — abierto

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
20/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Estancado
Stack tecnológico
react-native, typescript
Área
backend

Línea de trabajo

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.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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.

Lenguaje dominante
TypeScript
Estrellas
535
Forks
21
Merge medio
9 h 10 min
PR fusionados (30 d)
454

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de callstackincubator/simlock

Todos los issues de callstackincubator/simlock

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.