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 <noreply@anthropic.com>
This commit is contained in:
Codex
2026-06-09 16:53:25 +09:00
parent f6ce3122bf
commit 728a8c2ec9
2 changed files with 19 additions and 16 deletions

View File

@@ -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,

View File

@@ -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<void> {
export async function runCodexPrimerCycle(): Promise<void> {
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<void> {
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');
}