Public: anyone can read this; the crew can change it.
Sentinel: shared:01m23vygyffx5hg2f5vm8r74sr:2hvdu8l540 was degraded 60 minutes today: trevato/forge: "after a write, signed-in home is answered from memory within the budget and says what to swap" failed o… #8122
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/8096-sentinel-shared-01m23vygyffx5hg2f5vm8r74 → main 2 commits fork 2 threads · 2 unresolved
1 file
changed +27
−16
test/home-frame.test.ts +27 −16
| @@ -8,8 +8,11 @@ import { afterAll, beforeAll, expect, test } from "bun:test"; | ||
| 8 | 8 | import { snappyFixture, type SnappyFixture } from "../bench/snappy.ts"; |
| 9 | 9 | import { forgetHome } from "../src/web/studio/home_last.ts"; |
| 10 | 10 | |
| 11 | /** The server's own time for `/` after a write, median, in ms: what the request did before sending a byte. */ | |
| 12 | const APP_MEDIAN_MS = 50; | |
| 11 | /** The server's own time for `/` after a write, median of a sample, in ms: what the request did before sending a byte. */ | |
| 12 | const APP_BUDGET_MS = 50; | |
| 13 | /** Looks in a sample, and how many samples may be taken: a sample starved by the machine is taken once more, a slow code is slow in both. */ | |
| 14 | const LOOKS = 20; | |
| 15 | const SAMPLES = 2; | |
| 13 | 16 | /** The first response, uncompressed, on a forge this size. */ |
| 14 | 17 | const FIRST_BYTES = 100_000; |
| 15 | 18 | |
| @@ -40,21 +43,29 @@ test("after a write, signed-in home is answered from memory within the budget an | ||
| 40 | 43 | const cold = await look(f.ownerCookie); |
| 41 | 44 | expect(cold.res.status).toBe(200); |
| 42 | 45 | expect(cold.text).not.toContain(`data-refresh="/`); |
| 43 | const times: number[] = []; | |
| 44 | let marked = ""; | |
| 45 | for (let i = 0; i < 20; i++) { | |
| 46 | write(i); | |
| 47 | const got = await look(f.ownerCookie); | |
| 48 | expect(got.res.status).toBe(200); | |
| 49 | times.push(got.ms); | |
| 50 | // Answered from memory on every look, not only the first: this is the verdict that depends on the code alone. | |
| 51 | expect(got.text).toContain('data-refresh="/live/home/feed"'); | |
| 52 | if (i === 0) marked = got.text; | |
| 53 | await Bun.sleep(1); | |
| 46 | let marked: string; | |
| 47 | // The first look after a write schedules the one-off redraw of the five regions, which runs on this process's loop for the looks that follow; let it finish, so the sample measures the steady cost of a look. | |
| 48 | write(-1); | |
| 49 | marked = (await look(f.ownerCookie)).text; | |
| 50 | await Bun.sleep(1_000); | |
| 51 | let median = Infinity; | |
| 52 | for (let sample = 0; sample < SAMPLES && !(median < APP_BUDGET_MS); sample++) { | |
| 53 | const times: number[] = []; | |
| 54 | for (let i = 0; i < LOOKS; i++) { | |
| 55 | write(sample * LOOKS + i); | |
| 56 | const got = await look(f.ownerCookie); | |
| 57 | expect(got.res.status).toBe(200); | |
| 58 | times.push(got.ms); | |
outdated
times[floor(n/4)] is the 6th fastest of 20. It lets a regression through that slows most requests. Use a bound that still fails when the typical request is over budget (median after warm-up, or one whole-sample retry), and tie it to the cause seen in the failing check log. |
||
| 59 | // Answered from memory on every look, not only the first: this is the verdict that depends on the code alone. | |
| 60 | expect(got.text).toContain('data-refresh="/live/home/feed"'); | |
| 61 | await Bun.sleep(1); | |
| 62 | } | |
| 63 | // Every look measured a time; a missing one is a broken header, not a fast look. | |
| 64 | expect(times.every((t) => Number.isFinite(t))).toBe(true); | |
| 65 | times.sort((a, b) => a - b); | |
| 66 | median = times[Math.floor(times.length / 2)]!; | |
| 54 | 67 | } |
| 55 | times.sort((a, b) => a - b); | |
| 56 | // The median, not the slowest of twenty: one stalled look on a loaded check machine is the machine, not the code. | |
| 57 | expect(times[Math.floor(times.length / 2)]!).toBeLessThan(APP_MEDIAN_MS); | |
| 68 | expect(median).toBeLessThan(APP_BUDGET_MS); | |
| 58 | 69 | for (const name of ["kpis", "waiting", "panels", "asked", "feed"]) { |
| 59 | 70 | expect(marked).toContain(`id="home-${name}"`); |
| 60 | 71 | } |
new above
offline
APP_MEDIAN_MS is now compared to the lower quartile. Rename it (e.g. APP_BUDGET_MS) so the name and the doc comment agree.