From 1c6b13ef33257a56ab96872dec920a19ae439fca Mon Sep 17 00:00:00 2001 From: JUN Date: Tue, 10 Nov 2026 04:25:18 +0900 Subject: [PATCH 1/2] test(usage): name the input that moved when the warm aggregate rebuilds --- tests/server/model-costs-pricing-cache.test.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/server/model-costs-pricing-cache.test.ts b/tests/server/model-costs-pricing-cache.test.ts index e23c1b26e1b..1c273d72eae 100644 --- a/tests/server/model-costs-pricing-cache.test.ts +++ b/tests/server/model-costs-pricing-cache.test.ts @@ -9,8 +9,8 @@ import { getFilteredUsageAggregate, getUsageAggregate, resetUsageAggregateCacheF import { getUsageSummaryCacheEntry, resetUsageSummaryCacheForTests } from "../../src/server/management/usage-summary-cache"; import type { OcxConfig, PromptLengthPricing } from "../../src/types"; import { estimateRequestCost } from "../../src/usage/cost"; -import { resetUsageReadCacheForTests, type PersistedUsageEntry } from "../../src/usage/log"; -import { refreshUserCostOverlays, resetPreservedDiskOnlyProvidersForTests } from "../../src/usage/user-cost-overlays"; +import { currentUsageLogRevision, resetUsageReadCacheForTests, type PersistedUsageEntry } from "../../src/usage/log"; +import { refreshUserCostOverlays, resetPreservedDiskOnlyProvidersForTests, userCostOverlayVersion } from "../../src/usage/user-cost-overlays"; import { stopUserCostOverlayReconciler } from "../../src/usage/user-cost-overlay-reconciler"; import { installIsolatedCodexHome, type IsolatedCodexHome } from "../helpers/isolated-codex-home"; import { managementFetch } from "../helpers/management-auth"; @@ -106,7 +106,11 @@ test("policy-only API writes refresh warm estimate, summary and aggregate caches { policy: null, total: catalog.cost.total }, ]; let previousTotal = 0.259; - for (const { policy, total } of stages) { + // Every input the warm aggregate compares, so a Windows-only "rebuild" names what moved. + const aggregateInputs = () => ({ revision: currentUsageLogRevision(), overlayVersion: userCostOverlayVersion(), + timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone }); + for (const [stage, { policy, total }] of stages.entries()) { + const inputsAtStageStart = aggregateInputs(); const estimateBefore = estimateRequestCost(INPUT)!; expect(estimateBefore.cost.total).toBeCloseTo(previousTotal, 12); expect(estimateRequestCost(INPUT)?.price).toBe(estimateBefore.price); @@ -115,8 +119,10 @@ test("policy-only API writes refresh warm estimate, summary and aggregate caches expect(before.summary.estimatedCostUsd).toBeCloseTo(previousTotal, 12); expect((await summarize()).summary).toEqual(before.summary); expect(getUsageSummaryCacheEntry("all:all")).toBe(summaryCache); + const inputsBefore = aggregateInputs(); const aggregate = await getUsageAggregate({ now }); - expect(aggregate.update).toBe("unchanged"); + expect(aggregate.update, JSON.stringify({ stage, stageStart: inputsAtStageStart, beforeRead: inputsBefore, afterRead: aggregateInputs() })) + .toBe("unchanged"); expect((await getUsageAggregate({ now })).accumulator).toBe(aggregate.accumulator); const filtered = await getFilteredUsageAggregate({ provider: INPUT.provider }); expect((await getFilteredUsageAggregate({ provider: INPUT.provider })).update).toBe("unchanged"); From 740a867e82a60b7f9f9de1173da6b7b69e3c9e39 Mon Sep 17 00:00:00 2001 From: JUN Date: Tue, 10 Nov 2026 04:55:41 +0900 Subject: [PATCH 2/2] test(usage): report the previous stage's recorded base and the filtered reads --- tests/server/model-costs-pricing-cache.test.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tests/server/model-costs-pricing-cache.test.ts b/tests/server/model-costs-pricing-cache.test.ts index 1c273d72eae..34a0541123d 100644 --- a/tests/server/model-costs-pricing-cache.test.ts +++ b/tests/server/model-costs-pricing-cache.test.ts @@ -106,9 +106,13 @@ test("policy-only API writes refresh warm estimate, summary and aggregate caches { policy: null, total: catalog.cost.total }, ]; let previousTotal = 0.259; - // Every input the warm aggregate compares, so a Windows-only "rebuild" names what moved. + // Every input the warm aggregate compares, so a Windows-only "rebuild" names what moved. The + // comparison base is what the previous stage's refresh recorded, so that is reported too. const aggregateInputs = () => ({ revision: currentUsageLogRevision(), overlayVersion: userCostOverlayVersion(), timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone }); + const recorded = (result: { revision: unknown; overlayVersion: number; timeZone: string }) => + ({ revision: result.revision, overlayVersion: result.overlayVersion, timeZone: result.timeZone }); + let prevBase: unknown = null; for (const [stage, { policy, total }] of stages.entries()) { const inputsAtStageStart = aggregateInputs(); const estimateBefore = estimateRequestCost(INPUT)!; @@ -121,11 +125,13 @@ test("policy-only API writes refresh warm estimate, summary and aggregate caches expect(getUsageSummaryCacheEntry("all:all")).toBe(summaryCache); const inputsBefore = aggregateInputs(); const aggregate = await getUsageAggregate({ now }); - expect(aggregate.update, JSON.stringify({ stage, stageStart: inputsAtStageStart, beforeRead: inputsBefore, afterRead: aggregateInputs() })) - .toBe("unchanged"); + expect(aggregate.update, JSON.stringify({ stage, prevBase, stageStart: inputsAtStageStart, beforeRead: inputsBefore, + afterRead: aggregateInputs(), rebuiltTo: recorded(aggregate) })).toBe("unchanged"); expect((await getUsageAggregate({ now })).accumulator).toBe(aggregate.accumulator); const filtered = await getFilteredUsageAggregate({ provider: INPUT.provider }); - expect((await getFilteredUsageAggregate({ provider: INPUT.provider })).update).toBe("unchanged"); + const filteredAgain = await getFilteredUsageAggregate({ provider: INPUT.provider }); + expect(filteredAgain.update, JSON.stringify({ stage, filteredBase: recorded(filtered), now: aggregateInputs(), + rebuiltTo: recorded(filteredAgain) })).toBe("unchanged"); expect(filtered.accumulator.summarize("all", now).summary.estimatedCostUsd).toBeCloseTo(previousTotal, 12); await writePolicy(policy); @@ -142,10 +148,12 @@ test("policy-only API writes refresh warm estimate, summary and aggregate caches expect(refreshedAggregate.accumulator).not.toBe(aggregate.accumulator); expect(refreshedAggregate.accumulator.summarize("all", now).summary.estimatedCostUsd).toBeCloseTo(total, 12); const refreshedFiltered = await getFilteredUsageAggregate({ provider: INPUT.provider }); - expect(refreshedFiltered.update).toBe("rebuild"); + expect(refreshedFiltered.update, JSON.stringify({ stage, filteredBase: recorded(filtered), now: aggregateInputs() })) + .toBe("rebuild"); expect(refreshedFiltered.accumulator).not.toBe(filtered.accumulator); expect(refreshedFiltered.accumulator.summarize("all", now).summary.estimatedCostUsd).toBeCloseTo(total, 12); expect(readFileSync(ledgerPath, "utf8")).toBe(ledger); + prevBase = recorded(refreshedAggregate); previousTotal = total; } const reset = estimateRequestCost(INPUT)!;