From d1741f04e66bc4fb47fc1634d26721cf2472c01f Mon Sep 17 00:00:00 2001 From: Alexander Kirilin Date: Tue, 11 Aug 2026 13:52:48 -0400 Subject: [PATCH] fix(omp): prevent false reset fireworks --- packages/coding-agent/CHANGELOG.md | 1 + .../modes/components/codex-reset-fireworks.ts | 7 ++++++- .../components/codex-reset-fireworks.test.ts | 21 +++++++++++++++++-- .../test/status-line-usage-refresh.test.ts | 16 ++++++++++---- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 456e88609..855e26516 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -20,6 +20,7 @@ ### Fixed +- Fixed Codex reset fireworks triggering on ordinary weekly-usage decreases when the provider had not advanced the quota reset deadline. - Retried concurrent-request caps with a short backoff without deleting valid Copilot credentials or rotating through sibling accounts. - Fixed the default `textVerbosity` setting being forwarded to OpenAI Codex requests unless the user explicitly configures it, preserving Codex's native response-control defaults. ([#4949](https://github.com/can1357/oh-my-pi/issues/4949)) - Reduced streaming CPU usage by coalescing the cumulative `message_update` deltas of a turn at the event-controller dispatch boundary: at most one streaming-state rebuild runs per ~33ms window instead of one per token, cutting the per-token handler work that dominated the CPU profile of streaming sessions (especially at high token rates) while preserving per-delta speech output. Subscriber dispatch is serialized so a rapid stream tail (`message_update` → `message_end` → `agent_end`) cannot overtake the coalesced flush. ([#7443](https://github.com/can1357/oh-my-pi/issues/7443)) diff --git a/packages/coding-agent/src/modes/components/codex-reset-fireworks.ts b/packages/coding-agent/src/modes/components/codex-reset-fireworks.ts index 10d7018c0..6a6b48718 100644 --- a/packages/coding-agent/src/modes/components/codex-reset-fireworks.ts +++ b/packages/coding-agent/src/modes/components/codex-reset-fireworks.ts @@ -79,7 +79,8 @@ const BURSTS: readonly FireworkBurst[] = [ * precedence when both changes arrive in the same report. A verified decrease, * or a prior positive balance becoming unavailable, suppresses the weekly event * because the user may have redeemed a credit. Other weekly usage drops are - * celebrated only before the previously scheduled reset deadline. + * celebrated only when the provider advances the quota deadline before the + * previously scheduled reset. */ export function detectCodexResetFireworks( previous: CodexResetUsageSnapshot, @@ -111,9 +112,13 @@ export function detectCodexResetFireworks( if (previousWeeklyPercent === 0 || currentWeeklyPercent >= previousWeeklyPercent) return undefined; const scheduledResetAt = previous.sevenDay.resetsAt; + const nextResetAt = current.sevenDay.resetsAt; if ( scheduledResetAt === undefined || !Number.isFinite(scheduledResetAt) || + nextResetAt === undefined || + !Number.isFinite(nextResetAt) || + nextResetAt <= scheduledResetAt || typeof current.observedAt !== "number" || !Number.isFinite(current.observedAt) || current.observedAt >= scheduledResetAt diff --git a/packages/coding-agent/test/modes/components/codex-reset-fireworks.test.ts b/packages/coding-agent/test/modes/components/codex-reset-fireworks.test.ts index 70c95717c..0926d1bc5 100644 --- a/packages/coding-agent/test/modes/components/codex-reset-fireworks.test.ts +++ b/packages/coding-agent/test/modes/components/codex-reset-fireworks.test.ts @@ -93,14 +93,14 @@ describe("Codex reset fireworks", () => { expect( detectCodexResetFireworks(previous, { observedAt: 2_000, - sevenDay: { percent: 2, resetsAt: 10_000 }, + sevenDay: { percent: 2, resetsAt: 20_000 }, savedResets: 0, }), ).toEqual({ kind: "unscheduled-weekly-reset" }); expect( detectCodexResetFireworks(previous, { observedAt: 2_000, - sevenDay: { percent: 0, resetsAt: 10_000 }, + sevenDay: { percent: 0, resetsAt: 20_000 }, savedResets: 2, }), ).toEqual({ kind: "saved-reset-banked", added: 2, available: 2 }); @@ -122,6 +122,23 @@ describe("Codex reset fireworks", () => { ).toBeUndefined(); }); + it("suppresses a weekly decrease when the quota deadline did not advance", () => { + expect( + detectCodexResetFireworks( + { + observedAt: 1_000, + sevenDay: { percent: 42, resetsAt: 10_000 }, + savedResets: 0, + }, + { + observedAt: 2_000, + sevenDay: { percent: 41, resetsAt: 10_000 }, + savedResets: 0, + }, + ), + ).toBeUndefined(); + }); + it("suppresses a weekly transition observed at its scheduled reset deadline", () => { expect( detectCodexResetFireworks( diff --git a/packages/coding-agent/test/status-line-usage-refresh.test.ts b/packages/coding-agent/test/status-line-usage-refresh.test.ts index 499ca96d4..ccde9a3c3 100644 --- a/packages/coding-agent/test/status-line-usage-refresh.test.ts +++ b/packages/coding-agent/test/status-line-usage-refresh.test.ts @@ -305,6 +305,7 @@ describe("StatusLineComponent usage refresh", () => { it("emits distinct enabled events for an unscheduled weekly reset and a newly banked reset", async () => { Settings.instance.set("tui.codexResetFireworks", true); const sevenDayResetAt = Date.now() + 80 * 3_600_000; + const nextSevenDayResetAt = sevenDayResetAt + 7 * 24 * 3_600_000; let state: CodexUsageState = { sevenDayPercent: 42, sevenDayResetAt, @@ -317,20 +318,27 @@ describe("StatusLineComponent usage refresh", () => { await refreshUsage(component); expect(events).toEqual([]); state = { - sevenDayPercent: 2, + sevenDayPercent: 41, sevenDayResetAt, savedResets: 0, }; await refreshUsage(component, 5 * 60_000); + expect(events).toEqual([]); + state = { + sevenDayPercent: 2, + sevenDayResetAt: nextSevenDayResetAt, + savedResets: 0, + }; + await refreshUsage(component, 5 * 60_000); state = { sevenDayPercent: 25, - sevenDayResetAt, + sevenDayResetAt: nextSevenDayResetAt, savedResets: 0, }; await refreshUsage(component, 5 * 60_000); state = { sevenDayPercent: 25.2, - sevenDayResetAt, + sevenDayResetAt: nextSevenDayResetAt, savedResets: 1, }; await refreshUsage(component, 5 * 60_000); @@ -363,7 +371,7 @@ describe("StatusLineComponent usage refresh", () => { state = { ...state, sevenDayPercent: 42, tier: "spark" }; await refreshUsage(component, 5 * 60_000); - state = { ...state, sevenDayPercent: 2 }; + state = { ...state, sevenDayPercent: 2, sevenDayResetAt: sevenDayResetAt + 7 * 24 * 3_600_000 }; await refreshUsage(component, 5 * 60_000); expect(events).toEqual([{ kind: "unscheduled-weekly-reset" }]); component.dispose();