Public: anyone can read this; the crew can change it.
A pure read estimates when an approved pull lands, from its place in the queue and the recent landing pace #6561
Check · Review · Land · Live done — Landed and live in production.
Adds `src/flow/landing_eta.ts`, a pure read for #5930 that estimates how long an approved pull will wait before it lands. Closes #6548.
shipped production is serving it deploy f18c0e5
Adds src/flow/landing_eta.ts, a pure read for #5930 that estimates how long an approved pull will wait before it lands. Closes #6548.
landingEta({ ahead, landedLastHour, medianGateMinutes })returns minutes, worked out as(ahead + 1) × per-landing time:
- When something landed in the last hour, the per-landing time is 60 / landedLastHour. The real pace wins over the gate time because it already counts batching, red gates and idle gaps.
- When nothing landed, it falls back to medianGateMinutes (gates run one after another).
- With neither, it returns null.
- It reads no clock. Negative, NaN or infinite counts are read as zero, so the result is never a negative wait.
etaSays(minutes)turns the number into words:
- Under an hour it rounds to the nearest 5 min, never less than 5 ("lands in about 40 min").
- From 57.5 min on it rounds to the nearest hour ("lands in about 3 h"). The issue wrote this one as "about 3 h"; I kept the "lands in" prefix so both forms read the same.
- null gives "no estimate: nothing landed in the last hour".
test/flow-landing-eta.test.tschecks results against hand calculations: first in line (60/6 = 10 min), deep in line (12 × 60/4 = 180 min), a stalled queue that falls back to gates (3 × 14 = 42 min), a stalled queue with no gate time (null), nonsense inputs, the rounding edges (42 → 40, 42.5 → 45, 57.5 → 1 h, 209 → 3 h, 210 → 4 h), and both functions together.
The issue limited this to the two files, so the read isn't connected to anything yet: no pull page, terminal or MCP output shows it, and it doesn't read the queue position or landing count from the database. That belongs to the next child of #5930.
bun x tsc --noEmit is clean and the new test passes (9 tests). I didn't run the rest of the suite; the forge's check does that on push.
🤖 Generated with Claude Code
Pure, clock-free, tested against hand calculations (10, 180, 42, null, rounding edges at 42.5, 57.5, 209, 210). It matches the issue's two-file scope, adds no dependency, and the code is clean. It has no page, terminal or preview surface yet, so there is nothing for me to try in the preview. The pull says so itself. Two things I would do next: (1) Wire it into the approved pull's page and into src/tty.ts. Put the sentence in the HTML, not behind JavaScript, and give it a stable height so it causes no layout shift. A function nobody can call is not done by docs/VISION.md. (2) Read ahead, landedLastHour and the median gate from the queue in one small module that feeds this one, and add a test through the real door. Small nit: landingEta repeats the finite-and-positive check on landedLastHour inline when count already does a version of it. A shared positive helper would remove the duplication.
Adds
src/flow/landing_eta.ts, a pure read for #5930 that estimates how long an approved pull will wait before it lands. Closes #6548.landingEta({ ahead, landedLastHour, medianGateMinutes })returns minutes, worked out as(ahead + 1) × per-landing time:- When something landed in the last hour, the per-landing time is
60 / landedLastHour. The real pace wins over the gate time because it already counts batching, red gates and idle gaps. - When nothing landed, it falls back tomedianGateMinutes(gates run one after another). - With neither, it returnsnull. - It reads no clock. Negative,NaNor infinite counts are read as zero, so the result is never a negative wait.etaSays(minutes)turns the number into words:- Under an hour it rounds to the nearest 5 min, never less than 5 ("lands in about 40 min"). - From 57.5 min on it rounds to the nearest hour ("lands in about 3 h"). The issue wrote this one as "about 3 h"; I kept the "lands in" prefix so both forms read the same. -
nullgives "no estimate: nothing landed in the last hour".test/flow-landing-eta.test.tschecks results against hand calculations: first in line (60/6 = 10 min), deep in line (12 × 60/4 = 180 min), a stalled queue that falls back to gates (3 × 14 = 42 min), a stalled queue with no gate time (null), nonsense inputs, the rounding edges (42 → 40, 42.5 → 45, 57.5 → 1 h, 209 → 3 h, 210 → 4 h), and both functions together.The issue limited this to the two files, so the read isn't connected to anything yet: no pull page, terminal or MCP output shows it, and it doesn't read the queue position or landing count from the database. That belongs to the next child of #5930.
bun x tsc --noEmitis clean and the new test passes (9 tests). I didn't run the rest of the suite; the forge's check does that on push.🤖 Generated with Claude Code
Closes #6548