test(perf): raise entity-card ratio ceiling 50x -> 100x (CI flake)

The RATIO GUARD asserted entity p99 <= 50x max(getPage p50, 1ms). On a fast
runner getPage p50 floors to 1ms and a normal entity p99 (~50ms) reads as ~52x,
tripping the gate even though absolute p99 (52ms) is well under the 100ms budget
— a p99 tail divided by a sub-ms median. At the 1ms floor, 50x also made the
ratio STRICTER than the test's own 100ms absolute budget. Raise the ceiling to
100x: still far below the >=200x O(N)-regression signal the guard exists to
catch, and consistent with (never stricter than) the absolute budget.
This commit is contained in:
Garry Tan
2026-08-11 22:52:12 -07:00
parent ac905c68ed
commit fb0bf09a22
+14 -7
View File
@@ -12,12 +12,15 @@
* loosen in CI only with evidence of runner noise). The protocol DOC
* promises this number; the bound is op-layer latency (transport
* excluded, as documented).
* 2. RATIO GUARD (machine-independent) — entity p99 ≤ 50× max(getPage p50,
* 2. RATIO GUARD (machine-independent) — entity p99 ≤ 100× max(getPage p50,
* 1ms) on the same corpus. Calibration: the card is ~7 indexed reads +
* a keyword search on the miss path, measured ~21× a 1ms-floored
* getPage at 20K pages — an O(N) scan regression lands at 200ms+
* (≥200×), far past the ceiling even on a slow runner, while the
* 2.4× headroom absorbs planner noise.
* a keyword search on the miss path. It measures ~21× a getPage p50 of
* ~2.5ms, but on a fast runner getPage p50 floors to 1ms and normal
* entity p99 (~50ms) reads as ~50×. An O(N) scan regression lands at
* 200ms+ (≥200×), far past the ceiling even on a slow runner. The ceiling
* is 100× (not 50×) so the guard is never STRICTER than the 100ms absolute
* budget when getPage floors to 1ms — the earlier 50× tripped on fast
* runners (a p99 tail ÷ a sub-ms median) while p99 stayed well under budget.
*
* The 200K-page validation is a documented MANUAL recipe in
* docs/protocol/MEMORY_VERBS_v1.md — not CI-gated (seed time would dominate).
@@ -40,8 +43,12 @@ const MEASURED = 200;
const TARGET_ENTITIES = 50; // pages the measured calls rotate over
const P99_BUDGET_MS = 100 * (Number(process.env.GBRAIN_PERF_BUDGET_MULTIPLIER) || 1);
// entity p99 ≤ 50× max(getPage p50, 1ms) — see the calibration note above.
const RATIO_CEILING = 50;
// entity p99 ≤ 100× max(getPage p50, 1ms) — see the calibration note above.
// (100×, not 50×: at the 1ms getPage floor, 50× would cap p99 at 50ms — stricter
// than the 100ms absolute budget — and tripped on fast runners where a p99 tail
// is divided by a sub-ms getPage median. 100× stays far below the ≥200× O(N)
// regression signal.)
const RATIO_CEILING = 100;
function percentile(sorted: number[], p: number): number {
const idx = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);