Skip to content

Commit 4885705

Browse files
committed
fix(desktop): hide the main cache rate when the main-only summary read fails
A failed narrow query left the blended summary in place, and the rate then read the blend while presenting it as the main loop's — for 1M main input tokens with 950k cached plus 100k uncached auxiliary input, 86.36% shown where the main rate is 95%. The preload now marks the narrower read as unavailable, and the overview hides the rate instead of letting the blended number stand in. A summary that never asked the narrower question still falls back to the blend. Carries the #5691 review finding. Generated-by: GLM-5.3-Flash (ZCode)
1 parent 74c35a2 commit 4885705

4 files changed

Lines changed: 35 additions & 4 deletions

File tree

‎apps/desktop/src/main/__tests__/session-inspector-usage-stats.test.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,25 @@ test('reads the cache rate from the main loop alone when the main summary is ava
383383
assert.ok(refined);
384384
assert.equal(Math.round(refined * 100), 95);
385385
});
386+
387+
test('shows no cache rate when the main-only read failed rather than blending', () => {
388+
// A failed narrow query leaves the blended totals in place. Reporting the
389+
// blended 86% as the main loop's rate is the same misreading the main
390+
// summary exists to prevent (#5691 review): hide the rate instead.
391+
const { cacheHitRate } = deriveInspectorOverviewModel(undefined, {
392+
...usageSummary({
393+
totalTokens: {
394+
input: 1_100_000,
395+
output: 60_300,
396+
cacheMiss: 150_000,
397+
cacheRead: 950_000,
398+
cacheWrite: 0,
399+
reasoning: 0,
400+
total: 1_160_300,
401+
},
402+
}),
403+
mainSummaryUnavailable: true,
404+
});
405+
406+
assert.equal(cacheHitRate, undefined);
407+
});

‎apps/desktop/src/preload/bridge-contract.d.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,8 @@ export interface DesktopSessionUsageSummary extends UsageSummaryV2 {
824824
* reads this: auxiliary prompts have their own cache prefix (#5691).
825825
*/
826826
readonly mainSummary?: DesktopSessionUsageSummary;
827+
/** The narrower read failed; the blended rate must not stand in for it. */
828+
readonly mainSummaryUnavailable?: boolean;
827829
}
828830

829831
export interface MakaBridge {

‎apps/desktop/src/preload/preload.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,10 +1329,11 @@ async function loadSessionUsageSummary(
13291329
])) as [Result<DesktopSessionUsageSummary>, Result<DesktopSessionUsageSummary>];
13301330
if (!summary.ok) return summary;
13311331
// The main-only read refines the cache rate; losing it must not lose the
1332-
// overview, so a failed auxiliary query just leaves the blended rate.
1332+
// overview — but it must also not pass the blended rate off as the main
1333+
// loop's, so the failure is marked and the rate hides itself (#5691).
13331334
return main.ok
13341335
? { ...summary, data: { ...summary.data, mainSummary: main.data } }
1335-
: summary;
1336+
: { ...summary, data: { ...summary.data, mainSummaryUnavailable: true } };
13361337
}
13371338

13381339
async function updateDailyReviewConfig(

‎apps/desktop/src/renderer/application/contracts/session-inspector/session-inspector-overview-model.ts‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type SessionUsageSummary = UsageSummaryV2 & {
2828
readonly provenance?: UsageProvenance;
2929
/** The agent loop's own calls, when the narrower read succeeded (#5691). */
3030
readonly mainSummary?: SessionUsageSummary;
31+
/** The narrower read failed; the blended rate must not stand in for it. */
32+
readonly mainSummaryUnavailable?: boolean;
3133
};
3234

3335
/**
@@ -249,8 +251,12 @@ export function deriveInspectorOverviewModel(
249251
function usageCacheHitRate(usage: SessionUsageSummary | undefined): number | undefined {
250252
// Auxiliary calls keep their own prompt prefix, so blending them into the
251253
// rate reports the main loop's caching as worse than it is (#5691). The
252-
// main-only summary is the rate's input; the blended summary is only the
253-
// fallback when the narrower read is unavailable.
254+
// main-only summary is the rate's input. When that narrower read failed,
255+
// show no rate at all: the blended number is about a different set of calls
256+
// and presenting it as the main loop's is the same lie in weaker type. The
257+
// fallback to the blended summary only serves summaries that never asked
258+
// the narrower question.
259+
if (usage?.mainSummaryUnavailable && !usage.mainSummary) return undefined;
254260
const main = usage?.mainSummary ?? usage;
255261
if (!main || main.totalTokens.input === 0) return undefined;
256262
if (

0 commit comments

Comments
 (0)