From 728a8c2ec936c6efba5bd84703b3576acdd438ee Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 9 Jun 2026 16:53:25 +0900 Subject: [PATCH] perf(primer): drop pre-fire usage refresh so the Codex primer fires exactly on the slot The Codex primer awaited refreshAllCodexAccountUsage + refreshActiveCodexUsage before firing, purely to feed the old usage-based warm-up gating. With forceAttempt the primer fires regardless of usage, so those pre-call refreshes only added variable latency (the few-hundred-ms jitter that pushed the call off the exact slot) and a needless dependency on the usage API. Fire first at the slot; refresh once afterwards for observability (never delaying the call). The hourly usage collector keeps cached usage current. Verified: typecheck, build, bundle-smoke; usage-primer + codex-warmup suites pass (primer now fires before any refresh; refreshAll no longer called). Co-Authored-By: Claude Opus 4.7 --- src/usage-primer.test.ts | 7 +++++-- src/usage-primer.ts | 28 ++++++++++++++-------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/usage-primer.test.ts b/src/usage-primer.test.ts index feaaa64..ed956ee 100644 --- a/src/usage-primer.test.ts +++ b/src/usage-primer.test.ts @@ -54,7 +54,7 @@ vi.mock('./codex-warmup.js', () => ({ })); describe('usage-primer', () => { - it('refreshes Codex usage before primer selection and fires regardless of usage level', async () => { + it('fires the Codex primer first with forceAttempt and refreshes usage only afterwards', async () => { callOrder.length = 0; refreshAllCodexAccountUsage.mockClear(); refreshActiveCodexUsage.mockClear(); @@ -63,7 +63,10 @@ describe('usage-primer', () => { const { runCodexPrimerCycle } = await import('./usage-primer.js'); await runCodexPrimerCycle(); - expect(callOrder).toEqual(['refreshAll', 'refreshActive', 'warmup']); + // No pre-call usage refresh (that was the off-slot latency source); the + // command fires immediately, then usage is refreshed for observability. + expect(callOrder).toEqual(['warmup', 'refreshActive']); + expect(refreshAllCodexAccountUsage).not.toHaveBeenCalled(); expect(runCodexWarmupCycle).toHaveBeenCalledWith( expect.objectContaining({ enabled: true, diff --git a/src/usage-primer.ts b/src/usage-primer.ts index bb4687e..cee20c0 100644 --- a/src/usage-primer.ts +++ b/src/usage-primer.ts @@ -3,10 +3,7 @@ import fs from 'fs'; import path from 'path'; import { CODEX_WARMUP_CONFIG } from './config.js'; -import { - refreshActiveCodexUsage, - refreshAllCodexAccountUsage, -} from './codex-usage-collector.js'; +import { refreshActiveCodexUsage } from './codex-usage-collector.js'; import { runCodexWarmupCycle } from './codex-warmup.js'; import { logger } from './logger.js'; import { getAllTokens } from './token-rotation.js'; @@ -153,8 +150,11 @@ async function runClaudePrimerCycle(): Promise { export async function runCodexPrimerCycle(): Promise { try { - await refreshAllCodexAccountUsage(); - await refreshActiveCodexUsage(); + // Fire immediately at the slot. There is NO pre-call usage refresh on + // purpose: forceAttempt fires regardless of usage, so reading usage first + // only added variable latency (the few-hundred-ms processing jitter that + // pushed the call off the exact slot) and a needless dependency on the + // usage API. The hourly usage collector keeps cached usage current. const result = await runCodexWarmupCycle( { ...CODEX_WARMUP_CONFIG, @@ -164,17 +164,17 @@ export async function runCodexPrimerCycle(): Promise { maxD7UsagePct: CODEX_PRIMER_MAX_D7_USAGE_PCT, }, // forceAttempt: fire a real Codex command at *every* fixed slot, - // bypassing the opportunistic warm-up skip gates. Without it, two slots - // exactly 5h apart fall just under minIntervalMs (the primer fires a few - // hundred ms after the slot) and the later slot is silently skipped. + // bypassing the opportunistic warm-up skip gates (min-interval, stagger, + // failure cooldown, usage/rate-limit filters). { ignoreZeroUsageWindow: true, forceAttempt: true }, ); - // Best-effort: a slot may land while the trailing 5h window is exhausted, - // in which case this records `failed`. We deliberately do NOT try to - // re-anchor to the reported reset time: the 5h limit is a trailing rolling - // window whose reset slides forward with continued Codex usage, so no - // single timed call can pin the reset to a fixed clock time. logger.info({ result }, 'Codex primer cycle finished'); + // Observability only — runs AFTER the call so it never delays it: refresh + // so the newly-anchored reset window shows up in usage data/logs. A slot + // may still land while the trailing 5h window is exhausted (records + // `failed`); we do not chase the reported reset time, since a trailing + // window keeps sliding with later usage. + await refreshActiveCodexUsage(); } catch (err) { logger.warn({ err }, 'Codex primer cycle threw'); }